##// END OF EJS Templates
templatekw: add p1/p2 keywords which switches the current ctx...
Yuya Nishihara -
r40510:539efc88 default
parent child Browse files
Show More
@@ -1,860 +1,874 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 __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import (
12 12 hex,
13 13 nullid,
14 14 wdirid,
15 15 wdirrev,
16 16 )
17 17
18 18 from . import (
19 19 diffutil,
20 20 encoding,
21 21 error,
22 22 hbisect,
23 23 i18n,
24 24 obsutil,
25 25 patch,
26 26 pycompat,
27 27 registrar,
28 28 scmutil,
29 29 templateutil,
30 30 util,
31 31 )
32 32 from .utils import (
33 33 stringutil,
34 34 )
35 35
36 36 _hybrid = templateutil.hybrid
37 37 hybriddict = templateutil.hybriddict
38 38 hybridlist = templateutil.hybridlist
39 39 compatdict = templateutil.compatdict
40 40 compatlist = templateutil.compatlist
41 41 _showcompatlist = templateutil._showcompatlist
42 42
43 43 def getlatesttags(context, mapping, pattern=None):
44 44 '''return date, distance and name for the latest tag of rev'''
45 45 repo = context.resource(mapping, 'repo')
46 46 ctx = context.resource(mapping, 'ctx')
47 47 cache = context.resource(mapping, 'cache')
48 48
49 49 cachename = 'latesttags'
50 50 if pattern is not None:
51 51 cachename += '-' + pattern
52 52 match = stringutil.stringmatcher(pattern)[2]
53 53 else:
54 54 match = util.always
55 55
56 56 if cachename not in cache:
57 57 # Cache mapping from rev to a tuple with tag date, tag
58 58 # distance and tag name
59 59 cache[cachename] = {-1: (0, 0, ['null'])}
60 60 latesttags = cache[cachename]
61 61
62 62 rev = ctx.rev()
63 63 todo = [rev]
64 64 while todo:
65 65 rev = todo.pop()
66 66 if rev in latesttags:
67 67 continue
68 68 ctx = repo[rev]
69 69 tags = [t for t in ctx.tags()
70 70 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
71 71 and match(t))]
72 72 if tags:
73 73 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
74 74 continue
75 75 try:
76 76 ptags = [latesttags[p.rev()] for p in ctx.parents()]
77 77 if len(ptags) > 1:
78 78 if ptags[0][2] == ptags[1][2]:
79 79 # The tuples are laid out so the right one can be found by
80 80 # comparison in this case.
81 81 pdate, pdist, ptag = max(ptags)
82 82 else:
83 83 def key(x):
84 84 changessincetag = len(repo.revs('only(%d, %s)',
85 85 ctx.rev(), x[2][0]))
86 86 # Smallest number of changes since tag wins. Date is
87 87 # used as tiebreaker.
88 88 return [-changessincetag, x[0]]
89 89 pdate, pdist, ptag = max(ptags, key=key)
90 90 else:
91 91 pdate, pdist, ptag = ptags[0]
92 92 except KeyError:
93 93 # Cache miss - recurse
94 94 todo.append(rev)
95 95 todo.extend(p.rev() for p in ctx.parents())
96 96 continue
97 97 latesttags[rev] = pdate, pdist + 1, ptag
98 98 return latesttags[rev]
99 99
100 100 def getrenamedfn(repo, endrev=None):
101 101 rcache = {}
102 102 if endrev is None:
103 103 endrev = len(repo)
104 104
105 105 def getrenamed(fn, rev):
106 106 '''looks up all renames for a file (up to endrev) the first
107 107 time the file is given. It indexes on the changerev and only
108 108 parses the manifest if linkrev != changerev.
109 109 Returns rename info for fn at changerev rev.'''
110 110 if fn not in rcache:
111 111 rcache[fn] = {}
112 112 fl = repo.file(fn)
113 113 for i in fl:
114 114 lr = fl.linkrev(i)
115 115 renamed = fl.renamed(fl.node(i))
116 116 rcache[fn][lr] = renamed and renamed[0]
117 117 if lr >= endrev:
118 118 break
119 119 if rev in rcache[fn]:
120 120 return rcache[fn][rev]
121 121
122 122 # If linkrev != rev (i.e. rev not found in rcache) fallback to
123 123 # filectx logic.
124 124 try:
125 125 renamed = repo[rev][fn].renamed()
126 126 return renamed and renamed[0]
127 127 except error.LookupError:
128 128 return None
129 129
130 130 return getrenamed
131 131
132 132 def getlogcolumns():
133 133 """Return a dict of log column labels"""
134 134 _ = pycompat.identity # temporarily disable gettext
135 135 # i18n: column positioning for "hg log"
136 136 columns = _('bookmark: %s\n'
137 137 'branch: %s\n'
138 138 'changeset: %s\n'
139 139 'copies: %s\n'
140 140 'date: %s\n'
141 141 'extra: %s=%s\n'
142 142 'files+: %s\n'
143 143 'files-: %s\n'
144 144 'files: %s\n'
145 145 'instability: %s\n'
146 146 'manifest: %s\n'
147 147 'obsolete: %s\n'
148 148 'parent: %s\n'
149 149 'phase: %s\n'
150 150 'summary: %s\n'
151 151 'tag: %s\n'
152 152 'user: %s\n')
153 153 return dict(zip([s.split(':', 1)[0] for s in columns.splitlines()],
154 154 i18n._(columns).splitlines(True)))
155 155
156 156 # basic internal templates
157 157 _changeidtmpl = '{rev}:{node|formatnode}'
158 158
159 159 # default templates internally used for rendering of lists
160 160 defaulttempl = {
161 161 'parent': _changeidtmpl + ' ',
162 162 'manifest': _changeidtmpl,
163 163 'file_copy': '{name} ({source})',
164 164 'envvar': '{key}={value}',
165 165 'extra': '{key}={value|stringescape}'
166 166 }
167 167 # filecopy is preserved for compatibility reasons
168 168 defaulttempl['filecopy'] = defaulttempl['file_copy']
169 169
170 170 # keywords are callables (see registrar.templatekeyword for details)
171 171 keywords = {}
172 172 templatekeyword = registrar.templatekeyword(keywords)
173 173
174 174 @templatekeyword('author', requires={'ctx'})
175 175 def showauthor(context, mapping):
176 176 """Alias for ``{user}``"""
177 177 return showuser(context, mapping)
178 178
179 179 @templatekeyword('bisect', requires={'repo', 'ctx'})
180 180 def showbisect(context, mapping):
181 181 """String. The changeset bisection status."""
182 182 repo = context.resource(mapping, 'repo')
183 183 ctx = context.resource(mapping, 'ctx')
184 184 return hbisect.label(repo, ctx.node())
185 185
186 186 @templatekeyword('branch', requires={'ctx'})
187 187 def showbranch(context, mapping):
188 188 """String. The name of the branch on which the changeset was
189 189 committed.
190 190 """
191 191 ctx = context.resource(mapping, 'ctx')
192 192 return ctx.branch()
193 193
194 194 @templatekeyword('branches', requires={'ctx'})
195 195 def showbranches(context, mapping):
196 196 """List of strings. The name of the branch on which the
197 197 changeset was committed. Will be empty if the branch name was
198 198 default. (DEPRECATED)
199 199 """
200 200 ctx = context.resource(mapping, 'ctx')
201 201 branch = ctx.branch()
202 202 if branch != 'default':
203 203 return compatlist(context, mapping, 'branch', [branch],
204 204 plural='branches')
205 205 return compatlist(context, mapping, 'branch', [], plural='branches')
206 206
207 207 @templatekeyword('bookmarks', requires={'repo', 'ctx'})
208 208 def showbookmarks(context, mapping):
209 209 """List of strings. Any bookmarks associated with the
210 210 changeset. Also sets 'active', the name of the active bookmark.
211 211 """
212 212 repo = context.resource(mapping, 'repo')
213 213 ctx = context.resource(mapping, 'ctx')
214 214 bookmarks = ctx.bookmarks()
215 215 active = repo._activebookmark
216 216 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
217 217 f = _showcompatlist(context, mapping, 'bookmark', bookmarks)
218 218 return _hybrid(f, bookmarks, makemap, pycompat.identity)
219 219
220 220 @templatekeyword('children', requires={'ctx'})
221 221 def showchildren(context, mapping):
222 222 """List of strings. The children of the changeset."""
223 223 ctx = context.resource(mapping, 'ctx')
224 224 childrevs = ['%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
225 225 return compatlist(context, mapping, 'children', childrevs, element='child')
226 226
227 227 # Deprecated, but kept alive for help generation a purpose.
228 228 @templatekeyword('currentbookmark', requires={'repo', 'ctx'})
229 229 def showcurrentbookmark(context, mapping):
230 230 """String. The active bookmark, if it is associated with the changeset.
231 231 (DEPRECATED)"""
232 232 return showactivebookmark(context, mapping)
233 233
234 234 @templatekeyword('activebookmark', requires={'repo', 'ctx'})
235 235 def showactivebookmark(context, mapping):
236 236 """String. The active bookmark, if it is associated with the changeset."""
237 237 repo = context.resource(mapping, 'repo')
238 238 ctx = context.resource(mapping, 'ctx')
239 239 active = repo._activebookmark
240 240 if active and active in ctx.bookmarks():
241 241 return active
242 242 return ''
243 243
244 244 @templatekeyword('date', requires={'ctx'})
245 245 def showdate(context, mapping):
246 246 """Date information. The date when the changeset was committed."""
247 247 ctx = context.resource(mapping, 'ctx')
248 248 # the default string format is '<float(unixtime)><tzoffset>' because
249 249 # python-hglib splits date at decimal separator.
250 250 return templateutil.date(ctx.date(), showfmt='%d.0%d')
251 251
252 252 @templatekeyword('desc', requires={'ctx'})
253 253 def showdescription(context, mapping):
254 254 """String. The text of the changeset description."""
255 255 ctx = context.resource(mapping, 'ctx')
256 256 s = ctx.description()
257 257 if isinstance(s, encoding.localstr):
258 258 # try hard to preserve utf-8 bytes
259 259 return encoding.tolocal(encoding.fromlocal(s).strip())
260 260 elif isinstance(s, encoding.safelocalstr):
261 261 return encoding.safelocalstr(s.strip())
262 262 else:
263 263 return s.strip()
264 264
265 265 @templatekeyword('diffstat', requires={'ui', 'ctx'})
266 266 def showdiffstat(context, mapping):
267 267 """String. Statistics of changes with the following format:
268 268 "modified files: +added/-removed lines"
269 269 """
270 270 ui = context.resource(mapping, 'ui')
271 271 ctx = context.resource(mapping, 'ctx')
272 272 diffopts = diffutil.diffallopts(ui, {'noprefix': False})
273 273 diff = ctx.diff(opts=diffopts)
274 274 stats = patch.diffstatdata(util.iterlines(diff))
275 275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
276 276 return '%d: +%d/-%d' % (len(stats), adds, removes)
277 277
278 278 @templatekeyword('envvars', requires={'ui'})
279 279 def showenvvars(context, mapping):
280 280 """A dictionary of environment variables. (EXPERIMENTAL)"""
281 281 ui = context.resource(mapping, 'ui')
282 282 env = ui.exportableenviron()
283 283 env = util.sortdict((k, env[k]) for k in sorted(env))
284 284 return compatdict(context, mapping, 'envvar', env, plural='envvars')
285 285
286 286 @templatekeyword('extras', requires={'ctx'})
287 287 def showextras(context, mapping):
288 288 """List of dicts with key, value entries of the 'extras'
289 289 field of this changeset."""
290 290 ctx = context.resource(mapping, 'ctx')
291 291 extras = ctx.extra()
292 292 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
293 293 makemap = lambda k: {'key': k, 'value': extras[k]}
294 294 c = [makemap(k) for k in extras]
295 295 f = _showcompatlist(context, mapping, 'extra', c, plural='extras')
296 296 return _hybrid(f, extras, makemap,
297 297 lambda k: '%s=%s' % (k, stringutil.escapestr(extras[k])))
298 298
299 299 def _getfilestatus(context, mapping, listall=False):
300 300 ctx = context.resource(mapping, 'ctx')
301 301 revcache = context.resource(mapping, 'revcache')
302 302 if 'filestatus' not in revcache or revcache['filestatusall'] < listall:
303 303 stat = ctx.p1().status(ctx, listignored=listall, listclean=listall,
304 304 listunknown=listall)
305 305 revcache['filestatus'] = stat
306 306 revcache['filestatusall'] = listall
307 307 return revcache['filestatus']
308 308
309 309 def _getfilestatusmap(context, mapping, listall=False):
310 310 revcache = context.resource(mapping, 'revcache')
311 311 if 'filestatusmap' not in revcache or revcache['filestatusall'] < listall:
312 312 stat = _getfilestatus(context, mapping, listall=listall)
313 313 revcache['filestatusmap'] = statmap = {}
314 314 for char, files in zip(pycompat.iterbytestr('MAR!?IC'), stat):
315 315 statmap.update((f, char) for f in files)
316 316 return revcache['filestatusmap'] # {path: statchar}
317 317
318 318 def _showfilesbystat(context, mapping, name, index):
319 319 stat = _getfilestatus(context, mapping)
320 320 files = stat[index]
321 321 return templateutil.compatfileslist(context, mapping, name, files)
322 322
323 323 @templatekeyword('file_adds', requires={'ctx', 'revcache'})
324 324 def showfileadds(context, mapping):
325 325 """List of strings. Files added by this changeset."""
326 326 return _showfilesbystat(context, mapping, 'file_add', 1)
327 327
328 328 @templatekeyword('file_copies',
329 329 requires={'repo', 'ctx', 'cache', 'revcache'})
330 330 def showfilecopies(context, mapping):
331 331 """List of strings. Files copied in this changeset with
332 332 their sources.
333 333 """
334 334 repo = context.resource(mapping, 'repo')
335 335 ctx = context.resource(mapping, 'ctx')
336 336 cache = context.resource(mapping, 'cache')
337 337 copies = context.resource(mapping, 'revcache').get('copies')
338 338 if copies is None:
339 339 if 'getrenamed' not in cache:
340 340 cache['getrenamed'] = getrenamedfn(repo)
341 341 copies = []
342 342 getrenamed = cache['getrenamed']
343 343 for fn in ctx.files():
344 344 rename = getrenamed(fn, ctx.rev())
345 345 if rename:
346 346 copies.append((fn, rename))
347 347 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
348 348 copies)
349 349
350 350 # showfilecopiesswitch() displays file copies only if copy records are
351 351 # provided before calling the templater, usually with a --copies
352 352 # command line switch.
353 353 @templatekeyword('file_copies_switch', requires={'revcache'})
354 354 def showfilecopiesswitch(context, mapping):
355 355 """List of strings. Like "file_copies" but displayed
356 356 only if the --copied switch is set.
357 357 """
358 358 copies = context.resource(mapping, 'revcache').get('copies') or []
359 359 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
360 360 copies)
361 361
362 362 @templatekeyword('file_dels', requires={'ctx', 'revcache'})
363 363 def showfiledels(context, mapping):
364 364 """List of strings. Files removed by this changeset."""
365 365 return _showfilesbystat(context, mapping, 'file_del', 2)
366 366
367 367 @templatekeyword('file_mods', requires={'ctx', 'revcache'})
368 368 def showfilemods(context, mapping):
369 369 """List of strings. Files modified by this changeset."""
370 370 return _showfilesbystat(context, mapping, 'file_mod', 0)
371 371
372 372 @templatekeyword('files', requires={'ctx'})
373 373 def showfiles(context, mapping):
374 374 """List of strings. All files modified, added, or removed by this
375 375 changeset.
376 376 """
377 377 ctx = context.resource(mapping, 'ctx')
378 378 return templateutil.compatfileslist(context, mapping, 'file', ctx.files())
379 379
380 380 @templatekeyword('graphnode', requires={'repo', 'ctx'})
381 381 def showgraphnode(context, mapping):
382 382 """String. The character representing the changeset node in an ASCII
383 383 revision graph."""
384 384 repo = context.resource(mapping, 'repo')
385 385 ctx = context.resource(mapping, 'ctx')
386 386 return getgraphnode(repo, ctx)
387 387
388 388 def getgraphnode(repo, ctx):
389 389 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx)
390 390
391 391 def getgraphnodecurrent(repo, ctx):
392 392 wpnodes = repo.dirstate.parents()
393 393 if wpnodes[1] == nullid:
394 394 wpnodes = wpnodes[:1]
395 395 if ctx.node() in wpnodes:
396 396 return '@'
397 397 else:
398 398 return ''
399 399
400 400 def getgraphnodesymbol(ctx):
401 401 if ctx.obsolete():
402 402 return 'x'
403 403 elif ctx.isunstable():
404 404 return '*'
405 405 elif ctx.closesbranch():
406 406 return '_'
407 407 else:
408 408 return 'o'
409 409
410 410 @templatekeyword('graphwidth', requires=())
411 411 def showgraphwidth(context, mapping):
412 412 """Integer. The width of the graph drawn by 'log --graph' or zero."""
413 413 # just hosts documentation; should be overridden by template mapping
414 414 return 0
415 415
416 416 @templatekeyword('index', requires=())
417 417 def showindex(context, mapping):
418 418 """Integer. The current iteration of the loop. (0 indexed)"""
419 419 # just hosts documentation; should be overridden by template mapping
420 420 raise error.Abort(_("can't use index in this context"))
421 421
422 422 @templatekeyword('latesttag', requires={'repo', 'ctx', 'cache'})
423 423 def showlatesttag(context, mapping):
424 424 """List of strings. The global tags on the most recent globally
425 425 tagged ancestor of this changeset. If no such tags exist, the list
426 426 consists of the single string "null".
427 427 """
428 428 return showlatesttags(context, mapping, None)
429 429
430 430 def showlatesttags(context, mapping, pattern):
431 431 """helper method for the latesttag keyword and function"""
432 432 latesttags = getlatesttags(context, mapping, pattern)
433 433
434 434 # latesttag[0] is an implementation detail for sorting csets on different
435 435 # branches in a stable manner- it is the date the tagged cset was created,
436 436 # not the date the tag was created. Therefore it isn't made visible here.
437 437 makemap = lambda v: {
438 438 'changes': _showchangessincetag,
439 439 'distance': latesttags[1],
440 440 'latesttag': v, # BC with {latesttag % '{latesttag}'}
441 441 'tag': v
442 442 }
443 443
444 444 tags = latesttags[2]
445 445 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':')
446 446 return _hybrid(f, tags, makemap, pycompat.identity)
447 447
448 448 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'})
449 449 def showlatesttagdistance(context, mapping):
450 450 """Integer. Longest path to the latest tag."""
451 451 return getlatesttags(context, mapping)[1]
452 452
453 453 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
454 454 def showchangessincelatesttag(context, mapping):
455 455 """Integer. All ancestors not in the latest tag."""
456 456 tag = getlatesttags(context, mapping)[2][0]
457 457 mapping = context.overlaymap(mapping, {'tag': tag})
458 458 return _showchangessincetag(context, mapping)
459 459
460 460 def _showchangessincetag(context, mapping):
461 461 repo = context.resource(mapping, 'repo')
462 462 ctx = context.resource(mapping, 'ctx')
463 463 offset = 0
464 464 revs = [ctx.rev()]
465 465 tag = context.symbol(mapping, 'tag')
466 466
467 467 # The only() revset doesn't currently support wdir()
468 468 if ctx.rev() is None:
469 469 offset = 1
470 470 revs = [p.rev() for p in ctx.parents()]
471 471
472 472 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
473 473
474 474 # teach templater latesttags.changes is switched to (context, mapping) API
475 475 _showchangessincetag._requires = {'repo', 'ctx'}
476 476
477 477 @templatekeyword('manifest', requires={'repo', 'ctx'})
478 478 def showmanifest(context, mapping):
479 479 repo = context.resource(mapping, 'repo')
480 480 ctx = context.resource(mapping, 'ctx')
481 481 mnode = ctx.manifestnode()
482 482 if mnode is None:
483 483 mnode = wdirid
484 484 mrev = wdirrev
485 485 else:
486 486 mrev = repo.manifestlog.rev(mnode)
487 487 mhex = hex(mnode)
488 488 mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex})
489 489 f = context.process('manifest', mapping)
490 490 return templateutil.hybriditem(f, None, f,
491 491 lambda x: {'rev': mrev, 'node': mhex})
492 492
493 493 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'})
494 494 def showobsfate(context, mapping):
495 495 # this function returns a list containing pre-formatted obsfate strings.
496 496 #
497 497 # This function will be replaced by templates fragments when we will have
498 498 # the verbosity templatekw available.
499 499 succsandmarkers = showsuccsandmarkers(context, mapping)
500 500
501 501 ui = context.resource(mapping, 'ui')
502 502 repo = context.resource(mapping, 'repo')
503 503 values = []
504 504
505 505 for x in succsandmarkers.tovalue(context, mapping):
506 506 v = obsutil.obsfateprinter(ui, repo, x['successors'], x['markers'],
507 507 scmutil.formatchangeid)
508 508 values.append(v)
509 509
510 510 return compatlist(context, mapping, "fate", values)
511 511
512 512 def shownames(context, mapping, namespace):
513 513 """helper method to generate a template keyword for a namespace"""
514 514 repo = context.resource(mapping, 'repo')
515 515 ctx = context.resource(mapping, 'ctx')
516 516 ns = repo.names[namespace]
517 517 names = ns.names(repo, ctx.node())
518 518 return compatlist(context, mapping, ns.templatename, names,
519 519 plural=namespace)
520 520
521 521 @templatekeyword('namespaces', requires={'repo', 'ctx'})
522 522 def shownamespaces(context, mapping):
523 523 """Dict of lists. Names attached to this changeset per
524 524 namespace."""
525 525 repo = context.resource(mapping, 'repo')
526 526 ctx = context.resource(mapping, 'ctx')
527 527
528 528 namespaces = util.sortdict()
529 529 def makensmapfn(ns):
530 530 # 'name' for iterating over namespaces, templatename for local reference
531 531 return lambda v: {'name': v, ns.templatename: v}
532 532
533 533 for k, ns in repo.names.iteritems():
534 534 names = ns.names(repo, ctx.node())
535 535 f = _showcompatlist(context, mapping, 'name', names)
536 536 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
537 537
538 538 f = _showcompatlist(context, mapping, 'namespace', list(namespaces))
539 539
540 540 def makemap(ns):
541 541 return {
542 542 'namespace': ns,
543 543 'names': namespaces[ns],
544 544 'builtin': repo.names[ns].builtin,
545 545 'colorname': repo.names[ns].colorname,
546 546 }
547 547
548 548 return _hybrid(f, namespaces, makemap, pycompat.identity)
549 549
550 550 @templatekeyword('node', requires={'ctx'})
551 551 def shownode(context, mapping):
552 552 """String. The changeset identification hash, as a 40 hexadecimal
553 553 digit string.
554 554 """
555 555 ctx = context.resource(mapping, 'ctx')
556 556 return ctx.hex()
557 557
558 558 @templatekeyword('obsolete', requires={'ctx'})
559 559 def showobsolete(context, mapping):
560 560 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
561 561 ctx = context.resource(mapping, 'ctx')
562 562 if ctx.obsolete():
563 563 return 'obsolete'
564 564 return ''
565 565
566 566 @templatekeyword('path', requires={'fctx'})
567 567 def showpath(context, mapping):
568 568 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
569 569 fctx = context.resource(mapping, 'fctx')
570 570 return fctx.path()
571 571
572 572 @templatekeyword('peerurls', requires={'repo'})
573 573 def showpeerurls(context, mapping):
574 574 """A dictionary of repository locations defined in the [paths] section
575 575 of your configuration file."""
576 576 repo = context.resource(mapping, 'repo')
577 577 # see commands.paths() for naming of dictionary keys
578 578 paths = repo.ui.paths
579 579 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
580 580 def makemap(k):
581 581 p = paths[k]
582 582 d = {'name': k, 'url': p.rawloc}
583 583 d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
584 584 return d
585 585 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k]))
586 586
587 587 @templatekeyword("predecessors", requires={'repo', 'ctx'})
588 588 def showpredecessors(context, mapping):
589 589 """Returns the list if the closest visible successors. (EXPERIMENTAL)"""
590 590 repo = context.resource(mapping, 'repo')
591 591 ctx = context.resource(mapping, 'ctx')
592 592 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
593 593 predecessors = pycompat.maplist(hex, predecessors)
594 594
595 595 return _hybrid(None, predecessors,
596 596 lambda x: {'ctx': repo[x]},
597 597 lambda x: scmutil.formatchangeid(repo[x]))
598 598
599 599 @templatekeyword('reporoot', requires={'repo'})
600 600 def showreporoot(context, mapping):
601 601 """String. The root directory of the current repository."""
602 602 repo = context.resource(mapping, 'repo')
603 603 return repo.root
604 604
605 605 @templatekeyword('size', requires={'fctx'})
606 606 def showsize(context, mapping):
607 607 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
608 608 fctx = context.resource(mapping, 'fctx')
609 609 return fctx.size()
610 610
611 611 # requires 'fctx' to denote {status} depends on (ctx, path) pair
612 612 @templatekeyword('status', requires={'ctx', 'fctx', 'revcache'})
613 613 def showstatus(context, mapping):
614 614 """String. Status code of the current file. (EXPERIMENTAL)"""
615 615 path = templateutil.runsymbol(context, mapping, 'path')
616 616 path = templateutil.stringify(context, mapping, path)
617 617 if not path:
618 618 return
619 619 statmap = _getfilestatusmap(context, mapping)
620 620 if path not in statmap:
621 621 statmap = _getfilestatusmap(context, mapping, listall=True)
622 622 return statmap.get(path)
623 623
624 624 @templatekeyword("successorssets", requires={'repo', 'ctx'})
625 625 def showsuccessorssets(context, mapping):
626 626 """Returns a string of sets of successors for a changectx. Format used
627 627 is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2
628 628 while also diverged into ctx3. (EXPERIMENTAL)"""
629 629 repo = context.resource(mapping, 'repo')
630 630 ctx = context.resource(mapping, 'ctx')
631 631 if not ctx.obsolete():
632 632 return ''
633 633
634 634 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
635 635 ssets = [[hex(n) for n in ss] for ss in ssets]
636 636
637 637 data = []
638 638 for ss in ssets:
639 639 h = _hybrid(None, ss, lambda x: {'ctx': repo[x]},
640 640 lambda x: scmutil.formatchangeid(repo[x]))
641 641 data.append(h)
642 642
643 643 # Format the successorssets
644 644 def render(d):
645 645 return templateutil.stringify(context, mapping, d)
646 646
647 647 def gen(data):
648 648 yield "; ".join(render(d) for d in data)
649 649
650 650 return _hybrid(gen(data), data, lambda x: {'successorset': x},
651 651 pycompat.identity)
652 652
653 653 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'})
654 654 def showsuccsandmarkers(context, mapping):
655 655 """Returns a list of dict for each final successor of ctx. The dict
656 656 contains successors node id in "successors" keys and the list of
657 657 obs-markers from ctx to the set of successors in "markers".
658 658 (EXPERIMENTAL)
659 659 """
660 660 repo = context.resource(mapping, 'repo')
661 661 ctx = context.resource(mapping, 'ctx')
662 662
663 663 values = obsutil.successorsandmarkers(repo, ctx)
664 664
665 665 if values is None:
666 666 values = []
667 667
668 668 # Format successors and markers to avoid exposing binary to templates
669 669 data = []
670 670 for i in values:
671 671 # Format successors
672 672 successors = i['successors']
673 673
674 674 successors = [hex(n) for n in successors]
675 675 successors = _hybrid(None, successors,
676 676 lambda x: {'ctx': repo[x]},
677 677 lambda x: scmutil.formatchangeid(repo[x]))
678 678
679 679 # Format markers
680 680 finalmarkers = []
681 681 for m in i['markers']:
682 682 hexprec = hex(m[0])
683 683 hexsucs = tuple(hex(n) for n in m[1])
684 684 hexparents = None
685 685 if m[5] is not None:
686 686 hexparents = tuple(hex(n) for n in m[5])
687 687 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
688 688 finalmarkers.append(newmarker)
689 689
690 690 data.append({'successors': successors, 'markers': finalmarkers})
691 691
692 692 return templateutil.mappinglist(data)
693 693
694 @templatekeyword('p1', requires={'ctx'})
695 def showp1(context, mapping):
696 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
697 number, and ``{p1.node}`` for the identification hash."""
698 ctx = context.resource(mapping, 'ctx')
699 return templateutil.mappingdict({'ctx': ctx.p1()}, tmpl=_changeidtmpl)
700
701 @templatekeyword('p2', requires={'ctx'})
702 def showp2(context, mapping):
703 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
704 number, and ``{p2.node}`` for the identification hash."""
705 ctx = context.resource(mapping, 'ctx')
706 return templateutil.mappingdict({'ctx': ctx.p2()}, tmpl=_changeidtmpl)
707
694 708 @templatekeyword('p1rev', requires={'ctx'})
695 709 def showp1rev(context, mapping):
696 710 """Integer. The repository-local revision number of the changeset's
697 711 first parent, or -1 if the changeset has no parents."""
698 712 ctx = context.resource(mapping, 'ctx')
699 713 return ctx.p1().rev()
700 714
701 715 @templatekeyword('p2rev', requires={'ctx'})
702 716 def showp2rev(context, mapping):
703 717 """Integer. The repository-local revision number of the changeset's
704 718 second parent, or -1 if the changeset has no second parent."""
705 719 ctx = context.resource(mapping, 'ctx')
706 720 return ctx.p2().rev()
707 721
708 722 @templatekeyword('p1node', requires={'ctx'})
709 723 def showp1node(context, mapping):
710 724 """String. The identification hash of the changeset's first parent,
711 725 as a 40 digit hexadecimal string. If the changeset has no parents, all
712 726 digits are 0."""
713 727 ctx = context.resource(mapping, 'ctx')
714 728 return ctx.p1().hex()
715 729
716 730 @templatekeyword('p2node', requires={'ctx'})
717 731 def showp2node(context, mapping):
718 732 """String. The identification hash of the changeset's second
719 733 parent, as a 40 digit hexadecimal string. If the changeset has no second
720 734 parent, all digits are 0."""
721 735 ctx = context.resource(mapping, 'ctx')
722 736 return ctx.p2().hex()
723 737
724 738 @templatekeyword('parents', requires={'repo', 'ctx'})
725 739 def showparents(context, mapping):
726 740 """List of strings. The parents of the changeset in "rev:node"
727 741 format. If the changeset has only one "natural" parent (the predecessor
728 742 revision) nothing is shown."""
729 743 repo = context.resource(mapping, 'repo')
730 744 ctx = context.resource(mapping, 'ctx')
731 745 pctxs = scmutil.meaningfulparents(repo, ctx)
732 746 prevs = [p.rev() for p in pctxs]
733 747 parents = [[('rev', p.rev()),
734 748 ('node', p.hex()),
735 749 ('phase', p.phasestr())]
736 750 for p in pctxs]
737 751 f = _showcompatlist(context, mapping, 'parent', parents)
738 752 return _hybrid(f, prevs, lambda x: {'ctx': repo[x]},
739 753 lambda x: scmutil.formatchangeid(repo[x]), keytype=int)
740 754
741 755 @templatekeyword('phase', requires={'ctx'})
742 756 def showphase(context, mapping):
743 757 """String. The changeset phase name."""
744 758 ctx = context.resource(mapping, 'ctx')
745 759 return ctx.phasestr()
746 760
747 761 @templatekeyword('phaseidx', requires={'ctx'})
748 762 def showphaseidx(context, mapping):
749 763 """Integer. The changeset phase index. (ADVANCED)"""
750 764 ctx = context.resource(mapping, 'ctx')
751 765 return ctx.phase()
752 766
753 767 @templatekeyword('rev', requires={'ctx'})
754 768 def showrev(context, mapping):
755 769 """Integer. The repository-local changeset revision number."""
756 770 ctx = context.resource(mapping, 'ctx')
757 771 return scmutil.intrev(ctx)
758 772
759 773 def showrevslist(context, mapping, name, revs):
760 774 """helper to generate a list of revisions in which a mapped template will
761 775 be evaluated"""
762 776 repo = context.resource(mapping, 'repo')
763 777 f = _showcompatlist(context, mapping, name, ['%d' % r for r in revs])
764 778 return _hybrid(f, revs,
765 779 lambda x: {name: x, 'ctx': repo[x]},
766 780 pycompat.identity, keytype=int)
767 781
768 782 @templatekeyword('subrepos', requires={'ctx'})
769 783 def showsubrepos(context, mapping):
770 784 """List of strings. Updated subrepositories in the changeset."""
771 785 ctx = context.resource(mapping, 'ctx')
772 786 substate = ctx.substate
773 787 if not substate:
774 788 return compatlist(context, mapping, 'subrepo', [])
775 789 psubstate = ctx.parents()[0].substate or {}
776 790 subrepos = []
777 791 for sub in substate:
778 792 if sub not in psubstate or substate[sub] != psubstate[sub]:
779 793 subrepos.append(sub) # modified or newly added in ctx
780 794 for sub in psubstate:
781 795 if sub not in substate:
782 796 subrepos.append(sub) # removed in ctx
783 797 return compatlist(context, mapping, 'subrepo', sorted(subrepos))
784 798
785 799 # don't remove "showtags" definition, even though namespaces will put
786 800 # a helper function for "tags" keyword into "keywords" map automatically,
787 801 # because online help text is built without namespaces initialization
788 802 @templatekeyword('tags', requires={'repo', 'ctx'})
789 803 def showtags(context, mapping):
790 804 """List of strings. Any tags associated with the changeset."""
791 805 return shownames(context, mapping, 'tags')
792 806
793 807 @templatekeyword('termwidth', requires={'ui'})
794 808 def showtermwidth(context, mapping):
795 809 """Integer. The width of the current terminal."""
796 810 ui = context.resource(mapping, 'ui')
797 811 return ui.termwidth()
798 812
799 813 @templatekeyword('user', requires={'ctx'})
800 814 def showuser(context, mapping):
801 815 """String. The unmodified author of the changeset."""
802 816 ctx = context.resource(mapping, 'ctx')
803 817 return ctx.user()
804 818
805 819 @templatekeyword('instabilities', requires={'ctx'})
806 820 def showinstabilities(context, mapping):
807 821 """List of strings. Evolution instabilities affecting the changeset.
808 822 (EXPERIMENTAL)
809 823 """
810 824 ctx = context.resource(mapping, 'ctx')
811 825 return compatlist(context, mapping, 'instability', ctx.instabilities(),
812 826 plural='instabilities')
813 827
814 828 @templatekeyword('verbosity', requires={'ui'})
815 829 def showverbosity(context, mapping):
816 830 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
817 831 or ''."""
818 832 ui = context.resource(mapping, 'ui')
819 833 # see logcmdutil.changesettemplater for priority of these flags
820 834 if ui.debugflag:
821 835 return 'debug'
822 836 elif ui.quiet:
823 837 return 'quiet'
824 838 elif ui.verbose:
825 839 return 'verbose'
826 840 return ''
827 841
828 842 @templatekeyword('whyunstable', requires={'repo', 'ctx'})
829 843 def showwhyunstable(context, mapping):
830 844 """List of dicts explaining all instabilities of a changeset.
831 845 (EXPERIMENTAL)
832 846 """
833 847 repo = context.resource(mapping, 'repo')
834 848 ctx = context.resource(mapping, 'ctx')
835 849
836 850 def formatnode(ctx):
837 851 return '%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
838 852
839 853 entries = obsutil.whyunstable(repo, ctx)
840 854
841 855 for entry in entries:
842 856 if entry.get('divergentnodes'):
843 857 dnodes = entry['divergentnodes']
844 858 dnhybrid = _hybrid(None, [dnode.hex() for dnode in dnodes],
845 859 lambda x: {'ctx': repo[x]},
846 860 lambda x: formatnode(repo[x]))
847 861 entry['divergentnodes'] = dnhybrid
848 862
849 863 tmpl = ('{instability}:{if(divergentnodes, " ")}{divergentnodes} '
850 864 '{reason} {node|short}')
851 865 return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n')
852 866
853 867 def loadkeyword(ui, extname, registrarobj):
854 868 """Load template keyword from specified registrarobj
855 869 """
856 870 for name, func in registrarobj._table.iteritems():
857 871 keywords[name] = func
858 872
859 873 # tell hggettext to extract docstrings from these functions:
860 874 i18nfunctions = keywords.values()
@@ -1,1303 +1,1322 b''
1 1 Test template keywords
2 2 ======================
3 3
4 4 $ hg init a
5 5 $ cd a
6 6 $ echo a > a
7 7 $ hg add a
8 8 $ echo line 1 > b
9 9 $ echo line 2 >> b
10 10 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
11 11
12 12 $ hg add b
13 13 $ echo other 1 > c
14 14 $ echo other 2 >> c
15 15 $ echo >> c
16 16 $ echo other 3 >> c
17 17 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
18 18
19 19 $ hg add c
20 20 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
21 21 $ echo c >> c
22 22 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
23 23
24 24 $ echo foo > .hg/branch
25 25 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
26 26
27 27 $ hg co -q 3
28 28 $ echo other 4 >> d
29 29 $ hg add d
30 30 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
31 31
32 32 $ hg merge -q foo
33 33 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
34 34
35 35 Second branch starting at nullrev:
36 36
37 37 $ hg update null
38 38 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
39 39 $ echo second > second
40 40 $ hg add second
41 41 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
42 42 created new head
43 43
44 44 $ echo third > third
45 45 $ hg add third
46 46 $ hg mv second fourth
47 47 $ hg commit -m third -d "2020-01-01 10:01"
48 48
49 49 Working-directory revision has special identifiers, though they are still
50 50 experimental:
51 51
52 52 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
53 53 2147483647:ffffffffffffffffffffffffffffffffffffffff
54 54
55 55 $ hg log -r 'wdir()' -Tjson --debug
56 56 [
57 57 {
58 58 "added": [],
59 59 "bookmarks": [],
60 60 "branch": "default",
61 61 "date": [0, 0],
62 62 "desc": "",
63 63 "extra": {"branch": "default"},
64 64 "manifest": "ffffffffffffffffffffffffffffffffffffffff",
65 65 "modified": [],
66 66 "node": "ffffffffffffffffffffffffffffffffffffffff",
67 67 "parents": ["95c24699272ef57d062b8bccc32c878bf841784a"],
68 68 "phase": "draft",
69 69 "removed": [],
70 70 "rev": 2147483647,
71 71 "tags": [],
72 72 "user": "test"
73 73 }
74 74 ]
75 75
76 76 $ hg log -r 'wdir()' -T '{manifest}\n'
77 77 2147483647:ffffffffffff
78 78
79 79 Changectx-derived keywords are disabled within {manifest} as {node} changes:
80 80
81 81 $ hg log -r0 -T 'outer:{p1node} {manifest % "inner:{p1node}"}\n'
82 82 outer:0000000000000000000000000000000000000000 inner:
83 83
84 84 Check that {phase} works correctly on parents:
85 85
86 86 $ cat << EOF > parentphase
87 87 > changeset_debug = '{rev} ({phase}):{parents}\n'
88 88 > parent = ' {rev} ({phase})'
89 89 > EOF
90 90 $ hg phase -r 5 --public
91 91 $ hg phase -r 7 --secret --force
92 92 $ hg log --debug -G --style ./parentphase
93 93 @ 8 (secret): 7 (secret) -1 (public)
94 94 |
95 95 o 7 (secret): -1 (public) -1 (public)
96 96
97 97 o 6 (draft): 5 (public) 4 (draft)
98 98 |\
99 99 | o 5 (public): 3 (public) -1 (public)
100 100 | |
101 101 o | 4 (draft): 3 (public) -1 (public)
102 102 |/
103 103 o 3 (public): 2 (public) -1 (public)
104 104 |
105 105 o 2 (public): 1 (public) -1 (public)
106 106 |
107 107 o 1 (public): 0 (public) -1 (public)
108 108 |
109 109 o 0 (public): -1 (public) -1 (public)
110 110
111 111
112 112 Keys work:
113 113
114 114 $ for key in author branch branches date desc file_adds file_dels file_mods \
115 115 > file_copies file_copies_switch files \
116 116 > manifest node parents rev tags diffstat extras \
117 117 > p1rev p2rev p1node p2node user; do
118 118 > for mode in '' --verbose --debug; do
119 119 > hg log $mode --template "$key$mode: {$key}\n"
120 120 > done
121 121 > done
122 122 author: test
123 123 author: User Name <user@hostname>
124 124 author: person
125 125 author: person
126 126 author: person
127 127 author: person
128 128 author: other@place
129 129 author: A. N. Other <other@place>
130 130 author: User Name <user@hostname>
131 131 author--verbose: test
132 132 author--verbose: User Name <user@hostname>
133 133 author--verbose: person
134 134 author--verbose: person
135 135 author--verbose: person
136 136 author--verbose: person
137 137 author--verbose: other@place
138 138 author--verbose: A. N. Other <other@place>
139 139 author--verbose: User Name <user@hostname>
140 140 author--debug: test
141 141 author--debug: User Name <user@hostname>
142 142 author--debug: person
143 143 author--debug: person
144 144 author--debug: person
145 145 author--debug: person
146 146 author--debug: other@place
147 147 author--debug: A. N. Other <other@place>
148 148 author--debug: User Name <user@hostname>
149 149 branch: default
150 150 branch: default
151 151 branch: default
152 152 branch: default
153 153 branch: foo
154 154 branch: default
155 155 branch: default
156 156 branch: default
157 157 branch: default
158 158 branch--verbose: default
159 159 branch--verbose: default
160 160 branch--verbose: default
161 161 branch--verbose: default
162 162 branch--verbose: foo
163 163 branch--verbose: default
164 164 branch--verbose: default
165 165 branch--verbose: default
166 166 branch--verbose: default
167 167 branch--debug: default
168 168 branch--debug: default
169 169 branch--debug: default
170 170 branch--debug: default
171 171 branch--debug: foo
172 172 branch--debug: default
173 173 branch--debug: default
174 174 branch--debug: default
175 175 branch--debug: default
176 176 branches:
177 177 branches:
178 178 branches:
179 179 branches:
180 180 branches: foo
181 181 branches:
182 182 branches:
183 183 branches:
184 184 branches:
185 185 branches--verbose:
186 186 branches--verbose:
187 187 branches--verbose:
188 188 branches--verbose:
189 189 branches--verbose: foo
190 190 branches--verbose:
191 191 branches--verbose:
192 192 branches--verbose:
193 193 branches--verbose:
194 194 branches--debug:
195 195 branches--debug:
196 196 branches--debug:
197 197 branches--debug:
198 198 branches--debug: foo
199 199 branches--debug:
200 200 branches--debug:
201 201 branches--debug:
202 202 branches--debug:
203 203 date: 1577872860.00
204 204 date: 1000000.00
205 205 date: 1500001.00
206 206 date: 1500000.00
207 207 date: 1400000.00
208 208 date: 1300000.00
209 209 date: 1200000.00
210 210 date: 1100000.00
211 211 date: 1000000.00
212 212 date--verbose: 1577872860.00
213 213 date--verbose: 1000000.00
214 214 date--verbose: 1500001.00
215 215 date--verbose: 1500000.00
216 216 date--verbose: 1400000.00
217 217 date--verbose: 1300000.00
218 218 date--verbose: 1200000.00
219 219 date--verbose: 1100000.00
220 220 date--verbose: 1000000.00
221 221 date--debug: 1577872860.00
222 222 date--debug: 1000000.00
223 223 date--debug: 1500001.00
224 224 date--debug: 1500000.00
225 225 date--debug: 1400000.00
226 226 date--debug: 1300000.00
227 227 date--debug: 1200000.00
228 228 date--debug: 1100000.00
229 229 date--debug: 1000000.00
230 230 desc: third
231 231 desc: second
232 232 desc: merge
233 233 desc: new head
234 234 desc: new branch
235 235 desc: no user, no domain
236 236 desc: no person
237 237 desc: other 1
238 238 other 2
239 239
240 240 other 3
241 241 desc: line 1
242 242 line 2
243 243 desc--verbose: third
244 244 desc--verbose: second
245 245 desc--verbose: merge
246 246 desc--verbose: new head
247 247 desc--verbose: new branch
248 248 desc--verbose: no user, no domain
249 249 desc--verbose: no person
250 250 desc--verbose: other 1
251 251 other 2
252 252
253 253 other 3
254 254 desc--verbose: line 1
255 255 line 2
256 256 desc--debug: third
257 257 desc--debug: second
258 258 desc--debug: merge
259 259 desc--debug: new head
260 260 desc--debug: new branch
261 261 desc--debug: no user, no domain
262 262 desc--debug: no person
263 263 desc--debug: other 1
264 264 other 2
265 265
266 266 other 3
267 267 desc--debug: line 1
268 268 line 2
269 269 file_adds: fourth third
270 270 file_adds: second
271 271 file_adds:
272 272 file_adds: d
273 273 file_adds:
274 274 file_adds:
275 275 file_adds: c
276 276 file_adds: b
277 277 file_adds: a
278 278 file_adds--verbose: fourth third
279 279 file_adds--verbose: second
280 280 file_adds--verbose:
281 281 file_adds--verbose: d
282 282 file_adds--verbose:
283 283 file_adds--verbose:
284 284 file_adds--verbose: c
285 285 file_adds--verbose: b
286 286 file_adds--verbose: a
287 287 file_adds--debug: fourth third
288 288 file_adds--debug: second
289 289 file_adds--debug:
290 290 file_adds--debug: d
291 291 file_adds--debug:
292 292 file_adds--debug:
293 293 file_adds--debug: c
294 294 file_adds--debug: b
295 295 file_adds--debug: a
296 296 file_dels: second
297 297 file_dels:
298 298 file_dels:
299 299 file_dels:
300 300 file_dels:
301 301 file_dels:
302 302 file_dels:
303 303 file_dels:
304 304 file_dels:
305 305 file_dels--verbose: second
306 306 file_dels--verbose:
307 307 file_dels--verbose:
308 308 file_dels--verbose:
309 309 file_dels--verbose:
310 310 file_dels--verbose:
311 311 file_dels--verbose:
312 312 file_dels--verbose:
313 313 file_dels--verbose:
314 314 file_dels--debug: second
315 315 file_dels--debug:
316 316 file_dels--debug:
317 317 file_dels--debug:
318 318 file_dels--debug:
319 319 file_dels--debug:
320 320 file_dels--debug:
321 321 file_dels--debug:
322 322 file_dels--debug:
323 323 file_mods:
324 324 file_mods:
325 325 file_mods:
326 326 file_mods:
327 327 file_mods:
328 328 file_mods: c
329 329 file_mods:
330 330 file_mods:
331 331 file_mods:
332 332 file_mods--verbose:
333 333 file_mods--verbose:
334 334 file_mods--verbose:
335 335 file_mods--verbose:
336 336 file_mods--verbose:
337 337 file_mods--verbose: c
338 338 file_mods--verbose:
339 339 file_mods--verbose:
340 340 file_mods--verbose:
341 341 file_mods--debug:
342 342 file_mods--debug:
343 343 file_mods--debug:
344 344 file_mods--debug:
345 345 file_mods--debug:
346 346 file_mods--debug: c
347 347 file_mods--debug:
348 348 file_mods--debug:
349 349 file_mods--debug:
350 350 file_copies: fourth (second)
351 351 file_copies:
352 352 file_copies:
353 353 file_copies:
354 354 file_copies:
355 355 file_copies:
356 356 file_copies:
357 357 file_copies:
358 358 file_copies:
359 359 file_copies--verbose: fourth (second)
360 360 file_copies--verbose:
361 361 file_copies--verbose:
362 362 file_copies--verbose:
363 363 file_copies--verbose:
364 364 file_copies--verbose:
365 365 file_copies--verbose:
366 366 file_copies--verbose:
367 367 file_copies--verbose:
368 368 file_copies--debug: fourth (second)
369 369 file_copies--debug:
370 370 file_copies--debug:
371 371 file_copies--debug:
372 372 file_copies--debug:
373 373 file_copies--debug:
374 374 file_copies--debug:
375 375 file_copies--debug:
376 376 file_copies--debug:
377 377 file_copies_switch:
378 378 file_copies_switch:
379 379 file_copies_switch:
380 380 file_copies_switch:
381 381 file_copies_switch:
382 382 file_copies_switch:
383 383 file_copies_switch:
384 384 file_copies_switch:
385 385 file_copies_switch:
386 386 file_copies_switch--verbose:
387 387 file_copies_switch--verbose:
388 388 file_copies_switch--verbose:
389 389 file_copies_switch--verbose:
390 390 file_copies_switch--verbose:
391 391 file_copies_switch--verbose:
392 392 file_copies_switch--verbose:
393 393 file_copies_switch--verbose:
394 394 file_copies_switch--verbose:
395 395 file_copies_switch--debug:
396 396 file_copies_switch--debug:
397 397 file_copies_switch--debug:
398 398 file_copies_switch--debug:
399 399 file_copies_switch--debug:
400 400 file_copies_switch--debug:
401 401 file_copies_switch--debug:
402 402 file_copies_switch--debug:
403 403 file_copies_switch--debug:
404 404 files: fourth second third
405 405 files: second
406 406 files:
407 407 files: d
408 408 files:
409 409 files: c
410 410 files: c
411 411 files: b
412 412 files: a
413 413 files--verbose: fourth second third
414 414 files--verbose: second
415 415 files--verbose:
416 416 files--verbose: d
417 417 files--verbose:
418 418 files--verbose: c
419 419 files--verbose: c
420 420 files--verbose: b
421 421 files--verbose: a
422 422 files--debug: fourth second third
423 423 files--debug: second
424 424 files--debug:
425 425 files--debug: d
426 426 files--debug:
427 427 files--debug: c
428 428 files--debug: c
429 429 files--debug: b
430 430 files--debug: a
431 431 manifest: 6:94961b75a2da
432 432 manifest: 5:f2dbc354b94e
433 433 manifest: 4:4dc3def4f9b4
434 434 manifest: 4:4dc3def4f9b4
435 435 manifest: 3:cb5a1327723b
436 436 manifest: 3:cb5a1327723b
437 437 manifest: 2:6e0e82995c35
438 438 manifest: 1:4e8d705b1e53
439 439 manifest: 0:a0c8bcbbb45c
440 440 manifest--verbose: 6:94961b75a2da
441 441 manifest--verbose: 5:f2dbc354b94e
442 442 manifest--verbose: 4:4dc3def4f9b4
443 443 manifest--verbose: 4:4dc3def4f9b4
444 444 manifest--verbose: 3:cb5a1327723b
445 445 manifest--verbose: 3:cb5a1327723b
446 446 manifest--verbose: 2:6e0e82995c35
447 447 manifest--verbose: 1:4e8d705b1e53
448 448 manifest--verbose: 0:a0c8bcbbb45c
449 449 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
450 450 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
451 451 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
452 452 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
453 453 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
454 454 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
455 455 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
456 456 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
457 457 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
458 458 node: 95c24699272ef57d062b8bccc32c878bf841784a
459 459 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
460 460 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
461 461 node: 13207e5a10d9fd28ec424934298e176197f2c67f
462 462 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
463 463 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
464 464 node: 97054abb4ab824450e9164180baf491ae0078465
465 465 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
466 466 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
467 467 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
468 468 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
469 469 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
470 470 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
471 471 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
472 472 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
473 473 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
474 474 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
475 475 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
476 476 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
477 477 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
478 478 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
479 479 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
480 480 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
481 481 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
482 482 node--debug: 97054abb4ab824450e9164180baf491ae0078465
483 483 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
484 484 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
485 485 parents:
486 486 parents: -1:000000000000
487 487 parents: 5:13207e5a10d9 4:bbe44766e73d
488 488 parents: 3:10e46f2dcbf4
489 489 parents:
490 490 parents:
491 491 parents:
492 492 parents:
493 493 parents:
494 494 parents--verbose:
495 495 parents--verbose: -1:000000000000
496 496 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
497 497 parents--verbose: 3:10e46f2dcbf4
498 498 parents--verbose:
499 499 parents--verbose:
500 500 parents--verbose:
501 501 parents--verbose:
502 502 parents--verbose:
503 503 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
504 504 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
505 505 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
506 506 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
507 507 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
508 508 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
509 509 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
510 510 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
511 511 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
512 512 rev: 8
513 513 rev: 7
514 514 rev: 6
515 515 rev: 5
516 516 rev: 4
517 517 rev: 3
518 518 rev: 2
519 519 rev: 1
520 520 rev: 0
521 521 rev--verbose: 8
522 522 rev--verbose: 7
523 523 rev--verbose: 6
524 524 rev--verbose: 5
525 525 rev--verbose: 4
526 526 rev--verbose: 3
527 527 rev--verbose: 2
528 528 rev--verbose: 1
529 529 rev--verbose: 0
530 530 rev--debug: 8
531 531 rev--debug: 7
532 532 rev--debug: 6
533 533 rev--debug: 5
534 534 rev--debug: 4
535 535 rev--debug: 3
536 536 rev--debug: 2
537 537 rev--debug: 1
538 538 rev--debug: 0
539 539 tags: tip
540 540 tags:
541 541 tags:
542 542 tags:
543 543 tags:
544 544 tags:
545 545 tags:
546 546 tags:
547 547 tags:
548 548 tags--verbose: tip
549 549 tags--verbose:
550 550 tags--verbose:
551 551 tags--verbose:
552 552 tags--verbose:
553 553 tags--verbose:
554 554 tags--verbose:
555 555 tags--verbose:
556 556 tags--verbose:
557 557 tags--debug: tip
558 558 tags--debug:
559 559 tags--debug:
560 560 tags--debug:
561 561 tags--debug:
562 562 tags--debug:
563 563 tags--debug:
564 564 tags--debug:
565 565 tags--debug:
566 566 diffstat: 3: +2/-1
567 567 diffstat: 1: +1/-0
568 568 diffstat: 0: +0/-0
569 569 diffstat: 1: +1/-0
570 570 diffstat: 0: +0/-0
571 571 diffstat: 1: +1/-0
572 572 diffstat: 1: +4/-0
573 573 diffstat: 1: +2/-0
574 574 diffstat: 1: +1/-0
575 575 diffstat--verbose: 3: +2/-1
576 576 diffstat--verbose: 1: +1/-0
577 577 diffstat--verbose: 0: +0/-0
578 578 diffstat--verbose: 1: +1/-0
579 579 diffstat--verbose: 0: +0/-0
580 580 diffstat--verbose: 1: +1/-0
581 581 diffstat--verbose: 1: +4/-0
582 582 diffstat--verbose: 1: +2/-0
583 583 diffstat--verbose: 1: +1/-0
584 584 diffstat--debug: 3: +2/-1
585 585 diffstat--debug: 1: +1/-0
586 586 diffstat--debug: 0: +0/-0
587 587 diffstat--debug: 1: +1/-0
588 588 diffstat--debug: 0: +0/-0
589 589 diffstat--debug: 1: +1/-0
590 590 diffstat--debug: 1: +4/-0
591 591 diffstat--debug: 1: +2/-0
592 592 diffstat--debug: 1: +1/-0
593 593 extras: branch=default
594 594 extras: branch=default
595 595 extras: branch=default
596 596 extras: branch=default
597 597 extras: branch=foo
598 598 extras: branch=default
599 599 extras: branch=default
600 600 extras: branch=default
601 601 extras: branch=default
602 602 extras--verbose: branch=default
603 603 extras--verbose: branch=default
604 604 extras--verbose: branch=default
605 605 extras--verbose: branch=default
606 606 extras--verbose: branch=foo
607 607 extras--verbose: branch=default
608 608 extras--verbose: branch=default
609 609 extras--verbose: branch=default
610 610 extras--verbose: branch=default
611 611 extras--debug: branch=default
612 612 extras--debug: branch=default
613 613 extras--debug: branch=default
614 614 extras--debug: branch=default
615 615 extras--debug: branch=foo
616 616 extras--debug: branch=default
617 617 extras--debug: branch=default
618 618 extras--debug: branch=default
619 619 extras--debug: branch=default
620 620 p1rev: 7
621 621 p1rev: -1
622 622 p1rev: 5
623 623 p1rev: 3
624 624 p1rev: 3
625 625 p1rev: 2
626 626 p1rev: 1
627 627 p1rev: 0
628 628 p1rev: -1
629 629 p1rev--verbose: 7
630 630 p1rev--verbose: -1
631 631 p1rev--verbose: 5
632 632 p1rev--verbose: 3
633 633 p1rev--verbose: 3
634 634 p1rev--verbose: 2
635 635 p1rev--verbose: 1
636 636 p1rev--verbose: 0
637 637 p1rev--verbose: -1
638 638 p1rev--debug: 7
639 639 p1rev--debug: -1
640 640 p1rev--debug: 5
641 641 p1rev--debug: 3
642 642 p1rev--debug: 3
643 643 p1rev--debug: 2
644 644 p1rev--debug: 1
645 645 p1rev--debug: 0
646 646 p1rev--debug: -1
647 647 p2rev: -1
648 648 p2rev: -1
649 649 p2rev: 4
650 650 p2rev: -1
651 651 p2rev: -1
652 652 p2rev: -1
653 653 p2rev: -1
654 654 p2rev: -1
655 655 p2rev: -1
656 656 p2rev--verbose: -1
657 657 p2rev--verbose: -1
658 658 p2rev--verbose: 4
659 659 p2rev--verbose: -1
660 660 p2rev--verbose: -1
661 661 p2rev--verbose: -1
662 662 p2rev--verbose: -1
663 663 p2rev--verbose: -1
664 664 p2rev--verbose: -1
665 665 p2rev--debug: -1
666 666 p2rev--debug: -1
667 667 p2rev--debug: 4
668 668 p2rev--debug: -1
669 669 p2rev--debug: -1
670 670 p2rev--debug: -1
671 671 p2rev--debug: -1
672 672 p2rev--debug: -1
673 673 p2rev--debug: -1
674 674 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
675 675 p1node: 0000000000000000000000000000000000000000
676 676 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
677 677 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
678 678 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
679 679 p1node: 97054abb4ab824450e9164180baf491ae0078465
680 680 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
681 681 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
682 682 p1node: 0000000000000000000000000000000000000000
683 683 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
684 684 p1node--verbose: 0000000000000000000000000000000000000000
685 685 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
686 686 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
687 687 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
688 688 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
689 689 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
690 690 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
691 691 p1node--verbose: 0000000000000000000000000000000000000000
692 692 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
693 693 p1node--debug: 0000000000000000000000000000000000000000
694 694 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
695 695 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
696 696 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
697 697 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
698 698 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
699 699 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
700 700 p1node--debug: 0000000000000000000000000000000000000000
701 701 p2node: 0000000000000000000000000000000000000000
702 702 p2node: 0000000000000000000000000000000000000000
703 703 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
704 704 p2node: 0000000000000000000000000000000000000000
705 705 p2node: 0000000000000000000000000000000000000000
706 706 p2node: 0000000000000000000000000000000000000000
707 707 p2node: 0000000000000000000000000000000000000000
708 708 p2node: 0000000000000000000000000000000000000000
709 709 p2node: 0000000000000000000000000000000000000000
710 710 p2node--verbose: 0000000000000000000000000000000000000000
711 711 p2node--verbose: 0000000000000000000000000000000000000000
712 712 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
713 713 p2node--verbose: 0000000000000000000000000000000000000000
714 714 p2node--verbose: 0000000000000000000000000000000000000000
715 715 p2node--verbose: 0000000000000000000000000000000000000000
716 716 p2node--verbose: 0000000000000000000000000000000000000000
717 717 p2node--verbose: 0000000000000000000000000000000000000000
718 718 p2node--verbose: 0000000000000000000000000000000000000000
719 719 p2node--debug: 0000000000000000000000000000000000000000
720 720 p2node--debug: 0000000000000000000000000000000000000000
721 721 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
722 722 p2node--debug: 0000000000000000000000000000000000000000
723 723 p2node--debug: 0000000000000000000000000000000000000000
724 724 p2node--debug: 0000000000000000000000000000000000000000
725 725 p2node--debug: 0000000000000000000000000000000000000000
726 726 p2node--debug: 0000000000000000000000000000000000000000
727 727 p2node--debug: 0000000000000000000000000000000000000000
728 728 user: test
729 729 user: User Name <user@hostname>
730 730 user: person
731 731 user: person
732 732 user: person
733 733 user: person
734 734 user: other@place
735 735 user: A. N. Other <other@place>
736 736 user: User Name <user@hostname>
737 737 user--verbose: test
738 738 user--verbose: User Name <user@hostname>
739 739 user--verbose: person
740 740 user--verbose: person
741 741 user--verbose: person
742 742 user--verbose: person
743 743 user--verbose: other@place
744 744 user--verbose: A. N. Other <other@place>
745 745 user--verbose: User Name <user@hostname>
746 746 user--debug: test
747 747 user--debug: User Name <user@hostname>
748 748 user--debug: person
749 749 user--debug: person
750 750 user--debug: person
751 751 user--debug: person
752 752 user--debug: other@place
753 753 user--debug: A. N. Other <other@place>
754 754 user--debug: User Name <user@hostname>
755 755
756 756 Add a dummy commit to make up for the instability of the above:
757 757
758 758 $ echo a > a
759 759 $ hg add a
760 760 $ hg ci -m future
761 761
762 762 Add a commit that does all possible modifications at once
763 763
764 764 $ echo modify >> third
765 765 $ touch b
766 766 $ hg add b
767 767 $ hg mv fourth fifth
768 768 $ hg rm a
769 769 $ hg ci -m "Modify, add, remove, rename"
770 770
771 771 Test files list:
772 772
773 773 $ hg log -l1 -T '{join(file_mods, " ")}\n'
774 774 third
775 775 $ hg log -l1 -T '{file_mods % "{file}\n"}'
776 776 third
777 777 $ hg log -l1 -T '{file_mods % "{path}\n"}'
778 778 third
779 779
780 780 $ hg log -l1 -T '{join(files, " ")}\n'
781 781 a b fifth fourth third
782 782 $ hg log -l1 -T '{files % "{file}\n"}'
783 783 a
784 784 b
785 785 fifth
786 786 fourth
787 787 third
788 788 $ hg log -l1 -T '{files % "{path}\n"}'
789 789 a
790 790 b
791 791 fifth
792 792 fourth
793 793 third
794 794
795 795 Test file copies dict:
796 796
797 797 $ hg log -r8 -T '{join(file_copies, " ")}\n'
798 798 fourth (second)
799 799 $ hg log -r8 -T '{file_copies % "{name} <- {source}\n"}'
800 800 fourth <- second
801 801 $ hg log -r8 -T '{file_copies % "{path} <- {source}\n"}'
802 802 fourth <- second
803 803
804 804 $ hg log -r8 -T '{join(file_copies_switch, " ")}\n'
805 805
806 806 $ hg log -r8 -C -T '{join(file_copies_switch, " ")}\n'
807 807 fourth (second)
808 808 $ hg log -r8 -C -T '{file_copies_switch % "{name} <- {source}\n"}'
809 809 fourth <- second
810 810 $ hg log -r8 -C -T '{file_copies_switch % "{path} <- {source}\n"}'
811 811 fourth <- second
812 812
813 813 Test file attributes:
814 814
815 815 $ hg log -l1 -T '{files % "{status} {pad(size, 3, left=True)} {path}\n"}'
816 816 R a
817 817 A 0 b
818 818 A 7 fifth
819 819 R fourth
820 820 M 13 third
821 821
822 822 Test file status including clean ones:
823 823
824 824 $ hg log -r9 -T '{files("**") % "{status} {path}\n"}'
825 825 A a
826 826 C fourth
827 827 C third
828 828
829 829 Test index keyword:
830 830
831 831 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
832 832 10 0:a 1:b 2:fifth 3:fourth 4:third
833 833 11 0:a
834 834
835 835 $ hg branches -T '{index} {branch}\n'
836 836 0 default
837 837 1 foo
838 838
839 p1/p2 keywords:
840
841 $ hg log -r4:7 -GT '{rev} p1:{p1} p2:{p2} p1.rev:{p1.rev} p2.node:{p2.node}\n'
842 o 7 p1:-1:000000000000 p2:-1:000000000000 p1.rev:-1 p2.node:0000000000000000000000000000000000000000
843
844 o 6 p1:5:13207e5a10d9 p2:4:bbe44766e73d p1.rev:5 p2.node:bbe44766e73d5f11ed2177f1838de10c53ef3e74
845 |\
846 | o 5 p1:3:10e46f2dcbf4 p2:-1:000000000000 p1.rev:3 p2.node:0000000000000000000000000000000000000000
847 | |
848 | ~
849 o 4 p1:3:10e46f2dcbf4 p2:-1:000000000000 p1.rev:3 p2.node:0000000000000000000000000000000000000000
850 |
851 ~
852
853 TODO: no idea what should be displayed as a JSON representation
854 $ hg log -r6 -T 'p1:{p1|json}\np2:{p2|json}\n'
855 p1:{}
856 p2:{}
857
839 858 ui verbosity:
840 859
841 860 $ hg log -l1 -T '{verbosity}\n'
842 861
843 862 $ hg log -l1 -T '{verbosity}\n' --debug
844 863 debug
845 864 $ hg log -l1 -T '{verbosity}\n' --quiet
846 865 quiet
847 866 $ hg log -l1 -T '{verbosity}\n' --verbose
848 867 verbose
849 868
850 869 $ cd ..
851 870
852 871 latesttag:
853 872
854 873 $ hg init latesttag
855 874 $ cd latesttag
856 875
857 876 $ echo a > file
858 877 $ hg ci -Am a -d '0 0'
859 878 adding file
860 879
861 880 $ echo b >> file
862 881 $ hg ci -m b -d '1 0'
863 882
864 883 $ echo c >> head1
865 884 $ hg ci -Am h1c -d '2 0'
866 885 adding head1
867 886
868 887 $ hg update -q 1
869 888 $ echo d >> head2
870 889 $ hg ci -Am h2d -d '3 0'
871 890 adding head2
872 891 created new head
873 892
874 893 $ echo e >> head2
875 894 $ hg ci -m h2e -d '4 0'
876 895
877 896 $ hg merge -q
878 897 $ hg ci -m merge -d '5 -3600'
879 898
880 899 No tag set:
881 900
882 901 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
883 902 @ 5: null+5
884 903 |\
885 904 | o 4: null+4
886 905 | |
887 906 | o 3: null+3
888 907 | |
889 908 o | 2: null+3
890 909 |/
891 910 o 1: null+2
892 911 |
893 912 o 0: null+1
894 913
895 914
896 915 One common tag: longest path wins for {latesttagdistance}:
897 916
898 917 $ hg tag -r 1 -m t1 -d '6 0' t1
899 918 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
900 919 @ 6: t1+4
901 920 |
902 921 o 5: t1+3
903 922 |\
904 923 | o 4: t1+2
905 924 | |
906 925 | o 3: t1+1
907 926 | |
908 927 o | 2: t1+1
909 928 |/
910 929 o 1: t1+0
911 930 |
912 931 o 0: null+1
913 932
914 933
915 934 One ancestor tag: closest wins:
916 935
917 936 $ hg tag -r 2 -m t2 -d '7 0' t2
918 937 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
919 938 @ 7: t2+3
920 939 |
921 940 o 6: t2+2
922 941 |
923 942 o 5: t2+1
924 943 |\
925 944 | o 4: t1+2
926 945 | |
927 946 | o 3: t1+1
928 947 | |
929 948 o | 2: t2+0
930 949 |/
931 950 o 1: t1+0
932 951 |
933 952 o 0: null+1
934 953
935 954
936 955 Two branch tags: more recent wins if same number of changes:
937 956
938 957 $ hg tag -r 3 -m t3 -d '8 0' t3
939 958 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
940 959 @ 8: t3+5
941 960 |
942 961 o 7: t3+4
943 962 |
944 963 o 6: t3+3
945 964 |
946 965 o 5: t3+2
947 966 |\
948 967 | o 4: t3+1
949 968 | |
950 969 | o 3: t3+0
951 970 | |
952 971 o | 2: t2+0
953 972 |/
954 973 o 1: t1+0
955 974 |
956 975 o 0: null+1
957 976
958 977
959 978 Two branch tags: fewest changes wins:
960 979
961 980 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
962 981 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
963 982 @ 9: t4+5,6
964 983 |
965 984 o 8: t4+4,5
966 985 |
967 986 o 7: t4+3,4
968 987 |
969 988 o 6: t4+2,3
970 989 |
971 990 o 5: t4+1,2
972 991 |\
973 992 | o 4: t4+0,0
974 993 | |
975 994 | o 3: t3+0,0
976 995 | |
977 996 o | 2: t2+0,0
978 997 |/
979 998 o 1: t1+0,0
980 999 |
981 1000 o 0: null+1,1
982 1001
983 1002
984 1003 Merged tag overrides:
985 1004
986 1005 $ hg tag -r 5 -m t5 -d '9 0' t5
987 1006 $ hg tag -r 3 -m at3 -d '10 0' at3
988 1007 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
989 1008 @ 11: t5+6
990 1009 |
991 1010 o 10: t5+5
992 1011 |
993 1012 o 9: t5+4
994 1013 |
995 1014 o 8: t5+3
996 1015 |
997 1016 o 7: t5+2
998 1017 |
999 1018 o 6: t5+1
1000 1019 |
1001 1020 o 5: t5+0
1002 1021 |\
1003 1022 | o 4: t4+0
1004 1023 | |
1005 1024 | o 3: at3:t3+0
1006 1025 | |
1007 1026 o | 2: t2+0
1008 1027 |/
1009 1028 o 1: t1+0
1010 1029 |
1011 1030 o 0: null+1
1012 1031
1013 1032
1014 1033 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
1015 1034 @ 11: t5+6,6
1016 1035 |
1017 1036 o 10: t5+5,5
1018 1037 |
1019 1038 o 9: t5+4,4
1020 1039 |
1021 1040 o 8: t5+3,3
1022 1041 |
1023 1042 o 7: t5+2,2
1024 1043 |
1025 1044 o 6: t5+1,1
1026 1045 |
1027 1046 o 5: t5+0,0
1028 1047 |\
1029 1048 | o 4: t4+0,0
1030 1049 | |
1031 1050 | o 3: at3+0,0 t3+0,0
1032 1051 | |
1033 1052 o | 2: t2+0,0
1034 1053 |/
1035 1054 o 1: t1+0,0
1036 1055 |
1037 1056 o 0: null+1,1
1038 1057
1039 1058
1040 1059 $ cd ..
1041 1060
1042 1061 Set up repository containing template fragments in commit metadata:
1043 1062
1044 1063 $ hg init r
1045 1064 $ cd r
1046 1065 $ echo a > a
1047 1066 $ hg ci -Am '{rev}'
1048 1067 adding a
1049 1068
1050 1069 $ hg branch -q 'text.{rev}'
1051 1070 $ echo aa >> aa
1052 1071 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
1053 1072
1054 1073 Test termwidth:
1055 1074
1056 1075 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
1057 1076 bcc7ff960b8e:desc to be
1058 1077 termwidth.1:wrapped desc
1059 1078 termwidth.1:to be wrapped (no-eol)
1060 1079
1061 1080 Just one more commit:
1062 1081
1063 1082 $ echo b > b
1064 1083 $ hg ci -qAm b
1065 1084
1066 1085 Test 'originalnode'
1067 1086
1068 1087 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
1069 1088 000000000000 bcc7ff960b8e
1070 1089 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
1071 1090 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
1072 1091
1073 1092 Test active bookmark templating
1074 1093
1075 1094 $ hg book foo
1076 1095 $ hg book bar
1077 1096 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
1078 1097 2 bar* foo
1079 1098 1
1080 1099 0
1081 1100 $ hg log --template "{rev} {activebookmark}\n"
1082 1101 2 bar
1083 1102 1
1084 1103 0
1085 1104 $ hg bookmarks --inactive bar
1086 1105 $ hg log --template "{rev} {activebookmark}\n"
1087 1106 2
1088 1107 1
1089 1108 0
1090 1109 $ hg book -r1 baz
1091 1110 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
1092 1111 2 bar foo
1093 1112 1 baz
1094 1113 0
1095 1114 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
1096 1115 2 t
1097 1116 1 f
1098 1117 0 f
1099 1118
1100 1119 Test namespaces dict
1101 1120
1102 1121 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
1103 1122 2
1104 1123 bookmarks color=bookmark builtin=True
1105 1124 bar,foo
1106 1125 tags color=tag builtin=True
1107 1126 tip
1108 1127 branches color=branch builtin=True
1109 1128 text.{rev}
1110 1129 revnames color=revname builtin=False
1111 1130 r2
1112 1131
1113 1132 1
1114 1133 bookmarks color=bookmark builtin=True
1115 1134 baz
1116 1135 tags color=tag builtin=True
1117 1136
1118 1137 branches color=branch builtin=True
1119 1138 text.{rev}
1120 1139 revnames color=revname builtin=False
1121 1140 r1
1122 1141
1123 1142 0
1124 1143 bookmarks color=bookmark builtin=True
1125 1144
1126 1145 tags color=tag builtin=True
1127 1146
1128 1147 branches color=branch builtin=True
1129 1148 default
1130 1149 revnames color=revname builtin=False
1131 1150 r0
1132 1151
1133 1152 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
1134 1153 bookmarks: bar foo
1135 1154 tags: tip
1136 1155 branches: text.{rev}
1137 1156 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
1138 1157 bookmarks:
1139 1158 bar
1140 1159 foo
1141 1160 tags:
1142 1161 tip
1143 1162 branches:
1144 1163 text.{rev}
1145 1164 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
1146 1165 bar
1147 1166 foo
1148 1167 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
1149 1168 bar
1150 1169 foo
1151 1170
1152 1171 $ cd ..
1153 1172
1154 1173 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
1155 1174 printed graphwidths 3, 5, 7, etc. should all line up in their respective
1156 1175 columns. We don't care about other aspects of the graph rendering here.
1157 1176
1158 1177 $ hg init graphwidth
1159 1178 $ cd graphwidth
1160 1179
1161 1180 $ wrappabletext="a a a a a a a a a a a a"
1162 1181
1163 1182 $ printf "first\n" > file
1164 1183 $ hg add file
1165 1184 $ hg commit -m "$wrappabletext"
1166 1185
1167 1186 $ printf "first\nsecond\n" > file
1168 1187 $ hg commit -m "$wrappabletext"
1169 1188
1170 1189 $ hg checkout 0
1171 1190 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1172 1191 $ printf "third\nfirst\n" > file
1173 1192 $ hg commit -m "$wrappabletext"
1174 1193 created new head
1175 1194
1176 1195 $ hg merge
1177 1196 merging file
1178 1197 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1179 1198 (branch merge, don't forget to commit)
1180 1199
1181 1200 $ hg log --graph -T "{graphwidth}"
1182 1201 @ 3
1183 1202 |
1184 1203 | @ 5
1185 1204 |/
1186 1205 o 3
1187 1206
1188 1207 $ hg commit -m "$wrappabletext"
1189 1208
1190 1209 $ hg log --graph -T "{graphwidth}"
1191 1210 @ 5
1192 1211 |\
1193 1212 | o 5
1194 1213 | |
1195 1214 o | 5
1196 1215 |/
1197 1216 o 3
1198 1217
1199 1218
1200 1219 $ hg checkout 0
1201 1220 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1202 1221 $ printf "third\nfirst\nsecond\n" > file
1203 1222 $ hg commit -m "$wrappabletext"
1204 1223 created new head
1205 1224
1206 1225 $ hg log --graph -T "{graphwidth}"
1207 1226 @ 3
1208 1227 |
1209 1228 | o 7
1210 1229 | |\
1211 1230 +---o 7
1212 1231 | |
1213 1232 | o 5
1214 1233 |/
1215 1234 o 3
1216 1235
1217 1236
1218 1237 $ hg log --graph -T "{graphwidth}" -r 3
1219 1238 o 5
1220 1239 |\
1221 1240 ~ ~
1222 1241
1223 1242 $ hg log --graph -T "{graphwidth}" -r 1
1224 1243 o 3
1225 1244 |
1226 1245 ~
1227 1246
1228 1247 $ hg merge
1229 1248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1230 1249 (branch merge, don't forget to commit)
1231 1250 $ hg commit -m "$wrappabletext"
1232 1251
1233 1252 $ printf "seventh\n" >> file
1234 1253 $ hg commit -m "$wrappabletext"
1235 1254
1236 1255 $ hg log --graph -T "{graphwidth}"
1237 1256 @ 3
1238 1257 |
1239 1258 o 5
1240 1259 |\
1241 1260 | o 5
1242 1261 | |
1243 1262 o | 7
1244 1263 |\ \
1245 1264 | o | 7
1246 1265 | |/
1247 1266 o / 5
1248 1267 |/
1249 1268 o 3
1250 1269
1251 1270
1252 1271 The point of graphwidth is to allow wrapping that accounts for the space taken
1253 1272 by the graph.
1254 1273
1255 1274 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
1256 1275 @ a a a a
1257 1276 | a a a a
1258 1277 | a a a a
1259 1278 o a a a
1260 1279 |\ a a a
1261 1280 | | a a a
1262 1281 | | a a a
1263 1282 | o a a a
1264 1283 | | a a a
1265 1284 | | a a a
1266 1285 | | a a a
1267 1286 o | a a
1268 1287 |\ \ a a
1269 1288 | | | a a
1270 1289 | | | a a
1271 1290 | | | a a
1272 1291 | | | a a
1273 1292 | o | a a
1274 1293 | |/ a a
1275 1294 | | a a
1276 1295 | | a a
1277 1296 | | a a
1278 1297 | | a a
1279 1298 o | a a a
1280 1299 |/ a a a
1281 1300 | a a a
1282 1301 | a a a
1283 1302 o a a a a
1284 1303 a a a a
1285 1304 a a a a
1286 1305
1287 1306 Something tricky happens when there are elided nodes; the next drawn row of
1288 1307 edges can be more than one column wider, but the graph width only increases by
1289 1308 one column. The remaining columns are added in between the nodes.
1290 1309
1291 1310 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
1292 1311 o 5
1293 1312 |\
1294 1313 | \
1295 1314 | :\
1296 1315 o : : 7
1297 1316 :/ /
1298 1317 : o 5
1299 1318 :/
1300 1319 o 3
1301 1320
1302 1321
1303 1322 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now