sapling/hgext/churn.py

163 lines
5.2 KiB
Python
Raw Normal View History

# churn.py - create a graph of revisions count grouped by template
2006-07-27 03:42:56 +04:00
#
# Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
# Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
2006-07-27 03:42:56 +04:00
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
'''command to show certain statistics about revision history'''
2006-07-27 03:42:56 +04:00
from mercurial.i18n import _
from mercurial import patch, cmdutil, util, templater
2009-03-23 15:12:07 +03:00
import sys
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):
lines = 0
fmatch = cmdutil.match(repo, pats=fns)
diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
for l in diff.split('\n'):
if (l.startswith("+") and not l.startswith("+++ ") or
l.startswith("-") and not l.startswith("--- ")):
lines += 1
return lines
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()
count = pct = 0
rate = {}
df = False
if opts.get('date'):
df = util.matchdate(opts['date'])
get = util.cachefunc(lambda r: repo[r].changeset())
changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
for st, rev, fns in changeiter:
if not st == 'add':
continue
if df and not df(get(rev)[2][0]): # doesn't match date format
2006-09-04 00:30:07 +04:00
continue
ctx = repo[rev]
key = getkey(ctx)
key = amap.get(key, key) # alias remap
2008-10-09 01:14:20 +04:00
if opts.get('changesets'):
rate[key] = rate.get(key, 0) + 1
else:
parents = ctx.parents()
if len(parents) > 1:
ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
continue
ctx1 = parents[0]
lines = changedlines(ui, repo, ctx1, ctx, fns)
rate[key] = rate.get(key, 0) + lines
if opts.get('progress'):
count += 1
newpct = int(100.0 * count / max(len(repo), 1))
if pct < newpct:
pct = newpct
ui.write("\r" + _("generating stats: %d%%") % pct)
2006-09-04 00:30:07 +04:00
sys.stdout.flush()
if opts.get('progress'):
ui.write("\r")
2006-09-04 00:30:07 +04:00
sys.stdout.flush()
return rate
2006-07-27 03:42:56 +04:00
2008-10-09 01:14:20 +04:00
def churn(ui, repo, *pats, **opts):
'''graph count of revisions grouped by template
Will graph count of changed lines or revisions grouped by template
or alternatively by date, if dateformat is used. In this case it
will override template.
2008-10-09 01:14:20 +04:00
By default statistics are counted for number of changed lines.
Examples:
2006-10-01 21:26:33 +04:00
2008-10-09 01:14:20 +04:00
# display count of changed lines for every committer
hg churn -t '{author|email}'
# display daily activity graph
2008-10-09 01:14:20 +04:00
hg churn -f '%H' -s -c
# display activity of developers by month
2008-10-09 01:14:20 +04:00
hg churn -f '%Y-%m' -s -c
# display count of lines changed in every year
2008-10-09 01:14:20 +04:00
hg churn -f '%Y' -s
The map file format used to specify aliases is fairly simple:
<alias email> <actual email>'''
2006-07-27 03:42:56 +04:00
def pad(s, l):
return (s + " " * l)[:l]
2006-10-01 21:26:33 +04:00
2006-07-27 03:42:56 +04:00
amap = {}
2006-08-19 09:08:48 +04:00
aliases = opts.get('aliases')
2006-07-27 03:42:56 +04:00
if aliases:
for l in open(aliases, "r"):
l = l.strip()
alias, actual = l.split()
amap[alias] = actual
2006-08-19 09:08:48 +04:00
rate = countrate(ui, repo, amap, *pats, **opts).items()
if not rate:
2007-12-03 02:04:16 +03:00
return
sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None)
rate.sort(sortfn)
maxcount = float(max([v for k, v in rate]))
maxname = max([len(k) for k, v in rate])
2006-07-27 03:42:56 +04:00
ttywidth = util.termwidth()
ui.debug(_("assuming %i character terminal\n") % ttywidth)
width = ttywidth - maxname - 2 - 6 - 2 - 2
for date, count in rate:
print "%s %6d %s" % (pad(date, maxname), count,
"*" * int(count * width / maxcount))
2006-07-27 03:42:56 +04:00
cmdtable = {
2008-10-09 01:14:20 +04:00
"churn":
(churn,
[('r', 'rev', [], _('count rate for the specified revision or range')),
('d', 'date', '', _('count rate for revisions matching date spec')),
('t', 'template', '{author|email}', _('template to group changesets')),
('f', 'dateformat', '',
_('strftime-compatible format for grouping by date')),
2008-10-09 01:14:20 +04:00
('c', 'changesets', False, _('count rate by number of changesets')),
('s', 'sort', False, _('sort by key (default: sort by count)')),
('', 'aliases', '', _('file with email aliases')),
('', 'progress', None, _('show progress'))],
2008-10-18 18:51:26 +04:00
_("hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")),
2006-07-27 03:42:56 +04:00
}