##// END OF EJS Templates
templatekw.showdiffstat: use ctx.diff() instead of calling patch
Alexander Solovyov -
r13114:8f29a08e default
parent child Browse files
Show More
@@ -1,270 +1,269
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex
8 from node import hex
9 import encoding, patch, util, error
9 import encoding, patch, util, error
10
10
11 def showlist(name, values, plural=None, **args):
11 def showlist(name, values, plural=None, **args):
12 '''expand set of values.
12 '''expand set of values.
13 name is name of key in template map.
13 name is name of key in template map.
14 values is list of strings or dicts.
14 values is list of strings or dicts.
15 plural is plural of name, if not simply name + 's'.
15 plural is plural of name, if not simply name + 's'.
16
16
17 expansion works like this, given name 'foo'.
17 expansion works like this, given name 'foo'.
18
18
19 if values is empty, expand 'no_foos'.
19 if values is empty, expand 'no_foos'.
20
20
21 if 'foo' not in template map, return values as a string,
21 if 'foo' not in template map, return values as a string,
22 joined by space.
22 joined by space.
23
23
24 expand 'start_foos'.
24 expand 'start_foos'.
25
25
26 for each value, expand 'foo'. if 'last_foo' in template
26 for each value, expand 'foo'. if 'last_foo' in template
27 map, expand it instead of 'foo' for last key.
27 map, expand it instead of 'foo' for last key.
28
28
29 expand 'end_foos'.
29 expand 'end_foos'.
30 '''
30 '''
31 templ = args['templ']
31 templ = args['templ']
32 if plural:
32 if plural:
33 names = plural
33 names = plural
34 else: names = name + 's'
34 else: names = name + 's'
35 if not values:
35 if not values:
36 noname = 'no_' + names
36 noname = 'no_' + names
37 if noname in templ:
37 if noname in templ:
38 yield templ(noname, **args)
38 yield templ(noname, **args)
39 return
39 return
40 if name not in templ:
40 if name not in templ:
41 if isinstance(values[0], str):
41 if isinstance(values[0], str):
42 yield ' '.join(values)
42 yield ' '.join(values)
43 else:
43 else:
44 for v in values:
44 for v in values:
45 yield dict(v, **args)
45 yield dict(v, **args)
46 return
46 return
47 startname = 'start_' + names
47 startname = 'start_' + names
48 if startname in templ:
48 if startname in templ:
49 yield templ(startname, **args)
49 yield templ(startname, **args)
50 vargs = args.copy()
50 vargs = args.copy()
51 def one(v, tag=name):
51 def one(v, tag=name):
52 try:
52 try:
53 vargs.update(v)
53 vargs.update(v)
54 except (AttributeError, ValueError):
54 except (AttributeError, ValueError):
55 try:
55 try:
56 for a, b in v:
56 for a, b in v:
57 vargs[a] = b
57 vargs[a] = b
58 except ValueError:
58 except ValueError:
59 vargs[name] = v
59 vargs[name] = v
60 return templ(tag, **vargs)
60 return templ(tag, **vargs)
61 lastname = 'last_' + name
61 lastname = 'last_' + name
62 if lastname in templ:
62 if lastname in templ:
63 last = values.pop()
63 last = values.pop()
64 else:
64 else:
65 last = None
65 last = None
66 for v in values:
66 for v in values:
67 yield one(v)
67 yield one(v)
68 if last is not None:
68 if last is not None:
69 yield one(last, tag=lastname)
69 yield one(last, tag=lastname)
70 endname = 'end_' + names
70 endname = 'end_' + names
71 if endname in templ:
71 if endname in templ:
72 yield templ(endname, **args)
72 yield templ(endname, **args)
73
73
74 def getfiles(repo, ctx, revcache):
74 def getfiles(repo, ctx, revcache):
75 if 'files' not in revcache:
75 if 'files' not in revcache:
76 revcache['files'] = repo.status(ctx.parents()[0].node(),
76 revcache['files'] = repo.status(ctx.parents()[0].node(),
77 ctx.node())[:3]
77 ctx.node())[:3]
78 return revcache['files']
78 return revcache['files']
79
79
80 def getlatesttags(repo, ctx, cache):
80 def getlatesttags(repo, ctx, cache):
81 '''return date, distance and name for the latest tag of rev'''
81 '''return date, distance and name for the latest tag of rev'''
82
82
83 if 'latesttags' not in cache:
83 if 'latesttags' not in cache:
84 # Cache mapping from rev to a tuple with tag date, tag
84 # Cache mapping from rev to a tuple with tag date, tag
85 # distance and tag name
85 # distance and tag name
86 cache['latesttags'] = {-1: (0, 0, 'null')}
86 cache['latesttags'] = {-1: (0, 0, 'null')}
87 latesttags = cache['latesttags']
87 latesttags = cache['latesttags']
88
88
89 rev = ctx.rev()
89 rev = ctx.rev()
90 todo = [rev]
90 todo = [rev]
91 while todo:
91 while todo:
92 rev = todo.pop()
92 rev = todo.pop()
93 if rev in latesttags:
93 if rev in latesttags:
94 continue
94 continue
95 ctx = repo[rev]
95 ctx = repo[rev]
96 tags = [t for t in ctx.tags() if repo.tagtype(t) == 'global']
96 tags = [t for t in ctx.tags() if repo.tagtype(t) == 'global']
97 if tags:
97 if tags:
98 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
98 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
99 continue
99 continue
100 try:
100 try:
101 # The tuples are laid out so the right one can be found by
101 # The tuples are laid out so the right one can be found by
102 # comparison.
102 # comparison.
103 pdate, pdist, ptag = max(
103 pdate, pdist, ptag = max(
104 latesttags[p.rev()] for p in ctx.parents())
104 latesttags[p.rev()] for p in ctx.parents())
105 except KeyError:
105 except KeyError:
106 # Cache miss - recurse
106 # Cache miss - recurse
107 todo.append(rev)
107 todo.append(rev)
108 todo.extend(p.rev() for p in ctx.parents())
108 todo.extend(p.rev() for p in ctx.parents())
109 continue
109 continue
110 latesttags[rev] = pdate, pdist + 1, ptag
110 latesttags[rev] = pdate, pdist + 1, ptag
111 return latesttags[rev]
111 return latesttags[rev]
112
112
113 def getrenamedfn(repo, endrev=None):
113 def getrenamedfn(repo, endrev=None):
114 rcache = {}
114 rcache = {}
115 if endrev is None:
115 if endrev is None:
116 endrev = len(repo)
116 endrev = len(repo)
117
117
118 def getrenamed(fn, rev):
118 def getrenamed(fn, rev):
119 '''looks up all renames for a file (up to endrev) the first
119 '''looks up all renames for a file (up to endrev) the first
120 time the file is given. It indexes on the changerev and only
120 time the file is given. It indexes on the changerev and only
121 parses the manifest if linkrev != changerev.
121 parses the manifest if linkrev != changerev.
122 Returns rename info for fn at changerev rev.'''
122 Returns rename info for fn at changerev rev.'''
123 if fn not in rcache:
123 if fn not in rcache:
124 rcache[fn] = {}
124 rcache[fn] = {}
125 fl = repo.file(fn)
125 fl = repo.file(fn)
126 for i in fl:
126 for i in fl:
127 lr = fl.linkrev(i)
127 lr = fl.linkrev(i)
128 renamed = fl.renamed(fl.node(i))
128 renamed = fl.renamed(fl.node(i))
129 rcache[fn][lr] = renamed
129 rcache[fn][lr] = renamed
130 if lr >= endrev:
130 if lr >= endrev:
131 break
131 break
132 if rev in rcache[fn]:
132 if rev in rcache[fn]:
133 return rcache[fn][rev]
133 return rcache[fn][rev]
134
134
135 # If linkrev != rev (i.e. rev not found in rcache) fallback to
135 # If linkrev != rev (i.e. rev not found in rcache) fallback to
136 # filectx logic.
136 # filectx logic.
137 try:
137 try:
138 return repo[rev][fn].renamed()
138 return repo[rev][fn].renamed()
139 except error.LookupError:
139 except error.LookupError:
140 return None
140 return None
141
141
142 return getrenamed
142 return getrenamed
143
143
144
144
145 def showauthor(repo, ctx, templ, **args):
145 def showauthor(repo, ctx, templ, **args):
146 return ctx.user()
146 return ctx.user()
147
147
148 def showbranches(**args):
148 def showbranches(**args):
149 branch = args['ctx'].branch()
149 branch = args['ctx'].branch()
150 if branch != 'default':
150 if branch != 'default':
151 return showlist('branch', [branch], plural='branches', **args)
151 return showlist('branch', [branch], plural='branches', **args)
152
152
153 def showchildren(**args):
153 def showchildren(**args):
154 ctx = args['ctx']
154 ctx = args['ctx']
155 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
155 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
156 return showlist('children', childrevs, **args)
156 return showlist('children', childrevs, **args)
157
157
158 def showdate(repo, ctx, templ, **args):
158 def showdate(repo, ctx, templ, **args):
159 return ctx.date()
159 return ctx.date()
160
160
161 def showdescription(repo, ctx, templ, **args):
161 def showdescription(repo, ctx, templ, **args):
162 return ctx.description().strip()
162 return ctx.description().strip()
163
163
164 def showdiffstat(repo, ctx, templ, **args):
164 def showdiffstat(repo, ctx, templ, **args):
165 diff = patch.diff(repo, ctx.parents()[0].node(), ctx.node())
166 files, adds, removes = 0, 0, 0
165 files, adds, removes = 0, 0, 0
167 for i in patch.diffstatdata(util.iterlines(diff)):
166 for i in patch.diffstatdata(util.iterlines(ctx.diff())):
168 files += 1
167 files += 1
169 adds += i[1]
168 adds += i[1]
170 removes += i[2]
169 removes += i[2]
171 return '%s: +%s/-%s' % (files, adds, removes)
170 return '%s: +%s/-%s' % (files, adds, removes)
172
171
173 def showextras(**args):
172 def showextras(**args):
174 templ = args['templ']
173 templ = args['templ']
175 for key, value in sorted(args['ctx'].extra().items()):
174 for key, value in sorted(args['ctx'].extra().items()):
176 args = args.copy()
175 args = args.copy()
177 args.update(dict(key=key, value=value))
176 args.update(dict(key=key, value=value))
178 yield templ('extra', **args)
177 yield templ('extra', **args)
179
178
180 def showfileadds(**args):
179 def showfileadds(**args):
181 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
180 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
182 return showlist('file_add', getfiles(repo, ctx, revcache)[1], **args)
181 return showlist('file_add', getfiles(repo, ctx, revcache)[1], **args)
183
182
184 def showfilecopies(**args):
183 def showfilecopies(**args):
185 cache, ctx = args['cache'], args['ctx']
184 cache, ctx = args['cache'], args['ctx']
186 copies = args['revcache'].get('copies')
185 copies = args['revcache'].get('copies')
187 if copies is None:
186 if copies is None:
188 if 'getrenamed' not in cache:
187 if 'getrenamed' not in cache:
189 cache['getrenamed'] = getrenamedfn(args['repo'])
188 cache['getrenamed'] = getrenamedfn(args['repo'])
190 copies = []
189 copies = []
191 getrenamed = cache['getrenamed']
190 getrenamed = cache['getrenamed']
192 for fn in ctx.files():
191 for fn in ctx.files():
193 rename = getrenamed(fn, ctx.rev())
192 rename = getrenamed(fn, ctx.rev())
194 if rename:
193 if rename:
195 copies.append((fn, rename[0]))
194 copies.append((fn, rename[0]))
196
195
197 c = [{'name': x[0], 'source': x[1]} for x in copies]
196 c = [{'name': x[0], 'source': x[1]} for x in copies]
198 return showlist('file_copy', c, plural='file_copies', **args)
197 return showlist('file_copy', c, plural='file_copies', **args)
199
198
200 # showfilecopiesswitch() displays file copies only if copy records are
199 # showfilecopiesswitch() displays file copies only if copy records are
201 # provided before calling the templater, usually with a --copies
200 # provided before calling the templater, usually with a --copies
202 # command line switch.
201 # command line switch.
203 def showfilecopiesswitch(**args):
202 def showfilecopiesswitch(**args):
204 copies = args['revcache'].get('copies') or []
203 copies = args['revcache'].get('copies') or []
205 c = [{'name': x[0], 'source': x[1]} for x in copies]
204 c = [{'name': x[0], 'source': x[1]} for x in copies]
206 return showlist('file_copy', c, plural='file_copies', **args)
205 return showlist('file_copy', c, plural='file_copies', **args)
207
206
208 def showfiledels(**args):
207 def showfiledels(**args):
209 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
208 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
210 return showlist('file_del', getfiles(repo, ctx, revcache)[2], **args)
209 return showlist('file_del', getfiles(repo, ctx, revcache)[2], **args)
211
210
212 def showfilemods(**args):
211 def showfilemods(**args):
213 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
212 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
214 return showlist('file_mod', getfiles(repo, ctx, revcache)[0], **args)
213 return showlist('file_mod', getfiles(repo, ctx, revcache)[0], **args)
215
214
216 def showfiles(**args):
215 def showfiles(**args):
217 return showlist('file', args['ctx'].files(), **args)
216 return showlist('file', args['ctx'].files(), **args)
218
217
219 def showlatesttag(repo, ctx, templ, cache, **args):
218 def showlatesttag(repo, ctx, templ, cache, **args):
220 return getlatesttags(repo, ctx, cache)[2]
219 return getlatesttags(repo, ctx, cache)[2]
221
220
222 def showlatesttagdistance(repo, ctx, templ, cache, **args):
221 def showlatesttagdistance(repo, ctx, templ, cache, **args):
223 return getlatesttags(repo, ctx, cache)[1]
222 return getlatesttags(repo, ctx, cache)[1]
224
223
225 def showmanifest(**args):
224 def showmanifest(**args):
226 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
225 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
227 args = args.copy()
226 args = args.copy()
228 args.update(dict(rev=repo.manifest.rev(ctx.changeset()[0]),
227 args.update(dict(rev=repo.manifest.rev(ctx.changeset()[0]),
229 node=hex(ctx.changeset()[0])))
228 node=hex(ctx.changeset()[0])))
230 return templ('manifest', **args)
229 return templ('manifest', **args)
231
230
232 def shownode(repo, ctx, templ, **args):
231 def shownode(repo, ctx, templ, **args):
233 return ctx.hex()
232 return ctx.hex()
234
233
235 def showrev(repo, ctx, templ, **args):
234 def showrev(repo, ctx, templ, **args):
236 return ctx.rev()
235 return ctx.rev()
237
236
238 def showtags(**args):
237 def showtags(**args):
239 return showlist('tag', args['ctx'].tags(), **args)
238 return showlist('tag', args['ctx'].tags(), **args)
240
239
241 # keywords are callables like:
240 # keywords are callables like:
242 # fn(repo, ctx, templ, cache, revcache, **args)
241 # fn(repo, ctx, templ, cache, revcache, **args)
243 # with:
242 # with:
244 # repo - current repository instance
243 # repo - current repository instance
245 # ctx - the changectx being displayed
244 # ctx - the changectx being displayed
246 # templ - the templater instance
245 # templ - the templater instance
247 # cache - a cache dictionary for the whole templater run
246 # cache - a cache dictionary for the whole templater run
248 # revcache - a cache dictionary for the current revision
247 # revcache - a cache dictionary for the current revision
249 keywords = {
248 keywords = {
250 'author': showauthor,
249 'author': showauthor,
251 'branches': showbranches,
250 'branches': showbranches,
252 'children': showchildren,
251 'children': showchildren,
253 'date': showdate,
252 'date': showdate,
254 'desc': showdescription,
253 'desc': showdescription,
255 'diffstat': showdiffstat,
254 'diffstat': showdiffstat,
256 'extras': showextras,
255 'extras': showextras,
257 'file_adds': showfileadds,
256 'file_adds': showfileadds,
258 'file_copies': showfilecopies,
257 'file_copies': showfilecopies,
259 'file_copies_switch': showfilecopiesswitch,
258 'file_copies_switch': showfilecopiesswitch,
260 'file_dels': showfiledels,
259 'file_dels': showfiledels,
261 'file_mods': showfilemods,
260 'file_mods': showfilemods,
262 'files': showfiles,
261 'files': showfiles,
263 'latesttag': showlatesttag,
262 'latesttag': showlatesttag,
264 'latesttagdistance': showlatesttagdistance,
263 'latesttagdistance': showlatesttagdistance,
265 'manifest': showmanifest,
264 'manifest': showmanifest,
266 'node': shownode,
265 'node': shownode,
267 'rev': showrev,
266 'rev': showrev,
268 'tags': showtags,
267 'tags': showtags,
269 }
268 }
270
269
General Comments 0
You need to be logged in to leave comments. Login now