Eduardo Robles Elvira avatar Eduardo Robles Elvira committed 7fba299

Initial commit

Comments (0)

Files changed (1)

+#!/usr/bin/env python
+
+'''timetracker
+
+Tracks the time spent on a project.
+'''
+
+from mercurial import hg, extensions, commands, localrepo
+from datetime import datetime, timedelta
+import time
+import ConfigParser
+
+def timedelta_str(diff):
+    """
+    Returns string representing "time delta" e.g.
+    3 days, 5 hours 3 minutes, etc.
+    """
+    def int_sub(a, b):
+        if b >= a:
+            return 0
+        else:
+            return a - b
+
+    periods = (
+        (diff.seconds // 3600, "hour", "hours", 60),
+        (diff.seconds // 60, "minute", "minutes", 60),
+        (diff.seconds, "second", "seconds", 60),
+    )
+
+    ret_periods = []
+    count = 0
+    previous_period = None
+    for period, singular, plural, factor in periods:
+        if previous_period:
+            period -= previous_period * previous_factor
+        if period:
+            ret_periods += ["%d %s" % (period, singular if period == 1 else plural)]
+            count += 1
+        if count >= 2:
+            break
+        previous_period = period
+        previous_factor = factor
+
+    return ", ".join(ret_periods)
+
+
+def uisetup(ui):
+    entry = extensions.wrapcommand(commands.table, 'commit', wrap_commit)
+    extensions.wrapfunction(localrepo.localrepository, "commit", wrap_localrepo_commit)
+
+def readconfig(repo):
+    extra = dict()
+    config = ConfigParser.SafeConfigParser()
+    config.read(repo.join("timetracker"))
+    if not config.has_section("main"):
+        config.add_section("main")
+    config_time_spent = None
+    config_time_spent_start = None
+    if config.has_option("main", "time-spent"):
+        extra["time-spent"] = timedelta(seconds=int(config.get("main",
+            "time-spent", "0")))
+    if config.has_option("main", "time-spent-start"):
+        extra["time-spent-start"] = datetime.fromtimestamp(float(config.get(
+            "main", "time-spent-start", "0.0")))
+    return extra, config
+
+def saveconfig(config, extra, repo):
+    if not extra.has_key("time-spent") and\
+        config.has_option("main", "time-spent"):
+        config.remove_option("main", "time-spent")
+    elif extra.has_key("time-spent"):
+        time_spent = str(int(extra["time-spent"].total_seconds()))
+        config.set("main", "time-spent", time_spent)
+
+    if not extra.has_key("time-spent-start") and\
+        config.has_option("main", "time-spent-start"):
+        config.remove_option("main", "time-spent-start")
+    elif extra.has_key("time-spent-start"):
+        time_spent_start = str(time.mktime(extra["time-spent-start"].timetuple()))
+        config.set("main", "time-spent-start", str(time_spent_start))
+
+    filep = repo.opener('timetracker', 'w')
+    config.write(filep)
+    filep.close()
+
+def timetracker_cmd(ui, repo, *args, **opts):
+    """Tracks the time spent on a project"""
+
+    extra, config = readconfig(repo)
+
+    if opts['reset'] and extra.has_key("time-spent"):
+        extra = dict()
+        saveconfig(config, extra, repo)
+
+    elif opts['start']:
+        extra["time-spent-start"] = datetime.now()
+        saveconfig(config, extra, repo)
+
+    elif opts['stop'] and extra.get("time-spent-start", False):
+        start = extra.pop("time-spent-start")
+        delta = datetime.now() - start
+        if extra.get("time-spent", False):
+            extra["time-spent"] += delta
+        else:
+            extra["time-spent"] = delta
+        saveconfig(config, extra, repo)
+
+    elif opts['set']:
+        extra = {"time-spent": timedelta(seconds=int(args[0])*60)}
+        saveconfig(config, extra, repo)
+
+    elif opts['current']:
+        time_spent = extra.get("time-spent", timedelta(0))
+        now = datetime.now()
+        time_spent_current = now - extra.get("time-spent-start", now)
+        time_str = timedelta_str(time_spent + time_spent_current)
+        print "time spent in next commit: %s" % time_str
+
+    elif opts['summary']:
+        print "TODO"
+
+def wrap_commit(orig, ui, repo, *pats, **opts):
+    '''
+    Adds the timespent extra metadata to the changeset of this commit
+    '''
+    # do a stop
+    extra, config = readconfig(repo)
+    if extra.get("time-spent-start", False):
+        start = extra.pop("time-spent-start")
+        delta = datetime.now() - start
+        if extra.get("time-spent", False):
+            extra["time-spent"] += delta
+        else:
+            extra["time-spent"] = delta
+        saveconfig(config, extra, repo)
+
+    return orig(ui, repo, *pats, **opts)
+
+def wrap_localrepo_commit(origfunc, self, *args, **kwargs):
+    extra_config, config = readconfig(self)
+
+    # only adds time-spent extra if timetracker was put to use for this commit
+    if extra_config.get("time-spent", False):
+        if not kwargs["extra"]:
+            kwargs["extra"] = extra_config
+        else:
+            kwargs["extra"].update(extra_config)
+    ret = origfunc(self, *args, **kwargs)
+
+    extra_config = {} # starts again from zero, once the commit has been done
+    saveconfig(config, extra_config, self)
+
+    return ret
+
+cmdtable = {
+    # cmd name        function call
+    "timetracker": (timetracker_cmd,
+        # see mercurial/fancyopts.py for all of the command
+        # flag options.
+        [('s', 'start', None, 'start/continue counting time spent'),
+        ('p', 'stop', None, 'stop/pause counting time spent'),
+        ('r', 'reset', None, 'continue counting time spent'),
+        ('e', 'set', None, 'set time spent in minutes'),
+        ('c', 'current', None, 'time spent currently in next commit'),
+        ('o', 'summary', None, 'show summary of total time spent'),
+        ('b', 'branch', None, '(in combination with --summary) filters for a given branch'),
+        ('u', 'username', None, '(in combination with --summary) filters for a given username')],
+        "[options]")
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.