##// END OF EJS Templates
churn: py2.3 compatibility fix...
Alexander Solovyov -
r7076:c29d3f4e default
parent child Browse files
Show More
@@ -1,184 +1,184 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 '''allow graphing the number of lines (or count of revisions) grouped by template'''
9 9
10 10 from mercurial.i18n import _
11 11 from mercurial import patch, cmdutil, util, templater
12 12 import os, sys
13 13 import time, datetime
14 14
15 15 def get_tty_width():
16 16 if 'COLUMNS' in os.environ:
17 17 try:
18 18 return int(os.environ['COLUMNS'])
19 19 except ValueError:
20 20 pass
21 21 try:
22 22 import termios, array, fcntl
23 23 for dev in (sys.stdout, sys.stdin):
24 24 try:
25 25 fd = dev.fileno()
26 26 if not os.isatty(fd):
27 27 continue
28 28 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
29 29 return array.array('h', arri)[1]
30 30 except ValueError:
31 31 pass
32 32 except ImportError:
33 33 pass
34 34 return 80
35 35
36 36 def maketemplater(ui, repo, tmpl):
37 37 tmpl = templater.parsestring(tmpl, quoted=False)
38 38 try:
39 39 t = cmdutil.changeset_templater(ui, repo, False, None, False)
40 40 except SyntaxError, inst:
41 41 raise util.Abort(inst.args[0])
42 42 t.use_template(tmpl)
43 43 return t
44 44
45 45 def changedlines(ui, repo, ctx1, ctx2):
46 46 lines = 0
47 47 ui.pushbuffer()
48 48 patch.diff(repo, ctx1.node(), ctx2.node())
49 49 diff = ui.popbuffer()
50 50 for l in diff.split('\n'):
51 51 if (l.startswith("+") and not l.startswith("+++ ") or
52 52 l.startswith("-") and not l.startswith("--- ")):
53 53 lines += 1
54 54 return lines
55 55
56 56 def countrate(ui, repo, amap, *pats, **opts):
57 57 """Calculate stats"""
58 58 if opts.get('dateformat'):
59 59 def getkey(ctx):
60 60 t, tz = ctx.date()
61 61 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
62 62 return date.strftime(opts['dateformat'])
63 63 else:
64 64 tmpl = opts.get('template', '{author|email}')
65 65 tmpl = maketemplater(ui, repo, tmpl)
66 66 def getkey(ctx):
67 67 ui.pushbuffer()
68 68 tmpl.show(changenode=ctx.node())
69 69 return ui.popbuffer()
70 70
71 71 count = pct = 0
72 72 rate = {}
73 73 df = False
74 74 if opts.get('date'):
75 75 df = util.matchdate(opts['date'])
76 76
77 77 get = util.cachefunc(lambda r: repo[r].changeset())
78 78 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
79 79 for st, rev, fns in changeiter:
80 80 if not st == 'add':
81 81 continue
82 82 if df and not df(get(rev)[2][0]): # doesn't match date format
83 83 continue
84 84
85 85 ctx = repo[rev]
86 86 key = getkey(ctx)
87 87 key = amap.get(key, key) # alias remap
88 88 if opts.get('changesets'):
89 89 rate[key] = rate.get(key, 0) + 1
90 90 else:
91 91 parents = ctx.parents()
92 92 if len(parents) > 1:
93 93 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
94 94 continue
95 95
96 96 ctx1 = parents[0]
97 97 lines = changedlines(ui, repo, ctx1, ctx)
98 98 rate[key] = rate.get(key, 0) + lines
99 99
100 100 if opts.get('progress'):
101 101 count += 1
102 102 newpct = int(100.0 * count / max(len(repo), 1))
103 103 if pct < newpct:
104 104 pct = newpct
105 105 ui.write(_("\rGenerating stats: %d%%") % pct)
106 106 sys.stdout.flush()
107 107
108 108 if opts.get('progress'):
109 109 ui.write("\r")
110 110 sys.stdout.flush()
111 111
112 112 return rate
113 113
114 114
115 115 def churn(ui, repo, *pats, **opts):
116 116 '''Graph count of revisions grouped by template
117 117
118 118 Will graph count of changed lines or revisions grouped by template or
119 119 alternatively by date, if dateformat is used. In this case it will override
120 120 template.
121 121
122 122 By default statistics are counted for number of changed lines.
123 123
124 124 Examples:
125 125
126 126 # display count of changed lines for every committer
127 127 hg churn -t '{author|email}'
128 128
129 129 # display daily activity graph
130 130 hg churn -f '%H' -s -c
131 131
132 132 # display activity of developers by month
133 133 hg churn -f '%Y-%m' -s -c
134 134
135 135 # display count of lines changed in every year
136 136 hg churn -f '%Y' -s
137 137
138 138 The map file format used to specify aliases is fairly simple:
139 139
140 140 <alias email> <actual email>'''
141 141 def pad(s, l):
142 142 return (s + " " * l)[:l]
143 143
144 144 amap = {}
145 145 aliases = opts.get('aliases')
146 146 if aliases:
147 147 for l in open(aliases, "r"):
148 148 l = l.strip()
149 149 alias, actual = l.split()
150 150 amap[alias] = actual
151 151
152 152 rate = countrate(ui, repo, amap, *pats, **opts).items()
153 153 if not rate:
154 154 return
155 155
156 keyfn = (not opts.get('sort')) and (lambda (k,v): (v,k)) or None
157 rate.sort(key=keyfn, reverse=not opts.get('sort'))
156 sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None)
157 rate.sort(sortfn)
158 158
159 maxcount = float(max(v for k, v in rate))
160 maxname = max(len(k) for k, v in rate)
159 maxcount = float(max([v for k, v in rate]))
160 maxname = max([len(k) for k, v in rate])
161 161
162 162 ttywidth = get_tty_width()
163 163 ui.debug(_("assuming %i character terminal\n") % ttywidth)
164 164 width = ttywidth - maxname - 2 - 6 - 2 - 2
165 165
166 166 for date, count in rate:
167 167 print "%s %6d %s" % (pad(date, maxname), count,
168 168 "*" * int(count * width / maxcount))
169 169
170 170
171 171 cmdtable = {
172 172 "churn":
173 173 (churn,
174 174 [('r', 'rev', [], _('count rate for the specified revision or range')),
175 175 ('d', 'date', '', _('count rate for revs matching date spec')),
176 176 ('t', 'template', '{author|email}', _('template to group changesets')),
177 177 ('f', 'dateformat', '',
178 178 _('strftime-compatible format for grouping by date')),
179 179 ('c', 'changesets', False, _('count rate by number of changesets')),
180 180 ('s', 'sort', False, _('sort by key (default: sort by count)')),
181 181 ('', 'aliases', '', _('file with email aliases')),
182 182 ('', 'progress', None, _('show progress'))],
183 183 _("hg stats [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")),
184 184 }
General Comments 0
You need to be logged in to leave comments. Login now