##// END OF EJS Templates
revsetlang: check incomplete revspec format character
Yuya Nishihara -
r35611:850cd045 default
parent child Browse files
Show More
@@ -1,709 +1,715 b''
1 1 # revsetlang.py - parser, tokenizer and utility for revision set language
2 2 #
3 3 # Copyright 2010 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 import string
11 11
12 12 from .i18n import _
13 13 from . import (
14 14 error,
15 15 node,
16 16 parser,
17 17 pycompat,
18 18 util,
19 19 )
20 20
21 21 elements = {
22 22 # token-type: binding-strength, primary, prefix, infix, suffix
23 23 "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
24 24 "[": (21, None, None, ("subscript", 1, "]"), None),
25 25 "#": (21, None, None, ("relation", 21), None),
26 26 "##": (20, None, None, ("_concat", 20), None),
27 27 "~": (18, None, None, ("ancestor", 18), None),
28 28 "^": (18, None, None, ("parent", 18), "parentpost"),
29 29 "-": (5, None, ("negate", 19), ("minus", 5), None),
30 30 "::": (17, "dagrangeall", ("dagrangepre", 17), ("dagrange", 17),
31 31 "dagrangepost"),
32 32 "..": (17, "dagrangeall", ("dagrangepre", 17), ("dagrange", 17),
33 33 "dagrangepost"),
34 34 ":": (15, "rangeall", ("rangepre", 15), ("range", 15), "rangepost"),
35 35 "not": (10, None, ("not", 10), None, None),
36 36 "!": (10, None, ("not", 10), None, None),
37 37 "and": (5, None, None, ("and", 5), None),
38 38 "&": (5, None, None, ("and", 5), None),
39 39 "%": (5, None, None, ("only", 5), "onlypost"),
40 40 "or": (4, None, None, ("or", 4), None),
41 41 "|": (4, None, None, ("or", 4), None),
42 42 "+": (4, None, None, ("or", 4), None),
43 43 "=": (3, None, None, ("keyvalue", 3), None),
44 44 ",": (2, None, None, ("list", 2), None),
45 45 ")": (0, None, None, None, None),
46 46 "]": (0, None, None, None, None),
47 47 "symbol": (0, "symbol", None, None, None),
48 48 "string": (0, "string", None, None, None),
49 49 "end": (0, None, None, None, None),
50 50 }
51 51
52 52 keywords = {'and', 'or', 'not'}
53 53
54 54 symbols = {}
55 55
56 56 _quoteletters = {'"', "'"}
57 57 _simpleopletters = set(pycompat.iterbytestr("()[]#:=,-|&+!~^%"))
58 58
59 59 # default set of valid characters for the initial letter of symbols
60 60 _syminitletters = set(pycompat.iterbytestr(
61 61 string.ascii_letters.encode('ascii') +
62 62 string.digits.encode('ascii') +
63 63 '._@')) | set(map(pycompat.bytechr, xrange(128, 256)))
64 64
65 65 # default set of valid characters for non-initial letters of symbols
66 66 _symletters = _syminitletters | set(pycompat.iterbytestr('-/'))
67 67
68 68 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
69 69 '''
70 70 Parse a revset statement into a stream of tokens
71 71
72 72 ``syminitletters`` is the set of valid characters for the initial
73 73 letter of symbols.
74 74
75 75 By default, character ``c`` is recognized as valid for initial
76 76 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
77 77
78 78 ``symletters`` is the set of valid characters for non-initial
79 79 letters of symbols.
80 80
81 81 By default, character ``c`` is recognized as valid for non-initial
82 82 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
83 83
84 84 Check that @ is a valid unquoted token character (issue3686):
85 85 >>> list(tokenize(b"@::"))
86 86 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
87 87
88 88 '''
89 89 program = pycompat.bytestr(program)
90 90 if syminitletters is None:
91 91 syminitletters = _syminitletters
92 92 if symletters is None:
93 93 symletters = _symletters
94 94
95 95 if program and lookup:
96 96 # attempt to parse old-style ranges first to deal with
97 97 # things like old-tag which contain query metacharacters
98 98 parts = program.split(':', 1)
99 99 if all(lookup(sym) for sym in parts if sym):
100 100 if parts[0]:
101 101 yield ('symbol', parts[0], 0)
102 102 if len(parts) > 1:
103 103 s = len(parts[0])
104 104 yield (':', None, s)
105 105 if parts[1]:
106 106 yield ('symbol', parts[1], s + 1)
107 107 yield ('end', None, len(program))
108 108 return
109 109
110 110 pos, l = 0, len(program)
111 111 while pos < l:
112 112 c = program[pos]
113 113 if c.isspace(): # skip inter-token whitespace
114 114 pass
115 115 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
116 116 yield ('::', None, pos)
117 117 pos += 1 # skip ahead
118 118 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
119 119 yield ('..', None, pos)
120 120 pos += 1 # skip ahead
121 121 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
122 122 yield ('##', None, pos)
123 123 pos += 1 # skip ahead
124 124 elif c in _simpleopletters: # handle simple operators
125 125 yield (c, None, pos)
126 126 elif (c in _quoteletters or c == 'r' and
127 127 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
128 128 if c == 'r':
129 129 pos += 1
130 130 c = program[pos]
131 131 decode = lambda x: x
132 132 else:
133 133 decode = parser.unescapestr
134 134 pos += 1
135 135 s = pos
136 136 while pos < l: # find closing quote
137 137 d = program[pos]
138 138 if d == '\\': # skip over escaped characters
139 139 pos += 2
140 140 continue
141 141 if d == c:
142 142 yield ('string', decode(program[s:pos]), s)
143 143 break
144 144 pos += 1
145 145 else:
146 146 raise error.ParseError(_("unterminated string"), s)
147 147 # gather up a symbol/keyword
148 148 elif c in syminitletters:
149 149 s = pos
150 150 pos += 1
151 151 while pos < l: # find end of symbol
152 152 d = program[pos]
153 153 if d not in symletters:
154 154 break
155 155 if d == '.' and program[pos - 1] == '.': # special case for ..
156 156 pos -= 1
157 157 break
158 158 pos += 1
159 159 sym = program[s:pos]
160 160 if sym in keywords: # operator keywords
161 161 yield (sym, None, s)
162 162 elif '-' in sym:
163 163 # some jerk gave us foo-bar-baz, try to check if it's a symbol
164 164 if lookup and lookup(sym):
165 165 # looks like a real symbol
166 166 yield ('symbol', sym, s)
167 167 else:
168 168 # looks like an expression
169 169 parts = sym.split('-')
170 170 for p in parts[:-1]:
171 171 if p: # possible consecutive -
172 172 yield ('symbol', p, s)
173 173 s += len(p)
174 174 yield ('-', None, pos)
175 175 s += 1
176 176 if parts[-1]: # possible trailing -
177 177 yield ('symbol', parts[-1], s)
178 178 else:
179 179 yield ('symbol', sym, s)
180 180 pos -= 1
181 181 else:
182 182 raise error.ParseError(_("syntax error in revset '%s'") %
183 183 program, pos)
184 184 pos += 1
185 185 yield ('end', None, pos)
186 186
187 187 # helpers
188 188
189 189 _notset = object()
190 190
191 191 def getsymbol(x):
192 192 if x and x[0] == 'symbol':
193 193 return x[1]
194 194 raise error.ParseError(_('not a symbol'))
195 195
196 196 def getstring(x, err):
197 197 if x and (x[0] == 'string' or x[0] == 'symbol'):
198 198 return x[1]
199 199 raise error.ParseError(err)
200 200
201 201 def getinteger(x, err, default=_notset):
202 202 if not x and default is not _notset:
203 203 return default
204 204 try:
205 205 return int(getstring(x, err))
206 206 except ValueError:
207 207 raise error.ParseError(err)
208 208
209 209 def getboolean(x, err):
210 210 value = util.parsebool(getsymbol(x))
211 211 if value is not None:
212 212 return value
213 213 raise error.ParseError(err)
214 214
215 215 def getlist(x):
216 216 if not x:
217 217 return []
218 218 if x[0] == 'list':
219 219 return list(x[1:])
220 220 return [x]
221 221
222 222 def getrange(x, err):
223 223 if not x:
224 224 raise error.ParseError(err)
225 225 op = x[0]
226 226 if op == 'range':
227 227 return x[1], x[2]
228 228 elif op == 'rangepre':
229 229 return None, x[1]
230 230 elif op == 'rangepost':
231 231 return x[1], None
232 232 elif op == 'rangeall':
233 233 return None, None
234 234 raise error.ParseError(err)
235 235
236 236 def getargs(x, min, max, err):
237 237 l = getlist(x)
238 238 if len(l) < min or (max >= 0 and len(l) > max):
239 239 raise error.ParseError(err)
240 240 return l
241 241
242 242 def getargsdict(x, funcname, keys):
243 243 return parser.buildargsdict(getlist(x), funcname, parser.splitargspec(keys),
244 244 keyvaluenode='keyvalue', keynode='symbol')
245 245
246 246 # cache of {spec: raw parsed tree} built internally
247 247 _treecache = {}
248 248
249 249 def _cachedtree(spec):
250 250 # thread safe because parse() is reentrant and dict.__setitem__() is atomic
251 251 tree = _treecache.get(spec)
252 252 if tree is None:
253 253 _treecache[spec] = tree = parse(spec)
254 254 return tree
255 255
256 256 def _build(tmplspec, *repls):
257 257 """Create raw parsed tree from a template revset statement
258 258
259 259 >>> _build(b'f(_) and _', (b'string', b'1'), (b'symbol', b'2'))
260 260 ('and', ('func', ('symbol', 'f'), ('string', '1')), ('symbol', '2'))
261 261 """
262 262 template = _cachedtree(tmplspec)
263 263 return parser.buildtree(template, ('symbol', '_'), *repls)
264 264
265 265 def _match(patspec, tree):
266 266 """Test if a tree matches the given pattern statement; return the matches
267 267
268 268 >>> _match(b'f(_)', parse(b'f()'))
269 269 >>> _match(b'f(_)', parse(b'f(1)'))
270 270 [('func', ('symbol', 'f'), ('symbol', '1')), ('symbol', '1')]
271 271 >>> _match(b'f(_)', parse(b'f(1, 2)'))
272 272 """
273 273 pattern = _cachedtree(patspec)
274 274 return parser.matchtree(pattern, tree, ('symbol', '_'),
275 275 {'keyvalue', 'list'})
276 276
277 277 def _matchonly(revs, bases):
278 278 return _match('ancestors(_) and not ancestors(_)', ('and', revs, bases))
279 279
280 280 def _fixops(x):
281 281 """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be
282 282 handled well by our simple top-down parser"""
283 283 if not isinstance(x, tuple):
284 284 return x
285 285
286 286 op = x[0]
287 287 if op == 'parent':
288 288 # x^:y means (x^) : y, not x ^ (:y)
289 289 # x^: means (x^) :, not x ^ (:)
290 290 post = ('parentpost', x[1])
291 291 if x[2][0] == 'dagrangepre':
292 292 return _fixops(('dagrange', post, x[2][1]))
293 293 elif x[2][0] == 'dagrangeall':
294 294 return _fixops(('dagrangepost', post))
295 295 elif x[2][0] == 'rangepre':
296 296 return _fixops(('range', post, x[2][1]))
297 297 elif x[2][0] == 'rangeall':
298 298 return _fixops(('rangepost', post))
299 299 elif op == 'or':
300 300 # make number of arguments deterministic:
301 301 # x + y + z -> (or x y z) -> (or (list x y z))
302 302 return (op, _fixops(('list',) + x[1:]))
303 303 elif op == 'subscript' and x[1][0] == 'relation':
304 304 # x#y[z] ternary
305 305 return _fixops(('relsubscript', x[1][1], x[1][2], x[2]))
306 306
307 307 return (op,) + tuple(_fixops(y) for y in x[1:])
308 308
309 309 def _analyze(x):
310 310 if x is None:
311 311 return x
312 312
313 313 op = x[0]
314 314 if op == 'minus':
315 315 return _analyze(_build('_ and not _', *x[1:]))
316 316 elif op == 'only':
317 317 return _analyze(_build('only(_, _)', *x[1:]))
318 318 elif op == 'onlypost':
319 319 return _analyze(_build('only(_)', x[1]))
320 320 elif op == 'dagrangeall':
321 321 raise error.ParseError(_("can't use '::' in this context"))
322 322 elif op == 'dagrangepre':
323 323 return _analyze(_build('ancestors(_)', x[1]))
324 324 elif op == 'dagrangepost':
325 325 return _analyze(_build('descendants(_)', x[1]))
326 326 elif op == 'negate':
327 327 s = getstring(x[1], _("can't negate that"))
328 328 return _analyze(('string', '-' + s))
329 329 elif op in ('string', 'symbol'):
330 330 return x
331 331 elif op == 'rangeall':
332 332 return (op, None)
333 333 elif op in {'or', 'not', 'rangepre', 'rangepost', 'parentpost'}:
334 334 return (op, _analyze(x[1]))
335 335 elif op == 'group':
336 336 return _analyze(x[1])
337 337 elif op in {'and', 'dagrange', 'range', 'parent', 'ancestor', 'relation',
338 338 'subscript'}:
339 339 ta = _analyze(x[1])
340 340 tb = _analyze(x[2])
341 341 return (op, ta, tb)
342 342 elif op == 'relsubscript':
343 343 ta = _analyze(x[1])
344 344 tb = _analyze(x[2])
345 345 tc = _analyze(x[3])
346 346 return (op, ta, tb, tc)
347 347 elif op == 'list':
348 348 return (op,) + tuple(_analyze(y) for y in x[1:])
349 349 elif op == 'keyvalue':
350 350 return (op, x[1], _analyze(x[2]))
351 351 elif op == 'func':
352 352 return (op, x[1], _analyze(x[2]))
353 353 raise ValueError('invalid operator %r' % op)
354 354
355 355 def analyze(x):
356 356 """Transform raw parsed tree to evaluatable tree which can be fed to
357 357 optimize() or getset()
358 358
359 359 All pseudo operations should be mapped to real operations or functions
360 360 defined in methods or symbols table respectively.
361 361 """
362 362 return _analyze(x)
363 363
364 364 def _optimize(x):
365 365 if x is None:
366 366 return 0, x
367 367
368 368 op = x[0]
369 369 if op in ('string', 'symbol'):
370 370 return 0.5, x # single revisions are small
371 371 elif op == 'and':
372 372 wa, ta = _optimize(x[1])
373 373 wb, tb = _optimize(x[2])
374 374 w = min(wa, wb)
375 375
376 376 # (draft/secret/_notpublic() & ::x) have a fast path
377 377 m = _match('_() & ancestors(_)', ('and', ta, tb))
378 378 if m and getsymbol(m[1]) in {'draft', 'secret', '_notpublic'}:
379 379 return w, _build('_phaseandancestors(_, _)', m[1], m[2])
380 380
381 381 # (::x and not ::y)/(not ::y and ::x) have a fast path
382 382 m = _matchonly(ta, tb) or _matchonly(tb, ta)
383 383 if m:
384 384 return w, _build('only(_, _)', *m[1:])
385 385
386 386 m = _match('not _', tb)
387 387 if m:
388 388 return wa, ('difference', ta, m[1])
389 389 if wa > wb:
390 390 op = 'andsmally'
391 391 return w, (op, ta, tb)
392 392 elif op == 'or':
393 393 # fast path for machine-generated expression, that is likely to have
394 394 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
395 395 ws, ts, ss = [], [], []
396 396 def flushss():
397 397 if not ss:
398 398 return
399 399 if len(ss) == 1:
400 400 w, t = ss[0]
401 401 else:
402 402 s = '\0'.join(t[1] for w, t in ss)
403 403 y = _build('_list(_)', ('string', s))
404 404 w, t = _optimize(y)
405 405 ws.append(w)
406 406 ts.append(t)
407 407 del ss[:]
408 408 for y in getlist(x[1]):
409 409 w, t = _optimize(y)
410 410 if t is not None and (t[0] == 'string' or t[0] == 'symbol'):
411 411 ss.append((w, t))
412 412 continue
413 413 flushss()
414 414 ws.append(w)
415 415 ts.append(t)
416 416 flushss()
417 417 if len(ts) == 1:
418 418 return ws[0], ts[0] # 'or' operation is fully optimized out
419 419 return max(ws), (op, ('list',) + tuple(ts))
420 420 elif op == 'not':
421 421 # Optimize not public() to _notpublic() because we have a fast version
422 422 if _match('public()', x[1]):
423 423 o = _optimize(_build('_notpublic()'))
424 424 return o[0], o[1]
425 425 else:
426 426 o = _optimize(x[1])
427 427 return o[0], (op, o[1])
428 428 elif op == 'rangeall':
429 429 return 1, x
430 430 elif op in ('rangepre', 'rangepost', 'parentpost'):
431 431 o = _optimize(x[1])
432 432 return o[0], (op, o[1])
433 433 elif op in ('dagrange', 'range'):
434 434 wa, ta = _optimize(x[1])
435 435 wb, tb = _optimize(x[2])
436 436 return wa + wb, (op, ta, tb)
437 437 elif op in ('parent', 'ancestor', 'relation', 'subscript'):
438 438 w, t = _optimize(x[1])
439 439 return w, (op, t, x[2])
440 440 elif op == 'relsubscript':
441 441 w, t = _optimize(x[1])
442 442 return w, (op, t, x[2], x[3])
443 443 elif op == 'list':
444 444 ws, ts = zip(*(_optimize(y) for y in x[1:]))
445 445 return sum(ws), (op,) + ts
446 446 elif op == 'keyvalue':
447 447 w, t = _optimize(x[2])
448 448 return w, (op, x[1], t)
449 449 elif op == 'func':
450 450 f = getsymbol(x[1])
451 451 wa, ta = _optimize(x[2])
452 452 w = getattr(symbols.get(f), '_weight', 1)
453 453 return w + wa, (op, x[1], ta)
454 454 raise ValueError('invalid operator %r' % op)
455 455
456 456 def optimize(tree):
457 457 """Optimize evaluatable tree
458 458
459 459 All pseudo operations should be transformed beforehand.
460 460 """
461 461 _weight, newtree = _optimize(tree)
462 462 return newtree
463 463
464 464 # the set of valid characters for the initial letter of symbols in
465 465 # alias declarations and definitions
466 466 _aliassyminitletters = _syminitletters | {'$'}
467 467
468 468 def _parsewith(spec, lookup=None, syminitletters=None):
469 469 """Generate a parse tree of given spec with given tokenizing options
470 470
471 471 >>> _parsewith(b'foo($1)', syminitletters=_aliassyminitletters)
472 472 ('func', ('symbol', 'foo'), ('symbol', '$1'))
473 473 >>> _parsewith(b'$1')
474 474 Traceback (most recent call last):
475 475 ...
476 476 ParseError: ("syntax error in revset '$1'", 0)
477 477 >>> _parsewith(b'foo bar')
478 478 Traceback (most recent call last):
479 479 ...
480 480 ParseError: ('invalid token', 4)
481 481 """
482 482 p = parser.parser(elements)
483 483 tree, pos = p.parse(tokenize(spec, lookup=lookup,
484 484 syminitletters=syminitletters))
485 485 if pos != len(spec):
486 486 raise error.ParseError(_('invalid token'), pos)
487 487 return _fixops(parser.simplifyinfixops(tree, ('list', 'or')))
488 488
489 489 class _aliasrules(parser.basealiasrules):
490 490 """Parsing and expansion rule set of revset aliases"""
491 491 _section = _('revset alias')
492 492
493 493 @staticmethod
494 494 def _parse(spec):
495 495 """Parse alias declaration/definition ``spec``
496 496
497 497 This allows symbol names to use also ``$`` as an initial letter
498 498 (for backward compatibility), and callers of this function should
499 499 examine whether ``$`` is used also for unexpected symbols or not.
500 500 """
501 501 return _parsewith(spec, syminitletters=_aliassyminitletters)
502 502
503 503 @staticmethod
504 504 def _trygetfunc(tree):
505 505 if tree[0] == 'func' and tree[1][0] == 'symbol':
506 506 return tree[1][1], getlist(tree[2])
507 507
508 508 def expandaliases(tree, aliases, warn=None):
509 509 """Expand aliases in a tree, aliases is a list of (name, value) tuples"""
510 510 aliases = _aliasrules.buildmap(aliases)
511 511 tree = _aliasrules.expand(aliases, tree)
512 512 # warn about problematic (but not referred) aliases
513 513 if warn is not None:
514 514 for name, alias in sorted(aliases.iteritems()):
515 515 if alias.error and not alias.warned:
516 516 warn(_('warning: %s\n') % (alias.error))
517 517 alias.warned = True
518 518 return tree
519 519
520 520 def foldconcat(tree):
521 521 """Fold elements to be concatenated by `##`
522 522 """
523 523 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
524 524 return tree
525 525 if tree[0] == '_concat':
526 526 pending = [tree]
527 527 l = []
528 528 while pending:
529 529 e = pending.pop()
530 530 if e[0] == '_concat':
531 531 pending.extend(reversed(e[1:]))
532 532 elif e[0] in ('string', 'symbol'):
533 533 l.append(e[1])
534 534 else:
535 535 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
536 536 raise error.ParseError(msg)
537 537 return ('string', ''.join(l))
538 538 else:
539 539 return tuple(foldconcat(t) for t in tree)
540 540
541 541 def parse(spec, lookup=None):
542 542 return _parsewith(spec, lookup=lookup)
543 543
544 544 def _quote(s):
545 545 r"""Quote a value in order to make it safe for the revset engine.
546 546
547 547 >>> _quote(b'asdf')
548 548 "'asdf'"
549 549 >>> _quote(b"asdf'\"")
550 550 '\'asdf\\\'"\''
551 551 >>> _quote(b'asdf\'')
552 552 "'asdf\\''"
553 553 >>> _quote(1)
554 554 "'1'"
555 555 """
556 556 return "'%s'" % util.escapestr(pycompat.bytestr(s))
557 557
558 558 def formatspec(expr, *args):
559 559 '''
560 560 This is a convenience function for using revsets internally, and
561 561 escapes arguments appropriately. Aliases are intentionally ignored
562 562 so that intended expression behavior isn't accidentally subverted.
563 563
564 564 Supported arguments:
565 565
566 566 %r = revset expression, parenthesized
567 567 %d = int(arg), no quoting
568 568 %s = string(arg), escaped and single-quoted
569 569 %b = arg.branch(), escaped and single-quoted
570 570 %n = hex(arg), single-quoted
571 571 %% = a literal '%'
572 572
573 573 Prefixing the type with 'l' specifies a parenthesized list of that type.
574 574
575 575 >>> formatspec(b'%r:: and %lr', b'10 or 11', (b"this()", b"that()"))
576 576 '(10 or 11):: and ((this()) or (that()))'
577 577 >>> formatspec(b'%d:: and not %d::', 10, 20)
578 578 '10:: and not 20::'
579 579 >>> formatspec(b'%ld or %ld', [], [1])
580 580 "_list('') or 1"
581 581 >>> formatspec(b'keyword(%s)', b'foo\\xe9')
582 582 "keyword('foo\\\\xe9')"
583 583 >>> b = lambda: b'default'
584 584 >>> b.branch = b
585 585 >>> formatspec(b'branch(%b)', b)
586 586 "branch('default')"
587 587 >>> formatspec(b'root(%ls)', [b'a', b'b', b'c', b'd'])
588 588 "root(_list('a\\x00b\\x00c\\x00d'))"
589 589 '''
590 590
591 591 def argtype(c, arg):
592 592 if c == 'd':
593 593 return '%d' % int(arg)
594 594 elif c == 's':
595 595 return _quote(arg)
596 596 elif c == 'r':
597 597 parse(arg) # make sure syntax errors are confined
598 598 return '(%s)' % arg
599 599 elif c == 'n':
600 600 return _quote(node.hex(arg))
601 601 elif c == 'b':
602 602 return _quote(arg.branch())
603 603 raise error.ParseError(_('unexpected revspec format character %s') % c)
604 604
605 605 def listexp(s, t):
606 606 l = len(s)
607 607 if l == 0:
608 608 return "_list('')"
609 609 elif l == 1:
610 610 return argtype(t, s[0])
611 611 elif t == 'd':
612 612 return "_intlist('%s')" % "\0".join('%d' % int(a) for a in s)
613 613 elif t == 's':
614 614 return "_list('%s')" % "\0".join(s)
615 615 elif t == 'n':
616 616 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
617 617 elif t == 'b':
618 618 return "_list('%s')" % "\0".join(a.branch() for a in s)
619 619
620 620 m = l // 2
621 621 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
622 622
623 623 expr = pycompat.bytestr(expr)
624 624 argiter = iter(args)
625 625 ret = []
626 626 pos = 0
627 627 while pos < len(expr):
628 628 q = expr.find('%', pos)
629 629 if q < 0:
630 630 ret.append(expr[pos:])
631 631 break
632 632 ret.append(expr[pos:q])
633 633 pos = q + 1
634 d = expr[pos]
634 try:
635 d = expr[pos]
636 except IndexError:
637 raise error.ParseError(_('incomplete revspec format character'))
635 638 if d == '%':
636 639 ret.append(d)
637 640 pos += 1
638 641 continue
639 642
640 643 try:
641 644 arg = next(argiter)
642 645 except StopIteration:
643 646 raise error.ParseError(_('missing argument for revspec'))
644 647 if d == 'l':
645 648 # a list of some type
646 649 pos += 1
647 d = expr[pos]
650 try:
651 d = expr[pos]
652 except IndexError:
653 raise error.ParseError(_('incomplete revspec format character'))
648 654 ret.append(listexp(list(arg), d))
649 655 else:
650 656 ret.append(argtype(d, arg))
651 657 pos += 1
652 658
653 659 try:
654 660 next(argiter)
655 661 raise error.ParseError(_('too many revspec arguments specified'))
656 662 except StopIteration:
657 663 pass
658 664 return ''.join(ret)
659 665
660 666 def prettyformat(tree):
661 667 return parser.prettyformat(tree, ('string', 'symbol'))
662 668
663 669 def depth(tree):
664 670 if isinstance(tree, tuple):
665 671 return max(map(depth, tree)) + 1
666 672 else:
667 673 return 0
668 674
669 675 def funcsused(tree):
670 676 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
671 677 return set()
672 678 else:
673 679 funcs = set()
674 680 for s in tree[1:]:
675 681 funcs |= funcsused(s)
676 682 if tree[0] == 'func':
677 683 funcs.add(tree[1][1])
678 684 return funcs
679 685
680 686 _hashre = util.re.compile('[0-9a-fA-F]{1,40}$')
681 687
682 688 def _ishashlikesymbol(symbol):
683 689 """returns true if the symbol looks like a hash"""
684 690 return _hashre.match(symbol)
685 691
686 692 def gethashlikesymbols(tree):
687 693 """returns the list of symbols of the tree that look like hashes
688 694
689 695 >>> gethashlikesymbols(('dagrange', ('symbol', '3'), ('symbol', 'abe3ff')))
690 696 ['3', 'abe3ff']
691 697 >>> gethashlikesymbols(('func', ('symbol', 'precursors'), ('symbol', '.')))
692 698 []
693 699 >>> gethashlikesymbols(('func', ('symbol', 'precursors'), ('symbol', '34')))
694 700 ['34']
695 701 >>> gethashlikesymbols(('symbol', 'abe3ffZ'))
696 702 []
697 703 """
698 704 if not tree:
699 705 return []
700 706
701 707 if tree[0] == "symbol":
702 708 if _ishashlikesymbol(tree[1]):
703 709 return [tree[1]]
704 710 elif len(tree) >= 3:
705 711 results = []
706 712 for subtree in tree[1:]:
707 713 results += gethashlikesymbols(subtree)
708 714 return results
709 715 return []
@@ -1,4735 +1,4741 b''
1 1 $ hg init a
2 2 $ cd a
3 3 $ echo a > a
4 4 $ hg add a
5 5 $ echo line 1 > b
6 6 $ echo line 2 >> b
7 7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8 8
9 9 $ hg add b
10 10 $ echo other 1 > c
11 11 $ echo other 2 >> c
12 12 $ echo >> c
13 13 $ echo other 3 >> c
14 14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15 15
16 16 $ hg add c
17 17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 18 $ echo c >> c
19 19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20 20
21 21 $ echo foo > .hg/branch
22 22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23 23
24 24 $ hg co -q 3
25 25 $ echo other 4 >> d
26 26 $ hg add d
27 27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28 28
29 29 $ hg merge -q foo
30 30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31 31
32 32 Test arithmetic operators have the right precedence:
33 33
34 34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
35 35 2020 1964
36 36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
37 37 9860 5908
38 38
39 39 Test division:
40 40
41 41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
42 42 (template
43 43 (/
44 44 (integer '5')
45 45 (integer '2'))
46 46 (string ' ')
47 47 (func
48 48 (symbol 'mod')
49 49 (list
50 50 (integer '5')
51 51 (integer '2')))
52 52 (string '\n'))
53 53 2 1
54 54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
55 55 (template
56 56 (/
57 57 (integer '5')
58 58 (negate
59 59 (integer '2')))
60 60 (string ' ')
61 61 (func
62 62 (symbol 'mod')
63 63 (list
64 64 (integer '5')
65 65 (negate
66 66 (integer '2'))))
67 67 (string '\n'))
68 68 -3 -1
69 69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
70 70 (template
71 71 (/
72 72 (negate
73 73 (integer '5'))
74 74 (integer '2'))
75 75 (string ' ')
76 76 (func
77 77 (symbol 'mod')
78 78 (list
79 79 (negate
80 80 (integer '5'))
81 81 (integer '2')))
82 82 (string '\n'))
83 83 -3 1
84 84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
85 85 (template
86 86 (/
87 87 (negate
88 88 (integer '5'))
89 89 (negate
90 90 (integer '2')))
91 91 (string ' ')
92 92 (func
93 93 (symbol 'mod')
94 94 (list
95 95 (negate
96 96 (integer '5'))
97 97 (negate
98 98 (integer '2'))))
99 99 (string '\n'))
100 100 2 -1
101 101
102 102 Filters bind closer than arithmetic:
103 103
104 104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
105 105 (template
106 106 (-
107 107 (|
108 108 (func
109 109 (symbol 'revset')
110 110 (string '.'))
111 111 (symbol 'count'))
112 112 (integer '1'))
113 113 (string '\n'))
114 114 0
115 115
116 116 But negate binds closer still:
117 117
118 118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
119 119 (template
120 120 (-
121 121 (integer '1')
122 122 (|
123 123 (integer '3')
124 124 (symbol 'stringify')))
125 125 (string '\n'))
126 126 hg: parse error: arithmetic only defined on integers
127 127 [255]
128 128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
129 129 (template
130 130 (|
131 131 (negate
132 132 (integer '3'))
133 133 (symbol 'stringify'))
134 134 (string '\n'))
135 135 -3
136 136
137 137 Filters bind as close as map operator:
138 138
139 139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
140 140 (template
141 141 (%
142 142 (|
143 143 (symbol 'desc')
144 144 (symbol 'splitlines'))
145 145 (template
146 146 (symbol 'line')
147 147 (string '\n'))))
148 148 line 1
149 149 line 2
150 150
151 151 Keyword arguments:
152 152
153 153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
154 154 (template
155 155 (keyvalue
156 156 (symbol 'foo')
157 157 (|
158 158 (symbol 'bar')
159 159 (symbol 'baz'))))
160 160 hg: parse error: can't use a key-value pair in this context
161 161 [255]
162 162
163 163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
164 164 foo
165 165
166 166 Call function which takes named arguments by filter syntax:
167 167
168 168 $ hg debugtemplate '{" "|separate}'
169 169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
170 170 hg: parse error: unknown method 'list'
171 171 [255]
172 172
173 173 Second branch starting at nullrev:
174 174
175 175 $ hg update null
176 176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
177 177 $ echo second > second
178 178 $ hg add second
179 179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
180 180 created new head
181 181
182 182 $ echo third > third
183 183 $ hg add third
184 184 $ hg mv second fourth
185 185 $ hg commit -m third -d "2020-01-01 10:01"
186 186
187 187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
188 188 fourth (second)
189 189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
190 190 second -> fourth
191 191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
192 192 8 t
193 193 7 f
194 194
195 195 Working-directory revision has special identifiers, though they are still
196 196 experimental:
197 197
198 198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
199 199 2147483647:ffffffffffffffffffffffffffffffffffffffff
200 200
201 201 Some keywords are invalid for working-directory revision, but they should
202 202 never cause crash:
203 203
204 204 $ hg log -r 'wdir()' -T '{manifest}\n'
205 205
206 206
207 207 Internal resources shouldn't be exposed (issue5699):
208 208
209 209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
210 210
211 211 Never crash on internal resource not available:
212 212
213 213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
214 214 abort: template resource not available: ctx
215 215 [255]
216 216
217 217 Quoting for ui.logtemplate
218 218
219 219 $ hg tip --config "ui.logtemplate={rev}\n"
220 220 8
221 221 $ hg tip --config "ui.logtemplate='{rev}\n'"
222 222 8
223 223 $ hg tip --config 'ui.logtemplate="{rev}\n"'
224 224 8
225 225 $ hg tip --config 'ui.logtemplate=n{rev}\n'
226 226 n8
227 227
228 228 Make sure user/global hgrc does not affect tests
229 229
230 230 $ echo '[ui]' > .hg/hgrc
231 231 $ echo 'logtemplate =' >> .hg/hgrc
232 232 $ echo 'style =' >> .hg/hgrc
233 233
234 234 Add some simple styles to settings
235 235
236 236 $ cat <<'EOF' >> .hg/hgrc
237 237 > [templates]
238 238 > simple = "{rev}\n"
239 239 > simple2 = {rev}\n
240 240 > rev = "should not precede {rev} keyword\n"
241 241 > EOF
242 242
243 243 $ hg log -l1 -Tsimple
244 244 8
245 245 $ hg log -l1 -Tsimple2
246 246 8
247 247 $ hg log -l1 -Trev
248 248 should not precede 8 keyword
249 249 $ hg log -l1 -T '{simple}'
250 250 8
251 251
252 252 Map file shouldn't see user templates:
253 253
254 254 $ cat <<EOF > tmpl
255 255 > changeset = 'nothing expanded:{simple}\n'
256 256 > EOF
257 257 $ hg log -l1 --style ./tmpl
258 258 nothing expanded:
259 259
260 260 Test templates and style maps in files:
261 261
262 262 $ echo "{rev}" > tmpl
263 263 $ hg log -l1 -T./tmpl
264 264 8
265 265 $ hg log -l1 -Tblah/blah
266 266 blah/blah (no-eol)
267 267
268 268 $ printf 'changeset = "{rev}\\n"\n' > map-simple
269 269 $ hg log -l1 -T./map-simple
270 270 8
271 271
272 272 a map file may have [templates] and [templatealias] sections:
273 273
274 274 $ cat <<'EOF' > map-simple
275 275 > [templates]
276 276 > changeset = "{a}\n"
277 277 > [templatealias]
278 278 > a = rev
279 279 > EOF
280 280 $ hg log -l1 -T./map-simple
281 281 8
282 282
283 283 so it can be included in hgrc
284 284
285 285 $ cat <<'EOF' > myhgrc
286 286 > %include map-simple
287 287 > [templates]
288 288 > foo = "{changeset}"
289 289 > EOF
290 290 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
291 291 8
292 292 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
293 293 8
294 294
295 295 Test template map inheritance
296 296
297 297 $ echo "__base__ = map-cmdline.default" > map-simple
298 298 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
299 299 $ hg log -l1 -T./map-simple
300 300 changeset: ***8***
301 301 tag: tip
302 302 user: test
303 303 date: Wed Jan 01 10:01:00 2020 +0000
304 304 summary: third
305 305
306 306
307 307 Test docheader, docfooter and separator in template map
308 308
309 309 $ cat <<'EOF' > map-myjson
310 310 > docheader = '\{\n'
311 311 > docfooter = '\n}\n'
312 312 > separator = ',\n'
313 313 > changeset = ' {dict(rev, node|short)|json}'
314 314 > EOF
315 315 $ hg log -l2 -T./map-myjson
316 316 {
317 317 {"node": "95c24699272e", "rev": 8},
318 318 {"node": "29114dbae42b", "rev": 7}
319 319 }
320 320
321 321 Test docheader, docfooter and separator in [templates] section
322 322
323 323 $ cat <<'EOF' >> .hg/hgrc
324 324 > [templates]
325 325 > myjson = ' {dict(rev, node|short)|json}'
326 326 > myjson:docheader = '\{\n'
327 327 > myjson:docfooter = '\n}\n'
328 328 > myjson:separator = ',\n'
329 329 > :docheader = 'should not be selected as a docheader for literal templates\n'
330 330 > EOF
331 331 $ hg log -l2 -Tmyjson
332 332 {
333 333 {"node": "95c24699272e", "rev": 8},
334 334 {"node": "29114dbae42b", "rev": 7}
335 335 }
336 336 $ hg log -l1 -T'{rev}\n'
337 337 8
338 338
339 339 Template should precede style option
340 340
341 341 $ hg log -l1 --style default -T '{rev}\n'
342 342 8
343 343
344 344 Add a commit with empty description, to ensure that the templates
345 345 below will omit the description line.
346 346
347 347 $ echo c >> c
348 348 $ hg add c
349 349 $ hg commit -qm ' '
350 350
351 351 Default style is like normal output. Phases style should be the same
352 352 as default style, except for extra phase lines.
353 353
354 354 $ hg log > log.out
355 355 $ hg log --style default > style.out
356 356 $ cmp log.out style.out || diff -u log.out style.out
357 357 $ hg log -T phases > phases.out
358 358 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
359 359 +phase: draft
360 360 +phase: draft
361 361 +phase: draft
362 362 +phase: draft
363 363 +phase: draft
364 364 +phase: draft
365 365 +phase: draft
366 366 +phase: draft
367 367 +phase: draft
368 368 +phase: draft
369 369
370 370 $ hg log -v > log.out
371 371 $ hg log -v --style default > style.out
372 372 $ cmp log.out style.out || diff -u log.out style.out
373 373 $ hg log -v -T phases > phases.out
374 374 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
375 375 +phase: draft
376 376 +phase: draft
377 377 +phase: draft
378 378 +phase: draft
379 379 +phase: draft
380 380 +phase: draft
381 381 +phase: draft
382 382 +phase: draft
383 383 +phase: draft
384 384 +phase: draft
385 385
386 386 $ hg log -q > log.out
387 387 $ hg log -q --style default > style.out
388 388 $ cmp log.out style.out || diff -u log.out style.out
389 389 $ hg log -q -T phases > phases.out
390 390 $ cmp log.out phases.out || diff -u log.out phases.out
391 391
392 392 $ hg log --debug > log.out
393 393 $ hg log --debug --style default > style.out
394 394 $ cmp log.out style.out || diff -u log.out style.out
395 395 $ hg log --debug -T phases > phases.out
396 396 $ cmp log.out phases.out || diff -u log.out phases.out
397 397
398 398 Default style of working-directory revision should also be the same (but
399 399 date may change while running tests):
400 400
401 401 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
402 402 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
403 403 $ cmp log.out style.out || diff -u log.out style.out
404 404
405 405 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
406 406 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
407 407 $ cmp log.out style.out || diff -u log.out style.out
408 408
409 409 $ hg log -r 'wdir()' -q > log.out
410 410 $ hg log -r 'wdir()' -q --style default > style.out
411 411 $ cmp log.out style.out || diff -u log.out style.out
412 412
413 413 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
414 414 $ hg log -r 'wdir()' --debug --style default \
415 415 > | sed 's|^date:.*|date:|' > style.out
416 416 $ cmp log.out style.out || diff -u log.out style.out
417 417
418 418 Default style should also preserve color information (issue2866):
419 419
420 420 $ cp $HGRCPATH $HGRCPATH-bak
421 421 $ cat <<EOF >> $HGRCPATH
422 422 > [extensions]
423 423 > color=
424 424 > EOF
425 425
426 426 $ hg --color=debug log > log.out
427 427 $ hg --color=debug log --style default > style.out
428 428 $ cmp log.out style.out || diff -u log.out style.out
429 429 $ hg --color=debug log -T phases > phases.out
430 430 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
431 431 +[log.phase|phase: draft]
432 432 +[log.phase|phase: draft]
433 433 +[log.phase|phase: draft]
434 434 +[log.phase|phase: draft]
435 435 +[log.phase|phase: draft]
436 436 +[log.phase|phase: draft]
437 437 +[log.phase|phase: draft]
438 438 +[log.phase|phase: draft]
439 439 +[log.phase|phase: draft]
440 440 +[log.phase|phase: draft]
441 441
442 442 $ hg --color=debug -v log > log.out
443 443 $ hg --color=debug -v log --style default > style.out
444 444 $ cmp log.out style.out || diff -u log.out style.out
445 445 $ hg --color=debug -v log -T phases > phases.out
446 446 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
447 447 +[log.phase|phase: draft]
448 448 +[log.phase|phase: draft]
449 449 +[log.phase|phase: draft]
450 450 +[log.phase|phase: draft]
451 451 +[log.phase|phase: draft]
452 452 +[log.phase|phase: draft]
453 453 +[log.phase|phase: draft]
454 454 +[log.phase|phase: draft]
455 455 +[log.phase|phase: draft]
456 456 +[log.phase|phase: draft]
457 457
458 458 $ hg --color=debug -q log > log.out
459 459 $ hg --color=debug -q log --style default > style.out
460 460 $ cmp log.out style.out || diff -u log.out style.out
461 461 $ hg --color=debug -q log -T phases > phases.out
462 462 $ cmp log.out phases.out || diff -u log.out phases.out
463 463
464 464 $ hg --color=debug --debug log > log.out
465 465 $ hg --color=debug --debug log --style default > style.out
466 466 $ cmp log.out style.out || diff -u log.out style.out
467 467 $ hg --color=debug --debug log -T phases > phases.out
468 468 $ cmp log.out phases.out || diff -u log.out phases.out
469 469
470 470 $ mv $HGRCPATH-bak $HGRCPATH
471 471
472 472 Remove commit with empty commit message, so as to not pollute further
473 473 tests.
474 474
475 475 $ hg --config extensions.strip= strip -q .
476 476
477 477 Revision with no copies (used to print a traceback):
478 478
479 479 $ hg tip -v --template '\n'
480 480
481 481
482 482 Compact style works:
483 483
484 484 $ hg log -Tcompact
485 485 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
486 486 third
487 487
488 488 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
489 489 second
490 490
491 491 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
492 492 merge
493 493
494 494 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
495 495 new head
496 496
497 497 4 bbe44766e73d 1970-01-17 04:53 +0000 person
498 498 new branch
499 499
500 500 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
501 501 no user, no domain
502 502
503 503 2 97054abb4ab8 1970-01-14 21:20 +0000 other
504 504 no person
505 505
506 506 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
507 507 other 1
508 508
509 509 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
510 510 line 1
511 511
512 512
513 513 $ hg log -v --style compact
514 514 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
515 515 third
516 516
517 517 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
518 518 second
519 519
520 520 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
521 521 merge
522 522
523 523 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
524 524 new head
525 525
526 526 4 bbe44766e73d 1970-01-17 04:53 +0000 person
527 527 new branch
528 528
529 529 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
530 530 no user, no domain
531 531
532 532 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
533 533 no person
534 534
535 535 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
536 536 other 1
537 537 other 2
538 538
539 539 other 3
540 540
541 541 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
542 542 line 1
543 543 line 2
544 544
545 545
546 546 $ hg log --debug --style compact
547 547 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
548 548 third
549 549
550 550 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
551 551 second
552 552
553 553 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
554 554 merge
555 555
556 556 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
557 557 new head
558 558
559 559 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
560 560 new branch
561 561
562 562 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
563 563 no user, no domain
564 564
565 565 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
566 566 no person
567 567
568 568 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
569 569 other 1
570 570 other 2
571 571
572 572 other 3
573 573
574 574 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
575 575 line 1
576 576 line 2
577 577
578 578
579 579 Test xml styles:
580 580
581 581 $ hg log --style xml -r 'not all()'
582 582 <?xml version="1.0"?>
583 583 <log>
584 584 </log>
585 585
586 586 $ hg log --style xml
587 587 <?xml version="1.0"?>
588 588 <log>
589 589 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
590 590 <tag>tip</tag>
591 591 <author email="test">test</author>
592 592 <date>2020-01-01T10:01:00+00:00</date>
593 593 <msg xml:space="preserve">third</msg>
594 594 </logentry>
595 595 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
596 596 <parent revision="-1" node="0000000000000000000000000000000000000000" />
597 597 <author email="user@hostname">User Name</author>
598 598 <date>1970-01-12T13:46:40+00:00</date>
599 599 <msg xml:space="preserve">second</msg>
600 600 </logentry>
601 601 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
602 602 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
603 603 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
604 604 <author email="person">person</author>
605 605 <date>1970-01-18T08:40:01+00:00</date>
606 606 <msg xml:space="preserve">merge</msg>
607 607 </logentry>
608 608 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
609 609 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
610 610 <author email="person">person</author>
611 611 <date>1970-01-18T08:40:00+00:00</date>
612 612 <msg xml:space="preserve">new head</msg>
613 613 </logentry>
614 614 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
615 615 <branch>foo</branch>
616 616 <author email="person">person</author>
617 617 <date>1970-01-17T04:53:20+00:00</date>
618 618 <msg xml:space="preserve">new branch</msg>
619 619 </logentry>
620 620 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
621 621 <author email="person">person</author>
622 622 <date>1970-01-16T01:06:40+00:00</date>
623 623 <msg xml:space="preserve">no user, no domain</msg>
624 624 </logentry>
625 625 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
626 626 <author email="other@place">other</author>
627 627 <date>1970-01-14T21:20:00+00:00</date>
628 628 <msg xml:space="preserve">no person</msg>
629 629 </logentry>
630 630 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
631 631 <author email="other@place">A. N. Other</author>
632 632 <date>1970-01-13T17:33:20+00:00</date>
633 633 <msg xml:space="preserve">other 1
634 634 other 2
635 635
636 636 other 3</msg>
637 637 </logentry>
638 638 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
639 639 <author email="user@hostname">User Name</author>
640 640 <date>1970-01-12T13:46:40+00:00</date>
641 641 <msg xml:space="preserve">line 1
642 642 line 2</msg>
643 643 </logentry>
644 644 </log>
645 645
646 646 $ hg log -v --style xml
647 647 <?xml version="1.0"?>
648 648 <log>
649 649 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
650 650 <tag>tip</tag>
651 651 <author email="test">test</author>
652 652 <date>2020-01-01T10:01:00+00:00</date>
653 653 <msg xml:space="preserve">third</msg>
654 654 <paths>
655 655 <path action="A">fourth</path>
656 656 <path action="A">third</path>
657 657 <path action="R">second</path>
658 658 </paths>
659 659 <copies>
660 660 <copy source="second">fourth</copy>
661 661 </copies>
662 662 </logentry>
663 663 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
664 664 <parent revision="-1" node="0000000000000000000000000000000000000000" />
665 665 <author email="user@hostname">User Name</author>
666 666 <date>1970-01-12T13:46:40+00:00</date>
667 667 <msg xml:space="preserve">second</msg>
668 668 <paths>
669 669 <path action="A">second</path>
670 670 </paths>
671 671 </logentry>
672 672 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
673 673 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
674 674 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
675 675 <author email="person">person</author>
676 676 <date>1970-01-18T08:40:01+00:00</date>
677 677 <msg xml:space="preserve">merge</msg>
678 678 <paths>
679 679 </paths>
680 680 </logentry>
681 681 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
682 682 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
683 683 <author email="person">person</author>
684 684 <date>1970-01-18T08:40:00+00:00</date>
685 685 <msg xml:space="preserve">new head</msg>
686 686 <paths>
687 687 <path action="A">d</path>
688 688 </paths>
689 689 </logentry>
690 690 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
691 691 <branch>foo</branch>
692 692 <author email="person">person</author>
693 693 <date>1970-01-17T04:53:20+00:00</date>
694 694 <msg xml:space="preserve">new branch</msg>
695 695 <paths>
696 696 </paths>
697 697 </logentry>
698 698 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
699 699 <author email="person">person</author>
700 700 <date>1970-01-16T01:06:40+00:00</date>
701 701 <msg xml:space="preserve">no user, no domain</msg>
702 702 <paths>
703 703 <path action="M">c</path>
704 704 </paths>
705 705 </logentry>
706 706 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
707 707 <author email="other@place">other</author>
708 708 <date>1970-01-14T21:20:00+00:00</date>
709 709 <msg xml:space="preserve">no person</msg>
710 710 <paths>
711 711 <path action="A">c</path>
712 712 </paths>
713 713 </logentry>
714 714 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
715 715 <author email="other@place">A. N. Other</author>
716 716 <date>1970-01-13T17:33:20+00:00</date>
717 717 <msg xml:space="preserve">other 1
718 718 other 2
719 719
720 720 other 3</msg>
721 721 <paths>
722 722 <path action="A">b</path>
723 723 </paths>
724 724 </logentry>
725 725 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
726 726 <author email="user@hostname">User Name</author>
727 727 <date>1970-01-12T13:46:40+00:00</date>
728 728 <msg xml:space="preserve">line 1
729 729 line 2</msg>
730 730 <paths>
731 731 <path action="A">a</path>
732 732 </paths>
733 733 </logentry>
734 734 </log>
735 735
736 736 $ hg log --debug --style xml
737 737 <?xml version="1.0"?>
738 738 <log>
739 739 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
740 740 <tag>tip</tag>
741 741 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
742 742 <parent revision="-1" node="0000000000000000000000000000000000000000" />
743 743 <author email="test">test</author>
744 744 <date>2020-01-01T10:01:00+00:00</date>
745 745 <msg xml:space="preserve">third</msg>
746 746 <paths>
747 747 <path action="A">fourth</path>
748 748 <path action="A">third</path>
749 749 <path action="R">second</path>
750 750 </paths>
751 751 <copies>
752 752 <copy source="second">fourth</copy>
753 753 </copies>
754 754 <extra key="branch">default</extra>
755 755 </logentry>
756 756 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
757 757 <parent revision="-1" node="0000000000000000000000000000000000000000" />
758 758 <parent revision="-1" node="0000000000000000000000000000000000000000" />
759 759 <author email="user@hostname">User Name</author>
760 760 <date>1970-01-12T13:46:40+00:00</date>
761 761 <msg xml:space="preserve">second</msg>
762 762 <paths>
763 763 <path action="A">second</path>
764 764 </paths>
765 765 <extra key="branch">default</extra>
766 766 </logentry>
767 767 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
768 768 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
769 769 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
770 770 <author email="person">person</author>
771 771 <date>1970-01-18T08:40:01+00:00</date>
772 772 <msg xml:space="preserve">merge</msg>
773 773 <paths>
774 774 </paths>
775 775 <extra key="branch">default</extra>
776 776 </logentry>
777 777 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
778 778 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
779 779 <parent revision="-1" node="0000000000000000000000000000000000000000" />
780 780 <author email="person">person</author>
781 781 <date>1970-01-18T08:40:00+00:00</date>
782 782 <msg xml:space="preserve">new head</msg>
783 783 <paths>
784 784 <path action="A">d</path>
785 785 </paths>
786 786 <extra key="branch">default</extra>
787 787 </logentry>
788 788 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
789 789 <branch>foo</branch>
790 790 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
791 791 <parent revision="-1" node="0000000000000000000000000000000000000000" />
792 792 <author email="person">person</author>
793 793 <date>1970-01-17T04:53:20+00:00</date>
794 794 <msg xml:space="preserve">new branch</msg>
795 795 <paths>
796 796 </paths>
797 797 <extra key="branch">foo</extra>
798 798 </logentry>
799 799 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
800 800 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
801 801 <parent revision="-1" node="0000000000000000000000000000000000000000" />
802 802 <author email="person">person</author>
803 803 <date>1970-01-16T01:06:40+00:00</date>
804 804 <msg xml:space="preserve">no user, no domain</msg>
805 805 <paths>
806 806 <path action="M">c</path>
807 807 </paths>
808 808 <extra key="branch">default</extra>
809 809 </logentry>
810 810 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
811 811 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
812 812 <parent revision="-1" node="0000000000000000000000000000000000000000" />
813 813 <author email="other@place">other</author>
814 814 <date>1970-01-14T21:20:00+00:00</date>
815 815 <msg xml:space="preserve">no person</msg>
816 816 <paths>
817 817 <path action="A">c</path>
818 818 </paths>
819 819 <extra key="branch">default</extra>
820 820 </logentry>
821 821 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
822 822 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
823 823 <parent revision="-1" node="0000000000000000000000000000000000000000" />
824 824 <author email="other@place">A. N. Other</author>
825 825 <date>1970-01-13T17:33:20+00:00</date>
826 826 <msg xml:space="preserve">other 1
827 827 other 2
828 828
829 829 other 3</msg>
830 830 <paths>
831 831 <path action="A">b</path>
832 832 </paths>
833 833 <extra key="branch">default</extra>
834 834 </logentry>
835 835 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
836 836 <parent revision="-1" node="0000000000000000000000000000000000000000" />
837 837 <parent revision="-1" node="0000000000000000000000000000000000000000" />
838 838 <author email="user@hostname">User Name</author>
839 839 <date>1970-01-12T13:46:40+00:00</date>
840 840 <msg xml:space="preserve">line 1
841 841 line 2</msg>
842 842 <paths>
843 843 <path action="A">a</path>
844 844 </paths>
845 845 <extra key="branch">default</extra>
846 846 </logentry>
847 847 </log>
848 848
849 849
850 850 Test JSON style:
851 851
852 852 $ hg log -k nosuch -Tjson
853 853 []
854 854
855 855 $ hg log -qr . -Tjson
856 856 [
857 857 {
858 858 "rev": 8,
859 859 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
860 860 }
861 861 ]
862 862
863 863 $ hg log -vpr . -Tjson --stat
864 864 [
865 865 {
866 866 "rev": 8,
867 867 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
868 868 "branch": "default",
869 869 "phase": "draft",
870 870 "user": "test",
871 871 "date": [1577872860, 0],
872 872 "desc": "third",
873 873 "bookmarks": [],
874 874 "tags": ["tip"],
875 875 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
876 876 "files": ["fourth", "second", "third"],
877 877 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
878 878 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
879 879 }
880 880 ]
881 881
882 882 honor --git but not format-breaking diffopts
883 883 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
884 884 [
885 885 {
886 886 "rev": 8,
887 887 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
888 888 "branch": "default",
889 889 "phase": "draft",
890 890 "user": "test",
891 891 "date": [1577872860, 0],
892 892 "desc": "third",
893 893 "bookmarks": [],
894 894 "tags": ["tip"],
895 895 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
896 896 "files": ["fourth", "second", "third"],
897 897 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
898 898 }
899 899 ]
900 900
901 901 $ hg log -T json
902 902 [
903 903 {
904 904 "rev": 8,
905 905 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
906 906 "branch": "default",
907 907 "phase": "draft",
908 908 "user": "test",
909 909 "date": [1577872860, 0],
910 910 "desc": "third",
911 911 "bookmarks": [],
912 912 "tags": ["tip"],
913 913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
914 914 },
915 915 {
916 916 "rev": 7,
917 917 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
918 918 "branch": "default",
919 919 "phase": "draft",
920 920 "user": "User Name <user@hostname>",
921 921 "date": [1000000, 0],
922 922 "desc": "second",
923 923 "bookmarks": [],
924 924 "tags": [],
925 925 "parents": ["0000000000000000000000000000000000000000"]
926 926 },
927 927 {
928 928 "rev": 6,
929 929 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
930 930 "branch": "default",
931 931 "phase": "draft",
932 932 "user": "person",
933 933 "date": [1500001, 0],
934 934 "desc": "merge",
935 935 "bookmarks": [],
936 936 "tags": [],
937 937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
938 938 },
939 939 {
940 940 "rev": 5,
941 941 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
942 942 "branch": "default",
943 943 "phase": "draft",
944 944 "user": "person",
945 945 "date": [1500000, 0],
946 946 "desc": "new head",
947 947 "bookmarks": [],
948 948 "tags": [],
949 949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
950 950 },
951 951 {
952 952 "rev": 4,
953 953 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
954 954 "branch": "foo",
955 955 "phase": "draft",
956 956 "user": "person",
957 957 "date": [1400000, 0],
958 958 "desc": "new branch",
959 959 "bookmarks": [],
960 960 "tags": [],
961 961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
962 962 },
963 963 {
964 964 "rev": 3,
965 965 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
966 966 "branch": "default",
967 967 "phase": "draft",
968 968 "user": "person",
969 969 "date": [1300000, 0],
970 970 "desc": "no user, no domain",
971 971 "bookmarks": [],
972 972 "tags": [],
973 973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
974 974 },
975 975 {
976 976 "rev": 2,
977 977 "node": "97054abb4ab824450e9164180baf491ae0078465",
978 978 "branch": "default",
979 979 "phase": "draft",
980 980 "user": "other@place",
981 981 "date": [1200000, 0],
982 982 "desc": "no person",
983 983 "bookmarks": [],
984 984 "tags": [],
985 985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
986 986 },
987 987 {
988 988 "rev": 1,
989 989 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
990 990 "branch": "default",
991 991 "phase": "draft",
992 992 "user": "A. N. Other <other@place>",
993 993 "date": [1100000, 0],
994 994 "desc": "other 1\nother 2\n\nother 3",
995 995 "bookmarks": [],
996 996 "tags": [],
997 997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
998 998 },
999 999 {
1000 1000 "rev": 0,
1001 1001 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1002 1002 "branch": "default",
1003 1003 "phase": "draft",
1004 1004 "user": "User Name <user@hostname>",
1005 1005 "date": [1000000, 0],
1006 1006 "desc": "line 1\nline 2",
1007 1007 "bookmarks": [],
1008 1008 "tags": [],
1009 1009 "parents": ["0000000000000000000000000000000000000000"]
1010 1010 }
1011 1011 ]
1012 1012
1013 1013 $ hg heads -v -Tjson
1014 1014 [
1015 1015 {
1016 1016 "rev": 8,
1017 1017 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1018 1018 "branch": "default",
1019 1019 "phase": "draft",
1020 1020 "user": "test",
1021 1021 "date": [1577872860, 0],
1022 1022 "desc": "third",
1023 1023 "bookmarks": [],
1024 1024 "tags": ["tip"],
1025 1025 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1026 1026 "files": ["fourth", "second", "third"]
1027 1027 },
1028 1028 {
1029 1029 "rev": 6,
1030 1030 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1031 1031 "branch": "default",
1032 1032 "phase": "draft",
1033 1033 "user": "person",
1034 1034 "date": [1500001, 0],
1035 1035 "desc": "merge",
1036 1036 "bookmarks": [],
1037 1037 "tags": [],
1038 1038 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1039 1039 "files": []
1040 1040 },
1041 1041 {
1042 1042 "rev": 4,
1043 1043 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1044 1044 "branch": "foo",
1045 1045 "phase": "draft",
1046 1046 "user": "person",
1047 1047 "date": [1400000, 0],
1048 1048 "desc": "new branch",
1049 1049 "bookmarks": [],
1050 1050 "tags": [],
1051 1051 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1052 1052 "files": []
1053 1053 }
1054 1054 ]
1055 1055
1056 1056 $ hg log --debug -Tjson
1057 1057 [
1058 1058 {
1059 1059 "rev": 8,
1060 1060 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1061 1061 "branch": "default",
1062 1062 "phase": "draft",
1063 1063 "user": "test",
1064 1064 "date": [1577872860, 0],
1065 1065 "desc": "third",
1066 1066 "bookmarks": [],
1067 1067 "tags": ["tip"],
1068 1068 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1069 1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1070 1070 "extra": {"branch": "default"},
1071 1071 "modified": [],
1072 1072 "added": ["fourth", "third"],
1073 1073 "removed": ["second"]
1074 1074 },
1075 1075 {
1076 1076 "rev": 7,
1077 1077 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1078 1078 "branch": "default",
1079 1079 "phase": "draft",
1080 1080 "user": "User Name <user@hostname>",
1081 1081 "date": [1000000, 0],
1082 1082 "desc": "second",
1083 1083 "bookmarks": [],
1084 1084 "tags": [],
1085 1085 "parents": ["0000000000000000000000000000000000000000"],
1086 1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1087 1087 "extra": {"branch": "default"},
1088 1088 "modified": [],
1089 1089 "added": ["second"],
1090 1090 "removed": []
1091 1091 },
1092 1092 {
1093 1093 "rev": 6,
1094 1094 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1095 1095 "branch": "default",
1096 1096 "phase": "draft",
1097 1097 "user": "person",
1098 1098 "date": [1500001, 0],
1099 1099 "desc": "merge",
1100 1100 "bookmarks": [],
1101 1101 "tags": [],
1102 1102 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1103 1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1104 1104 "extra": {"branch": "default"},
1105 1105 "modified": [],
1106 1106 "added": [],
1107 1107 "removed": []
1108 1108 },
1109 1109 {
1110 1110 "rev": 5,
1111 1111 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1112 1112 "branch": "default",
1113 1113 "phase": "draft",
1114 1114 "user": "person",
1115 1115 "date": [1500000, 0],
1116 1116 "desc": "new head",
1117 1117 "bookmarks": [],
1118 1118 "tags": [],
1119 1119 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1120 1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1121 1121 "extra": {"branch": "default"},
1122 1122 "modified": [],
1123 1123 "added": ["d"],
1124 1124 "removed": []
1125 1125 },
1126 1126 {
1127 1127 "rev": 4,
1128 1128 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1129 1129 "branch": "foo",
1130 1130 "phase": "draft",
1131 1131 "user": "person",
1132 1132 "date": [1400000, 0],
1133 1133 "desc": "new branch",
1134 1134 "bookmarks": [],
1135 1135 "tags": [],
1136 1136 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1137 1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1138 1138 "extra": {"branch": "foo"},
1139 1139 "modified": [],
1140 1140 "added": [],
1141 1141 "removed": []
1142 1142 },
1143 1143 {
1144 1144 "rev": 3,
1145 1145 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1146 1146 "branch": "default",
1147 1147 "phase": "draft",
1148 1148 "user": "person",
1149 1149 "date": [1300000, 0],
1150 1150 "desc": "no user, no domain",
1151 1151 "bookmarks": [],
1152 1152 "tags": [],
1153 1153 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1154 1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1155 1155 "extra": {"branch": "default"},
1156 1156 "modified": ["c"],
1157 1157 "added": [],
1158 1158 "removed": []
1159 1159 },
1160 1160 {
1161 1161 "rev": 2,
1162 1162 "node": "97054abb4ab824450e9164180baf491ae0078465",
1163 1163 "branch": "default",
1164 1164 "phase": "draft",
1165 1165 "user": "other@place",
1166 1166 "date": [1200000, 0],
1167 1167 "desc": "no person",
1168 1168 "bookmarks": [],
1169 1169 "tags": [],
1170 1170 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1171 1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1172 1172 "extra": {"branch": "default"},
1173 1173 "modified": [],
1174 1174 "added": ["c"],
1175 1175 "removed": []
1176 1176 },
1177 1177 {
1178 1178 "rev": 1,
1179 1179 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1180 1180 "branch": "default",
1181 1181 "phase": "draft",
1182 1182 "user": "A. N. Other <other@place>",
1183 1183 "date": [1100000, 0],
1184 1184 "desc": "other 1\nother 2\n\nother 3",
1185 1185 "bookmarks": [],
1186 1186 "tags": [],
1187 1187 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1188 1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1189 1189 "extra": {"branch": "default"},
1190 1190 "modified": [],
1191 1191 "added": ["b"],
1192 1192 "removed": []
1193 1193 },
1194 1194 {
1195 1195 "rev": 0,
1196 1196 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1197 1197 "branch": "default",
1198 1198 "phase": "draft",
1199 1199 "user": "User Name <user@hostname>",
1200 1200 "date": [1000000, 0],
1201 1201 "desc": "line 1\nline 2",
1202 1202 "bookmarks": [],
1203 1203 "tags": [],
1204 1204 "parents": ["0000000000000000000000000000000000000000"],
1205 1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1206 1206 "extra": {"branch": "default"},
1207 1207 "modified": [],
1208 1208 "added": ["a"],
1209 1209 "removed": []
1210 1210 }
1211 1211 ]
1212 1212
1213 1213 Error if style not readable:
1214 1214
1215 1215 #if unix-permissions no-root
1216 1216 $ touch q
1217 1217 $ chmod 0 q
1218 1218 $ hg log --style ./q
1219 1219 abort: Permission denied: ./q
1220 1220 [255]
1221 1221 #endif
1222 1222
1223 1223 Error if no style:
1224 1224
1225 1225 $ hg log --style notexist
1226 1226 abort: style 'notexist' not found
1227 1227 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1228 1228 [255]
1229 1229
1230 1230 $ hg log -T list
1231 1231 available styles: bisect, changelog, compact, default, phases, show, status, xml
1232 1232 abort: specify a template
1233 1233 [255]
1234 1234
1235 1235 Error if style missing key:
1236 1236
1237 1237 $ echo 'q = q' > t
1238 1238 $ hg log --style ./t
1239 1239 abort: "changeset" not in template map
1240 1240 [255]
1241 1241
1242 1242 Error if style missing value:
1243 1243
1244 1244 $ echo 'changeset =' > t
1245 1245 $ hg log --style t
1246 1246 hg: parse error at t:1: missing value
1247 1247 [255]
1248 1248
1249 1249 Error if include fails:
1250 1250
1251 1251 $ echo 'changeset = q' >> t
1252 1252 #if unix-permissions no-root
1253 1253 $ hg log --style ./t
1254 1254 abort: template file ./q: Permission denied
1255 1255 [255]
1256 1256 $ rm -f q
1257 1257 #endif
1258 1258
1259 1259 Include works:
1260 1260
1261 1261 $ echo '{rev}' > q
1262 1262 $ hg log --style ./t
1263 1263 8
1264 1264 7
1265 1265 6
1266 1266 5
1267 1267 4
1268 1268 3
1269 1269 2
1270 1270 1
1271 1271 0
1272 1272
1273 1273 Check that recursive reference does not fall into RuntimeError (issue4758):
1274 1274
1275 1275 common mistake:
1276 1276
1277 1277 $ cat << EOF > issue4758
1278 1278 > changeset = '{changeset}\n'
1279 1279 > EOF
1280 1280 $ hg log --style ./issue4758
1281 1281 abort: recursive reference 'changeset' in template
1282 1282 [255]
1283 1283
1284 1284 circular reference:
1285 1285
1286 1286 $ cat << EOF > issue4758
1287 1287 > changeset = '{foo}'
1288 1288 > foo = '{changeset}'
1289 1289 > EOF
1290 1290 $ hg log --style ./issue4758
1291 1291 abort: recursive reference 'foo' in template
1292 1292 [255]
1293 1293
1294 1294 buildmap() -> gettemplate(), where no thunk was made:
1295 1295
1296 1296 $ cat << EOF > issue4758
1297 1297 > changeset = '{files % changeset}\n'
1298 1298 > EOF
1299 1299 $ hg log --style ./issue4758
1300 1300 abort: recursive reference 'changeset' in template
1301 1301 [255]
1302 1302
1303 1303 not a recursion if a keyword of the same name exists:
1304 1304
1305 1305 $ cat << EOF > issue4758
1306 1306 > changeset = '{tags % rev}'
1307 1307 > rev = '{rev} {tag}\n'
1308 1308 > EOF
1309 1309 $ hg log --style ./issue4758 -r tip
1310 1310 8 tip
1311 1311
1312 1312 Check that {phase} works correctly on parents:
1313 1313
1314 1314 $ cat << EOF > parentphase
1315 1315 > changeset_debug = '{rev} ({phase}):{parents}\n'
1316 1316 > parent = ' {rev} ({phase})'
1317 1317 > EOF
1318 1318 $ hg phase -r 5 --public
1319 1319 $ hg phase -r 7 --secret --force
1320 1320 $ hg log --debug -G --style ./parentphase
1321 1321 @ 8 (secret): 7 (secret) -1 (public)
1322 1322 |
1323 1323 o 7 (secret): -1 (public) -1 (public)
1324 1324
1325 1325 o 6 (draft): 5 (public) 4 (draft)
1326 1326 |\
1327 1327 | o 5 (public): 3 (public) -1 (public)
1328 1328 | |
1329 1329 o | 4 (draft): 3 (public) -1 (public)
1330 1330 |/
1331 1331 o 3 (public): 2 (public) -1 (public)
1332 1332 |
1333 1333 o 2 (public): 1 (public) -1 (public)
1334 1334 |
1335 1335 o 1 (public): 0 (public) -1 (public)
1336 1336 |
1337 1337 o 0 (public): -1 (public) -1 (public)
1338 1338
1339 1339
1340 1340 Missing non-standard names give no error (backward compatibility):
1341 1341
1342 1342 $ echo "changeset = '{c}'" > t
1343 1343 $ hg log --style ./t
1344 1344
1345 1345 Defining non-standard name works:
1346 1346
1347 1347 $ cat <<EOF > t
1348 1348 > changeset = '{c}'
1349 1349 > c = q
1350 1350 > EOF
1351 1351 $ hg log --style ./t
1352 1352 8
1353 1353 7
1354 1354 6
1355 1355 5
1356 1356 4
1357 1357 3
1358 1358 2
1359 1359 1
1360 1360 0
1361 1361
1362 1362 ui.style works:
1363 1363
1364 1364 $ echo '[ui]' > .hg/hgrc
1365 1365 $ echo 'style = t' >> .hg/hgrc
1366 1366 $ hg log
1367 1367 8
1368 1368 7
1369 1369 6
1370 1370 5
1371 1371 4
1372 1372 3
1373 1373 2
1374 1374 1
1375 1375 0
1376 1376
1377 1377
1378 1378 Issue338:
1379 1379
1380 1380 $ hg log --style=changelog > changelog
1381 1381
1382 1382 $ cat changelog
1383 1383 2020-01-01 test <test>
1384 1384
1385 1385 * fourth, second, third:
1386 1386 third
1387 1387 [95c24699272e] [tip]
1388 1388
1389 1389 1970-01-12 User Name <user@hostname>
1390 1390
1391 1391 * second:
1392 1392 second
1393 1393 [29114dbae42b]
1394 1394
1395 1395 1970-01-18 person <person>
1396 1396
1397 1397 * merge
1398 1398 [d41e714fe50d]
1399 1399
1400 1400 * d:
1401 1401 new head
1402 1402 [13207e5a10d9]
1403 1403
1404 1404 1970-01-17 person <person>
1405 1405
1406 1406 * new branch
1407 1407 [bbe44766e73d] <foo>
1408 1408
1409 1409 1970-01-16 person <person>
1410 1410
1411 1411 * c:
1412 1412 no user, no domain
1413 1413 [10e46f2dcbf4]
1414 1414
1415 1415 1970-01-14 other <other@place>
1416 1416
1417 1417 * c:
1418 1418 no person
1419 1419 [97054abb4ab8]
1420 1420
1421 1421 1970-01-13 A. N. Other <other@place>
1422 1422
1423 1423 * b:
1424 1424 other 1 other 2
1425 1425
1426 1426 other 3
1427 1427 [b608e9d1a3f0]
1428 1428
1429 1429 1970-01-12 User Name <user@hostname>
1430 1430
1431 1431 * a:
1432 1432 line 1 line 2
1433 1433 [1e4e1b8f71e0]
1434 1434
1435 1435
1436 1436 Issue2130: xml output for 'hg heads' is malformed
1437 1437
1438 1438 $ hg heads --style changelog
1439 1439 2020-01-01 test <test>
1440 1440
1441 1441 * fourth, second, third:
1442 1442 third
1443 1443 [95c24699272e] [tip]
1444 1444
1445 1445 1970-01-18 person <person>
1446 1446
1447 1447 * merge
1448 1448 [d41e714fe50d]
1449 1449
1450 1450 1970-01-17 person <person>
1451 1451
1452 1452 * new branch
1453 1453 [bbe44766e73d] <foo>
1454 1454
1455 1455
1456 1456 Keys work:
1457 1457
1458 1458 $ for key in author branch branches date desc file_adds file_dels file_mods \
1459 1459 > file_copies file_copies_switch files \
1460 1460 > manifest node parents rev tags diffstat extras \
1461 1461 > p1rev p2rev p1node p2node; do
1462 1462 > for mode in '' --verbose --debug; do
1463 1463 > hg log $mode --template "$key$mode: {$key}\n"
1464 1464 > done
1465 1465 > done
1466 1466 author: test
1467 1467 author: User Name <user@hostname>
1468 1468 author: person
1469 1469 author: person
1470 1470 author: person
1471 1471 author: person
1472 1472 author: other@place
1473 1473 author: A. N. Other <other@place>
1474 1474 author: User Name <user@hostname>
1475 1475 author--verbose: test
1476 1476 author--verbose: User Name <user@hostname>
1477 1477 author--verbose: person
1478 1478 author--verbose: person
1479 1479 author--verbose: person
1480 1480 author--verbose: person
1481 1481 author--verbose: other@place
1482 1482 author--verbose: A. N. Other <other@place>
1483 1483 author--verbose: User Name <user@hostname>
1484 1484 author--debug: test
1485 1485 author--debug: User Name <user@hostname>
1486 1486 author--debug: person
1487 1487 author--debug: person
1488 1488 author--debug: person
1489 1489 author--debug: person
1490 1490 author--debug: other@place
1491 1491 author--debug: A. N. Other <other@place>
1492 1492 author--debug: User Name <user@hostname>
1493 1493 branch: default
1494 1494 branch: default
1495 1495 branch: default
1496 1496 branch: default
1497 1497 branch: foo
1498 1498 branch: default
1499 1499 branch: default
1500 1500 branch: default
1501 1501 branch: default
1502 1502 branch--verbose: default
1503 1503 branch--verbose: default
1504 1504 branch--verbose: default
1505 1505 branch--verbose: default
1506 1506 branch--verbose: foo
1507 1507 branch--verbose: default
1508 1508 branch--verbose: default
1509 1509 branch--verbose: default
1510 1510 branch--verbose: default
1511 1511 branch--debug: default
1512 1512 branch--debug: default
1513 1513 branch--debug: default
1514 1514 branch--debug: default
1515 1515 branch--debug: foo
1516 1516 branch--debug: default
1517 1517 branch--debug: default
1518 1518 branch--debug: default
1519 1519 branch--debug: default
1520 1520 branches:
1521 1521 branches:
1522 1522 branches:
1523 1523 branches:
1524 1524 branches: foo
1525 1525 branches:
1526 1526 branches:
1527 1527 branches:
1528 1528 branches:
1529 1529 branches--verbose:
1530 1530 branches--verbose:
1531 1531 branches--verbose:
1532 1532 branches--verbose:
1533 1533 branches--verbose: foo
1534 1534 branches--verbose:
1535 1535 branches--verbose:
1536 1536 branches--verbose:
1537 1537 branches--verbose:
1538 1538 branches--debug:
1539 1539 branches--debug:
1540 1540 branches--debug:
1541 1541 branches--debug:
1542 1542 branches--debug: foo
1543 1543 branches--debug:
1544 1544 branches--debug:
1545 1545 branches--debug:
1546 1546 branches--debug:
1547 1547 date: 1577872860.00
1548 1548 date: 1000000.00
1549 1549 date: 1500001.00
1550 1550 date: 1500000.00
1551 1551 date: 1400000.00
1552 1552 date: 1300000.00
1553 1553 date: 1200000.00
1554 1554 date: 1100000.00
1555 1555 date: 1000000.00
1556 1556 date--verbose: 1577872860.00
1557 1557 date--verbose: 1000000.00
1558 1558 date--verbose: 1500001.00
1559 1559 date--verbose: 1500000.00
1560 1560 date--verbose: 1400000.00
1561 1561 date--verbose: 1300000.00
1562 1562 date--verbose: 1200000.00
1563 1563 date--verbose: 1100000.00
1564 1564 date--verbose: 1000000.00
1565 1565 date--debug: 1577872860.00
1566 1566 date--debug: 1000000.00
1567 1567 date--debug: 1500001.00
1568 1568 date--debug: 1500000.00
1569 1569 date--debug: 1400000.00
1570 1570 date--debug: 1300000.00
1571 1571 date--debug: 1200000.00
1572 1572 date--debug: 1100000.00
1573 1573 date--debug: 1000000.00
1574 1574 desc: third
1575 1575 desc: second
1576 1576 desc: merge
1577 1577 desc: new head
1578 1578 desc: new branch
1579 1579 desc: no user, no domain
1580 1580 desc: no person
1581 1581 desc: other 1
1582 1582 other 2
1583 1583
1584 1584 other 3
1585 1585 desc: line 1
1586 1586 line 2
1587 1587 desc--verbose: third
1588 1588 desc--verbose: second
1589 1589 desc--verbose: merge
1590 1590 desc--verbose: new head
1591 1591 desc--verbose: new branch
1592 1592 desc--verbose: no user, no domain
1593 1593 desc--verbose: no person
1594 1594 desc--verbose: other 1
1595 1595 other 2
1596 1596
1597 1597 other 3
1598 1598 desc--verbose: line 1
1599 1599 line 2
1600 1600 desc--debug: third
1601 1601 desc--debug: second
1602 1602 desc--debug: merge
1603 1603 desc--debug: new head
1604 1604 desc--debug: new branch
1605 1605 desc--debug: no user, no domain
1606 1606 desc--debug: no person
1607 1607 desc--debug: other 1
1608 1608 other 2
1609 1609
1610 1610 other 3
1611 1611 desc--debug: line 1
1612 1612 line 2
1613 1613 file_adds: fourth third
1614 1614 file_adds: second
1615 1615 file_adds:
1616 1616 file_adds: d
1617 1617 file_adds:
1618 1618 file_adds:
1619 1619 file_adds: c
1620 1620 file_adds: b
1621 1621 file_adds: a
1622 1622 file_adds--verbose: fourth third
1623 1623 file_adds--verbose: second
1624 1624 file_adds--verbose:
1625 1625 file_adds--verbose: d
1626 1626 file_adds--verbose:
1627 1627 file_adds--verbose:
1628 1628 file_adds--verbose: c
1629 1629 file_adds--verbose: b
1630 1630 file_adds--verbose: a
1631 1631 file_adds--debug: fourth third
1632 1632 file_adds--debug: second
1633 1633 file_adds--debug:
1634 1634 file_adds--debug: d
1635 1635 file_adds--debug:
1636 1636 file_adds--debug:
1637 1637 file_adds--debug: c
1638 1638 file_adds--debug: b
1639 1639 file_adds--debug: a
1640 1640 file_dels: second
1641 1641 file_dels:
1642 1642 file_dels:
1643 1643 file_dels:
1644 1644 file_dels:
1645 1645 file_dels:
1646 1646 file_dels:
1647 1647 file_dels:
1648 1648 file_dels:
1649 1649 file_dels--verbose: second
1650 1650 file_dels--verbose:
1651 1651 file_dels--verbose:
1652 1652 file_dels--verbose:
1653 1653 file_dels--verbose:
1654 1654 file_dels--verbose:
1655 1655 file_dels--verbose:
1656 1656 file_dels--verbose:
1657 1657 file_dels--verbose:
1658 1658 file_dels--debug: second
1659 1659 file_dels--debug:
1660 1660 file_dels--debug:
1661 1661 file_dels--debug:
1662 1662 file_dels--debug:
1663 1663 file_dels--debug:
1664 1664 file_dels--debug:
1665 1665 file_dels--debug:
1666 1666 file_dels--debug:
1667 1667 file_mods:
1668 1668 file_mods:
1669 1669 file_mods:
1670 1670 file_mods:
1671 1671 file_mods:
1672 1672 file_mods: c
1673 1673 file_mods:
1674 1674 file_mods:
1675 1675 file_mods:
1676 1676 file_mods--verbose:
1677 1677 file_mods--verbose:
1678 1678 file_mods--verbose:
1679 1679 file_mods--verbose:
1680 1680 file_mods--verbose:
1681 1681 file_mods--verbose: c
1682 1682 file_mods--verbose:
1683 1683 file_mods--verbose:
1684 1684 file_mods--verbose:
1685 1685 file_mods--debug:
1686 1686 file_mods--debug:
1687 1687 file_mods--debug:
1688 1688 file_mods--debug:
1689 1689 file_mods--debug:
1690 1690 file_mods--debug: c
1691 1691 file_mods--debug:
1692 1692 file_mods--debug:
1693 1693 file_mods--debug:
1694 1694 file_copies: fourth (second)
1695 1695 file_copies:
1696 1696 file_copies:
1697 1697 file_copies:
1698 1698 file_copies:
1699 1699 file_copies:
1700 1700 file_copies:
1701 1701 file_copies:
1702 1702 file_copies:
1703 1703 file_copies--verbose: fourth (second)
1704 1704 file_copies--verbose:
1705 1705 file_copies--verbose:
1706 1706 file_copies--verbose:
1707 1707 file_copies--verbose:
1708 1708 file_copies--verbose:
1709 1709 file_copies--verbose:
1710 1710 file_copies--verbose:
1711 1711 file_copies--verbose:
1712 1712 file_copies--debug: fourth (second)
1713 1713 file_copies--debug:
1714 1714 file_copies--debug:
1715 1715 file_copies--debug:
1716 1716 file_copies--debug:
1717 1717 file_copies--debug:
1718 1718 file_copies--debug:
1719 1719 file_copies--debug:
1720 1720 file_copies--debug:
1721 1721 file_copies_switch:
1722 1722 file_copies_switch:
1723 1723 file_copies_switch:
1724 1724 file_copies_switch:
1725 1725 file_copies_switch:
1726 1726 file_copies_switch:
1727 1727 file_copies_switch:
1728 1728 file_copies_switch:
1729 1729 file_copies_switch:
1730 1730 file_copies_switch--verbose:
1731 1731 file_copies_switch--verbose:
1732 1732 file_copies_switch--verbose:
1733 1733 file_copies_switch--verbose:
1734 1734 file_copies_switch--verbose:
1735 1735 file_copies_switch--verbose:
1736 1736 file_copies_switch--verbose:
1737 1737 file_copies_switch--verbose:
1738 1738 file_copies_switch--verbose:
1739 1739 file_copies_switch--debug:
1740 1740 file_copies_switch--debug:
1741 1741 file_copies_switch--debug:
1742 1742 file_copies_switch--debug:
1743 1743 file_copies_switch--debug:
1744 1744 file_copies_switch--debug:
1745 1745 file_copies_switch--debug:
1746 1746 file_copies_switch--debug:
1747 1747 file_copies_switch--debug:
1748 1748 files: fourth second third
1749 1749 files: second
1750 1750 files:
1751 1751 files: d
1752 1752 files:
1753 1753 files: c
1754 1754 files: c
1755 1755 files: b
1756 1756 files: a
1757 1757 files--verbose: fourth second third
1758 1758 files--verbose: second
1759 1759 files--verbose:
1760 1760 files--verbose: d
1761 1761 files--verbose:
1762 1762 files--verbose: c
1763 1763 files--verbose: c
1764 1764 files--verbose: b
1765 1765 files--verbose: a
1766 1766 files--debug: fourth second third
1767 1767 files--debug: second
1768 1768 files--debug:
1769 1769 files--debug: d
1770 1770 files--debug:
1771 1771 files--debug: c
1772 1772 files--debug: c
1773 1773 files--debug: b
1774 1774 files--debug: a
1775 1775 manifest: 6:94961b75a2da
1776 1776 manifest: 5:f2dbc354b94e
1777 1777 manifest: 4:4dc3def4f9b4
1778 1778 manifest: 4:4dc3def4f9b4
1779 1779 manifest: 3:cb5a1327723b
1780 1780 manifest: 3:cb5a1327723b
1781 1781 manifest: 2:6e0e82995c35
1782 1782 manifest: 1:4e8d705b1e53
1783 1783 manifest: 0:a0c8bcbbb45c
1784 1784 manifest--verbose: 6:94961b75a2da
1785 1785 manifest--verbose: 5:f2dbc354b94e
1786 1786 manifest--verbose: 4:4dc3def4f9b4
1787 1787 manifest--verbose: 4:4dc3def4f9b4
1788 1788 manifest--verbose: 3:cb5a1327723b
1789 1789 manifest--verbose: 3:cb5a1327723b
1790 1790 manifest--verbose: 2:6e0e82995c35
1791 1791 manifest--verbose: 1:4e8d705b1e53
1792 1792 manifest--verbose: 0:a0c8bcbbb45c
1793 1793 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1794 1794 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1795 1795 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1796 1796 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1797 1797 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1798 1798 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1799 1799 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1800 1800 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1801 1801 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1802 1802 node: 95c24699272ef57d062b8bccc32c878bf841784a
1803 1803 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1804 1804 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1805 1805 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1806 1806 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1807 1807 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1808 1808 node: 97054abb4ab824450e9164180baf491ae0078465
1809 1809 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1810 1810 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1811 1811 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1812 1812 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1813 1813 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1814 1814 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1815 1815 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1816 1816 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1817 1817 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1818 1818 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1819 1819 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1820 1820 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1821 1821 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1822 1822 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1823 1823 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1824 1824 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1825 1825 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1826 1826 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1827 1827 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1828 1828 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1829 1829 parents:
1830 1830 parents: -1:000000000000
1831 1831 parents: 5:13207e5a10d9 4:bbe44766e73d
1832 1832 parents: 3:10e46f2dcbf4
1833 1833 parents:
1834 1834 parents:
1835 1835 parents:
1836 1836 parents:
1837 1837 parents:
1838 1838 parents--verbose:
1839 1839 parents--verbose: -1:000000000000
1840 1840 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1841 1841 parents--verbose: 3:10e46f2dcbf4
1842 1842 parents--verbose:
1843 1843 parents--verbose:
1844 1844 parents--verbose:
1845 1845 parents--verbose:
1846 1846 parents--verbose:
1847 1847 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1848 1848 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1849 1849 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1850 1850 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1851 1851 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1852 1852 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1853 1853 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1854 1854 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1855 1855 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1856 1856 rev: 8
1857 1857 rev: 7
1858 1858 rev: 6
1859 1859 rev: 5
1860 1860 rev: 4
1861 1861 rev: 3
1862 1862 rev: 2
1863 1863 rev: 1
1864 1864 rev: 0
1865 1865 rev--verbose: 8
1866 1866 rev--verbose: 7
1867 1867 rev--verbose: 6
1868 1868 rev--verbose: 5
1869 1869 rev--verbose: 4
1870 1870 rev--verbose: 3
1871 1871 rev--verbose: 2
1872 1872 rev--verbose: 1
1873 1873 rev--verbose: 0
1874 1874 rev--debug: 8
1875 1875 rev--debug: 7
1876 1876 rev--debug: 6
1877 1877 rev--debug: 5
1878 1878 rev--debug: 4
1879 1879 rev--debug: 3
1880 1880 rev--debug: 2
1881 1881 rev--debug: 1
1882 1882 rev--debug: 0
1883 1883 tags: tip
1884 1884 tags:
1885 1885 tags:
1886 1886 tags:
1887 1887 tags:
1888 1888 tags:
1889 1889 tags:
1890 1890 tags:
1891 1891 tags:
1892 1892 tags--verbose: tip
1893 1893 tags--verbose:
1894 1894 tags--verbose:
1895 1895 tags--verbose:
1896 1896 tags--verbose:
1897 1897 tags--verbose:
1898 1898 tags--verbose:
1899 1899 tags--verbose:
1900 1900 tags--verbose:
1901 1901 tags--debug: tip
1902 1902 tags--debug:
1903 1903 tags--debug:
1904 1904 tags--debug:
1905 1905 tags--debug:
1906 1906 tags--debug:
1907 1907 tags--debug:
1908 1908 tags--debug:
1909 1909 tags--debug:
1910 1910 diffstat: 3: +2/-1
1911 1911 diffstat: 1: +1/-0
1912 1912 diffstat: 0: +0/-0
1913 1913 diffstat: 1: +1/-0
1914 1914 diffstat: 0: +0/-0
1915 1915 diffstat: 1: +1/-0
1916 1916 diffstat: 1: +4/-0
1917 1917 diffstat: 1: +2/-0
1918 1918 diffstat: 1: +1/-0
1919 1919 diffstat--verbose: 3: +2/-1
1920 1920 diffstat--verbose: 1: +1/-0
1921 1921 diffstat--verbose: 0: +0/-0
1922 1922 diffstat--verbose: 1: +1/-0
1923 1923 diffstat--verbose: 0: +0/-0
1924 1924 diffstat--verbose: 1: +1/-0
1925 1925 diffstat--verbose: 1: +4/-0
1926 1926 diffstat--verbose: 1: +2/-0
1927 1927 diffstat--verbose: 1: +1/-0
1928 1928 diffstat--debug: 3: +2/-1
1929 1929 diffstat--debug: 1: +1/-0
1930 1930 diffstat--debug: 0: +0/-0
1931 1931 diffstat--debug: 1: +1/-0
1932 1932 diffstat--debug: 0: +0/-0
1933 1933 diffstat--debug: 1: +1/-0
1934 1934 diffstat--debug: 1: +4/-0
1935 1935 diffstat--debug: 1: +2/-0
1936 1936 diffstat--debug: 1: +1/-0
1937 1937 extras: branch=default
1938 1938 extras: branch=default
1939 1939 extras: branch=default
1940 1940 extras: branch=default
1941 1941 extras: branch=foo
1942 1942 extras: branch=default
1943 1943 extras: branch=default
1944 1944 extras: branch=default
1945 1945 extras: branch=default
1946 1946 extras--verbose: branch=default
1947 1947 extras--verbose: branch=default
1948 1948 extras--verbose: branch=default
1949 1949 extras--verbose: branch=default
1950 1950 extras--verbose: branch=foo
1951 1951 extras--verbose: branch=default
1952 1952 extras--verbose: branch=default
1953 1953 extras--verbose: branch=default
1954 1954 extras--verbose: branch=default
1955 1955 extras--debug: branch=default
1956 1956 extras--debug: branch=default
1957 1957 extras--debug: branch=default
1958 1958 extras--debug: branch=default
1959 1959 extras--debug: branch=foo
1960 1960 extras--debug: branch=default
1961 1961 extras--debug: branch=default
1962 1962 extras--debug: branch=default
1963 1963 extras--debug: branch=default
1964 1964 p1rev: 7
1965 1965 p1rev: -1
1966 1966 p1rev: 5
1967 1967 p1rev: 3
1968 1968 p1rev: 3
1969 1969 p1rev: 2
1970 1970 p1rev: 1
1971 1971 p1rev: 0
1972 1972 p1rev: -1
1973 1973 p1rev--verbose: 7
1974 1974 p1rev--verbose: -1
1975 1975 p1rev--verbose: 5
1976 1976 p1rev--verbose: 3
1977 1977 p1rev--verbose: 3
1978 1978 p1rev--verbose: 2
1979 1979 p1rev--verbose: 1
1980 1980 p1rev--verbose: 0
1981 1981 p1rev--verbose: -1
1982 1982 p1rev--debug: 7
1983 1983 p1rev--debug: -1
1984 1984 p1rev--debug: 5
1985 1985 p1rev--debug: 3
1986 1986 p1rev--debug: 3
1987 1987 p1rev--debug: 2
1988 1988 p1rev--debug: 1
1989 1989 p1rev--debug: 0
1990 1990 p1rev--debug: -1
1991 1991 p2rev: -1
1992 1992 p2rev: -1
1993 1993 p2rev: 4
1994 1994 p2rev: -1
1995 1995 p2rev: -1
1996 1996 p2rev: -1
1997 1997 p2rev: -1
1998 1998 p2rev: -1
1999 1999 p2rev: -1
2000 2000 p2rev--verbose: -1
2001 2001 p2rev--verbose: -1
2002 2002 p2rev--verbose: 4
2003 2003 p2rev--verbose: -1
2004 2004 p2rev--verbose: -1
2005 2005 p2rev--verbose: -1
2006 2006 p2rev--verbose: -1
2007 2007 p2rev--verbose: -1
2008 2008 p2rev--verbose: -1
2009 2009 p2rev--debug: -1
2010 2010 p2rev--debug: -1
2011 2011 p2rev--debug: 4
2012 2012 p2rev--debug: -1
2013 2013 p2rev--debug: -1
2014 2014 p2rev--debug: -1
2015 2015 p2rev--debug: -1
2016 2016 p2rev--debug: -1
2017 2017 p2rev--debug: -1
2018 2018 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2019 2019 p1node: 0000000000000000000000000000000000000000
2020 2020 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2021 2021 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2022 2022 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2023 2023 p1node: 97054abb4ab824450e9164180baf491ae0078465
2024 2024 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2025 2025 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2026 2026 p1node: 0000000000000000000000000000000000000000
2027 2027 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2028 2028 p1node--verbose: 0000000000000000000000000000000000000000
2029 2029 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2030 2030 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2031 2031 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2032 2032 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2033 2033 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2034 2034 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2035 2035 p1node--verbose: 0000000000000000000000000000000000000000
2036 2036 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2037 2037 p1node--debug: 0000000000000000000000000000000000000000
2038 2038 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2039 2039 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2040 2040 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2041 2041 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2042 2042 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2043 2043 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2044 2044 p1node--debug: 0000000000000000000000000000000000000000
2045 2045 p2node: 0000000000000000000000000000000000000000
2046 2046 p2node: 0000000000000000000000000000000000000000
2047 2047 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2048 2048 p2node: 0000000000000000000000000000000000000000
2049 2049 p2node: 0000000000000000000000000000000000000000
2050 2050 p2node: 0000000000000000000000000000000000000000
2051 2051 p2node: 0000000000000000000000000000000000000000
2052 2052 p2node: 0000000000000000000000000000000000000000
2053 2053 p2node: 0000000000000000000000000000000000000000
2054 2054 p2node--verbose: 0000000000000000000000000000000000000000
2055 2055 p2node--verbose: 0000000000000000000000000000000000000000
2056 2056 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2057 2057 p2node--verbose: 0000000000000000000000000000000000000000
2058 2058 p2node--verbose: 0000000000000000000000000000000000000000
2059 2059 p2node--verbose: 0000000000000000000000000000000000000000
2060 2060 p2node--verbose: 0000000000000000000000000000000000000000
2061 2061 p2node--verbose: 0000000000000000000000000000000000000000
2062 2062 p2node--verbose: 0000000000000000000000000000000000000000
2063 2063 p2node--debug: 0000000000000000000000000000000000000000
2064 2064 p2node--debug: 0000000000000000000000000000000000000000
2065 2065 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2066 2066 p2node--debug: 0000000000000000000000000000000000000000
2067 2067 p2node--debug: 0000000000000000000000000000000000000000
2068 2068 p2node--debug: 0000000000000000000000000000000000000000
2069 2069 p2node--debug: 0000000000000000000000000000000000000000
2070 2070 p2node--debug: 0000000000000000000000000000000000000000
2071 2071 p2node--debug: 0000000000000000000000000000000000000000
2072 2072
2073 2073 Filters work:
2074 2074
2075 2075 $ hg log --template '{author|domain}\n'
2076 2076
2077 2077 hostname
2078 2078
2079 2079
2080 2080
2081 2081
2082 2082 place
2083 2083 place
2084 2084 hostname
2085 2085
2086 2086 $ hg log --template '{author|person}\n'
2087 2087 test
2088 2088 User Name
2089 2089 person
2090 2090 person
2091 2091 person
2092 2092 person
2093 2093 other
2094 2094 A. N. Other
2095 2095 User Name
2096 2096
2097 2097 $ hg log --template '{author|user}\n'
2098 2098 test
2099 2099 user
2100 2100 person
2101 2101 person
2102 2102 person
2103 2103 person
2104 2104 other
2105 2105 other
2106 2106 user
2107 2107
2108 2108 $ hg log --template '{date|date}\n'
2109 2109 Wed Jan 01 10:01:00 2020 +0000
2110 2110 Mon Jan 12 13:46:40 1970 +0000
2111 2111 Sun Jan 18 08:40:01 1970 +0000
2112 2112 Sun Jan 18 08:40:00 1970 +0000
2113 2113 Sat Jan 17 04:53:20 1970 +0000
2114 2114 Fri Jan 16 01:06:40 1970 +0000
2115 2115 Wed Jan 14 21:20:00 1970 +0000
2116 2116 Tue Jan 13 17:33:20 1970 +0000
2117 2117 Mon Jan 12 13:46:40 1970 +0000
2118 2118
2119 2119 $ hg log --template '{date|isodate}\n'
2120 2120 2020-01-01 10:01 +0000
2121 2121 1970-01-12 13:46 +0000
2122 2122 1970-01-18 08:40 +0000
2123 2123 1970-01-18 08:40 +0000
2124 2124 1970-01-17 04:53 +0000
2125 2125 1970-01-16 01:06 +0000
2126 2126 1970-01-14 21:20 +0000
2127 2127 1970-01-13 17:33 +0000
2128 2128 1970-01-12 13:46 +0000
2129 2129
2130 2130 $ hg log --template '{date|isodatesec}\n'
2131 2131 2020-01-01 10:01:00 +0000
2132 2132 1970-01-12 13:46:40 +0000
2133 2133 1970-01-18 08:40:01 +0000
2134 2134 1970-01-18 08:40:00 +0000
2135 2135 1970-01-17 04:53:20 +0000
2136 2136 1970-01-16 01:06:40 +0000
2137 2137 1970-01-14 21:20:00 +0000
2138 2138 1970-01-13 17:33:20 +0000
2139 2139 1970-01-12 13:46:40 +0000
2140 2140
2141 2141 $ hg log --template '{date|rfc822date}\n'
2142 2142 Wed, 01 Jan 2020 10:01:00 +0000
2143 2143 Mon, 12 Jan 1970 13:46:40 +0000
2144 2144 Sun, 18 Jan 1970 08:40:01 +0000
2145 2145 Sun, 18 Jan 1970 08:40:00 +0000
2146 2146 Sat, 17 Jan 1970 04:53:20 +0000
2147 2147 Fri, 16 Jan 1970 01:06:40 +0000
2148 2148 Wed, 14 Jan 1970 21:20:00 +0000
2149 2149 Tue, 13 Jan 1970 17:33:20 +0000
2150 2150 Mon, 12 Jan 1970 13:46:40 +0000
2151 2151
2152 2152 $ hg log --template '{desc|firstline}\n'
2153 2153 third
2154 2154 second
2155 2155 merge
2156 2156 new head
2157 2157 new branch
2158 2158 no user, no domain
2159 2159 no person
2160 2160 other 1
2161 2161 line 1
2162 2162
2163 2163 $ hg log --template '{node|short}\n'
2164 2164 95c24699272e
2165 2165 29114dbae42b
2166 2166 d41e714fe50d
2167 2167 13207e5a10d9
2168 2168 bbe44766e73d
2169 2169 10e46f2dcbf4
2170 2170 97054abb4ab8
2171 2171 b608e9d1a3f0
2172 2172 1e4e1b8f71e0
2173 2173
2174 2174 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2175 2175 <changeset author="test"/>
2176 2176 <changeset author="User Name &lt;user@hostname&gt;"/>
2177 2177 <changeset author="person"/>
2178 2178 <changeset author="person"/>
2179 2179 <changeset author="person"/>
2180 2180 <changeset author="person"/>
2181 2181 <changeset author="other@place"/>
2182 2182 <changeset author="A. N. Other &lt;other@place&gt;"/>
2183 2183 <changeset author="User Name &lt;user@hostname&gt;"/>
2184 2184
2185 2185 $ hg log --template '{rev}: {children}\n'
2186 2186 8:
2187 2187 7: 8:95c24699272e
2188 2188 6:
2189 2189 5: 6:d41e714fe50d
2190 2190 4: 6:d41e714fe50d
2191 2191 3: 4:bbe44766e73d 5:13207e5a10d9
2192 2192 2: 3:10e46f2dcbf4
2193 2193 1: 2:97054abb4ab8
2194 2194 0: 1:b608e9d1a3f0
2195 2195
2196 2196 Formatnode filter works:
2197 2197
2198 2198 $ hg -q log -r 0 --template '{node|formatnode}\n'
2199 2199 1e4e1b8f71e0
2200 2200
2201 2201 $ hg log -r 0 --template '{node|formatnode}\n'
2202 2202 1e4e1b8f71e0
2203 2203
2204 2204 $ hg -v log -r 0 --template '{node|formatnode}\n'
2205 2205 1e4e1b8f71e0
2206 2206
2207 2207 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2208 2208 1e4e1b8f71e05681d422154f5421e385fec3454f
2209 2209
2210 2210 Age filter:
2211 2211
2212 2212 $ hg init unstable-hash
2213 2213 $ cd unstable-hash
2214 2214 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2215 2215
2216 2216 >>> from __future__ import absolute_import
2217 2217 >>> import datetime
2218 2218 >>> fp = open('a', 'w')
2219 2219 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2220 2220 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2221 2221 >>> fp.close()
2222 2222 $ hg add a
2223 2223 $ hg commit -m future -d "`cat a`"
2224 2224
2225 2225 $ hg log -l1 --template '{date|age}\n'
2226 2226 7 years from now
2227 2227
2228 2228 $ cd ..
2229 2229 $ rm -rf unstable-hash
2230 2230
2231 2231 Add a dummy commit to make up for the instability of the above:
2232 2232
2233 2233 $ echo a > a
2234 2234 $ hg add a
2235 2235 $ hg ci -m future
2236 2236
2237 2237 Count filter:
2238 2238
2239 2239 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2240 2240 40 12
2241 2241
2242 2242 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2243 2243 0 1 4
2244 2244
2245 2245 $ hg log -G --template '{rev}: children: {children|count}, \
2246 2246 > tags: {tags|count}, file_adds: {file_adds|count}, \
2247 2247 > ancestors: {revset("ancestors(%s)", rev)|count}'
2248 2248 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2249 2249 |
2250 2250 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2251 2251 |
2252 2252 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2253 2253
2254 2254 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2255 2255 |\
2256 2256 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2257 2257 | |
2258 2258 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2259 2259 |/
2260 2260 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2261 2261 |
2262 2262 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2263 2263 |
2264 2264 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2265 2265 |
2266 2266 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2267 2267
2268 2268
2269 2269 Upper/lower filters:
2270 2270
2271 2271 $ hg log -r0 --template '{branch|upper}\n'
2272 2272 DEFAULT
2273 2273 $ hg log -r0 --template '{author|lower}\n'
2274 2274 user name <user@hostname>
2275 2275 $ hg log -r0 --template '{date|upper}\n'
2276 2276 abort: template filter 'upper' is not compatible with keyword 'date'
2277 2277 [255]
2278 2278
2279 2279 Add a commit that does all possible modifications at once
2280 2280
2281 2281 $ echo modify >> third
2282 2282 $ touch b
2283 2283 $ hg add b
2284 2284 $ hg mv fourth fifth
2285 2285 $ hg rm a
2286 2286 $ hg ci -m "Modify, add, remove, rename"
2287 2287
2288 2288 Check the status template
2289 2289
2290 2290 $ cat <<EOF >> $HGRCPATH
2291 2291 > [extensions]
2292 2292 > color=
2293 2293 > EOF
2294 2294
2295 2295 $ hg log -T status -r 10
2296 2296 changeset: 10:0f9759ec227a
2297 2297 tag: tip
2298 2298 user: test
2299 2299 date: Thu Jan 01 00:00:00 1970 +0000
2300 2300 summary: Modify, add, remove, rename
2301 2301 files:
2302 2302 M third
2303 2303 A b
2304 2304 A fifth
2305 2305 R a
2306 2306 R fourth
2307 2307
2308 2308 $ hg log -T status -C -r 10
2309 2309 changeset: 10:0f9759ec227a
2310 2310 tag: tip
2311 2311 user: test
2312 2312 date: Thu Jan 01 00:00:00 1970 +0000
2313 2313 summary: Modify, add, remove, rename
2314 2314 files:
2315 2315 M third
2316 2316 A b
2317 2317 A fifth
2318 2318 fourth
2319 2319 R a
2320 2320 R fourth
2321 2321
2322 2322 $ hg log -T status -C -r 10 -v
2323 2323 changeset: 10:0f9759ec227a
2324 2324 tag: tip
2325 2325 user: test
2326 2326 date: Thu Jan 01 00:00:00 1970 +0000
2327 2327 description:
2328 2328 Modify, add, remove, rename
2329 2329
2330 2330 files:
2331 2331 M third
2332 2332 A b
2333 2333 A fifth
2334 2334 fourth
2335 2335 R a
2336 2336 R fourth
2337 2337
2338 2338 $ hg log -T status -C -r 10 --debug
2339 2339 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2340 2340 tag: tip
2341 2341 phase: secret
2342 2342 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2343 2343 parent: -1:0000000000000000000000000000000000000000
2344 2344 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2345 2345 user: test
2346 2346 date: Thu Jan 01 00:00:00 1970 +0000
2347 2347 extra: branch=default
2348 2348 description:
2349 2349 Modify, add, remove, rename
2350 2350
2351 2351 files:
2352 2352 M third
2353 2353 A b
2354 2354 A fifth
2355 2355 fourth
2356 2356 R a
2357 2357 R fourth
2358 2358
2359 2359 $ hg log -T status -C -r 10 --quiet
2360 2360 10:0f9759ec227a
2361 2361 $ hg --color=debug log -T status -r 10
2362 2362 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2363 2363 [log.tag|tag: tip]
2364 2364 [log.user|user: test]
2365 2365 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2366 2366 [log.summary|summary: Modify, add, remove, rename]
2367 2367 [ui.note log.files|files:]
2368 2368 [status.modified|M third]
2369 2369 [status.added|A b]
2370 2370 [status.added|A fifth]
2371 2371 [status.removed|R a]
2372 2372 [status.removed|R fourth]
2373 2373
2374 2374 $ hg --color=debug log -T status -C -r 10
2375 2375 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2376 2376 [log.tag|tag: tip]
2377 2377 [log.user|user: test]
2378 2378 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2379 2379 [log.summary|summary: Modify, add, remove, rename]
2380 2380 [ui.note log.files|files:]
2381 2381 [status.modified|M third]
2382 2382 [status.added|A b]
2383 2383 [status.added|A fifth]
2384 2384 [status.copied| fourth]
2385 2385 [status.removed|R a]
2386 2386 [status.removed|R fourth]
2387 2387
2388 2388 $ hg --color=debug log -T status -C -r 10 -v
2389 2389 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2390 2390 [log.tag|tag: tip]
2391 2391 [log.user|user: test]
2392 2392 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2393 2393 [ui.note log.description|description:]
2394 2394 [ui.note log.description|Modify, add, remove, rename]
2395 2395
2396 2396 [ui.note log.files|files:]
2397 2397 [status.modified|M third]
2398 2398 [status.added|A b]
2399 2399 [status.added|A fifth]
2400 2400 [status.copied| fourth]
2401 2401 [status.removed|R a]
2402 2402 [status.removed|R fourth]
2403 2403
2404 2404 $ hg --color=debug log -T status -C -r 10 --debug
2405 2405 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2406 2406 [log.tag|tag: tip]
2407 2407 [log.phase|phase: secret]
2408 2408 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2409 2409 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2410 2410 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2411 2411 [log.user|user: test]
2412 2412 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2413 2413 [ui.debug log.extra|extra: branch=default]
2414 2414 [ui.note log.description|description:]
2415 2415 [ui.note log.description|Modify, add, remove, rename]
2416 2416
2417 2417 [ui.note log.files|files:]
2418 2418 [status.modified|M third]
2419 2419 [status.added|A b]
2420 2420 [status.added|A fifth]
2421 2421 [status.copied| fourth]
2422 2422 [status.removed|R a]
2423 2423 [status.removed|R fourth]
2424 2424
2425 2425 $ hg --color=debug log -T status -C -r 10 --quiet
2426 2426 [log.node|10:0f9759ec227a]
2427 2427
2428 2428 Check the bisect template
2429 2429
2430 2430 $ hg bisect -g 1
2431 2431 $ hg bisect -b 3 --noupdate
2432 2432 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2433 2433 $ hg log -T bisect -r 0:4
2434 2434 changeset: 0:1e4e1b8f71e0
2435 2435 bisect: good (implicit)
2436 2436 user: User Name <user@hostname>
2437 2437 date: Mon Jan 12 13:46:40 1970 +0000
2438 2438 summary: line 1
2439 2439
2440 2440 changeset: 1:b608e9d1a3f0
2441 2441 bisect: good
2442 2442 user: A. N. Other <other@place>
2443 2443 date: Tue Jan 13 17:33:20 1970 +0000
2444 2444 summary: other 1
2445 2445
2446 2446 changeset: 2:97054abb4ab8
2447 2447 bisect: untested
2448 2448 user: other@place
2449 2449 date: Wed Jan 14 21:20:00 1970 +0000
2450 2450 summary: no person
2451 2451
2452 2452 changeset: 3:10e46f2dcbf4
2453 2453 bisect: bad
2454 2454 user: person
2455 2455 date: Fri Jan 16 01:06:40 1970 +0000
2456 2456 summary: no user, no domain
2457 2457
2458 2458 changeset: 4:bbe44766e73d
2459 2459 bisect: bad (implicit)
2460 2460 branch: foo
2461 2461 user: person
2462 2462 date: Sat Jan 17 04:53:20 1970 +0000
2463 2463 summary: new branch
2464 2464
2465 2465 $ hg log --debug -T bisect -r 0:4
2466 2466 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2467 2467 bisect: good (implicit)
2468 2468 phase: public
2469 2469 parent: -1:0000000000000000000000000000000000000000
2470 2470 parent: -1:0000000000000000000000000000000000000000
2471 2471 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2472 2472 user: User Name <user@hostname>
2473 2473 date: Mon Jan 12 13:46:40 1970 +0000
2474 2474 files+: a
2475 2475 extra: branch=default
2476 2476 description:
2477 2477 line 1
2478 2478 line 2
2479 2479
2480 2480
2481 2481 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2482 2482 bisect: good
2483 2483 phase: public
2484 2484 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2485 2485 parent: -1:0000000000000000000000000000000000000000
2486 2486 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2487 2487 user: A. N. Other <other@place>
2488 2488 date: Tue Jan 13 17:33:20 1970 +0000
2489 2489 files+: b
2490 2490 extra: branch=default
2491 2491 description:
2492 2492 other 1
2493 2493 other 2
2494 2494
2495 2495 other 3
2496 2496
2497 2497
2498 2498 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2499 2499 bisect: untested
2500 2500 phase: public
2501 2501 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2502 2502 parent: -1:0000000000000000000000000000000000000000
2503 2503 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2504 2504 user: other@place
2505 2505 date: Wed Jan 14 21:20:00 1970 +0000
2506 2506 files+: c
2507 2507 extra: branch=default
2508 2508 description:
2509 2509 no person
2510 2510
2511 2511
2512 2512 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2513 2513 bisect: bad
2514 2514 phase: public
2515 2515 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2516 2516 parent: -1:0000000000000000000000000000000000000000
2517 2517 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2518 2518 user: person
2519 2519 date: Fri Jan 16 01:06:40 1970 +0000
2520 2520 files: c
2521 2521 extra: branch=default
2522 2522 description:
2523 2523 no user, no domain
2524 2524
2525 2525
2526 2526 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2527 2527 bisect: bad (implicit)
2528 2528 branch: foo
2529 2529 phase: draft
2530 2530 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2531 2531 parent: -1:0000000000000000000000000000000000000000
2532 2532 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2533 2533 user: person
2534 2534 date: Sat Jan 17 04:53:20 1970 +0000
2535 2535 extra: branch=foo
2536 2536 description:
2537 2537 new branch
2538 2538
2539 2539
2540 2540 $ hg log -v -T bisect -r 0:4
2541 2541 changeset: 0:1e4e1b8f71e0
2542 2542 bisect: good (implicit)
2543 2543 user: User Name <user@hostname>
2544 2544 date: Mon Jan 12 13:46:40 1970 +0000
2545 2545 files: a
2546 2546 description:
2547 2547 line 1
2548 2548 line 2
2549 2549
2550 2550
2551 2551 changeset: 1:b608e9d1a3f0
2552 2552 bisect: good
2553 2553 user: A. N. Other <other@place>
2554 2554 date: Tue Jan 13 17:33:20 1970 +0000
2555 2555 files: b
2556 2556 description:
2557 2557 other 1
2558 2558 other 2
2559 2559
2560 2560 other 3
2561 2561
2562 2562
2563 2563 changeset: 2:97054abb4ab8
2564 2564 bisect: untested
2565 2565 user: other@place
2566 2566 date: Wed Jan 14 21:20:00 1970 +0000
2567 2567 files: c
2568 2568 description:
2569 2569 no person
2570 2570
2571 2571
2572 2572 changeset: 3:10e46f2dcbf4
2573 2573 bisect: bad
2574 2574 user: person
2575 2575 date: Fri Jan 16 01:06:40 1970 +0000
2576 2576 files: c
2577 2577 description:
2578 2578 no user, no domain
2579 2579
2580 2580
2581 2581 changeset: 4:bbe44766e73d
2582 2582 bisect: bad (implicit)
2583 2583 branch: foo
2584 2584 user: person
2585 2585 date: Sat Jan 17 04:53:20 1970 +0000
2586 2586 description:
2587 2587 new branch
2588 2588
2589 2589
2590 2590 $ hg --color=debug log -T bisect -r 0:4
2591 2591 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2592 2592 [log.bisect bisect.good|bisect: good (implicit)]
2593 2593 [log.user|user: User Name <user@hostname>]
2594 2594 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2595 2595 [log.summary|summary: line 1]
2596 2596
2597 2597 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2598 2598 [log.bisect bisect.good|bisect: good]
2599 2599 [log.user|user: A. N. Other <other@place>]
2600 2600 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2601 2601 [log.summary|summary: other 1]
2602 2602
2603 2603 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2604 2604 [log.bisect bisect.untested|bisect: untested]
2605 2605 [log.user|user: other@place]
2606 2606 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2607 2607 [log.summary|summary: no person]
2608 2608
2609 2609 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2610 2610 [log.bisect bisect.bad|bisect: bad]
2611 2611 [log.user|user: person]
2612 2612 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2613 2613 [log.summary|summary: no user, no domain]
2614 2614
2615 2615 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2616 2616 [log.bisect bisect.bad|bisect: bad (implicit)]
2617 2617 [log.branch|branch: foo]
2618 2618 [log.user|user: person]
2619 2619 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2620 2620 [log.summary|summary: new branch]
2621 2621
2622 2622 $ hg --color=debug log --debug -T bisect -r 0:4
2623 2623 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2624 2624 [log.bisect bisect.good|bisect: good (implicit)]
2625 2625 [log.phase|phase: public]
2626 2626 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2627 2627 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2628 2628 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2629 2629 [log.user|user: User Name <user@hostname>]
2630 2630 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2631 2631 [ui.debug log.files|files+: a]
2632 2632 [ui.debug log.extra|extra: branch=default]
2633 2633 [ui.note log.description|description:]
2634 2634 [ui.note log.description|line 1
2635 2635 line 2]
2636 2636
2637 2637
2638 2638 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2639 2639 [log.bisect bisect.good|bisect: good]
2640 2640 [log.phase|phase: public]
2641 2641 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2642 2642 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2643 2643 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2644 2644 [log.user|user: A. N. Other <other@place>]
2645 2645 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2646 2646 [ui.debug log.files|files+: b]
2647 2647 [ui.debug log.extra|extra: branch=default]
2648 2648 [ui.note log.description|description:]
2649 2649 [ui.note log.description|other 1
2650 2650 other 2
2651 2651
2652 2652 other 3]
2653 2653
2654 2654
2655 2655 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2656 2656 [log.bisect bisect.untested|bisect: untested]
2657 2657 [log.phase|phase: public]
2658 2658 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2659 2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2660 2660 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2661 2661 [log.user|user: other@place]
2662 2662 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2663 2663 [ui.debug log.files|files+: c]
2664 2664 [ui.debug log.extra|extra: branch=default]
2665 2665 [ui.note log.description|description:]
2666 2666 [ui.note log.description|no person]
2667 2667
2668 2668
2669 2669 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2670 2670 [log.bisect bisect.bad|bisect: bad]
2671 2671 [log.phase|phase: public]
2672 2672 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2673 2673 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2674 2674 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2675 2675 [log.user|user: person]
2676 2676 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2677 2677 [ui.debug log.files|files: c]
2678 2678 [ui.debug log.extra|extra: branch=default]
2679 2679 [ui.note log.description|description:]
2680 2680 [ui.note log.description|no user, no domain]
2681 2681
2682 2682
2683 2683 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2684 2684 [log.bisect bisect.bad|bisect: bad (implicit)]
2685 2685 [log.branch|branch: foo]
2686 2686 [log.phase|phase: draft]
2687 2687 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2688 2688 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2689 2689 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2690 2690 [log.user|user: person]
2691 2691 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2692 2692 [ui.debug log.extra|extra: branch=foo]
2693 2693 [ui.note log.description|description:]
2694 2694 [ui.note log.description|new branch]
2695 2695
2696 2696
2697 2697 $ hg --color=debug log -v -T bisect -r 0:4
2698 2698 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2699 2699 [log.bisect bisect.good|bisect: good (implicit)]
2700 2700 [log.user|user: User Name <user@hostname>]
2701 2701 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2702 2702 [ui.note log.files|files: a]
2703 2703 [ui.note log.description|description:]
2704 2704 [ui.note log.description|line 1
2705 2705 line 2]
2706 2706
2707 2707
2708 2708 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2709 2709 [log.bisect bisect.good|bisect: good]
2710 2710 [log.user|user: A. N. Other <other@place>]
2711 2711 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2712 2712 [ui.note log.files|files: b]
2713 2713 [ui.note log.description|description:]
2714 2714 [ui.note log.description|other 1
2715 2715 other 2
2716 2716
2717 2717 other 3]
2718 2718
2719 2719
2720 2720 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2721 2721 [log.bisect bisect.untested|bisect: untested]
2722 2722 [log.user|user: other@place]
2723 2723 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2724 2724 [ui.note log.files|files: c]
2725 2725 [ui.note log.description|description:]
2726 2726 [ui.note log.description|no person]
2727 2727
2728 2728
2729 2729 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2730 2730 [log.bisect bisect.bad|bisect: bad]
2731 2731 [log.user|user: person]
2732 2732 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2733 2733 [ui.note log.files|files: c]
2734 2734 [ui.note log.description|description:]
2735 2735 [ui.note log.description|no user, no domain]
2736 2736
2737 2737
2738 2738 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2739 2739 [log.bisect bisect.bad|bisect: bad (implicit)]
2740 2740 [log.branch|branch: foo]
2741 2741 [log.user|user: person]
2742 2742 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2743 2743 [ui.note log.description|description:]
2744 2744 [ui.note log.description|new branch]
2745 2745
2746 2746
2747 2747 $ hg bisect --reset
2748 2748
2749 2749 Error on syntax:
2750 2750
2751 2751 $ echo 'x = "f' >> t
2752 2752 $ hg log
2753 2753 hg: parse error at t:3: unmatched quotes
2754 2754 [255]
2755 2755
2756 2756 $ hg log -T '{date'
2757 2757 hg: parse error at 1: unterminated template expansion
2758 2758 [255]
2759 2759
2760 2760 Behind the scenes, this will throw TypeError
2761 2761
2762 2762 $ hg log -l 3 --template '{date|obfuscate}\n'
2763 2763 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2764 2764 [255]
2765 2765
2766 2766 Behind the scenes, this will throw a ValueError
2767 2767
2768 2768 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2769 2769 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2770 2770 [255]
2771 2771
2772 2772 Behind the scenes, this will throw AttributeError
2773 2773
2774 2774 $ hg log -l 3 --template 'line: {date|escape}\n'
2775 2775 abort: template filter 'escape' is not compatible with keyword 'date'
2776 2776 [255]
2777 2777
2778 2778 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2779 2779 hg: parse error: localdate expects a date information
2780 2780 [255]
2781 2781
2782 2782 Behind the scenes, this will throw ValueError
2783 2783
2784 2784 $ hg tip --template '{author|email|date}\n'
2785 2785 hg: parse error: date expects a date information
2786 2786 [255]
2787 2787
2788 2788 $ hg tip -T '{author|email|shortdate}\n'
2789 2789 abort: template filter 'shortdate' is not compatible with keyword 'author'
2790 2790 [255]
2791 2791
2792 2792 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2793 2793 abort: incompatible use of template filter 'shortdate'
2794 2794 [255]
2795 2795
2796 2796 Error in nested template:
2797 2797
2798 2798 $ hg log -T '{"date'
2799 2799 hg: parse error at 2: unterminated string
2800 2800 [255]
2801 2801
2802 2802 $ hg log -T '{"foo{date|?}"}'
2803 2803 hg: parse error at 11: syntax error
2804 2804 [255]
2805 2805
2806 2806 Thrown an error if a template function doesn't exist
2807 2807
2808 2808 $ hg tip --template '{foo()}\n'
2809 2809 hg: parse error: unknown function 'foo'
2810 2810 [255]
2811 2811
2812 2812 Pass generator object created by template function to filter
2813 2813
2814 2814 $ hg log -l 1 --template '{if(author, author)|user}\n'
2815 2815 test
2816 2816
2817 2817 Test index keyword:
2818 2818
2819 2819 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2820 2820 10 0:a 1:b 2:fifth 3:fourth 4:third
2821 2821 11 0:a
2822 2822
2823 2823 $ hg branches -T '{index} {branch}\n'
2824 2824 0 default
2825 2825 1 foo
2826 2826
2827 2827 Test diff function:
2828 2828
2829 2829 $ hg diff -c 8
2830 2830 diff -r 29114dbae42b -r 95c24699272e fourth
2831 2831 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2832 2832 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2833 2833 @@ -0,0 +1,1 @@
2834 2834 +second
2835 2835 diff -r 29114dbae42b -r 95c24699272e second
2836 2836 --- a/second Mon Jan 12 13:46:40 1970 +0000
2837 2837 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2838 2838 @@ -1,1 +0,0 @@
2839 2839 -second
2840 2840 diff -r 29114dbae42b -r 95c24699272e third
2841 2841 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2842 2842 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2843 2843 @@ -0,0 +1,1 @@
2844 2844 +third
2845 2845
2846 2846 $ hg log -r 8 -T "{diff()}"
2847 2847 diff -r 29114dbae42b -r 95c24699272e fourth
2848 2848 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2849 2849 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2850 2850 @@ -0,0 +1,1 @@
2851 2851 +second
2852 2852 diff -r 29114dbae42b -r 95c24699272e second
2853 2853 --- a/second Mon Jan 12 13:46:40 1970 +0000
2854 2854 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2855 2855 @@ -1,1 +0,0 @@
2856 2856 -second
2857 2857 diff -r 29114dbae42b -r 95c24699272e third
2858 2858 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2859 2859 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2860 2860 @@ -0,0 +1,1 @@
2861 2861 +third
2862 2862
2863 2863 $ hg log -r 8 -T "{diff('glob:f*')}"
2864 2864 diff -r 29114dbae42b -r 95c24699272e fourth
2865 2865 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2866 2866 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2867 2867 @@ -0,0 +1,1 @@
2868 2868 +second
2869 2869
2870 2870 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2871 2871 diff -r 29114dbae42b -r 95c24699272e second
2872 2872 --- a/second Mon Jan 12 13:46:40 1970 +0000
2873 2873 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2874 2874 @@ -1,1 +0,0 @@
2875 2875 -second
2876 2876 diff -r 29114dbae42b -r 95c24699272e third
2877 2877 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2878 2878 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2879 2879 @@ -0,0 +1,1 @@
2880 2880 +third
2881 2881
2882 2882 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2883 2883 diff -r 29114dbae42b -r 95c24699272e fourth
2884 2884 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2885 2885 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2886 2886 @@ -0,0 +1,1 @@
2887 2887 +second
2888 2888
2889 2889 ui verbosity:
2890 2890
2891 2891 $ hg log -l1 -T '{verbosity}\n'
2892 2892
2893 2893 $ hg log -l1 -T '{verbosity}\n' --debug
2894 2894 debug
2895 2895 $ hg log -l1 -T '{verbosity}\n' --quiet
2896 2896 quiet
2897 2897 $ hg log -l1 -T '{verbosity}\n' --verbose
2898 2898 verbose
2899 2899
2900 2900 $ cd ..
2901 2901
2902 2902
2903 2903 latesttag:
2904 2904
2905 2905 $ hg init latesttag
2906 2906 $ cd latesttag
2907 2907
2908 2908 $ echo a > file
2909 2909 $ hg ci -Am a -d '0 0'
2910 2910 adding file
2911 2911
2912 2912 $ echo b >> file
2913 2913 $ hg ci -m b -d '1 0'
2914 2914
2915 2915 $ echo c >> head1
2916 2916 $ hg ci -Am h1c -d '2 0'
2917 2917 adding head1
2918 2918
2919 2919 $ hg update -q 1
2920 2920 $ echo d >> head2
2921 2921 $ hg ci -Am h2d -d '3 0'
2922 2922 adding head2
2923 2923 created new head
2924 2924
2925 2925 $ echo e >> head2
2926 2926 $ hg ci -m h2e -d '4 0'
2927 2927
2928 2928 $ hg merge -q
2929 2929 $ hg ci -m merge -d '5 -3600'
2930 2930
2931 2931 No tag set:
2932 2932
2933 2933 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2934 2934 @ 5: null+5
2935 2935 |\
2936 2936 | o 4: null+4
2937 2937 | |
2938 2938 | o 3: null+3
2939 2939 | |
2940 2940 o | 2: null+3
2941 2941 |/
2942 2942 o 1: null+2
2943 2943 |
2944 2944 o 0: null+1
2945 2945
2946 2946
2947 2947 One common tag: longest path wins for {latesttagdistance}:
2948 2948
2949 2949 $ hg tag -r 1 -m t1 -d '6 0' t1
2950 2950 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2951 2951 @ 6: t1+4
2952 2952 |
2953 2953 o 5: t1+3
2954 2954 |\
2955 2955 | o 4: t1+2
2956 2956 | |
2957 2957 | o 3: t1+1
2958 2958 | |
2959 2959 o | 2: t1+1
2960 2960 |/
2961 2961 o 1: t1+0
2962 2962 |
2963 2963 o 0: null+1
2964 2964
2965 2965
2966 2966 One ancestor tag: closest wins:
2967 2967
2968 2968 $ hg tag -r 2 -m t2 -d '7 0' t2
2969 2969 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2970 2970 @ 7: t2+3
2971 2971 |
2972 2972 o 6: t2+2
2973 2973 |
2974 2974 o 5: t2+1
2975 2975 |\
2976 2976 | o 4: t1+2
2977 2977 | |
2978 2978 | o 3: t1+1
2979 2979 | |
2980 2980 o | 2: t2+0
2981 2981 |/
2982 2982 o 1: t1+0
2983 2983 |
2984 2984 o 0: null+1
2985 2985
2986 2986
2987 2987 Two branch tags: more recent wins if same number of changes:
2988 2988
2989 2989 $ hg tag -r 3 -m t3 -d '8 0' t3
2990 2990 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2991 2991 @ 8: t3+5
2992 2992 |
2993 2993 o 7: t3+4
2994 2994 |
2995 2995 o 6: t3+3
2996 2996 |
2997 2997 o 5: t3+2
2998 2998 |\
2999 2999 | o 4: t3+1
3000 3000 | |
3001 3001 | o 3: t3+0
3002 3002 | |
3003 3003 o | 2: t2+0
3004 3004 |/
3005 3005 o 1: t1+0
3006 3006 |
3007 3007 o 0: null+1
3008 3008
3009 3009
3010 3010 Two branch tags: fewest changes wins:
3011 3011
3012 3012 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3013 3013 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3014 3014 @ 9: t4+5,6
3015 3015 |
3016 3016 o 8: t4+4,5
3017 3017 |
3018 3018 o 7: t4+3,4
3019 3019 |
3020 3020 o 6: t4+2,3
3021 3021 |
3022 3022 o 5: t4+1,2
3023 3023 |\
3024 3024 | o 4: t4+0,0
3025 3025 | |
3026 3026 | o 3: t3+0,0
3027 3027 | |
3028 3028 o | 2: t2+0,0
3029 3029 |/
3030 3030 o 1: t1+0,0
3031 3031 |
3032 3032 o 0: null+1,1
3033 3033
3034 3034
3035 3035 Merged tag overrides:
3036 3036
3037 3037 $ hg tag -r 5 -m t5 -d '9 0' t5
3038 3038 $ hg tag -r 3 -m at3 -d '10 0' at3
3039 3039 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3040 3040 @ 11: t5+6
3041 3041 |
3042 3042 o 10: t5+5
3043 3043 |
3044 3044 o 9: t5+4
3045 3045 |
3046 3046 o 8: t5+3
3047 3047 |
3048 3048 o 7: t5+2
3049 3049 |
3050 3050 o 6: t5+1
3051 3051 |
3052 3052 o 5: t5+0
3053 3053 |\
3054 3054 | o 4: t4+0
3055 3055 | |
3056 3056 | o 3: at3:t3+0
3057 3057 | |
3058 3058 o | 2: t2+0
3059 3059 |/
3060 3060 o 1: t1+0
3061 3061 |
3062 3062 o 0: null+1
3063 3063
3064 3064
3065 3065 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3066 3066 @ 11: t5+6,6
3067 3067 |
3068 3068 o 10: t5+5,5
3069 3069 |
3070 3070 o 9: t5+4,4
3071 3071 |
3072 3072 o 8: t5+3,3
3073 3073 |
3074 3074 o 7: t5+2,2
3075 3075 |
3076 3076 o 6: t5+1,1
3077 3077 |
3078 3078 o 5: t5+0,0
3079 3079 |\
3080 3080 | o 4: t4+0,0
3081 3081 | |
3082 3082 | o 3: at3+0,0 t3+0,0
3083 3083 | |
3084 3084 o | 2: t2+0,0
3085 3085 |/
3086 3086 o 1: t1+0,0
3087 3087 |
3088 3088 o 0: null+1,1
3089 3089
3090 3090
3091 3091 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3092 3092 @ 11: t3, C: 9, D: 8
3093 3093 |
3094 3094 o 10: t3, C: 8, D: 7
3095 3095 |
3096 3096 o 9: t3, C: 7, D: 6
3097 3097 |
3098 3098 o 8: t3, C: 6, D: 5
3099 3099 |
3100 3100 o 7: t3, C: 5, D: 4
3101 3101 |
3102 3102 o 6: t3, C: 4, D: 3
3103 3103 |
3104 3104 o 5: t3, C: 3, D: 2
3105 3105 |\
3106 3106 | o 4: t3, C: 1, D: 1
3107 3107 | |
3108 3108 | o 3: t3, C: 0, D: 0
3109 3109 | |
3110 3110 o | 2: t1, C: 1, D: 1
3111 3111 |/
3112 3112 o 1: t1, C: 0, D: 0
3113 3113 |
3114 3114 o 0: null, C: 1, D: 1
3115 3115
3116 3116
3117 3117 $ cd ..
3118 3118
3119 3119
3120 3120 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3121 3121 if it is a relative path
3122 3122
3123 3123 $ mkdir -p home/styles
3124 3124
3125 3125 $ cat > home/styles/teststyle <<EOF
3126 3126 > changeset = 'test {rev}:{node|short}\n'
3127 3127 > EOF
3128 3128
3129 3129 $ HOME=`pwd`/home; export HOME
3130 3130
3131 3131 $ cat > latesttag/.hg/hgrc <<EOF
3132 3132 > [ui]
3133 3133 > style = ~/styles/teststyle
3134 3134 > EOF
3135 3135
3136 3136 $ hg -R latesttag tip
3137 3137 test 11:97e5943b523a
3138 3138
3139 3139 Test recursive showlist template (issue1989):
3140 3140
3141 3141 $ cat > style1989 <<EOF
3142 3142 > changeset = '{file_mods}{manifest}{extras}'
3143 3143 > file_mod = 'M|{author|person}\n'
3144 3144 > manifest = '{rev},{author}\n'
3145 3145 > extra = '{key}: {author}\n'
3146 3146 > EOF
3147 3147
3148 3148 $ hg -R latesttag log -r tip --style=style1989
3149 3149 M|test
3150 3150 11,test
3151 3151 branch: test
3152 3152
3153 3153 Test new-style inline templating:
3154 3154
3155 3155 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3156 3156 modified files: .hgtags
3157 3157
3158 3158
3159 3159 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3160 3160 hg: parse error: keyword 'rev' is not iterable
3161 3161 [255]
3162 3162 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3163 3163 hg: parse error: None is not iterable
3164 3164 [255]
3165 3165
3166 3166 Test new-style inline templating of non-list/dict type:
3167 3167
3168 3168 $ hg log -R latesttag -r tip -T '{manifest}\n'
3169 3169 11:2bc6e9006ce2
3170 3170 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3171 3171 string length: 15
3172 3172 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3173 3173 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3174 3174
3175 3175 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3176 3176 branch: default
3177 3177 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3178 3178 hg: parse error: None is not iterable
3179 3179 [255]
3180 3180 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3181 3181 branch: default
3182 3182 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3183 3183 0:ce3cec86e6c2
3184 3184 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3185 3185 9:fbc7cd862e9c
3186 3186
3187 3187 Test manifest/get() can be join()-ed as before, though it's silly:
3188 3188
3189 3189 $ hg log -R latesttag -r tip -T '{join(manifest, "")}\n'
3190 3190 11:2bc6e9006ce2
3191 3191 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3192 3192 default
3193 3193
3194 3194 Test min/max of integers
3195 3195
3196 3196 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3197 3197 9
3198 3198 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3199 3199 10
3200 3200
3201 3201 Test dot operator precedence:
3202 3202
3203 3203 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3204 3204 (template
3205 3205 (|
3206 3206 (.
3207 3207 (symbol 'manifest')
3208 3208 (symbol 'node'))
3209 3209 (symbol 'short'))
3210 3210 (string '\n'))
3211 3211 89f4071fec70
3212 3212
3213 3213 (the following examples are invalid, but seem natural in parsing POV)
3214 3214
3215 3215 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3216 3216 (template
3217 3217 (|
3218 3218 (symbol 'foo')
3219 3219 (.
3220 3220 (symbol 'bar')
3221 3221 (symbol 'baz')))
3222 3222 (string '\n'))
3223 3223 [255]
3224 3224 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3225 3225 (template
3226 3226 (.
3227 3227 (symbol 'foo')
3228 3228 (func
3229 3229 (symbol 'bar')
3230 3230 None))
3231 3231 (string '\n'))
3232 3232 [255]
3233 3233
3234 3234 Test evaluation of dot operator:
3235 3235
3236 3236 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3237 3237 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3238 3238 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3239 3239 default
3240 3240
3241 3241 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3242 3242 hg: parse error: keyword 'author' has no member
3243 3243 [255]
3244 3244 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3245 3245 hg: parse error: 'a' has no member
3246 3246 [255]
3247 3247
3248 3248 Test the sub function of templating for expansion:
3249 3249
3250 3250 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3251 3251 xx
3252 3252
3253 3253 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3254 3254 hg: parse error: sub got an invalid pattern: [
3255 3255 [255]
3256 3256 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3257 3257 hg: parse error: sub got an invalid replacement: \1
3258 3258 [255]
3259 3259
3260 3260 Test the strip function with chars specified:
3261 3261
3262 3262 $ hg log -R latesttag --template '{desc}\n'
3263 3263 at3
3264 3264 t5
3265 3265 t4
3266 3266 t3
3267 3267 t2
3268 3268 t1
3269 3269 merge
3270 3270 h2e
3271 3271 h2d
3272 3272 h1c
3273 3273 b
3274 3274 a
3275 3275
3276 3276 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3277 3277 at3
3278 3278 5
3279 3279 4
3280 3280 3
3281 3281 2
3282 3282 1
3283 3283 merg
3284 3284 h2
3285 3285 h2d
3286 3286 h1c
3287 3287 b
3288 3288 a
3289 3289
3290 3290 Test date format:
3291 3291
3292 3292 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3293 3293 date: 70 01 01 10 +0000
3294 3294 date: 70 01 01 09 +0000
3295 3295 date: 70 01 01 04 +0000
3296 3296 date: 70 01 01 08 +0000
3297 3297 date: 70 01 01 07 +0000
3298 3298 date: 70 01 01 06 +0000
3299 3299 date: 70 01 01 05 +0100
3300 3300 date: 70 01 01 04 +0000
3301 3301 date: 70 01 01 03 +0000
3302 3302 date: 70 01 01 02 +0000
3303 3303 date: 70 01 01 01 +0000
3304 3304 date: 70 01 01 00 +0000
3305 3305
3306 3306 Test invalid date:
3307 3307
3308 3308 $ hg log -R latesttag -T '{date(rev)}\n'
3309 3309 hg: parse error: date expects a date information
3310 3310 [255]
3311 3311
3312 3312 Test integer literal:
3313 3313
3314 3314 $ hg debugtemplate -v '{(0)}\n'
3315 3315 (template
3316 3316 (group
3317 3317 (integer '0'))
3318 3318 (string '\n'))
3319 3319 0
3320 3320 $ hg debugtemplate -v '{(123)}\n'
3321 3321 (template
3322 3322 (group
3323 3323 (integer '123'))
3324 3324 (string '\n'))
3325 3325 123
3326 3326 $ hg debugtemplate -v '{(-4)}\n'
3327 3327 (template
3328 3328 (group
3329 3329 (negate
3330 3330 (integer '4')))
3331 3331 (string '\n'))
3332 3332 -4
3333 3333 $ hg debugtemplate '{(-)}\n'
3334 3334 hg: parse error at 3: not a prefix: )
3335 3335 [255]
3336 3336 $ hg debugtemplate '{(-a)}\n'
3337 3337 hg: parse error: negation needs an integer argument
3338 3338 [255]
3339 3339
3340 3340 top-level integer literal is interpreted as symbol (i.e. variable name):
3341 3341
3342 3342 $ hg debugtemplate -D 1=one -v '{1}\n'
3343 3343 (template
3344 3344 (integer '1')
3345 3345 (string '\n'))
3346 3346 one
3347 3347 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3348 3348 (template
3349 3349 (func
3350 3350 (symbol 'if')
3351 3351 (list
3352 3352 (string 't')
3353 3353 (template
3354 3354 (integer '1'))))
3355 3355 (string '\n'))
3356 3356 one
3357 3357 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3358 3358 (template
3359 3359 (|
3360 3360 (integer '1')
3361 3361 (symbol 'stringify'))
3362 3362 (string '\n'))
3363 3363 one
3364 3364
3365 3365 unless explicit symbol is expected:
3366 3366
3367 3367 $ hg log -Ra -r0 -T '{desc|1}\n'
3368 3368 hg: parse error: expected a symbol, got 'integer'
3369 3369 [255]
3370 3370 $ hg log -Ra -r0 -T '{1()}\n'
3371 3371 hg: parse error: expected a symbol, got 'integer'
3372 3372 [255]
3373 3373
3374 3374 Test string literal:
3375 3375
3376 3376 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3377 3377 (template
3378 3378 (string 'string with no template fragment')
3379 3379 (string '\n'))
3380 3380 string with no template fragment
3381 3381 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3382 3382 (template
3383 3383 (template
3384 3384 (string 'template: ')
3385 3385 (symbol 'rev'))
3386 3386 (string '\n'))
3387 3387 template: 0
3388 3388 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3389 3389 (template
3390 3390 (string 'rawstring: {rev}')
3391 3391 (string '\n'))
3392 3392 rawstring: {rev}
3393 3393 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3394 3394 (template
3395 3395 (%
3396 3396 (symbol 'files')
3397 3397 (string 'rawstring: {file}'))
3398 3398 (string '\n'))
3399 3399 rawstring: {file}
3400 3400
3401 3401 Test string escaping:
3402 3402
3403 3403 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3404 3404 >
3405 3405 <>\n<[>
3406 3406 <>\n<]>
3407 3407 <>\n<
3408 3408
3409 3409 $ hg log -R latesttag -r 0 \
3410 3410 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3411 3411 >
3412 3412 <>\n<[>
3413 3413 <>\n<]>
3414 3414 <>\n<
3415 3415
3416 3416 $ hg log -R latesttag -r 0 -T esc \
3417 3417 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3418 3418 >
3419 3419 <>\n<[>
3420 3420 <>\n<]>
3421 3421 <>\n<
3422 3422
3423 3423 $ cat <<'EOF' > esctmpl
3424 3424 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3425 3425 > EOF
3426 3426 $ hg log -R latesttag -r 0 --style ./esctmpl
3427 3427 >
3428 3428 <>\n<[>
3429 3429 <>\n<]>
3430 3430 <>\n<
3431 3431
3432 3432 Test string escaping of quotes:
3433 3433
3434 3434 $ hg log -Ra -r0 -T '{"\""}\n'
3435 3435 "
3436 3436 $ hg log -Ra -r0 -T '{"\\\""}\n'
3437 3437 \"
3438 3438 $ hg log -Ra -r0 -T '{r"\""}\n'
3439 3439 \"
3440 3440 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3441 3441 \\\"
3442 3442
3443 3443
3444 3444 $ hg log -Ra -r0 -T '{"\""}\n'
3445 3445 "
3446 3446 $ hg log -Ra -r0 -T '{"\\\""}\n'
3447 3447 \"
3448 3448 $ hg log -Ra -r0 -T '{r"\""}\n'
3449 3449 \"
3450 3450 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3451 3451 \\\"
3452 3452
3453 3453 Test exception in quoted template. single backslash before quotation mark is
3454 3454 stripped before parsing:
3455 3455
3456 3456 $ cat <<'EOF' > escquotetmpl
3457 3457 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3458 3458 > EOF
3459 3459 $ cd latesttag
3460 3460 $ hg log -r 2 --style ../escquotetmpl
3461 3461 " \" \" \\" head1
3462 3462
3463 3463 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3464 3464 valid
3465 3465 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3466 3466 valid
3467 3467
3468 3468 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3469 3469 _evalifliteral() templates (issue4733):
3470 3470
3471 3471 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3472 3472 "2
3473 3473 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3474 3474 "2
3475 3475 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3476 3476 "2
3477 3477
3478 3478 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3479 3479 \"
3480 3480 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3481 3481 \"
3482 3482 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3483 3483 \"
3484 3484
3485 3485 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3486 3486 \\\"
3487 3487 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3488 3488 \\\"
3489 3489 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3490 3490 \\\"
3491 3491
3492 3492 escaped single quotes and errors:
3493 3493
3494 3494 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3495 3495 foo
3496 3496 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3497 3497 foo
3498 3498 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3499 3499 hg: parse error at 21: unterminated string
3500 3500 [255]
3501 3501 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3502 3502 hg: parse error: trailing \ in string
3503 3503 [255]
3504 3504 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3505 3505 hg: parse error: trailing \ in string
3506 3506 [255]
3507 3507
3508 3508 $ cd ..
3509 3509
3510 3510 Test leading backslashes:
3511 3511
3512 3512 $ cd latesttag
3513 3513 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3514 3514 {rev} {file}
3515 3515 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3516 3516 \2 \head1
3517 3517 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3518 3518 \{rev} \{file}
3519 3519 $ cd ..
3520 3520
3521 3521 Test leading backslashes in "if" expression (issue4714):
3522 3522
3523 3523 $ cd latesttag
3524 3524 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3525 3525 {rev} \{rev}
3526 3526 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3527 3527 \2 \\{rev}
3528 3528 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3529 3529 \{rev} \\\{rev}
3530 3530 $ cd ..
3531 3531
3532 3532 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3533 3533
3534 3534 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3535 3535 \x6e
3536 3536 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3537 3537 \x5c\x786e
3538 3538 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3539 3539 \x6e
3540 3540 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3541 3541 \x5c\x786e
3542 3542
3543 3543 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3544 3544 \x6e
3545 3545 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3546 3546 \x5c\x786e
3547 3547 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3548 3548 \x6e
3549 3549 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3550 3550 \x5c\x786e
3551 3551
3552 3552 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3553 3553 fourth
3554 3554 second
3555 3555 third
3556 3556 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3557 3557 fourth\nsecond\nthird
3558 3558
3559 3559 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3560 3560 <p>
3561 3561 1st
3562 3562 </p>
3563 3563 <p>
3564 3564 2nd
3565 3565 </p>
3566 3566 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3567 3567 <p>
3568 3568 1st\n\n2nd
3569 3569 </p>
3570 3570 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3571 3571 1st
3572 3572
3573 3573 2nd
3574 3574
3575 3575 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3576 3576 o perso
3577 3577 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3578 3578 no person
3579 3579 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3580 3580 o perso
3581 3581 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3582 3582 no perso
3583 3583
3584 3584 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3585 3585 -o perso-
3586 3586 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3587 3587 no person
3588 3588 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3589 3589 \x2do perso\x2d
3590 3590 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3591 3591 -o perso-
3592 3592 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3593 3593 \x2do perso\x6e
3594 3594
3595 3595 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3596 3596 fourth
3597 3597 second
3598 3598 third
3599 3599
3600 3600 Test string escaping in nested expression:
3601 3601
3602 3602 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3603 3603 fourth\x6esecond\x6ethird
3604 3604 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3605 3605 fourth\x6esecond\x6ethird
3606 3606
3607 3607 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3608 3608 fourth\x6esecond\x6ethird
3609 3609 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3610 3610 fourth\x5c\x786esecond\x5c\x786ethird
3611 3611
3612 3612 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3613 3613 3:\x6eo user, \x6eo domai\x6e
3614 3614 4:\x5c\x786eew bra\x5c\x786ech
3615 3615
3616 3616 Test quotes in nested expression are evaluated just like a $(command)
3617 3617 substitution in POSIX shells:
3618 3618
3619 3619 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3620 3620 8:95c24699272e
3621 3621 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3622 3622 {8} "95c24699272e"
3623 3623
3624 3624 Test recursive evaluation:
3625 3625
3626 3626 $ hg init r
3627 3627 $ cd r
3628 3628 $ echo a > a
3629 3629 $ hg ci -Am '{rev}'
3630 3630 adding a
3631 3631 $ hg log -r 0 --template '{if(rev, desc)}\n'
3632 3632 {rev}
3633 3633 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3634 3634 test 0
3635 3635
3636 3636 $ hg branch -q 'text.{rev}'
3637 3637 $ echo aa >> aa
3638 3638 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3639 3639
3640 3640 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3641 3641 {node|short}desc to
3642 3642 text.{rev}be wrapped
3643 3643 text.{rev}desc to be
3644 3644 text.{rev}wrapped (no-eol)
3645 3645 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3646 3646 bcc7ff960b8e:desc to
3647 3647 text.1:be wrapped
3648 3648 text.1:desc to be
3649 3649 text.1:wrapped (no-eol)
3650 3650 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3651 3651 hg: parse error: fill expects an integer width
3652 3652 [255]
3653 3653
3654 3654 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3655 3655 bcc7ff960b8e:desc to be
3656 3656 termwidth.1:wrapped desc
3657 3657 termwidth.1:to be wrapped (no-eol)
3658 3658
3659 3659 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3660 3660 {node|short} (no-eol)
3661 3661 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3662 3662 bcc-ff---b-e (no-eol)
3663 3663
3664 3664 $ cat >> .hg/hgrc <<EOF
3665 3665 > [extensions]
3666 3666 > color=
3667 3667 > [color]
3668 3668 > mode=ansi
3669 3669 > text.{rev} = red
3670 3670 > text.1 = green
3671 3671 > EOF
3672 3672 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3673 3673 \x1b[0;31mtext\x1b[0m (esc)
3674 3674 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3675 3675 \x1b[0;32mtext\x1b[0m (esc)
3676 3676
3677 3677 color effect can be specified without quoting:
3678 3678
3679 3679 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3680 3680 \x1b[0;31mtext\x1b[0m (esc)
3681 3681
3682 3682 color effects can be nested (issue5413)
3683 3683
3684 3684 $ hg debugtemplate --color=always \
3685 3685 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3686 3686 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3687 3687
3688 3688 pad() should interact well with color codes (issue5416)
3689 3689
3690 3690 $ hg debugtemplate --color=always \
3691 3691 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3692 3692 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3693 3693
3694 3694 label should be no-op if color is disabled:
3695 3695
3696 3696 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3697 3697 text
3698 3698 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3699 3699 text
3700 3700
3701 3701 Test branches inside if statement:
3702 3702
3703 3703 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3704 3704 no
3705 3705
3706 3706 Test dict constructor:
3707 3707
3708 3708 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3709 3709 y=f7769ec2ab97 x=0
3710 3710 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3711 3711 x=0
3712 3712 y=f7769ec2ab97
3713 3713 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3714 3714 {"x": 0, "y": "f7769ec2ab97"}
3715 3715 $ hg log -r 0 -T '{dict()|json}\n'
3716 3716 {}
3717 3717
3718 3718 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3719 3719 rev=0 node=f7769ec2ab97
3720 3720 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3721 3721 rev=0 node=f7769ec2ab97
3722 3722
3723 3723 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3724 3724 hg: parse error: duplicated dict key 'rev' inferred
3725 3725 [255]
3726 3726 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3727 3727 hg: parse error: duplicated dict key 'node' inferred
3728 3728 [255]
3729 3729 $ hg log -r 0 -T '{dict(1 + 2)}'
3730 3730 hg: parse error: dict key cannot be inferred
3731 3731 [255]
3732 3732
3733 3733 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3734 3734 hg: parse error: dict got multiple values for keyword argument 'x'
3735 3735 [255]
3736 3736
3737 3737 Test get function:
3738 3738
3739 3739 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3740 3740 default
3741 3741 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3742 3742 default
3743 3743 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3744 3744 hg: parse error: get() expects a dict as first argument
3745 3745 [255]
3746 3746
3747 3747 Test json filter applied to hybrid object:
3748 3748
3749 3749 $ hg log -r0 -T '{files|json}\n'
3750 3750 ["a"]
3751 3751 $ hg log -r0 -T '{extras|json}\n'
3752 3752 {"branch": "default"}
3753 3753
3754 3754 Test localdate(date, tz) function:
3755 3755
3756 3756 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3757 3757 1970-01-01 09:00 +0900
3758 3758 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3759 3759 1970-01-01 00:00 +0000
3760 3760 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3761 3761 hg: parse error: localdate expects a timezone
3762 3762 [255]
3763 3763 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3764 3764 1970-01-01 02:00 +0200
3765 3765 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3766 3766 1970-01-01 00:00 +0000
3767 3767 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3768 3768 1970-01-01 00:00 +0000
3769 3769 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3770 3770 hg: parse error: localdate expects a timezone
3771 3771 [255]
3772 3772 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3773 3773 hg: parse error: localdate expects a timezone
3774 3774 [255]
3775 3775
3776 3776 Test shortest(node) function:
3777 3777
3778 3778 $ echo b > b
3779 3779 $ hg ci -qAm b
3780 3780 $ hg log --template '{shortest(node)}\n'
3781 3781 e777
3782 3782 bcc7
3783 3783 f776
3784 3784 $ hg log --template '{shortest(node, 10)}\n'
3785 3785 e777603221
3786 3786 bcc7ff960b
3787 3787 f7769ec2ab
3788 3788 $ hg log --template '{node|shortest}\n' -l1
3789 3789 e777
3790 3790
3791 3791 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3792 3792 f7769ec2ab
3793 3793 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3794 3794 hg: parse error: shortest() expects an integer minlength
3795 3795 [255]
3796 3796
3797 3797 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3798 3798 ffff
3799 3799
3800 3800 $ cd ..
3801 3801
3802 3802 Test shortest(node) with the repo having short hash collision:
3803 3803
3804 3804 $ hg init hashcollision
3805 3805 $ cd hashcollision
3806 3806 $ cat <<EOF >> .hg/hgrc
3807 3807 > [experimental]
3808 3808 > evolution.createmarkers=True
3809 3809 > EOF
3810 3810 $ echo 0 > a
3811 3811 $ hg ci -qAm 0
3812 3812 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3813 3813 > hg up -q 0
3814 3814 > echo $i > a
3815 3815 > hg ci -qm $i
3816 3816 > done
3817 3817 $ hg up -q null
3818 3818 $ hg log -r0: -T '{rev}:{node}\n'
3819 3819 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3820 3820 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3821 3821 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3822 3822 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3823 3823 4:10776689e627b465361ad5c296a20a487e153ca4
3824 3824 5:a00be79088084cb3aff086ab799f8790e01a976b
3825 3825 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3826 3826 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3827 3827 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3828 3828 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3829 3829 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3830 3830 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3831 3831 obsoleted 1 changesets
3832 3832 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3833 3833 obsoleted 1 changesets
3834 3834 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3835 3835 obsoleted 1 changesets
3836 3836
3837 3837 nodes starting with '11' (we don't have the revision number '11' though)
3838 3838
3839 3839 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3840 3840 1:1142
3841 3841 2:1140
3842 3842 3:11d
3843 3843
3844 3844 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3845 3845
3846 3846 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3847 3847 6:a0b
3848 3848 7:a04
3849 3849
3850 3850 node '10' conflicts with the revision number '10' even if it is hidden
3851 3851 (we could exclude hidden revision numbers, but currently we don't)
3852 3852
3853 3853 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3854 3854 4:107
3855 3855 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3856 3856 4:107
3857 3857
3858 3858 node 'c562' should be unique if the other 'c562' nodes are hidden
3859 3859 (but we don't try the slow path to filter out hidden nodes for now)
3860 3860
3861 3861 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3862 3862 8:c5625
3863 3863 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3864 3864 8:c5625
3865 3865 9:c5623
3866 3866 10:c562d
3867 3867
3868 3868 $ cd ..
3869 3869
3870 3870 Test pad function
3871 3871
3872 3872 $ cd r
3873 3873
3874 3874 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3875 3875 2 test
3876 3876 1 {node|short}
3877 3877 0 test
3878 3878
3879 3879 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3880 3880 2 test
3881 3881 1 {node|short}
3882 3882 0 test
3883 3883
3884 3884 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3885 3885 2------------------- test
3886 3886 1------------------- {node|short}
3887 3887 0------------------- test
3888 3888
3889 3889 Test template string in pad function
3890 3890
3891 3891 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3892 3892 {0} test
3893 3893
3894 3894 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3895 3895 \{rev} test
3896 3896
3897 3897 Test width argument passed to pad function
3898 3898
3899 3899 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3900 3900 0 test
3901 3901 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3902 3902 hg: parse error: pad() expects an integer width
3903 3903 [255]
3904 3904
3905 3905 Test invalid fillchar passed to pad function
3906 3906
3907 3907 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3908 3908 hg: parse error: pad() expects a single fill character
3909 3909 [255]
3910 3910 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3911 3911 hg: parse error: pad() expects a single fill character
3912 3912 [255]
3913 3913
3914 3914 Test boolean argument passed to pad function
3915 3915
3916 3916 no crash
3917 3917
3918 3918 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3919 3919 ---------0
3920 3920
3921 3921 string/literal
3922 3922
3923 3923 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3924 3924 ---------0
3925 3925 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3926 3926 0---------
3927 3927 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3928 3928 0---------
3929 3929
3930 3930 unknown keyword is evaluated to ''
3931 3931
3932 3932 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3933 3933 0---------
3934 3934
3935 3935 Test separate function
3936 3936
3937 3937 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3938 3938 a-b-c
3939 3939 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3940 3940 0:f7769ec2ab97 test default
3941 3941 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3942 3942 a \x1b[0;31mb\x1b[0m c d (esc)
3943 3943
3944 3944 Test boolean expression/literal passed to if function
3945 3945
3946 3946 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3947 3947 rev 0 is True
3948 3948 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3949 3949 literal 0 is True as well
3950 3950 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3951 3951 empty string is False
3952 3952 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3953 3953 empty list is False
3954 3954 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3955 3955 true is True
3956 3956 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3957 3957 false is False
3958 3958 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3959 3959 non-empty string is True
3960 3960
3961 3961 Test ifcontains function
3962 3962
3963 3963 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3964 3964 2 is in the string
3965 3965 1 is not
3966 3966 0 is in the string
3967 3967
3968 3968 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3969 3969 2 is in the string
3970 3970 1 is not
3971 3971 0 is in the string
3972 3972
3973 3973 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3974 3974 2 did not add a
3975 3975 1 did not add a
3976 3976 0 added a
3977 3977
3978 3978 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3979 3979 2 is parent of 1
3980 3980 1
3981 3981 0
3982 3982
3983 3983 Test revset function
3984 3984
3985 3985 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3986 3986 2 current rev
3987 3987 1 not current rev
3988 3988 0 not current rev
3989 3989
3990 3990 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3991 3991 2 match rev
3992 3992 1 match rev
3993 3993 0 not match rev
3994 3994
3995 3995 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
3996 3996 type not match
3997 3997
3998 3998 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3999 3999 2 Parents: 1
4000 4000 1 Parents: 0
4001 4001 0 Parents:
4002 4002
4003 4003 $ cat >> .hg/hgrc <<EOF
4004 4004 > [revsetalias]
4005 4005 > myparents(\$1) = parents(\$1)
4006 4006 > EOF
4007 4007 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4008 4008 2 Parents: 1
4009 4009 1 Parents: 0
4010 4010 0 Parents:
4011 4011
4012 4012 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4013 4013 Rev: 2
4014 4014 Ancestor: 0
4015 4015 Ancestor: 1
4016 4016 Ancestor: 2
4017 4017
4018 4018 Rev: 1
4019 4019 Ancestor: 0
4020 4020 Ancestor: 1
4021 4021
4022 4022 Rev: 0
4023 4023 Ancestor: 0
4024 4024
4025 4025 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4026 4026 2
4027 4027
4028 4028 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4029 4029 2
4030 4030
4031 4031 a list template is evaluated for each item of revset/parents
4032 4032
4033 4033 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4034 4034 2 p: 1:bcc7ff960b8e
4035 4035 1 p: 0:f7769ec2ab97
4036 4036 0 p:
4037 4037
4038 4038 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4039 4039 2 p: 1:bcc7ff960b8e -1:000000000000
4040 4040 1 p: 0:f7769ec2ab97 -1:000000000000
4041 4041 0 p: -1:000000000000 -1:000000000000
4042 4042
4043 4043 therefore, 'revcache' should be recreated for each rev
4044 4044
4045 4045 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4046 4046 2 aa b
4047 4047 p
4048 4048 1
4049 4049 p a
4050 4050 0 a
4051 4051 p
4052 4052
4053 4053 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4054 4054 2 aa b
4055 4055 p
4056 4056 1
4057 4057 p a
4058 4058 0 a
4059 4059 p
4060 4060
4061 4061 a revset item must be evaluated as an integer revision, not an offset from tip
4062 4062
4063 4063 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4064 4064 -1:000000000000
4065 4065 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4066 4066 -1:000000000000
4067 4067
4068 4068 join() should pick '{rev}' from revset items:
4069 4069
4070 4070 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4071 4071 4, 5
4072 4072
4073 4073 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4074 4074 default. join() should agree with the default formatting:
4075 4075
4076 4076 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4077 4077 5:13207e5a10d9, 4:bbe44766e73d
4078 4078
4079 4079 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4080 4080 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4081 4081 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4082 4082
4083 4083 Invalid arguments passed to revset()
4084 4084
4085 4085 $ hg log -T '{revset("%whatever", 0)}\n'
4086 4086 hg: parse error: unexpected revspec format character w
4087 4087 [255]
4088 4088 $ hg log -T '{revset("%lwhatever", files)}\n'
4089 4089 hg: parse error: unexpected revspec format character w
4090 4090 [255]
4091 4091 $ hg log -T '{revset("%s %s", 0)}\n'
4092 4092 hg: parse error: missing argument for revspec
4093 4093 [255]
4094 4094 $ hg log -T '{revset("", 0)}\n'
4095 4095 hg: parse error: too many revspec arguments specified
4096 4096 [255]
4097 4097 $ hg log -T '{revset("%s", 0, 1)}\n'
4098 4098 hg: parse error: too many revspec arguments specified
4099 4099 [255]
4100 $ hg log -T '{revset("%", 0)}\n'
4101 hg: parse error: incomplete revspec format character
4102 [255]
4103 $ hg log -T '{revset("%l", 0)}\n'
4104 hg: parse error: incomplete revspec format character
4105 [255]
4100 4106
4101 4107 Test files function
4102 4108
4103 4109 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4104 4110 2
4105 4111 a
4106 4112 aa
4107 4113 b
4108 4114 1
4109 4115 a
4110 4116 0
4111 4117 a
4112 4118
4113 4119 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4114 4120 2
4115 4121 aa
4116 4122 1
4117 4123
4118 4124 0
4119 4125
4120 4126
4121 4127 Test relpath function
4122 4128
4123 4129 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4124 4130 a
4125 4131 $ cd ..
4126 4132 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4127 4133 r/a
4128 4134 $ cd r
4129 4135
4130 4136 Test active bookmark templating
4131 4137
4132 4138 $ hg book foo
4133 4139 $ hg book bar
4134 4140 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4135 4141 2 bar* foo
4136 4142 1
4137 4143 0
4138 4144 $ hg log --template "{rev} {activebookmark}\n"
4139 4145 2 bar
4140 4146 1
4141 4147 0
4142 4148 $ hg bookmarks --inactive bar
4143 4149 $ hg log --template "{rev} {activebookmark}\n"
4144 4150 2
4145 4151 1
4146 4152 0
4147 4153 $ hg book -r1 baz
4148 4154 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4149 4155 2 bar foo
4150 4156 1 baz
4151 4157 0
4152 4158 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4153 4159 2 t
4154 4160 1 f
4155 4161 0 f
4156 4162
4157 4163 Test namespaces dict
4158 4164
4159 4165 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4160 4166 2
4161 4167 bookmarks color=bookmark builtin=True
4162 4168 bar,foo
4163 4169 tags color=tag builtin=True
4164 4170 tip
4165 4171 branches color=branch builtin=True
4166 4172 text.{rev}
4167 4173 revnames color=revname builtin=False
4168 4174 r2
4169 4175
4170 4176 1
4171 4177 bookmarks color=bookmark builtin=True
4172 4178 baz
4173 4179 tags color=tag builtin=True
4174 4180
4175 4181 branches color=branch builtin=True
4176 4182 text.{rev}
4177 4183 revnames color=revname builtin=False
4178 4184 r1
4179 4185
4180 4186 0
4181 4187 bookmarks color=bookmark builtin=True
4182 4188
4183 4189 tags color=tag builtin=True
4184 4190
4185 4191 branches color=branch builtin=True
4186 4192 default
4187 4193 revnames color=revname builtin=False
4188 4194 r0
4189 4195
4190 4196 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4191 4197 bookmarks: bar foo
4192 4198 tags: tip
4193 4199 branches: text.{rev}
4194 4200 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4195 4201 bookmarks:
4196 4202 bar
4197 4203 foo
4198 4204 tags:
4199 4205 tip
4200 4206 branches:
4201 4207 text.{rev}
4202 4208 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4203 4209 bar
4204 4210 foo
4205 4211 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4206 4212 bar
4207 4213 foo
4208 4214
4209 4215 Test stringify on sub expressions
4210 4216
4211 4217 $ cd ..
4212 4218 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4213 4219 fourth, second, third
4214 4220 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4215 4221 abc
4216 4222
4217 4223 Test splitlines
4218 4224
4219 4225 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4220 4226 @ foo Modify, add, remove, rename
4221 4227 |
4222 4228 o foo future
4223 4229 |
4224 4230 o foo third
4225 4231 |
4226 4232 o foo second
4227 4233
4228 4234 o foo merge
4229 4235 |\
4230 4236 | o foo new head
4231 4237 | |
4232 4238 o | foo new branch
4233 4239 |/
4234 4240 o foo no user, no domain
4235 4241 |
4236 4242 o foo no person
4237 4243 |
4238 4244 o foo other 1
4239 4245 | foo other 2
4240 4246 | foo
4241 4247 | foo other 3
4242 4248 o foo line 1
4243 4249 foo line 2
4244 4250
4245 4251 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4246 4252 line 1 line 2
4247 4253 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4248 4254 line 1|line 2
4249 4255
4250 4256 Test startswith
4251 4257 $ hg log -Gv -R a --template "{startswith(desc)}"
4252 4258 hg: parse error: startswith expects two arguments
4253 4259 [255]
4254 4260
4255 4261 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4256 4262 @
4257 4263 |
4258 4264 o
4259 4265 |
4260 4266 o
4261 4267 |
4262 4268 o
4263 4269
4264 4270 o
4265 4271 |\
4266 4272 | o
4267 4273 | |
4268 4274 o |
4269 4275 |/
4270 4276 o
4271 4277 |
4272 4278 o
4273 4279 |
4274 4280 o
4275 4281 |
4276 4282 o line 1
4277 4283 line 2
4278 4284
4279 4285 Test bad template with better error message
4280 4286
4281 4287 $ hg log -Gv -R a --template '{desc|user()}'
4282 4288 hg: parse error: expected a symbol, got 'func'
4283 4289 [255]
4284 4290
4285 4291 Test word function (including index out of bounds graceful failure)
4286 4292
4287 4293 $ hg log -Gv -R a --template "{word('1', desc)}"
4288 4294 @ add,
4289 4295 |
4290 4296 o
4291 4297 |
4292 4298 o
4293 4299 |
4294 4300 o
4295 4301
4296 4302 o
4297 4303 |\
4298 4304 | o head
4299 4305 | |
4300 4306 o | branch
4301 4307 |/
4302 4308 o user,
4303 4309 |
4304 4310 o person
4305 4311 |
4306 4312 o 1
4307 4313 |
4308 4314 o 1
4309 4315
4310 4316
4311 4317 Test word third parameter used as splitter
4312 4318
4313 4319 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4314 4320 @ M
4315 4321 |
4316 4322 o future
4317 4323 |
4318 4324 o third
4319 4325 |
4320 4326 o sec
4321 4327
4322 4328 o merge
4323 4329 |\
4324 4330 | o new head
4325 4331 | |
4326 4332 o | new branch
4327 4333 |/
4328 4334 o n
4329 4335 |
4330 4336 o n
4331 4337 |
4332 4338 o
4333 4339 |
4334 4340 o line 1
4335 4341 line 2
4336 4342
4337 4343 Test word error messages for not enough and too many arguments
4338 4344
4339 4345 $ hg log -Gv -R a --template "{word('0')}"
4340 4346 hg: parse error: word expects two or three arguments, got 1
4341 4347 [255]
4342 4348
4343 4349 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4344 4350 hg: parse error: word expects two or three arguments, got 7
4345 4351 [255]
4346 4352
4347 4353 Test word for integer literal
4348 4354
4349 4355 $ hg log -R a --template "{word(2, desc)}\n" -r0
4350 4356 line
4351 4357
4352 4358 Test word for invalid numbers
4353 4359
4354 4360 $ hg log -Gv -R a --template "{word('a', desc)}"
4355 4361 hg: parse error: word expects an integer index
4356 4362 [255]
4357 4363
4358 4364 Test word for out of range
4359 4365
4360 4366 $ hg log -R a --template "{word(10000, desc)}"
4361 4367 $ hg log -R a --template "{word(-10000, desc)}"
4362 4368
4363 4369 Test indent and not adding to empty lines
4364 4370
4365 4371 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4366 4372 -----
4367 4373 > line 1
4368 4374 >> line 2
4369 4375 -----
4370 4376 > other 1
4371 4377 >> other 2
4372 4378
4373 4379 >> other 3
4374 4380
4375 4381 Test with non-strings like dates
4376 4382
4377 4383 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4378 4384 1200000.00
4379 4385 1300000.00
4380 4386
4381 4387 Test broken string escapes:
4382 4388
4383 4389 $ hg log -T "bogus\\" -R a
4384 4390 hg: parse error: trailing \ in string
4385 4391 [255]
4386 4392 $ hg log -T "\\xy" -R a
4387 4393 hg: parse error: invalid \x escape
4388 4394 [255]
4389 4395
4390 4396 json filter should escape HTML tags so that the output can be embedded in hgweb:
4391 4397
4392 4398 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4393 4399 "\u003cfoo@example.org\u003e"
4394 4400
4395 4401 Templater supports aliases of symbol and func() styles:
4396 4402
4397 4403 $ hg clone -q a aliases
4398 4404 $ cd aliases
4399 4405 $ cat <<EOF >> .hg/hgrc
4400 4406 > [templatealias]
4401 4407 > r = rev
4402 4408 > rn = "{r}:{node|short}"
4403 4409 > status(c, files) = files % "{c} {file}\n"
4404 4410 > utcdate(d) = localdate(d, "UTC")
4405 4411 > EOF
4406 4412
4407 4413 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4408 4414 (template
4409 4415 (symbol 'rn')
4410 4416 (string ' ')
4411 4417 (|
4412 4418 (func
4413 4419 (symbol 'utcdate')
4414 4420 (symbol 'date'))
4415 4421 (symbol 'isodate'))
4416 4422 (string '\n'))
4417 4423 * expanded:
4418 4424 (template
4419 4425 (template
4420 4426 (symbol 'rev')
4421 4427 (string ':')
4422 4428 (|
4423 4429 (symbol 'node')
4424 4430 (symbol 'short')))
4425 4431 (string ' ')
4426 4432 (|
4427 4433 (func
4428 4434 (symbol 'localdate')
4429 4435 (list
4430 4436 (symbol 'date')
4431 4437 (string 'UTC')))
4432 4438 (symbol 'isodate'))
4433 4439 (string '\n'))
4434 4440 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4435 4441
4436 4442 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4437 4443 (template
4438 4444 (func
4439 4445 (symbol 'status')
4440 4446 (list
4441 4447 (string 'A')
4442 4448 (symbol 'file_adds'))))
4443 4449 * expanded:
4444 4450 (template
4445 4451 (%
4446 4452 (symbol 'file_adds')
4447 4453 (template
4448 4454 (string 'A')
4449 4455 (string ' ')
4450 4456 (symbol 'file')
4451 4457 (string '\n'))))
4452 4458 A a
4453 4459
4454 4460 A unary function alias can be called as a filter:
4455 4461
4456 4462 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4457 4463 (template
4458 4464 (|
4459 4465 (|
4460 4466 (symbol 'date')
4461 4467 (symbol 'utcdate'))
4462 4468 (symbol 'isodate'))
4463 4469 (string '\n'))
4464 4470 * expanded:
4465 4471 (template
4466 4472 (|
4467 4473 (func
4468 4474 (symbol 'localdate')
4469 4475 (list
4470 4476 (symbol 'date')
4471 4477 (string 'UTC')))
4472 4478 (symbol 'isodate'))
4473 4479 (string '\n'))
4474 4480 1970-01-12 13:46 +0000
4475 4481
4476 4482 Aliases should be applied only to command arguments and templates in hgrc.
4477 4483 Otherwise, our stock styles and web templates could be corrupted:
4478 4484
4479 4485 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4480 4486 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4481 4487
4482 4488 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4483 4489 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4484 4490
4485 4491 $ cat <<EOF > tmpl
4486 4492 > changeset = 'nothing expanded:{rn}\n'
4487 4493 > EOF
4488 4494 $ hg log -r0 --style ./tmpl
4489 4495 nothing expanded:
4490 4496
4491 4497 Aliases in formatter:
4492 4498
4493 4499 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4494 4500 default 6:d41e714fe50d
4495 4501 foo 4:bbe44766e73d
4496 4502
4497 4503 Aliases should honor HGPLAIN:
4498 4504
4499 4505 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4500 4506 nothing expanded:
4501 4507 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4502 4508 0:1e4e1b8f71e0
4503 4509
4504 4510 Unparsable alias:
4505 4511
4506 4512 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4507 4513 (template
4508 4514 (symbol 'bad'))
4509 4515 abort: bad definition of template alias "bad": at 2: not a prefix: end
4510 4516 [255]
4511 4517 $ hg log --config templatealias.bad='x(' -T '{bad}'
4512 4518 abort: bad definition of template alias "bad": at 2: not a prefix: end
4513 4519 [255]
4514 4520
4515 4521 $ cd ..
4516 4522
4517 4523 Set up repository for non-ascii encoding tests:
4518 4524
4519 4525 $ hg init nonascii
4520 4526 $ cd nonascii
4521 4527 $ $PYTHON <<EOF
4522 4528 > open('latin1', 'w').write('\xe9')
4523 4529 > open('utf-8', 'w').write('\xc3\xa9')
4524 4530 > EOF
4525 4531 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4526 4532 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4527 4533
4528 4534 json filter should try round-trip conversion to utf-8:
4529 4535
4530 4536 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4531 4537 "\u00e9"
4532 4538 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4533 4539 "non-ascii branch: \u00e9"
4534 4540
4535 4541 json filter takes input as utf-8b:
4536 4542
4537 4543 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4538 4544 "\u00e9"
4539 4545 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4540 4546 "\udce9"
4541 4547
4542 4548 utf8 filter:
4543 4549
4544 4550 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4545 4551 round-trip: c3a9
4546 4552 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4547 4553 decoded: c3a9
4548 4554 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4549 4555 abort: decoding near * (glob)
4550 4556 [255]
4551 4557 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4552 4558 abort: template filter 'utf8' is not compatible with keyword 'rev'
4553 4559 [255]
4554 4560
4555 4561 pad width:
4556 4562
4557 4563 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4558 4564 \xc3\xa9- (esc)
4559 4565
4560 4566 $ cd ..
4561 4567
4562 4568 Test that template function in extension is registered as expected
4563 4569
4564 4570 $ cd a
4565 4571
4566 4572 $ cat <<EOF > $TESTTMP/customfunc.py
4567 4573 > from mercurial import registrar
4568 4574 >
4569 4575 > templatefunc = registrar.templatefunc()
4570 4576 >
4571 4577 > @templatefunc('custom()')
4572 4578 > def custom(context, mapping, args):
4573 4579 > return 'custom'
4574 4580 > EOF
4575 4581 $ cat <<EOF > .hg/hgrc
4576 4582 > [extensions]
4577 4583 > customfunc = $TESTTMP/customfunc.py
4578 4584 > EOF
4579 4585
4580 4586 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4581 4587 custom
4582 4588
4583 4589 $ cd ..
4584 4590
4585 4591 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4586 4592 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4587 4593 columns. We don't care about other aspects of the graph rendering here.
4588 4594
4589 4595 $ hg init graphwidth
4590 4596 $ cd graphwidth
4591 4597
4592 4598 $ wrappabletext="a a a a a a a a a a a a"
4593 4599
4594 4600 $ printf "first\n" > file
4595 4601 $ hg add file
4596 4602 $ hg commit -m "$wrappabletext"
4597 4603
4598 4604 $ printf "first\nsecond\n" > file
4599 4605 $ hg commit -m "$wrappabletext"
4600 4606
4601 4607 $ hg checkout 0
4602 4608 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4603 4609 $ printf "third\nfirst\n" > file
4604 4610 $ hg commit -m "$wrappabletext"
4605 4611 created new head
4606 4612
4607 4613 $ hg merge
4608 4614 merging file
4609 4615 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4610 4616 (branch merge, don't forget to commit)
4611 4617
4612 4618 $ hg log --graph -T "{graphwidth}"
4613 4619 @ 3
4614 4620 |
4615 4621 | @ 5
4616 4622 |/
4617 4623 o 3
4618 4624
4619 4625 $ hg commit -m "$wrappabletext"
4620 4626
4621 4627 $ hg log --graph -T "{graphwidth}"
4622 4628 @ 5
4623 4629 |\
4624 4630 | o 5
4625 4631 | |
4626 4632 o | 5
4627 4633 |/
4628 4634 o 3
4629 4635
4630 4636
4631 4637 $ hg checkout 0
4632 4638 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4633 4639 $ printf "third\nfirst\nsecond\n" > file
4634 4640 $ hg commit -m "$wrappabletext"
4635 4641 created new head
4636 4642
4637 4643 $ hg log --graph -T "{graphwidth}"
4638 4644 @ 3
4639 4645 |
4640 4646 | o 7
4641 4647 | |\
4642 4648 +---o 7
4643 4649 | |
4644 4650 | o 5
4645 4651 |/
4646 4652 o 3
4647 4653
4648 4654
4649 4655 $ hg log --graph -T "{graphwidth}" -r 3
4650 4656 o 5
4651 4657 |\
4652 4658 ~ ~
4653 4659
4654 4660 $ hg log --graph -T "{graphwidth}" -r 1
4655 4661 o 3
4656 4662 |
4657 4663 ~
4658 4664
4659 4665 $ hg merge
4660 4666 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4661 4667 (branch merge, don't forget to commit)
4662 4668 $ hg commit -m "$wrappabletext"
4663 4669
4664 4670 $ printf "seventh\n" >> file
4665 4671 $ hg commit -m "$wrappabletext"
4666 4672
4667 4673 $ hg log --graph -T "{graphwidth}"
4668 4674 @ 3
4669 4675 |
4670 4676 o 5
4671 4677 |\
4672 4678 | o 5
4673 4679 | |
4674 4680 o | 7
4675 4681 |\ \
4676 4682 | o | 7
4677 4683 | |/
4678 4684 o / 5
4679 4685 |/
4680 4686 o 3
4681 4687
4682 4688
4683 4689 The point of graphwidth is to allow wrapping that accounts for the space taken
4684 4690 by the graph.
4685 4691
4686 4692 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4687 4693 @ a a a a
4688 4694 | a a a a
4689 4695 | a a a a
4690 4696 o a a a
4691 4697 |\ a a a
4692 4698 | | a a a
4693 4699 | | a a a
4694 4700 | o a a a
4695 4701 | | a a a
4696 4702 | | a a a
4697 4703 | | a a a
4698 4704 o | a a
4699 4705 |\ \ a a
4700 4706 | | | a a
4701 4707 | | | a a
4702 4708 | | | a a
4703 4709 | | | a a
4704 4710 | o | a a
4705 4711 | |/ a a
4706 4712 | | a a
4707 4713 | | a a
4708 4714 | | a a
4709 4715 | | a a
4710 4716 o | a a a
4711 4717 |/ a a a
4712 4718 | a a a
4713 4719 | a a a
4714 4720 o a a a a
4715 4721 a a a a
4716 4722 a a a a
4717 4723
4718 4724 Something tricky happens when there are elided nodes; the next drawn row of
4719 4725 edges can be more than one column wider, but the graph width only increases by
4720 4726 one column. The remaining columns are added in between the nodes.
4721 4727
4722 4728 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4723 4729 o 5
4724 4730 |\
4725 4731 | \
4726 4732 | :\
4727 4733 o : : 7
4728 4734 :/ /
4729 4735 : o 5
4730 4736 :/
4731 4737 o 3
4732 4738
4733 4739
4734 4740 $ cd ..
4735 4741
General Comments 0
You need to be logged in to leave comments. Login now