summaryrefslogtreecommitdiff
path: root/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/churn.py
diff options
context:
space:
mode:
Diffstat (limited to 'eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/churn.py')
-rw-r--r--eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/churn.py198
1 files changed, 198 insertions, 0 deletions
diff --git a/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/churn.py b/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/churn.py
new file mode 100644
index 0000000..32e481f
--- /dev/null
+++ b/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/churn.py
@@ -0,0 +1,198 @@
+# churn.py - create a graph of revisions count grouped by template
+#
+# Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
+# Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''command to display statistics about repository history'''
+
+from mercurial.i18n import _
+from mercurial import patch, cmdutil, util, templater, commands
+import os
+import time, datetime
+
+def maketemplater(ui, repo, tmpl):
+ tmpl = templater.parsestring(tmpl, quoted=False)
+ try:
+ t = cmdutil.changeset_templater(ui, repo, False, None, None, False)
+ except SyntaxError, inst:
+ raise util.Abort(inst.args[0])
+ t.use_template(tmpl)
+ return t
+
+def changedlines(ui, repo, ctx1, ctx2, fns):
+ added, removed = 0, 0
+ fmatch = cmdutil.matchfiles(repo, fns)
+ diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
+ for l in diff.split('\n'):
+ if l.startswith("+") and not l.startswith("+++ "):
+ added += 1
+ elif l.startswith("-") and not l.startswith("--- "):
+ removed += 1
+ return (added, removed)
+
+def countrate(ui, repo, amap, *pats, **opts):
+ """Calculate stats"""
+ if opts.get('dateformat'):
+ def getkey(ctx):
+ t, tz = ctx.date()
+ date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
+ return date.strftime(opts['dateformat'])
+ else:
+ tmpl = opts.get('template', '{author|email}')
+ tmpl = maketemplater(ui, repo, tmpl)
+ def getkey(ctx):
+ ui.pushbuffer()
+ tmpl.show(ctx)
+ return ui.popbuffer()
+
+ state = {'count': 0}
+ rate = {}
+ df = False
+ if opts.get('date'):
+ df = util.matchdate(opts['date'])
+
+ m = cmdutil.match(repo, pats, opts)
+ def prep(ctx, fns):
+ rev = ctx.rev()
+ if df and not df(ctx.date()[0]): # doesn't match date format
+ return
+
+ key = getkey(ctx)
+ key = amap.get(key, key) # alias remap
+ key = key.strip() # ignore leading and trailing spaces
+ if opts.get('changesets'):
+ rate[key] = (rate.get(key, (0,))[0] + 1, 0)
+ else:
+ parents = ctx.parents()
+ if len(parents) > 1:
+ ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
+ return
+
+ ctx1 = parents[0]
+ lines = changedlines(ui, repo, ctx1, ctx, fns)
+ rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)]
+
+ state['count'] += 1
+ ui.progress(_('analyzing'), state['count'], total=len(repo))
+
+ for ctx in cmdutil.walkchangerevs(repo, m, opts, prep):
+ continue
+
+ ui.progress(_('analyzing'), None)
+
+ return rate
+
+
+def churn(ui, repo, *pats, **opts):
+ '''histogram of changes to the repository
+
+ This command will display a histogram representing the number
+ of changed lines or revisions, grouped according to the given
+ template. The default template will group changes by author.
+ The --dateformat option may be used to group the results by
+ date instead.
+
+ Statistics are based on the number of changed lines, or
+ alternatively the number of matching revisions if the
+ --changesets option is specified.
+
+ Examples::
+
+ # display count of changed lines for every committer
+ hg churn -t '{author|email}'
+
+ # display daily activity graph
+ hg churn -f '%H' -s -c
+
+ # display activity of developers by month
+ hg churn -f '%Y-%m' -s -c
+
+ # display count of lines changed in every year
+ hg churn -f '%Y' -s
+
+ It is possible to map alternate email addresses to a main address
+ by providing a file using the following format::
+
+ <alias email> = <actual email>
+
+ Such a file may be specified with the --aliases option, otherwise
+ a .hgchurn file will be looked for in the working directory root.
+ '''
+ def pad(s, l):
+ return (s + " " * l)[:l]
+
+ amap = {}
+ aliases = opts.get('aliases')
+ if not aliases and os.path.exists(repo.wjoin('.hgchurn')):
+ aliases = repo.wjoin('.hgchurn')
+ if aliases:
+ for l in open(aliases, "r"):
+ try:
+ alias, actual = l.split('=' in l and '=' or None, 1)
+ amap[alias.strip()] = actual.strip()
+ except ValueError:
+ l = l.strip()
+ if l:
+ ui.warn(_("skipping malformed alias: %s\n" % l))
+ continue
+
+ rate = countrate(ui, repo, amap, *pats, **opts).items()
+ if not rate:
+ return
+
+ sortkey = ((not opts.get('sort')) and (lambda x: -sum(x[1])) or None)
+ rate.sort(key=sortkey)
+
+ # Be careful not to have a zero maxcount (issue833)
+ maxcount = float(max(sum(v) for k, v in rate)) or 1.0
+ maxname = max(len(k) for k, v in rate)
+
+ ttywidth = ui.termwidth()
+ ui.debug("assuming %i character terminal\n" % ttywidth)
+ width = ttywidth - maxname - 2 - 2 - 2
+
+ if opts.get('diffstat'):
+ width -= 15
+ def format(name, diffstat):
+ added, removed = diffstat
+ return "%s %15s %s%s\n" % (pad(name, maxname),
+ '+%d/-%d' % (added, removed),
+ ui.label('+' * charnum(added),
+ 'diffstat.inserted'),
+ ui.label('-' * charnum(removed),
+ 'diffstat.deleted'))
+ else:
+ width -= 6
+ def format(name, count):
+ return "%s %6d %s\n" % (pad(name, maxname), sum(count),
+ '*' * charnum(sum(count)))
+
+ def charnum(count):
+ return int(round(count * width / maxcount))
+
+ for name, count in rate:
+ ui.write(format(name, count))
+
+
+cmdtable = {
+ "churn":
+ (churn,
+ [('r', 'rev', [],
+ _('count rate for the specified revision or range'), _('REV')),
+ ('d', 'date', '',
+ _('count rate for revisions matching date spec'), _('DATE')),
+ ('t', 'template', '{author|email}',
+ _('template to group changesets'), _('TEMPLATE')),
+ ('f', 'dateformat', '',
+ _('strftime-compatible format for grouping by date'), _('FORMAT')),
+ ('c', 'changesets', False, _('count rate by number of changesets')),
+ ('s', 'sort', False, _('sort by key (default: sort by count)')),
+ ('', 'diffstat', False, _('display added/removed lines separately')),
+ ('', 'aliases', '',
+ _('file with email aliases'), _('FILE')),
+ ] + commands.walkopts,
+ _("hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]")),
+}