##// END OF EJS Templates
merge with crew-stable
Dirkjan Ochtman -
r9389:7cca9803 merge default
parent child Browse files
Show More
@@ -1,176 +1,177
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 of the
7 7 # GNU General Public License version 2, incorporated herein by reference.
8 8
9 9 '''command to display statistics about repository history'''
10 10
11 11 from mercurial.i18n import _
12 12 from mercurial import patch, cmdutil, util, templater
13 13 import sys, os
14 14 import time, datetime
15 15
16 16 def maketemplater(ui, repo, tmpl):
17 17 tmpl = templater.parsestring(tmpl, quoted=False)
18 18 try:
19 19 t = cmdutil.changeset_templater(ui, repo, False, None, None, False)
20 20 except SyntaxError, inst:
21 21 raise util.Abort(inst.args[0])
22 22 t.use_template(tmpl)
23 23 return t
24 24
25 25 def changedlines(ui, repo, ctx1, ctx2, fns):
26 26 lines = 0
27 27 fmatch = cmdutil.matchfiles(repo, fns)
28 28 diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
29 29 for l in diff.split('\n'):
30 30 if (l.startswith("+") and not l.startswith("+++ ") or
31 31 l.startswith("-") and not l.startswith("--- ")):
32 32 lines += 1
33 33 return lines
34 34
35 35 def countrate(ui, repo, amap, *pats, **opts):
36 36 """Calculate stats"""
37 37 if opts.get('dateformat'):
38 38 def getkey(ctx):
39 39 t, tz = ctx.date()
40 40 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
41 41 return date.strftime(opts['dateformat'])
42 42 else:
43 43 tmpl = opts.get('template', '{author|email}')
44 44 tmpl = maketemplater(ui, repo, tmpl)
45 45 def getkey(ctx):
46 46 ui.pushbuffer()
47 47 tmpl.show(ctx)
48 48 return ui.popbuffer()
49 49
50 50 count = pct = 0
51 51 rate = {}
52 52 df = False
53 53 if opts.get('date'):
54 54 df = util.matchdate(opts['date'])
55 55
56 56 get = util.cachefunc(lambda r: repo[r])
57 57 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
58 58 for st, rev, fns in changeiter:
59 59
60 60 if not st == 'add':
61 61 continue
62 62
63 63 ctx = get(rev)
64 64 if df and not df(ctx.date()[0]): # doesn't match date format
65 65 continue
66 66
67 67 key = getkey(ctx)
68 68 key = amap.get(key, key) # alias remap
69 69 if opts.get('changesets'):
70 70 rate[key] = rate.get(key, 0) + 1
71 71 else:
72 72 parents = ctx.parents()
73 73 if len(parents) > 1:
74 74 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
75 75 continue
76 76
77 77 ctx1 = parents[0]
78 78 lines = changedlines(ui, repo, ctx1, ctx, fns)
79 79 rate[key] = rate.get(key, 0) + lines
80 80
81 81 if opts.get('progress'):
82 82 count += 1
83 83 newpct = int(100.0 * count / max(len(repo), 1))
84 84 if pct < newpct:
85 85 pct = newpct
86 86 ui.write("\r" + _("generating stats: %d%%") % pct)
87 87 sys.stdout.flush()
88 88
89 89 if opts.get('progress'):
90 90 ui.write("\r")
91 91 sys.stdout.flush()
92 92
93 93 return rate
94 94
95 95
96 96 def churn(ui, repo, *pats, **opts):
97 97 '''histogram of changes to the repository
98 98
99 99 This command will display a histogram representing the number
100 100 of changed lines or revisions, grouped according to the given
101 101 template. The default template will group changes by author.
102 102 The --dateformat option may be used to group the results by
103 103 date instead.
104 104
105 105 Statistics are based on the number of changed lines, or
106 106 alternatively the number of matching revisions if the
107 107 --changesets option is specified.
108 108
109 109 Examples::
110 110
111 111 # display count of changed lines for every committer
112 112 hg churn -t '{author|email}'
113 113
114 114 # display daily activity graph
115 115 hg churn -f '%H' -s -c
116 116
117 117 # display activity of developers by month
118 118 hg churn -f '%Y-%m' -s -c
119 119
120 120 # display count of lines changed in every year
121 121 hg churn -f '%Y' -s
122 122
123 123 It is possible to map alternate email addresses to a main address
124 124 by providing a file using the following format::
125 125
126 126 <alias email> <actual email>
127 127
128 128 Such a file may be specified with the --aliases option, otherwise
129 129 a .hgchurn file will be looked for in the working directory root.
130 130 '''
131 131 def pad(s, l):
132 132 return (s + " " * l)[:l]
133 133
134 134 amap = {}
135 135 aliases = opts.get('aliases')
136 136 if not aliases and os.path.exists(repo.wjoin('.hgchurn')):
137 137 aliases = repo.wjoin('.hgchurn')
138 138 if aliases:
139 139 for l in open(aliases, "r"):
140 140 l = l.strip()
141 141 alias, actual = l.split()
142 142 amap[alias] = actual
143 143
144 144 rate = countrate(ui, repo, amap, *pats, **opts).items()
145 145 if not rate:
146 146 return
147 147
148 148 sortkey = ((not opts.get('sort')) and (lambda x: -x[1]) or None)
149 149 rate.sort(key=sortkey)
150 150
151 maxcount = float(max([v for k, v in rate]))
151 # Be careful not to have a zero maxcount (issue833)
152 maxcount = float(max([v for k, v in rate])) or 1.0
152 153 maxname = max([len(k) for k, v in rate])
153 154
154 155 ttywidth = util.termwidth()
155 156 ui.debug(_("assuming %i character terminal\n") % ttywidth)
156 157 width = ttywidth - maxname - 2 - 6 - 2 - 2
157 158
158 159 for date, count in rate:
159 160 print "%s %6d %s" % (pad(date, maxname), count,
160 161 "*" * int(count * width / maxcount))
161 162
162 163
163 164 cmdtable = {
164 165 "churn":
165 166 (churn,
166 167 [('r', 'rev', [], _('count rate for the specified revision or range')),
167 168 ('d', 'date', '', _('count rate for revisions matching date spec')),
168 169 ('t', 'template', '{author|email}', _('template to group changesets')),
169 170 ('f', 'dateformat', '',
170 171 _('strftime-compatible format for grouping by date')),
171 172 ('c', 'changesets', False, _('count rate by number of changesets')),
172 173 ('s', 'sort', False, _('sort by key (default: sort by count)')),
173 174 ('', 'aliases', '', _('file with email aliases')),
174 175 ('', 'progress', None, _('show progress'))],
175 176 _("hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")),
176 177 }
@@ -1,52 +1,62
1 1 #!/bin/sh
2 2
3 3 echo "[extensions]" >> $HGRCPATH
4 4 echo "churn=" >> $HGRCPATH
5 5
6 6 COLUMNS=80; export COLUMNS
7 7
8 8 echo % create test repository
9 9 hg init repo
10 10 cd repo
11 11 echo a > a
12 12 hg ci -Am adda -u user1 -d 6:00
13 13 echo b >> a
14 14 echo b > b
15 15 hg ci -m changeba -u user2 -d 9:00 a
16 16 hg ci -Am addb -u user2 -d 9:30
17 17 echo c >> a
18 18 echo c >> b
19 19 echo c > c
20 20 hg ci -m changeca -u user3 -d 12:00 a
21 21 hg ci -m changecb -u user3 -d 12:15 b
22 22 hg ci -Am addc -u user3 -d 12:30
23 23 mkdir -p d/e
24 24 echo abc > d/e/f1.txt
25 25 hg ci -Am "add d/e/f1.txt" -u user1 -d 12:45 d/e/f1.txt
26 26 mkdir -p d/g
27 27 echo def > d/g/f2.txt
28 28 hg ci -Am "add d/g/f2.txt" -u user1 -d 13:00 d/g/f2.txt
29 29
30 30 echo % churn separate directories
31 31 cd d
32 32 hg churn e
33 33 echo % churn all
34 34 hg churn
35 35 echo % churn up to rev 2
36 36 hg churn -r :2
37 37 cd ..
38 38 echo % churn with aliases
39 39 cat > ../aliases <<EOF
40 40 user1 alias1
41 41 user3 alias3
42 42 EOF
43 43 hg churn --aliases ../aliases
44 44 echo % churn with .hgchurn
45 45 mv ../aliases .hgchurn
46 46 hg churn
47 47 rm .hgchurn
48 48 echo % churn with column specifier
49 49 COLUMNS=40 hg churn
50 50 echo % churn by hour
51 51 hg churn -f '%H' -s
52 52
53 cd ..
54
55 # issue 833: ZeroDivisionError
56 hg init issue-833
57 cd issue-833
58 touch foo
59 hg ci -Am foo
60 # this was failing with a ZeroDivisionError
61 hg churn
62 cd ..
@@ -1,30 +1,32
1 1 % create test repository
2 2 adding a
3 3 adding b
4 4 adding c
5 5 % churn separate directories
6 6 user1 1 ***************************************************************
7 7 % churn all
8 8 user3 3 ***************************************************************
9 9 user1 3 ***************************************************************
10 10 user2 2 ******************************************
11 11 % churn up to rev 2
12 12 user2 2 ***************************************************************
13 13 user1 1 *******************************
14 14 % churn with aliases
15 15 alias3 3 **************************************************************
16 16 alias1 3 **************************************************************
17 17 user2 2 *****************************************
18 18 % churn with .hgchurn
19 19 alias3 3 **************************************************************
20 20 alias1 3 **************************************************************
21 21 user2 2 *****************************************
22 22 % churn with column specifier
23 23 user3 3 ***********************
24 24 user1 3 ***********************
25 25 user2 2 ***************
26 26 % churn by hour
27 27 06 1 ****************
28 28 09 2 *********************************
29 29 12 4 ******************************************************************
30 30 13 1 ****************
31 adding foo
32 test 0
General Comments 0
You need to be logged in to leave comments. Login now