##// END OF EJS Templates
formatter: populate ctx from repo and node value...
Yuya Nishihara -
r39659:34ecc0a0 default
parent child Browse files
Show More
@@ -1,665 +1,678 b''
1 1 # formatter.py - generic output formatting for mercurial
2 2 #
3 3 # Copyright 2012 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 """Generic output formatting for Mercurial
9 9
10 10 The formatter provides API to show data in various ways. The following
11 11 functions should be used in place of ui.write():
12 12
13 13 - fm.write() for unconditional output
14 14 - fm.condwrite() to show some extra data conditionally in plain output
15 15 - fm.context() to provide changectx to template output
16 16 - fm.data() to provide extra data to JSON or template output
17 17 - fm.plain() to show raw text that isn't provided to JSON or template output
18 18
19 19 To show structured data (e.g. date tuples, dicts, lists), apply fm.format*()
20 20 beforehand so the data is converted to the appropriate data type. Use
21 21 fm.isplain() if you need to convert or format data conditionally which isn't
22 22 supported by the formatter API.
23 23
24 24 To build nested structure (i.e. a list of dicts), use fm.nested().
25 25
26 26 See also https://www.mercurial-scm.org/wiki/GenericTemplatingPlan
27 27
28 28 fm.condwrite() vs 'if cond:':
29 29
30 30 In most cases, use fm.condwrite() so users can selectively show the data
31 31 in template output. If it's costly to build data, use plain 'if cond:' with
32 32 fm.write().
33 33
34 34 fm.nested() vs fm.formatdict() (or fm.formatlist()):
35 35
36 36 fm.nested() should be used to form a tree structure (a list of dicts of
37 37 lists of dicts...) which can be accessed through template keywords, e.g.
38 38 "{foo % "{bar % {...}} {baz % {...}}"}". On the other hand, fm.formatdict()
39 39 exports a dict-type object to template, which can be accessed by e.g.
40 40 "{get(foo, key)}" function.
41 41
42 42 Doctest helper:
43 43
44 44 >>> def show(fn, verbose=False, **opts):
45 45 ... import sys
46 46 ... from . import ui as uimod
47 47 ... ui = uimod.ui()
48 48 ... ui.verbose = verbose
49 49 ... ui.pushbuffer()
50 50 ... try:
51 51 ... return fn(ui, ui.formatter(pycompat.sysbytes(fn.__name__),
52 52 ... pycompat.byteskwargs(opts)))
53 53 ... finally:
54 54 ... print(pycompat.sysstr(ui.popbuffer()), end='')
55 55
56 56 Basic example:
57 57
58 58 >>> def files(ui, fm):
59 59 ... files = [(b'foo', 123, (0, 0)), (b'bar', 456, (1, 0))]
60 60 ... for f in files:
61 61 ... fm.startitem()
62 62 ... fm.write(b'path', b'%s', f[0])
63 63 ... fm.condwrite(ui.verbose, b'date', b' %s',
64 64 ... fm.formatdate(f[2], b'%Y-%m-%d %H:%M:%S'))
65 65 ... fm.data(size=f[1])
66 66 ... fm.plain(b'\\n')
67 67 ... fm.end()
68 68 >>> show(files)
69 69 foo
70 70 bar
71 71 >>> show(files, verbose=True)
72 72 foo 1970-01-01 00:00:00
73 73 bar 1970-01-01 00:00:01
74 74 >>> show(files, template=b'json')
75 75 [
76 76 {
77 77 "date": [0, 0],
78 78 "path": "foo",
79 79 "size": 123
80 80 },
81 81 {
82 82 "date": [1, 0],
83 83 "path": "bar",
84 84 "size": 456
85 85 }
86 86 ]
87 87 >>> show(files, template=b'path: {path}\\ndate: {date|rfc3339date}\\n')
88 88 path: foo
89 89 date: 1970-01-01T00:00:00+00:00
90 90 path: bar
91 91 date: 1970-01-01T00:00:01+00:00
92 92
93 93 Nested example:
94 94
95 95 >>> def subrepos(ui, fm):
96 96 ... fm.startitem()
97 97 ... fm.write(b'reponame', b'[%s]\\n', b'baz')
98 98 ... files(ui, fm.nested(b'files', tmpl=b'{reponame}'))
99 99 ... fm.end()
100 100 >>> show(subrepos)
101 101 [baz]
102 102 foo
103 103 bar
104 104 >>> show(subrepos, template=b'{reponame}: {join(files % "{path}", ", ")}\\n')
105 105 baz: foo, bar
106 106 """
107 107
108 108 from __future__ import absolute_import, print_function
109 109
110 110 import contextlib
111 111 import itertools
112 112 import os
113 113
114 114 from .i18n import _
115 115 from .node import (
116 116 hex,
117 117 short,
118 118 )
119 119 from .thirdparty import (
120 120 attr,
121 121 )
122 122
123 123 from . import (
124 124 error,
125 125 pycompat,
126 126 templatefilters,
127 127 templatefuncs,
128 128 templatekw,
129 129 templater,
130 130 templateutil,
131 131 util,
132 132 )
133 133 from .utils import dateutil
134 134
135 135 pickle = util.pickle
136 136
137 137 class _nullconverter(object):
138 138 '''convert non-primitive data types to be processed by formatter'''
139 139
140 140 # set to True if context object should be stored as item
141 141 storecontext = False
142 142
143 143 @staticmethod
144 144 def wrapnested(data, tmpl, sep):
145 145 '''wrap nested data by appropriate type'''
146 146 return data
147 147 @staticmethod
148 148 def formatdate(date, fmt):
149 149 '''convert date tuple to appropriate format'''
150 150 # timestamp can be float, but the canonical form should be int
151 151 ts, tz = date
152 152 return (int(ts), tz)
153 153 @staticmethod
154 154 def formatdict(data, key, value, fmt, sep):
155 155 '''convert dict or key-value pairs to appropriate dict format'''
156 156 # use plain dict instead of util.sortdict so that data can be
157 157 # serialized as a builtin dict in pickle output
158 158 return dict(data)
159 159 @staticmethod
160 160 def formatlist(data, name, fmt, sep):
161 161 '''convert iterable to appropriate list format'''
162 162 return list(data)
163 163
164 164 class baseformatter(object):
165 165 def __init__(self, ui, topic, opts, converter):
166 166 self._ui = ui
167 167 self._topic = topic
168 168 self._opts = opts
169 169 self._converter = converter
170 170 self._item = None
171 171 # function to convert node to string suitable for this output
172 172 self.hexfunc = hex
173 173 def __enter__(self):
174 174 return self
175 175 def __exit__(self, exctype, excvalue, traceback):
176 176 if exctype is None:
177 177 self.end()
178 178 def _showitem(self):
179 179 '''show a formatted item once all data is collected'''
180 180 def startitem(self):
181 181 '''begin an item in the format list'''
182 182 if self._item is not None:
183 183 self._showitem()
184 184 self._item = {}
185 185 def formatdate(self, date, fmt='%a %b %d %H:%M:%S %Y %1%2'):
186 186 '''convert date tuple to appropriate format'''
187 187 return self._converter.formatdate(date, fmt)
188 188 def formatdict(self, data, key='key', value='value', fmt=None, sep=' '):
189 189 '''convert dict or key-value pairs to appropriate dict format'''
190 190 return self._converter.formatdict(data, key, value, fmt, sep)
191 191 def formatlist(self, data, name, fmt=None, sep=' '):
192 192 '''convert iterable to appropriate list format'''
193 193 # name is mandatory argument for now, but it could be optional if
194 194 # we have default template keyword, e.g. {item}
195 195 return self._converter.formatlist(data, name, fmt, sep)
196 196 def contexthint(self, datafields):
197 197 '''set of context object keys to be required given datafields set'''
198 198 return set()
199 199 def context(self, **ctxs):
200 200 '''insert context objects to be used to render template keywords'''
201 201 ctxs = pycompat.byteskwargs(ctxs)
202 202 assert all(k in {'repo', 'ctx', 'fctx'} for k in ctxs)
203 203 if self._converter.storecontext:
204 204 # populate missing resources in fctx -> ctx -> repo order
205 205 if 'fctx' in ctxs and 'ctx' not in ctxs:
206 206 ctxs['ctx'] = ctxs['fctx'].changectx()
207 207 if 'ctx' in ctxs and 'repo' not in ctxs:
208 208 ctxs['repo'] = ctxs['ctx'].repo()
209 209 self._item.update(ctxs)
210 210 def datahint(self):
211 211 '''set of field names to be referenced'''
212 212 return set()
213 213 def data(self, **data):
214 214 '''insert data into item that's not shown in default output'''
215 215 data = pycompat.byteskwargs(data)
216 216 self._item.update(data)
217 217 def write(self, fields, deftext, *fielddata, **opts):
218 218 '''do default text output while assigning data to item'''
219 219 fieldkeys = fields.split()
220 220 assert len(fieldkeys) == len(fielddata)
221 221 self._item.update(zip(fieldkeys, fielddata))
222 222 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
223 223 '''do conditional write (primarily for plain formatter)'''
224 224 fieldkeys = fields.split()
225 225 assert len(fieldkeys) == len(fielddata)
226 226 self._item.update(zip(fieldkeys, fielddata))
227 227 def plain(self, text, **opts):
228 228 '''show raw text for non-templated mode'''
229 229 def isplain(self):
230 230 '''check for plain formatter usage'''
231 231 return False
232 232 def nested(self, field, tmpl=None, sep=''):
233 233 '''sub formatter to store nested data in the specified field'''
234 234 data = []
235 235 self._item[field] = self._converter.wrapnested(data, tmpl, sep)
236 236 return _nestedformatter(self._ui, self._converter, data)
237 237 def end(self):
238 238 '''end output for the formatter'''
239 239 if self._item is not None:
240 240 self._showitem()
241 241
242 242 def nullformatter(ui, topic, opts):
243 243 '''formatter that prints nothing'''
244 244 return baseformatter(ui, topic, opts, converter=_nullconverter)
245 245
246 246 class _nestedformatter(baseformatter):
247 247 '''build sub items and store them in the parent formatter'''
248 248 def __init__(self, ui, converter, data):
249 249 baseformatter.__init__(self, ui, topic='', opts={}, converter=converter)
250 250 self._data = data
251 251 def _showitem(self):
252 252 self._data.append(self._item)
253 253
254 254 def _iteritems(data):
255 255 '''iterate key-value pairs in stable order'''
256 256 if isinstance(data, dict):
257 257 return sorted(data.iteritems())
258 258 return data
259 259
260 260 class _plainconverter(object):
261 261 '''convert non-primitive data types to text'''
262 262
263 263 storecontext = False
264 264
265 265 @staticmethod
266 266 def wrapnested(data, tmpl, sep):
267 267 raise error.ProgrammingError('plainformatter should never be nested')
268 268 @staticmethod
269 269 def formatdate(date, fmt):
270 270 '''stringify date tuple in the given format'''
271 271 return dateutil.datestr(date, fmt)
272 272 @staticmethod
273 273 def formatdict(data, key, value, fmt, sep):
274 274 '''stringify key-value pairs separated by sep'''
275 275 prefmt = pycompat.identity
276 276 if fmt is None:
277 277 fmt = '%s=%s'
278 278 prefmt = pycompat.bytestr
279 279 return sep.join(fmt % (prefmt(k), prefmt(v))
280 280 for k, v in _iteritems(data))
281 281 @staticmethod
282 282 def formatlist(data, name, fmt, sep):
283 283 '''stringify iterable separated by sep'''
284 284 prefmt = pycompat.identity
285 285 if fmt is None:
286 286 fmt = '%s'
287 287 prefmt = pycompat.bytestr
288 288 return sep.join(fmt % prefmt(e) for e in data)
289 289
290 290 class plainformatter(baseformatter):
291 291 '''the default text output scheme'''
292 292 def __init__(self, ui, out, topic, opts):
293 293 baseformatter.__init__(self, ui, topic, opts, _plainconverter)
294 294 if ui.debugflag:
295 295 self.hexfunc = hex
296 296 else:
297 297 self.hexfunc = short
298 298 if ui is out:
299 299 self._write = ui.write
300 300 else:
301 301 self._write = lambda s, **opts: out.write(s)
302 302 def startitem(self):
303 303 pass
304 304 def data(self, **data):
305 305 pass
306 306 def write(self, fields, deftext, *fielddata, **opts):
307 307 self._write(deftext % fielddata, **opts)
308 308 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
309 309 '''do conditional write'''
310 310 if cond:
311 311 self._write(deftext % fielddata, **opts)
312 312 def plain(self, text, **opts):
313 313 self._write(text, **opts)
314 314 def isplain(self):
315 315 return True
316 316 def nested(self, field, tmpl=None, sep=''):
317 317 # nested data will be directly written to ui
318 318 return self
319 319 def end(self):
320 320 pass
321 321
322 322 class debugformatter(baseformatter):
323 323 def __init__(self, ui, out, topic, opts):
324 324 baseformatter.__init__(self, ui, topic, opts, _nullconverter)
325 325 self._out = out
326 326 self._out.write("%s = [\n" % self._topic)
327 327 def _showitem(self):
328 328 self._out.write(' %s,\n' % pycompat.byterepr(self._item))
329 329 def end(self):
330 330 baseformatter.end(self)
331 331 self._out.write("]\n")
332 332
333 333 class pickleformatter(baseformatter):
334 334 def __init__(self, ui, out, topic, opts):
335 335 baseformatter.__init__(self, ui, topic, opts, _nullconverter)
336 336 self._out = out
337 337 self._data = []
338 338 def _showitem(self):
339 339 self._data.append(self._item)
340 340 def end(self):
341 341 baseformatter.end(self)
342 342 self._out.write(pickle.dumps(self._data))
343 343
344 344 class jsonformatter(baseformatter):
345 345 def __init__(self, ui, out, topic, opts):
346 346 baseformatter.__init__(self, ui, topic, opts, _nullconverter)
347 347 self._out = out
348 348 self._out.write("[")
349 349 self._first = True
350 350 def _showitem(self):
351 351 if self._first:
352 352 self._first = False
353 353 else:
354 354 self._out.write(",")
355 355
356 356 self._out.write("\n {\n")
357 357 first = True
358 358 for k, v in sorted(self._item.items()):
359 359 if first:
360 360 first = False
361 361 else:
362 362 self._out.write(",\n")
363 363 u = templatefilters.json(v, paranoid=False)
364 364 self._out.write(' "%s": %s' % (k, u))
365 365 self._out.write("\n }")
366 366 def end(self):
367 367 baseformatter.end(self)
368 368 self._out.write("\n]\n")
369 369
370 370 class _templateconverter(object):
371 371 '''convert non-primitive data types to be processed by templater'''
372 372
373 373 storecontext = True
374 374
375 375 @staticmethod
376 376 def wrapnested(data, tmpl, sep):
377 377 '''wrap nested data by templatable type'''
378 378 return templateutil.mappinglist(data, tmpl=tmpl, sep=sep)
379 379 @staticmethod
380 380 def formatdate(date, fmt):
381 381 '''return date tuple'''
382 382 return templateutil.date(date)
383 383 @staticmethod
384 384 def formatdict(data, key, value, fmt, sep):
385 385 '''build object that can be evaluated as either plain string or dict'''
386 386 data = util.sortdict(_iteritems(data))
387 387 def f():
388 388 yield _plainconverter.formatdict(data, key, value, fmt, sep)
389 389 return templateutil.hybriddict(data, key=key, value=value, fmt=fmt,
390 390 gen=f)
391 391 @staticmethod
392 392 def formatlist(data, name, fmt, sep):
393 393 '''build object that can be evaluated as either plain string or list'''
394 394 data = list(data)
395 395 def f():
396 396 yield _plainconverter.formatlist(data, name, fmt, sep)
397 397 return templateutil.hybridlist(data, name=name, fmt=fmt, gen=f)
398 398
399 399 class templateformatter(baseformatter):
400 400 def __init__(self, ui, out, topic, opts):
401 401 baseformatter.__init__(self, ui, topic, opts, _templateconverter)
402 402 self._out = out
403 403 spec = lookuptemplate(ui, topic, opts.get('template', ''))
404 404 self._tref = spec.ref
405 405 self._t = loadtemplater(ui, spec, defaults=templatekw.keywords,
406 406 resources=templateresources(ui),
407 407 cache=templatekw.defaulttempl)
408 408 self._parts = templatepartsmap(spec, self._t,
409 409 ['docheader', 'docfooter', 'separator'])
410 410 self._counter = itertools.count()
411 411 self._renderitem('docheader', {})
412 412
413 413 def _showitem(self):
414 414 item = self._item.copy()
415 415 item['index'] = index = next(self._counter)
416 416 if index > 0:
417 417 self._renderitem('separator', {})
418 418 self._renderitem(self._tref, item)
419 419
420 420 def _renderitem(self, part, item):
421 421 if part not in self._parts:
422 422 return
423 423 ref = self._parts[part]
424 424 self._out.write(self._t.render(ref, item))
425 425
426 426 @util.propertycache
427 427 def _symbolsused(self):
428 428 return self._t.symbolsused(self._tref)
429 429
430 430 def contexthint(self, datafields):
431 431 '''set of context object keys to be required by the template, given
432 432 datafields overridden by immediate values'''
433 433 requires = set()
434 434 ksyms, fsyms = self._symbolsused
435 435 ksyms = ksyms - set(datafields.split()) # exclude immediate fields
436 436 symtables = [(ksyms, templatekw.keywords),
437 437 (fsyms, templatefuncs.funcs)]
438 438 for syms, table in symtables:
439 439 for k in syms:
440 440 f = table.get(k)
441 441 if not f:
442 442 continue
443 443 requires.update(getattr(f, '_requires', ()))
444 444 if 'repo' in requires:
445 445 requires.add('ctx') # there's no API to pass repo to formatter
446 446 return requires & {'ctx', 'fctx'}
447 447
448 448 def datahint(self):
449 449 '''set of field names to be referenced from the template'''
450 450 return self._symbolsused[0]
451 451
452 452 def end(self):
453 453 baseformatter.end(self)
454 454 self._renderitem('docfooter', {})
455 455
456 456 @attr.s(frozen=True)
457 457 class templatespec(object):
458 458 ref = attr.ib()
459 459 tmpl = attr.ib()
460 460 mapfile = attr.ib()
461 461
462 462 def lookuptemplate(ui, topic, tmpl):
463 463 """Find the template matching the given -T/--template spec 'tmpl'
464 464
465 465 'tmpl' can be any of the following:
466 466
467 467 - a literal template (e.g. '{rev}')
468 468 - a map-file name or path (e.g. 'changelog')
469 469 - a reference to [templates] in config file
470 470 - a path to raw template file
471 471
472 472 A map file defines a stand-alone template environment. If a map file
473 473 selected, all templates defined in the file will be loaded, and the
474 474 template matching the given topic will be rendered. Aliases won't be
475 475 loaded from user config, but from the map file.
476 476
477 477 If no map file selected, all templates in [templates] section will be
478 478 available as well as aliases in [templatealias].
479 479 """
480 480
481 481 # looks like a literal template?
482 482 if '{' in tmpl:
483 483 return templatespec('', tmpl, None)
484 484
485 485 # perhaps a stock style?
486 486 if not os.path.split(tmpl)[0]:
487 487 mapname = (templater.templatepath('map-cmdline.' + tmpl)
488 488 or templater.templatepath(tmpl))
489 489 if mapname and os.path.isfile(mapname):
490 490 return templatespec(topic, None, mapname)
491 491
492 492 # perhaps it's a reference to [templates]
493 493 if ui.config('templates', tmpl):
494 494 return templatespec(tmpl, None, None)
495 495
496 496 if tmpl == 'list':
497 497 ui.write(_("available styles: %s\n") % templater.stylelist())
498 498 raise error.Abort(_("specify a template"))
499 499
500 500 # perhaps it's a path to a map or a template
501 501 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
502 502 # is it a mapfile for a style?
503 503 if os.path.basename(tmpl).startswith("map-"):
504 504 return templatespec(topic, None, os.path.realpath(tmpl))
505 505 with util.posixfile(tmpl, 'rb') as f:
506 506 tmpl = f.read()
507 507 return templatespec('', tmpl, None)
508 508
509 509 # constant string?
510 510 return templatespec('', tmpl, None)
511 511
512 512 def templatepartsmap(spec, t, partnames):
513 513 """Create a mapping of {part: ref}"""
514 514 partsmap = {spec.ref: spec.ref} # initial ref must exist in t
515 515 if spec.mapfile:
516 516 partsmap.update((p, p) for p in partnames if p in t)
517 517 elif spec.ref:
518 518 for part in partnames:
519 519 ref = '%s:%s' % (spec.ref, part) # select config sub-section
520 520 if ref in t:
521 521 partsmap[part] = ref
522 522 return partsmap
523 523
524 524 def loadtemplater(ui, spec, defaults=None, resources=None, cache=None):
525 525 """Create a templater from either a literal template or loading from
526 526 a map file"""
527 527 assert not (spec.tmpl and spec.mapfile)
528 528 if spec.mapfile:
529 529 frommapfile = templater.templater.frommapfile
530 530 return frommapfile(spec.mapfile, defaults=defaults, resources=resources,
531 531 cache=cache)
532 532 return maketemplater(ui, spec.tmpl, defaults=defaults, resources=resources,
533 533 cache=cache)
534 534
535 535 def maketemplater(ui, tmpl, defaults=None, resources=None, cache=None):
536 536 """Create a templater from a string template 'tmpl'"""
537 537 aliases = ui.configitems('templatealias')
538 538 t = templater.templater(defaults=defaults, resources=resources,
539 539 cache=cache, aliases=aliases)
540 540 t.cache.update((k, templater.unquotestring(v))
541 541 for k, v in ui.configitems('templates'))
542 542 if tmpl:
543 543 t.cache[''] = tmpl
544 544 return t
545 545
546 546 # marker to denote a resource to be loaded on demand based on mapping values
547 547 # (e.g. (ctx, path) -> fctx)
548 548 _placeholder = object()
549 549
550 550 class templateresources(templater.resourcemapper):
551 551 """Resource mapper designed for the default templatekw and function"""
552 552
553 553 def __init__(self, ui, repo=None):
554 554 self._resmap = {
555 555 'cache': {}, # for templatekw/funcs to store reusable data
556 556 'repo': repo,
557 557 'ui': ui,
558 558 }
559 559
560 560 def availablekeys(self, mapping):
561 561 return {k for k in self.knownkeys()
562 562 if self._getsome(mapping, k) is not None}
563 563
564 564 def knownkeys(self):
565 565 return {'cache', 'ctx', 'fctx', 'repo', 'revcache', 'ui'}
566 566
567 567 def lookup(self, mapping, key):
568 568 if key not in self.knownkeys():
569 569 return None
570 570 v = self._getsome(mapping, key)
571 571 if v is _placeholder:
572 572 v = mapping[key] = self._loadermap[key](self, mapping)
573 573 return v
574 574
575 575 def populatemap(self, context, origmapping, newmapping):
576 576 mapping = {}
577 577 if self._hasnodespec(newmapping):
578 578 mapping['revcache'] = {} # per-ctx cache
579 579 if self._hasnodespec(origmapping) and self._hasnodespec(newmapping):
580 580 orignode = templateutil.runsymbol(context, origmapping, 'node')
581 581 mapping['originalnode'] = orignode
582 # put marker to override 'fctx' in mapping if any, and flag
582 # put marker to override 'ctx'/'fctx' in mapping if any, and flag
583 583 # its existence to be reported by availablekeys()
584 if 'ctx' not in newmapping and self._hasliteral(newmapping, 'node'):
585 mapping['ctx'] = _placeholder
584 586 if 'fctx' not in newmapping and self._hasliteral(newmapping, 'path'):
585 587 mapping['fctx'] = _placeholder
586 588 return mapping
587 589
588 590 def _getsome(self, mapping, key):
589 591 v = mapping.get(key)
590 592 if v is not None:
591 593 return v
592 594 return self._resmap.get(key)
593 595
594 596 def _hasliteral(self, mapping, key):
595 597 """Test if a literal value is set or unset in the given mapping"""
596 598 return key in mapping and not callable(mapping[key])
597 599
598 600 def _getliteral(self, mapping, key):
599 601 """Return value of the given name if it is a literal"""
600 602 v = mapping.get(key)
601 603 if callable(v):
602 604 return None
603 605 return v
604 606
605 607 def _hasnodespec(self, mapping):
606 608 """Test if context revision is set or unset in the given mapping"""
607 609 return 'node' in mapping or 'ctx' in mapping
608 610
611 def _loadctx(self, mapping):
612 repo = self._getsome(mapping, 'repo')
613 node = self._getliteral(mapping, 'node')
614 if repo is None or node is None:
615 return
616 try:
617 return repo[node]
618 except error.RepoLookupError:
619 return None # maybe hidden/non-existent node
620
609 621 def _loadfctx(self, mapping):
610 622 ctx = self._getsome(mapping, 'ctx')
611 623 path = self._getliteral(mapping, 'path')
612 624 if ctx is None or path is None:
613 625 return None
614 626 try:
615 627 return ctx[path]
616 628 except error.LookupError:
617 629 return None # maybe removed file?
618 630
619 631 _loadermap = {
632 'ctx': _loadctx,
620 633 'fctx': _loadfctx,
621 634 }
622 635
623 636 def formatter(ui, out, topic, opts):
624 637 template = opts.get("template", "")
625 638 if template == "json":
626 639 return jsonformatter(ui, out, topic, opts)
627 640 elif template == "pickle":
628 641 return pickleformatter(ui, out, topic, opts)
629 642 elif template == "debug":
630 643 return debugformatter(ui, out, topic, opts)
631 644 elif template != "":
632 645 return templateformatter(ui, out, topic, opts)
633 646 # developer config: ui.formatdebug
634 647 elif ui.configbool('ui', 'formatdebug'):
635 648 return debugformatter(ui, out, topic, opts)
636 649 # deprecated config: ui.formatjson
637 650 elif ui.configbool('ui', 'formatjson'):
638 651 return jsonformatter(ui, out, topic, opts)
639 652 return plainformatter(ui, out, topic, opts)
640 653
641 654 @contextlib.contextmanager
642 655 def openformatter(ui, filename, topic, opts):
643 656 """Create a formatter that writes outputs to the specified file
644 657
645 658 Must be invoked using the 'with' statement.
646 659 """
647 660 with util.posixfile(filename, 'wb') as out:
648 661 with formatter(ui, out, topic, opts) as fm:
649 662 yield fm
650 663
651 664 @contextlib.contextmanager
652 665 def _neverending(fm):
653 666 yield fm
654 667
655 668 def maybereopen(fm, filename):
656 669 """Create a formatter backed by file if filename specified, else return
657 670 the given formatter
658 671
659 672 Must be invoked using the 'with' statement. This will never call fm.end()
660 673 of the given formatter.
661 674 """
662 675 if filename:
663 676 return openformatter(fm._ui, filename, fm._topic, fm._opts)
664 677 else:
665 678 return _neverending(fm)
@@ -1,856 +1,854 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import (
12 12 hex,
13 13 nullid,
14 14 )
15 15
16 16 from . import (
17 17 diffutil,
18 18 encoding,
19 19 error,
20 20 hbisect,
21 21 i18n,
22 22 obsutil,
23 23 patch,
24 24 pycompat,
25 25 registrar,
26 26 scmutil,
27 27 templateutil,
28 28 util,
29 29 )
30 30 from .utils import (
31 31 stringutil,
32 32 )
33 33
34 34 _hybrid = templateutil.hybrid
35 35 hybriddict = templateutil.hybriddict
36 36 hybridlist = templateutil.hybridlist
37 37 compatdict = templateutil.compatdict
38 38 compatlist = templateutil.compatlist
39 39 _showcompatlist = templateutil._showcompatlist
40 40
41 41 def getlatesttags(context, mapping, pattern=None):
42 42 '''return date, distance and name for the latest tag of rev'''
43 43 repo = context.resource(mapping, 'repo')
44 44 ctx = context.resource(mapping, 'ctx')
45 45 cache = context.resource(mapping, 'cache')
46 46
47 47 cachename = 'latesttags'
48 48 if pattern is not None:
49 49 cachename += '-' + pattern
50 50 match = stringutil.stringmatcher(pattern)[2]
51 51 else:
52 52 match = util.always
53 53
54 54 if cachename not in cache:
55 55 # Cache mapping from rev to a tuple with tag date, tag
56 56 # distance and tag name
57 57 cache[cachename] = {-1: (0, 0, ['null'])}
58 58 latesttags = cache[cachename]
59 59
60 60 rev = ctx.rev()
61 61 todo = [rev]
62 62 while todo:
63 63 rev = todo.pop()
64 64 if rev in latesttags:
65 65 continue
66 66 ctx = repo[rev]
67 67 tags = [t for t in ctx.tags()
68 68 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
69 69 and match(t))]
70 70 if tags:
71 71 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
72 72 continue
73 73 try:
74 74 ptags = [latesttags[p.rev()] for p in ctx.parents()]
75 75 if len(ptags) > 1:
76 76 if ptags[0][2] == ptags[1][2]:
77 77 # The tuples are laid out so the right one can be found by
78 78 # comparison in this case.
79 79 pdate, pdist, ptag = max(ptags)
80 80 else:
81 81 def key(x):
82 82 changessincetag = len(repo.revs('only(%d, %s)',
83 83 ctx.rev(), x[2][0]))
84 84 # Smallest number of changes since tag wins. Date is
85 85 # used as tiebreaker.
86 86 return [-changessincetag, x[0]]
87 87 pdate, pdist, ptag = max(ptags, key=key)
88 88 else:
89 89 pdate, pdist, ptag = ptags[0]
90 90 except KeyError:
91 91 # Cache miss - recurse
92 92 todo.append(rev)
93 93 todo.extend(p.rev() for p in ctx.parents())
94 94 continue
95 95 latesttags[rev] = pdate, pdist + 1, ptag
96 96 return latesttags[rev]
97 97
98 98 def getrenamedfn(repo, endrev=None):
99 99 rcache = {}
100 100 if endrev is None:
101 101 endrev = len(repo)
102 102
103 103 def getrenamed(fn, rev):
104 104 '''looks up all renames for a file (up to endrev) the first
105 105 time the file is given. It indexes on the changerev and only
106 106 parses the manifest if linkrev != changerev.
107 107 Returns rename info for fn at changerev rev.'''
108 108 if fn not in rcache:
109 109 rcache[fn] = {}
110 110 fl = repo.file(fn)
111 111 for i in fl:
112 112 lr = fl.linkrev(i)
113 113 renamed = fl.renamed(fl.node(i))
114 114 rcache[fn][lr] = renamed and renamed[0]
115 115 if lr >= endrev:
116 116 break
117 117 if rev in rcache[fn]:
118 118 return rcache[fn][rev]
119 119
120 120 # If linkrev != rev (i.e. rev not found in rcache) fallback to
121 121 # filectx logic.
122 122 try:
123 123 renamed = repo[rev][fn].renamed()
124 124 return renamed and renamed[0]
125 125 except error.LookupError:
126 126 return None
127 127
128 128 return getrenamed
129 129
130 130 def getlogcolumns():
131 131 """Return a dict of log column labels"""
132 132 _ = pycompat.identity # temporarily disable gettext
133 133 # i18n: column positioning for "hg log"
134 134 columns = _('bookmark: %s\n'
135 135 'branch: %s\n'
136 136 'changeset: %s\n'
137 137 'copies: %s\n'
138 138 'date: %s\n'
139 139 'extra: %s=%s\n'
140 140 'files+: %s\n'
141 141 'files-: %s\n'
142 142 'files: %s\n'
143 143 'instability: %s\n'
144 144 'manifest: %s\n'
145 145 'obsolete: %s\n'
146 146 'parent: %s\n'
147 147 'phase: %s\n'
148 148 'summary: %s\n'
149 149 'tag: %s\n'
150 150 'user: %s\n')
151 151 return dict(zip([s.split(':', 1)[0] for s in columns.splitlines()],
152 152 i18n._(columns).splitlines(True)))
153 153
154 154 # default templates internally used for rendering of lists
155 155 defaulttempl = {
156 156 'parent': '{rev}:{node|formatnode} ',
157 157 'manifest': '{rev}:{node|formatnode}',
158 158 'file_copy': '{name} ({source})',
159 159 'envvar': '{key}={value}',
160 160 'extra': '{key}={value|stringescape}'
161 161 }
162 162 # filecopy is preserved for compatibility reasons
163 163 defaulttempl['filecopy'] = defaulttempl['file_copy']
164 164
165 165 # keywords are callables (see registrar.templatekeyword for details)
166 166 keywords = {}
167 167 templatekeyword = registrar.templatekeyword(keywords)
168 168
169 169 @templatekeyword('author', requires={'ctx'})
170 170 def showauthor(context, mapping):
171 171 """Alias for ``{user}``"""
172 172 return showuser(context, mapping)
173 173
174 174 @templatekeyword('bisect', requires={'repo', 'ctx'})
175 175 def showbisect(context, mapping):
176 176 """String. The changeset bisection status."""
177 177 repo = context.resource(mapping, 'repo')
178 178 ctx = context.resource(mapping, 'ctx')
179 179 return hbisect.label(repo, ctx.node())
180 180
181 181 @templatekeyword('branch', requires={'ctx'})
182 182 def showbranch(context, mapping):
183 183 """String. The name of the branch on which the changeset was
184 184 committed.
185 185 """
186 186 ctx = context.resource(mapping, 'ctx')
187 187 return ctx.branch()
188 188
189 189 @templatekeyword('branches', requires={'ctx'})
190 190 def showbranches(context, mapping):
191 191 """List of strings. The name of the branch on which the
192 192 changeset was committed. Will be empty if the branch name was
193 193 default. (DEPRECATED)
194 194 """
195 195 ctx = context.resource(mapping, 'ctx')
196 196 branch = ctx.branch()
197 197 if branch != 'default':
198 198 return compatlist(context, mapping, 'branch', [branch],
199 199 plural='branches')
200 200 return compatlist(context, mapping, 'branch', [], plural='branches')
201 201
202 202 @templatekeyword('bookmarks', requires={'repo', 'ctx'})
203 203 def showbookmarks(context, mapping):
204 204 """List of strings. Any bookmarks associated with the
205 205 changeset. Also sets 'active', the name of the active bookmark.
206 206 """
207 207 repo = context.resource(mapping, 'repo')
208 208 ctx = context.resource(mapping, 'ctx')
209 209 bookmarks = ctx.bookmarks()
210 210 active = repo._activebookmark
211 211 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
212 212 f = _showcompatlist(context, mapping, 'bookmark', bookmarks)
213 213 return _hybrid(f, bookmarks, makemap, pycompat.identity)
214 214
215 215 @templatekeyword('children', requires={'ctx'})
216 216 def showchildren(context, mapping):
217 217 """List of strings. The children of the changeset."""
218 218 ctx = context.resource(mapping, 'ctx')
219 219 childrevs = ['%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
220 220 return compatlist(context, mapping, 'children', childrevs, element='child')
221 221
222 222 # Deprecated, but kept alive for help generation a purpose.
223 223 @templatekeyword('currentbookmark', requires={'repo', 'ctx'})
224 224 def showcurrentbookmark(context, mapping):
225 225 """String. The active bookmark, if it is associated with the changeset.
226 226 (DEPRECATED)"""
227 227 return showactivebookmark(context, mapping)
228 228
229 229 @templatekeyword('activebookmark', requires={'repo', 'ctx'})
230 230 def showactivebookmark(context, mapping):
231 231 """String. The active bookmark, if it is associated with the changeset."""
232 232 repo = context.resource(mapping, 'repo')
233 233 ctx = context.resource(mapping, 'ctx')
234 234 active = repo._activebookmark
235 235 if active and active in ctx.bookmarks():
236 236 return active
237 237 return ''
238 238
239 239 @templatekeyword('date', requires={'ctx'})
240 240 def showdate(context, mapping):
241 241 """Date information. The date when the changeset was committed."""
242 242 ctx = context.resource(mapping, 'ctx')
243 243 # the default string format is '<float(unixtime)><tzoffset>' because
244 244 # python-hglib splits date at decimal separator.
245 245 return templateutil.date(ctx.date(), showfmt='%d.0%d')
246 246
247 247 @templatekeyword('desc', requires={'ctx'})
248 248 def showdescription(context, mapping):
249 249 """String. The text of the changeset description."""
250 250 ctx = context.resource(mapping, 'ctx')
251 251 s = ctx.description()
252 252 if isinstance(s, encoding.localstr):
253 253 # try hard to preserve utf-8 bytes
254 254 return encoding.tolocal(encoding.fromlocal(s).strip())
255 255 elif isinstance(s, encoding.safelocalstr):
256 256 return encoding.safelocalstr(s.strip())
257 257 else:
258 258 return s.strip()
259 259
260 260 @templatekeyword('diffstat', requires={'ui', 'ctx'})
261 261 def showdiffstat(context, mapping):
262 262 """String. Statistics of changes with the following format:
263 263 "modified files: +added/-removed lines"
264 264 """
265 265 ui = context.resource(mapping, 'ui')
266 266 ctx = context.resource(mapping, 'ctx')
267 267 diffopts = diffutil.diffallopts(ui, {'noprefix': False})
268 268 diff = ctx.diff(opts=diffopts)
269 269 stats = patch.diffstatdata(util.iterlines(diff))
270 270 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
271 271 return '%d: +%d/-%d' % (len(stats), adds, removes)
272 272
273 273 @templatekeyword('envvars', requires={'ui'})
274 274 def showenvvars(context, mapping):
275 275 """A dictionary of environment variables. (EXPERIMENTAL)"""
276 276 ui = context.resource(mapping, 'ui')
277 277 env = ui.exportableenviron()
278 278 env = util.sortdict((k, env[k]) for k in sorted(env))
279 279 return compatdict(context, mapping, 'envvar', env, plural='envvars')
280 280
281 281 @templatekeyword('extras', requires={'ctx'})
282 282 def showextras(context, mapping):
283 283 """List of dicts with key, value entries of the 'extras'
284 284 field of this changeset."""
285 285 ctx = context.resource(mapping, 'ctx')
286 286 extras = ctx.extra()
287 287 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
288 288 makemap = lambda k: {'key': k, 'value': extras[k]}
289 289 c = [makemap(k) for k in extras]
290 290 f = _showcompatlist(context, mapping, 'extra', c, plural='extras')
291 291 return _hybrid(f, extras, makemap,
292 292 lambda k: '%s=%s' % (k, stringutil.escapestr(extras[k])))
293 293
294 294 def _getfilestatus(context, mapping, listall=False):
295 295 ctx = context.resource(mapping, 'ctx')
296 296 revcache = context.resource(mapping, 'revcache')
297 297 if 'filestatus' not in revcache or revcache['filestatusall'] < listall:
298 298 stat = ctx.p1().status(ctx, listignored=listall, listclean=listall,
299 299 listunknown=listall)
300 300 revcache['filestatus'] = stat
301 301 revcache['filestatusall'] = listall
302 302 return revcache['filestatus']
303 303
304 304 def _getfilestatusmap(context, mapping, listall=False):
305 305 revcache = context.resource(mapping, 'revcache')
306 306 if 'filestatusmap' not in revcache or revcache['filestatusall'] < listall:
307 307 stat = _getfilestatus(context, mapping, listall=listall)
308 308 revcache['filestatusmap'] = statmap = {}
309 309 for char, files in zip(pycompat.iterbytestr('MAR!?IC'), stat):
310 310 statmap.update((f, char) for f in files)
311 311 return revcache['filestatusmap'] # {path: statchar}
312 312
313 313 def _showfilesbystat(context, mapping, name, index):
314 314 stat = _getfilestatus(context, mapping)
315 315 files = stat[index]
316 316 return templateutil.compatfileslist(context, mapping, name, files)
317 317
318 318 @templatekeyword('file_adds', requires={'ctx', 'revcache'})
319 319 def showfileadds(context, mapping):
320 320 """List of strings. Files added by this changeset."""
321 321 return _showfilesbystat(context, mapping, 'file_add', 1)
322 322
323 323 @templatekeyword('file_copies',
324 324 requires={'repo', 'ctx', 'cache', 'revcache'})
325 325 def showfilecopies(context, mapping):
326 326 """List of strings. Files copied in this changeset with
327 327 their sources.
328 328 """
329 329 repo = context.resource(mapping, 'repo')
330 330 ctx = context.resource(mapping, 'ctx')
331 331 cache = context.resource(mapping, 'cache')
332 332 copies = context.resource(mapping, 'revcache').get('copies')
333 333 if copies is None:
334 334 if 'getrenamed' not in cache:
335 335 cache['getrenamed'] = getrenamedfn(repo)
336 336 copies = []
337 337 getrenamed = cache['getrenamed']
338 338 for fn in ctx.files():
339 339 rename = getrenamed(fn, ctx.rev())
340 340 if rename:
341 341 copies.append((fn, rename))
342 342 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
343 343 copies)
344 344
345 345 # showfilecopiesswitch() displays file copies only if copy records are
346 346 # provided before calling the templater, usually with a --copies
347 347 # command line switch.
348 348 @templatekeyword('file_copies_switch', requires={'revcache'})
349 349 def showfilecopiesswitch(context, mapping):
350 350 """List of strings. Like "file_copies" but displayed
351 351 only if the --copied switch is set.
352 352 """
353 353 copies = context.resource(mapping, 'revcache').get('copies') or []
354 354 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
355 355 copies)
356 356
357 357 @templatekeyword('file_dels', requires={'ctx', 'revcache'})
358 358 def showfiledels(context, mapping):
359 359 """List of strings. Files removed by this changeset."""
360 360 return _showfilesbystat(context, mapping, 'file_del', 2)
361 361
362 362 @templatekeyword('file_mods', requires={'ctx', 'revcache'})
363 363 def showfilemods(context, mapping):
364 364 """List of strings. Files modified by this changeset."""
365 365 return _showfilesbystat(context, mapping, 'file_mod', 0)
366 366
367 367 @templatekeyword('files', requires={'ctx'})
368 368 def showfiles(context, mapping):
369 369 """List of strings. All files modified, added, or removed by this
370 370 changeset.
371 371 """
372 372 ctx = context.resource(mapping, 'ctx')
373 373 return templateutil.compatfileslist(context, mapping, 'file', ctx.files())
374 374
375 375 @templatekeyword('graphnode', requires={'repo', 'ctx'})
376 376 def showgraphnode(context, mapping):
377 377 """String. The character representing the changeset node in an ASCII
378 378 revision graph."""
379 379 repo = context.resource(mapping, 'repo')
380 380 ctx = context.resource(mapping, 'ctx')
381 381 return getgraphnode(repo, ctx)
382 382
383 383 def getgraphnode(repo, ctx):
384 384 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx)
385 385
386 386 def getgraphnodecurrent(repo, ctx):
387 387 wpnodes = repo.dirstate.parents()
388 388 if wpnodes[1] == nullid:
389 389 wpnodes = wpnodes[:1]
390 390 if ctx.node() in wpnodes:
391 391 return '@'
392 392 else:
393 393 return ''
394 394
395 395 def getgraphnodesymbol(ctx):
396 396 if ctx.obsolete():
397 397 return 'x'
398 398 elif ctx.isunstable():
399 399 return '*'
400 400 elif ctx.closesbranch():
401 401 return '_'
402 402 else:
403 403 return 'o'
404 404
405 405 @templatekeyword('graphwidth', requires=())
406 406 def showgraphwidth(context, mapping):
407 407 """Integer. The width of the graph drawn by 'log --graph' or zero."""
408 408 # just hosts documentation; should be overridden by template mapping
409 409 return 0
410 410
411 411 @templatekeyword('index', requires=())
412 412 def showindex(context, mapping):
413 413 """Integer. The current iteration of the loop. (0 indexed)"""
414 414 # just hosts documentation; should be overridden by template mapping
415 415 raise error.Abort(_("can't use index in this context"))
416 416
417 417 @templatekeyword('latesttag', requires={'repo', 'ctx', 'cache'})
418 418 def showlatesttag(context, mapping):
419 419 """List of strings. The global tags on the most recent globally
420 420 tagged ancestor of this changeset. If no such tags exist, the list
421 421 consists of the single string "null".
422 422 """
423 423 return showlatesttags(context, mapping, None)
424 424
425 425 def showlatesttags(context, mapping, pattern):
426 426 """helper method for the latesttag keyword and function"""
427 427 latesttags = getlatesttags(context, mapping, pattern)
428 428
429 429 # latesttag[0] is an implementation detail for sorting csets on different
430 430 # branches in a stable manner- it is the date the tagged cset was created,
431 431 # not the date the tag was created. Therefore it isn't made visible here.
432 432 makemap = lambda v: {
433 433 'changes': _showchangessincetag,
434 434 'distance': latesttags[1],
435 435 'latesttag': v, # BC with {latesttag % '{latesttag}'}
436 436 'tag': v
437 437 }
438 438
439 439 tags = latesttags[2]
440 440 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':')
441 441 return _hybrid(f, tags, makemap, pycompat.identity)
442 442
443 443 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'})
444 444 def showlatesttagdistance(context, mapping):
445 445 """Integer. Longest path to the latest tag."""
446 446 return getlatesttags(context, mapping)[1]
447 447
448 448 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
449 449 def showchangessincelatesttag(context, mapping):
450 450 """Integer. All ancestors not in the latest tag."""
451 451 tag = getlatesttags(context, mapping)[2][0]
452 452 mapping = context.overlaymap(mapping, {'tag': tag})
453 453 return _showchangessincetag(context, mapping)
454 454
455 455 def _showchangessincetag(context, mapping):
456 456 repo = context.resource(mapping, 'repo')
457 457 ctx = context.resource(mapping, 'ctx')
458 458 offset = 0
459 459 revs = [ctx.rev()]
460 460 tag = context.symbol(mapping, 'tag')
461 461
462 462 # The only() revset doesn't currently support wdir()
463 463 if ctx.rev() is None:
464 464 offset = 1
465 465 revs = [p.rev() for p in ctx.parents()]
466 466
467 467 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
468 468
469 469 # teach templater latesttags.changes is switched to (context, mapping) API
470 470 _showchangessincetag._requires = {'repo', 'ctx'}
471 471
472 472 @templatekeyword('manifest', requires={'repo', 'ctx'})
473 473 def showmanifest(context, mapping):
474 474 repo = context.resource(mapping, 'repo')
475 475 ctx = context.resource(mapping, 'ctx')
476 476 mnode = ctx.manifestnode()
477 477 if mnode is None:
478 478 # just avoid crash, we might want to use the 'ff...' hash in future
479 479 return
480 480 mrev = repo.manifestlog.rev(mnode)
481 481 mhex = hex(mnode)
482 482 mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex})
483 483 f = context.process('manifest', mapping)
484 # TODO: perhaps 'ctx' should be dropped from mapping because manifest
485 # rev and node are completely different from changeset's.
486 484 return templateutil.hybriditem(f, None, f,
487 485 lambda x: {'rev': mrev, 'node': mhex})
488 486
489 487 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'})
490 488 def showobsfate(context, mapping):
491 489 # this function returns a list containing pre-formatted obsfate strings.
492 490 #
493 491 # This function will be replaced by templates fragments when we will have
494 492 # the verbosity templatekw available.
495 493 succsandmarkers = showsuccsandmarkers(context, mapping)
496 494
497 495 ui = context.resource(mapping, 'ui')
498 496 repo = context.resource(mapping, 'repo')
499 497 values = []
500 498
501 499 for x in succsandmarkers.tovalue(context, mapping):
502 500 v = obsutil.obsfateprinter(ui, repo, x['successors'], x['markers'],
503 501 scmutil.formatchangeid)
504 502 values.append(v)
505 503
506 504 return compatlist(context, mapping, "fate", values)
507 505
508 506 def shownames(context, mapping, namespace):
509 507 """helper method to generate a template keyword for a namespace"""
510 508 repo = context.resource(mapping, 'repo')
511 509 ctx = context.resource(mapping, 'ctx')
512 510 ns = repo.names[namespace]
513 511 names = ns.names(repo, ctx.node())
514 512 return compatlist(context, mapping, ns.templatename, names,
515 513 plural=namespace)
516 514
517 515 @templatekeyword('namespaces', requires={'repo', 'ctx'})
518 516 def shownamespaces(context, mapping):
519 517 """Dict of lists. Names attached to this changeset per
520 518 namespace."""
521 519 repo = context.resource(mapping, 'repo')
522 520 ctx = context.resource(mapping, 'ctx')
523 521
524 522 namespaces = util.sortdict()
525 523 def makensmapfn(ns):
526 524 # 'name' for iterating over namespaces, templatename for local reference
527 525 return lambda v: {'name': v, ns.templatename: v}
528 526
529 527 for k, ns in repo.names.iteritems():
530 528 names = ns.names(repo, ctx.node())
531 529 f = _showcompatlist(context, mapping, 'name', names)
532 530 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
533 531
534 532 f = _showcompatlist(context, mapping, 'namespace', list(namespaces))
535 533
536 534 def makemap(ns):
537 535 return {
538 536 'namespace': ns,
539 537 'names': namespaces[ns],
540 538 'builtin': repo.names[ns].builtin,
541 539 'colorname': repo.names[ns].colorname,
542 540 }
543 541
544 542 return _hybrid(f, namespaces, makemap, pycompat.identity)
545 543
546 544 @templatekeyword('node', requires={'ctx'})
547 545 def shownode(context, mapping):
548 546 """String. The changeset identification hash, as a 40 hexadecimal
549 547 digit string.
550 548 """
551 549 ctx = context.resource(mapping, 'ctx')
552 550 return ctx.hex()
553 551
554 552 @templatekeyword('obsolete', requires={'ctx'})
555 553 def showobsolete(context, mapping):
556 554 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
557 555 ctx = context.resource(mapping, 'ctx')
558 556 if ctx.obsolete():
559 557 return 'obsolete'
560 558 return ''
561 559
562 560 @templatekeyword('path', requires={'fctx'})
563 561 def showpath(context, mapping):
564 562 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
565 563 fctx = context.resource(mapping, 'fctx')
566 564 return fctx.path()
567 565
568 566 @templatekeyword('peerurls', requires={'repo'})
569 567 def showpeerurls(context, mapping):
570 568 """A dictionary of repository locations defined in the [paths] section
571 569 of your configuration file."""
572 570 repo = context.resource(mapping, 'repo')
573 571 # see commands.paths() for naming of dictionary keys
574 572 paths = repo.ui.paths
575 573 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
576 574 def makemap(k):
577 575 p = paths[k]
578 576 d = {'name': k, 'url': p.rawloc}
579 577 d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
580 578 return d
581 579 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k]))
582 580
583 581 @templatekeyword("predecessors", requires={'repo', 'ctx'})
584 582 def showpredecessors(context, mapping):
585 583 """Returns the list if the closest visible successors. (EXPERIMENTAL)"""
586 584 repo = context.resource(mapping, 'repo')
587 585 ctx = context.resource(mapping, 'ctx')
588 586 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
589 587 predecessors = pycompat.maplist(hex, predecessors)
590 588
591 589 return _hybrid(None, predecessors,
592 590 lambda x: {'ctx': repo[x]},
593 591 lambda x: scmutil.formatchangeid(repo[x]))
594 592
595 593 @templatekeyword('reporoot', requires={'repo'})
596 594 def showreporoot(context, mapping):
597 595 """String. The root directory of the current repository."""
598 596 repo = context.resource(mapping, 'repo')
599 597 return repo.root
600 598
601 599 @templatekeyword('size', requires={'fctx'})
602 600 def showsize(context, mapping):
603 601 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
604 602 fctx = context.resource(mapping, 'fctx')
605 603 return fctx.size()
606 604
607 605 # requires 'fctx' to denote {status} depends on (ctx, path) pair
608 606 @templatekeyword('status', requires={'ctx', 'fctx', 'revcache'})
609 607 def showstatus(context, mapping):
610 608 """String. Status code of the current file. (EXPERIMENTAL)"""
611 609 path = templateutil.runsymbol(context, mapping, 'path')
612 610 path = templateutil.stringify(context, mapping, path)
613 611 if not path:
614 612 return
615 613 statmap = _getfilestatusmap(context, mapping)
616 614 if path not in statmap:
617 615 statmap = _getfilestatusmap(context, mapping, listall=True)
618 616 return statmap.get(path)
619 617
620 618 @templatekeyword("successorssets", requires={'repo', 'ctx'})
621 619 def showsuccessorssets(context, mapping):
622 620 """Returns a string of sets of successors for a changectx. Format used
623 621 is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2
624 622 while also diverged into ctx3. (EXPERIMENTAL)"""
625 623 repo = context.resource(mapping, 'repo')
626 624 ctx = context.resource(mapping, 'ctx')
627 625 if not ctx.obsolete():
628 626 return ''
629 627
630 628 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
631 629 ssets = [[hex(n) for n in ss] for ss in ssets]
632 630
633 631 data = []
634 632 for ss in ssets:
635 633 h = _hybrid(None, ss, lambda x: {'ctx': repo[x]},
636 634 lambda x: scmutil.formatchangeid(repo[x]))
637 635 data.append(h)
638 636
639 637 # Format the successorssets
640 638 def render(d):
641 639 return templateutil.stringify(context, mapping, d)
642 640
643 641 def gen(data):
644 642 yield "; ".join(render(d) for d in data)
645 643
646 644 return _hybrid(gen(data), data, lambda x: {'successorset': x},
647 645 pycompat.identity)
648 646
649 647 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'})
650 648 def showsuccsandmarkers(context, mapping):
651 649 """Returns a list of dict for each final successor of ctx. The dict
652 650 contains successors node id in "successors" keys and the list of
653 651 obs-markers from ctx to the set of successors in "markers".
654 652 (EXPERIMENTAL)
655 653 """
656 654 repo = context.resource(mapping, 'repo')
657 655 ctx = context.resource(mapping, 'ctx')
658 656
659 657 values = obsutil.successorsandmarkers(repo, ctx)
660 658
661 659 if values is None:
662 660 values = []
663 661
664 662 # Format successors and markers to avoid exposing binary to templates
665 663 data = []
666 664 for i in values:
667 665 # Format successors
668 666 successors = i['successors']
669 667
670 668 successors = [hex(n) for n in successors]
671 669 successors = _hybrid(None, successors,
672 670 lambda x: {'ctx': repo[x]},
673 671 lambda x: scmutil.formatchangeid(repo[x]))
674 672
675 673 # Format markers
676 674 finalmarkers = []
677 675 for m in i['markers']:
678 676 hexprec = hex(m[0])
679 677 hexsucs = tuple(hex(n) for n in m[1])
680 678 hexparents = None
681 679 if m[5] is not None:
682 680 hexparents = tuple(hex(n) for n in m[5])
683 681 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
684 682 finalmarkers.append(newmarker)
685 683
686 684 data.append({'successors': successors, 'markers': finalmarkers})
687 685
688 686 return templateutil.mappinglist(data)
689 687
690 688 @templatekeyword('p1rev', requires={'ctx'})
691 689 def showp1rev(context, mapping):
692 690 """Integer. The repository-local revision number of the changeset's
693 691 first parent, or -1 if the changeset has no parents."""
694 692 ctx = context.resource(mapping, 'ctx')
695 693 return ctx.p1().rev()
696 694
697 695 @templatekeyword('p2rev', requires={'ctx'})
698 696 def showp2rev(context, mapping):
699 697 """Integer. The repository-local revision number of the changeset's
700 698 second parent, or -1 if the changeset has no second parent."""
701 699 ctx = context.resource(mapping, 'ctx')
702 700 return ctx.p2().rev()
703 701
704 702 @templatekeyword('p1node', requires={'ctx'})
705 703 def showp1node(context, mapping):
706 704 """String. The identification hash of the changeset's first parent,
707 705 as a 40 digit hexadecimal string. If the changeset has no parents, all
708 706 digits are 0."""
709 707 ctx = context.resource(mapping, 'ctx')
710 708 return ctx.p1().hex()
711 709
712 710 @templatekeyword('p2node', requires={'ctx'})
713 711 def showp2node(context, mapping):
714 712 """String. The identification hash of the changeset's second
715 713 parent, as a 40 digit hexadecimal string. If the changeset has no second
716 714 parent, all digits are 0."""
717 715 ctx = context.resource(mapping, 'ctx')
718 716 return ctx.p2().hex()
719 717
720 718 @templatekeyword('parents', requires={'repo', 'ctx'})
721 719 def showparents(context, mapping):
722 720 """List of strings. The parents of the changeset in "rev:node"
723 721 format. If the changeset has only one "natural" parent (the predecessor
724 722 revision) nothing is shown."""
725 723 repo = context.resource(mapping, 'repo')
726 724 ctx = context.resource(mapping, 'ctx')
727 725 pctxs = scmutil.meaningfulparents(repo, ctx)
728 726 prevs = [p.rev() for p in pctxs]
729 727 parents = [[('rev', p.rev()),
730 728 ('node', p.hex()),
731 729 ('phase', p.phasestr())]
732 730 for p in pctxs]
733 731 f = _showcompatlist(context, mapping, 'parent', parents)
734 732 return _hybrid(f, prevs, lambda x: {'ctx': repo[x]},
735 733 lambda x: scmutil.formatchangeid(repo[x]), keytype=int)
736 734
737 735 @templatekeyword('phase', requires={'ctx'})
738 736 def showphase(context, mapping):
739 737 """String. The changeset phase name."""
740 738 ctx = context.resource(mapping, 'ctx')
741 739 return ctx.phasestr()
742 740
743 741 @templatekeyword('phaseidx', requires={'ctx'})
744 742 def showphaseidx(context, mapping):
745 743 """Integer. The changeset phase index. (ADVANCED)"""
746 744 ctx = context.resource(mapping, 'ctx')
747 745 return ctx.phase()
748 746
749 747 @templatekeyword('rev', requires={'ctx'})
750 748 def showrev(context, mapping):
751 749 """Integer. The repository-local changeset revision number."""
752 750 ctx = context.resource(mapping, 'ctx')
753 751 return scmutil.intrev(ctx)
754 752
755 753 def showrevslist(context, mapping, name, revs):
756 754 """helper to generate a list of revisions in which a mapped template will
757 755 be evaluated"""
758 756 repo = context.resource(mapping, 'repo')
759 757 f = _showcompatlist(context, mapping, name, ['%d' % r for r in revs])
760 758 return _hybrid(f, revs,
761 759 lambda x: {name: x, 'ctx': repo[x]},
762 760 pycompat.identity, keytype=int)
763 761
764 762 @templatekeyword('subrepos', requires={'ctx'})
765 763 def showsubrepos(context, mapping):
766 764 """List of strings. Updated subrepositories in the changeset."""
767 765 ctx = context.resource(mapping, 'ctx')
768 766 substate = ctx.substate
769 767 if not substate:
770 768 return compatlist(context, mapping, 'subrepo', [])
771 769 psubstate = ctx.parents()[0].substate or {}
772 770 subrepos = []
773 771 for sub in substate:
774 772 if sub not in psubstate or substate[sub] != psubstate[sub]:
775 773 subrepos.append(sub) # modified or newly added in ctx
776 774 for sub in psubstate:
777 775 if sub not in substate:
778 776 subrepos.append(sub) # removed in ctx
779 777 return compatlist(context, mapping, 'subrepo', sorted(subrepos))
780 778
781 779 # don't remove "showtags" definition, even though namespaces will put
782 780 # a helper function for "tags" keyword into "keywords" map automatically,
783 781 # because online help text is built without namespaces initialization
784 782 @templatekeyword('tags', requires={'repo', 'ctx'})
785 783 def showtags(context, mapping):
786 784 """List of strings. Any tags associated with the changeset."""
787 785 return shownames(context, mapping, 'tags')
788 786
789 787 @templatekeyword('termwidth', requires={'ui'})
790 788 def showtermwidth(context, mapping):
791 789 """Integer. The width of the current terminal."""
792 790 ui = context.resource(mapping, 'ui')
793 791 return ui.termwidth()
794 792
795 793 @templatekeyword('user', requires={'ctx'})
796 794 def showuser(context, mapping):
797 795 """String. The unmodified author of the changeset."""
798 796 ctx = context.resource(mapping, 'ctx')
799 797 return ctx.user()
800 798
801 799 @templatekeyword('instabilities', requires={'ctx'})
802 800 def showinstabilities(context, mapping):
803 801 """List of strings. Evolution instabilities affecting the changeset.
804 802 (EXPERIMENTAL)
805 803 """
806 804 ctx = context.resource(mapping, 'ctx')
807 805 return compatlist(context, mapping, 'instability', ctx.instabilities(),
808 806 plural='instabilities')
809 807
810 808 @templatekeyword('verbosity', requires={'ui'})
811 809 def showverbosity(context, mapping):
812 810 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
813 811 or ''."""
814 812 ui = context.resource(mapping, 'ui')
815 813 # see logcmdutil.changesettemplater for priority of these flags
816 814 if ui.debugflag:
817 815 return 'debug'
818 816 elif ui.quiet:
819 817 return 'quiet'
820 818 elif ui.verbose:
821 819 return 'verbose'
822 820 return ''
823 821
824 822 @templatekeyword('whyunstable', requires={'repo', 'ctx'})
825 823 def showwhyunstable(context, mapping):
826 824 """List of dicts explaining all instabilities of a changeset.
827 825 (EXPERIMENTAL)
828 826 """
829 827 repo = context.resource(mapping, 'repo')
830 828 ctx = context.resource(mapping, 'ctx')
831 829
832 830 def formatnode(ctx):
833 831 return '%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
834 832
835 833 entries = obsutil.whyunstable(repo, ctx)
836 834
837 835 for entry in entries:
838 836 if entry.get('divergentnodes'):
839 837 dnodes = entry['divergentnodes']
840 838 dnhybrid = _hybrid(None, [dnode.hex() for dnode in dnodes],
841 839 lambda x: {'ctx': repo[x]},
842 840 lambda x: formatnode(repo[x]))
843 841 entry['divergentnodes'] = dnhybrid
844 842
845 843 tmpl = ('{instability}:{if(divergentnodes, " ")}{divergentnodes} '
846 844 '{reason} {node|short}')
847 845 return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n')
848 846
849 847 def loadkeyword(ui, extname, registrarobj):
850 848 """Load template keyword from specified registrarobj
851 849 """
852 850 for name, func in registrarobj._table.iteritems():
853 851 keywords[name] = func
854 852
855 853 # tell hggettext to extract docstrings from these functions:
856 854 i18nfunctions = keywords.values()
@@ -1,1280 +1,1285 b''
1 1 Test template keywords
2 2 ======================
3 3
4 4 $ hg init a
5 5 $ cd a
6 6 $ echo a > a
7 7 $ hg add a
8 8 $ echo line 1 > b
9 9 $ echo line 2 >> b
10 10 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
11 11
12 12 $ hg add b
13 13 $ echo other 1 > c
14 14 $ echo other 2 >> c
15 15 $ echo >> c
16 16 $ echo other 3 >> c
17 17 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
18 18
19 19 $ hg add c
20 20 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
21 21 $ echo c >> c
22 22 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
23 23
24 24 $ echo foo > .hg/branch
25 25 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
26 26
27 27 $ hg co -q 3
28 28 $ echo other 4 >> d
29 29 $ hg add d
30 30 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
31 31
32 32 $ hg merge -q foo
33 33 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
34 34
35 35 Second branch starting at nullrev:
36 36
37 37 $ hg update null
38 38 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
39 39 $ echo second > second
40 40 $ hg add second
41 41 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
42 42 created new head
43 43
44 44 $ echo third > third
45 45 $ hg add third
46 46 $ hg mv second fourth
47 47 $ hg commit -m third -d "2020-01-01 10:01"
48 48
49 49 Working-directory revision has special identifiers, though they are still
50 50 experimental:
51 51
52 52 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
53 53 2147483647:ffffffffffffffffffffffffffffffffffffffff
54 54
55 55 Some keywords are invalid for working-directory revision, but they should
56 56 never cause crash:
57 57
58 58 $ hg log -r 'wdir()' -T '{manifest}\n'
59 59
60 60
61 Changectx-derived keywords are disabled within {manifest} as {node} changes:
62
63 $ hg log -r0 -T 'outer:{p1node} {manifest % "inner:{p1node}"}\n'
64 outer:0000000000000000000000000000000000000000 inner:
65
61 66 Check that {phase} works correctly on parents:
62 67
63 68 $ cat << EOF > parentphase
64 69 > changeset_debug = '{rev} ({phase}):{parents}\n'
65 70 > parent = ' {rev} ({phase})'
66 71 > EOF
67 72 $ hg phase -r 5 --public
68 73 $ hg phase -r 7 --secret --force
69 74 $ hg log --debug -G --style ./parentphase
70 75 @ 8 (secret): 7 (secret) -1 (public)
71 76 |
72 77 o 7 (secret): -1 (public) -1 (public)
73 78
74 79 o 6 (draft): 5 (public) 4 (draft)
75 80 |\
76 81 | o 5 (public): 3 (public) -1 (public)
77 82 | |
78 83 o | 4 (draft): 3 (public) -1 (public)
79 84 |/
80 85 o 3 (public): 2 (public) -1 (public)
81 86 |
82 87 o 2 (public): 1 (public) -1 (public)
83 88 |
84 89 o 1 (public): 0 (public) -1 (public)
85 90 |
86 91 o 0 (public): -1 (public) -1 (public)
87 92
88 93
89 94 Keys work:
90 95
91 96 $ for key in author branch branches date desc file_adds file_dels file_mods \
92 97 > file_copies file_copies_switch files \
93 98 > manifest node parents rev tags diffstat extras \
94 99 > p1rev p2rev p1node p2node user; do
95 100 > for mode in '' --verbose --debug; do
96 101 > hg log $mode --template "$key$mode: {$key}\n"
97 102 > done
98 103 > done
99 104 author: test
100 105 author: User Name <user@hostname>
101 106 author: person
102 107 author: person
103 108 author: person
104 109 author: person
105 110 author: other@place
106 111 author: A. N. Other <other@place>
107 112 author: User Name <user@hostname>
108 113 author--verbose: test
109 114 author--verbose: User Name <user@hostname>
110 115 author--verbose: person
111 116 author--verbose: person
112 117 author--verbose: person
113 118 author--verbose: person
114 119 author--verbose: other@place
115 120 author--verbose: A. N. Other <other@place>
116 121 author--verbose: User Name <user@hostname>
117 122 author--debug: test
118 123 author--debug: User Name <user@hostname>
119 124 author--debug: person
120 125 author--debug: person
121 126 author--debug: person
122 127 author--debug: person
123 128 author--debug: other@place
124 129 author--debug: A. N. Other <other@place>
125 130 author--debug: User Name <user@hostname>
126 131 branch: default
127 132 branch: default
128 133 branch: default
129 134 branch: default
130 135 branch: foo
131 136 branch: default
132 137 branch: default
133 138 branch: default
134 139 branch: default
135 140 branch--verbose: default
136 141 branch--verbose: default
137 142 branch--verbose: default
138 143 branch--verbose: default
139 144 branch--verbose: foo
140 145 branch--verbose: default
141 146 branch--verbose: default
142 147 branch--verbose: default
143 148 branch--verbose: default
144 149 branch--debug: default
145 150 branch--debug: default
146 151 branch--debug: default
147 152 branch--debug: default
148 153 branch--debug: foo
149 154 branch--debug: default
150 155 branch--debug: default
151 156 branch--debug: default
152 157 branch--debug: default
153 158 branches:
154 159 branches:
155 160 branches:
156 161 branches:
157 162 branches: foo
158 163 branches:
159 164 branches:
160 165 branches:
161 166 branches:
162 167 branches--verbose:
163 168 branches--verbose:
164 169 branches--verbose:
165 170 branches--verbose:
166 171 branches--verbose: foo
167 172 branches--verbose:
168 173 branches--verbose:
169 174 branches--verbose:
170 175 branches--verbose:
171 176 branches--debug:
172 177 branches--debug:
173 178 branches--debug:
174 179 branches--debug:
175 180 branches--debug: foo
176 181 branches--debug:
177 182 branches--debug:
178 183 branches--debug:
179 184 branches--debug:
180 185 date: 1577872860.00
181 186 date: 1000000.00
182 187 date: 1500001.00
183 188 date: 1500000.00
184 189 date: 1400000.00
185 190 date: 1300000.00
186 191 date: 1200000.00
187 192 date: 1100000.00
188 193 date: 1000000.00
189 194 date--verbose: 1577872860.00
190 195 date--verbose: 1000000.00
191 196 date--verbose: 1500001.00
192 197 date--verbose: 1500000.00
193 198 date--verbose: 1400000.00
194 199 date--verbose: 1300000.00
195 200 date--verbose: 1200000.00
196 201 date--verbose: 1100000.00
197 202 date--verbose: 1000000.00
198 203 date--debug: 1577872860.00
199 204 date--debug: 1000000.00
200 205 date--debug: 1500001.00
201 206 date--debug: 1500000.00
202 207 date--debug: 1400000.00
203 208 date--debug: 1300000.00
204 209 date--debug: 1200000.00
205 210 date--debug: 1100000.00
206 211 date--debug: 1000000.00
207 212 desc: third
208 213 desc: second
209 214 desc: merge
210 215 desc: new head
211 216 desc: new branch
212 217 desc: no user, no domain
213 218 desc: no person
214 219 desc: other 1
215 220 other 2
216 221
217 222 other 3
218 223 desc: line 1
219 224 line 2
220 225 desc--verbose: third
221 226 desc--verbose: second
222 227 desc--verbose: merge
223 228 desc--verbose: new head
224 229 desc--verbose: new branch
225 230 desc--verbose: no user, no domain
226 231 desc--verbose: no person
227 232 desc--verbose: other 1
228 233 other 2
229 234
230 235 other 3
231 236 desc--verbose: line 1
232 237 line 2
233 238 desc--debug: third
234 239 desc--debug: second
235 240 desc--debug: merge
236 241 desc--debug: new head
237 242 desc--debug: new branch
238 243 desc--debug: no user, no domain
239 244 desc--debug: no person
240 245 desc--debug: other 1
241 246 other 2
242 247
243 248 other 3
244 249 desc--debug: line 1
245 250 line 2
246 251 file_adds: fourth third
247 252 file_adds: second
248 253 file_adds:
249 254 file_adds: d
250 255 file_adds:
251 256 file_adds:
252 257 file_adds: c
253 258 file_adds: b
254 259 file_adds: a
255 260 file_adds--verbose: fourth third
256 261 file_adds--verbose: second
257 262 file_adds--verbose:
258 263 file_adds--verbose: d
259 264 file_adds--verbose:
260 265 file_adds--verbose:
261 266 file_adds--verbose: c
262 267 file_adds--verbose: b
263 268 file_adds--verbose: a
264 269 file_adds--debug: fourth third
265 270 file_adds--debug: second
266 271 file_adds--debug:
267 272 file_adds--debug: d
268 273 file_adds--debug:
269 274 file_adds--debug:
270 275 file_adds--debug: c
271 276 file_adds--debug: b
272 277 file_adds--debug: a
273 278 file_dels: second
274 279 file_dels:
275 280 file_dels:
276 281 file_dels:
277 282 file_dels:
278 283 file_dels:
279 284 file_dels:
280 285 file_dels:
281 286 file_dels:
282 287 file_dels--verbose: second
283 288 file_dels--verbose:
284 289 file_dels--verbose:
285 290 file_dels--verbose:
286 291 file_dels--verbose:
287 292 file_dels--verbose:
288 293 file_dels--verbose:
289 294 file_dels--verbose:
290 295 file_dels--verbose:
291 296 file_dels--debug: second
292 297 file_dels--debug:
293 298 file_dels--debug:
294 299 file_dels--debug:
295 300 file_dels--debug:
296 301 file_dels--debug:
297 302 file_dels--debug:
298 303 file_dels--debug:
299 304 file_dels--debug:
300 305 file_mods:
301 306 file_mods:
302 307 file_mods:
303 308 file_mods:
304 309 file_mods:
305 310 file_mods: c
306 311 file_mods:
307 312 file_mods:
308 313 file_mods:
309 314 file_mods--verbose:
310 315 file_mods--verbose:
311 316 file_mods--verbose:
312 317 file_mods--verbose:
313 318 file_mods--verbose:
314 319 file_mods--verbose: c
315 320 file_mods--verbose:
316 321 file_mods--verbose:
317 322 file_mods--verbose:
318 323 file_mods--debug:
319 324 file_mods--debug:
320 325 file_mods--debug:
321 326 file_mods--debug:
322 327 file_mods--debug:
323 328 file_mods--debug: c
324 329 file_mods--debug:
325 330 file_mods--debug:
326 331 file_mods--debug:
327 332 file_copies: fourth (second)
328 333 file_copies:
329 334 file_copies:
330 335 file_copies:
331 336 file_copies:
332 337 file_copies:
333 338 file_copies:
334 339 file_copies:
335 340 file_copies:
336 341 file_copies--verbose: fourth (second)
337 342 file_copies--verbose:
338 343 file_copies--verbose:
339 344 file_copies--verbose:
340 345 file_copies--verbose:
341 346 file_copies--verbose:
342 347 file_copies--verbose:
343 348 file_copies--verbose:
344 349 file_copies--verbose:
345 350 file_copies--debug: fourth (second)
346 351 file_copies--debug:
347 352 file_copies--debug:
348 353 file_copies--debug:
349 354 file_copies--debug:
350 355 file_copies--debug:
351 356 file_copies--debug:
352 357 file_copies--debug:
353 358 file_copies--debug:
354 359 file_copies_switch:
355 360 file_copies_switch:
356 361 file_copies_switch:
357 362 file_copies_switch:
358 363 file_copies_switch:
359 364 file_copies_switch:
360 365 file_copies_switch:
361 366 file_copies_switch:
362 367 file_copies_switch:
363 368 file_copies_switch--verbose:
364 369 file_copies_switch--verbose:
365 370 file_copies_switch--verbose:
366 371 file_copies_switch--verbose:
367 372 file_copies_switch--verbose:
368 373 file_copies_switch--verbose:
369 374 file_copies_switch--verbose:
370 375 file_copies_switch--verbose:
371 376 file_copies_switch--verbose:
372 377 file_copies_switch--debug:
373 378 file_copies_switch--debug:
374 379 file_copies_switch--debug:
375 380 file_copies_switch--debug:
376 381 file_copies_switch--debug:
377 382 file_copies_switch--debug:
378 383 file_copies_switch--debug:
379 384 file_copies_switch--debug:
380 385 file_copies_switch--debug:
381 386 files: fourth second third
382 387 files: second
383 388 files:
384 389 files: d
385 390 files:
386 391 files: c
387 392 files: c
388 393 files: b
389 394 files: a
390 395 files--verbose: fourth second third
391 396 files--verbose: second
392 397 files--verbose:
393 398 files--verbose: d
394 399 files--verbose:
395 400 files--verbose: c
396 401 files--verbose: c
397 402 files--verbose: b
398 403 files--verbose: a
399 404 files--debug: fourth second third
400 405 files--debug: second
401 406 files--debug:
402 407 files--debug: d
403 408 files--debug:
404 409 files--debug: c
405 410 files--debug: c
406 411 files--debug: b
407 412 files--debug: a
408 413 manifest: 6:94961b75a2da
409 414 manifest: 5:f2dbc354b94e
410 415 manifest: 4:4dc3def4f9b4
411 416 manifest: 4:4dc3def4f9b4
412 417 manifest: 3:cb5a1327723b
413 418 manifest: 3:cb5a1327723b
414 419 manifest: 2:6e0e82995c35
415 420 manifest: 1:4e8d705b1e53
416 421 manifest: 0:a0c8bcbbb45c
417 422 manifest--verbose: 6:94961b75a2da
418 423 manifest--verbose: 5:f2dbc354b94e
419 424 manifest--verbose: 4:4dc3def4f9b4
420 425 manifest--verbose: 4:4dc3def4f9b4
421 426 manifest--verbose: 3:cb5a1327723b
422 427 manifest--verbose: 3:cb5a1327723b
423 428 manifest--verbose: 2:6e0e82995c35
424 429 manifest--verbose: 1:4e8d705b1e53
425 430 manifest--verbose: 0:a0c8bcbbb45c
426 431 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
427 432 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
428 433 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
429 434 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
430 435 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
431 436 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
432 437 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
433 438 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
434 439 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
435 440 node: 95c24699272ef57d062b8bccc32c878bf841784a
436 441 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
437 442 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
438 443 node: 13207e5a10d9fd28ec424934298e176197f2c67f
439 444 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
440 445 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
441 446 node: 97054abb4ab824450e9164180baf491ae0078465
442 447 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
443 448 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
444 449 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
445 450 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
446 451 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
447 452 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
448 453 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
449 454 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
450 455 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
451 456 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
452 457 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
453 458 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
454 459 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
455 460 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
456 461 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
457 462 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
458 463 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
459 464 node--debug: 97054abb4ab824450e9164180baf491ae0078465
460 465 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
461 466 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
462 467 parents:
463 468 parents: -1:000000000000
464 469 parents: 5:13207e5a10d9 4:bbe44766e73d
465 470 parents: 3:10e46f2dcbf4
466 471 parents:
467 472 parents:
468 473 parents:
469 474 parents:
470 475 parents:
471 476 parents--verbose:
472 477 parents--verbose: -1:000000000000
473 478 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
474 479 parents--verbose: 3:10e46f2dcbf4
475 480 parents--verbose:
476 481 parents--verbose:
477 482 parents--verbose:
478 483 parents--verbose:
479 484 parents--verbose:
480 485 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
481 486 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
482 487 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
483 488 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
484 489 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
485 490 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
486 491 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
487 492 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
488 493 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
489 494 rev: 8
490 495 rev: 7
491 496 rev: 6
492 497 rev: 5
493 498 rev: 4
494 499 rev: 3
495 500 rev: 2
496 501 rev: 1
497 502 rev: 0
498 503 rev--verbose: 8
499 504 rev--verbose: 7
500 505 rev--verbose: 6
501 506 rev--verbose: 5
502 507 rev--verbose: 4
503 508 rev--verbose: 3
504 509 rev--verbose: 2
505 510 rev--verbose: 1
506 511 rev--verbose: 0
507 512 rev--debug: 8
508 513 rev--debug: 7
509 514 rev--debug: 6
510 515 rev--debug: 5
511 516 rev--debug: 4
512 517 rev--debug: 3
513 518 rev--debug: 2
514 519 rev--debug: 1
515 520 rev--debug: 0
516 521 tags: tip
517 522 tags:
518 523 tags:
519 524 tags:
520 525 tags:
521 526 tags:
522 527 tags:
523 528 tags:
524 529 tags:
525 530 tags--verbose: tip
526 531 tags--verbose:
527 532 tags--verbose:
528 533 tags--verbose:
529 534 tags--verbose:
530 535 tags--verbose:
531 536 tags--verbose:
532 537 tags--verbose:
533 538 tags--verbose:
534 539 tags--debug: tip
535 540 tags--debug:
536 541 tags--debug:
537 542 tags--debug:
538 543 tags--debug:
539 544 tags--debug:
540 545 tags--debug:
541 546 tags--debug:
542 547 tags--debug:
543 548 diffstat: 3: +2/-1
544 549 diffstat: 1: +1/-0
545 550 diffstat: 0: +0/-0
546 551 diffstat: 1: +1/-0
547 552 diffstat: 0: +0/-0
548 553 diffstat: 1: +1/-0
549 554 diffstat: 1: +4/-0
550 555 diffstat: 1: +2/-0
551 556 diffstat: 1: +1/-0
552 557 diffstat--verbose: 3: +2/-1
553 558 diffstat--verbose: 1: +1/-0
554 559 diffstat--verbose: 0: +0/-0
555 560 diffstat--verbose: 1: +1/-0
556 561 diffstat--verbose: 0: +0/-0
557 562 diffstat--verbose: 1: +1/-0
558 563 diffstat--verbose: 1: +4/-0
559 564 diffstat--verbose: 1: +2/-0
560 565 diffstat--verbose: 1: +1/-0
561 566 diffstat--debug: 3: +2/-1
562 567 diffstat--debug: 1: +1/-0
563 568 diffstat--debug: 0: +0/-0
564 569 diffstat--debug: 1: +1/-0
565 570 diffstat--debug: 0: +0/-0
566 571 diffstat--debug: 1: +1/-0
567 572 diffstat--debug: 1: +4/-0
568 573 diffstat--debug: 1: +2/-0
569 574 diffstat--debug: 1: +1/-0
570 575 extras: branch=default
571 576 extras: branch=default
572 577 extras: branch=default
573 578 extras: branch=default
574 579 extras: branch=foo
575 580 extras: branch=default
576 581 extras: branch=default
577 582 extras: branch=default
578 583 extras: branch=default
579 584 extras--verbose: branch=default
580 585 extras--verbose: branch=default
581 586 extras--verbose: branch=default
582 587 extras--verbose: branch=default
583 588 extras--verbose: branch=foo
584 589 extras--verbose: branch=default
585 590 extras--verbose: branch=default
586 591 extras--verbose: branch=default
587 592 extras--verbose: branch=default
588 593 extras--debug: branch=default
589 594 extras--debug: branch=default
590 595 extras--debug: branch=default
591 596 extras--debug: branch=default
592 597 extras--debug: branch=foo
593 598 extras--debug: branch=default
594 599 extras--debug: branch=default
595 600 extras--debug: branch=default
596 601 extras--debug: branch=default
597 602 p1rev: 7
598 603 p1rev: -1
599 604 p1rev: 5
600 605 p1rev: 3
601 606 p1rev: 3
602 607 p1rev: 2
603 608 p1rev: 1
604 609 p1rev: 0
605 610 p1rev: -1
606 611 p1rev--verbose: 7
607 612 p1rev--verbose: -1
608 613 p1rev--verbose: 5
609 614 p1rev--verbose: 3
610 615 p1rev--verbose: 3
611 616 p1rev--verbose: 2
612 617 p1rev--verbose: 1
613 618 p1rev--verbose: 0
614 619 p1rev--verbose: -1
615 620 p1rev--debug: 7
616 621 p1rev--debug: -1
617 622 p1rev--debug: 5
618 623 p1rev--debug: 3
619 624 p1rev--debug: 3
620 625 p1rev--debug: 2
621 626 p1rev--debug: 1
622 627 p1rev--debug: 0
623 628 p1rev--debug: -1
624 629 p2rev: -1
625 630 p2rev: -1
626 631 p2rev: 4
627 632 p2rev: -1
628 633 p2rev: -1
629 634 p2rev: -1
630 635 p2rev: -1
631 636 p2rev: -1
632 637 p2rev: -1
633 638 p2rev--verbose: -1
634 639 p2rev--verbose: -1
635 640 p2rev--verbose: 4
636 641 p2rev--verbose: -1
637 642 p2rev--verbose: -1
638 643 p2rev--verbose: -1
639 644 p2rev--verbose: -1
640 645 p2rev--verbose: -1
641 646 p2rev--verbose: -1
642 647 p2rev--debug: -1
643 648 p2rev--debug: -1
644 649 p2rev--debug: 4
645 650 p2rev--debug: -1
646 651 p2rev--debug: -1
647 652 p2rev--debug: -1
648 653 p2rev--debug: -1
649 654 p2rev--debug: -1
650 655 p2rev--debug: -1
651 656 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
652 657 p1node: 0000000000000000000000000000000000000000
653 658 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
654 659 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
655 660 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
656 661 p1node: 97054abb4ab824450e9164180baf491ae0078465
657 662 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
658 663 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
659 664 p1node: 0000000000000000000000000000000000000000
660 665 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
661 666 p1node--verbose: 0000000000000000000000000000000000000000
662 667 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
663 668 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
664 669 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
665 670 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
666 671 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
667 672 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
668 673 p1node--verbose: 0000000000000000000000000000000000000000
669 674 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
670 675 p1node--debug: 0000000000000000000000000000000000000000
671 676 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
672 677 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
673 678 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
674 679 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
675 680 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
676 681 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
677 682 p1node--debug: 0000000000000000000000000000000000000000
678 683 p2node: 0000000000000000000000000000000000000000
679 684 p2node: 0000000000000000000000000000000000000000
680 685 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
681 686 p2node: 0000000000000000000000000000000000000000
682 687 p2node: 0000000000000000000000000000000000000000
683 688 p2node: 0000000000000000000000000000000000000000
684 689 p2node: 0000000000000000000000000000000000000000
685 690 p2node: 0000000000000000000000000000000000000000
686 691 p2node: 0000000000000000000000000000000000000000
687 692 p2node--verbose: 0000000000000000000000000000000000000000
688 693 p2node--verbose: 0000000000000000000000000000000000000000
689 694 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
690 695 p2node--verbose: 0000000000000000000000000000000000000000
691 696 p2node--verbose: 0000000000000000000000000000000000000000
692 697 p2node--verbose: 0000000000000000000000000000000000000000
693 698 p2node--verbose: 0000000000000000000000000000000000000000
694 699 p2node--verbose: 0000000000000000000000000000000000000000
695 700 p2node--verbose: 0000000000000000000000000000000000000000
696 701 p2node--debug: 0000000000000000000000000000000000000000
697 702 p2node--debug: 0000000000000000000000000000000000000000
698 703 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
699 704 p2node--debug: 0000000000000000000000000000000000000000
700 705 p2node--debug: 0000000000000000000000000000000000000000
701 706 p2node--debug: 0000000000000000000000000000000000000000
702 707 p2node--debug: 0000000000000000000000000000000000000000
703 708 p2node--debug: 0000000000000000000000000000000000000000
704 709 p2node--debug: 0000000000000000000000000000000000000000
705 710 user: test
706 711 user: User Name <user@hostname>
707 712 user: person
708 713 user: person
709 714 user: person
710 715 user: person
711 716 user: other@place
712 717 user: A. N. Other <other@place>
713 718 user: User Name <user@hostname>
714 719 user--verbose: test
715 720 user--verbose: User Name <user@hostname>
716 721 user--verbose: person
717 722 user--verbose: person
718 723 user--verbose: person
719 724 user--verbose: person
720 725 user--verbose: other@place
721 726 user--verbose: A. N. Other <other@place>
722 727 user--verbose: User Name <user@hostname>
723 728 user--debug: test
724 729 user--debug: User Name <user@hostname>
725 730 user--debug: person
726 731 user--debug: person
727 732 user--debug: person
728 733 user--debug: person
729 734 user--debug: other@place
730 735 user--debug: A. N. Other <other@place>
731 736 user--debug: User Name <user@hostname>
732 737
733 738 Add a dummy commit to make up for the instability of the above:
734 739
735 740 $ echo a > a
736 741 $ hg add a
737 742 $ hg ci -m future
738 743
739 744 Add a commit that does all possible modifications at once
740 745
741 746 $ echo modify >> third
742 747 $ touch b
743 748 $ hg add b
744 749 $ hg mv fourth fifth
745 750 $ hg rm a
746 751 $ hg ci -m "Modify, add, remove, rename"
747 752
748 753 Test files list:
749 754
750 755 $ hg log -l1 -T '{join(file_mods, " ")}\n'
751 756 third
752 757 $ hg log -l1 -T '{file_mods % "{file}\n"}'
753 758 third
754 759 $ hg log -l1 -T '{file_mods % "{path}\n"}'
755 760 third
756 761
757 762 $ hg log -l1 -T '{join(files, " ")}\n'
758 763 a b fifth fourth third
759 764 $ hg log -l1 -T '{files % "{file}\n"}'
760 765 a
761 766 b
762 767 fifth
763 768 fourth
764 769 third
765 770 $ hg log -l1 -T '{files % "{path}\n"}'
766 771 a
767 772 b
768 773 fifth
769 774 fourth
770 775 third
771 776
772 777 Test file copies dict:
773 778
774 779 $ hg log -r8 -T '{join(file_copies, " ")}\n'
775 780 fourth (second)
776 781 $ hg log -r8 -T '{file_copies % "{name} <- {source}\n"}'
777 782 fourth <- second
778 783 $ hg log -r8 -T '{file_copies % "{path} <- {source}\n"}'
779 784 fourth <- second
780 785
781 786 $ hg log -r8 -T '{join(file_copies_switch, " ")}\n'
782 787
783 788 $ hg log -r8 -C -T '{join(file_copies_switch, " ")}\n'
784 789 fourth (second)
785 790 $ hg log -r8 -C -T '{file_copies_switch % "{name} <- {source}\n"}'
786 791 fourth <- second
787 792 $ hg log -r8 -C -T '{file_copies_switch % "{path} <- {source}\n"}'
788 793 fourth <- second
789 794
790 795 Test file attributes:
791 796
792 797 $ hg log -l1 -T '{files % "{status} {pad(size, 3, left=True)} {path}\n"}'
793 798 R a
794 799 A 0 b
795 800 A 7 fifth
796 801 R fourth
797 802 M 13 third
798 803
799 804 Test file status including clean ones:
800 805
801 806 $ hg log -r9 -T '{files("**") % "{status} {path}\n"}'
802 807 A a
803 808 C fourth
804 809 C third
805 810
806 811 Test index keyword:
807 812
808 813 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
809 814 10 0:a 1:b 2:fifth 3:fourth 4:third
810 815 11 0:a
811 816
812 817 $ hg branches -T '{index} {branch}\n'
813 818 0 default
814 819 1 foo
815 820
816 821 ui verbosity:
817 822
818 823 $ hg log -l1 -T '{verbosity}\n'
819 824
820 825 $ hg log -l1 -T '{verbosity}\n' --debug
821 826 debug
822 827 $ hg log -l1 -T '{verbosity}\n' --quiet
823 828 quiet
824 829 $ hg log -l1 -T '{verbosity}\n' --verbose
825 830 verbose
826 831
827 832 $ cd ..
828 833
829 834 latesttag:
830 835
831 836 $ hg init latesttag
832 837 $ cd latesttag
833 838
834 839 $ echo a > file
835 840 $ hg ci -Am a -d '0 0'
836 841 adding file
837 842
838 843 $ echo b >> file
839 844 $ hg ci -m b -d '1 0'
840 845
841 846 $ echo c >> head1
842 847 $ hg ci -Am h1c -d '2 0'
843 848 adding head1
844 849
845 850 $ hg update -q 1
846 851 $ echo d >> head2
847 852 $ hg ci -Am h2d -d '3 0'
848 853 adding head2
849 854 created new head
850 855
851 856 $ echo e >> head2
852 857 $ hg ci -m h2e -d '4 0'
853 858
854 859 $ hg merge -q
855 860 $ hg ci -m merge -d '5 -3600'
856 861
857 862 No tag set:
858 863
859 864 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
860 865 @ 5: null+5
861 866 |\
862 867 | o 4: null+4
863 868 | |
864 869 | o 3: null+3
865 870 | |
866 871 o | 2: null+3
867 872 |/
868 873 o 1: null+2
869 874 |
870 875 o 0: null+1
871 876
872 877
873 878 One common tag: longest path wins for {latesttagdistance}:
874 879
875 880 $ hg tag -r 1 -m t1 -d '6 0' t1
876 881 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
877 882 @ 6: t1+4
878 883 |
879 884 o 5: t1+3
880 885 |\
881 886 | o 4: t1+2
882 887 | |
883 888 | o 3: t1+1
884 889 | |
885 890 o | 2: t1+1
886 891 |/
887 892 o 1: t1+0
888 893 |
889 894 o 0: null+1
890 895
891 896
892 897 One ancestor tag: closest wins:
893 898
894 899 $ hg tag -r 2 -m t2 -d '7 0' t2
895 900 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
896 901 @ 7: t2+3
897 902 |
898 903 o 6: t2+2
899 904 |
900 905 o 5: t2+1
901 906 |\
902 907 | o 4: t1+2
903 908 | |
904 909 | o 3: t1+1
905 910 | |
906 911 o | 2: t2+0
907 912 |/
908 913 o 1: t1+0
909 914 |
910 915 o 0: null+1
911 916
912 917
913 918 Two branch tags: more recent wins if same number of changes:
914 919
915 920 $ hg tag -r 3 -m t3 -d '8 0' t3
916 921 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
917 922 @ 8: t3+5
918 923 |
919 924 o 7: t3+4
920 925 |
921 926 o 6: t3+3
922 927 |
923 928 o 5: t3+2
924 929 |\
925 930 | o 4: t3+1
926 931 | |
927 932 | o 3: t3+0
928 933 | |
929 934 o | 2: t2+0
930 935 |/
931 936 o 1: t1+0
932 937 |
933 938 o 0: null+1
934 939
935 940
936 941 Two branch tags: fewest changes wins:
937 942
938 943 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
939 944 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
940 945 @ 9: t4+5,6
941 946 |
942 947 o 8: t4+4,5
943 948 |
944 949 o 7: t4+3,4
945 950 |
946 951 o 6: t4+2,3
947 952 |
948 953 o 5: t4+1,2
949 954 |\
950 955 | o 4: t4+0,0
951 956 | |
952 957 | o 3: t3+0,0
953 958 | |
954 959 o | 2: t2+0,0
955 960 |/
956 961 o 1: t1+0,0
957 962 |
958 963 o 0: null+1,1
959 964
960 965
961 966 Merged tag overrides:
962 967
963 968 $ hg tag -r 5 -m t5 -d '9 0' t5
964 969 $ hg tag -r 3 -m at3 -d '10 0' at3
965 970 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
966 971 @ 11: t5+6
967 972 |
968 973 o 10: t5+5
969 974 |
970 975 o 9: t5+4
971 976 |
972 977 o 8: t5+3
973 978 |
974 979 o 7: t5+2
975 980 |
976 981 o 6: t5+1
977 982 |
978 983 o 5: t5+0
979 984 |\
980 985 | o 4: t4+0
981 986 | |
982 987 | o 3: at3:t3+0
983 988 | |
984 989 o | 2: t2+0
985 990 |/
986 991 o 1: t1+0
987 992 |
988 993 o 0: null+1
989 994
990 995
991 996 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
992 997 @ 11: t5+6,6
993 998 |
994 999 o 10: t5+5,5
995 1000 |
996 1001 o 9: t5+4,4
997 1002 |
998 1003 o 8: t5+3,3
999 1004 |
1000 1005 o 7: t5+2,2
1001 1006 |
1002 1007 o 6: t5+1,1
1003 1008 |
1004 1009 o 5: t5+0,0
1005 1010 |\
1006 1011 | o 4: t4+0,0
1007 1012 | |
1008 1013 | o 3: at3+0,0 t3+0,0
1009 1014 | |
1010 1015 o | 2: t2+0,0
1011 1016 |/
1012 1017 o 1: t1+0,0
1013 1018 |
1014 1019 o 0: null+1,1
1015 1020
1016 1021
1017 1022 $ cd ..
1018 1023
1019 1024 Set up repository containing template fragments in commit metadata:
1020 1025
1021 1026 $ hg init r
1022 1027 $ cd r
1023 1028 $ echo a > a
1024 1029 $ hg ci -Am '{rev}'
1025 1030 adding a
1026 1031
1027 1032 $ hg branch -q 'text.{rev}'
1028 1033 $ echo aa >> aa
1029 1034 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
1030 1035
1031 1036 Test termwidth:
1032 1037
1033 1038 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
1034 1039 bcc7ff960b8e:desc to be
1035 1040 termwidth.1:wrapped desc
1036 1041 termwidth.1:to be wrapped (no-eol)
1037 1042
1038 1043 Just one more commit:
1039 1044
1040 1045 $ echo b > b
1041 1046 $ hg ci -qAm b
1042 1047
1043 1048 Test 'originalnode'
1044 1049
1045 1050 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
1046 1051 000000000000 bcc7ff960b8e
1047 1052 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
1048 1053 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
1049 1054
1050 1055 Test active bookmark templating
1051 1056
1052 1057 $ hg book foo
1053 1058 $ hg book bar
1054 1059 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
1055 1060 2 bar* foo
1056 1061 1
1057 1062 0
1058 1063 $ hg log --template "{rev} {activebookmark}\n"
1059 1064 2 bar
1060 1065 1
1061 1066 0
1062 1067 $ hg bookmarks --inactive bar
1063 1068 $ hg log --template "{rev} {activebookmark}\n"
1064 1069 2
1065 1070 1
1066 1071 0
1067 1072 $ hg book -r1 baz
1068 1073 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
1069 1074 2 bar foo
1070 1075 1 baz
1071 1076 0
1072 1077 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
1073 1078 2 t
1074 1079 1 f
1075 1080 0 f
1076 1081
1077 1082 Test namespaces dict
1078 1083
1079 1084 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
1080 1085 2
1081 1086 bookmarks color=bookmark builtin=True
1082 1087 bar,foo
1083 1088 tags color=tag builtin=True
1084 1089 tip
1085 1090 branches color=branch builtin=True
1086 1091 text.{rev}
1087 1092 revnames color=revname builtin=False
1088 1093 r2
1089 1094
1090 1095 1
1091 1096 bookmarks color=bookmark builtin=True
1092 1097 baz
1093 1098 tags color=tag builtin=True
1094 1099
1095 1100 branches color=branch builtin=True
1096 1101 text.{rev}
1097 1102 revnames color=revname builtin=False
1098 1103 r1
1099 1104
1100 1105 0
1101 1106 bookmarks color=bookmark builtin=True
1102 1107
1103 1108 tags color=tag builtin=True
1104 1109
1105 1110 branches color=branch builtin=True
1106 1111 default
1107 1112 revnames color=revname builtin=False
1108 1113 r0
1109 1114
1110 1115 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
1111 1116 bookmarks: bar foo
1112 1117 tags: tip
1113 1118 branches: text.{rev}
1114 1119 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
1115 1120 bookmarks:
1116 1121 bar
1117 1122 foo
1118 1123 tags:
1119 1124 tip
1120 1125 branches:
1121 1126 text.{rev}
1122 1127 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
1123 1128 bar
1124 1129 foo
1125 1130 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
1126 1131 bar
1127 1132 foo
1128 1133
1129 1134 $ cd ..
1130 1135
1131 1136 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
1132 1137 printed graphwidths 3, 5, 7, etc. should all line up in their respective
1133 1138 columns. We don't care about other aspects of the graph rendering here.
1134 1139
1135 1140 $ hg init graphwidth
1136 1141 $ cd graphwidth
1137 1142
1138 1143 $ wrappabletext="a a a a a a a a a a a a"
1139 1144
1140 1145 $ printf "first\n" > file
1141 1146 $ hg add file
1142 1147 $ hg commit -m "$wrappabletext"
1143 1148
1144 1149 $ printf "first\nsecond\n" > file
1145 1150 $ hg commit -m "$wrappabletext"
1146 1151
1147 1152 $ hg checkout 0
1148 1153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1149 1154 $ printf "third\nfirst\n" > file
1150 1155 $ hg commit -m "$wrappabletext"
1151 1156 created new head
1152 1157
1153 1158 $ hg merge
1154 1159 merging file
1155 1160 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1156 1161 (branch merge, don't forget to commit)
1157 1162
1158 1163 $ hg log --graph -T "{graphwidth}"
1159 1164 @ 3
1160 1165 |
1161 1166 | @ 5
1162 1167 |/
1163 1168 o 3
1164 1169
1165 1170 $ hg commit -m "$wrappabletext"
1166 1171
1167 1172 $ hg log --graph -T "{graphwidth}"
1168 1173 @ 5
1169 1174 |\
1170 1175 | o 5
1171 1176 | |
1172 1177 o | 5
1173 1178 |/
1174 1179 o 3
1175 1180
1176 1181
1177 1182 $ hg checkout 0
1178 1183 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1179 1184 $ printf "third\nfirst\nsecond\n" > file
1180 1185 $ hg commit -m "$wrappabletext"
1181 1186 created new head
1182 1187
1183 1188 $ hg log --graph -T "{graphwidth}"
1184 1189 @ 3
1185 1190 |
1186 1191 | o 7
1187 1192 | |\
1188 1193 +---o 7
1189 1194 | |
1190 1195 | o 5
1191 1196 |/
1192 1197 o 3
1193 1198
1194 1199
1195 1200 $ hg log --graph -T "{graphwidth}" -r 3
1196 1201 o 5
1197 1202 |\
1198 1203 ~ ~
1199 1204
1200 1205 $ hg log --graph -T "{graphwidth}" -r 1
1201 1206 o 3
1202 1207 |
1203 1208 ~
1204 1209
1205 1210 $ hg merge
1206 1211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1207 1212 (branch merge, don't forget to commit)
1208 1213 $ hg commit -m "$wrappabletext"
1209 1214
1210 1215 $ printf "seventh\n" >> file
1211 1216 $ hg commit -m "$wrappabletext"
1212 1217
1213 1218 $ hg log --graph -T "{graphwidth}"
1214 1219 @ 3
1215 1220 |
1216 1221 o 5
1217 1222 |\
1218 1223 | o 5
1219 1224 | |
1220 1225 o | 7
1221 1226 |\ \
1222 1227 | o | 7
1223 1228 | |/
1224 1229 o / 5
1225 1230 |/
1226 1231 o 3
1227 1232
1228 1233
1229 1234 The point of graphwidth is to allow wrapping that accounts for the space taken
1230 1235 by the graph.
1231 1236
1232 1237 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
1233 1238 @ a a a a
1234 1239 | a a a a
1235 1240 | a a a a
1236 1241 o a a a
1237 1242 |\ a a a
1238 1243 | | a a a
1239 1244 | | a a a
1240 1245 | o a a a
1241 1246 | | a a a
1242 1247 | | a a a
1243 1248 | | a a a
1244 1249 o | a a
1245 1250 |\ \ a a
1246 1251 | | | a a
1247 1252 | | | a a
1248 1253 | | | a a
1249 1254 | | | a a
1250 1255 | o | a a
1251 1256 | |/ a a
1252 1257 | | a a
1253 1258 | | a a
1254 1259 | | a a
1255 1260 | | a a
1256 1261 o | a a a
1257 1262 |/ a a a
1258 1263 | a a a
1259 1264 | a a a
1260 1265 o a a a a
1261 1266 a a a a
1262 1267 a a a a
1263 1268
1264 1269 Something tricky happens when there are elided nodes; the next drawn row of
1265 1270 edges can be more than one column wider, but the graph width only increases by
1266 1271 one column. The remaining columns are added in between the nodes.
1267 1272
1268 1273 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
1269 1274 o 5
1270 1275 |\
1271 1276 | \
1272 1277 | :\
1273 1278 o : : 7
1274 1279 :/ /
1275 1280 : o 5
1276 1281 :/
1277 1282 o 3
1278 1283
1279 1284
1280 1285 $ cd ..
@@ -1,1760 +1,1760 b''
1 1 Test template map files and styles
2 2 ==================================
3 3
4 4 $ hg init a
5 5 $ cd a
6 6 $ echo a > a
7 7 $ hg add a
8 8 $ echo line 1 > b
9 9 $ echo line 2 >> b
10 10 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
11 11
12 12 $ hg add b
13 13 $ echo other 1 > c
14 14 $ echo other 2 >> c
15 15 $ echo >> c
16 16 $ echo other 3 >> c
17 17 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
18 18
19 19 $ hg add c
20 20 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
21 21 $ echo c >> c
22 22 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
23 23
24 24 $ echo foo > .hg/branch
25 25 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
26 26
27 27 $ hg co -q 3
28 28 $ echo other 4 >> d
29 29 $ hg add d
30 30 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
31 31
32 32 $ hg merge -q foo
33 33 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
34 34
35 35 Second branch starting at nullrev:
36 36
37 37 $ hg update null
38 38 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
39 39 $ echo second > second
40 40 $ hg add second
41 41 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
42 42 created new head
43 43
44 44 $ echo third > third
45 45 $ hg add third
46 46 $ hg mv second fourth
47 47 $ hg commit -m third -d "2020-01-01 10:01"
48 48
49 49 Make sure user/global hgrc does not affect tests
50 50
51 51 $ echo '[ui]' > .hg/hgrc
52 52 $ echo 'logtemplate =' >> .hg/hgrc
53 53 $ echo 'style =' >> .hg/hgrc
54 54
55 55 Add some simple styles to settings
56 56
57 57 $ cat <<'EOF' >> .hg/hgrc
58 58 > [templates]
59 59 > simple = "{rev}\n"
60 60 > simple2 = {rev}\n
61 61 > rev = "should not precede {rev} keyword\n"
62 62 > EOF
63 63
64 64 $ hg log -l1 -Tsimple
65 65 8
66 66 $ hg log -l1 -Tsimple2
67 67 8
68 68 $ hg log -l1 -Trev
69 69 should not precede 8 keyword
70 70 $ hg log -l1 -T '{simple}'
71 71 8
72 72
73 73 Map file shouldn't see user templates:
74 74
75 75 $ cat <<EOF > tmpl
76 76 > changeset = 'nothing expanded:{simple}\n'
77 77 > EOF
78 78 $ hg log -l1 --style ./tmpl
79 79 nothing expanded:
80 80
81 81 Test templates and style maps in files:
82 82
83 83 $ echo "{rev}" > tmpl
84 84 $ hg log -l1 -T./tmpl
85 85 8
86 86 $ hg log -l1 -Tblah/blah
87 87 blah/blah (no-eol)
88 88
89 89 $ printf 'changeset = "{rev}\\n"\n' > map-simple
90 90 $ hg log -l1 -T./map-simple
91 91 8
92 92
93 93 a map file may have [templates] and [templatealias] sections:
94 94
95 95 $ cat <<'EOF' > map-simple
96 96 > [templates]
97 97 > changeset = "{a}\n"
98 98 > [templatealias]
99 99 > a = rev
100 100 > EOF
101 101 $ hg log -l1 -T./map-simple
102 102 8
103 103
104 104 so it can be included in hgrc
105 105
106 106 $ cat <<EOF > myhgrc
107 107 > %include $HGRCPATH
108 108 > %include map-simple
109 109 > [templates]
110 110 > foo = "{changeset}"
111 111 > EOF
112 112 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
113 113 8
114 114 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
115 115 8
116 116
117 117 Test template map inheritance
118 118
119 119 $ echo "__base__ = map-cmdline.default" > map-simple
120 120 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
121 121 $ hg log -l1 -T./map-simple
122 122 changeset: ***8***
123 123 tag: tip
124 124 user: test
125 125 date: Wed Jan 01 10:01:00 2020 +0000
126 126 summary: third
127 127
128 128
129 129 Test docheader, docfooter and separator in template map
130 130
131 131 $ cat <<'EOF' > map-myjson
132 132 > docheader = '\{\n'
133 133 > docfooter = '\n}\n'
134 134 > separator = ',\n'
135 135 > changeset = ' {dict(rev, node|short)|json}'
136 136 > EOF
137 137 $ hg log -l2 -T./map-myjson
138 138 {
139 139 {"node": "95c24699272e", "rev": 8},
140 140 {"node": "29114dbae42b", "rev": 7}
141 141 }
142 142
143 143 Test docheader, docfooter and separator in [templates] section
144 144
145 145 $ cat <<'EOF' >> .hg/hgrc
146 146 > [templates]
147 147 > myjson = ' {dict(rev, node|short)|json}'
148 148 > myjson:docheader = '\{\n'
149 149 > myjson:docfooter = '\n}\n'
150 150 > myjson:separator = ',\n'
151 151 > :docheader = 'should not be selected as a docheader for literal templates\n'
152 152 > EOF
153 153 $ hg log -l2 -Tmyjson
154 154 {
155 155 {"node": "95c24699272e", "rev": 8},
156 156 {"node": "29114dbae42b", "rev": 7}
157 157 }
158 158 $ hg log -l1 -T'{rev}\n'
159 159 8
160 160
161 161 Template should precede style option
162 162
163 163 $ hg log -l1 --style default -T '{rev}\n'
164 164 8
165 165
166 166 Add a commit with empty description, to ensure that the templates
167 167 below will omit the description line.
168 168
169 169 $ echo c >> c
170 170 $ hg add c
171 171 $ hg commit -qm ' '
172 172
173 173 Default style is like normal output. Phases style should be the same
174 174 as default style, except for extra phase lines.
175 175
176 176 $ hg log > log.out
177 177 $ hg log --style default > style.out
178 178 $ cmp log.out style.out || diff -u log.out style.out
179 179 $ hg log -T phases > phases.out
180 180 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
181 181 +phase: draft
182 182 +phase: draft
183 183 +phase: draft
184 184 +phase: draft
185 185 +phase: draft
186 186 +phase: draft
187 187 +phase: draft
188 188 +phase: draft
189 189 +phase: draft
190 190 +phase: draft
191 191
192 192 $ hg log -v > log.out
193 193 $ hg log -v --style default > style.out
194 194 $ cmp log.out style.out || diff -u log.out style.out
195 195 $ hg log -v -T phases > phases.out
196 196 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
197 197 +phase: draft
198 198 +phase: draft
199 199 +phase: draft
200 200 +phase: draft
201 201 +phase: draft
202 202 +phase: draft
203 203 +phase: draft
204 204 +phase: draft
205 205 +phase: draft
206 206 +phase: draft
207 207
208 208 $ hg log -q > log.out
209 209 $ hg log -q --style default > style.out
210 210 $ cmp log.out style.out || diff -u log.out style.out
211 211 $ hg log -q -T phases > phases.out
212 212 $ cmp log.out phases.out || diff -u log.out phases.out
213 213
214 214 $ hg log --debug > log.out
215 215 $ hg log --debug --style default > style.out
216 216 $ cmp log.out style.out || diff -u log.out style.out
217 217 $ hg log --debug -T phases > phases.out
218 218 $ cmp log.out phases.out || diff -u log.out phases.out
219 219
220 220 Default style of working-directory revision should also be the same (but
221 221 date may change while running tests):
222 222
223 223 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
224 224 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
225 225 $ cmp log.out style.out || diff -u log.out style.out
226 226
227 227 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
228 228 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
229 229 $ cmp log.out style.out || diff -u log.out style.out
230 230
231 231 $ hg log -r 'wdir()' -q > log.out
232 232 $ hg log -r 'wdir()' -q --style default > style.out
233 233 $ cmp log.out style.out || diff -u log.out style.out
234 234
235 235 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
236 236 $ hg log -r 'wdir()' --debug --style default \
237 237 > | sed 's|^date:.*|date:|' > style.out
238 238 $ cmp log.out style.out || diff -u log.out style.out
239 239
240 240 Default style should also preserve color information (issue2866):
241 241
242 242 $ cp $HGRCPATH $HGRCPATH-bak
243 243 $ cat <<EOF >> $HGRCPATH
244 244 > [extensions]
245 245 > color=
246 246 > EOF
247 247
248 248 $ hg --color=debug log > log.out
249 249 $ hg --color=debug log --style default > style.out
250 250 $ cmp log.out style.out || diff -u log.out style.out
251 251 $ hg --color=debug log -T phases > phases.out
252 252 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
253 253 +[log.phase|phase: draft]
254 254 +[log.phase|phase: draft]
255 255 +[log.phase|phase: draft]
256 256 +[log.phase|phase: draft]
257 257 +[log.phase|phase: draft]
258 258 +[log.phase|phase: draft]
259 259 +[log.phase|phase: draft]
260 260 +[log.phase|phase: draft]
261 261 +[log.phase|phase: draft]
262 262 +[log.phase|phase: draft]
263 263
264 264 $ hg --color=debug -v log > log.out
265 265 $ hg --color=debug -v log --style default > style.out
266 266 $ cmp log.out style.out || diff -u log.out style.out
267 267 $ hg --color=debug -v log -T phases > phases.out
268 268 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
269 269 +[log.phase|phase: draft]
270 270 +[log.phase|phase: draft]
271 271 +[log.phase|phase: draft]
272 272 +[log.phase|phase: draft]
273 273 +[log.phase|phase: draft]
274 274 +[log.phase|phase: draft]
275 275 +[log.phase|phase: draft]
276 276 +[log.phase|phase: draft]
277 277 +[log.phase|phase: draft]
278 278 +[log.phase|phase: draft]
279 279
280 280 $ hg --color=debug -q log > log.out
281 281 $ hg --color=debug -q log --style default > style.out
282 282 $ cmp log.out style.out || diff -u log.out style.out
283 283 $ hg --color=debug -q log -T phases > phases.out
284 284 $ cmp log.out phases.out || diff -u log.out phases.out
285 285
286 286 $ hg --color=debug --debug log > log.out
287 287 $ hg --color=debug --debug log --style default > style.out
288 288 $ cmp log.out style.out || diff -u log.out style.out
289 289 $ hg --color=debug --debug log -T phases > phases.out
290 290 $ cmp log.out phases.out || diff -u log.out phases.out
291 291
292 292 $ mv $HGRCPATH-bak $HGRCPATH
293 293
294 294 Remove commit with empty commit message, so as to not pollute further
295 295 tests.
296 296
297 297 $ hg --config extensions.strip= strip -q .
298 298
299 299 Revision with no copies (used to print a traceback):
300 300
301 301 $ hg tip -v --template '\n'
302 302
303 303
304 304 Compact style works:
305 305
306 306 $ hg log -Tcompact
307 307 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
308 308 third
309 309
310 310 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
311 311 second
312 312
313 313 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
314 314 merge
315 315
316 316 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
317 317 new head
318 318
319 319 4 bbe44766e73d 1970-01-17 04:53 +0000 person
320 320 new branch
321 321
322 322 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
323 323 no user, no domain
324 324
325 325 2 97054abb4ab8 1970-01-14 21:20 +0000 other
326 326 no person
327 327
328 328 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
329 329 other 1
330 330
331 331 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
332 332 line 1
333 333
334 334
335 335 $ hg log -v --style compact
336 336 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
337 337 third
338 338
339 339 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
340 340 second
341 341
342 342 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
343 343 merge
344 344
345 345 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
346 346 new head
347 347
348 348 4 bbe44766e73d 1970-01-17 04:53 +0000 person
349 349 new branch
350 350
351 351 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
352 352 no user, no domain
353 353
354 354 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
355 355 no person
356 356
357 357 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
358 358 other 1
359 359 other 2
360 360
361 361 other 3
362 362
363 363 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
364 364 line 1
365 365 line 2
366 366
367 367
368 368 $ hg log --debug --style compact
369 369 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
370 370 third
371 371
372 372 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
373 373 second
374 374
375 375 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
376 376 merge
377 377
378 378 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
379 379 new head
380 380
381 381 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
382 382 new branch
383 383
384 384 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
385 385 no user, no domain
386 386
387 387 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
388 388 no person
389 389
390 390 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
391 391 other 1
392 392 other 2
393 393
394 394 other 3
395 395
396 396 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
397 397 line 1
398 398 line 2
399 399
400 400
401 401 Test xml styles:
402 402
403 403 $ hg log --style xml -r 'not all()'
404 404 <?xml version="1.0"?>
405 405 <log>
406 406 </log>
407 407
408 408 $ hg log --style xml
409 409 <?xml version="1.0"?>
410 410 <log>
411 411 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
412 412 <tag>tip</tag>
413 413 <author email="test">test</author>
414 414 <date>2020-01-01T10:01:00+00:00</date>
415 415 <msg xml:space="preserve">third</msg>
416 416 </logentry>
417 417 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
418 418 <parent revision="-1" node="0000000000000000000000000000000000000000" />
419 419 <author email="user@hostname">User Name</author>
420 420 <date>1970-01-12T13:46:40+00:00</date>
421 421 <msg xml:space="preserve">second</msg>
422 422 </logentry>
423 423 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
424 424 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
425 425 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
426 426 <author email="person">person</author>
427 427 <date>1970-01-18T08:40:01+00:00</date>
428 428 <msg xml:space="preserve">merge</msg>
429 429 </logentry>
430 430 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
431 431 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
432 432 <author email="person">person</author>
433 433 <date>1970-01-18T08:40:00+00:00</date>
434 434 <msg xml:space="preserve">new head</msg>
435 435 </logentry>
436 436 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
437 437 <branch>foo</branch>
438 438 <author email="person">person</author>
439 439 <date>1970-01-17T04:53:20+00:00</date>
440 440 <msg xml:space="preserve">new branch</msg>
441 441 </logentry>
442 442 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
443 443 <author email="person">person</author>
444 444 <date>1970-01-16T01:06:40+00:00</date>
445 445 <msg xml:space="preserve">no user, no domain</msg>
446 446 </logentry>
447 447 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
448 448 <author email="other@place">other</author>
449 449 <date>1970-01-14T21:20:00+00:00</date>
450 450 <msg xml:space="preserve">no person</msg>
451 451 </logentry>
452 452 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
453 453 <author email="other@place">A. N. Other</author>
454 454 <date>1970-01-13T17:33:20+00:00</date>
455 455 <msg xml:space="preserve">other 1
456 456 other 2
457 457
458 458 other 3</msg>
459 459 </logentry>
460 460 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
461 461 <author email="user@hostname">User Name</author>
462 462 <date>1970-01-12T13:46:40+00:00</date>
463 463 <msg xml:space="preserve">line 1
464 464 line 2</msg>
465 465 </logentry>
466 466 </log>
467 467
468 468 $ hg log -v --style xml
469 469 <?xml version="1.0"?>
470 470 <log>
471 471 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
472 472 <tag>tip</tag>
473 473 <author email="test">test</author>
474 474 <date>2020-01-01T10:01:00+00:00</date>
475 475 <msg xml:space="preserve">third</msg>
476 476 <paths>
477 477 <path action="A">fourth</path>
478 478 <path action="A">third</path>
479 479 <path action="R">second</path>
480 480 </paths>
481 481 <copies>
482 482 <copy source="second">fourth</copy>
483 483 </copies>
484 484 </logentry>
485 485 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
486 486 <parent revision="-1" node="0000000000000000000000000000000000000000" />
487 487 <author email="user@hostname">User Name</author>
488 488 <date>1970-01-12T13:46:40+00:00</date>
489 489 <msg xml:space="preserve">second</msg>
490 490 <paths>
491 491 <path action="A">second</path>
492 492 </paths>
493 493 </logentry>
494 494 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
495 495 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
496 496 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
497 497 <author email="person">person</author>
498 498 <date>1970-01-18T08:40:01+00:00</date>
499 499 <msg xml:space="preserve">merge</msg>
500 500 <paths>
501 501 </paths>
502 502 </logentry>
503 503 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
504 504 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
505 505 <author email="person">person</author>
506 506 <date>1970-01-18T08:40:00+00:00</date>
507 507 <msg xml:space="preserve">new head</msg>
508 508 <paths>
509 509 <path action="A">d</path>
510 510 </paths>
511 511 </logentry>
512 512 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
513 513 <branch>foo</branch>
514 514 <author email="person">person</author>
515 515 <date>1970-01-17T04:53:20+00:00</date>
516 516 <msg xml:space="preserve">new branch</msg>
517 517 <paths>
518 518 </paths>
519 519 </logentry>
520 520 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
521 521 <author email="person">person</author>
522 522 <date>1970-01-16T01:06:40+00:00</date>
523 523 <msg xml:space="preserve">no user, no domain</msg>
524 524 <paths>
525 525 <path action="M">c</path>
526 526 </paths>
527 527 </logentry>
528 528 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
529 529 <author email="other@place">other</author>
530 530 <date>1970-01-14T21:20:00+00:00</date>
531 531 <msg xml:space="preserve">no person</msg>
532 532 <paths>
533 533 <path action="A">c</path>
534 534 </paths>
535 535 </logentry>
536 536 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
537 537 <author email="other@place">A. N. Other</author>
538 538 <date>1970-01-13T17:33:20+00:00</date>
539 539 <msg xml:space="preserve">other 1
540 540 other 2
541 541
542 542 other 3</msg>
543 543 <paths>
544 544 <path action="A">b</path>
545 545 </paths>
546 546 </logentry>
547 547 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
548 548 <author email="user@hostname">User Name</author>
549 549 <date>1970-01-12T13:46:40+00:00</date>
550 550 <msg xml:space="preserve">line 1
551 551 line 2</msg>
552 552 <paths>
553 553 <path action="A">a</path>
554 554 </paths>
555 555 </logentry>
556 556 </log>
557 557
558 558 $ hg log --debug --style xml
559 559 <?xml version="1.0"?>
560 560 <log>
561 561 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
562 562 <tag>tip</tag>
563 563 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
564 564 <parent revision="-1" node="0000000000000000000000000000000000000000" />
565 565 <author email="test">test</author>
566 566 <date>2020-01-01T10:01:00+00:00</date>
567 567 <msg xml:space="preserve">third</msg>
568 568 <paths>
569 569 <path action="A">fourth</path>
570 570 <path action="A">third</path>
571 571 <path action="R">second</path>
572 572 </paths>
573 573 <copies>
574 574 <copy source="second">fourth</copy>
575 575 </copies>
576 576 <extra key="branch">default</extra>
577 577 </logentry>
578 578 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
579 579 <parent revision="-1" node="0000000000000000000000000000000000000000" />
580 580 <parent revision="-1" node="0000000000000000000000000000000000000000" />
581 581 <author email="user@hostname">User Name</author>
582 582 <date>1970-01-12T13:46:40+00:00</date>
583 583 <msg xml:space="preserve">second</msg>
584 584 <paths>
585 585 <path action="A">second</path>
586 586 </paths>
587 587 <extra key="branch">default</extra>
588 588 </logentry>
589 589 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
590 590 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
591 591 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
592 592 <author email="person">person</author>
593 593 <date>1970-01-18T08:40:01+00:00</date>
594 594 <msg xml:space="preserve">merge</msg>
595 595 <paths>
596 596 </paths>
597 597 <extra key="branch">default</extra>
598 598 </logentry>
599 599 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
600 600 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
601 601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
602 602 <author email="person">person</author>
603 603 <date>1970-01-18T08:40:00+00:00</date>
604 604 <msg xml:space="preserve">new head</msg>
605 605 <paths>
606 606 <path action="A">d</path>
607 607 </paths>
608 608 <extra key="branch">default</extra>
609 609 </logentry>
610 610 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
611 611 <branch>foo</branch>
612 612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
613 613 <parent revision="-1" node="0000000000000000000000000000000000000000" />
614 614 <author email="person">person</author>
615 615 <date>1970-01-17T04:53:20+00:00</date>
616 616 <msg xml:space="preserve">new branch</msg>
617 617 <paths>
618 618 </paths>
619 619 <extra key="branch">foo</extra>
620 620 </logentry>
621 621 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
622 622 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
623 623 <parent revision="-1" node="0000000000000000000000000000000000000000" />
624 624 <author email="person">person</author>
625 625 <date>1970-01-16T01:06:40+00:00</date>
626 626 <msg xml:space="preserve">no user, no domain</msg>
627 627 <paths>
628 628 <path action="M">c</path>
629 629 </paths>
630 630 <extra key="branch">default</extra>
631 631 </logentry>
632 632 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
633 633 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
634 634 <parent revision="-1" node="0000000000000000000000000000000000000000" />
635 635 <author email="other@place">other</author>
636 636 <date>1970-01-14T21:20:00+00:00</date>
637 637 <msg xml:space="preserve">no person</msg>
638 638 <paths>
639 639 <path action="A">c</path>
640 640 </paths>
641 641 <extra key="branch">default</extra>
642 642 </logentry>
643 643 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
644 644 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
645 645 <parent revision="-1" node="0000000000000000000000000000000000000000" />
646 646 <author email="other@place">A. N. Other</author>
647 647 <date>1970-01-13T17:33:20+00:00</date>
648 648 <msg xml:space="preserve">other 1
649 649 other 2
650 650
651 651 other 3</msg>
652 652 <paths>
653 653 <path action="A">b</path>
654 654 </paths>
655 655 <extra key="branch">default</extra>
656 656 </logentry>
657 657 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
658 658 <parent revision="-1" node="0000000000000000000000000000000000000000" />
659 659 <parent revision="-1" node="0000000000000000000000000000000000000000" />
660 660 <author email="user@hostname">User Name</author>
661 661 <date>1970-01-12T13:46:40+00:00</date>
662 662 <msg xml:space="preserve">line 1
663 663 line 2</msg>
664 664 <paths>
665 665 <path action="A">a</path>
666 666 </paths>
667 667 <extra key="branch">default</extra>
668 668 </logentry>
669 669 </log>
670 670
671 671
672 672 Test JSON style:
673 673
674 674 $ hg log -k nosuch -Tjson
675 675 [
676 676 ]
677 677
678 678 $ hg log -qr . -Tjson
679 679 [
680 680 {
681 681 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
682 682 "rev": 8
683 683 }
684 684 ]
685 685
686 686 $ hg log -vpr . -Tjson --stat
687 687 [
688 688 {
689 689 "bookmarks": [],
690 690 "branch": "default",
691 691 "date": [1577872860, 0],
692 692 "desc": "third",
693 693 "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",
694 694 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
695 695 "files": ["fourth", "second", "third"],
696 696 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
697 697 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
698 698 "phase": "draft",
699 699 "rev": 8,
700 700 "tags": ["tip"],
701 701 "user": "test"
702 702 }
703 703 ]
704 704
705 705 honor --git but not format-breaking diffopts
706 706 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
707 707 [
708 708 {
709 709 "bookmarks": [],
710 710 "branch": "default",
711 711 "date": [1577872860, 0],
712 712 "desc": "third",
713 713 "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",
714 714 "files": ["fourth", "second", "third"],
715 715 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
716 716 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
717 717 "phase": "draft",
718 718 "rev": 8,
719 719 "tags": ["tip"],
720 720 "user": "test"
721 721 }
722 722 ]
723 723
724 724 $ hg log -T json
725 725 [
726 726 {
727 727 "bookmarks": [],
728 728 "branch": "default",
729 729 "date": [1577872860, 0],
730 730 "desc": "third",
731 731 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
732 732 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
733 733 "phase": "draft",
734 734 "rev": 8,
735 735 "tags": ["tip"],
736 736 "user": "test"
737 737 },
738 738 {
739 739 "bookmarks": [],
740 740 "branch": "default",
741 741 "date": [1000000, 0],
742 742 "desc": "second",
743 743 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
744 744 "parents": ["0000000000000000000000000000000000000000"],
745 745 "phase": "draft",
746 746 "rev": 7,
747 747 "tags": [],
748 748 "user": "User Name <user@hostname>"
749 749 },
750 750 {
751 751 "bookmarks": [],
752 752 "branch": "default",
753 753 "date": [1500001, 0],
754 754 "desc": "merge",
755 755 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
756 756 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
757 757 "phase": "draft",
758 758 "rev": 6,
759 759 "tags": [],
760 760 "user": "person"
761 761 },
762 762 {
763 763 "bookmarks": [],
764 764 "branch": "default",
765 765 "date": [1500000, 0],
766 766 "desc": "new head",
767 767 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
768 768 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
769 769 "phase": "draft",
770 770 "rev": 5,
771 771 "tags": [],
772 772 "user": "person"
773 773 },
774 774 {
775 775 "bookmarks": [],
776 776 "branch": "foo",
777 777 "date": [1400000, 0],
778 778 "desc": "new branch",
779 779 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
780 780 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
781 781 "phase": "draft",
782 782 "rev": 4,
783 783 "tags": [],
784 784 "user": "person"
785 785 },
786 786 {
787 787 "bookmarks": [],
788 788 "branch": "default",
789 789 "date": [1300000, 0],
790 790 "desc": "no user, no domain",
791 791 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
792 792 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
793 793 "phase": "draft",
794 794 "rev": 3,
795 795 "tags": [],
796 796 "user": "person"
797 797 },
798 798 {
799 799 "bookmarks": [],
800 800 "branch": "default",
801 801 "date": [1200000, 0],
802 802 "desc": "no person",
803 803 "node": "97054abb4ab824450e9164180baf491ae0078465",
804 804 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
805 805 "phase": "draft",
806 806 "rev": 2,
807 807 "tags": [],
808 808 "user": "other@place"
809 809 },
810 810 {
811 811 "bookmarks": [],
812 812 "branch": "default",
813 813 "date": [1100000, 0],
814 814 "desc": "other 1\nother 2\n\nother 3",
815 815 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
816 816 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
817 817 "phase": "draft",
818 818 "rev": 1,
819 819 "tags": [],
820 820 "user": "A. N. Other <other@place>"
821 821 },
822 822 {
823 823 "bookmarks": [],
824 824 "branch": "default",
825 825 "date": [1000000, 0],
826 826 "desc": "line 1\nline 2",
827 827 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
828 828 "parents": ["0000000000000000000000000000000000000000"],
829 829 "phase": "draft",
830 830 "rev": 0,
831 831 "tags": [],
832 832 "user": "User Name <user@hostname>"
833 833 }
834 834 ]
835 835
836 836 $ hg heads -v -Tjson
837 837 [
838 838 {
839 839 "bookmarks": [],
840 840 "branch": "default",
841 841 "date": [1577872860, 0],
842 842 "desc": "third",
843 843 "files": ["fourth", "second", "third"],
844 844 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
845 845 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
846 846 "phase": "draft",
847 847 "rev": 8,
848 848 "tags": ["tip"],
849 849 "user": "test"
850 850 },
851 851 {
852 852 "bookmarks": [],
853 853 "branch": "default",
854 854 "date": [1500001, 0],
855 855 "desc": "merge",
856 856 "files": [],
857 857 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
858 858 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
859 859 "phase": "draft",
860 860 "rev": 6,
861 861 "tags": [],
862 862 "user": "person"
863 863 },
864 864 {
865 865 "bookmarks": [],
866 866 "branch": "foo",
867 867 "date": [1400000, 0],
868 868 "desc": "new branch",
869 869 "files": [],
870 870 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
871 871 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
872 872 "phase": "draft",
873 873 "rev": 4,
874 874 "tags": [],
875 875 "user": "person"
876 876 }
877 877 ]
878 878
879 879 $ hg log --debug -Tjson
880 880 [
881 881 {
882 882 "added": ["fourth", "third"],
883 883 "bookmarks": [],
884 884 "branch": "default",
885 885 "date": [1577872860, 0],
886 886 "desc": "third",
887 887 "extra": {"branch": "default"},
888 888 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
889 889 "modified": [],
890 890 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
891 891 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
892 892 "phase": "draft",
893 893 "removed": ["second"],
894 894 "rev": 8,
895 895 "tags": ["tip"],
896 896 "user": "test"
897 897 },
898 898 {
899 899 "added": ["second"],
900 900 "bookmarks": [],
901 901 "branch": "default",
902 902 "date": [1000000, 0],
903 903 "desc": "second",
904 904 "extra": {"branch": "default"},
905 905 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
906 906 "modified": [],
907 907 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
908 908 "parents": ["0000000000000000000000000000000000000000"],
909 909 "phase": "draft",
910 910 "removed": [],
911 911 "rev": 7,
912 912 "tags": [],
913 913 "user": "User Name <user@hostname>"
914 914 },
915 915 {
916 916 "added": [],
917 917 "bookmarks": [],
918 918 "branch": "default",
919 919 "date": [1500001, 0],
920 920 "desc": "merge",
921 921 "extra": {"branch": "default"},
922 922 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
923 923 "modified": [],
924 924 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
925 925 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
926 926 "phase": "draft",
927 927 "removed": [],
928 928 "rev": 6,
929 929 "tags": [],
930 930 "user": "person"
931 931 },
932 932 {
933 933 "added": ["d"],
934 934 "bookmarks": [],
935 935 "branch": "default",
936 936 "date": [1500000, 0],
937 937 "desc": "new head",
938 938 "extra": {"branch": "default"},
939 939 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
940 940 "modified": [],
941 941 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
942 942 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
943 943 "phase": "draft",
944 944 "removed": [],
945 945 "rev": 5,
946 946 "tags": [],
947 947 "user": "person"
948 948 },
949 949 {
950 950 "added": [],
951 951 "bookmarks": [],
952 952 "branch": "foo",
953 953 "date": [1400000, 0],
954 954 "desc": "new branch",
955 955 "extra": {"branch": "foo"},
956 956 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
957 957 "modified": [],
958 958 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
959 959 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
960 960 "phase": "draft",
961 961 "removed": [],
962 962 "rev": 4,
963 963 "tags": [],
964 964 "user": "person"
965 965 },
966 966 {
967 967 "added": [],
968 968 "bookmarks": [],
969 969 "branch": "default",
970 970 "date": [1300000, 0],
971 971 "desc": "no user, no domain",
972 972 "extra": {"branch": "default"},
973 973 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
974 974 "modified": ["c"],
975 975 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
976 976 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
977 977 "phase": "draft",
978 978 "removed": [],
979 979 "rev": 3,
980 980 "tags": [],
981 981 "user": "person"
982 982 },
983 983 {
984 984 "added": ["c"],
985 985 "bookmarks": [],
986 986 "branch": "default",
987 987 "date": [1200000, 0],
988 988 "desc": "no person",
989 989 "extra": {"branch": "default"},
990 990 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
991 991 "modified": [],
992 992 "node": "97054abb4ab824450e9164180baf491ae0078465",
993 993 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
994 994 "phase": "draft",
995 995 "removed": [],
996 996 "rev": 2,
997 997 "tags": [],
998 998 "user": "other@place"
999 999 },
1000 1000 {
1001 1001 "added": ["b"],
1002 1002 "bookmarks": [],
1003 1003 "branch": "default",
1004 1004 "date": [1100000, 0],
1005 1005 "desc": "other 1\nother 2\n\nother 3",
1006 1006 "extra": {"branch": "default"},
1007 1007 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1008 1008 "modified": [],
1009 1009 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1010 1010 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1011 1011 "phase": "draft",
1012 1012 "removed": [],
1013 1013 "rev": 1,
1014 1014 "tags": [],
1015 1015 "user": "A. N. Other <other@place>"
1016 1016 },
1017 1017 {
1018 1018 "added": ["a"],
1019 1019 "bookmarks": [],
1020 1020 "branch": "default",
1021 1021 "date": [1000000, 0],
1022 1022 "desc": "line 1\nline 2",
1023 1023 "extra": {"branch": "default"},
1024 1024 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1025 1025 "modified": [],
1026 1026 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1027 1027 "parents": ["0000000000000000000000000000000000000000"],
1028 1028 "phase": "draft",
1029 1029 "removed": [],
1030 1030 "rev": 0,
1031 1031 "tags": [],
1032 1032 "user": "User Name <user@hostname>"
1033 1033 }
1034 1034 ]
1035 1035
1036 1036 Error if style not readable:
1037 1037
1038 1038 #if unix-permissions no-root
1039 1039 $ touch q
1040 1040 $ chmod 0 q
1041 1041 $ hg log --style ./q
1042 1042 abort: Permission denied: ./q
1043 1043 [255]
1044 1044 #endif
1045 1045
1046 1046 Error if no style:
1047 1047
1048 1048 $ hg log --style notexist
1049 1049 abort: style 'notexist' not found
1050 1050 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1051 1051 [255]
1052 1052
1053 1053 $ hg log -T list
1054 1054 available styles: bisect, changelog, compact, default, phases, show, status, xml
1055 1055 abort: specify a template
1056 1056 [255]
1057 1057
1058 1058 Error if style missing key:
1059 1059
1060 1060 $ echo 'q = q' > t
1061 1061 $ hg log --style ./t
1062 1062 abort: "changeset" not in template map
1063 1063 [255]
1064 1064
1065 1065 Error if style missing value:
1066 1066
1067 1067 $ echo 'changeset =' > t
1068 1068 $ hg log --style t
1069 1069 hg: parse error at t:1: missing value
1070 1070 [255]
1071 1071
1072 1072 Error if include fails:
1073 1073
1074 1074 $ echo 'changeset = q' >> t
1075 1075 #if unix-permissions no-root
1076 1076 $ hg log --style ./t
1077 1077 abort: template file ./q: Permission denied
1078 1078 [255]
1079 1079 $ rm -f q
1080 1080 #endif
1081 1081
1082 1082 Include works:
1083 1083
1084 1084 $ echo '{rev}' > q
1085 1085 $ hg log --style ./t
1086 1086 8
1087 1087 7
1088 1088 6
1089 1089 5
1090 1090 4
1091 1091 3
1092 1092 2
1093 1093 1
1094 1094 0
1095 1095
1096 1096 $ hg phase -r 5 --public
1097 1097 $ hg phase -r 7 --secret --force
1098 1098
1099 1099 Missing non-standard names give no error (backward compatibility):
1100 1100
1101 1101 $ echo "changeset = '{c}'" > t
1102 1102 $ hg log --style ./t
1103 1103
1104 1104 Defining non-standard name works:
1105 1105
1106 1106 $ cat <<EOF > t
1107 1107 > changeset = '{c}'
1108 1108 > c = q
1109 1109 > EOF
1110 1110 $ hg log --style ./t
1111 1111 8
1112 1112 7
1113 1113 6
1114 1114 5
1115 1115 4
1116 1116 3
1117 1117 2
1118 1118 1
1119 1119 0
1120 1120
1121 1121 ui.style works:
1122 1122
1123 1123 $ echo '[ui]' > .hg/hgrc
1124 1124 $ echo 'style = t' >> .hg/hgrc
1125 1125 $ hg log
1126 1126 8
1127 1127 7
1128 1128 6
1129 1129 5
1130 1130 4
1131 1131 3
1132 1132 2
1133 1133 1
1134 1134 0
1135 1135
1136 1136 Issue338:
1137 1137
1138 1138 $ hg log --style=changelog > changelog
1139 1139
1140 1140 $ cat changelog
1141 1141 2020-01-01 test <test>
1142 1142
1143 1143 * fourth, second, third:
1144 1144 third
1145 1145 [95c24699272e] [tip]
1146 1146
1147 1147 1970-01-12 User Name <user@hostname>
1148 1148
1149 1149 * second:
1150 1150 second
1151 1151 [29114dbae42b]
1152 1152
1153 1153 1970-01-18 person <person>
1154 1154
1155 1155 * merge
1156 1156 [d41e714fe50d]
1157 1157
1158 1158 * d:
1159 1159 new head
1160 1160 [13207e5a10d9]
1161 1161
1162 1162 1970-01-17 person <person>
1163 1163
1164 1164 * new branch
1165 1165 [bbe44766e73d] <foo>
1166 1166
1167 1167 1970-01-16 person <person>
1168 1168
1169 1169 * c:
1170 1170 no user, no domain
1171 1171 [10e46f2dcbf4]
1172 1172
1173 1173 1970-01-14 other <other@place>
1174 1174
1175 1175 * c:
1176 1176 no person
1177 1177 [97054abb4ab8]
1178 1178
1179 1179 1970-01-13 A. N. Other <other@place>
1180 1180
1181 1181 * b:
1182 1182 other 1 other 2
1183 1183
1184 1184 other 3
1185 1185 [b608e9d1a3f0]
1186 1186
1187 1187 1970-01-12 User Name <user@hostname>
1188 1188
1189 1189 * a:
1190 1190 line 1 line 2
1191 1191 [1e4e1b8f71e0]
1192 1192
1193 1193
1194 1194 Issue2130: xml output for 'hg heads' is malformed
1195 1195
1196 1196 $ hg heads --style changelog
1197 1197 2020-01-01 test <test>
1198 1198
1199 1199 * fourth, second, third:
1200 1200 third
1201 1201 [95c24699272e] [tip]
1202 1202
1203 1203 1970-01-18 person <person>
1204 1204
1205 1205 * merge
1206 1206 [d41e714fe50d]
1207 1207
1208 1208 1970-01-17 person <person>
1209 1209
1210 1210 * new branch
1211 1211 [bbe44766e73d] <foo>
1212 1212
1213 1213
1214 1214 Add a dummy commit to make up for the instability of the above:
1215 1215
1216 1216 $ echo a > a
1217 1217 $ hg add a
1218 1218 $ hg ci -m future
1219 1219
1220 1220 Add a commit that does all possible modifications at once
1221 1221
1222 1222 $ echo modify >> third
1223 1223 $ touch b
1224 1224 $ hg add b
1225 1225 $ hg mv fourth fifth
1226 1226 $ hg rm a
1227 1227 $ hg ci -m "Modify, add, remove, rename"
1228 1228
1229 1229 Check the status template
1230 1230
1231 1231 $ cat <<EOF >> $HGRCPATH
1232 1232 > [extensions]
1233 1233 > color=
1234 1234 > EOF
1235 1235
1236 1236 $ hg log -T status -r 10
1237 1237 changeset: 10:0f9759ec227a
1238 1238 tag: tip
1239 1239 user: test
1240 1240 date: Thu Jan 01 00:00:00 1970 +0000
1241 1241 summary: Modify, add, remove, rename
1242 1242 files:
1243 1243 M third
1244 1244 A b
1245 1245 A fifth
1246 1246 R a
1247 1247 R fourth
1248 1248
1249 1249 $ hg log -T status -C -r 10
1250 1250 changeset: 10:0f9759ec227a
1251 1251 tag: tip
1252 1252 user: test
1253 1253 date: Thu Jan 01 00:00:00 1970 +0000
1254 1254 summary: Modify, add, remove, rename
1255 1255 files:
1256 1256 M third
1257 1257 A b
1258 1258 A fifth
1259 1259 fourth
1260 1260 R a
1261 1261 R fourth
1262 1262
1263 1263 $ hg log -T status -C -r 10 -v
1264 1264 changeset: 10:0f9759ec227a
1265 1265 tag: tip
1266 1266 user: test
1267 1267 date: Thu Jan 01 00:00:00 1970 +0000
1268 1268 description:
1269 1269 Modify, add, remove, rename
1270 1270
1271 1271 files:
1272 1272 M third
1273 1273 A b
1274 1274 A fifth
1275 1275 fourth
1276 1276 R a
1277 1277 R fourth
1278 1278
1279 1279 $ hg log -T status -C -r 10 --debug
1280 1280 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
1281 1281 tag: tip
1282 1282 phase: secret
1283 1283 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
1284 1284 parent: -1:0000000000000000000000000000000000000000
1285 1285 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
1286 1286 user: test
1287 1287 date: Thu Jan 01 00:00:00 1970 +0000
1288 1288 extra: branch=default
1289 1289 description:
1290 1290 Modify, add, remove, rename
1291 1291
1292 1292 files:
1293 1293 M third
1294 1294 A b
1295 1295 A fifth
1296 1296 fourth
1297 1297 R a
1298 1298 R fourth
1299 1299
1300 1300 $ hg log -T status -C -r 10 --quiet
1301 1301 10:0f9759ec227a
1302 1302 $ hg --color=debug log -T status -r 10
1303 1303 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
1304 1304 [log.tag|tag: tip]
1305 1305 [log.user|user: test]
1306 1306 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1307 1307 [log.summary|summary: Modify, add, remove, rename]
1308 1308 [ui.note log.files|files:]
1309 1309 [status.modified|M third]
1310 1310 [status.added|A b]
1311 1311 [status.added|A fifth]
1312 1312 [status.removed|R a]
1313 1313 [status.removed|R fourth]
1314 1314
1315 1315 $ hg --color=debug log -T status -C -r 10
1316 1316 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
1317 1317 [log.tag|tag: tip]
1318 1318 [log.user|user: test]
1319 1319 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1320 1320 [log.summary|summary: Modify, add, remove, rename]
1321 1321 [ui.note log.files|files:]
1322 1322 [status.modified|M third]
1323 1323 [status.added|A b]
1324 1324 [status.added|A fifth]
1325 1325 [status.copied| fourth]
1326 1326 [status.removed|R a]
1327 1327 [status.removed|R fourth]
1328 1328
1329 1329 $ hg --color=debug log -T status -C -r 10 -v
1330 1330 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
1331 1331 [log.tag|tag: tip]
1332 1332 [log.user|user: test]
1333 1333 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1334 1334 [ui.note log.description|description:]
1335 1335 [ui.note log.description|Modify, add, remove, rename]
1336 1336
1337 1337 [ui.note log.files|files:]
1338 1338 [status.modified|M third]
1339 1339 [status.added|A b]
1340 1340 [status.added|A fifth]
1341 1341 [status.copied| fourth]
1342 1342 [status.removed|R a]
1343 1343 [status.removed|R fourth]
1344 1344
1345 1345 $ hg --color=debug log -T status -C -r 10 --debug
1346 1346 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
1347 1347 [log.tag|tag: tip]
1348 1348 [log.phase|phase: secret]
1349 1349 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
1350 1350 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1351 1351 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
1352 1352 [log.user|user: test]
1353 1353 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1354 1354 [ui.debug log.extra|extra: branch=default]
1355 1355 [ui.note log.description|description:]
1356 1356 [ui.note log.description|Modify, add, remove, rename]
1357 1357
1358 1358 [ui.note log.files|files:]
1359 1359 [status.modified|M third]
1360 1360 [status.added|A b]
1361 1361 [status.added|A fifth]
1362 1362 [status.copied| fourth]
1363 1363 [status.removed|R a]
1364 1364 [status.removed|R fourth]
1365 1365
1366 1366 $ hg --color=debug log -T status -C -r 10 --quiet
1367 1367 [log.node|10:0f9759ec227a]
1368 1368
1369 1369 Check the bisect template
1370 1370
1371 1371 $ hg bisect -g 1
1372 1372 $ hg bisect -b 3 --noupdate
1373 1373 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
1374 1374 $ hg log -T bisect -r 0:4
1375 1375 changeset: 0:1e4e1b8f71e0
1376 1376 bisect: good (implicit)
1377 1377 user: User Name <user@hostname>
1378 1378 date: Mon Jan 12 13:46:40 1970 +0000
1379 1379 summary: line 1
1380 1380
1381 1381 changeset: 1:b608e9d1a3f0
1382 1382 bisect: good
1383 1383 user: A. N. Other <other@place>
1384 1384 date: Tue Jan 13 17:33:20 1970 +0000
1385 1385 summary: other 1
1386 1386
1387 1387 changeset: 2:97054abb4ab8
1388 1388 bisect: untested
1389 1389 user: other@place
1390 1390 date: Wed Jan 14 21:20:00 1970 +0000
1391 1391 summary: no person
1392 1392
1393 1393 changeset: 3:10e46f2dcbf4
1394 1394 bisect: bad
1395 1395 user: person
1396 1396 date: Fri Jan 16 01:06:40 1970 +0000
1397 1397 summary: no user, no domain
1398 1398
1399 1399 changeset: 4:bbe44766e73d
1400 1400 bisect: bad (implicit)
1401 1401 branch: foo
1402 1402 user: person
1403 1403 date: Sat Jan 17 04:53:20 1970 +0000
1404 1404 summary: new branch
1405 1405
1406 1406 $ hg log --debug -T bisect -r 0:4
1407 1407 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
1408 1408 bisect: good (implicit)
1409 1409 phase: public
1410 1410 parent: -1:0000000000000000000000000000000000000000
1411 1411 parent: -1:0000000000000000000000000000000000000000
1412 1412 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1413 1413 user: User Name <user@hostname>
1414 1414 date: Mon Jan 12 13:46:40 1970 +0000
1415 1415 files+: a
1416 1416 extra: branch=default
1417 1417 description:
1418 1418 line 1
1419 1419 line 2
1420 1420
1421 1421
1422 1422 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1423 1423 bisect: good
1424 1424 phase: public
1425 1425 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
1426 1426 parent: -1:0000000000000000000000000000000000000000
1427 1427 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1428 1428 user: A. N. Other <other@place>
1429 1429 date: Tue Jan 13 17:33:20 1970 +0000
1430 1430 files+: b
1431 1431 extra: branch=default
1432 1432 description:
1433 1433 other 1
1434 1434 other 2
1435 1435
1436 1436 other 3
1437 1437
1438 1438
1439 1439 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
1440 1440 bisect: untested
1441 1441 phase: public
1442 1442 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1443 1443 parent: -1:0000000000000000000000000000000000000000
1444 1444 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1445 1445 user: other@place
1446 1446 date: Wed Jan 14 21:20:00 1970 +0000
1447 1447 files+: c
1448 1448 extra: branch=default
1449 1449 description:
1450 1450 no person
1451 1451
1452 1452
1453 1453 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
1454 1454 bisect: bad
1455 1455 phase: public
1456 1456 parent: 2:97054abb4ab824450e9164180baf491ae0078465
1457 1457 parent: -1:0000000000000000000000000000000000000000
1458 1458 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1459 1459 user: person
1460 1460 date: Fri Jan 16 01:06:40 1970 +0000
1461 1461 files: c
1462 1462 extra: branch=default
1463 1463 description:
1464 1464 no user, no domain
1465 1465
1466 1466
1467 1467 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1468 1468 bisect: bad (implicit)
1469 1469 branch: foo
1470 1470 phase: draft
1471 1471 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
1472 1472 parent: -1:0000000000000000000000000000000000000000
1473 1473 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1474 1474 user: person
1475 1475 date: Sat Jan 17 04:53:20 1970 +0000
1476 1476 extra: branch=foo
1477 1477 description:
1478 1478 new branch
1479 1479
1480 1480
1481 1481 $ hg log -v -T bisect -r 0:4
1482 1482 changeset: 0:1e4e1b8f71e0
1483 1483 bisect: good (implicit)
1484 1484 user: User Name <user@hostname>
1485 1485 date: Mon Jan 12 13:46:40 1970 +0000
1486 1486 files: a
1487 1487 description:
1488 1488 line 1
1489 1489 line 2
1490 1490
1491 1491
1492 1492 changeset: 1:b608e9d1a3f0
1493 1493 bisect: good
1494 1494 user: A. N. Other <other@place>
1495 1495 date: Tue Jan 13 17:33:20 1970 +0000
1496 1496 files: b
1497 1497 description:
1498 1498 other 1
1499 1499 other 2
1500 1500
1501 1501 other 3
1502 1502
1503 1503
1504 1504 changeset: 2:97054abb4ab8
1505 1505 bisect: untested
1506 1506 user: other@place
1507 1507 date: Wed Jan 14 21:20:00 1970 +0000
1508 1508 files: c
1509 1509 description:
1510 1510 no person
1511 1511
1512 1512
1513 1513 changeset: 3:10e46f2dcbf4
1514 1514 bisect: bad
1515 1515 user: person
1516 1516 date: Fri Jan 16 01:06:40 1970 +0000
1517 1517 files: c
1518 1518 description:
1519 1519 no user, no domain
1520 1520
1521 1521
1522 1522 changeset: 4:bbe44766e73d
1523 1523 bisect: bad (implicit)
1524 1524 branch: foo
1525 1525 user: person
1526 1526 date: Sat Jan 17 04:53:20 1970 +0000
1527 1527 description:
1528 1528 new branch
1529 1529
1530 1530
1531 1531 $ hg --color=debug log -T bisect -r 0:4
1532 1532 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
1533 1533 [log.bisect bisect.good|bisect: good (implicit)]
1534 1534 [log.user|user: User Name <user@hostname>]
1535 1535 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
1536 1536 [log.summary|summary: line 1]
1537 1537
1538 1538 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
1539 1539 [log.bisect bisect.good|bisect: good]
1540 1540 [log.user|user: A. N. Other <other@place>]
1541 1541 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
1542 1542 [log.summary|summary: other 1]
1543 1543
1544 1544 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
1545 1545 [log.bisect bisect.untested|bisect: untested]
1546 1546 [log.user|user: other@place]
1547 1547 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
1548 1548 [log.summary|summary: no person]
1549 1549
1550 1550 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
1551 1551 [log.bisect bisect.bad|bisect: bad]
1552 1552 [log.user|user: person]
1553 1553 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
1554 1554 [log.summary|summary: no user, no domain]
1555 1555
1556 1556 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
1557 1557 [log.bisect bisect.bad|bisect: bad (implicit)]
1558 1558 [log.branch|branch: foo]
1559 1559 [log.user|user: person]
1560 1560 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
1561 1561 [log.summary|summary: new branch]
1562 1562
1563 1563 $ hg --color=debug log --debug -T bisect -r 0:4
1564 1564 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
1565 1565 [log.bisect bisect.good|bisect: good (implicit)]
1566 1566 [log.phase|phase: public]
1567 1567 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1568 1568 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1569 1569 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
1570 1570 [log.user|user: User Name <user@hostname>]
1571 1571 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
1572 1572 [ui.debug log.files|files+: a]
1573 1573 [ui.debug log.extra|extra: branch=default]
1574 1574 [ui.note log.description|description:]
1575 1575 [ui.note log.description|line 1
1576 1576 line 2]
1577 1577
1578 1578
1579 1579 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
1580 1580 [log.bisect bisect.good|bisect: good]
1581 1581 [log.phase|phase: public]
1582 1582 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
1583 1583 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1584 1584 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
1585 1585 [log.user|user: A. N. Other <other@place>]
1586 1586 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
1587 1587 [ui.debug log.files|files+: b]
1588 1588 [ui.debug log.extra|extra: branch=default]
1589 1589 [ui.note log.description|description:]
1590 1590 [ui.note log.description|other 1
1591 1591 other 2
1592 1592
1593 1593 other 3]
1594 1594
1595 1595
1596 1596 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
1597 1597 [log.bisect bisect.untested|bisect: untested]
1598 1598 [log.phase|phase: public]
1599 1599 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
1600 1600 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1601 1601 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
1602 1602 [log.user|user: other@place]
1603 1603 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
1604 1604 [ui.debug log.files|files+: c]
1605 1605 [ui.debug log.extra|extra: branch=default]
1606 1606 [ui.note log.description|description:]
1607 1607 [ui.note log.description|no person]
1608 1608
1609 1609
1610 1610 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
1611 1611 [log.bisect bisect.bad|bisect: bad]
1612 1612 [log.phase|phase: public]
1613 1613 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
1614 1614 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1615 1615 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
1616 1616 [log.user|user: person]
1617 1617 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
1618 1618 [ui.debug log.files|files: c]
1619 1619 [ui.debug log.extra|extra: branch=default]
1620 1620 [ui.note log.description|description:]
1621 1621 [ui.note log.description|no user, no domain]
1622 1622
1623 1623
1624 1624 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
1625 1625 [log.bisect bisect.bad|bisect: bad (implicit)]
1626 1626 [log.branch|branch: foo]
1627 1627 [log.phase|phase: draft]
1628 1628 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
1629 1629 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
1630 1630 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
1631 1631 [log.user|user: person]
1632 1632 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
1633 1633 [ui.debug log.extra|extra: branch=foo]
1634 1634 [ui.note log.description|description:]
1635 1635 [ui.note log.description|new branch]
1636 1636
1637 1637
1638 1638 $ hg --color=debug log -v -T bisect -r 0:4
1639 1639 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
1640 1640 [log.bisect bisect.good|bisect: good (implicit)]
1641 1641 [log.user|user: User Name <user@hostname>]
1642 1642 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
1643 1643 [ui.note log.files|files: a]
1644 1644 [ui.note log.description|description:]
1645 1645 [ui.note log.description|line 1
1646 1646 line 2]
1647 1647
1648 1648
1649 1649 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
1650 1650 [log.bisect bisect.good|bisect: good]
1651 1651 [log.user|user: A. N. Other <other@place>]
1652 1652 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
1653 1653 [ui.note log.files|files: b]
1654 1654 [ui.note log.description|description:]
1655 1655 [ui.note log.description|other 1
1656 1656 other 2
1657 1657
1658 1658 other 3]
1659 1659
1660 1660
1661 1661 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
1662 1662 [log.bisect bisect.untested|bisect: untested]
1663 1663 [log.user|user: other@place]
1664 1664 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
1665 1665 [ui.note log.files|files: c]
1666 1666 [ui.note log.description|description:]
1667 1667 [ui.note log.description|no person]
1668 1668
1669 1669
1670 1670 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
1671 1671 [log.bisect bisect.bad|bisect: bad]
1672 1672 [log.user|user: person]
1673 1673 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
1674 1674 [ui.note log.files|files: c]
1675 1675 [ui.note log.description|description:]
1676 1676 [ui.note log.description|no user, no domain]
1677 1677
1678 1678
1679 1679 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
1680 1680 [log.bisect bisect.bad|bisect: bad (implicit)]
1681 1681 [log.branch|branch: foo]
1682 1682 [log.user|user: person]
1683 1683 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
1684 1684 [ui.note log.description|description:]
1685 1685 [ui.note log.description|new branch]
1686 1686
1687 1687
1688 1688 $ hg bisect --reset
1689 1689
1690 1690 $ cd ..
1691 1691
1692 1692 Set up latesttag repository:
1693 1693
1694 1694 $ hg init latesttag
1695 1695 $ cd latesttag
1696 1696
1697 1697 $ echo a > file
1698 1698 $ hg ci -Am a -d '0 0'
1699 1699 adding file
1700 1700
1701 1701 $ echo b >> file
1702 1702 $ hg ci -m b -d '1 0'
1703 1703
1704 1704 $ echo c >> head1
1705 1705 $ hg ci -Am h1c -d '2 0'
1706 1706 adding head1
1707 1707
1708 1708 $ hg update -q 1
1709 1709 $ echo d >> head2
1710 1710 $ hg ci -Am h2d -d '3 0'
1711 1711 adding head2
1712 1712 created new head
1713 1713
1714 1714 $ echo e >> head2
1715 1715 $ hg ci -m h2e -d '4 0'
1716 1716
1717 1717 $ hg merge -q
1718 1718 $ hg ci -m merge -d '5 -3600'
1719 1719
1720 1720 $ hg tag -r 1 -m t1 -d '6 0' t1
1721 1721 $ hg tag -r 2 -m t2 -d '7 0' t2
1722 1722 $ hg tag -r 3 -m t3 -d '8 0' t3
1723 1723 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
1724 1724 $ hg tag -r 5 -m t5 -d '9 0' t5
1725 1725 $ hg tag -r 3 -m at3 -d '10 0' at3
1726 1726
1727 1727 $ cd ..
1728 1728
1729 1729 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1730 1730 if it is a relative path
1731 1731
1732 1732 $ mkdir -p home/styles
1733 1733
1734 1734 $ cat > home/styles/teststyle <<EOF
1735 1735 > changeset = 'test {rev}:{node|short}\n'
1736 1736 > EOF
1737 1737
1738 1738 $ HOME=`pwd`/home; export HOME
1739 1739
1740 1740 $ cat > latesttag/.hg/hgrc <<EOF
1741 1741 > [ui]
1742 1742 > style = ~/styles/teststyle
1743 1743 > EOF
1744 1744
1745 1745 $ hg -R latesttag tip
1746 1746 test 11:97e5943b523a
1747 1747
1748 1748 Test recursive showlist template (issue1989):
1749 1749
1750 1750 $ cat > style1989 <<EOF
1751 1751 > changeset = '{file_mods}{manifest}{extras}'
1752 1752 > file_mod = 'M|{author|person}\n'
1753 1753 > manifest = '{rev},{author}\n'
1754 1754 > extra = '{key}: {author}\n'
1755 1755 > EOF
1756 1756
1757 1757 $ hg -R latesttag log -r tip --style=style1989
1758 1758 M|test
1759 11,test
1759 11,
1760 1760 branch: test
General Comments 0
You need to be logged in to leave comments. Login now