##// END OF EJS Templates
templater: support using templates with non-standard names from map file...
Alexander Plavin -
r19770:0361163e default
parent child Browse files
Show More
@@ -1,576 +1,585
1 1 # templater.py - template expansion for output
2 2 #
3 3 # Copyright 2005, 2006 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 i18n import _
9 9 import sys, os, re
10 10 import util, config, templatefilters, parser, error
11 11 import types
12 12 import minirst
13 13
14 14 # template parsing
15 15
16 16 elements = {
17 17 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
18 18 ",": (2, None, ("list", 2)),
19 19 "|": (5, None, ("|", 5)),
20 20 "%": (6, None, ("%", 6)),
21 21 ")": (0, None, None),
22 22 "symbol": (0, ("symbol",), None),
23 23 "string": (0, ("string",), None),
24 24 "end": (0, None, None),
25 25 }
26 26
27 27 def tokenizer(data):
28 28 program, start, end = data
29 29 pos = start
30 30 while pos < end:
31 31 c = program[pos]
32 32 if c.isspace(): # skip inter-token whitespace
33 33 pass
34 34 elif c in "(,)%|": # handle simple operators
35 35 yield (c, None, pos)
36 36 elif (c in '"\'' or c == 'r' and
37 37 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
38 38 if c == 'r':
39 39 pos += 1
40 40 c = program[pos]
41 41 decode = False
42 42 else:
43 43 decode = True
44 44 pos += 1
45 45 s = pos
46 46 while pos < end: # find closing quote
47 47 d = program[pos]
48 48 if decode and d == '\\': # skip over escaped characters
49 49 pos += 2
50 50 continue
51 51 if d == c:
52 52 if not decode:
53 53 yield ('string', program[s:pos].replace('\\', r'\\'), s)
54 54 break
55 55 yield ('string', program[s:pos].decode('string-escape'), s)
56 56 break
57 57 pos += 1
58 58 else:
59 59 raise error.ParseError(_("unterminated string"), s)
60 60 elif c.isalnum() or c in '_':
61 61 s = pos
62 62 pos += 1
63 63 while pos < end: # find end of symbol
64 64 d = program[pos]
65 65 if not (d.isalnum() or d == "_"):
66 66 break
67 67 pos += 1
68 68 sym = program[s:pos]
69 69 yield ('symbol', sym, s)
70 70 pos -= 1
71 71 elif c == '}':
72 72 pos += 1
73 73 break
74 74 else:
75 75 raise error.ParseError(_("syntax error"), pos)
76 76 pos += 1
77 77 yield ('end', None, pos)
78 78
79 79 def compiletemplate(tmpl, context):
80 80 parsed = []
81 81 pos, stop = 0, len(tmpl)
82 82 p = parser.parser(tokenizer, elements)
83 83
84 84 while pos < stop:
85 85 n = tmpl.find('{', pos)
86 86 if n < 0:
87 87 parsed.append(("string", tmpl[pos:]))
88 88 break
89 89 if n > 0 and tmpl[n - 1] == '\\':
90 90 # escaped
91 91 parsed.append(("string", tmpl[pos:n - 1] + "{"))
92 92 pos = n + 1
93 93 continue
94 94 if n > pos:
95 95 parsed.append(("string", tmpl[pos:n]))
96 96
97 97 pd = [tmpl, n + 1, stop]
98 98 parseres, pos = p.parse(pd)
99 99 parsed.append(parseres)
100 100
101 101 return [compileexp(e, context) for e in parsed]
102 102
103 103 def compileexp(exp, context):
104 104 t = exp[0]
105 105 if t in methods:
106 106 return methods[t](exp, context)
107 107 raise error.ParseError(_("unknown method '%s'") % t)
108 108
109 109 # template evaluation
110 110
111 111 def getsymbol(exp):
112 112 if exp[0] == 'symbol':
113 113 return exp[1]
114 114 raise error.ParseError(_("expected a symbol"))
115 115
116 116 def getlist(x):
117 117 if not x:
118 118 return []
119 119 if x[0] == 'list':
120 120 return getlist(x[1]) + [x[2]]
121 121 return [x]
122 122
123 123 def getfilter(exp, context):
124 124 f = getsymbol(exp)
125 125 if f not in context._filters:
126 126 raise error.ParseError(_("unknown function '%s'") % f)
127 127 return context._filters[f]
128 128
129 129 def gettemplate(exp, context):
130 130 if exp[0] == 'string':
131 131 return compiletemplate(exp[1], context)
132 132 if exp[0] == 'symbol':
133 133 return context._load(exp[1])
134 134 raise error.ParseError(_("expected template specifier"))
135 135
136 136 def runstring(context, mapping, data):
137 137 return data
138 138
139 139 def runsymbol(context, mapping, key):
140 140 v = mapping.get(key)
141 141 if v is None:
142 v = context._defaults.get(key, '')
142 v = context._defaults.get(key)
143 if v is None:
144 try:
145 v = context.process(key, mapping)
146 except TemplateNotFound:
147 v = ''
143 148 if util.safehasattr(v, '__call__'):
144 149 return v(**mapping)
145 150 if isinstance(v, types.GeneratorType):
146 151 v = list(v)
147 152 mapping[key] = v
148 153 return v
149 154 return v
150 155
151 156 def buildfilter(exp, context):
152 157 func, data = compileexp(exp[1], context)
153 158 filt = getfilter(exp[2], context)
154 159 return (runfilter, (func, data, filt))
155 160
156 161 def runfilter(context, mapping, data):
157 162 func, data, filt = data
158 163 try:
159 164 return filt(func(context, mapping, data))
160 165 except (ValueError, AttributeError, TypeError):
161 166 if isinstance(data, tuple):
162 167 dt = data[1]
163 168 else:
164 169 dt = data
165 170 raise util.Abort(_("template filter '%s' is not compatible with "
166 171 "keyword '%s'") % (filt.func_name, dt))
167 172
168 173 def buildmap(exp, context):
169 174 func, data = compileexp(exp[1], context)
170 175 ctmpl = gettemplate(exp[2], context)
171 176 return (runmap, (func, data, ctmpl))
172 177
173 178 def runtemplate(context, mapping, template):
174 179 for func, data in template:
175 180 yield func(context, mapping, data)
176 181
177 182 def runmap(context, mapping, data):
178 183 func, data, ctmpl = data
179 184 d = func(context, mapping, data)
180 185 if util.safehasattr(d, '__call__'):
181 186 d = d()
182 187
183 188 lm = mapping.copy()
184 189
185 190 for i in d:
186 191 if isinstance(i, dict):
187 192 lm.update(i)
188 193 lm['originalnode'] = mapping.get('node')
189 194 yield runtemplate(context, lm, ctmpl)
190 195 else:
191 196 # v is not an iterable of dicts, this happen when 'key'
192 197 # has been fully expanded already and format is useless.
193 198 # If so, return the expanded value.
194 199 yield i
195 200
196 201 def buildfunc(exp, context):
197 202 n = getsymbol(exp[1])
198 203 args = [compileexp(x, context) for x in getlist(exp[2])]
199 204 if n in funcs:
200 205 f = funcs[n]
201 206 return (f, args)
202 207 if n in context._filters:
203 208 if len(args) != 1:
204 209 raise error.ParseError(_("filter %s expects one argument") % n)
205 210 f = context._filters[n]
206 211 return (runfilter, (args[0][0], args[0][1], f))
207 212
208 213 def date(context, mapping, args):
209 214 if not (1 <= len(args) <= 2):
210 215 raise error.ParseError(_("date expects one or two arguments"))
211 216
212 217 date = args[0][0](context, mapping, args[0][1])
213 218 if len(args) == 2:
214 219 fmt = stringify(args[1][0](context, mapping, args[1][1]))
215 220 return util.datestr(date, fmt)
216 221 return util.datestr(date)
217 222
218 223 def fill(context, mapping, args):
219 224 if not (1 <= len(args) <= 4):
220 225 raise error.ParseError(_("fill expects one to four arguments"))
221 226
222 227 text = stringify(args[0][0](context, mapping, args[0][1]))
223 228 width = 76
224 229 initindent = ''
225 230 hangindent = ''
226 231 if 2 <= len(args) <= 4:
227 232 try:
228 233 width = int(stringify(args[1][0](context, mapping, args[1][1])))
229 234 except ValueError:
230 235 raise error.ParseError(_("fill expects an integer width"))
231 236 try:
232 237 initindent = stringify(args[2][0](context, mapping, args[2][1]))
233 238 initindent = stringify(runtemplate(context, mapping,
234 239 compiletemplate(initindent, context)))
235 240 hangindent = stringify(args[3][0](context, mapping, args[3][1]))
236 241 hangindent = stringify(runtemplate(context, mapping,
237 242 compiletemplate(hangindent, context)))
238 243 except IndexError:
239 244 pass
240 245
241 246 return templatefilters.fill(text, width, initindent, hangindent)
242 247
243 248 def get(context, mapping, args):
244 249 if len(args) != 2:
245 250 # i18n: "get" is a keyword
246 251 raise error.ParseError(_("get() expects two arguments"))
247 252
248 253 dictarg = args[0][0](context, mapping, args[0][1])
249 254 if not util.safehasattr(dictarg, 'get'):
250 255 # i18n: "get" is a keyword
251 256 raise error.ParseError(_("get() expects a dict as first argument"))
252 257
253 258 key = args[1][0](context, mapping, args[1][1])
254 259 yield dictarg.get(key)
255 260
256 261 def if_(context, mapping, args):
257 262 if not (2 <= len(args) <= 3):
258 263 # i18n: "if" is a keyword
259 264 raise error.ParseError(_("if expects two or three arguments"))
260 265
261 266 test = stringify(args[0][0](context, mapping, args[0][1]))
262 267 if test:
263 268 t = stringify(args[1][0](context, mapping, args[1][1]))
264 269 yield runtemplate(context, mapping, compiletemplate(t, context))
265 270 elif len(args) == 3:
266 271 t = stringify(args[2][0](context, mapping, args[2][1]))
267 272 yield runtemplate(context, mapping, compiletemplate(t, context))
268 273
269 274 def ifeq(context, mapping, args):
270 275 if not (3 <= len(args) <= 4):
271 276 # i18n: "ifeq" is a keyword
272 277 raise error.ParseError(_("ifeq expects three or four arguments"))
273 278
274 279 test = stringify(args[0][0](context, mapping, args[0][1]))
275 280 match = stringify(args[1][0](context, mapping, args[1][1]))
276 281 if test == match:
277 282 t = stringify(args[2][0](context, mapping, args[2][1]))
278 283 yield runtemplate(context, mapping, compiletemplate(t, context))
279 284 elif len(args) == 4:
280 285 t = stringify(args[3][0](context, mapping, args[3][1]))
281 286 yield runtemplate(context, mapping, compiletemplate(t, context))
282 287
283 288 def join(context, mapping, args):
284 289 if not (1 <= len(args) <= 2):
285 290 # i18n: "join" is a keyword
286 291 raise error.ParseError(_("join expects one or two arguments"))
287 292
288 293 joinset = args[0][0](context, mapping, args[0][1])
289 294 if util.safehasattr(joinset, '__call__'):
290 295 jf = joinset.joinfmt
291 296 joinset = [jf(x) for x in joinset()]
292 297
293 298 joiner = " "
294 299 if len(args) > 1:
295 300 joiner = args[1][0](context, mapping, args[1][1])
296 301
297 302 first = True
298 303 for x in joinset:
299 304 if first:
300 305 first = False
301 306 else:
302 307 yield joiner
303 308 yield x
304 309
305 310 def label(context, mapping, args):
306 311 if len(args) != 2:
307 312 # i18n: "label" is a keyword
308 313 raise error.ParseError(_("label expects two arguments"))
309 314
310 315 # ignore args[0] (the label string) since this is supposed to be a a no-op
311 316 t = stringify(args[1][0](context, mapping, args[1][1]))
312 317 yield runtemplate(context, mapping, compiletemplate(t, context))
313 318
314 319 def rstdoc(context, mapping, args):
315 320 if len(args) != 2:
316 321 # i18n: "rstdoc" is a keyword
317 322 raise error.ParseError(_("rstdoc expects two arguments"))
318 323
319 324 text = stringify(args[0][0](context, mapping, args[0][1]))
320 325 style = stringify(args[1][0](context, mapping, args[1][1]))
321 326
322 327 return minirst.format(text, style=style, keep=['verbose'])
323 328
324 329 def strip(context, mapping, args):
325 330 if not (1 <= len(args) <= 2):
326 331 raise error.ParseError(_("strip expects one or two arguments"))
327 332
328 333 text = args[0][0](context, mapping, args[0][1])
329 334 if len(args) == 2:
330 335 chars = args[1][0](context, mapping, args[1][1])
331 336 return text.strip(chars)
332 337 return text.strip()
333 338
334 339 def sub(context, mapping, args):
335 340 if len(args) != 3:
336 341 # i18n: "sub" is a keyword
337 342 raise error.ParseError(_("sub expects three arguments"))
338 343
339 344 pat = stringify(args[0][0](context, mapping, args[0][1]))
340 345 rpl = stringify(args[1][0](context, mapping, args[1][1]))
341 346 src = stringify(args[2][0](context, mapping, args[2][1]))
342 347 src = stringify(runtemplate(context, mapping,
343 348 compiletemplate(src, context)))
344 349 yield re.sub(pat, rpl, src)
345 350
346 351 methods = {
347 352 "string": lambda e, c: (runstring, e[1]),
348 353 "symbol": lambda e, c: (runsymbol, e[1]),
349 354 "group": lambda e, c: compileexp(e[1], c),
350 355 # ".": buildmember,
351 356 "|": buildfilter,
352 357 "%": buildmap,
353 358 "func": buildfunc,
354 359 }
355 360
356 361 funcs = {
357 362 "date": date,
358 363 "fill": fill,
359 364 "get": get,
360 365 "if": if_,
361 366 "ifeq": ifeq,
362 367 "join": join,
363 368 "label": label,
364 369 "rstdoc": rstdoc,
365 370 "strip": strip,
366 371 "sub": sub,
367 372 }
368 373
369 374 # template engine
370 375
371 376 path = ['templates', '../templates']
372 377 stringify = templatefilters.stringify
373 378
374 379 def _flatten(thing):
375 380 '''yield a single stream from a possibly nested set of iterators'''
376 381 if isinstance(thing, str):
377 382 yield thing
378 383 elif not util.safehasattr(thing, '__iter__'):
379 384 if thing is not None:
380 385 yield str(thing)
381 386 else:
382 387 for i in thing:
383 388 if isinstance(i, str):
384 389 yield i
385 390 elif not util.safehasattr(i, '__iter__'):
386 391 if i is not None:
387 392 yield str(i)
388 393 elif i is not None:
389 394 for j in _flatten(i):
390 395 yield j
391 396
392 397 def parsestring(s, quoted=True):
393 398 '''parse a string using simple c-like syntax.
394 399 string must be in quotes if quoted is True.'''
395 400 if quoted:
396 401 if len(s) < 2 or s[0] != s[-1]:
397 402 raise SyntaxError(_('unmatched quotes'))
398 403 return s[1:-1].decode('string_escape')
399 404
400 405 return s.decode('string_escape')
401 406
402 407 class engine(object):
403 408 '''template expansion engine.
404 409
405 410 template expansion works like this. a map file contains key=value
406 411 pairs. if value is quoted, it is treated as string. otherwise, it
407 412 is treated as name of template file.
408 413
409 414 templater is asked to expand a key in map. it looks up key, and
410 415 looks for strings like this: {foo}. it expands {foo} by looking up
411 416 foo in map, and substituting it. expansion is recursive: it stops
412 417 when there is no more {foo} to replace.
413 418
414 419 expansion also allows formatting and filtering.
415 420
416 421 format uses key to expand each item in list. syntax is
417 422 {key%format}.
418 423
419 424 filter uses function to transform value. syntax is
420 425 {key|filter1|filter2|...}.'''
421 426
422 427 def __init__(self, loader, filters={}, defaults={}):
423 428 self._loader = loader
424 429 self._filters = filters
425 430 self._defaults = defaults
426 431 self._cache = {}
427 432
428 433 def _load(self, t):
429 434 '''load, parse, and cache a template'''
430 435 if t not in self._cache:
431 436 self._cache[t] = compiletemplate(self._loader(t), self)
432 437 return self._cache[t]
433 438
434 439 def process(self, t, mapping):
435 440 '''Perform expansion. t is name of map element to expand.
436 441 mapping contains added elements for use during expansion. Is a
437 442 generator.'''
438 443 return _flatten(runtemplate(self, mapping, self._load(t)))
439 444
440 445 engines = {'default': engine}
441 446
442 447 def stylelist():
443 448 path = templatepath()[0]
444 449 dirlist = os.listdir(path)
445 450 stylelist = []
446 451 for file in dirlist:
447 452 split = file.split(".")
448 453 if split[0] == "map-cmdline":
449 454 stylelist.append(split[1])
450 455 return ", ".join(sorted(stylelist))
451 456
457 class TemplateNotFound(util.Abort):
458 pass
459
452 460 class templater(object):
453 461
454 462 def __init__(self, mapfile, filters={}, defaults={}, cache={},
455 463 minchunk=1024, maxchunk=65536):
456 464 '''set up template engine.
457 465 mapfile is name of file to read map definitions from.
458 466 filters is dict of functions. each transforms a value into another.
459 467 defaults is dict of default map definitions.'''
460 468 self.mapfile = mapfile or 'template'
461 469 self.cache = cache.copy()
462 470 self.map = {}
463 471 self.base = (mapfile and os.path.dirname(mapfile)) or ''
464 472 self.filters = templatefilters.filters.copy()
465 473 self.filters.update(filters)
466 474 self.defaults = defaults
467 475 self.minchunk, self.maxchunk = minchunk, maxchunk
468 476 self.ecache = {}
469 477
470 478 if not mapfile:
471 479 return
472 480 if not os.path.exists(mapfile):
473 481 raise util.Abort(_("style '%s' not found") % mapfile,
474 482 hint=_("available styles: %s") % stylelist())
475 483
476 484 conf = config.config()
477 485 conf.read(mapfile)
478 486
479 487 for key, val in conf[''].items():
480 488 if not val:
481 489 raise SyntaxError(_('%s: missing value') % conf.source('', key))
482 490 if val[0] in "'\"":
483 491 try:
484 492 self.cache[key] = parsestring(val)
485 493 except SyntaxError, inst:
486 494 raise SyntaxError('%s: %s' %
487 495 (conf.source('', key), inst.args[0]))
488 496 else:
489 497 val = 'default', val
490 498 if ':' in val[1]:
491 499 val = val[1].split(':', 1)
492 500 self.map[key] = val[0], os.path.join(self.base, val[1])
493 501
494 502 def __contains__(self, key):
495 503 return key in self.cache or key in self.map
496 504
497 505 def load(self, t):
498 506 '''Get the template for the given template name. Use a local cache.'''
499 507 if t not in self.cache:
500 508 try:
501 509 self.cache[t] = util.readfile(self.map[t][1])
502 510 except KeyError, inst:
503 raise util.Abort(_('"%s" not in template map') % inst.args[0])
511 raise TemplateNotFound(_('"%s" not in template map') %
512 inst.args[0])
504 513 except IOError, inst:
505 514 raise IOError(inst.args[0], _('template file %s: %s') %
506 515 (self.map[t][1], inst.args[1]))
507 516 return self.cache[t]
508 517
509 518 def __call__(self, t, **mapping):
510 519 ttype = t in self.map and self.map[t][0] or 'default'
511 520 if ttype not in self.ecache:
512 521 self.ecache[ttype] = engines[ttype](self.load,
513 522 self.filters, self.defaults)
514 523 proc = self.ecache[ttype]
515 524
516 525 stream = proc.process(t, mapping)
517 526 if self.minchunk:
518 527 stream = util.increasingchunks(stream, min=self.minchunk,
519 528 max=self.maxchunk)
520 529 return stream
521 530
522 531 def templatepath(name=None):
523 532 '''return location of template file or directory (if no name).
524 533 returns None if not found.'''
525 534 normpaths = []
526 535
527 536 # executable version (py2exe) doesn't support __file__
528 537 if util.mainfrozen():
529 538 module = sys.executable
530 539 else:
531 540 module = __file__
532 541 for f in path:
533 542 if f.startswith('/'):
534 543 p = f
535 544 else:
536 545 fl = f.split('/')
537 546 p = os.path.join(os.path.dirname(module), *fl)
538 547 if name:
539 548 p = os.path.join(p, name)
540 549 if name and os.path.exists(p):
541 550 return os.path.normpath(p)
542 551 elif os.path.isdir(p):
543 552 normpaths.append(os.path.normpath(p))
544 553
545 554 return normpaths
546 555
547 556 def stylemap(styles, paths=None):
548 557 """Return path to mapfile for a given style.
549 558
550 559 Searches mapfile in the following locations:
551 560 1. templatepath/style/map
552 561 2. templatepath/map-style
553 562 3. templatepath/map
554 563 """
555 564
556 565 if paths is None:
557 566 paths = templatepath()
558 567 elif isinstance(paths, str):
559 568 paths = [paths]
560 569
561 570 if isinstance(styles, str):
562 571 styles = [styles]
563 572
564 573 for style in styles:
565 574 if not style:
566 575 continue
567 576 locations = [os.path.join(style, 'map'), 'map-' + style]
568 577 locations.append('map')
569 578
570 579 for path in paths:
571 580 for location in locations:
572 581 mapfile = os.path.join(path, location)
573 582 if os.path.isfile(mapfile):
574 583 return style, mapfile
575 584
576 585 raise RuntimeError("No hgweb templates found in %r" % paths)
@@ -1,1566 +1,1588
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 Second branch starting at nullrev:
33 33
34 34 $ hg update null
35 35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
36 36 $ echo second > second
37 37 $ hg add second
38 38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
39 39 created new head
40 40
41 41 $ echo third > third
42 42 $ hg add third
43 43 $ hg mv second fourth
44 44 $ hg commit -m third -d "2020-01-01 10:01"
45 45
46 46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
47 47 fourth (second)
48 48 $ hg log --template '{file_copies % "{source} -> {name}\n"}' -r .
49 49 second -> fourth
50 50
51 51 Quoting for ui.logtemplate
52 52
53 53 $ hg tip --config "ui.logtemplate={rev}\n"
54 54 8
55 55 $ hg tip --config "ui.logtemplate='{rev}\n'"
56 56 8
57 57 $ hg tip --config 'ui.logtemplate="{rev}\n"'
58 58 8
59 59
60 60 Make sure user/global hgrc does not affect tests
61 61
62 62 $ echo '[ui]' > .hg/hgrc
63 63 $ echo 'logtemplate =' >> .hg/hgrc
64 64 $ echo 'style =' >> .hg/hgrc
65 65
66 66 Default style is like normal output:
67 67
68 68 $ hg log > log.out
69 69 $ hg log --style default > style.out
70 70 $ cmp log.out style.out || diff -u log.out style.out
71 71
72 72 $ hg log -v > log.out
73 73 $ hg log -v --style default > style.out
74 74 $ cmp log.out style.out || diff -u log.out style.out
75 75
76 76 $ hg log --debug > log.out
77 77 $ hg log --debug --style default > style.out
78 78 $ cmp log.out style.out || diff -u log.out style.out
79 79
80 80 Revision with no copies (used to print a traceback):
81 81
82 82 $ hg tip -v --template '\n'
83 83
84 84
85 85 Compact style works:
86 86
87 87 $ hg log --style compact
88 88 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
89 89 third
90 90
91 91 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
92 92 second
93 93
94 94 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
95 95 merge
96 96
97 97 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
98 98 new head
99 99
100 100 4 bbe44766e73d 1970-01-17 04:53 +0000 person
101 101 new branch
102 102
103 103 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
104 104 no user, no domain
105 105
106 106 2 97054abb4ab8 1970-01-14 21:20 +0000 other
107 107 no person
108 108
109 109 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
110 110 other 1
111 111
112 112 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
113 113 line 1
114 114
115 115
116 116 $ hg log -v --style compact
117 117 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
118 118 third
119 119
120 120 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
121 121 second
122 122
123 123 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
124 124 merge
125 125
126 126 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
127 127 new head
128 128
129 129 4 bbe44766e73d 1970-01-17 04:53 +0000 person
130 130 new branch
131 131
132 132 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
133 133 no user, no domain
134 134
135 135 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
136 136 no person
137 137
138 138 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
139 139 other 1
140 140 other 2
141 141
142 142 other 3
143 143
144 144 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
145 145 line 1
146 146 line 2
147 147
148 148
149 149 $ hg log --debug --style compact
150 150 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
151 151 third
152 152
153 153 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
154 154 second
155 155
156 156 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
157 157 merge
158 158
159 159 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
160 160 new head
161 161
162 162 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
163 163 new branch
164 164
165 165 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
166 166 no user, no domain
167 167
168 168 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
169 169 no person
170 170
171 171 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
172 172 other 1
173 173 other 2
174 174
175 175 other 3
176 176
177 177 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
178 178 line 1
179 179 line 2
180 180
181 181
182 182 Test xml styles:
183 183
184 184 $ hg log --style xml
185 185 <?xml version="1.0"?>
186 186 <log>
187 187 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
188 188 <tag>tip</tag>
189 189 <author email="test">test</author>
190 190 <date>2020-01-01T10:01:00+00:00</date>
191 191 <msg xml:space="preserve">third</msg>
192 192 </logentry>
193 193 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
194 194 <parent revision="-1" node="0000000000000000000000000000000000000000" />
195 195 <author email="user@hostname">User Name</author>
196 196 <date>1970-01-12T13:46:40+00:00</date>
197 197 <msg xml:space="preserve">second</msg>
198 198 </logentry>
199 199 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
200 200 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
201 201 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
202 202 <author email="person">person</author>
203 203 <date>1970-01-18T08:40:01+00:00</date>
204 204 <msg xml:space="preserve">merge</msg>
205 205 </logentry>
206 206 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
207 207 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
208 208 <author email="person">person</author>
209 209 <date>1970-01-18T08:40:00+00:00</date>
210 210 <msg xml:space="preserve">new head</msg>
211 211 </logentry>
212 212 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
213 213 <branch>foo</branch>
214 214 <author email="person">person</author>
215 215 <date>1970-01-17T04:53:20+00:00</date>
216 216 <msg xml:space="preserve">new branch</msg>
217 217 </logentry>
218 218 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
219 219 <author email="person">person</author>
220 220 <date>1970-01-16T01:06:40+00:00</date>
221 221 <msg xml:space="preserve">no user, no domain</msg>
222 222 </logentry>
223 223 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
224 224 <author email="other@place">other</author>
225 225 <date>1970-01-14T21:20:00+00:00</date>
226 226 <msg xml:space="preserve">no person</msg>
227 227 </logentry>
228 228 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
229 229 <author email="other@place">A. N. Other</author>
230 230 <date>1970-01-13T17:33:20+00:00</date>
231 231 <msg xml:space="preserve">other 1
232 232 other 2
233 233
234 234 other 3</msg>
235 235 </logentry>
236 236 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
237 237 <author email="user@hostname">User Name</author>
238 238 <date>1970-01-12T13:46:40+00:00</date>
239 239 <msg xml:space="preserve">line 1
240 240 line 2</msg>
241 241 </logentry>
242 242 </log>
243 243
244 244 $ hg log -v --style xml
245 245 <?xml version="1.0"?>
246 246 <log>
247 247 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
248 248 <tag>tip</tag>
249 249 <author email="test">test</author>
250 250 <date>2020-01-01T10:01:00+00:00</date>
251 251 <msg xml:space="preserve">third</msg>
252 252 <paths>
253 253 <path action="A">fourth</path>
254 254 <path action="A">third</path>
255 255 <path action="R">second</path>
256 256 </paths>
257 257 <copies>
258 258 <copy source="second">fourth</copy>
259 259 </copies>
260 260 </logentry>
261 261 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
262 262 <parent revision="-1" node="0000000000000000000000000000000000000000" />
263 263 <author email="user@hostname">User Name</author>
264 264 <date>1970-01-12T13:46:40+00:00</date>
265 265 <msg xml:space="preserve">second</msg>
266 266 <paths>
267 267 <path action="A">second</path>
268 268 </paths>
269 269 </logentry>
270 270 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
271 271 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
272 272 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
273 273 <author email="person">person</author>
274 274 <date>1970-01-18T08:40:01+00:00</date>
275 275 <msg xml:space="preserve">merge</msg>
276 276 <paths>
277 277 </paths>
278 278 </logentry>
279 279 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
280 280 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
281 281 <author email="person">person</author>
282 282 <date>1970-01-18T08:40:00+00:00</date>
283 283 <msg xml:space="preserve">new head</msg>
284 284 <paths>
285 285 <path action="A">d</path>
286 286 </paths>
287 287 </logentry>
288 288 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
289 289 <branch>foo</branch>
290 290 <author email="person">person</author>
291 291 <date>1970-01-17T04:53:20+00:00</date>
292 292 <msg xml:space="preserve">new branch</msg>
293 293 <paths>
294 294 </paths>
295 295 </logentry>
296 296 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
297 297 <author email="person">person</author>
298 298 <date>1970-01-16T01:06:40+00:00</date>
299 299 <msg xml:space="preserve">no user, no domain</msg>
300 300 <paths>
301 301 <path action="M">c</path>
302 302 </paths>
303 303 </logentry>
304 304 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
305 305 <author email="other@place">other</author>
306 306 <date>1970-01-14T21:20:00+00:00</date>
307 307 <msg xml:space="preserve">no person</msg>
308 308 <paths>
309 309 <path action="A">c</path>
310 310 </paths>
311 311 </logentry>
312 312 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
313 313 <author email="other@place">A. N. Other</author>
314 314 <date>1970-01-13T17:33:20+00:00</date>
315 315 <msg xml:space="preserve">other 1
316 316 other 2
317 317
318 318 other 3</msg>
319 319 <paths>
320 320 <path action="A">b</path>
321 321 </paths>
322 322 </logentry>
323 323 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
324 324 <author email="user@hostname">User Name</author>
325 325 <date>1970-01-12T13:46:40+00:00</date>
326 326 <msg xml:space="preserve">line 1
327 327 line 2</msg>
328 328 <paths>
329 329 <path action="A">a</path>
330 330 </paths>
331 331 </logentry>
332 332 </log>
333 333
334 334 $ hg log --debug --style xml
335 335 <?xml version="1.0"?>
336 336 <log>
337 337 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
338 338 <tag>tip</tag>
339 339 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
340 340 <parent revision="-1" node="0000000000000000000000000000000000000000" />
341 341 <author email="test">test</author>
342 342 <date>2020-01-01T10:01:00+00:00</date>
343 343 <msg xml:space="preserve">third</msg>
344 344 <paths>
345 345 <path action="A">fourth</path>
346 346 <path action="A">third</path>
347 347 <path action="R">second</path>
348 348 </paths>
349 349 <copies>
350 350 <copy source="second">fourth</copy>
351 351 </copies>
352 352 <extra key="branch">default</extra>
353 353 </logentry>
354 354 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
355 355 <parent revision="-1" node="0000000000000000000000000000000000000000" />
356 356 <parent revision="-1" node="0000000000000000000000000000000000000000" />
357 357 <author email="user@hostname">User Name</author>
358 358 <date>1970-01-12T13:46:40+00:00</date>
359 359 <msg xml:space="preserve">second</msg>
360 360 <paths>
361 361 <path action="A">second</path>
362 362 </paths>
363 363 <extra key="branch">default</extra>
364 364 </logentry>
365 365 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
366 366 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
367 367 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
368 368 <author email="person">person</author>
369 369 <date>1970-01-18T08:40:01+00:00</date>
370 370 <msg xml:space="preserve">merge</msg>
371 371 <paths>
372 372 </paths>
373 373 <extra key="branch">default</extra>
374 374 </logentry>
375 375 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
376 376 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
377 377 <parent revision="-1" node="0000000000000000000000000000000000000000" />
378 378 <author email="person">person</author>
379 379 <date>1970-01-18T08:40:00+00:00</date>
380 380 <msg xml:space="preserve">new head</msg>
381 381 <paths>
382 382 <path action="A">d</path>
383 383 </paths>
384 384 <extra key="branch">default</extra>
385 385 </logentry>
386 386 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
387 387 <branch>foo</branch>
388 388 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
389 389 <parent revision="-1" node="0000000000000000000000000000000000000000" />
390 390 <author email="person">person</author>
391 391 <date>1970-01-17T04:53:20+00:00</date>
392 392 <msg xml:space="preserve">new branch</msg>
393 393 <paths>
394 394 </paths>
395 395 <extra key="branch">foo</extra>
396 396 </logentry>
397 397 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
398 398 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
399 399 <parent revision="-1" node="0000000000000000000000000000000000000000" />
400 400 <author email="person">person</author>
401 401 <date>1970-01-16T01:06:40+00:00</date>
402 402 <msg xml:space="preserve">no user, no domain</msg>
403 403 <paths>
404 404 <path action="M">c</path>
405 405 </paths>
406 406 <extra key="branch">default</extra>
407 407 </logentry>
408 408 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
409 409 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
410 410 <parent revision="-1" node="0000000000000000000000000000000000000000" />
411 411 <author email="other@place">other</author>
412 412 <date>1970-01-14T21:20:00+00:00</date>
413 413 <msg xml:space="preserve">no person</msg>
414 414 <paths>
415 415 <path action="A">c</path>
416 416 </paths>
417 417 <extra key="branch">default</extra>
418 418 </logentry>
419 419 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
420 420 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
421 421 <parent revision="-1" node="0000000000000000000000000000000000000000" />
422 422 <author email="other@place">A. N. Other</author>
423 423 <date>1970-01-13T17:33:20+00:00</date>
424 424 <msg xml:space="preserve">other 1
425 425 other 2
426 426
427 427 other 3</msg>
428 428 <paths>
429 429 <path action="A">b</path>
430 430 </paths>
431 431 <extra key="branch">default</extra>
432 432 </logentry>
433 433 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
434 434 <parent revision="-1" node="0000000000000000000000000000000000000000" />
435 435 <parent revision="-1" node="0000000000000000000000000000000000000000" />
436 436 <author email="user@hostname">User Name</author>
437 437 <date>1970-01-12T13:46:40+00:00</date>
438 438 <msg xml:space="preserve">line 1
439 439 line 2</msg>
440 440 <paths>
441 441 <path action="A">a</path>
442 442 </paths>
443 443 <extra key="branch">default</extra>
444 444 </logentry>
445 445 </log>
446 446
447 447
448 448 Error if style not readable:
449 449
450 450 #if unix-permissions
451 451 $ touch q
452 452 $ chmod 0 q
453 453 $ hg log --style ./q
454 454 abort: Permission denied: ./q
455 455 [255]
456 456 #endif
457 457
458 458 Error if no style:
459 459
460 460 $ hg log --style notexist
461 461 abort: style 'notexist' not found
462 462 (available styles: bisect, changelog, compact, default, phases, xml)
463 463 [255]
464 464
465 465 Error if style missing key:
466 466
467 467 $ echo 'q = q' > t
468 468 $ hg log --style ./t
469 469 abort: "changeset" not in template map
470 470 [255]
471 471
472 472 Error if style missing value:
473 473
474 474 $ echo 'changeset =' > t
475 475 $ hg log --style t
476 476 abort: t:1: missing value
477 477 [255]
478 478
479 479 Error if include fails:
480 480
481 481 $ echo 'changeset = q' >> t
482 482 #if unix-permissions
483 483 $ hg log --style ./t
484 484 abort: template file ./q: Permission denied
485 485 [255]
486 486 $ rm q
487 487 #endif
488 488
489 489 Include works:
490 490
491 491 $ echo '{rev}' > q
492 492 $ hg log --style ./t
493 493 8
494 494 7
495 495 6
496 496 5
497 497 4
498 498 3
499 499 2
500 500 1
501 501 0
502 502
503 Missing non-standard names give no error (backward compatibility):
504
505 $ echo "changeset = '{c}'" > t
506 $ hg log --style ./t
507
508 Defining non-standard name works:
509
510 $ cat <<EOF > t
511 > changeset = '{c}'
512 > c = q
513 > EOF
514 $ hg log --style ./t
515 8
516 7
517 6
518 5
519 4
520 3
521 2
522 1
523 0
524
503 525 ui.style works:
504 526
505 527 $ echo '[ui]' > .hg/hgrc
506 528 $ echo 'style = t' >> .hg/hgrc
507 529 $ hg log
508 530 8
509 531 7
510 532 6
511 533 5
512 534 4
513 535 3
514 536 2
515 537 1
516 538 0
517 539
518 540
519 541 Issue338:
520 542
521 543 $ hg log --style=changelog > changelog
522 544
523 545 $ cat changelog
524 546 2020-01-01 test <test>
525 547
526 548 * fourth, second, third:
527 549 third
528 550 [95c24699272e] [tip]
529 551
530 552 1970-01-12 User Name <user@hostname>
531 553
532 554 * second:
533 555 second
534 556 [29114dbae42b]
535 557
536 558 1970-01-18 person <person>
537 559
538 560 * merge
539 561 [d41e714fe50d]
540 562
541 563 * d:
542 564 new head
543 565 [13207e5a10d9]
544 566
545 567 1970-01-17 person <person>
546 568
547 569 * new branch
548 570 [bbe44766e73d] <foo>
549 571
550 572 1970-01-16 person <person>
551 573
552 574 * c:
553 575 no user, no domain
554 576 [10e46f2dcbf4]
555 577
556 578 1970-01-14 other <other@place>
557 579
558 580 * c:
559 581 no person
560 582 [97054abb4ab8]
561 583
562 584 1970-01-13 A. N. Other <other@place>
563 585
564 586 * b:
565 587 other 1 other 2
566 588
567 589 other 3
568 590 [b608e9d1a3f0]
569 591
570 592 1970-01-12 User Name <user@hostname>
571 593
572 594 * a:
573 595 line 1 line 2
574 596 [1e4e1b8f71e0]
575 597
576 598
577 599 Issue2130: xml output for 'hg heads' is malformed
578 600
579 601 $ hg heads --style changelog
580 602 2020-01-01 test <test>
581 603
582 604 * fourth, second, third:
583 605 third
584 606 [95c24699272e] [tip]
585 607
586 608 1970-01-18 person <person>
587 609
588 610 * merge
589 611 [d41e714fe50d]
590 612
591 613 1970-01-17 person <person>
592 614
593 615 * new branch
594 616 [bbe44766e73d] <foo>
595 617
596 618
597 619 Keys work:
598 620
599 621 $ for key in author branch branches date desc file_adds file_dels file_mods \
600 622 > file_copies file_copies_switch files \
601 623 > manifest node parents rev tags diffstat extras \
602 624 > p1rev p2rev p1node p2node; do
603 625 > for mode in '' --verbose --debug; do
604 626 > hg log $mode --template "$key$mode: {$key}\n"
605 627 > done
606 628 > done
607 629 author: test
608 630 author: User Name <user@hostname>
609 631 author: person
610 632 author: person
611 633 author: person
612 634 author: person
613 635 author: other@place
614 636 author: A. N. Other <other@place>
615 637 author: User Name <user@hostname>
616 638 author--verbose: test
617 639 author--verbose: User Name <user@hostname>
618 640 author--verbose: person
619 641 author--verbose: person
620 642 author--verbose: person
621 643 author--verbose: person
622 644 author--verbose: other@place
623 645 author--verbose: A. N. Other <other@place>
624 646 author--verbose: User Name <user@hostname>
625 647 author--debug: test
626 648 author--debug: User Name <user@hostname>
627 649 author--debug: person
628 650 author--debug: person
629 651 author--debug: person
630 652 author--debug: person
631 653 author--debug: other@place
632 654 author--debug: A. N. Other <other@place>
633 655 author--debug: User Name <user@hostname>
634 656 branch: default
635 657 branch: default
636 658 branch: default
637 659 branch: default
638 660 branch: foo
639 661 branch: default
640 662 branch: default
641 663 branch: default
642 664 branch: default
643 665 branch--verbose: default
644 666 branch--verbose: default
645 667 branch--verbose: default
646 668 branch--verbose: default
647 669 branch--verbose: foo
648 670 branch--verbose: default
649 671 branch--verbose: default
650 672 branch--verbose: default
651 673 branch--verbose: default
652 674 branch--debug: default
653 675 branch--debug: default
654 676 branch--debug: default
655 677 branch--debug: default
656 678 branch--debug: foo
657 679 branch--debug: default
658 680 branch--debug: default
659 681 branch--debug: default
660 682 branch--debug: default
661 683 branches:
662 684 branches:
663 685 branches:
664 686 branches:
665 687 branches: foo
666 688 branches:
667 689 branches:
668 690 branches:
669 691 branches:
670 692 branches--verbose:
671 693 branches--verbose:
672 694 branches--verbose:
673 695 branches--verbose:
674 696 branches--verbose: foo
675 697 branches--verbose:
676 698 branches--verbose:
677 699 branches--verbose:
678 700 branches--verbose:
679 701 branches--debug:
680 702 branches--debug:
681 703 branches--debug:
682 704 branches--debug:
683 705 branches--debug: foo
684 706 branches--debug:
685 707 branches--debug:
686 708 branches--debug:
687 709 branches--debug:
688 710 date: 1577872860.00
689 711 date: 1000000.00
690 712 date: 1500001.00
691 713 date: 1500000.00
692 714 date: 1400000.00
693 715 date: 1300000.00
694 716 date: 1200000.00
695 717 date: 1100000.00
696 718 date: 1000000.00
697 719 date--verbose: 1577872860.00
698 720 date--verbose: 1000000.00
699 721 date--verbose: 1500001.00
700 722 date--verbose: 1500000.00
701 723 date--verbose: 1400000.00
702 724 date--verbose: 1300000.00
703 725 date--verbose: 1200000.00
704 726 date--verbose: 1100000.00
705 727 date--verbose: 1000000.00
706 728 date--debug: 1577872860.00
707 729 date--debug: 1000000.00
708 730 date--debug: 1500001.00
709 731 date--debug: 1500000.00
710 732 date--debug: 1400000.00
711 733 date--debug: 1300000.00
712 734 date--debug: 1200000.00
713 735 date--debug: 1100000.00
714 736 date--debug: 1000000.00
715 737 desc: third
716 738 desc: second
717 739 desc: merge
718 740 desc: new head
719 741 desc: new branch
720 742 desc: no user, no domain
721 743 desc: no person
722 744 desc: other 1
723 745 other 2
724 746
725 747 other 3
726 748 desc: line 1
727 749 line 2
728 750 desc--verbose: third
729 751 desc--verbose: second
730 752 desc--verbose: merge
731 753 desc--verbose: new head
732 754 desc--verbose: new branch
733 755 desc--verbose: no user, no domain
734 756 desc--verbose: no person
735 757 desc--verbose: other 1
736 758 other 2
737 759
738 760 other 3
739 761 desc--verbose: line 1
740 762 line 2
741 763 desc--debug: third
742 764 desc--debug: second
743 765 desc--debug: merge
744 766 desc--debug: new head
745 767 desc--debug: new branch
746 768 desc--debug: no user, no domain
747 769 desc--debug: no person
748 770 desc--debug: other 1
749 771 other 2
750 772
751 773 other 3
752 774 desc--debug: line 1
753 775 line 2
754 776 file_adds: fourth third
755 777 file_adds: second
756 778 file_adds:
757 779 file_adds: d
758 780 file_adds:
759 781 file_adds:
760 782 file_adds: c
761 783 file_adds: b
762 784 file_adds: a
763 785 file_adds--verbose: fourth third
764 786 file_adds--verbose: second
765 787 file_adds--verbose:
766 788 file_adds--verbose: d
767 789 file_adds--verbose:
768 790 file_adds--verbose:
769 791 file_adds--verbose: c
770 792 file_adds--verbose: b
771 793 file_adds--verbose: a
772 794 file_adds--debug: fourth third
773 795 file_adds--debug: second
774 796 file_adds--debug:
775 797 file_adds--debug: d
776 798 file_adds--debug:
777 799 file_adds--debug:
778 800 file_adds--debug: c
779 801 file_adds--debug: b
780 802 file_adds--debug: a
781 803 file_dels: second
782 804 file_dels:
783 805 file_dels:
784 806 file_dels:
785 807 file_dels:
786 808 file_dels:
787 809 file_dels:
788 810 file_dels:
789 811 file_dels:
790 812 file_dels--verbose: second
791 813 file_dels--verbose:
792 814 file_dels--verbose:
793 815 file_dels--verbose:
794 816 file_dels--verbose:
795 817 file_dels--verbose:
796 818 file_dels--verbose:
797 819 file_dels--verbose:
798 820 file_dels--verbose:
799 821 file_dels--debug: second
800 822 file_dels--debug:
801 823 file_dels--debug:
802 824 file_dels--debug:
803 825 file_dels--debug:
804 826 file_dels--debug:
805 827 file_dels--debug:
806 828 file_dels--debug:
807 829 file_dels--debug:
808 830 file_mods:
809 831 file_mods:
810 832 file_mods:
811 833 file_mods:
812 834 file_mods:
813 835 file_mods: c
814 836 file_mods:
815 837 file_mods:
816 838 file_mods:
817 839 file_mods--verbose:
818 840 file_mods--verbose:
819 841 file_mods--verbose:
820 842 file_mods--verbose:
821 843 file_mods--verbose:
822 844 file_mods--verbose: c
823 845 file_mods--verbose:
824 846 file_mods--verbose:
825 847 file_mods--verbose:
826 848 file_mods--debug:
827 849 file_mods--debug:
828 850 file_mods--debug:
829 851 file_mods--debug:
830 852 file_mods--debug:
831 853 file_mods--debug: c
832 854 file_mods--debug:
833 855 file_mods--debug:
834 856 file_mods--debug:
835 857 file_copies: fourth (second)
836 858 file_copies:
837 859 file_copies:
838 860 file_copies:
839 861 file_copies:
840 862 file_copies:
841 863 file_copies:
842 864 file_copies:
843 865 file_copies:
844 866 file_copies--verbose: fourth (second)
845 867 file_copies--verbose:
846 868 file_copies--verbose:
847 869 file_copies--verbose:
848 870 file_copies--verbose:
849 871 file_copies--verbose:
850 872 file_copies--verbose:
851 873 file_copies--verbose:
852 874 file_copies--verbose:
853 875 file_copies--debug: fourth (second)
854 876 file_copies--debug:
855 877 file_copies--debug:
856 878 file_copies--debug:
857 879 file_copies--debug:
858 880 file_copies--debug:
859 881 file_copies--debug:
860 882 file_copies--debug:
861 883 file_copies--debug:
862 884 file_copies_switch:
863 885 file_copies_switch:
864 886 file_copies_switch:
865 887 file_copies_switch:
866 888 file_copies_switch:
867 889 file_copies_switch:
868 890 file_copies_switch:
869 891 file_copies_switch:
870 892 file_copies_switch:
871 893 file_copies_switch--verbose:
872 894 file_copies_switch--verbose:
873 895 file_copies_switch--verbose:
874 896 file_copies_switch--verbose:
875 897 file_copies_switch--verbose:
876 898 file_copies_switch--verbose:
877 899 file_copies_switch--verbose:
878 900 file_copies_switch--verbose:
879 901 file_copies_switch--verbose:
880 902 file_copies_switch--debug:
881 903 file_copies_switch--debug:
882 904 file_copies_switch--debug:
883 905 file_copies_switch--debug:
884 906 file_copies_switch--debug:
885 907 file_copies_switch--debug:
886 908 file_copies_switch--debug:
887 909 file_copies_switch--debug:
888 910 file_copies_switch--debug:
889 911 files: fourth second third
890 912 files: second
891 913 files:
892 914 files: d
893 915 files:
894 916 files: c
895 917 files: c
896 918 files: b
897 919 files: a
898 920 files--verbose: fourth second third
899 921 files--verbose: second
900 922 files--verbose:
901 923 files--verbose: d
902 924 files--verbose:
903 925 files--verbose: c
904 926 files--verbose: c
905 927 files--verbose: b
906 928 files--verbose: a
907 929 files--debug: fourth second third
908 930 files--debug: second
909 931 files--debug:
910 932 files--debug: d
911 933 files--debug:
912 934 files--debug: c
913 935 files--debug: c
914 936 files--debug: b
915 937 files--debug: a
916 938 manifest: 6:94961b75a2da
917 939 manifest: 5:f2dbc354b94e
918 940 manifest: 4:4dc3def4f9b4
919 941 manifest: 4:4dc3def4f9b4
920 942 manifest: 3:cb5a1327723b
921 943 manifest: 3:cb5a1327723b
922 944 manifest: 2:6e0e82995c35
923 945 manifest: 1:4e8d705b1e53
924 946 manifest: 0:a0c8bcbbb45c
925 947 manifest--verbose: 6:94961b75a2da
926 948 manifest--verbose: 5:f2dbc354b94e
927 949 manifest--verbose: 4:4dc3def4f9b4
928 950 manifest--verbose: 4:4dc3def4f9b4
929 951 manifest--verbose: 3:cb5a1327723b
930 952 manifest--verbose: 3:cb5a1327723b
931 953 manifest--verbose: 2:6e0e82995c35
932 954 manifest--verbose: 1:4e8d705b1e53
933 955 manifest--verbose: 0:a0c8bcbbb45c
934 956 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
935 957 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
936 958 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
937 959 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
938 960 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
939 961 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
940 962 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
941 963 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
942 964 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
943 965 node: 95c24699272ef57d062b8bccc32c878bf841784a
944 966 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
945 967 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
946 968 node: 13207e5a10d9fd28ec424934298e176197f2c67f
947 969 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
948 970 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
949 971 node: 97054abb4ab824450e9164180baf491ae0078465
950 972 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
951 973 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
952 974 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
953 975 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
954 976 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
955 977 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
956 978 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
957 979 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
958 980 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
959 981 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
960 982 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
961 983 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
962 984 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
963 985 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
964 986 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
965 987 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
966 988 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
967 989 node--debug: 97054abb4ab824450e9164180baf491ae0078465
968 990 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
969 991 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
970 992 parents:
971 993 parents: -1:000000000000
972 994 parents: 5:13207e5a10d9 4:bbe44766e73d
973 995 parents: 3:10e46f2dcbf4
974 996 parents:
975 997 parents:
976 998 parents:
977 999 parents:
978 1000 parents:
979 1001 parents--verbose:
980 1002 parents--verbose: -1:000000000000
981 1003 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
982 1004 parents--verbose: 3:10e46f2dcbf4
983 1005 parents--verbose:
984 1006 parents--verbose:
985 1007 parents--verbose:
986 1008 parents--verbose:
987 1009 parents--verbose:
988 1010 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
989 1011 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
990 1012 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
991 1013 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
992 1014 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
993 1015 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
994 1016 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
995 1017 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
996 1018 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
997 1019 rev: 8
998 1020 rev: 7
999 1021 rev: 6
1000 1022 rev: 5
1001 1023 rev: 4
1002 1024 rev: 3
1003 1025 rev: 2
1004 1026 rev: 1
1005 1027 rev: 0
1006 1028 rev--verbose: 8
1007 1029 rev--verbose: 7
1008 1030 rev--verbose: 6
1009 1031 rev--verbose: 5
1010 1032 rev--verbose: 4
1011 1033 rev--verbose: 3
1012 1034 rev--verbose: 2
1013 1035 rev--verbose: 1
1014 1036 rev--verbose: 0
1015 1037 rev--debug: 8
1016 1038 rev--debug: 7
1017 1039 rev--debug: 6
1018 1040 rev--debug: 5
1019 1041 rev--debug: 4
1020 1042 rev--debug: 3
1021 1043 rev--debug: 2
1022 1044 rev--debug: 1
1023 1045 rev--debug: 0
1024 1046 tags: tip
1025 1047 tags:
1026 1048 tags:
1027 1049 tags:
1028 1050 tags:
1029 1051 tags:
1030 1052 tags:
1031 1053 tags:
1032 1054 tags:
1033 1055 tags--verbose: tip
1034 1056 tags--verbose:
1035 1057 tags--verbose:
1036 1058 tags--verbose:
1037 1059 tags--verbose:
1038 1060 tags--verbose:
1039 1061 tags--verbose:
1040 1062 tags--verbose:
1041 1063 tags--verbose:
1042 1064 tags--debug: tip
1043 1065 tags--debug:
1044 1066 tags--debug:
1045 1067 tags--debug:
1046 1068 tags--debug:
1047 1069 tags--debug:
1048 1070 tags--debug:
1049 1071 tags--debug:
1050 1072 tags--debug:
1051 1073 diffstat: 3: +2/-1
1052 1074 diffstat: 1: +1/-0
1053 1075 diffstat: 0: +0/-0
1054 1076 diffstat: 1: +1/-0
1055 1077 diffstat: 0: +0/-0
1056 1078 diffstat: 1: +1/-0
1057 1079 diffstat: 1: +4/-0
1058 1080 diffstat: 1: +2/-0
1059 1081 diffstat: 1: +1/-0
1060 1082 diffstat--verbose: 3: +2/-1
1061 1083 diffstat--verbose: 1: +1/-0
1062 1084 diffstat--verbose: 0: +0/-0
1063 1085 diffstat--verbose: 1: +1/-0
1064 1086 diffstat--verbose: 0: +0/-0
1065 1087 diffstat--verbose: 1: +1/-0
1066 1088 diffstat--verbose: 1: +4/-0
1067 1089 diffstat--verbose: 1: +2/-0
1068 1090 diffstat--verbose: 1: +1/-0
1069 1091 diffstat--debug: 3: +2/-1
1070 1092 diffstat--debug: 1: +1/-0
1071 1093 diffstat--debug: 0: +0/-0
1072 1094 diffstat--debug: 1: +1/-0
1073 1095 diffstat--debug: 0: +0/-0
1074 1096 diffstat--debug: 1: +1/-0
1075 1097 diffstat--debug: 1: +4/-0
1076 1098 diffstat--debug: 1: +2/-0
1077 1099 diffstat--debug: 1: +1/-0
1078 1100 extras: branch=default
1079 1101 extras: branch=default
1080 1102 extras: branch=default
1081 1103 extras: branch=default
1082 1104 extras: branch=foo
1083 1105 extras: branch=default
1084 1106 extras: branch=default
1085 1107 extras: branch=default
1086 1108 extras: branch=default
1087 1109 extras--verbose: branch=default
1088 1110 extras--verbose: branch=default
1089 1111 extras--verbose: branch=default
1090 1112 extras--verbose: branch=default
1091 1113 extras--verbose: branch=foo
1092 1114 extras--verbose: branch=default
1093 1115 extras--verbose: branch=default
1094 1116 extras--verbose: branch=default
1095 1117 extras--verbose: branch=default
1096 1118 extras--debug: branch=default
1097 1119 extras--debug: branch=default
1098 1120 extras--debug: branch=default
1099 1121 extras--debug: branch=default
1100 1122 extras--debug: branch=foo
1101 1123 extras--debug: branch=default
1102 1124 extras--debug: branch=default
1103 1125 extras--debug: branch=default
1104 1126 extras--debug: branch=default
1105 1127 p1rev: 7
1106 1128 p1rev: -1
1107 1129 p1rev: 5
1108 1130 p1rev: 3
1109 1131 p1rev: 3
1110 1132 p1rev: 2
1111 1133 p1rev: 1
1112 1134 p1rev: 0
1113 1135 p1rev: -1
1114 1136 p1rev--verbose: 7
1115 1137 p1rev--verbose: -1
1116 1138 p1rev--verbose: 5
1117 1139 p1rev--verbose: 3
1118 1140 p1rev--verbose: 3
1119 1141 p1rev--verbose: 2
1120 1142 p1rev--verbose: 1
1121 1143 p1rev--verbose: 0
1122 1144 p1rev--verbose: -1
1123 1145 p1rev--debug: 7
1124 1146 p1rev--debug: -1
1125 1147 p1rev--debug: 5
1126 1148 p1rev--debug: 3
1127 1149 p1rev--debug: 3
1128 1150 p1rev--debug: 2
1129 1151 p1rev--debug: 1
1130 1152 p1rev--debug: 0
1131 1153 p1rev--debug: -1
1132 1154 p2rev: -1
1133 1155 p2rev: -1
1134 1156 p2rev: 4
1135 1157 p2rev: -1
1136 1158 p2rev: -1
1137 1159 p2rev: -1
1138 1160 p2rev: -1
1139 1161 p2rev: -1
1140 1162 p2rev: -1
1141 1163 p2rev--verbose: -1
1142 1164 p2rev--verbose: -1
1143 1165 p2rev--verbose: 4
1144 1166 p2rev--verbose: -1
1145 1167 p2rev--verbose: -1
1146 1168 p2rev--verbose: -1
1147 1169 p2rev--verbose: -1
1148 1170 p2rev--verbose: -1
1149 1171 p2rev--verbose: -1
1150 1172 p2rev--debug: -1
1151 1173 p2rev--debug: -1
1152 1174 p2rev--debug: 4
1153 1175 p2rev--debug: -1
1154 1176 p2rev--debug: -1
1155 1177 p2rev--debug: -1
1156 1178 p2rev--debug: -1
1157 1179 p2rev--debug: -1
1158 1180 p2rev--debug: -1
1159 1181 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1160 1182 p1node: 0000000000000000000000000000000000000000
1161 1183 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1162 1184 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1163 1185 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1164 1186 p1node: 97054abb4ab824450e9164180baf491ae0078465
1165 1187 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1166 1188 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1167 1189 p1node: 0000000000000000000000000000000000000000
1168 1190 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1169 1191 p1node--verbose: 0000000000000000000000000000000000000000
1170 1192 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1171 1193 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1172 1194 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1173 1195 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1174 1196 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1175 1197 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1176 1198 p1node--verbose: 0000000000000000000000000000000000000000
1177 1199 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1178 1200 p1node--debug: 0000000000000000000000000000000000000000
1179 1201 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1180 1202 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1181 1203 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1182 1204 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1183 1205 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1184 1206 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1185 1207 p1node--debug: 0000000000000000000000000000000000000000
1186 1208 p2node: 0000000000000000000000000000000000000000
1187 1209 p2node: 0000000000000000000000000000000000000000
1188 1210 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1189 1211 p2node: 0000000000000000000000000000000000000000
1190 1212 p2node: 0000000000000000000000000000000000000000
1191 1213 p2node: 0000000000000000000000000000000000000000
1192 1214 p2node: 0000000000000000000000000000000000000000
1193 1215 p2node: 0000000000000000000000000000000000000000
1194 1216 p2node: 0000000000000000000000000000000000000000
1195 1217 p2node--verbose: 0000000000000000000000000000000000000000
1196 1218 p2node--verbose: 0000000000000000000000000000000000000000
1197 1219 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1198 1220 p2node--verbose: 0000000000000000000000000000000000000000
1199 1221 p2node--verbose: 0000000000000000000000000000000000000000
1200 1222 p2node--verbose: 0000000000000000000000000000000000000000
1201 1223 p2node--verbose: 0000000000000000000000000000000000000000
1202 1224 p2node--verbose: 0000000000000000000000000000000000000000
1203 1225 p2node--verbose: 0000000000000000000000000000000000000000
1204 1226 p2node--debug: 0000000000000000000000000000000000000000
1205 1227 p2node--debug: 0000000000000000000000000000000000000000
1206 1228 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1207 1229 p2node--debug: 0000000000000000000000000000000000000000
1208 1230 p2node--debug: 0000000000000000000000000000000000000000
1209 1231 p2node--debug: 0000000000000000000000000000000000000000
1210 1232 p2node--debug: 0000000000000000000000000000000000000000
1211 1233 p2node--debug: 0000000000000000000000000000000000000000
1212 1234 p2node--debug: 0000000000000000000000000000000000000000
1213 1235
1214 1236 Filters work:
1215 1237
1216 1238 $ hg log --template '{author|domain}\n'
1217 1239
1218 1240 hostname
1219 1241
1220 1242
1221 1243
1222 1244
1223 1245 place
1224 1246 place
1225 1247 hostname
1226 1248
1227 1249 $ hg log --template '{author|person}\n'
1228 1250 test
1229 1251 User Name
1230 1252 person
1231 1253 person
1232 1254 person
1233 1255 person
1234 1256 other
1235 1257 A. N. Other
1236 1258 User Name
1237 1259
1238 1260 $ hg log --template '{author|user}\n'
1239 1261 test
1240 1262 user
1241 1263 person
1242 1264 person
1243 1265 person
1244 1266 person
1245 1267 other
1246 1268 other
1247 1269 user
1248 1270
1249 1271 $ hg log --template '{date|date}\n'
1250 1272 Wed Jan 01 10:01:00 2020 +0000
1251 1273 Mon Jan 12 13:46:40 1970 +0000
1252 1274 Sun Jan 18 08:40:01 1970 +0000
1253 1275 Sun Jan 18 08:40:00 1970 +0000
1254 1276 Sat Jan 17 04:53:20 1970 +0000
1255 1277 Fri Jan 16 01:06:40 1970 +0000
1256 1278 Wed Jan 14 21:20:00 1970 +0000
1257 1279 Tue Jan 13 17:33:20 1970 +0000
1258 1280 Mon Jan 12 13:46:40 1970 +0000
1259 1281
1260 1282 $ hg log --template '{date|isodate}\n'
1261 1283 2020-01-01 10:01 +0000
1262 1284 1970-01-12 13:46 +0000
1263 1285 1970-01-18 08:40 +0000
1264 1286 1970-01-18 08:40 +0000
1265 1287 1970-01-17 04:53 +0000
1266 1288 1970-01-16 01:06 +0000
1267 1289 1970-01-14 21:20 +0000
1268 1290 1970-01-13 17:33 +0000
1269 1291 1970-01-12 13:46 +0000
1270 1292
1271 1293 $ hg log --template '{date|isodatesec}\n'
1272 1294 2020-01-01 10:01:00 +0000
1273 1295 1970-01-12 13:46:40 +0000
1274 1296 1970-01-18 08:40:01 +0000
1275 1297 1970-01-18 08:40:00 +0000
1276 1298 1970-01-17 04:53:20 +0000
1277 1299 1970-01-16 01:06:40 +0000
1278 1300 1970-01-14 21:20:00 +0000
1279 1301 1970-01-13 17:33:20 +0000
1280 1302 1970-01-12 13:46:40 +0000
1281 1303
1282 1304 $ hg log --template '{date|rfc822date}\n'
1283 1305 Wed, 01 Jan 2020 10:01:00 +0000
1284 1306 Mon, 12 Jan 1970 13:46:40 +0000
1285 1307 Sun, 18 Jan 1970 08:40:01 +0000
1286 1308 Sun, 18 Jan 1970 08:40:00 +0000
1287 1309 Sat, 17 Jan 1970 04:53:20 +0000
1288 1310 Fri, 16 Jan 1970 01:06:40 +0000
1289 1311 Wed, 14 Jan 1970 21:20:00 +0000
1290 1312 Tue, 13 Jan 1970 17:33:20 +0000
1291 1313 Mon, 12 Jan 1970 13:46:40 +0000
1292 1314
1293 1315 $ hg log --template '{desc|firstline}\n'
1294 1316 third
1295 1317 second
1296 1318 merge
1297 1319 new head
1298 1320 new branch
1299 1321 no user, no domain
1300 1322 no person
1301 1323 other 1
1302 1324 line 1
1303 1325
1304 1326 $ hg log --template '{node|short}\n'
1305 1327 95c24699272e
1306 1328 29114dbae42b
1307 1329 d41e714fe50d
1308 1330 13207e5a10d9
1309 1331 bbe44766e73d
1310 1332 10e46f2dcbf4
1311 1333 97054abb4ab8
1312 1334 b608e9d1a3f0
1313 1335 1e4e1b8f71e0
1314 1336
1315 1337 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1316 1338 <changeset author="test"/>
1317 1339 <changeset author="User Name &lt;user@hostname&gt;"/>
1318 1340 <changeset author="person"/>
1319 1341 <changeset author="person"/>
1320 1342 <changeset author="person"/>
1321 1343 <changeset author="person"/>
1322 1344 <changeset author="other@place"/>
1323 1345 <changeset author="A. N. Other &lt;other@place&gt;"/>
1324 1346 <changeset author="User Name &lt;user@hostname&gt;"/>
1325 1347
1326 1348 $ hg log --template '{rev}: {children}\n'
1327 1349 8:
1328 1350 7: 8:95c24699272e
1329 1351 6:
1330 1352 5: 6:d41e714fe50d
1331 1353 4: 6:d41e714fe50d
1332 1354 3: 4:bbe44766e73d 5:13207e5a10d9
1333 1355 2: 3:10e46f2dcbf4
1334 1356 1: 2:97054abb4ab8
1335 1357 0: 1:b608e9d1a3f0
1336 1358
1337 1359 Formatnode filter works:
1338 1360
1339 1361 $ hg -q log -r 0 --template '{node|formatnode}\n'
1340 1362 1e4e1b8f71e0
1341 1363
1342 1364 $ hg log -r 0 --template '{node|formatnode}\n'
1343 1365 1e4e1b8f71e0
1344 1366
1345 1367 $ hg -v log -r 0 --template '{node|formatnode}\n'
1346 1368 1e4e1b8f71e0
1347 1369
1348 1370 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1349 1371 1e4e1b8f71e05681d422154f5421e385fec3454f
1350 1372
1351 1373 Age filter:
1352 1374
1353 1375 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1354 1376
1355 1377 >>> from datetime import datetime, timedelta
1356 1378 >>> fp = open('a', 'w')
1357 1379 >>> n = datetime.now() + timedelta(366 * 7)
1358 1380 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1359 1381 >>> fp.close()
1360 1382 $ hg add a
1361 1383 $ hg commit -m future -d "`cat a`"
1362 1384
1363 1385 $ hg log -l1 --template '{date|age}\n'
1364 1386 7 years from now
1365 1387
1366 1388 Error on syntax:
1367 1389
1368 1390 $ echo 'x = "f' >> t
1369 1391 $ hg log
1370 1392 abort: t:3: unmatched quotes
1371 1393 [255]
1372 1394
1373 1395 Behind the scenes, this will throw TypeError
1374 1396
1375 1397 $ hg log -l 3 --template '{date|obfuscate}\n'
1376 1398 abort: template filter 'obfuscate' is not compatible with keyword 'date'
1377 1399 [255]
1378 1400
1379 1401 Behind the scenes, this will throw a ValueError
1380 1402
1381 1403 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
1382 1404 abort: template filter 'shortdate' is not compatible with keyword 'desc'
1383 1405 [255]
1384 1406
1385 1407 Behind the scenes, this will throw AttributeError
1386 1408
1387 1409 $ hg log -l 3 --template 'line: {date|escape}\n'
1388 1410 abort: template filter 'escape' is not compatible with keyword 'date'
1389 1411 [255]
1390 1412
1391 1413 Behind the scenes, this will throw ValueError
1392 1414
1393 1415 $ hg tip --template '{author|email|date}\n'
1394 1416 abort: template filter 'datefilter' is not compatible with keyword 'author'
1395 1417 [255]
1396 1418
1397 1419 $ cd ..
1398 1420
1399 1421
1400 1422 latesttag:
1401 1423
1402 1424 $ hg init latesttag
1403 1425 $ cd latesttag
1404 1426
1405 1427 $ echo a > file
1406 1428 $ hg ci -Am a -d '0 0'
1407 1429 adding file
1408 1430
1409 1431 $ echo b >> file
1410 1432 $ hg ci -m b -d '1 0'
1411 1433
1412 1434 $ echo c >> head1
1413 1435 $ hg ci -Am h1c -d '2 0'
1414 1436 adding head1
1415 1437
1416 1438 $ hg update -q 1
1417 1439 $ echo d >> head2
1418 1440 $ hg ci -Am h2d -d '3 0'
1419 1441 adding head2
1420 1442 created new head
1421 1443
1422 1444 $ echo e >> head2
1423 1445 $ hg ci -m h2e -d '4 0'
1424 1446
1425 1447 $ hg merge -q
1426 1448 $ hg ci -m merge -d '5 0'
1427 1449
1428 1450 No tag set:
1429 1451
1430 1452 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1431 1453 5: null+5
1432 1454 4: null+4
1433 1455 3: null+3
1434 1456 2: null+3
1435 1457 1: null+2
1436 1458 0: null+1
1437 1459
1438 1460 One common tag: longuest path wins:
1439 1461
1440 1462 $ hg tag -r 1 -m t1 -d '6 0' t1
1441 1463 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1442 1464 6: t1+4
1443 1465 5: t1+3
1444 1466 4: t1+2
1445 1467 3: t1+1
1446 1468 2: t1+1
1447 1469 1: t1+0
1448 1470 0: null+1
1449 1471
1450 1472 One ancestor tag: more recent wins:
1451 1473
1452 1474 $ hg tag -r 2 -m t2 -d '7 0' t2
1453 1475 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1454 1476 7: t2+3
1455 1477 6: t2+2
1456 1478 5: t2+1
1457 1479 4: t1+2
1458 1480 3: t1+1
1459 1481 2: t2+0
1460 1482 1: t1+0
1461 1483 0: null+1
1462 1484
1463 1485 Two branch tags: more recent wins:
1464 1486
1465 1487 $ hg tag -r 3 -m t3 -d '8 0' t3
1466 1488 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1467 1489 8: t3+5
1468 1490 7: t3+4
1469 1491 6: t3+3
1470 1492 5: t3+2
1471 1493 4: t3+1
1472 1494 3: t3+0
1473 1495 2: t2+0
1474 1496 1: t1+0
1475 1497 0: null+1
1476 1498
1477 1499 Merged tag overrides:
1478 1500
1479 1501 $ hg tag -r 5 -m t5 -d '9 0' t5
1480 1502 $ hg tag -r 3 -m at3 -d '10 0' at3
1481 1503 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1482 1504 10: t5+5
1483 1505 9: t5+4
1484 1506 8: t5+3
1485 1507 7: t5+2
1486 1508 6: t5+1
1487 1509 5: t5+0
1488 1510 4: at3:t3+1
1489 1511 3: at3:t3+0
1490 1512 2: t2+0
1491 1513 1: t1+0
1492 1514 0: null+1
1493 1515
1494 1516 $ cd ..
1495 1517
1496 1518
1497 1519 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1498 1520 if it is a relative path
1499 1521
1500 1522 $ mkdir -p home/styles
1501 1523
1502 1524 $ cat > home/styles/teststyle <<EOF
1503 1525 > changeset = 'test {rev}:{node|short}\n'
1504 1526 > EOF
1505 1527
1506 1528 $ HOME=`pwd`/home; export HOME
1507 1529
1508 1530 $ cat > latesttag/.hg/hgrc <<EOF
1509 1531 > [ui]
1510 1532 > style = ~/styles/teststyle
1511 1533 > EOF
1512 1534
1513 1535 $ hg -R latesttag tip
1514 1536 test 10:dee8f28249af
1515 1537
1516 1538 Test recursive showlist template (issue1989):
1517 1539
1518 1540 $ cat > style1989 <<EOF
1519 1541 > changeset = '{file_mods}{manifest}{extras}'
1520 1542 > file_mod = 'M|{author|person}\n'
1521 1543 > manifest = '{rev},{author}\n'
1522 1544 > extra = '{key}: {author}\n'
1523 1545 > EOF
1524 1546
1525 1547 $ hg -R latesttag log -r tip --style=style1989
1526 1548 M|test
1527 1549 10,test
1528 1550 branch: test
1529 1551
1530 1552 Test new-style inline templating:
1531 1553
1532 1554 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
1533 1555 modified files: .hgtags
1534 1556
1535 1557 Test the sub function of templating for expansion:
1536 1558
1537 1559 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
1538 1560 xx
1539 1561
1540 1562 Test the strip function with chars specified:
1541 1563
1542 1564 $ hg log -R latesttag --template '{desc}\n'
1543 1565 at3
1544 1566 t5
1545 1567 t3
1546 1568 t2
1547 1569 t1
1548 1570 merge
1549 1571 h2e
1550 1572 h2d
1551 1573 h1c
1552 1574 b
1553 1575 a
1554 1576
1555 1577 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
1556 1578 at3
1557 1579 5
1558 1580 3
1559 1581 2
1560 1582 1
1561 1583 merg
1562 1584 h2
1563 1585 h2d
1564 1586 h1c
1565 1587 b
1566 1588 a
General Comments 0
You need to be logged in to leave comments. Login now