##// END OF EJS Templates
help: drop help for branches template keyword...
Matt Mackall -
r20078:43e872a3 default
parent child Browse files
Show More
@@ -1,395 +1,396 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import hex
9 9 import patch, util, error
10 10 import hbisect
11 11
12 12 # This helper class allows us to handle both:
13 13 # "{files}" (legacy command-line-specific list hack) and
14 14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
15 15
16 16 class _hybrid(object):
17 17 def __init__(self, gen, values, joinfmt=None):
18 18 self.gen = gen
19 19 self.values = values
20 20 if joinfmt:
21 21 self.joinfmt = joinfmt
22 22 else:
23 23 self.joinfmt = lambda x: x.values()[0]
24 24 def __iter__(self):
25 25 return self.gen
26 26 def __call__(self):
27 27 for x in self.values:
28 28 yield x
29 29
30 30 def showlist(name, values, plural=None, element=None, **args):
31 31 if not element:
32 32 element = name
33 33 f = _showlist(name, values, plural, **args)
34 34 return _hybrid(f, [{element: x} for x in values])
35 35
36 36 def _showlist(name, values, plural=None, **args):
37 37 '''expand set of values.
38 38 name is name of key in template map.
39 39 values is list of strings or dicts.
40 40 plural is plural of name, if not simply name + 's'.
41 41
42 42 expansion works like this, given name 'foo'.
43 43
44 44 if values is empty, expand 'no_foos'.
45 45
46 46 if 'foo' not in template map, return values as a string,
47 47 joined by space.
48 48
49 49 expand 'start_foos'.
50 50
51 51 for each value, expand 'foo'. if 'last_foo' in template
52 52 map, expand it instead of 'foo' for last key.
53 53
54 54 expand 'end_foos'.
55 55 '''
56 56 templ = args['templ']
57 57 if plural:
58 58 names = plural
59 59 else: names = name + 's'
60 60 if not values:
61 61 noname = 'no_' + names
62 62 if noname in templ:
63 63 yield templ(noname, **args)
64 64 return
65 65 if name not in templ:
66 66 if isinstance(values[0], str):
67 67 yield ' '.join(values)
68 68 else:
69 69 for v in values:
70 70 yield dict(v, **args)
71 71 return
72 72 startname = 'start_' + names
73 73 if startname in templ:
74 74 yield templ(startname, **args)
75 75 vargs = args.copy()
76 76 def one(v, tag=name):
77 77 try:
78 78 vargs.update(v)
79 79 except (AttributeError, ValueError):
80 80 try:
81 81 for a, b in v:
82 82 vargs[a] = b
83 83 except ValueError:
84 84 vargs[name] = v
85 85 return templ(tag, **vargs)
86 86 lastname = 'last_' + name
87 87 if lastname in templ:
88 88 last = values.pop()
89 89 else:
90 90 last = None
91 91 for v in values:
92 92 yield one(v)
93 93 if last is not None:
94 94 yield one(last, tag=lastname)
95 95 endname = 'end_' + names
96 96 if endname in templ:
97 97 yield templ(endname, **args)
98 98
99 99 def getfiles(repo, ctx, revcache):
100 100 if 'files' not in revcache:
101 101 revcache['files'] = repo.status(ctx.p1().node(), ctx.node())[:3]
102 102 return revcache['files']
103 103
104 104 def getlatesttags(repo, ctx, cache):
105 105 '''return date, distance and name for the latest tag of rev'''
106 106
107 107 if 'latesttags' not in cache:
108 108 # Cache mapping from rev to a tuple with tag date, tag
109 109 # distance and tag name
110 110 cache['latesttags'] = {-1: (0, 0, 'null')}
111 111 latesttags = cache['latesttags']
112 112
113 113 rev = ctx.rev()
114 114 todo = [rev]
115 115 while todo:
116 116 rev = todo.pop()
117 117 if rev in latesttags:
118 118 continue
119 119 ctx = repo[rev]
120 120 tags = [t for t in ctx.tags() if repo.tagtype(t) == 'global']
121 121 if tags:
122 122 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
123 123 continue
124 124 try:
125 125 # The tuples are laid out so the right one can be found by
126 126 # comparison.
127 127 pdate, pdist, ptag = max(
128 128 latesttags[p.rev()] for p in ctx.parents())
129 129 except KeyError:
130 130 # Cache miss - recurse
131 131 todo.append(rev)
132 132 todo.extend(p.rev() for p in ctx.parents())
133 133 continue
134 134 latesttags[rev] = pdate, pdist + 1, ptag
135 135 return latesttags[rev]
136 136
137 137 def getrenamedfn(repo, endrev=None):
138 138 rcache = {}
139 139 if endrev is None:
140 140 endrev = len(repo)
141 141
142 142 def getrenamed(fn, rev):
143 143 '''looks up all renames for a file (up to endrev) the first
144 144 time the file is given. It indexes on the changerev and only
145 145 parses the manifest if linkrev != changerev.
146 146 Returns rename info for fn at changerev rev.'''
147 147 if fn not in rcache:
148 148 rcache[fn] = {}
149 149 fl = repo.file(fn)
150 150 for i in fl:
151 151 lr = fl.linkrev(i)
152 152 renamed = fl.renamed(fl.node(i))
153 153 rcache[fn][lr] = renamed
154 154 if lr >= endrev:
155 155 break
156 156 if rev in rcache[fn]:
157 157 return rcache[fn][rev]
158 158
159 159 # If linkrev != rev (i.e. rev not found in rcache) fallback to
160 160 # filectx logic.
161 161 try:
162 162 return repo[rev][fn].renamed()
163 163 except error.LookupError:
164 164 return None
165 165
166 166 return getrenamed
167 167
168 168
169 169 def showauthor(repo, ctx, templ, **args):
170 170 """:author: String. The unmodified author of the changeset."""
171 171 return ctx.user()
172 172
173 173 def showbisect(repo, ctx, templ, **args):
174 174 """:bisect: String. The changeset bisection status."""
175 175 return hbisect.label(repo, ctx.node())
176 176
177 177 def showbranch(**args):
178 178 """:branch: String. The name of the branch on which the changeset was
179 179 committed.
180 180 """
181 181 return args['ctx'].branch()
182 182
183 183 def showbranches(**args):
184 184 """:branches: List of strings. The name of the branch on which the
185 185 changeset was committed. Will be empty if the branch name was
186 186 default.
187 187 """
188 188 branch = args['ctx'].branch()
189 189 if branch != 'default':
190 190 return showlist('branch', [branch], plural='branches', **args)
191 191
192 192 def showbookmarks(**args):
193 193 """:bookmarks: List of strings. Any bookmarks associated with the
194 194 changeset.
195 195 """
196 196 bookmarks = args['ctx'].bookmarks()
197 197 return showlist('bookmark', bookmarks, **args)
198 198
199 199 def showchildren(**args):
200 200 """:children: List of strings. The children of the changeset."""
201 201 ctx = args['ctx']
202 202 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
203 203 return showlist('children', childrevs, element='child', **args)
204 204
205 205 def showdate(repo, ctx, templ, **args):
206 206 """:date: Date information. The date when the changeset was committed."""
207 207 return ctx.date()
208 208
209 209 def showdescription(repo, ctx, templ, **args):
210 210 """:desc: String. The text of the changeset description."""
211 211 return ctx.description().strip()
212 212
213 213 def showdiffstat(repo, ctx, templ, **args):
214 214 """:diffstat: String. Statistics of changes with the following format:
215 215 "modified files: +added/-removed lines"
216 216 """
217 217 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
218 218 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
219 219 return '%s: +%s/-%s' % (len(stats), adds, removes)
220 220
221 221 def showextras(**args):
222 222 """:extras: List of dicts with key, value entries of the 'extras'
223 223 field of this changeset."""
224 224 yield showlist('extra', sorted(dict(key=a, value=b)
225 225 for (a, b) in args['ctx'].extra().items()), **args)
226 226
227 227 def showfileadds(**args):
228 228 """:file_adds: List of strings. Files added by this changeset."""
229 229 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
230 230 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
231 231 element='file', **args)
232 232
233 233 def showfilecopies(**args):
234 234 """:file_copies: List of strings. Files copied in this changeset with
235 235 their sources.
236 236 """
237 237 cache, ctx = args['cache'], args['ctx']
238 238 copies = args['revcache'].get('copies')
239 239 if copies is None:
240 240 if 'getrenamed' not in cache:
241 241 cache['getrenamed'] = getrenamedfn(args['repo'])
242 242 copies = []
243 243 getrenamed = cache['getrenamed']
244 244 for fn in ctx.files():
245 245 rename = getrenamed(fn, ctx.rev())
246 246 if rename:
247 247 copies.append((fn, rename[0]))
248 248
249 249 c = [{'name': x[0], 'source': x[1]} for x in copies]
250 250 f = _showlist('file_copy', c, plural='file_copies', **args)
251 251 return _hybrid(f, c, lambda x: '%s (%s)' % (x['name'], x['source']))
252 252
253 253 # showfilecopiesswitch() displays file copies only if copy records are
254 254 # provided before calling the templater, usually with a --copies
255 255 # command line switch.
256 256 def showfilecopiesswitch(**args):
257 257 """:file_copies_switch: List of strings. Like "file_copies" but displayed
258 258 only if the --copied switch is set.
259 259 """
260 260 copies = args['revcache'].get('copies') or []
261 261 c = [{'name': x[0], 'source': x[1]} for x in copies]
262 262 f = _showlist('file_copy', c, plural='file_copies', **args)
263 263 return _hybrid(f, c, lambda x: '%s (%s)' % (x['name'], x['source']))
264 264
265 265 def showfiledels(**args):
266 266 """:file_dels: List of strings. Files removed by this changeset."""
267 267 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
268 268 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
269 269 element='file', **args)
270 270
271 271 def showfilemods(**args):
272 272 """:file_mods: List of strings. Files modified by this changeset."""
273 273 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
274 274 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
275 275 element='file', **args)
276 276
277 277 def showfiles(**args):
278 278 """:files: List of strings. All files modified, added, or removed by this
279 279 changeset.
280 280 """
281 281 return showlist('file', args['ctx'].files(), **args)
282 282
283 283 def showlatesttag(repo, ctx, templ, cache, **args):
284 284 """:latesttag: String. Most recent global tag in the ancestors of this
285 285 changeset.
286 286 """
287 287 return getlatesttags(repo, ctx, cache)[2]
288 288
289 289 def showlatesttagdistance(repo, ctx, templ, cache, **args):
290 290 """:latesttagdistance: Integer. Longest path to the latest tag."""
291 291 return getlatesttags(repo, ctx, cache)[1]
292 292
293 293 def showmanifest(**args):
294 294 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
295 295 args = args.copy()
296 296 args.update(dict(rev=repo.manifest.rev(ctx.changeset()[0]),
297 297 node=hex(ctx.changeset()[0])))
298 298 return templ('manifest', **args)
299 299
300 300 def shownode(repo, ctx, templ, **args):
301 301 """:node: String. The changeset identification hash, as a 40 hexadecimal
302 302 digit string.
303 303 """
304 304 return ctx.hex()
305 305
306 306 def showp1rev(repo, ctx, templ, **args):
307 307 """:p1rev: Integer. The repository-local revision number of the changeset's
308 308 first parent, or -1 if the changeset has no parents."""
309 309 return ctx.p1().rev()
310 310
311 311 def showp2rev(repo, ctx, templ, **args):
312 312 """:p2rev: Integer. The repository-local revision number of the changeset's
313 313 second parent, or -1 if the changeset has no second parent."""
314 314 return ctx.p2().rev()
315 315
316 316 def showp1node(repo, ctx, templ, **args):
317 317 """:p1node: String. The identification hash of the changeset's first parent,
318 318 as a 40 digit hexadecimal string. If the changeset has no parents, all
319 319 digits are 0."""
320 320 return ctx.p1().hex()
321 321
322 322 def showp2node(repo, ctx, templ, **args):
323 323 """:p2node: String. The identification hash of the changeset's second
324 324 parent, as a 40 digit hexadecimal string. If the changeset has no second
325 325 parent, all digits are 0."""
326 326 return ctx.p2().hex()
327 327
328 328 def showphase(repo, ctx, templ, **args):
329 329 """:phase: String. The changeset phase name."""
330 330 return ctx.phasestr()
331 331
332 332 def showphaseidx(repo, ctx, templ, **args):
333 333 """:phaseidx: Integer. The changeset phase index."""
334 334 return ctx.phase()
335 335
336 336 def showrev(repo, ctx, templ, **args):
337 337 """:rev: Integer. The repository-local changeset revision number."""
338 338 return ctx.rev()
339 339
340 340 def showtags(**args):
341 341 """:tags: List of strings. Any tags associated with the changeset."""
342 342 return showlist('tag', args['ctx'].tags(), **args)
343 343
344 344 # keywords are callables like:
345 345 # fn(repo, ctx, templ, cache, revcache, **args)
346 346 # with:
347 347 # repo - current repository instance
348 348 # ctx - the changectx being displayed
349 349 # templ - the templater instance
350 350 # cache - a cache dictionary for the whole templater run
351 351 # revcache - a cache dictionary for the current revision
352 352 keywords = {
353 353 'author': showauthor,
354 354 'bisect': showbisect,
355 355 'branch': showbranch,
356 356 'branches': showbranches,
357 357 'bookmarks': showbookmarks,
358 358 'children': showchildren,
359 359 'date': showdate,
360 360 'desc': showdescription,
361 361 'diffstat': showdiffstat,
362 362 'extras': showextras,
363 363 'file_adds': showfileadds,
364 364 'file_copies': showfilecopies,
365 365 'file_copies_switch': showfilecopiesswitch,
366 366 'file_dels': showfiledels,
367 367 'file_mods': showfilemods,
368 368 'files': showfiles,
369 369 'latesttag': showlatesttag,
370 370 'latesttagdistance': showlatesttagdistance,
371 371 'manifest': showmanifest,
372 372 'node': shownode,
373 373 'p1rev': showp1rev,
374 374 'p1node': showp1node,
375 375 'p2rev': showp2rev,
376 376 'p2node': showp2node,
377 377 'phase': showphase,
378 378 'phaseidx': showphaseidx,
379 379 'rev': showrev,
380 380 'tags': showtags,
381 381 }
382 382
383 383 def _showparents(**args):
384 384 """:parents: List of strings. The parents of the changeset in "rev:node"
385 385 format. If the changeset has only one "natural" parent (the predecessor
386 386 revision) nothing is shown."""
387 387 pass
388 388
389 389 dockeywords = {
390 390 'parents': _showparents,
391 391 }
392 392 dockeywords.update(keywords)
393 del dockeywords['branches']
393 394
394 395 # tell hggettext to extract docstrings from these functions:
395 396 i18nfunctions = dockeywords.values()
General Comments 0
You need to be logged in to leave comments. Login now