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