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