Mercurial > hg > mercurial-crew-with-dirclash
annotate contrib/churn.py @ 3612:d1b16a746db6
Add allowed bundle types as argument to hgweb unbundle capability.
Arguments to capabilities were added before the 0.9.1 release, so there
are no compatibility issues. Mercurial 0.9 didn't support http push.
Using HG10GZ, HG10BZ and HG10UN has the advantage that new bundle types can
be added later and the client doesn't have to try sending them first and
reacting on errors sent by the server.
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Thu, 02 Nov 2006 14:39:08 +0100 |
parents | 53e843840349 |
children | 4670470b97bd |
rev | line source |
---|---|
3037 | 1 # churn.py - create a graph showing who changed the most lines |
2 # | |
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 # | |
8 # | |
9 # Aliases map file format is simple one alias per line in the following | |
10 # format: | |
11 # | |
12 # <alias email> <actual email> | |
13 | |
3038
45942bb49194
[churn] Cleanup suggestions from tonfa
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3037
diff
changeset
|
14 from mercurial.demandload import * |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
15 from mercurial.i18n import gettext as _ |
3038
45942bb49194
[churn] Cleanup suggestions from tonfa
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3037
diff
changeset
|
16 demandload(globals(), 'time sys signal os') |
3087
eeaf9bcdfa25
Move revision parsing into cmdutil.
Brendan Cully <brendan@kublai.com>
parents:
3057
diff
changeset
|
17 demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node') |
3037 | 18 |
19 def __gather(ui, repo, node1, node2): | |
20 def dirtywork(f, mmap1, mmap2): | |
21 lines = 0 | |
22 | |
3039
2d35d7c6f251
[churn] Trivial cleanup suggested by Thomas
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3038
diff
changeset
|
23 to = mmap1 and repo.file(f).read(mmap1[f]) or None |
2d35d7c6f251
[churn] Trivial cleanup suggested by Thomas
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3038
diff
changeset
|
24 tn = mmap2 and repo.file(f).read(mmap2[f]) or None |
3037 | 25 |
26 diff = mdiff.unidiff(to, "", tn, "", f).split("\n") | |
27 | |
28 for line in diff: | |
3040
fe0e3508ec6e
[churn] Trivial cleanup
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3039
diff
changeset
|
29 if not line: |
3037 | 30 continue # skip EOF |
3039
2d35d7c6f251
[churn] Trivial cleanup suggested by Thomas
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3038
diff
changeset
|
31 if line.startswith(" "): |
3037 | 32 continue # context line |
3039
2d35d7c6f251
[churn] Trivial cleanup suggested by Thomas
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3038
diff
changeset
|
33 if line.startswith("--- ") or line.startswith("+++ "): |
3037 | 34 continue # begining of diff |
3039
2d35d7c6f251
[churn] Trivial cleanup suggested by Thomas
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3038
diff
changeset
|
35 if line.startswith("@@ "): |
3037 | 36 continue # info line |
37 | |
38 # changed lines | |
39 lines += 1 | |
40 | |
41 return lines | |
42 | |
43 ## | |
44 | |
45 lines = 0 | |
46 | |
3045
8d344bc72e68
[churn] repo.changes was renamed to repo.status
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3043
diff
changeset
|
47 changes = repo.status(node1, node2, None, util.always)[:5] |
3037 | 48 |
49 modified, added, removed, deleted, unknown = changes | |
50 | |
51 who = repo.changelog.read(node2)[1] | |
52 who = templater.email(who) # get the email of the person | |
53 | |
54 mmap1 = repo.manifest.read(repo.changelog.read(node1)[0]) | |
55 mmap2 = repo.manifest.read(repo.changelog.read(node2)[0]) | |
56 for f in modified: | |
57 lines += dirtywork(f, mmap1, mmap2) | |
58 | |
59 for f in added: | |
60 lines += dirtywork(f, None, mmap2) | |
3215
53e843840349
Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3087
diff
changeset
|
61 |
3037 | 62 for f in removed: |
63 lines += dirtywork(f, mmap1, None) | |
64 | |
65 for f in deleted: | |
66 lines += dirtywork(f, mmap1, mmap2) | |
67 | |
68 for f in unknown: | |
69 lines += dirtywork(f, mmap1, mmap2) | |
70 | |
71 return (who, lines) | |
72 | |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
73 def gather_stats(ui, repo, amap, revs=None, progress=False): |
3037 | 74 stats = {} |
3215
53e843840349
Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3087
diff
changeset
|
75 |
3037 | 76 cl = repo.changelog |
77 | |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
78 if not revs: |
3043 | 79 revs = range(0, cl.count()) |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
80 |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
81 nr_revs = len(revs) |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
82 cur_rev = 0 |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
83 |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
84 for rev in revs: |
3048
7ffaf5aba4d8
[churn] Fix progress bar not incrementing when merge cset is encountered
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3047
diff
changeset
|
85 cur_rev += 1 # next revision |
7ffaf5aba4d8
[churn] Fix progress bar not incrementing when merge cset is encountered
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3047
diff
changeset
|
86 |
3037 | 87 node2 = cl.node(rev) |
88 node1 = cl.parents(node2)[0] | |
89 | |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
90 if cl.parents(node2)[1] != node.nullid: |
3046
461573aa02ef
[churn] Ignore merge csets
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3045
diff
changeset
|
91 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,)) |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
92 continue |
3046
461573aa02ef
[churn] Ignore merge csets
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3045
diff
changeset
|
93 |
3037 | 94 who, lines = __gather(ui, repo, node1, node2) |
95 | |
96 # remap the owner if possible | |
97 if amap.has_key(who): | |
98 ui.note("using '%s' alias for '%s'\n" % (amap[who], who)) | |
99 who = amap[who] | |
100 | |
101 if not stats.has_key(who): | |
102 stats[who] = 0 | |
103 stats[who] += lines | |
104 | |
105 ui.note("rev %d: %d lines by %s\n" % (rev, lines, who)) | |
106 | |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
107 if progress: |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
108 if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs): |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
109 ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),)) |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
110 sys.stdout.flush() |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
111 |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
112 if progress: |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
113 ui.write("done\n") |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
114 sys.stdout.flush() |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
115 |
3037 | 116 return stats |
117 | |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
118 def churn(ui, repo, **opts): |
3037 | 119 "Graphs the number of lines changed" |
3215
53e843840349
Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3087
diff
changeset
|
120 |
3037 | 121 def pad(s, l): |
122 if len(s) < l: | |
123 return s + " " * (l-len(s)) | |
124 return s[0:l] | |
125 | |
126 def graph(n, maximum, width, char): | |
127 n = int(n * width / float(maximum)) | |
3215
53e843840349
Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3087
diff
changeset
|
128 |
3037 | 129 return char * (n) |
130 | |
131 def get_aliases(f): | |
132 aliases = {} | |
133 | |
134 for l in f.readlines(): | |
135 l = l.strip() | |
136 alias, actual = l.split(" ") | |
137 aliases[alias] = actual | |
138 | |
139 return aliases | |
3215
53e843840349
Whitespace/Tab cleanup
Thomas Arendsen Hein <thomas@intevation.de>
parents:
3087
diff
changeset
|
140 |
3037 | 141 amap = {} |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
142 aliases = opts.get('aliases') |
3037 | 143 if aliases: |
144 try: | |
145 f = open(aliases,"r") | |
146 except OSError, e: | |
147 print "Error: " + e | |
148 return | |
149 | |
150 amap = get_aliases(f) | |
151 f.close() | |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
152 |
3087
eeaf9bcdfa25
Move revision parsing into cmdutil.
Brendan Cully <brendan@kublai.com>
parents:
3057
diff
changeset
|
153 revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])] |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
154 revs.sort() |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
155 stats = gather_stats(ui, repo, amap, revs, opts.get('progress')) |
3037 | 156 |
157 # make a list of tuples (name, lines) and sort it in descending order | |
158 ordered = stats.items() | |
3057
50e0392d51df
Fix for Python 2.3 compatibility.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents:
3049
diff
changeset
|
159 ordered.sort(lambda x, y: cmp(y[1], x[1])) |
3037 | 160 |
161 maximum = ordered[0][1] | |
162 | |
163 ui.note("Assuming 80 character terminal\n") | |
164 width = 80 - 1 | |
165 | |
166 for i in ordered: | |
167 person = i[0] | |
168 lines = i[1] | |
169 print "%s %6d %s" % (pad(person, 20), lines, | |
170 graph(lines, maximum, width - 20 - 1 - 6 - 2 - 2, '*')) | |
171 | |
172 cmdtable = { | |
173 "churn": | |
174 (churn, | |
3042
c0be8990e819
Add revision range support
Brendan Cully <brendan@kublai.com>
parents:
3040
diff
changeset
|
175 [('r', 'rev', [], _('limit statistics to the specified revisions')), |
3047
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
176 ('', 'aliases', '', _('file with email aliases')), |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
177 ('', 'progress', None, _('show progress'))], |
dd1a142988d3
[churn] progress meter
Josef "Jeff" Sipek <jeffpc@josefsipek.net>
parents:
3046
diff
changeset
|
178 'hg churn [-r revision range] [-a file] [--progress]'), |
3037 | 179 } |