##// END OF EJS Templates
i18n: the message should not contain '\r'...
Benoit Boissinot -
r8085:404a2c31 default
parent child Browse files
Show More
@@ -1,162 +1,162 b''
1 1 # churn.py - create a graph of revisions count grouped by template
2 2 #
3 3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
4 4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
5 5 #
6 6 # This software may be used and distributed according to the terms
7 7 # of the GNU General Public License, incorporated herein by reference.
8 8 '''command to show certain statistics about revision history'''
9 9
10 10 from mercurial.i18n import _
11 11 from mercurial import patch, cmdutil, util, templater
12 12 import sys
13 13 import time, datetime
14 14
15 15 def maketemplater(ui, repo, tmpl):
16 16 tmpl = templater.parsestring(tmpl, quoted=False)
17 17 try:
18 18 t = cmdutil.changeset_templater(ui, repo, False, None, None, False)
19 19 except SyntaxError, inst:
20 20 raise util.Abort(inst.args[0])
21 21 t.use_template(tmpl)
22 22 return t
23 23
24 24 def changedlines(ui, repo, ctx1, ctx2, fns):
25 25 lines = 0
26 26 fmatch = cmdutil.match(repo, pats=fns)
27 27 diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
28 28 for l in diff.split('\n'):
29 29 if (l.startswith("+") and not l.startswith("+++ ") or
30 30 l.startswith("-") and not l.startswith("--- ")):
31 31 lines += 1
32 32 return lines
33 33
34 34 def countrate(ui, repo, amap, *pats, **opts):
35 35 """Calculate stats"""
36 36 if opts.get('dateformat'):
37 37 def getkey(ctx):
38 38 t, tz = ctx.date()
39 39 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
40 40 return date.strftime(opts['dateformat'])
41 41 else:
42 42 tmpl = opts.get('template', '{author|email}')
43 43 tmpl = maketemplater(ui, repo, tmpl)
44 44 def getkey(ctx):
45 45 ui.pushbuffer()
46 46 tmpl.show(ctx)
47 47 return ui.popbuffer()
48 48
49 49 count = pct = 0
50 50 rate = {}
51 51 df = False
52 52 if opts.get('date'):
53 53 df = util.matchdate(opts['date'])
54 54
55 55 get = util.cachefunc(lambda r: repo[r].changeset())
56 56 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
57 57 for st, rev, fns in changeiter:
58 58 if not st == 'add':
59 59 continue
60 60 if df and not df(get(rev)[2][0]): # doesn't match date format
61 61 continue
62 62
63 63 ctx = repo[rev]
64 64 key = getkey(ctx)
65 65 key = amap.get(key, key) # alias remap
66 66 if opts.get('changesets'):
67 67 rate[key] = rate.get(key, 0) + 1
68 68 else:
69 69 parents = ctx.parents()
70 70 if len(parents) > 1:
71 71 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
72 72 continue
73 73
74 74 ctx1 = parents[0]
75 75 lines = changedlines(ui, repo, ctx1, ctx, fns)
76 76 rate[key] = rate.get(key, 0) + lines
77 77
78 78 if opts.get('progress'):
79 79 count += 1
80 80 newpct = int(100.0 * count / max(len(repo), 1))
81 81 if pct < newpct:
82 82 pct = newpct
83 ui.write(_("\rgenerating stats: %d%%") % pct)
83 ui.write("\r" + _("generating stats: %d%%") % pct)
84 84 sys.stdout.flush()
85 85
86 86 if opts.get('progress'):
87 87 ui.write("\r")
88 88 sys.stdout.flush()
89 89
90 90 return rate
91 91
92 92
93 93 def churn(ui, repo, *pats, **opts):
94 94 '''graph count of revisions grouped by template
95 95
96 96 Will graph count of changed lines or revisions grouped by template
97 97 or alternatively by date, if dateformat is used. In this case it
98 98 will override template.
99 99
100 100 By default statistics are counted for number of changed lines.
101 101
102 102 Examples:
103 103
104 104 # display count of changed lines for every committer
105 105 hg churn -t '{author|email}'
106 106
107 107 # display daily activity graph
108 108 hg churn -f '%H' -s -c
109 109
110 110 # display activity of developers by month
111 111 hg churn -f '%Y-%m' -s -c
112 112
113 113 # display count of lines changed in every year
114 114 hg churn -f '%Y' -s
115 115
116 116 The map file format used to specify aliases is fairly simple:
117 117
118 118 <alias email> <actual email>'''
119 119 def pad(s, l):
120 120 return (s + " " * l)[:l]
121 121
122 122 amap = {}
123 123 aliases = opts.get('aliases')
124 124 if aliases:
125 125 for l in open(aliases, "r"):
126 126 l = l.strip()
127 127 alias, actual = l.split()
128 128 amap[alias] = actual
129 129
130 130 rate = countrate(ui, repo, amap, *pats, **opts).items()
131 131 if not rate:
132 132 return
133 133
134 134 sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None)
135 135 rate.sort(sortfn)
136 136
137 137 maxcount = float(max([v for k, v in rate]))
138 138 maxname = max([len(k) for k, v in rate])
139 139
140 140 ttywidth = util.termwidth()
141 141 ui.debug(_("assuming %i character terminal\n") % ttywidth)
142 142 width = ttywidth - maxname - 2 - 6 - 2 - 2
143 143
144 144 for date, count in rate:
145 145 print "%s %6d %s" % (pad(date, maxname), count,
146 146 "*" * int(count * width / maxcount))
147 147
148 148
149 149 cmdtable = {
150 150 "churn":
151 151 (churn,
152 152 [('r', 'rev', [], _('count rate for the specified revision or range')),
153 153 ('d', 'date', '', _('count rate for revisions matching date spec')),
154 154 ('t', 'template', '{author|email}', _('template to group changesets')),
155 155 ('f', 'dateformat', '',
156 156 _('strftime-compatible format for grouping by date')),
157 157 ('c', 'changesets', False, _('count rate by number of changesets')),
158 158 ('s', 'sort', False, _('sort by key (default: sort by count)')),
159 159 ('', 'aliases', '', _('file with email aliases')),
160 160 ('', 'progress', None, _('show progress'))],
161 161 _("hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")),
162 162 }
General Comments 0
You need to be logged in to leave comments. Login now