##// END OF EJS Templates
templater: fix crash by empty group expression...
Yuya Nishihara -
r35762:8685192a default
parent child Browse files
Show More
@@ -1,1578 +1,1580
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, print_function
8 from __future__ import absolute_import, print_function
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 obsutil,
21 obsutil,
22 parser,
22 parser,
23 pycompat,
23 pycompat,
24 registrar,
24 registrar,
25 revset as revsetmod,
25 revset as revsetmod,
26 revsetlang,
26 revsetlang,
27 scmutil,
27 scmutil,
28 templatefilters,
28 templatefilters,
29 templatekw,
29 templatekw,
30 util,
30 util,
31 )
31 )
32
32
33 # template parsing
33 # template parsing
34
34
35 elements = {
35 elements = {
36 # token-type: binding-strength, primary, prefix, infix, suffix
36 # token-type: binding-strength, primary, prefix, infix, suffix
37 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
37 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
38 ".": (18, None, None, (".", 18), None),
38 ".": (18, None, None, (".", 18), None),
39 "%": (15, None, None, ("%", 15), None),
39 "%": (15, None, None, ("%", 15), None),
40 "|": (15, None, None, ("|", 15), None),
40 "|": (15, None, None, ("|", 15), None),
41 "*": (5, None, None, ("*", 5), None),
41 "*": (5, None, None, ("*", 5), None),
42 "/": (5, None, None, ("/", 5), None),
42 "/": (5, None, None, ("/", 5), None),
43 "+": (4, None, None, ("+", 4), None),
43 "+": (4, None, None, ("+", 4), None),
44 "-": (4, None, ("negate", 19), ("-", 4), None),
44 "-": (4, None, ("negate", 19), ("-", 4), None),
45 "=": (3, None, None, ("keyvalue", 3), None),
45 "=": (3, None, None, ("keyvalue", 3), None),
46 ",": (2, None, None, ("list", 2), None),
46 ",": (2, None, None, ("list", 2), None),
47 ")": (0, None, None, None, None),
47 ")": (0, None, None, None, None),
48 "integer": (0, "integer", None, None, None),
48 "integer": (0, "integer", None, None, None),
49 "symbol": (0, "symbol", None, None, None),
49 "symbol": (0, "symbol", None, None, None),
50 "string": (0, "string", None, None, None),
50 "string": (0, "string", None, None, None),
51 "template": (0, "template", None, None, None),
51 "template": (0, "template", None, None, None),
52 "end": (0, None, None, None, None),
52 "end": (0, None, None, None, None),
53 }
53 }
54
54
55 def tokenize(program, start, end, term=None):
55 def tokenize(program, start, end, term=None):
56 """Parse a template expression into a stream of tokens, which must end
56 """Parse a template expression into a stream of tokens, which must end
57 with term if specified"""
57 with term if specified"""
58 pos = start
58 pos = start
59 program = pycompat.bytestr(program)
59 program = pycompat.bytestr(program)
60 while pos < end:
60 while pos < end:
61 c = program[pos]
61 c = program[pos]
62 if c.isspace(): # skip inter-token whitespace
62 if c.isspace(): # skip inter-token whitespace
63 pass
63 pass
64 elif c in "(=,).%|+-*/": # handle simple operators
64 elif c in "(=,).%|+-*/": # handle simple operators
65 yield (c, None, pos)
65 yield (c, None, pos)
66 elif c in '"\'': # handle quoted templates
66 elif c in '"\'': # handle quoted templates
67 s = pos + 1
67 s = pos + 1
68 data, pos = _parsetemplate(program, s, end, c)
68 data, pos = _parsetemplate(program, s, end, c)
69 yield ('template', data, s)
69 yield ('template', data, s)
70 pos -= 1
70 pos -= 1
71 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
71 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
72 # handle quoted strings
72 # handle quoted strings
73 c = program[pos + 1]
73 c = program[pos + 1]
74 s = pos = pos + 2
74 s = pos = pos + 2
75 while pos < end: # find closing quote
75 while pos < end: # find closing quote
76 d = program[pos]
76 d = program[pos]
77 if d == '\\': # skip over escaped characters
77 if d == '\\': # skip over escaped characters
78 pos += 2
78 pos += 2
79 continue
79 continue
80 if d == c:
80 if d == c:
81 yield ('string', program[s:pos], s)
81 yield ('string', program[s:pos], s)
82 break
82 break
83 pos += 1
83 pos += 1
84 else:
84 else:
85 raise error.ParseError(_("unterminated string"), s)
85 raise error.ParseError(_("unterminated string"), s)
86 elif c.isdigit():
86 elif c.isdigit():
87 s = pos
87 s = pos
88 while pos < end:
88 while pos < end:
89 d = program[pos]
89 d = program[pos]
90 if not d.isdigit():
90 if not d.isdigit():
91 break
91 break
92 pos += 1
92 pos += 1
93 yield ('integer', program[s:pos], s)
93 yield ('integer', program[s:pos], s)
94 pos -= 1
94 pos -= 1
95 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
95 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
96 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
96 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
97 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
97 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
98 # where some of nested templates were preprocessed as strings and
98 # where some of nested templates were preprocessed as strings and
99 # then compiled. therefore, \"...\" was allowed. (issue4733)
99 # then compiled. therefore, \"...\" was allowed. (issue4733)
100 #
100 #
101 # processing flow of _evalifliteral() at 5ab28a2e9962:
101 # processing flow of _evalifliteral() at 5ab28a2e9962:
102 # outer template string -> stringify() -> compiletemplate()
102 # outer template string -> stringify() -> compiletemplate()
103 # ------------------------ ------------ ------------------
103 # ------------------------ ------------ ------------------
104 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
104 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
105 # ~~~~~~~~
105 # ~~~~~~~~
106 # escaped quoted string
106 # escaped quoted string
107 if c == 'r':
107 if c == 'r':
108 pos += 1
108 pos += 1
109 token = 'string'
109 token = 'string'
110 else:
110 else:
111 token = 'template'
111 token = 'template'
112 quote = program[pos:pos + 2]
112 quote = program[pos:pos + 2]
113 s = pos = pos + 2
113 s = pos = pos + 2
114 while pos < end: # find closing escaped quote
114 while pos < end: # find closing escaped quote
115 if program.startswith('\\\\\\', pos, end):
115 if program.startswith('\\\\\\', pos, end):
116 pos += 4 # skip over double escaped characters
116 pos += 4 # skip over double escaped characters
117 continue
117 continue
118 if program.startswith(quote, pos, end):
118 if program.startswith(quote, pos, end):
119 # interpret as if it were a part of an outer string
119 # interpret as if it were a part of an outer string
120 data = parser.unescapestr(program[s:pos])
120 data = parser.unescapestr(program[s:pos])
121 if token == 'template':
121 if token == 'template':
122 data = _parsetemplate(data, 0, len(data))[0]
122 data = _parsetemplate(data, 0, len(data))[0]
123 yield (token, data, s)
123 yield (token, data, s)
124 pos += 1
124 pos += 1
125 break
125 break
126 pos += 1
126 pos += 1
127 else:
127 else:
128 raise error.ParseError(_("unterminated string"), s)
128 raise error.ParseError(_("unterminated string"), s)
129 elif c.isalnum() or c in '_':
129 elif c.isalnum() or c in '_':
130 s = pos
130 s = pos
131 pos += 1
131 pos += 1
132 while pos < end: # find end of symbol
132 while pos < end: # find end of symbol
133 d = program[pos]
133 d = program[pos]
134 if not (d.isalnum() or d == "_"):
134 if not (d.isalnum() or d == "_"):
135 break
135 break
136 pos += 1
136 pos += 1
137 sym = program[s:pos]
137 sym = program[s:pos]
138 yield ('symbol', sym, s)
138 yield ('symbol', sym, s)
139 pos -= 1
139 pos -= 1
140 elif c == term:
140 elif c == term:
141 yield ('end', None, pos + 1)
141 yield ('end', None, pos + 1)
142 return
142 return
143 else:
143 else:
144 raise error.ParseError(_("syntax error"), pos)
144 raise error.ParseError(_("syntax error"), pos)
145 pos += 1
145 pos += 1
146 if term:
146 if term:
147 raise error.ParseError(_("unterminated template expansion"), start)
147 raise error.ParseError(_("unterminated template expansion"), start)
148 yield ('end', None, pos)
148 yield ('end', None, pos)
149
149
150 def _parsetemplate(tmpl, start, stop, quote=''):
150 def _parsetemplate(tmpl, start, stop, quote=''):
151 r"""
151 r"""
152 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
152 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
153 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
153 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
154 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
154 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
155 ([('string', 'foo'), ('symbol', 'bar')], 9)
155 ([('string', 'foo'), ('symbol', 'bar')], 9)
156 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
156 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
157 ([('string', 'foo')], 4)
157 ([('string', 'foo')], 4)
158 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
158 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
159 ([('string', 'foo"'), ('string', 'bar')], 9)
159 ([('string', 'foo"'), ('string', 'bar')], 9)
160 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
160 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
161 ([('string', 'foo\\')], 6)
161 ([('string', 'foo\\')], 6)
162 """
162 """
163 parsed = []
163 parsed = []
164 sepchars = '{' + quote
164 sepchars = '{' + quote
165 pos = start
165 pos = start
166 p = parser.parser(elements)
166 p = parser.parser(elements)
167 while pos < stop:
167 while pos < stop:
168 n = min((tmpl.find(c, pos, stop) for c in sepchars),
168 n = min((tmpl.find(c, pos, stop) for c in sepchars),
169 key=lambda n: (n < 0, n))
169 key=lambda n: (n < 0, n))
170 if n < 0:
170 if n < 0:
171 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
171 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
172 pos = stop
172 pos = stop
173 break
173 break
174 c = tmpl[n:n + 1]
174 c = tmpl[n:n + 1]
175 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
175 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
176 if bs % 2 == 1:
176 if bs % 2 == 1:
177 # escaped (e.g. '\{', '\\\{', but not '\\{')
177 # escaped (e.g. '\{', '\\\{', but not '\\{')
178 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
178 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
179 pos = n + 1
179 pos = n + 1
180 continue
180 continue
181 if n > pos:
181 if n > pos:
182 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
182 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
183 if c == quote:
183 if c == quote:
184 return parsed, n + 1
184 return parsed, n + 1
185
185
186 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
186 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
187 if not tmpl.endswith('}', n + 1, pos):
187 if not tmpl.endswith('}', n + 1, pos):
188 raise error.ParseError(_("invalid token"), pos)
188 raise error.ParseError(_("invalid token"), pos)
189 parsed.append(parseres)
189 parsed.append(parseres)
190
190
191 if quote:
191 if quote:
192 raise error.ParseError(_("unterminated string"), start)
192 raise error.ParseError(_("unterminated string"), start)
193 return parsed, pos
193 return parsed, pos
194
194
195 def _unnesttemplatelist(tree):
195 def _unnesttemplatelist(tree):
196 """Expand list of templates to node tuple
196 """Expand list of templates to node tuple
197
197
198 >>> def f(tree):
198 >>> def f(tree):
199 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
199 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
200 >>> f((b'template', []))
200 >>> f((b'template', []))
201 (string '')
201 (string '')
202 >>> f((b'template', [(b'string', b'foo')]))
202 >>> f((b'template', [(b'string', b'foo')]))
203 (string 'foo')
203 (string 'foo')
204 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
204 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
205 (template
205 (template
206 (string 'foo')
206 (string 'foo')
207 (symbol 'rev'))
207 (symbol 'rev'))
208 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
208 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
209 (template
209 (template
210 (symbol 'rev'))
210 (symbol 'rev'))
211 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
211 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
212 (string 'foo')
212 (string 'foo')
213 """
213 """
214 if not isinstance(tree, tuple):
214 if not isinstance(tree, tuple):
215 return tree
215 return tree
216 op = tree[0]
216 op = tree[0]
217 if op != 'template':
217 if op != 'template':
218 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
218 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
219
219
220 assert len(tree) == 2
220 assert len(tree) == 2
221 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
221 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
222 if not xs:
222 if not xs:
223 return ('string', '') # empty template ""
223 return ('string', '') # empty template ""
224 elif len(xs) == 1 and xs[0][0] == 'string':
224 elif len(xs) == 1 and xs[0][0] == 'string':
225 return xs[0] # fast path for string with no template fragment "x"
225 return xs[0] # fast path for string with no template fragment "x"
226 else:
226 else:
227 return (op,) + xs
227 return (op,) + xs
228
228
229 def parse(tmpl):
229 def parse(tmpl):
230 """Parse template string into tree"""
230 """Parse template string into tree"""
231 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
231 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
232 assert pos == len(tmpl), 'unquoted template should be consumed'
232 assert pos == len(tmpl), 'unquoted template should be consumed'
233 return _unnesttemplatelist(('template', parsed))
233 return _unnesttemplatelist(('template', parsed))
234
234
235 def _parseexpr(expr):
235 def _parseexpr(expr):
236 """Parse a template expression into tree
236 """Parse a template expression into tree
237
237
238 >>> _parseexpr(b'"foo"')
238 >>> _parseexpr(b'"foo"')
239 ('string', 'foo')
239 ('string', 'foo')
240 >>> _parseexpr(b'foo(bar)')
240 >>> _parseexpr(b'foo(bar)')
241 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
241 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
242 >>> _parseexpr(b'foo(')
242 >>> _parseexpr(b'foo(')
243 Traceback (most recent call last):
243 Traceback (most recent call last):
244 ...
244 ...
245 ParseError: ('not a prefix: end', 4)
245 ParseError: ('not a prefix: end', 4)
246 >>> _parseexpr(b'"foo" "bar"')
246 >>> _parseexpr(b'"foo" "bar"')
247 Traceback (most recent call last):
247 Traceback (most recent call last):
248 ...
248 ...
249 ParseError: ('invalid token', 7)
249 ParseError: ('invalid token', 7)
250 """
250 """
251 p = parser.parser(elements)
251 p = parser.parser(elements)
252 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
252 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
253 if pos != len(expr):
253 if pos != len(expr):
254 raise error.ParseError(_('invalid token'), pos)
254 raise error.ParseError(_('invalid token'), pos)
255 return _unnesttemplatelist(tree)
255 return _unnesttemplatelist(tree)
256
256
257 def prettyformat(tree):
257 def prettyformat(tree):
258 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
258 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
259
259
260 def compileexp(exp, context, curmethods):
260 def compileexp(exp, context, curmethods):
261 """Compile parsed template tree to (func, data) pair"""
261 """Compile parsed template tree to (func, data) pair"""
262 if not exp:
263 raise error.ParseError(_("missing argument"))
262 t = exp[0]
264 t = exp[0]
263 if t in curmethods:
265 if t in curmethods:
264 return curmethods[t](exp, context)
266 return curmethods[t](exp, context)
265 raise error.ParseError(_("unknown method '%s'") % t)
267 raise error.ParseError(_("unknown method '%s'") % t)
266
268
267 # template evaluation
269 # template evaluation
268
270
269 def getsymbol(exp):
271 def getsymbol(exp):
270 if exp[0] == 'symbol':
272 if exp[0] == 'symbol':
271 return exp[1]
273 return exp[1]
272 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
274 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
273
275
274 def getlist(x):
276 def getlist(x):
275 if not x:
277 if not x:
276 return []
278 return []
277 if x[0] == 'list':
279 if x[0] == 'list':
278 return getlist(x[1]) + [x[2]]
280 return getlist(x[1]) + [x[2]]
279 return [x]
281 return [x]
280
282
281 def gettemplate(exp, context):
283 def gettemplate(exp, context):
282 """Compile given template tree or load named template from map file;
284 """Compile given template tree or load named template from map file;
283 returns (func, data) pair"""
285 returns (func, data) pair"""
284 if exp[0] in ('template', 'string'):
286 if exp[0] in ('template', 'string'):
285 return compileexp(exp, context, methods)
287 return compileexp(exp, context, methods)
286 if exp[0] == 'symbol':
288 if exp[0] == 'symbol':
287 # unlike runsymbol(), here 'symbol' is always taken as template name
289 # unlike runsymbol(), here 'symbol' is always taken as template name
288 # even if it exists in mapping. this allows us to override mapping
290 # even if it exists in mapping. this allows us to override mapping
289 # by web templates, e.g. 'changelogtag' is redefined in map file.
291 # by web templates, e.g. 'changelogtag' is redefined in map file.
290 return context._load(exp[1])
292 return context._load(exp[1])
291 raise error.ParseError(_("expected template specifier"))
293 raise error.ParseError(_("expected template specifier"))
292
294
293 def findsymbolicname(arg):
295 def findsymbolicname(arg):
294 """Find symbolic name for the given compiled expression; returns None
296 """Find symbolic name for the given compiled expression; returns None
295 if nothing found reliably"""
297 if nothing found reliably"""
296 while True:
298 while True:
297 func, data = arg
299 func, data = arg
298 if func is runsymbol:
300 if func is runsymbol:
299 return data
301 return data
300 elif func is runfilter:
302 elif func is runfilter:
301 arg = data[0]
303 arg = data[0]
302 else:
304 else:
303 return None
305 return None
304
306
305 def evalrawexp(context, mapping, arg):
307 def evalrawexp(context, mapping, arg):
306 """Evaluate given argument as a bare template object which may require
308 """Evaluate given argument as a bare template object which may require
307 further processing (such as folding generator of strings)"""
309 further processing (such as folding generator of strings)"""
308 func, data = arg
310 func, data = arg
309 return func(context, mapping, data)
311 return func(context, mapping, data)
310
312
311 def evalfuncarg(context, mapping, arg):
313 def evalfuncarg(context, mapping, arg):
312 """Evaluate given argument as value type"""
314 """Evaluate given argument as value type"""
313 thing = evalrawexp(context, mapping, arg)
315 thing = evalrawexp(context, mapping, arg)
314 thing = templatekw.unwrapvalue(thing)
316 thing = templatekw.unwrapvalue(thing)
315 # evalrawexp() may return string, generator of strings or arbitrary object
317 # evalrawexp() may return string, generator of strings or arbitrary object
316 # such as date tuple, but filter does not want generator.
318 # such as date tuple, but filter does not want generator.
317 if isinstance(thing, types.GeneratorType):
319 if isinstance(thing, types.GeneratorType):
318 thing = stringify(thing)
320 thing = stringify(thing)
319 return thing
321 return thing
320
322
321 def evalboolean(context, mapping, arg):
323 def evalboolean(context, mapping, arg):
322 """Evaluate given argument as boolean, but also takes boolean literals"""
324 """Evaluate given argument as boolean, but also takes boolean literals"""
323 func, data = arg
325 func, data = arg
324 if func is runsymbol:
326 if func is runsymbol:
325 thing = func(context, mapping, data, default=None)
327 thing = func(context, mapping, data, default=None)
326 if thing is None:
328 if thing is None:
327 # not a template keyword, takes as a boolean literal
329 # not a template keyword, takes as a boolean literal
328 thing = util.parsebool(data)
330 thing = util.parsebool(data)
329 else:
331 else:
330 thing = func(context, mapping, data)
332 thing = func(context, mapping, data)
331 thing = templatekw.unwrapvalue(thing)
333 thing = templatekw.unwrapvalue(thing)
332 if isinstance(thing, bool):
334 if isinstance(thing, bool):
333 return thing
335 return thing
334 # other objects are evaluated as strings, which means 0 is True, but
336 # other objects are evaluated as strings, which means 0 is True, but
335 # empty dict/list should be False as they are expected to be ''
337 # empty dict/list should be False as they are expected to be ''
336 return bool(stringify(thing))
338 return bool(stringify(thing))
337
339
338 def evalinteger(context, mapping, arg, err=None):
340 def evalinteger(context, mapping, arg, err=None):
339 v = evalfuncarg(context, mapping, arg)
341 v = evalfuncarg(context, mapping, arg)
340 try:
342 try:
341 return int(v)
343 return int(v)
342 except (TypeError, ValueError):
344 except (TypeError, ValueError):
343 raise error.ParseError(err or _('not an integer'))
345 raise error.ParseError(err or _('not an integer'))
344
346
345 def evalstring(context, mapping, arg):
347 def evalstring(context, mapping, arg):
346 return stringify(evalrawexp(context, mapping, arg))
348 return stringify(evalrawexp(context, mapping, arg))
347
349
348 def evalstringliteral(context, mapping, arg):
350 def evalstringliteral(context, mapping, arg):
349 """Evaluate given argument as string template, but returns symbol name
351 """Evaluate given argument as string template, but returns symbol name
350 if it is unknown"""
352 if it is unknown"""
351 func, data = arg
353 func, data = arg
352 if func is runsymbol:
354 if func is runsymbol:
353 thing = func(context, mapping, data, default=data)
355 thing = func(context, mapping, data, default=data)
354 else:
356 else:
355 thing = func(context, mapping, data)
357 thing = func(context, mapping, data)
356 return stringify(thing)
358 return stringify(thing)
357
359
358 _evalfuncbytype = {
360 _evalfuncbytype = {
359 bool: evalboolean,
361 bool: evalboolean,
360 bytes: evalstring,
362 bytes: evalstring,
361 int: evalinteger,
363 int: evalinteger,
362 }
364 }
363
365
364 def evalastype(context, mapping, arg, typ):
366 def evalastype(context, mapping, arg, typ):
365 """Evaluate given argument and coerce its type"""
367 """Evaluate given argument and coerce its type"""
366 try:
368 try:
367 f = _evalfuncbytype[typ]
369 f = _evalfuncbytype[typ]
368 except KeyError:
370 except KeyError:
369 raise error.ProgrammingError('invalid type specified: %r' % typ)
371 raise error.ProgrammingError('invalid type specified: %r' % typ)
370 return f(context, mapping, arg)
372 return f(context, mapping, arg)
371
373
372 def runinteger(context, mapping, data):
374 def runinteger(context, mapping, data):
373 return int(data)
375 return int(data)
374
376
375 def runstring(context, mapping, data):
377 def runstring(context, mapping, data):
376 return data
378 return data
377
379
378 def _recursivesymbolblocker(key):
380 def _recursivesymbolblocker(key):
379 def showrecursion(**args):
381 def showrecursion(**args):
380 raise error.Abort(_("recursive reference '%s' in template") % key)
382 raise error.Abort(_("recursive reference '%s' in template") % key)
381 return showrecursion
383 return showrecursion
382
384
383 def _runrecursivesymbol(context, mapping, key):
385 def _runrecursivesymbol(context, mapping, key):
384 raise error.Abort(_("recursive reference '%s' in template") % key)
386 raise error.Abort(_("recursive reference '%s' in template") % key)
385
387
386 def runsymbol(context, mapping, key, default=''):
388 def runsymbol(context, mapping, key, default=''):
387 v = context.symbol(mapping, key)
389 v = context.symbol(mapping, key)
388 if v is None:
390 if v is None:
389 # put poison to cut recursion. we can't move this to parsing phase
391 # put poison to cut recursion. we can't move this to parsing phase
390 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
392 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
391 safemapping = mapping.copy()
393 safemapping = mapping.copy()
392 safemapping[key] = _recursivesymbolblocker(key)
394 safemapping[key] = _recursivesymbolblocker(key)
393 try:
395 try:
394 v = context.process(key, safemapping)
396 v = context.process(key, safemapping)
395 except TemplateNotFound:
397 except TemplateNotFound:
396 v = default
398 v = default
397 if callable(v):
399 if callable(v):
398 # TODO: templatekw functions will be updated to take (context, mapping)
400 # TODO: templatekw functions will be updated to take (context, mapping)
399 # pair instead of **props
401 # pair instead of **props
400 props = context._resources.copy()
402 props = context._resources.copy()
401 props.update(mapping)
403 props.update(mapping)
402 return v(**pycompat.strkwargs(props))
404 return v(**pycompat.strkwargs(props))
403 return v
405 return v
404
406
405 def buildtemplate(exp, context):
407 def buildtemplate(exp, context):
406 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
408 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
407 return (runtemplate, ctmpl)
409 return (runtemplate, ctmpl)
408
410
409 def runtemplate(context, mapping, template):
411 def runtemplate(context, mapping, template):
410 for arg in template:
412 for arg in template:
411 yield evalrawexp(context, mapping, arg)
413 yield evalrawexp(context, mapping, arg)
412
414
413 def buildfilter(exp, context):
415 def buildfilter(exp, context):
414 n = getsymbol(exp[2])
416 n = getsymbol(exp[2])
415 if n in context._filters:
417 if n in context._filters:
416 filt = context._filters[n]
418 filt = context._filters[n]
417 arg = compileexp(exp[1], context, methods)
419 arg = compileexp(exp[1], context, methods)
418 return (runfilter, (arg, filt))
420 return (runfilter, (arg, filt))
419 if n in funcs:
421 if n in funcs:
420 f = funcs[n]
422 f = funcs[n]
421 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
423 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
422 return (f, args)
424 return (f, args)
423 raise error.ParseError(_("unknown function '%s'") % n)
425 raise error.ParseError(_("unknown function '%s'") % n)
424
426
425 def runfilter(context, mapping, data):
427 def runfilter(context, mapping, data):
426 arg, filt = data
428 arg, filt = data
427 thing = evalfuncarg(context, mapping, arg)
429 thing = evalfuncarg(context, mapping, arg)
428 try:
430 try:
429 return filt(thing)
431 return filt(thing)
430 except (ValueError, AttributeError, TypeError):
432 except (ValueError, AttributeError, TypeError):
431 sym = findsymbolicname(arg)
433 sym = findsymbolicname(arg)
432 if sym:
434 if sym:
433 msg = (_("template filter '%s' is not compatible with keyword '%s'")
435 msg = (_("template filter '%s' is not compatible with keyword '%s'")
434 % (pycompat.sysbytes(filt.__name__), sym))
436 % (pycompat.sysbytes(filt.__name__), sym))
435 else:
437 else:
436 msg = (_("incompatible use of template filter '%s'")
438 msg = (_("incompatible use of template filter '%s'")
437 % pycompat.sysbytes(filt.__name__))
439 % pycompat.sysbytes(filt.__name__))
438 raise error.Abort(msg)
440 raise error.Abort(msg)
439
441
440 def buildmap(exp, context):
442 def buildmap(exp, context):
441 darg = compileexp(exp[1], context, methods)
443 darg = compileexp(exp[1], context, methods)
442 targ = gettemplate(exp[2], context)
444 targ = gettemplate(exp[2], context)
443 return (runmap, (darg, targ))
445 return (runmap, (darg, targ))
444
446
445 def runmap(context, mapping, data):
447 def runmap(context, mapping, data):
446 darg, targ = data
448 darg, targ = data
447 d = evalrawexp(context, mapping, darg)
449 d = evalrawexp(context, mapping, darg)
448 if util.safehasattr(d, 'itermaps'):
450 if util.safehasattr(d, 'itermaps'):
449 diter = d.itermaps()
451 diter = d.itermaps()
450 else:
452 else:
451 try:
453 try:
452 diter = iter(d)
454 diter = iter(d)
453 except TypeError:
455 except TypeError:
454 sym = findsymbolicname(darg)
456 sym = findsymbolicname(darg)
455 if sym:
457 if sym:
456 raise error.ParseError(_("keyword '%s' is not iterable") % sym)
458 raise error.ParseError(_("keyword '%s' is not iterable") % sym)
457 else:
459 else:
458 raise error.ParseError(_("%r is not iterable") % d)
460 raise error.ParseError(_("%r is not iterable") % d)
459
461
460 for i, v in enumerate(diter):
462 for i, v in enumerate(diter):
461 lm = mapping.copy()
463 lm = mapping.copy()
462 lm['index'] = i
464 lm['index'] = i
463 if isinstance(v, dict):
465 if isinstance(v, dict):
464 lm.update(v)
466 lm.update(v)
465 lm['originalnode'] = mapping.get('node')
467 lm['originalnode'] = mapping.get('node')
466 yield evalrawexp(context, lm, targ)
468 yield evalrawexp(context, lm, targ)
467 else:
469 else:
468 # v is not an iterable of dicts, this happen when 'key'
470 # v is not an iterable of dicts, this happen when 'key'
469 # has been fully expanded already and format is useless.
471 # has been fully expanded already and format is useless.
470 # If so, return the expanded value.
472 # If so, return the expanded value.
471 yield v
473 yield v
472
474
473 def buildmember(exp, context):
475 def buildmember(exp, context):
474 darg = compileexp(exp[1], context, methods)
476 darg = compileexp(exp[1], context, methods)
475 memb = getsymbol(exp[2])
477 memb = getsymbol(exp[2])
476 return (runmember, (darg, memb))
478 return (runmember, (darg, memb))
477
479
478 def runmember(context, mapping, data):
480 def runmember(context, mapping, data):
479 darg, memb = data
481 darg, memb = data
480 d = evalrawexp(context, mapping, darg)
482 d = evalrawexp(context, mapping, darg)
481 if util.safehasattr(d, 'tomap'):
483 if util.safehasattr(d, 'tomap'):
482 lm = mapping.copy()
484 lm = mapping.copy()
483 lm.update(d.tomap())
485 lm.update(d.tomap())
484 return runsymbol(context, lm, memb)
486 return runsymbol(context, lm, memb)
485 if util.safehasattr(d, 'get'):
487 if util.safehasattr(d, 'get'):
486 return _getdictitem(d, memb)
488 return _getdictitem(d, memb)
487
489
488 sym = findsymbolicname(darg)
490 sym = findsymbolicname(darg)
489 if sym:
491 if sym:
490 raise error.ParseError(_("keyword '%s' has no member") % sym)
492 raise error.ParseError(_("keyword '%s' has no member") % sym)
491 else:
493 else:
492 raise error.ParseError(_("%r has no member") % d)
494 raise error.ParseError(_("%r has no member") % d)
493
495
494 def buildnegate(exp, context):
496 def buildnegate(exp, context):
495 arg = compileexp(exp[1], context, exprmethods)
497 arg = compileexp(exp[1], context, exprmethods)
496 return (runnegate, arg)
498 return (runnegate, arg)
497
499
498 def runnegate(context, mapping, data):
500 def runnegate(context, mapping, data):
499 data = evalinteger(context, mapping, data,
501 data = evalinteger(context, mapping, data,
500 _('negation needs an integer argument'))
502 _('negation needs an integer argument'))
501 return -data
503 return -data
502
504
503 def buildarithmetic(exp, context, func):
505 def buildarithmetic(exp, context, func):
504 left = compileexp(exp[1], context, exprmethods)
506 left = compileexp(exp[1], context, exprmethods)
505 right = compileexp(exp[2], context, exprmethods)
507 right = compileexp(exp[2], context, exprmethods)
506 return (runarithmetic, (func, left, right))
508 return (runarithmetic, (func, left, right))
507
509
508 def runarithmetic(context, mapping, data):
510 def runarithmetic(context, mapping, data):
509 func, left, right = data
511 func, left, right = data
510 left = evalinteger(context, mapping, left,
512 left = evalinteger(context, mapping, left,
511 _('arithmetic only defined on integers'))
513 _('arithmetic only defined on integers'))
512 right = evalinteger(context, mapping, right,
514 right = evalinteger(context, mapping, right,
513 _('arithmetic only defined on integers'))
515 _('arithmetic only defined on integers'))
514 try:
516 try:
515 return func(left, right)
517 return func(left, right)
516 except ZeroDivisionError:
518 except ZeroDivisionError:
517 raise error.Abort(_('division by zero is not defined'))
519 raise error.Abort(_('division by zero is not defined'))
518
520
519 def buildfunc(exp, context):
521 def buildfunc(exp, context):
520 n = getsymbol(exp[1])
522 n = getsymbol(exp[1])
521 if n in funcs:
523 if n in funcs:
522 f = funcs[n]
524 f = funcs[n]
523 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
525 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
524 return (f, args)
526 return (f, args)
525 if n in context._filters:
527 if n in context._filters:
526 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
528 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
527 if len(args) != 1:
529 if len(args) != 1:
528 raise error.ParseError(_("filter %s expects one argument") % n)
530 raise error.ParseError(_("filter %s expects one argument") % n)
529 f = context._filters[n]
531 f = context._filters[n]
530 return (runfilter, (args[0], f))
532 return (runfilter, (args[0], f))
531 raise error.ParseError(_("unknown function '%s'") % n)
533 raise error.ParseError(_("unknown function '%s'") % n)
532
534
533 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
535 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
534 """Compile parsed tree of function arguments into list or dict of
536 """Compile parsed tree of function arguments into list or dict of
535 (func, data) pairs
537 (func, data) pairs
536
538
537 >>> context = engine(lambda t: (runsymbol, t))
539 >>> context = engine(lambda t: (runsymbol, t))
538 >>> def fargs(expr, argspec):
540 >>> def fargs(expr, argspec):
539 ... x = _parseexpr(expr)
541 ... x = _parseexpr(expr)
540 ... n = getsymbol(x[1])
542 ... n = getsymbol(x[1])
541 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
543 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
542 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
544 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
543 ['l', 'k']
545 ['l', 'k']
544 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
546 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
545 >>> list(args.keys()), list(args[b'opts'].keys())
547 >>> list(args.keys()), list(args[b'opts'].keys())
546 (['opts'], ['opts', 'k'])
548 (['opts'], ['opts', 'k'])
547 """
549 """
548 def compiledict(xs):
550 def compiledict(xs):
549 return util.sortdict((k, compileexp(x, context, curmethods))
551 return util.sortdict((k, compileexp(x, context, curmethods))
550 for k, x in xs.iteritems())
552 for k, x in xs.iteritems())
551 def compilelist(xs):
553 def compilelist(xs):
552 return [compileexp(x, context, curmethods) for x in xs]
554 return [compileexp(x, context, curmethods) for x in xs]
553
555
554 if not argspec:
556 if not argspec:
555 # filter or function with no argspec: return list of positional args
557 # filter or function with no argspec: return list of positional args
556 return compilelist(getlist(exp))
558 return compilelist(getlist(exp))
557
559
558 # function with argspec: return dict of named args
560 # function with argspec: return dict of named args
559 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
561 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
560 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
562 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
561 keyvaluenode='keyvalue', keynode='symbol')
563 keyvaluenode='keyvalue', keynode='symbol')
562 compargs = util.sortdict()
564 compargs = util.sortdict()
563 if varkey:
565 if varkey:
564 compargs[varkey] = compilelist(treeargs.pop(varkey))
566 compargs[varkey] = compilelist(treeargs.pop(varkey))
565 if optkey:
567 if optkey:
566 compargs[optkey] = compiledict(treeargs.pop(optkey))
568 compargs[optkey] = compiledict(treeargs.pop(optkey))
567 compargs.update(compiledict(treeargs))
569 compargs.update(compiledict(treeargs))
568 return compargs
570 return compargs
569
571
570 def buildkeyvaluepair(exp, content):
572 def buildkeyvaluepair(exp, content):
571 raise error.ParseError(_("can't use a key-value pair in this context"))
573 raise error.ParseError(_("can't use a key-value pair in this context"))
572
574
573 # dict of template built-in functions
575 # dict of template built-in functions
574 funcs = {}
576 funcs = {}
575
577
576 templatefunc = registrar.templatefunc(funcs)
578 templatefunc = registrar.templatefunc(funcs)
577
579
578 @templatefunc('date(date[, fmt])')
580 @templatefunc('date(date[, fmt])')
579 def date(context, mapping, args):
581 def date(context, mapping, args):
580 """Format a date. See :hg:`help dates` for formatting
582 """Format a date. See :hg:`help dates` for formatting
581 strings. The default is a Unix date format, including the timezone:
583 strings. The default is a Unix date format, including the timezone:
582 "Mon Sep 04 15:13:13 2006 0700"."""
584 "Mon Sep 04 15:13:13 2006 0700"."""
583 if not (1 <= len(args) <= 2):
585 if not (1 <= len(args) <= 2):
584 # i18n: "date" is a keyword
586 # i18n: "date" is a keyword
585 raise error.ParseError(_("date expects one or two arguments"))
587 raise error.ParseError(_("date expects one or two arguments"))
586
588
587 date = evalfuncarg(context, mapping, args[0])
589 date = evalfuncarg(context, mapping, args[0])
588 fmt = None
590 fmt = None
589 if len(args) == 2:
591 if len(args) == 2:
590 fmt = evalstring(context, mapping, args[1])
592 fmt = evalstring(context, mapping, args[1])
591 try:
593 try:
592 if fmt is None:
594 if fmt is None:
593 return util.datestr(date)
595 return util.datestr(date)
594 else:
596 else:
595 return util.datestr(date, fmt)
597 return util.datestr(date, fmt)
596 except (TypeError, ValueError):
598 except (TypeError, ValueError):
597 # i18n: "date" is a keyword
599 # i18n: "date" is a keyword
598 raise error.ParseError(_("date expects a date information"))
600 raise error.ParseError(_("date expects a date information"))
599
601
600 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
602 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
601 def dict_(context, mapping, args):
603 def dict_(context, mapping, args):
602 """Construct a dict from key-value pairs. A key may be omitted if
604 """Construct a dict from key-value pairs. A key may be omitted if
603 a value expression can provide an unambiguous name."""
605 a value expression can provide an unambiguous name."""
604 data = util.sortdict()
606 data = util.sortdict()
605
607
606 for v in args['args']:
608 for v in args['args']:
607 k = findsymbolicname(v)
609 k = findsymbolicname(v)
608 if not k:
610 if not k:
609 raise error.ParseError(_('dict key cannot be inferred'))
611 raise error.ParseError(_('dict key cannot be inferred'))
610 if k in data or k in args['kwargs']:
612 if k in data or k in args['kwargs']:
611 raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
613 raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
612 data[k] = evalfuncarg(context, mapping, v)
614 data[k] = evalfuncarg(context, mapping, v)
613
615
614 data.update((k, evalfuncarg(context, mapping, v))
616 data.update((k, evalfuncarg(context, mapping, v))
615 for k, v in args['kwargs'].iteritems())
617 for k, v in args['kwargs'].iteritems())
616 return templatekw.hybriddict(data)
618 return templatekw.hybriddict(data)
617
619
618 @templatefunc('diff([includepattern [, excludepattern]])')
620 @templatefunc('diff([includepattern [, excludepattern]])')
619 def diff(context, mapping, args):
621 def diff(context, mapping, args):
620 """Show a diff, optionally
622 """Show a diff, optionally
621 specifying files to include or exclude."""
623 specifying files to include or exclude."""
622 if len(args) > 2:
624 if len(args) > 2:
623 # i18n: "diff" is a keyword
625 # i18n: "diff" is a keyword
624 raise error.ParseError(_("diff expects zero, one, or two arguments"))
626 raise error.ParseError(_("diff expects zero, one, or two arguments"))
625
627
626 def getpatterns(i):
628 def getpatterns(i):
627 if i < len(args):
629 if i < len(args):
628 s = evalstring(context, mapping, args[i]).strip()
630 s = evalstring(context, mapping, args[i]).strip()
629 if s:
631 if s:
630 return [s]
632 return [s]
631 return []
633 return []
632
634
633 ctx = context.resource(mapping, 'ctx')
635 ctx = context.resource(mapping, 'ctx')
634 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
636 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
635
637
636 return ''.join(chunks)
638 return ''.join(chunks)
637
639
638 @templatefunc('extdata(source)', argspec='source')
640 @templatefunc('extdata(source)', argspec='source')
639 def extdata(context, mapping, args):
641 def extdata(context, mapping, args):
640 """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
642 """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
641 if 'source' not in args:
643 if 'source' not in args:
642 # i18n: "extdata" is a keyword
644 # i18n: "extdata" is a keyword
643 raise error.ParseError(_('extdata expects one argument'))
645 raise error.ParseError(_('extdata expects one argument'))
644
646
645 source = evalstring(context, mapping, args['source'])
647 source = evalstring(context, mapping, args['source'])
646 cache = context.resource(mapping, 'cache').setdefault('extdata', {})
648 cache = context.resource(mapping, 'cache').setdefault('extdata', {})
647 ctx = context.resource(mapping, 'ctx')
649 ctx = context.resource(mapping, 'ctx')
648 if source in cache:
650 if source in cache:
649 data = cache[source]
651 data = cache[source]
650 else:
652 else:
651 data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
653 data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
652 return data.get(ctx.rev(), '')
654 return data.get(ctx.rev(), '')
653
655
654 @templatefunc('files(pattern)')
656 @templatefunc('files(pattern)')
655 def files(context, mapping, args):
657 def files(context, mapping, args):
656 """All files of the current changeset matching the pattern. See
658 """All files of the current changeset matching the pattern. See
657 :hg:`help patterns`."""
659 :hg:`help patterns`."""
658 if not len(args) == 1:
660 if not len(args) == 1:
659 # i18n: "files" is a keyword
661 # i18n: "files" is a keyword
660 raise error.ParseError(_("files expects one argument"))
662 raise error.ParseError(_("files expects one argument"))
661
663
662 raw = evalstring(context, mapping, args[0])
664 raw = evalstring(context, mapping, args[0])
663 ctx = context.resource(mapping, 'ctx')
665 ctx = context.resource(mapping, 'ctx')
664 m = ctx.match([raw])
666 m = ctx.match([raw])
665 files = list(ctx.matches(m))
667 files = list(ctx.matches(m))
666 # TODO: pass (context, mapping) pair to keyword function
668 # TODO: pass (context, mapping) pair to keyword function
667 props = context._resources.copy()
669 props = context._resources.copy()
668 props.update(mapping)
670 props.update(mapping)
669 return templatekw.showlist("file", files, props)
671 return templatekw.showlist("file", files, props)
670
672
671 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
673 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
672 def fill(context, mapping, args):
674 def fill(context, mapping, args):
673 """Fill many
675 """Fill many
674 paragraphs with optional indentation. See the "fill" filter."""
676 paragraphs with optional indentation. See the "fill" filter."""
675 if not (1 <= len(args) <= 4):
677 if not (1 <= len(args) <= 4):
676 # i18n: "fill" is a keyword
678 # i18n: "fill" is a keyword
677 raise error.ParseError(_("fill expects one to four arguments"))
679 raise error.ParseError(_("fill expects one to four arguments"))
678
680
679 text = evalstring(context, mapping, args[0])
681 text = evalstring(context, mapping, args[0])
680 width = 76
682 width = 76
681 initindent = ''
683 initindent = ''
682 hangindent = ''
684 hangindent = ''
683 if 2 <= len(args) <= 4:
685 if 2 <= len(args) <= 4:
684 width = evalinteger(context, mapping, args[1],
686 width = evalinteger(context, mapping, args[1],
685 # i18n: "fill" is a keyword
687 # i18n: "fill" is a keyword
686 _("fill expects an integer width"))
688 _("fill expects an integer width"))
687 try:
689 try:
688 initindent = evalstring(context, mapping, args[2])
690 initindent = evalstring(context, mapping, args[2])
689 hangindent = evalstring(context, mapping, args[3])
691 hangindent = evalstring(context, mapping, args[3])
690 except IndexError:
692 except IndexError:
691 pass
693 pass
692
694
693 return templatefilters.fill(text, width, initindent, hangindent)
695 return templatefilters.fill(text, width, initindent, hangindent)
694
696
695 @templatefunc('formatnode(node)')
697 @templatefunc('formatnode(node)')
696 def formatnode(context, mapping, args):
698 def formatnode(context, mapping, args):
697 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
699 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
698 if len(args) != 1:
700 if len(args) != 1:
699 # i18n: "formatnode" is a keyword
701 # i18n: "formatnode" is a keyword
700 raise error.ParseError(_("formatnode expects one argument"))
702 raise error.ParseError(_("formatnode expects one argument"))
701
703
702 ui = context.resource(mapping, 'ui')
704 ui = context.resource(mapping, 'ui')
703 node = evalstring(context, mapping, args[0])
705 node = evalstring(context, mapping, args[0])
704 if ui.debugflag:
706 if ui.debugflag:
705 return node
707 return node
706 return templatefilters.short(node)
708 return templatefilters.short(node)
707
709
708 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
710 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
709 argspec='text width fillchar left')
711 argspec='text width fillchar left')
710 def pad(context, mapping, args):
712 def pad(context, mapping, args):
711 """Pad text with a
713 """Pad text with a
712 fill character."""
714 fill character."""
713 if 'text' not in args or 'width' not in args:
715 if 'text' not in args or 'width' not in args:
714 # i18n: "pad" is a keyword
716 # i18n: "pad" is a keyword
715 raise error.ParseError(_("pad() expects two to four arguments"))
717 raise error.ParseError(_("pad() expects two to four arguments"))
716
718
717 width = evalinteger(context, mapping, args['width'],
719 width = evalinteger(context, mapping, args['width'],
718 # i18n: "pad" is a keyword
720 # i18n: "pad" is a keyword
719 _("pad() expects an integer width"))
721 _("pad() expects an integer width"))
720
722
721 text = evalstring(context, mapping, args['text'])
723 text = evalstring(context, mapping, args['text'])
722
724
723 left = False
725 left = False
724 fillchar = ' '
726 fillchar = ' '
725 if 'fillchar' in args:
727 if 'fillchar' in args:
726 fillchar = evalstring(context, mapping, args['fillchar'])
728 fillchar = evalstring(context, mapping, args['fillchar'])
727 if len(color.stripeffects(fillchar)) != 1:
729 if len(color.stripeffects(fillchar)) != 1:
728 # i18n: "pad" is a keyword
730 # i18n: "pad" is a keyword
729 raise error.ParseError(_("pad() expects a single fill character"))
731 raise error.ParseError(_("pad() expects a single fill character"))
730 if 'left' in args:
732 if 'left' in args:
731 left = evalboolean(context, mapping, args['left'])
733 left = evalboolean(context, mapping, args['left'])
732
734
733 fillwidth = width - encoding.colwidth(color.stripeffects(text))
735 fillwidth = width - encoding.colwidth(color.stripeffects(text))
734 if fillwidth <= 0:
736 if fillwidth <= 0:
735 return text
737 return text
736 if left:
738 if left:
737 return fillchar * fillwidth + text
739 return fillchar * fillwidth + text
738 else:
740 else:
739 return text + fillchar * fillwidth
741 return text + fillchar * fillwidth
740
742
741 @templatefunc('indent(text, indentchars[, firstline])')
743 @templatefunc('indent(text, indentchars[, firstline])')
742 def indent(context, mapping, args):
744 def indent(context, mapping, args):
743 """Indents all non-empty lines
745 """Indents all non-empty lines
744 with the characters given in the indentchars string. An optional
746 with the characters given in the indentchars string. An optional
745 third parameter will override the indent for the first line only
747 third parameter will override the indent for the first line only
746 if present."""
748 if present."""
747 if not (2 <= len(args) <= 3):
749 if not (2 <= len(args) <= 3):
748 # i18n: "indent" is a keyword
750 # i18n: "indent" is a keyword
749 raise error.ParseError(_("indent() expects two or three arguments"))
751 raise error.ParseError(_("indent() expects two or three arguments"))
750
752
751 text = evalstring(context, mapping, args[0])
753 text = evalstring(context, mapping, args[0])
752 indent = evalstring(context, mapping, args[1])
754 indent = evalstring(context, mapping, args[1])
753
755
754 if len(args) == 3:
756 if len(args) == 3:
755 firstline = evalstring(context, mapping, args[2])
757 firstline = evalstring(context, mapping, args[2])
756 else:
758 else:
757 firstline = indent
759 firstline = indent
758
760
759 # the indent function doesn't indent the first line, so we do it here
761 # the indent function doesn't indent the first line, so we do it here
760 return templatefilters.indent(firstline + text, indent)
762 return templatefilters.indent(firstline + text, indent)
761
763
762 @templatefunc('get(dict, key)')
764 @templatefunc('get(dict, key)')
763 def get(context, mapping, args):
765 def get(context, mapping, args):
764 """Get an attribute/key from an object. Some keywords
766 """Get an attribute/key from an object. Some keywords
765 are complex types. This function allows you to obtain the value of an
767 are complex types. This function allows you to obtain the value of an
766 attribute on these types."""
768 attribute on these types."""
767 if len(args) != 2:
769 if len(args) != 2:
768 # i18n: "get" is a keyword
770 # i18n: "get" is a keyword
769 raise error.ParseError(_("get() expects two arguments"))
771 raise error.ParseError(_("get() expects two arguments"))
770
772
771 dictarg = evalfuncarg(context, mapping, args[0])
773 dictarg = evalfuncarg(context, mapping, args[0])
772 if not util.safehasattr(dictarg, 'get'):
774 if not util.safehasattr(dictarg, 'get'):
773 # i18n: "get" is a keyword
775 # i18n: "get" is a keyword
774 raise error.ParseError(_("get() expects a dict as first argument"))
776 raise error.ParseError(_("get() expects a dict as first argument"))
775
777
776 key = evalfuncarg(context, mapping, args[1])
778 key = evalfuncarg(context, mapping, args[1])
777 return _getdictitem(dictarg, key)
779 return _getdictitem(dictarg, key)
778
780
779 def _getdictitem(dictarg, key):
781 def _getdictitem(dictarg, key):
780 val = dictarg.get(key)
782 val = dictarg.get(key)
781 if val is None:
783 if val is None:
782 return
784 return
783 return templatekw.wraphybridvalue(dictarg, key, val)
785 return templatekw.wraphybridvalue(dictarg, key, val)
784
786
785 @templatefunc('if(expr, then[, else])')
787 @templatefunc('if(expr, then[, else])')
786 def if_(context, mapping, args):
788 def if_(context, mapping, args):
787 """Conditionally execute based on the result of
789 """Conditionally execute based on the result of
788 an expression."""
790 an expression."""
789 if not (2 <= len(args) <= 3):
791 if not (2 <= len(args) <= 3):
790 # i18n: "if" is a keyword
792 # i18n: "if" is a keyword
791 raise error.ParseError(_("if expects two or three arguments"))
793 raise error.ParseError(_("if expects two or three arguments"))
792
794
793 test = evalboolean(context, mapping, args[0])
795 test = evalboolean(context, mapping, args[0])
794 if test:
796 if test:
795 yield evalrawexp(context, mapping, args[1])
797 yield evalrawexp(context, mapping, args[1])
796 elif len(args) == 3:
798 elif len(args) == 3:
797 yield evalrawexp(context, mapping, args[2])
799 yield evalrawexp(context, mapping, args[2])
798
800
799 @templatefunc('ifcontains(needle, haystack, then[, else])')
801 @templatefunc('ifcontains(needle, haystack, then[, else])')
800 def ifcontains(context, mapping, args):
802 def ifcontains(context, mapping, args):
801 """Conditionally execute based
803 """Conditionally execute based
802 on whether the item "needle" is in "haystack"."""
804 on whether the item "needle" is in "haystack"."""
803 if not (3 <= len(args) <= 4):
805 if not (3 <= len(args) <= 4):
804 # i18n: "ifcontains" is a keyword
806 # i18n: "ifcontains" is a keyword
805 raise error.ParseError(_("ifcontains expects three or four arguments"))
807 raise error.ParseError(_("ifcontains expects three or four arguments"))
806
808
807 haystack = evalfuncarg(context, mapping, args[1])
809 haystack = evalfuncarg(context, mapping, args[1])
808 try:
810 try:
809 needle = evalastype(context, mapping, args[0],
811 needle = evalastype(context, mapping, args[0],
810 getattr(haystack, 'keytype', None) or bytes)
812 getattr(haystack, 'keytype', None) or bytes)
811 found = (needle in haystack)
813 found = (needle in haystack)
812 except error.ParseError:
814 except error.ParseError:
813 found = False
815 found = False
814
816
815 if found:
817 if found:
816 yield evalrawexp(context, mapping, args[2])
818 yield evalrawexp(context, mapping, args[2])
817 elif len(args) == 4:
819 elif len(args) == 4:
818 yield evalrawexp(context, mapping, args[3])
820 yield evalrawexp(context, mapping, args[3])
819
821
820 @templatefunc('ifeq(expr1, expr2, then[, else])')
822 @templatefunc('ifeq(expr1, expr2, then[, else])')
821 def ifeq(context, mapping, args):
823 def ifeq(context, mapping, args):
822 """Conditionally execute based on
824 """Conditionally execute based on
823 whether 2 items are equivalent."""
825 whether 2 items are equivalent."""
824 if not (3 <= len(args) <= 4):
826 if not (3 <= len(args) <= 4):
825 # i18n: "ifeq" is a keyword
827 # i18n: "ifeq" is a keyword
826 raise error.ParseError(_("ifeq expects three or four arguments"))
828 raise error.ParseError(_("ifeq expects three or four arguments"))
827
829
828 test = evalstring(context, mapping, args[0])
830 test = evalstring(context, mapping, args[0])
829 match = evalstring(context, mapping, args[1])
831 match = evalstring(context, mapping, args[1])
830 if test == match:
832 if test == match:
831 yield evalrawexp(context, mapping, args[2])
833 yield evalrawexp(context, mapping, args[2])
832 elif len(args) == 4:
834 elif len(args) == 4:
833 yield evalrawexp(context, mapping, args[3])
835 yield evalrawexp(context, mapping, args[3])
834
836
835 @templatefunc('join(list, sep)')
837 @templatefunc('join(list, sep)')
836 def join(context, mapping, args):
838 def join(context, mapping, args):
837 """Join items in a list with a delimiter."""
839 """Join items in a list with a delimiter."""
838 if not (1 <= len(args) <= 2):
840 if not (1 <= len(args) <= 2):
839 # i18n: "join" is a keyword
841 # i18n: "join" is a keyword
840 raise error.ParseError(_("join expects one or two arguments"))
842 raise error.ParseError(_("join expects one or two arguments"))
841
843
842 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
844 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
843 # abuses generator as a keyword that returns a list of dicts.
845 # abuses generator as a keyword that returns a list of dicts.
844 joinset = evalrawexp(context, mapping, args[0])
846 joinset = evalrawexp(context, mapping, args[0])
845 joinset = templatekw.unwrapvalue(joinset)
847 joinset = templatekw.unwrapvalue(joinset)
846 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
848 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
847 joiner = " "
849 joiner = " "
848 if len(args) > 1:
850 if len(args) > 1:
849 joiner = evalstring(context, mapping, args[1])
851 joiner = evalstring(context, mapping, args[1])
850
852
851 first = True
853 first = True
852 for x in joinset:
854 for x in joinset:
853 if first:
855 if first:
854 first = False
856 first = False
855 else:
857 else:
856 yield joiner
858 yield joiner
857 yield joinfmt(x)
859 yield joinfmt(x)
858
860
859 @templatefunc('label(label, expr)')
861 @templatefunc('label(label, expr)')
860 def label(context, mapping, args):
862 def label(context, mapping, args):
861 """Apply a label to generated content. Content with
863 """Apply a label to generated content. Content with
862 a label applied can result in additional post-processing, such as
864 a label applied can result in additional post-processing, such as
863 automatic colorization."""
865 automatic colorization."""
864 if len(args) != 2:
866 if len(args) != 2:
865 # i18n: "label" is a keyword
867 # i18n: "label" is a keyword
866 raise error.ParseError(_("label expects two arguments"))
868 raise error.ParseError(_("label expects two arguments"))
867
869
868 ui = context.resource(mapping, 'ui')
870 ui = context.resource(mapping, 'ui')
869 thing = evalstring(context, mapping, args[1])
871 thing = evalstring(context, mapping, args[1])
870 # preserve unknown symbol as literal so effects like 'red', 'bold',
872 # preserve unknown symbol as literal so effects like 'red', 'bold',
871 # etc. don't need to be quoted
873 # etc. don't need to be quoted
872 label = evalstringliteral(context, mapping, args[0])
874 label = evalstringliteral(context, mapping, args[0])
873
875
874 return ui.label(thing, label)
876 return ui.label(thing, label)
875
877
876 @templatefunc('latesttag([pattern])')
878 @templatefunc('latesttag([pattern])')
877 def latesttag(context, mapping, args):
879 def latesttag(context, mapping, args):
878 """The global tags matching the given pattern on the
880 """The global tags matching the given pattern on the
879 most recent globally tagged ancestor of this changeset.
881 most recent globally tagged ancestor of this changeset.
880 If no such tags exist, the "{tag}" template resolves to
882 If no such tags exist, the "{tag}" template resolves to
881 the string "null"."""
883 the string "null"."""
882 if len(args) > 1:
884 if len(args) > 1:
883 # i18n: "latesttag" is a keyword
885 # i18n: "latesttag" is a keyword
884 raise error.ParseError(_("latesttag expects at most one argument"))
886 raise error.ParseError(_("latesttag expects at most one argument"))
885
887
886 pattern = None
888 pattern = None
887 if len(args) == 1:
889 if len(args) == 1:
888 pattern = evalstring(context, mapping, args[0])
890 pattern = evalstring(context, mapping, args[0])
889
891
890 # TODO: pass (context, mapping) pair to keyword function
892 # TODO: pass (context, mapping) pair to keyword function
891 props = context._resources.copy()
893 props = context._resources.copy()
892 props.update(mapping)
894 props.update(mapping)
893 return templatekw.showlatesttags(pattern, **pycompat.strkwargs(props))
895 return templatekw.showlatesttags(pattern, **pycompat.strkwargs(props))
894
896
895 @templatefunc('localdate(date[, tz])')
897 @templatefunc('localdate(date[, tz])')
896 def localdate(context, mapping, args):
898 def localdate(context, mapping, args):
897 """Converts a date to the specified timezone.
899 """Converts a date to the specified timezone.
898 The default is local date."""
900 The default is local date."""
899 if not (1 <= len(args) <= 2):
901 if not (1 <= len(args) <= 2):
900 # i18n: "localdate" is a keyword
902 # i18n: "localdate" is a keyword
901 raise error.ParseError(_("localdate expects one or two arguments"))
903 raise error.ParseError(_("localdate expects one or two arguments"))
902
904
903 date = evalfuncarg(context, mapping, args[0])
905 date = evalfuncarg(context, mapping, args[0])
904 try:
906 try:
905 date = util.parsedate(date)
907 date = util.parsedate(date)
906 except AttributeError: # not str nor date tuple
908 except AttributeError: # not str nor date tuple
907 # i18n: "localdate" is a keyword
909 # i18n: "localdate" is a keyword
908 raise error.ParseError(_("localdate expects a date information"))
910 raise error.ParseError(_("localdate expects a date information"))
909 if len(args) >= 2:
911 if len(args) >= 2:
910 tzoffset = None
912 tzoffset = None
911 tz = evalfuncarg(context, mapping, args[1])
913 tz = evalfuncarg(context, mapping, args[1])
912 if isinstance(tz, str):
914 if isinstance(tz, str):
913 tzoffset, remainder = util.parsetimezone(tz)
915 tzoffset, remainder = util.parsetimezone(tz)
914 if remainder:
916 if remainder:
915 tzoffset = None
917 tzoffset = None
916 if tzoffset is None:
918 if tzoffset is None:
917 try:
919 try:
918 tzoffset = int(tz)
920 tzoffset = int(tz)
919 except (TypeError, ValueError):
921 except (TypeError, ValueError):
920 # i18n: "localdate" is a keyword
922 # i18n: "localdate" is a keyword
921 raise error.ParseError(_("localdate expects a timezone"))
923 raise error.ParseError(_("localdate expects a timezone"))
922 else:
924 else:
923 tzoffset = util.makedate()[1]
925 tzoffset = util.makedate()[1]
924 return (date[0], tzoffset)
926 return (date[0], tzoffset)
925
927
926 @templatefunc('max(iterable)')
928 @templatefunc('max(iterable)')
927 def max_(context, mapping, args, **kwargs):
929 def max_(context, mapping, args, **kwargs):
928 """Return the max of an iterable"""
930 """Return the max of an iterable"""
929 if len(args) != 1:
931 if len(args) != 1:
930 # i18n: "max" is a keyword
932 # i18n: "max" is a keyword
931 raise error.ParseError(_("max expects one argument"))
933 raise error.ParseError(_("max expects one argument"))
932
934
933 iterable = evalfuncarg(context, mapping, args[0])
935 iterable = evalfuncarg(context, mapping, args[0])
934 try:
936 try:
935 x = max(iterable)
937 x = max(iterable)
936 except (TypeError, ValueError):
938 except (TypeError, ValueError):
937 # i18n: "max" is a keyword
939 # i18n: "max" is a keyword
938 raise error.ParseError(_("max first argument should be an iterable"))
940 raise error.ParseError(_("max first argument should be an iterable"))
939 return templatekw.wraphybridvalue(iterable, x, x)
941 return templatekw.wraphybridvalue(iterable, x, x)
940
942
941 @templatefunc('min(iterable)')
943 @templatefunc('min(iterable)')
942 def min_(context, mapping, args, **kwargs):
944 def min_(context, mapping, args, **kwargs):
943 """Return the min of an iterable"""
945 """Return the min of an iterable"""
944 if len(args) != 1:
946 if len(args) != 1:
945 # i18n: "min" is a keyword
947 # i18n: "min" is a keyword
946 raise error.ParseError(_("min expects one argument"))
948 raise error.ParseError(_("min expects one argument"))
947
949
948 iterable = evalfuncarg(context, mapping, args[0])
950 iterable = evalfuncarg(context, mapping, args[0])
949 try:
951 try:
950 x = min(iterable)
952 x = min(iterable)
951 except (TypeError, ValueError):
953 except (TypeError, ValueError):
952 # i18n: "min" is a keyword
954 # i18n: "min" is a keyword
953 raise error.ParseError(_("min first argument should be an iterable"))
955 raise error.ParseError(_("min first argument should be an iterable"))
954 return templatekw.wraphybridvalue(iterable, x, x)
956 return templatekw.wraphybridvalue(iterable, x, x)
955
957
956 @templatefunc('mod(a, b)')
958 @templatefunc('mod(a, b)')
957 def mod(context, mapping, args):
959 def mod(context, mapping, args):
958 """Calculate a mod b such that a / b + a mod b == a"""
960 """Calculate a mod b such that a / b + a mod b == a"""
959 if not len(args) == 2:
961 if not len(args) == 2:
960 # i18n: "mod" is a keyword
962 # i18n: "mod" is a keyword
961 raise error.ParseError(_("mod expects two arguments"))
963 raise error.ParseError(_("mod expects two arguments"))
962
964
963 func = lambda a, b: a % b
965 func = lambda a, b: a % b
964 return runarithmetic(context, mapping, (func, args[0], args[1]))
966 return runarithmetic(context, mapping, (func, args[0], args[1]))
965
967
966 @templatefunc('obsfateoperations(markers)')
968 @templatefunc('obsfateoperations(markers)')
967 def obsfateoperations(context, mapping, args):
969 def obsfateoperations(context, mapping, args):
968 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
970 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
969 if len(args) != 1:
971 if len(args) != 1:
970 # i18n: "obsfateoperations" is a keyword
972 # i18n: "obsfateoperations" is a keyword
971 raise error.ParseError(_("obsfateoperations expects one argument"))
973 raise error.ParseError(_("obsfateoperations expects one argument"))
972
974
973 markers = evalfuncarg(context, mapping, args[0])
975 markers = evalfuncarg(context, mapping, args[0])
974
976
975 try:
977 try:
976 data = obsutil.markersoperations(markers)
978 data = obsutil.markersoperations(markers)
977 return templatekw.hybridlist(data, name='operation')
979 return templatekw.hybridlist(data, name='operation')
978 except (TypeError, KeyError):
980 except (TypeError, KeyError):
979 # i18n: "obsfateoperations" is a keyword
981 # i18n: "obsfateoperations" is a keyword
980 errmsg = _("obsfateoperations first argument should be an iterable")
982 errmsg = _("obsfateoperations first argument should be an iterable")
981 raise error.ParseError(errmsg)
983 raise error.ParseError(errmsg)
982
984
983 @templatefunc('obsfatedate(markers)')
985 @templatefunc('obsfatedate(markers)')
984 def obsfatedate(context, mapping, args):
986 def obsfatedate(context, mapping, args):
985 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
987 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
986 if len(args) != 1:
988 if len(args) != 1:
987 # i18n: "obsfatedate" is a keyword
989 # i18n: "obsfatedate" is a keyword
988 raise error.ParseError(_("obsfatedate expects one argument"))
990 raise error.ParseError(_("obsfatedate expects one argument"))
989
991
990 markers = evalfuncarg(context, mapping, args[0])
992 markers = evalfuncarg(context, mapping, args[0])
991
993
992 try:
994 try:
993 data = obsutil.markersdates(markers)
995 data = obsutil.markersdates(markers)
994 return templatekw.hybridlist(data, name='date', fmt='%d %d')
996 return templatekw.hybridlist(data, name='date', fmt='%d %d')
995 except (TypeError, KeyError):
997 except (TypeError, KeyError):
996 # i18n: "obsfatedate" is a keyword
998 # i18n: "obsfatedate" is a keyword
997 errmsg = _("obsfatedate first argument should be an iterable")
999 errmsg = _("obsfatedate first argument should be an iterable")
998 raise error.ParseError(errmsg)
1000 raise error.ParseError(errmsg)
999
1001
1000 @templatefunc('obsfateusers(markers)')
1002 @templatefunc('obsfateusers(markers)')
1001 def obsfateusers(context, mapping, args):
1003 def obsfateusers(context, mapping, args):
1002 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
1004 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
1003 if len(args) != 1:
1005 if len(args) != 1:
1004 # i18n: "obsfateusers" is a keyword
1006 # i18n: "obsfateusers" is a keyword
1005 raise error.ParseError(_("obsfateusers expects one argument"))
1007 raise error.ParseError(_("obsfateusers expects one argument"))
1006
1008
1007 markers = evalfuncarg(context, mapping, args[0])
1009 markers = evalfuncarg(context, mapping, args[0])
1008
1010
1009 try:
1011 try:
1010 data = obsutil.markersusers(markers)
1012 data = obsutil.markersusers(markers)
1011 return templatekw.hybridlist(data, name='user')
1013 return templatekw.hybridlist(data, name='user')
1012 except (TypeError, KeyError, ValueError):
1014 except (TypeError, KeyError, ValueError):
1013 # i18n: "obsfateusers" is a keyword
1015 # i18n: "obsfateusers" is a keyword
1014 msg = _("obsfateusers first argument should be an iterable of "
1016 msg = _("obsfateusers first argument should be an iterable of "
1015 "obsmakers")
1017 "obsmakers")
1016 raise error.ParseError(msg)
1018 raise error.ParseError(msg)
1017
1019
1018 @templatefunc('obsfateverb(successors, markers)')
1020 @templatefunc('obsfateverb(successors, markers)')
1019 def obsfateverb(context, mapping, args):
1021 def obsfateverb(context, mapping, args):
1020 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
1022 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
1021 if len(args) != 2:
1023 if len(args) != 2:
1022 # i18n: "obsfateverb" is a keyword
1024 # i18n: "obsfateverb" is a keyword
1023 raise error.ParseError(_("obsfateverb expects two arguments"))
1025 raise error.ParseError(_("obsfateverb expects two arguments"))
1024
1026
1025 successors = evalfuncarg(context, mapping, args[0])
1027 successors = evalfuncarg(context, mapping, args[0])
1026 markers = evalfuncarg(context, mapping, args[1])
1028 markers = evalfuncarg(context, mapping, args[1])
1027
1029
1028 try:
1030 try:
1029 return obsutil.obsfateverb(successors, markers)
1031 return obsutil.obsfateverb(successors, markers)
1030 except TypeError:
1032 except TypeError:
1031 # i18n: "obsfateverb" is a keyword
1033 # i18n: "obsfateverb" is a keyword
1032 errmsg = _("obsfateverb first argument should be countable")
1034 errmsg = _("obsfateverb first argument should be countable")
1033 raise error.ParseError(errmsg)
1035 raise error.ParseError(errmsg)
1034
1036
1035 @templatefunc('relpath(path)')
1037 @templatefunc('relpath(path)')
1036 def relpath(context, mapping, args):
1038 def relpath(context, mapping, args):
1037 """Convert a repository-absolute path into a filesystem path relative to
1039 """Convert a repository-absolute path into a filesystem path relative to
1038 the current working directory."""
1040 the current working directory."""
1039 if len(args) != 1:
1041 if len(args) != 1:
1040 # i18n: "relpath" is a keyword
1042 # i18n: "relpath" is a keyword
1041 raise error.ParseError(_("relpath expects one argument"))
1043 raise error.ParseError(_("relpath expects one argument"))
1042
1044
1043 repo = context.resource(mapping, 'ctx').repo()
1045 repo = context.resource(mapping, 'ctx').repo()
1044 path = evalstring(context, mapping, args[0])
1046 path = evalstring(context, mapping, args[0])
1045 return repo.pathto(path)
1047 return repo.pathto(path)
1046
1048
1047 @templatefunc('revset(query[, formatargs...])')
1049 @templatefunc('revset(query[, formatargs...])')
1048 def revset(context, mapping, args):
1050 def revset(context, mapping, args):
1049 """Execute a revision set query. See
1051 """Execute a revision set query. See
1050 :hg:`help revset`."""
1052 :hg:`help revset`."""
1051 if not len(args) > 0:
1053 if not len(args) > 0:
1052 # i18n: "revset" is a keyword
1054 # i18n: "revset" is a keyword
1053 raise error.ParseError(_("revset expects one or more arguments"))
1055 raise error.ParseError(_("revset expects one or more arguments"))
1054
1056
1055 raw = evalstring(context, mapping, args[0])
1057 raw = evalstring(context, mapping, args[0])
1056 ctx = context.resource(mapping, 'ctx')
1058 ctx = context.resource(mapping, 'ctx')
1057 repo = ctx.repo()
1059 repo = ctx.repo()
1058
1060
1059 def query(expr):
1061 def query(expr):
1060 m = revsetmod.match(repo.ui, expr, repo=repo)
1062 m = revsetmod.match(repo.ui, expr, repo=repo)
1061 return m(repo)
1063 return m(repo)
1062
1064
1063 if len(args) > 1:
1065 if len(args) > 1:
1064 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
1066 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
1065 revs = query(revsetlang.formatspec(raw, *formatargs))
1067 revs = query(revsetlang.formatspec(raw, *formatargs))
1066 revs = list(revs)
1068 revs = list(revs)
1067 else:
1069 else:
1068 cache = context.resource(mapping, 'cache')
1070 cache = context.resource(mapping, 'cache')
1069 revsetcache = cache.setdefault("revsetcache", {})
1071 revsetcache = cache.setdefault("revsetcache", {})
1070 if raw in revsetcache:
1072 if raw in revsetcache:
1071 revs = revsetcache[raw]
1073 revs = revsetcache[raw]
1072 else:
1074 else:
1073 revs = query(raw)
1075 revs = query(raw)
1074 revs = list(revs)
1076 revs = list(revs)
1075 revsetcache[raw] = revs
1077 revsetcache[raw] = revs
1076
1078
1077 # TODO: pass (context, mapping) pair to keyword function
1079 # TODO: pass (context, mapping) pair to keyword function
1078 props = context._resources.copy()
1080 props = context._resources.copy()
1079 props.update(mapping)
1081 props.update(mapping)
1080 return templatekw.showrevslist("revision", revs,
1082 return templatekw.showrevslist("revision", revs,
1081 **pycompat.strkwargs(props))
1083 **pycompat.strkwargs(props))
1082
1084
1083 @templatefunc('rstdoc(text, style)')
1085 @templatefunc('rstdoc(text, style)')
1084 def rstdoc(context, mapping, args):
1086 def rstdoc(context, mapping, args):
1085 """Format reStructuredText."""
1087 """Format reStructuredText."""
1086 if len(args) != 2:
1088 if len(args) != 2:
1087 # i18n: "rstdoc" is a keyword
1089 # i18n: "rstdoc" is a keyword
1088 raise error.ParseError(_("rstdoc expects two arguments"))
1090 raise error.ParseError(_("rstdoc expects two arguments"))
1089
1091
1090 text = evalstring(context, mapping, args[0])
1092 text = evalstring(context, mapping, args[0])
1091 style = evalstring(context, mapping, args[1])
1093 style = evalstring(context, mapping, args[1])
1092
1094
1093 return minirst.format(text, style=style, keep=['verbose'])
1095 return minirst.format(text, style=style, keep=['verbose'])
1094
1096
1095 @templatefunc('separate(sep, args)', argspec='sep *args')
1097 @templatefunc('separate(sep, args)', argspec='sep *args')
1096 def separate(context, mapping, args):
1098 def separate(context, mapping, args):
1097 """Add a separator between non-empty arguments."""
1099 """Add a separator between non-empty arguments."""
1098 if 'sep' not in args:
1100 if 'sep' not in args:
1099 # i18n: "separate" is a keyword
1101 # i18n: "separate" is a keyword
1100 raise error.ParseError(_("separate expects at least one argument"))
1102 raise error.ParseError(_("separate expects at least one argument"))
1101
1103
1102 sep = evalstring(context, mapping, args['sep'])
1104 sep = evalstring(context, mapping, args['sep'])
1103 first = True
1105 first = True
1104 for arg in args['args']:
1106 for arg in args['args']:
1105 argstr = evalstring(context, mapping, arg)
1107 argstr = evalstring(context, mapping, arg)
1106 if not argstr:
1108 if not argstr:
1107 continue
1109 continue
1108 if first:
1110 if first:
1109 first = False
1111 first = False
1110 else:
1112 else:
1111 yield sep
1113 yield sep
1112 yield argstr
1114 yield argstr
1113
1115
1114 @templatefunc('shortest(node, minlength=4)')
1116 @templatefunc('shortest(node, minlength=4)')
1115 def shortest(context, mapping, args):
1117 def shortest(context, mapping, args):
1116 """Obtain the shortest representation of
1118 """Obtain the shortest representation of
1117 a node."""
1119 a node."""
1118 if not (1 <= len(args) <= 2):
1120 if not (1 <= len(args) <= 2):
1119 # i18n: "shortest" is a keyword
1121 # i18n: "shortest" is a keyword
1120 raise error.ParseError(_("shortest() expects one or two arguments"))
1122 raise error.ParseError(_("shortest() expects one or two arguments"))
1121
1123
1122 node = evalstring(context, mapping, args[0])
1124 node = evalstring(context, mapping, args[0])
1123
1125
1124 minlength = 4
1126 minlength = 4
1125 if len(args) > 1:
1127 if len(args) > 1:
1126 minlength = evalinteger(context, mapping, args[1],
1128 minlength = evalinteger(context, mapping, args[1],
1127 # i18n: "shortest" is a keyword
1129 # i18n: "shortest" is a keyword
1128 _("shortest() expects an integer minlength"))
1130 _("shortest() expects an integer minlength"))
1129
1131
1130 # _partialmatch() of filtered changelog could take O(len(repo)) time,
1132 # _partialmatch() of filtered changelog could take O(len(repo)) time,
1131 # which would be unacceptably slow. so we look for hash collision in
1133 # which would be unacceptably slow. so we look for hash collision in
1132 # unfiltered space, which means some hashes may be slightly longer.
1134 # unfiltered space, which means some hashes may be slightly longer.
1133 cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog
1135 cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog
1134 return cl.shortest(node, minlength)
1136 return cl.shortest(node, minlength)
1135
1137
1136 @templatefunc('strip(text[, chars])')
1138 @templatefunc('strip(text[, chars])')
1137 def strip(context, mapping, args):
1139 def strip(context, mapping, args):
1138 """Strip characters from a string. By default,
1140 """Strip characters from a string. By default,
1139 strips all leading and trailing whitespace."""
1141 strips all leading and trailing whitespace."""
1140 if not (1 <= len(args) <= 2):
1142 if not (1 <= len(args) <= 2):
1141 # i18n: "strip" is a keyword
1143 # i18n: "strip" is a keyword
1142 raise error.ParseError(_("strip expects one or two arguments"))
1144 raise error.ParseError(_("strip expects one or two arguments"))
1143
1145
1144 text = evalstring(context, mapping, args[0])
1146 text = evalstring(context, mapping, args[0])
1145 if len(args) == 2:
1147 if len(args) == 2:
1146 chars = evalstring(context, mapping, args[1])
1148 chars = evalstring(context, mapping, args[1])
1147 return text.strip(chars)
1149 return text.strip(chars)
1148 return text.strip()
1150 return text.strip()
1149
1151
1150 @templatefunc('sub(pattern, replacement, expression)')
1152 @templatefunc('sub(pattern, replacement, expression)')
1151 def sub(context, mapping, args):
1153 def sub(context, mapping, args):
1152 """Perform text substitution
1154 """Perform text substitution
1153 using regular expressions."""
1155 using regular expressions."""
1154 if len(args) != 3:
1156 if len(args) != 3:
1155 # i18n: "sub" is a keyword
1157 # i18n: "sub" is a keyword
1156 raise error.ParseError(_("sub expects three arguments"))
1158 raise error.ParseError(_("sub expects three arguments"))
1157
1159
1158 pat = evalstring(context, mapping, args[0])
1160 pat = evalstring(context, mapping, args[0])
1159 rpl = evalstring(context, mapping, args[1])
1161 rpl = evalstring(context, mapping, args[1])
1160 src = evalstring(context, mapping, args[2])
1162 src = evalstring(context, mapping, args[2])
1161 try:
1163 try:
1162 patre = re.compile(pat)
1164 patre = re.compile(pat)
1163 except re.error:
1165 except re.error:
1164 # i18n: "sub" is a keyword
1166 # i18n: "sub" is a keyword
1165 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
1167 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
1166 try:
1168 try:
1167 yield patre.sub(rpl, src)
1169 yield patre.sub(rpl, src)
1168 except re.error:
1170 except re.error:
1169 # i18n: "sub" is a keyword
1171 # i18n: "sub" is a keyword
1170 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
1172 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
1171
1173
1172 @templatefunc('startswith(pattern, text)')
1174 @templatefunc('startswith(pattern, text)')
1173 def startswith(context, mapping, args):
1175 def startswith(context, mapping, args):
1174 """Returns the value from the "text" argument
1176 """Returns the value from the "text" argument
1175 if it begins with the content from the "pattern" argument."""
1177 if it begins with the content from the "pattern" argument."""
1176 if len(args) != 2:
1178 if len(args) != 2:
1177 # i18n: "startswith" is a keyword
1179 # i18n: "startswith" is a keyword
1178 raise error.ParseError(_("startswith expects two arguments"))
1180 raise error.ParseError(_("startswith expects two arguments"))
1179
1181
1180 patn = evalstring(context, mapping, args[0])
1182 patn = evalstring(context, mapping, args[0])
1181 text = evalstring(context, mapping, args[1])
1183 text = evalstring(context, mapping, args[1])
1182 if text.startswith(patn):
1184 if text.startswith(patn):
1183 return text
1185 return text
1184 return ''
1186 return ''
1185
1187
1186 @templatefunc('word(number, text[, separator])')
1188 @templatefunc('word(number, text[, separator])')
1187 def word(context, mapping, args):
1189 def word(context, mapping, args):
1188 """Return the nth word from a string."""
1190 """Return the nth word from a string."""
1189 if not (2 <= len(args) <= 3):
1191 if not (2 <= len(args) <= 3):
1190 # i18n: "word" is a keyword
1192 # i18n: "word" is a keyword
1191 raise error.ParseError(_("word expects two or three arguments, got %d")
1193 raise error.ParseError(_("word expects two or three arguments, got %d")
1192 % len(args))
1194 % len(args))
1193
1195
1194 num = evalinteger(context, mapping, args[0],
1196 num = evalinteger(context, mapping, args[0],
1195 # i18n: "word" is a keyword
1197 # i18n: "word" is a keyword
1196 _("word expects an integer index"))
1198 _("word expects an integer index"))
1197 text = evalstring(context, mapping, args[1])
1199 text = evalstring(context, mapping, args[1])
1198 if len(args) == 3:
1200 if len(args) == 3:
1199 splitter = evalstring(context, mapping, args[2])
1201 splitter = evalstring(context, mapping, args[2])
1200 else:
1202 else:
1201 splitter = None
1203 splitter = None
1202
1204
1203 tokens = text.split(splitter)
1205 tokens = text.split(splitter)
1204 if num >= len(tokens) or num < -len(tokens):
1206 if num >= len(tokens) or num < -len(tokens):
1205 return ''
1207 return ''
1206 else:
1208 else:
1207 return tokens[num]
1209 return tokens[num]
1208
1210
1209 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1211 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1210 exprmethods = {
1212 exprmethods = {
1211 "integer": lambda e, c: (runinteger, e[1]),
1213 "integer": lambda e, c: (runinteger, e[1]),
1212 "string": lambda e, c: (runstring, e[1]),
1214 "string": lambda e, c: (runstring, e[1]),
1213 "symbol": lambda e, c: (runsymbol, e[1]),
1215 "symbol": lambda e, c: (runsymbol, e[1]),
1214 "template": buildtemplate,
1216 "template": buildtemplate,
1215 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1217 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1216 ".": buildmember,
1218 ".": buildmember,
1217 "|": buildfilter,
1219 "|": buildfilter,
1218 "%": buildmap,
1220 "%": buildmap,
1219 "func": buildfunc,
1221 "func": buildfunc,
1220 "keyvalue": buildkeyvaluepair,
1222 "keyvalue": buildkeyvaluepair,
1221 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1223 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1222 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1224 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1223 "negate": buildnegate,
1225 "negate": buildnegate,
1224 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1226 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1225 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1227 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1226 }
1228 }
1227
1229
1228 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1230 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1229 methods = exprmethods.copy()
1231 methods = exprmethods.copy()
1230 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1232 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1231
1233
1232 class _aliasrules(parser.basealiasrules):
1234 class _aliasrules(parser.basealiasrules):
1233 """Parsing and expansion rule set of template aliases"""
1235 """Parsing and expansion rule set of template aliases"""
1234 _section = _('template alias')
1236 _section = _('template alias')
1235 _parse = staticmethod(_parseexpr)
1237 _parse = staticmethod(_parseexpr)
1236
1238
1237 @staticmethod
1239 @staticmethod
1238 def _trygetfunc(tree):
1240 def _trygetfunc(tree):
1239 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1241 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1240 None"""
1242 None"""
1241 if tree[0] == 'func' and tree[1][0] == 'symbol':
1243 if tree[0] == 'func' and tree[1][0] == 'symbol':
1242 return tree[1][1], getlist(tree[2])
1244 return tree[1][1], getlist(tree[2])
1243 if tree[0] == '|' and tree[2][0] == 'symbol':
1245 if tree[0] == '|' and tree[2][0] == 'symbol':
1244 return tree[2][1], [tree[1]]
1246 return tree[2][1], [tree[1]]
1245
1247
1246 def expandaliases(tree, aliases):
1248 def expandaliases(tree, aliases):
1247 """Return new tree of aliases are expanded"""
1249 """Return new tree of aliases are expanded"""
1248 aliasmap = _aliasrules.buildmap(aliases)
1250 aliasmap = _aliasrules.buildmap(aliases)
1249 return _aliasrules.expand(aliasmap, tree)
1251 return _aliasrules.expand(aliasmap, tree)
1250
1252
1251 # template engine
1253 # template engine
1252
1254
1253 stringify = templatefilters.stringify
1255 stringify = templatefilters.stringify
1254
1256
1255 def _flatten(thing):
1257 def _flatten(thing):
1256 '''yield a single stream from a possibly nested set of iterators'''
1258 '''yield a single stream from a possibly nested set of iterators'''
1257 thing = templatekw.unwraphybrid(thing)
1259 thing = templatekw.unwraphybrid(thing)
1258 if isinstance(thing, bytes):
1260 if isinstance(thing, bytes):
1259 yield thing
1261 yield thing
1260 elif isinstance(thing, str):
1262 elif isinstance(thing, str):
1261 # We can only hit this on Python 3, and it's here to guard
1263 # We can only hit this on Python 3, and it's here to guard
1262 # against infinite recursion.
1264 # against infinite recursion.
1263 raise error.ProgrammingError('Mercurial IO including templates is done'
1265 raise error.ProgrammingError('Mercurial IO including templates is done'
1264 ' with bytes, not strings')
1266 ' with bytes, not strings')
1265 elif thing is None:
1267 elif thing is None:
1266 pass
1268 pass
1267 elif not util.safehasattr(thing, '__iter__'):
1269 elif not util.safehasattr(thing, '__iter__'):
1268 yield pycompat.bytestr(thing)
1270 yield pycompat.bytestr(thing)
1269 else:
1271 else:
1270 for i in thing:
1272 for i in thing:
1271 i = templatekw.unwraphybrid(i)
1273 i = templatekw.unwraphybrid(i)
1272 if isinstance(i, bytes):
1274 if isinstance(i, bytes):
1273 yield i
1275 yield i
1274 elif i is None:
1276 elif i is None:
1275 pass
1277 pass
1276 elif not util.safehasattr(i, '__iter__'):
1278 elif not util.safehasattr(i, '__iter__'):
1277 yield pycompat.bytestr(i)
1279 yield pycompat.bytestr(i)
1278 else:
1280 else:
1279 for j in _flatten(i):
1281 for j in _flatten(i):
1280 yield j
1282 yield j
1281
1283
1282 def unquotestring(s):
1284 def unquotestring(s):
1283 '''unwrap quotes if any; otherwise returns unmodified string'''
1285 '''unwrap quotes if any; otherwise returns unmodified string'''
1284 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1286 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1285 return s
1287 return s
1286 return s[1:-1]
1288 return s[1:-1]
1287
1289
1288 class engine(object):
1290 class engine(object):
1289 '''template expansion engine.
1291 '''template expansion engine.
1290
1292
1291 template expansion works like this. a map file contains key=value
1293 template expansion works like this. a map file contains key=value
1292 pairs. if value is quoted, it is treated as string. otherwise, it
1294 pairs. if value is quoted, it is treated as string. otherwise, it
1293 is treated as name of template file.
1295 is treated as name of template file.
1294
1296
1295 templater is asked to expand a key in map. it looks up key, and
1297 templater is asked to expand a key in map. it looks up key, and
1296 looks for strings like this: {foo}. it expands {foo} by looking up
1298 looks for strings like this: {foo}. it expands {foo} by looking up
1297 foo in map, and substituting it. expansion is recursive: it stops
1299 foo in map, and substituting it. expansion is recursive: it stops
1298 when there is no more {foo} to replace.
1300 when there is no more {foo} to replace.
1299
1301
1300 expansion also allows formatting and filtering.
1302 expansion also allows formatting and filtering.
1301
1303
1302 format uses key to expand each item in list. syntax is
1304 format uses key to expand each item in list. syntax is
1303 {key%format}.
1305 {key%format}.
1304
1306
1305 filter uses function to transform value. syntax is
1307 filter uses function to transform value. syntax is
1306 {key|filter1|filter2|...}.'''
1308 {key|filter1|filter2|...}.'''
1307
1309
1308 def __init__(self, loader, filters=None, defaults=None, resources=None,
1310 def __init__(self, loader, filters=None, defaults=None, resources=None,
1309 aliases=()):
1311 aliases=()):
1310 self._loader = loader
1312 self._loader = loader
1311 if filters is None:
1313 if filters is None:
1312 filters = {}
1314 filters = {}
1313 self._filters = filters
1315 self._filters = filters
1314 if defaults is None:
1316 if defaults is None:
1315 defaults = {}
1317 defaults = {}
1316 if resources is None:
1318 if resources is None:
1317 resources = {}
1319 resources = {}
1318 self._defaults = defaults
1320 self._defaults = defaults
1319 self._resources = resources
1321 self._resources = resources
1320 self._aliasmap = _aliasrules.buildmap(aliases)
1322 self._aliasmap = _aliasrules.buildmap(aliases)
1321 self._cache = {} # key: (func, data)
1323 self._cache = {} # key: (func, data)
1322
1324
1323 def symbol(self, mapping, key):
1325 def symbol(self, mapping, key):
1324 """Resolve symbol to value or function; None if nothing found"""
1326 """Resolve symbol to value or function; None if nothing found"""
1325 v = None
1327 v = None
1326 if key not in self._resources:
1328 if key not in self._resources:
1327 v = mapping.get(key)
1329 v = mapping.get(key)
1328 if v is None:
1330 if v is None:
1329 v = self._defaults.get(key)
1331 v = self._defaults.get(key)
1330 return v
1332 return v
1331
1333
1332 def resource(self, mapping, key):
1334 def resource(self, mapping, key):
1333 """Return internal data (e.g. cache) used for keyword/function
1335 """Return internal data (e.g. cache) used for keyword/function
1334 evaluation"""
1336 evaluation"""
1335 v = None
1337 v = None
1336 if key in self._resources:
1338 if key in self._resources:
1337 v = mapping.get(key)
1339 v = mapping.get(key)
1338 if v is None:
1340 if v is None:
1339 v = self._resources.get(key)
1341 v = self._resources.get(key)
1340 if v is None:
1342 if v is None:
1341 raise error.Abort(_('template resource not available: %s') % key)
1343 raise error.Abort(_('template resource not available: %s') % key)
1342 return v
1344 return v
1343
1345
1344 def _load(self, t):
1346 def _load(self, t):
1345 '''load, parse, and cache a template'''
1347 '''load, parse, and cache a template'''
1346 if t not in self._cache:
1348 if t not in self._cache:
1347 # put poison to cut recursion while compiling 't'
1349 # put poison to cut recursion while compiling 't'
1348 self._cache[t] = (_runrecursivesymbol, t)
1350 self._cache[t] = (_runrecursivesymbol, t)
1349 try:
1351 try:
1350 x = parse(self._loader(t))
1352 x = parse(self._loader(t))
1351 if self._aliasmap:
1353 if self._aliasmap:
1352 x = _aliasrules.expand(self._aliasmap, x)
1354 x = _aliasrules.expand(self._aliasmap, x)
1353 self._cache[t] = compileexp(x, self, methods)
1355 self._cache[t] = compileexp(x, self, methods)
1354 except: # re-raises
1356 except: # re-raises
1355 del self._cache[t]
1357 del self._cache[t]
1356 raise
1358 raise
1357 return self._cache[t]
1359 return self._cache[t]
1358
1360
1359 def process(self, t, mapping):
1361 def process(self, t, mapping):
1360 '''Perform expansion. t is name of map element to expand.
1362 '''Perform expansion. t is name of map element to expand.
1361 mapping contains added elements for use during expansion. Is a
1363 mapping contains added elements for use during expansion. Is a
1362 generator.'''
1364 generator.'''
1363 func, data = self._load(t)
1365 func, data = self._load(t)
1364 return _flatten(func(self, mapping, data))
1366 return _flatten(func(self, mapping, data))
1365
1367
1366 engines = {'default': engine}
1368 engines = {'default': engine}
1367
1369
1368 def stylelist():
1370 def stylelist():
1369 paths = templatepaths()
1371 paths = templatepaths()
1370 if not paths:
1372 if not paths:
1371 return _('no templates found, try `hg debuginstall` for more info')
1373 return _('no templates found, try `hg debuginstall` for more info')
1372 dirlist = os.listdir(paths[0])
1374 dirlist = os.listdir(paths[0])
1373 stylelist = []
1375 stylelist = []
1374 for file in dirlist:
1376 for file in dirlist:
1375 split = file.split(".")
1377 split = file.split(".")
1376 if split[-1] in ('orig', 'rej'):
1378 if split[-1] in ('orig', 'rej'):
1377 continue
1379 continue
1378 if split[0] == "map-cmdline":
1380 if split[0] == "map-cmdline":
1379 stylelist.append(split[1])
1381 stylelist.append(split[1])
1380 return ", ".join(sorted(stylelist))
1382 return ", ".join(sorted(stylelist))
1381
1383
1382 def _readmapfile(mapfile):
1384 def _readmapfile(mapfile):
1383 """Load template elements from the given map file"""
1385 """Load template elements from the given map file"""
1384 if not os.path.exists(mapfile):
1386 if not os.path.exists(mapfile):
1385 raise error.Abort(_("style '%s' not found") % mapfile,
1387 raise error.Abort(_("style '%s' not found") % mapfile,
1386 hint=_("available styles: %s") % stylelist())
1388 hint=_("available styles: %s") % stylelist())
1387
1389
1388 base = os.path.dirname(mapfile)
1390 base = os.path.dirname(mapfile)
1389 conf = config.config(includepaths=templatepaths())
1391 conf = config.config(includepaths=templatepaths())
1390 conf.read(mapfile, remap={'': 'templates'})
1392 conf.read(mapfile, remap={'': 'templates'})
1391
1393
1392 cache = {}
1394 cache = {}
1393 tmap = {}
1395 tmap = {}
1394 aliases = []
1396 aliases = []
1395
1397
1396 val = conf.get('templates', '__base__')
1398 val = conf.get('templates', '__base__')
1397 if val and val[0] not in "'\"":
1399 if val and val[0] not in "'\"":
1398 # treat as a pointer to a base class for this style
1400 # treat as a pointer to a base class for this style
1399 path = util.normpath(os.path.join(base, val))
1401 path = util.normpath(os.path.join(base, val))
1400
1402
1401 # fallback check in template paths
1403 # fallback check in template paths
1402 if not os.path.exists(path):
1404 if not os.path.exists(path):
1403 for p in templatepaths():
1405 for p in templatepaths():
1404 p2 = util.normpath(os.path.join(p, val))
1406 p2 = util.normpath(os.path.join(p, val))
1405 if os.path.isfile(p2):
1407 if os.path.isfile(p2):
1406 path = p2
1408 path = p2
1407 break
1409 break
1408 p3 = util.normpath(os.path.join(p2, "map"))
1410 p3 = util.normpath(os.path.join(p2, "map"))
1409 if os.path.isfile(p3):
1411 if os.path.isfile(p3):
1410 path = p3
1412 path = p3
1411 break
1413 break
1412
1414
1413 cache, tmap, aliases = _readmapfile(path)
1415 cache, tmap, aliases = _readmapfile(path)
1414
1416
1415 for key, val in conf['templates'].items():
1417 for key, val in conf['templates'].items():
1416 if not val:
1418 if not val:
1417 raise error.ParseError(_('missing value'),
1419 raise error.ParseError(_('missing value'),
1418 conf.source('templates', key))
1420 conf.source('templates', key))
1419 if val[0] in "'\"":
1421 if val[0] in "'\"":
1420 if val[0] != val[-1]:
1422 if val[0] != val[-1]:
1421 raise error.ParseError(_('unmatched quotes'),
1423 raise error.ParseError(_('unmatched quotes'),
1422 conf.source('templates', key))
1424 conf.source('templates', key))
1423 cache[key] = unquotestring(val)
1425 cache[key] = unquotestring(val)
1424 elif key != '__base__':
1426 elif key != '__base__':
1425 val = 'default', val
1427 val = 'default', val
1426 if ':' in val[1]:
1428 if ':' in val[1]:
1427 val = val[1].split(':', 1)
1429 val = val[1].split(':', 1)
1428 tmap[key] = val[0], os.path.join(base, val[1])
1430 tmap[key] = val[0], os.path.join(base, val[1])
1429 aliases.extend(conf['templatealias'].items())
1431 aliases.extend(conf['templatealias'].items())
1430 return cache, tmap, aliases
1432 return cache, tmap, aliases
1431
1433
1432 class TemplateNotFound(error.Abort):
1434 class TemplateNotFound(error.Abort):
1433 pass
1435 pass
1434
1436
1435 class templater(object):
1437 class templater(object):
1436
1438
1437 def __init__(self, filters=None, defaults=None, resources=None,
1439 def __init__(self, filters=None, defaults=None, resources=None,
1438 cache=None, aliases=(), minchunk=1024, maxchunk=65536):
1440 cache=None, aliases=(), minchunk=1024, maxchunk=65536):
1439 """Create template engine optionally with preloaded template fragments
1441 """Create template engine optionally with preloaded template fragments
1440
1442
1441 - ``filters``: a dict of functions to transform a value into another.
1443 - ``filters``: a dict of functions to transform a value into another.
1442 - ``defaults``: a dict of symbol values/functions; may be overridden
1444 - ``defaults``: a dict of symbol values/functions; may be overridden
1443 by a ``mapping`` dict.
1445 by a ``mapping`` dict.
1444 - ``resources``: a dict of internal data (e.g. cache), inaccessible
1446 - ``resources``: a dict of internal data (e.g. cache), inaccessible
1445 from user template; may be overridden by a ``mapping`` dict.
1447 from user template; may be overridden by a ``mapping`` dict.
1446 - ``cache``: a dict of preloaded template fragments.
1448 - ``cache``: a dict of preloaded template fragments.
1447 - ``aliases``: a list of alias (name, replacement) pairs.
1449 - ``aliases``: a list of alias (name, replacement) pairs.
1448
1450
1449 self.cache may be updated later to register additional template
1451 self.cache may be updated later to register additional template
1450 fragments.
1452 fragments.
1451 """
1453 """
1452 if filters is None:
1454 if filters is None:
1453 filters = {}
1455 filters = {}
1454 if defaults is None:
1456 if defaults is None:
1455 defaults = {}
1457 defaults = {}
1456 if resources is None:
1458 if resources is None:
1457 resources = {}
1459 resources = {}
1458 if cache is None:
1460 if cache is None:
1459 cache = {}
1461 cache = {}
1460 self.cache = cache.copy()
1462 self.cache = cache.copy()
1461 self.map = {}
1463 self.map = {}
1462 self.filters = templatefilters.filters.copy()
1464 self.filters = templatefilters.filters.copy()
1463 self.filters.update(filters)
1465 self.filters.update(filters)
1464 self.defaults = defaults
1466 self.defaults = defaults
1465 self._resources = {'templ': self}
1467 self._resources = {'templ': self}
1466 self._resources.update(resources)
1468 self._resources.update(resources)
1467 self._aliases = aliases
1469 self._aliases = aliases
1468 self.minchunk, self.maxchunk = minchunk, maxchunk
1470 self.minchunk, self.maxchunk = minchunk, maxchunk
1469 self.ecache = {}
1471 self.ecache = {}
1470
1472
1471 @classmethod
1473 @classmethod
1472 def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
1474 def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
1473 cache=None, minchunk=1024, maxchunk=65536):
1475 cache=None, minchunk=1024, maxchunk=65536):
1474 """Create templater from the specified map file"""
1476 """Create templater from the specified map file"""
1475 t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk)
1477 t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk)
1476 cache, tmap, aliases = _readmapfile(mapfile)
1478 cache, tmap, aliases = _readmapfile(mapfile)
1477 t.cache.update(cache)
1479 t.cache.update(cache)
1478 t.map = tmap
1480 t.map = tmap
1479 t._aliases = aliases
1481 t._aliases = aliases
1480 return t
1482 return t
1481
1483
1482 def __contains__(self, key):
1484 def __contains__(self, key):
1483 return key in self.cache or key in self.map
1485 return key in self.cache or key in self.map
1484
1486
1485 def load(self, t):
1487 def load(self, t):
1486 '''Get the template for the given template name. Use a local cache.'''
1488 '''Get the template for the given template name. Use a local cache.'''
1487 if t not in self.cache:
1489 if t not in self.cache:
1488 try:
1490 try:
1489 self.cache[t] = util.readfile(self.map[t][1])
1491 self.cache[t] = util.readfile(self.map[t][1])
1490 except KeyError as inst:
1492 except KeyError as inst:
1491 raise TemplateNotFound(_('"%s" not in template map') %
1493 raise TemplateNotFound(_('"%s" not in template map') %
1492 inst.args[0])
1494 inst.args[0])
1493 except IOError as inst:
1495 except IOError as inst:
1494 raise IOError(inst.args[0], _('template file %s: %s') %
1496 raise IOError(inst.args[0], _('template file %s: %s') %
1495 (self.map[t][1], inst.args[1]))
1497 (self.map[t][1], inst.args[1]))
1496 return self.cache[t]
1498 return self.cache[t]
1497
1499
1498 def render(self, mapping):
1500 def render(self, mapping):
1499 """Render the default unnamed template and return result as string"""
1501 """Render the default unnamed template and return result as string"""
1500 mapping = pycompat.strkwargs(mapping)
1502 mapping = pycompat.strkwargs(mapping)
1501 return stringify(self('', **mapping))
1503 return stringify(self('', **mapping))
1502
1504
1503 def __call__(self, t, **mapping):
1505 def __call__(self, t, **mapping):
1504 mapping = pycompat.byteskwargs(mapping)
1506 mapping = pycompat.byteskwargs(mapping)
1505 ttype = t in self.map and self.map[t][0] or 'default'
1507 ttype = t in self.map and self.map[t][0] or 'default'
1506 if ttype not in self.ecache:
1508 if ttype not in self.ecache:
1507 try:
1509 try:
1508 ecls = engines[ttype]
1510 ecls = engines[ttype]
1509 except KeyError:
1511 except KeyError:
1510 raise error.Abort(_('invalid template engine: %s') % ttype)
1512 raise error.Abort(_('invalid template engine: %s') % ttype)
1511 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1513 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1512 self._resources, self._aliases)
1514 self._resources, self._aliases)
1513 proc = self.ecache[ttype]
1515 proc = self.ecache[ttype]
1514
1516
1515 stream = proc.process(t, mapping)
1517 stream = proc.process(t, mapping)
1516 if self.minchunk:
1518 if self.minchunk:
1517 stream = util.increasingchunks(stream, min=self.minchunk,
1519 stream = util.increasingchunks(stream, min=self.minchunk,
1518 max=self.maxchunk)
1520 max=self.maxchunk)
1519 return stream
1521 return stream
1520
1522
1521 def templatepaths():
1523 def templatepaths():
1522 '''return locations used for template files.'''
1524 '''return locations used for template files.'''
1523 pathsrel = ['templates']
1525 pathsrel = ['templates']
1524 paths = [os.path.normpath(os.path.join(util.datapath, f))
1526 paths = [os.path.normpath(os.path.join(util.datapath, f))
1525 for f in pathsrel]
1527 for f in pathsrel]
1526 return [p for p in paths if os.path.isdir(p)]
1528 return [p for p in paths if os.path.isdir(p)]
1527
1529
1528 def templatepath(name):
1530 def templatepath(name):
1529 '''return location of template file. returns None if not found.'''
1531 '''return location of template file. returns None if not found.'''
1530 for p in templatepaths():
1532 for p in templatepaths():
1531 f = os.path.join(p, name)
1533 f = os.path.join(p, name)
1532 if os.path.exists(f):
1534 if os.path.exists(f):
1533 return f
1535 return f
1534 return None
1536 return None
1535
1537
1536 def stylemap(styles, paths=None):
1538 def stylemap(styles, paths=None):
1537 """Return path to mapfile for a given style.
1539 """Return path to mapfile for a given style.
1538
1540
1539 Searches mapfile in the following locations:
1541 Searches mapfile in the following locations:
1540 1. templatepath/style/map
1542 1. templatepath/style/map
1541 2. templatepath/map-style
1543 2. templatepath/map-style
1542 3. templatepath/map
1544 3. templatepath/map
1543 """
1545 """
1544
1546
1545 if paths is None:
1547 if paths is None:
1546 paths = templatepaths()
1548 paths = templatepaths()
1547 elif isinstance(paths, str):
1549 elif isinstance(paths, str):
1548 paths = [paths]
1550 paths = [paths]
1549
1551
1550 if isinstance(styles, str):
1552 if isinstance(styles, str):
1551 styles = [styles]
1553 styles = [styles]
1552
1554
1553 for style in styles:
1555 for style in styles:
1554 # only plain name is allowed to honor template paths
1556 # only plain name is allowed to honor template paths
1555 if (not style
1557 if (not style
1556 or style in (os.curdir, os.pardir)
1558 or style in (os.curdir, os.pardir)
1557 or pycompat.ossep in style
1559 or pycompat.ossep in style
1558 or pycompat.osaltsep and pycompat.osaltsep in style):
1560 or pycompat.osaltsep and pycompat.osaltsep in style):
1559 continue
1561 continue
1560 locations = [os.path.join(style, 'map'), 'map-' + style]
1562 locations = [os.path.join(style, 'map'), 'map-' + style]
1561 locations.append('map')
1563 locations.append('map')
1562
1564
1563 for path in paths:
1565 for path in paths:
1564 for location in locations:
1566 for location in locations:
1565 mapfile = os.path.join(path, location)
1567 mapfile = os.path.join(path, location)
1566 if os.path.isfile(mapfile):
1568 if os.path.isfile(mapfile):
1567 return style, mapfile
1569 return style, mapfile
1568
1570
1569 raise RuntimeError("No hgweb templates found in %r" % paths)
1571 raise RuntimeError("No hgweb templates found in %r" % paths)
1570
1572
1571 def loadfunction(ui, extname, registrarobj):
1573 def loadfunction(ui, extname, registrarobj):
1572 """Load template function from specified registrarobj
1574 """Load template function from specified registrarobj
1573 """
1575 """
1574 for name, func in registrarobj._table.iteritems():
1576 for name, func in registrarobj._table.iteritems():
1575 funcs[name] = func
1577 funcs[name] = func
1576
1578
1577 # tell hggettext to extract docstrings from these functions:
1579 # tell hggettext to extract docstrings from these functions:
1578 i18nfunctions = funcs.values()
1580 i18nfunctions = funcs.values()
@@ -1,4768 +1,4778
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 Filters bind as close as map operator:
137 Filters bind as close as map operator:
138
138
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
140 (template
140 (template
141 (%
141 (%
142 (|
142 (|
143 (symbol 'desc')
143 (symbol 'desc')
144 (symbol 'splitlines'))
144 (symbol 'splitlines'))
145 (template
145 (template
146 (symbol 'line')
146 (symbol 'line')
147 (string '\n'))))
147 (string '\n'))))
148 line 1
148 line 1
149 line 2
149 line 2
150
150
151 Keyword arguments:
151 Keyword arguments:
152
152
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
154 (template
154 (template
155 (keyvalue
155 (keyvalue
156 (symbol 'foo')
156 (symbol 'foo')
157 (|
157 (|
158 (symbol 'bar')
158 (symbol 'bar')
159 (symbol 'baz'))))
159 (symbol 'baz'))))
160 hg: parse error: can't use a key-value pair in this context
160 hg: parse error: can't use a key-value pair in this context
161 [255]
161 [255]
162
162
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
164 foo
164 foo
165
165
166 Call function which takes named arguments by filter syntax:
166 Call function which takes named arguments by filter syntax:
167
167
168 $ hg debugtemplate '{" "|separate}'
168 $ hg debugtemplate '{" "|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
170 hg: parse error: unknown method 'list'
170 hg: parse error: unknown method 'list'
171 [255]
171 [255]
172
172
173 Second branch starting at nullrev:
173 Second branch starting at nullrev:
174
174
175 $ hg update null
175 $ hg update null
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
177 $ echo second > second
177 $ echo second > second
178 $ hg add second
178 $ hg add second
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
180 created new head
180 created new head
181
181
182 $ echo third > third
182 $ echo third > third
183 $ hg add third
183 $ hg add third
184 $ hg mv second fourth
184 $ hg mv second fourth
185 $ hg commit -m third -d "2020-01-01 10:01"
185 $ hg commit -m third -d "2020-01-01 10:01"
186
186
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
188 fourth (second)
188 fourth (second)
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
190 second -> fourth
190 second -> fourth
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
192 8 t
192 8 t
193 7 f
193 7 f
194
194
195 Working-directory revision has special identifiers, though they are still
195 Working-directory revision has special identifiers, though they are still
196 experimental:
196 experimental:
197
197
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
200
200
201 Some keywords are invalid for working-directory revision, but they should
201 Some keywords are invalid for working-directory revision, but they should
202 never cause crash:
202 never cause crash:
203
203
204 $ hg log -r 'wdir()' -T '{manifest}\n'
204 $ hg log -r 'wdir()' -T '{manifest}\n'
205
205
206
206
207 Internal resources shouldn't be exposed (issue5699):
207 Internal resources shouldn't be exposed (issue5699):
208
208
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
210
210
211 Never crash on internal resource not available:
211 Never crash on internal resource not available:
212
212
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
214 abort: template resource not available: ctx
214 abort: template resource not available: ctx
215 [255]
215 [255]
216
216
217 Quoting for ui.logtemplate
217 Quoting for ui.logtemplate
218
218
219 $ hg tip --config "ui.logtemplate={rev}\n"
219 $ hg tip --config "ui.logtemplate={rev}\n"
220 8
220 8
221 $ hg tip --config "ui.logtemplate='{rev}\n'"
221 $ hg tip --config "ui.logtemplate='{rev}\n'"
222 8
222 8
223 $ hg tip --config 'ui.logtemplate="{rev}\n"'
223 $ hg tip --config 'ui.logtemplate="{rev}\n"'
224 8
224 8
225 $ hg tip --config 'ui.logtemplate=n{rev}\n'
225 $ hg tip --config 'ui.logtemplate=n{rev}\n'
226 n8
226 n8
227
227
228 Make sure user/global hgrc does not affect tests
228 Make sure user/global hgrc does not affect tests
229
229
230 $ echo '[ui]' > .hg/hgrc
230 $ echo '[ui]' > .hg/hgrc
231 $ echo 'logtemplate =' >> .hg/hgrc
231 $ echo 'logtemplate =' >> .hg/hgrc
232 $ echo 'style =' >> .hg/hgrc
232 $ echo 'style =' >> .hg/hgrc
233
233
234 Add some simple styles to settings
234 Add some simple styles to settings
235
235
236 $ cat <<'EOF' >> .hg/hgrc
236 $ cat <<'EOF' >> .hg/hgrc
237 > [templates]
237 > [templates]
238 > simple = "{rev}\n"
238 > simple = "{rev}\n"
239 > simple2 = {rev}\n
239 > simple2 = {rev}\n
240 > rev = "should not precede {rev} keyword\n"
240 > rev = "should not precede {rev} keyword\n"
241 > EOF
241 > EOF
242
242
243 $ hg log -l1 -Tsimple
243 $ hg log -l1 -Tsimple
244 8
244 8
245 $ hg log -l1 -Tsimple2
245 $ hg log -l1 -Tsimple2
246 8
246 8
247 $ hg log -l1 -Trev
247 $ hg log -l1 -Trev
248 should not precede 8 keyword
248 should not precede 8 keyword
249 $ hg log -l1 -T '{simple}'
249 $ hg log -l1 -T '{simple}'
250 8
250 8
251
251
252 Map file shouldn't see user templates:
252 Map file shouldn't see user templates:
253
253
254 $ cat <<EOF > tmpl
254 $ cat <<EOF > tmpl
255 > changeset = 'nothing expanded:{simple}\n'
255 > changeset = 'nothing expanded:{simple}\n'
256 > EOF
256 > EOF
257 $ hg log -l1 --style ./tmpl
257 $ hg log -l1 --style ./tmpl
258 nothing expanded:
258 nothing expanded:
259
259
260 Test templates and style maps in files:
260 Test templates and style maps in files:
261
261
262 $ echo "{rev}" > tmpl
262 $ echo "{rev}" > tmpl
263 $ hg log -l1 -T./tmpl
263 $ hg log -l1 -T./tmpl
264 8
264 8
265 $ hg log -l1 -Tblah/blah
265 $ hg log -l1 -Tblah/blah
266 blah/blah (no-eol)
266 blah/blah (no-eol)
267
267
268 $ printf 'changeset = "{rev}\\n"\n' > map-simple
268 $ printf 'changeset = "{rev}\\n"\n' > map-simple
269 $ hg log -l1 -T./map-simple
269 $ hg log -l1 -T./map-simple
270 8
270 8
271
271
272 a map file may have [templates] and [templatealias] sections:
272 a map file may have [templates] and [templatealias] sections:
273
273
274 $ cat <<'EOF' > map-simple
274 $ cat <<'EOF' > map-simple
275 > [templates]
275 > [templates]
276 > changeset = "{a}\n"
276 > changeset = "{a}\n"
277 > [templatealias]
277 > [templatealias]
278 > a = rev
278 > a = rev
279 > EOF
279 > EOF
280 $ hg log -l1 -T./map-simple
280 $ hg log -l1 -T./map-simple
281 8
281 8
282
282
283 so it can be included in hgrc
283 so it can be included in hgrc
284
284
285 $ cat <<'EOF' > myhgrc
285 $ cat <<'EOF' > myhgrc
286 > %include map-simple
286 > %include map-simple
287 > [templates]
287 > [templates]
288 > foo = "{changeset}"
288 > foo = "{changeset}"
289 > EOF
289 > EOF
290 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
290 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
291 8
291 8
292 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
292 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
293 8
293 8
294
294
295 Test template map inheritance
295 Test template map inheritance
296
296
297 $ echo "__base__ = map-cmdline.default" > map-simple
297 $ echo "__base__ = map-cmdline.default" > map-simple
298 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
298 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
299 $ hg log -l1 -T./map-simple
299 $ hg log -l1 -T./map-simple
300 changeset: ***8***
300 changeset: ***8***
301 tag: tip
301 tag: tip
302 user: test
302 user: test
303 date: Wed Jan 01 10:01:00 2020 +0000
303 date: Wed Jan 01 10:01:00 2020 +0000
304 summary: third
304 summary: third
305
305
306
306
307 Test docheader, docfooter and separator in template map
307 Test docheader, docfooter and separator in template map
308
308
309 $ cat <<'EOF' > map-myjson
309 $ cat <<'EOF' > map-myjson
310 > docheader = '\{\n'
310 > docheader = '\{\n'
311 > docfooter = '\n}\n'
311 > docfooter = '\n}\n'
312 > separator = ',\n'
312 > separator = ',\n'
313 > changeset = ' {dict(rev, node|short)|json}'
313 > changeset = ' {dict(rev, node|short)|json}'
314 > EOF
314 > EOF
315 $ hg log -l2 -T./map-myjson
315 $ hg log -l2 -T./map-myjson
316 {
316 {
317 {"node": "95c24699272e", "rev": 8},
317 {"node": "95c24699272e", "rev": 8},
318 {"node": "29114dbae42b", "rev": 7}
318 {"node": "29114dbae42b", "rev": 7}
319 }
319 }
320
320
321 Test docheader, docfooter and separator in [templates] section
321 Test docheader, docfooter and separator in [templates] section
322
322
323 $ cat <<'EOF' >> .hg/hgrc
323 $ cat <<'EOF' >> .hg/hgrc
324 > [templates]
324 > [templates]
325 > myjson = ' {dict(rev, node|short)|json}'
325 > myjson = ' {dict(rev, node|short)|json}'
326 > myjson:docheader = '\{\n'
326 > myjson:docheader = '\{\n'
327 > myjson:docfooter = '\n}\n'
327 > myjson:docfooter = '\n}\n'
328 > myjson:separator = ',\n'
328 > myjson:separator = ',\n'
329 > :docheader = 'should not be selected as a docheader for literal templates\n'
329 > :docheader = 'should not be selected as a docheader for literal templates\n'
330 > EOF
330 > EOF
331 $ hg log -l2 -Tmyjson
331 $ hg log -l2 -Tmyjson
332 {
332 {
333 {"node": "95c24699272e", "rev": 8},
333 {"node": "95c24699272e", "rev": 8},
334 {"node": "29114dbae42b", "rev": 7}
334 {"node": "29114dbae42b", "rev": 7}
335 }
335 }
336 $ hg log -l1 -T'{rev}\n'
336 $ hg log -l1 -T'{rev}\n'
337 8
337 8
338
338
339 Template should precede style option
339 Template should precede style option
340
340
341 $ hg log -l1 --style default -T '{rev}\n'
341 $ hg log -l1 --style default -T '{rev}\n'
342 8
342 8
343
343
344 Add a commit with empty description, to ensure that the templates
344 Add a commit with empty description, to ensure that the templates
345 below will omit the description line.
345 below will omit the description line.
346
346
347 $ echo c >> c
347 $ echo c >> c
348 $ hg add c
348 $ hg add c
349 $ hg commit -qm ' '
349 $ hg commit -qm ' '
350
350
351 Default style is like normal output. Phases style should be the same
351 Default style is like normal output. Phases style should be the same
352 as default style, except for extra phase lines.
352 as default style, except for extra phase lines.
353
353
354 $ hg log > log.out
354 $ hg log > log.out
355 $ hg log --style default > style.out
355 $ hg log --style default > style.out
356 $ cmp log.out style.out || diff -u log.out style.out
356 $ cmp log.out style.out || diff -u log.out style.out
357 $ hg log -T phases > phases.out
357 $ hg log -T phases > phases.out
358 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
358 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
359 +phase: draft
359 +phase: draft
360 +phase: draft
360 +phase: draft
361 +phase: draft
361 +phase: draft
362 +phase: draft
362 +phase: draft
363 +phase: draft
363 +phase: draft
364 +phase: draft
364 +phase: draft
365 +phase: draft
365 +phase: draft
366 +phase: draft
366 +phase: draft
367 +phase: draft
367 +phase: draft
368 +phase: draft
368 +phase: draft
369
369
370 $ hg log -v > log.out
370 $ hg log -v > log.out
371 $ hg log -v --style default > style.out
371 $ hg log -v --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 log -v -T phases > phases.out
373 $ hg log -v -T phases > phases.out
374 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
374 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
375 +phase: draft
375 +phase: draft
376 +phase: draft
376 +phase: draft
377 +phase: draft
377 +phase: draft
378 +phase: draft
378 +phase: draft
379 +phase: draft
379 +phase: draft
380 +phase: draft
380 +phase: draft
381 +phase: draft
381 +phase: draft
382 +phase: draft
382 +phase: draft
383 +phase: draft
383 +phase: draft
384 +phase: draft
384 +phase: draft
385
385
386 $ hg log -q > log.out
386 $ hg log -q > log.out
387 $ hg log -q --style default > style.out
387 $ hg log -q --style default > style.out
388 $ cmp log.out style.out || diff -u log.out style.out
388 $ cmp log.out style.out || diff -u log.out style.out
389 $ hg log -q -T phases > phases.out
389 $ hg log -q -T phases > phases.out
390 $ cmp log.out phases.out || diff -u log.out phases.out
390 $ cmp log.out phases.out || diff -u log.out phases.out
391
391
392 $ hg log --debug > log.out
392 $ hg log --debug > log.out
393 $ hg log --debug --style default > style.out
393 $ hg log --debug --style default > style.out
394 $ cmp log.out style.out || diff -u log.out style.out
394 $ cmp log.out style.out || diff -u log.out style.out
395 $ hg log --debug -T phases > phases.out
395 $ hg log --debug -T phases > phases.out
396 $ cmp log.out phases.out || diff -u log.out phases.out
396 $ cmp log.out phases.out || diff -u log.out phases.out
397
397
398 Default style of working-directory revision should also be the same (but
398 Default style of working-directory revision should also be the same (but
399 date may change while running tests):
399 date may change while running tests):
400
400
401 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
401 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
402 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
402 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
403 $ cmp log.out style.out || diff -u log.out style.out
403 $ cmp log.out style.out || diff -u log.out style.out
404
404
405 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
405 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
406 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
406 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
407 $ cmp log.out style.out || diff -u log.out style.out
407 $ cmp log.out style.out || diff -u log.out style.out
408
408
409 $ hg log -r 'wdir()' -q > log.out
409 $ hg log -r 'wdir()' -q > log.out
410 $ hg log -r 'wdir()' -q --style default > style.out
410 $ hg log -r 'wdir()' -q --style default > style.out
411 $ cmp log.out style.out || diff -u log.out style.out
411 $ cmp log.out style.out || diff -u log.out style.out
412
412
413 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
413 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
414 $ hg log -r 'wdir()' --debug --style default \
414 $ hg log -r 'wdir()' --debug --style default \
415 > | sed 's|^date:.*|date:|' > style.out
415 > | sed 's|^date:.*|date:|' > style.out
416 $ cmp log.out style.out || diff -u log.out style.out
416 $ cmp log.out style.out || diff -u log.out style.out
417
417
418 Default style should also preserve color information (issue2866):
418 Default style should also preserve color information (issue2866):
419
419
420 $ cp $HGRCPATH $HGRCPATH-bak
420 $ cp $HGRCPATH $HGRCPATH-bak
421 $ cat <<EOF >> $HGRCPATH
421 $ cat <<EOF >> $HGRCPATH
422 > [extensions]
422 > [extensions]
423 > color=
423 > color=
424 > EOF
424 > EOF
425
425
426 $ hg --color=debug log > log.out
426 $ hg --color=debug log > log.out
427 $ hg --color=debug log --style default > style.out
427 $ hg --color=debug log --style default > style.out
428 $ cmp log.out style.out || diff -u log.out style.out
428 $ cmp log.out style.out || diff -u log.out style.out
429 $ hg --color=debug log -T phases > phases.out
429 $ hg --color=debug log -T phases > phases.out
430 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
430 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
431 +[log.phase|phase: draft]
431 +[log.phase|phase: draft]
432 +[log.phase|phase: draft]
432 +[log.phase|phase: draft]
433 +[log.phase|phase: draft]
433 +[log.phase|phase: draft]
434 +[log.phase|phase: draft]
434 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
441
441
442 $ hg --color=debug -v log > log.out
442 $ hg --color=debug -v log > log.out
443 $ hg --color=debug -v log --style default > style.out
443 $ hg --color=debug -v log --style default > style.out
444 $ cmp log.out style.out || diff -u log.out style.out
444 $ cmp log.out style.out || diff -u log.out style.out
445 $ hg --color=debug -v log -T phases > phases.out
445 $ hg --color=debug -v log -T phases > phases.out
446 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
446 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
447 +[log.phase|phase: draft]
447 +[log.phase|phase: draft]
448 +[log.phase|phase: draft]
448 +[log.phase|phase: draft]
449 +[log.phase|phase: draft]
449 +[log.phase|phase: draft]
450 +[log.phase|phase: draft]
450 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
457
457
458 $ hg --color=debug -q log > log.out
458 $ hg --color=debug -q log > log.out
459 $ hg --color=debug -q log --style default > style.out
459 $ hg --color=debug -q log --style default > style.out
460 $ cmp log.out style.out || diff -u log.out style.out
460 $ cmp log.out style.out || diff -u log.out style.out
461 $ hg --color=debug -q log -T phases > phases.out
461 $ hg --color=debug -q log -T phases > phases.out
462 $ cmp log.out phases.out || diff -u log.out phases.out
462 $ cmp log.out phases.out || diff -u log.out phases.out
463
463
464 $ hg --color=debug --debug log > log.out
464 $ hg --color=debug --debug log > log.out
465 $ hg --color=debug --debug log --style default > style.out
465 $ hg --color=debug --debug log --style default > style.out
466 $ cmp log.out style.out || diff -u log.out style.out
466 $ cmp log.out style.out || diff -u log.out style.out
467 $ hg --color=debug --debug log -T phases > phases.out
467 $ hg --color=debug --debug log -T phases > phases.out
468 $ cmp log.out phases.out || diff -u log.out phases.out
468 $ cmp log.out phases.out || diff -u log.out phases.out
469
469
470 $ mv $HGRCPATH-bak $HGRCPATH
470 $ mv $HGRCPATH-bak $HGRCPATH
471
471
472 Remove commit with empty commit message, so as to not pollute further
472 Remove commit with empty commit message, so as to not pollute further
473 tests.
473 tests.
474
474
475 $ hg --config extensions.strip= strip -q .
475 $ hg --config extensions.strip= strip -q .
476
476
477 Revision with no copies (used to print a traceback):
477 Revision with no copies (used to print a traceback):
478
478
479 $ hg tip -v --template '\n'
479 $ hg tip -v --template '\n'
480
480
481
481
482 Compact style works:
482 Compact style works:
483
483
484 $ hg log -Tcompact
484 $ hg log -Tcompact
485 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
485 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
486 third
486 third
487
487
488 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
488 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
489 second
489 second
490
490
491 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
491 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
492 merge
492 merge
493
493
494 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
494 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
495 new head
495 new head
496
496
497 4 bbe44766e73d 1970-01-17 04:53 +0000 person
497 4 bbe44766e73d 1970-01-17 04:53 +0000 person
498 new branch
498 new branch
499
499
500 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
500 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
501 no user, no domain
501 no user, no domain
502
502
503 2 97054abb4ab8 1970-01-14 21:20 +0000 other
503 2 97054abb4ab8 1970-01-14 21:20 +0000 other
504 no person
504 no person
505
505
506 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
506 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
507 other 1
507 other 1
508
508
509 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
509 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
510 line 1
510 line 1
511
511
512
512
513 $ hg log -v --style compact
513 $ hg log -v --style compact
514 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
514 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
515 third
515 third
516
516
517 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
517 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
518 second
518 second
519
519
520 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
520 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
521 merge
521 merge
522
522
523 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
523 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
524 new head
524 new head
525
525
526 4 bbe44766e73d 1970-01-17 04:53 +0000 person
526 4 bbe44766e73d 1970-01-17 04:53 +0000 person
527 new branch
527 new branch
528
528
529 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
529 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
530 no user, no domain
530 no user, no domain
531
531
532 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
532 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
533 no person
533 no person
534
534
535 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
535 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
536 other 1
536 other 1
537 other 2
537 other 2
538
538
539 other 3
539 other 3
540
540
541 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
541 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
542 line 1
542 line 1
543 line 2
543 line 2
544
544
545
545
546 $ hg log --debug --style compact
546 $ hg log --debug --style compact
547 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
547 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
548 third
548 third
549
549
550 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
550 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
551 second
551 second
552
552
553 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
553 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
554 merge
554 merge
555
555
556 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
556 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
557 new head
557 new head
558
558
559 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
559 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
560 new branch
560 new branch
561
561
562 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
562 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
563 no user, no domain
563 no user, no domain
564
564
565 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
565 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
566 no person
566 no person
567
567
568 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
568 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
569 other 1
569 other 1
570 other 2
570 other 2
571
571
572 other 3
572 other 3
573
573
574 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
574 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
575 line 1
575 line 1
576 line 2
576 line 2
577
577
578
578
579 Test xml styles:
579 Test xml styles:
580
580
581 $ hg log --style xml -r 'not all()'
581 $ hg log --style xml -r 'not all()'
582 <?xml version="1.0"?>
582 <?xml version="1.0"?>
583 <log>
583 <log>
584 </log>
584 </log>
585
585
586 $ hg log --style xml
586 $ hg log --style xml
587 <?xml version="1.0"?>
587 <?xml version="1.0"?>
588 <log>
588 <log>
589 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
589 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
590 <tag>tip</tag>
590 <tag>tip</tag>
591 <author email="test">test</author>
591 <author email="test">test</author>
592 <date>2020-01-01T10:01:00+00:00</date>
592 <date>2020-01-01T10:01:00+00:00</date>
593 <msg xml:space="preserve">third</msg>
593 <msg xml:space="preserve">third</msg>
594 </logentry>
594 </logentry>
595 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
595 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
596 <parent revision="-1" node="0000000000000000000000000000000000000000" />
596 <parent revision="-1" node="0000000000000000000000000000000000000000" />
597 <author email="user@hostname">User Name</author>
597 <author email="user@hostname">User Name</author>
598 <date>1970-01-12T13:46:40+00:00</date>
598 <date>1970-01-12T13:46:40+00:00</date>
599 <msg xml:space="preserve">second</msg>
599 <msg xml:space="preserve">second</msg>
600 </logentry>
600 </logentry>
601 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
601 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
602 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
602 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
603 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
603 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
604 <author email="person">person</author>
604 <author email="person">person</author>
605 <date>1970-01-18T08:40:01+00:00</date>
605 <date>1970-01-18T08:40:01+00:00</date>
606 <msg xml:space="preserve">merge</msg>
606 <msg xml:space="preserve">merge</msg>
607 </logentry>
607 </logentry>
608 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
608 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
609 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
609 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
610 <author email="person">person</author>
610 <author email="person">person</author>
611 <date>1970-01-18T08:40:00+00:00</date>
611 <date>1970-01-18T08:40:00+00:00</date>
612 <msg xml:space="preserve">new head</msg>
612 <msg xml:space="preserve">new head</msg>
613 </logentry>
613 </logentry>
614 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
614 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
615 <branch>foo</branch>
615 <branch>foo</branch>
616 <author email="person">person</author>
616 <author email="person">person</author>
617 <date>1970-01-17T04:53:20+00:00</date>
617 <date>1970-01-17T04:53:20+00:00</date>
618 <msg xml:space="preserve">new branch</msg>
618 <msg xml:space="preserve">new branch</msg>
619 </logentry>
619 </logentry>
620 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
620 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
621 <author email="person">person</author>
621 <author email="person">person</author>
622 <date>1970-01-16T01:06:40+00:00</date>
622 <date>1970-01-16T01:06:40+00:00</date>
623 <msg xml:space="preserve">no user, no domain</msg>
623 <msg xml:space="preserve">no user, no domain</msg>
624 </logentry>
624 </logentry>
625 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
625 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
626 <author email="other@place">other</author>
626 <author email="other@place">other</author>
627 <date>1970-01-14T21:20:00+00:00</date>
627 <date>1970-01-14T21:20:00+00:00</date>
628 <msg xml:space="preserve">no person</msg>
628 <msg xml:space="preserve">no person</msg>
629 </logentry>
629 </logentry>
630 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
630 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
631 <author email="other@place">A. N. Other</author>
631 <author email="other@place">A. N. Other</author>
632 <date>1970-01-13T17:33:20+00:00</date>
632 <date>1970-01-13T17:33:20+00:00</date>
633 <msg xml:space="preserve">other 1
633 <msg xml:space="preserve">other 1
634 other 2
634 other 2
635
635
636 other 3</msg>
636 other 3</msg>
637 </logentry>
637 </logentry>
638 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
638 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
639 <author email="user@hostname">User Name</author>
639 <author email="user@hostname">User Name</author>
640 <date>1970-01-12T13:46:40+00:00</date>
640 <date>1970-01-12T13:46:40+00:00</date>
641 <msg xml:space="preserve">line 1
641 <msg xml:space="preserve">line 1
642 line 2</msg>
642 line 2</msg>
643 </logentry>
643 </logentry>
644 </log>
644 </log>
645
645
646 $ hg log -v --style xml
646 $ hg log -v --style xml
647 <?xml version="1.0"?>
647 <?xml version="1.0"?>
648 <log>
648 <log>
649 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
649 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
650 <tag>tip</tag>
650 <tag>tip</tag>
651 <author email="test">test</author>
651 <author email="test">test</author>
652 <date>2020-01-01T10:01:00+00:00</date>
652 <date>2020-01-01T10:01:00+00:00</date>
653 <msg xml:space="preserve">third</msg>
653 <msg xml:space="preserve">third</msg>
654 <paths>
654 <paths>
655 <path action="A">fourth</path>
655 <path action="A">fourth</path>
656 <path action="A">third</path>
656 <path action="A">third</path>
657 <path action="R">second</path>
657 <path action="R">second</path>
658 </paths>
658 </paths>
659 <copies>
659 <copies>
660 <copy source="second">fourth</copy>
660 <copy source="second">fourth</copy>
661 </copies>
661 </copies>
662 </logentry>
662 </logentry>
663 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
663 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
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 </logentry>
671 </logentry>
672 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
672 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
673 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
673 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
674 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
674 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
675 <author email="person">person</author>
675 <author email="person">person</author>
676 <date>1970-01-18T08:40:01+00:00</date>
676 <date>1970-01-18T08:40:01+00:00</date>
677 <msg xml:space="preserve">merge</msg>
677 <msg xml:space="preserve">merge</msg>
678 <paths>
678 <paths>
679 </paths>
679 </paths>
680 </logentry>
680 </logentry>
681 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
681 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
682 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
682 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
683 <author email="person">person</author>
683 <author email="person">person</author>
684 <date>1970-01-18T08:40:00+00:00</date>
684 <date>1970-01-18T08:40:00+00:00</date>
685 <msg xml:space="preserve">new head</msg>
685 <msg xml:space="preserve">new head</msg>
686 <paths>
686 <paths>
687 <path action="A">d</path>
687 <path action="A">d</path>
688 </paths>
688 </paths>
689 </logentry>
689 </logentry>
690 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
690 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
691 <branch>foo</branch>
691 <branch>foo</branch>
692 <author email="person">person</author>
692 <author email="person">person</author>
693 <date>1970-01-17T04:53:20+00:00</date>
693 <date>1970-01-17T04:53:20+00:00</date>
694 <msg xml:space="preserve">new branch</msg>
694 <msg xml:space="preserve">new branch</msg>
695 <paths>
695 <paths>
696 </paths>
696 </paths>
697 </logentry>
697 </logentry>
698 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
698 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
699 <author email="person">person</author>
699 <author email="person">person</author>
700 <date>1970-01-16T01:06:40+00:00</date>
700 <date>1970-01-16T01:06:40+00:00</date>
701 <msg xml:space="preserve">no user, no domain</msg>
701 <msg xml:space="preserve">no user, no domain</msg>
702 <paths>
702 <paths>
703 <path action="M">c</path>
703 <path action="M">c</path>
704 </paths>
704 </paths>
705 </logentry>
705 </logentry>
706 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
706 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
707 <author email="other@place">other</author>
707 <author email="other@place">other</author>
708 <date>1970-01-14T21:20:00+00:00</date>
708 <date>1970-01-14T21:20:00+00:00</date>
709 <msg xml:space="preserve">no person</msg>
709 <msg xml:space="preserve">no person</msg>
710 <paths>
710 <paths>
711 <path action="A">c</path>
711 <path action="A">c</path>
712 </paths>
712 </paths>
713 </logentry>
713 </logentry>
714 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
714 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
715 <author email="other@place">A. N. Other</author>
715 <author email="other@place">A. N. Other</author>
716 <date>1970-01-13T17:33:20+00:00</date>
716 <date>1970-01-13T17:33:20+00:00</date>
717 <msg xml:space="preserve">other 1
717 <msg xml:space="preserve">other 1
718 other 2
718 other 2
719
719
720 other 3</msg>
720 other 3</msg>
721 <paths>
721 <paths>
722 <path action="A">b</path>
722 <path action="A">b</path>
723 </paths>
723 </paths>
724 </logentry>
724 </logentry>
725 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
725 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
726 <author email="user@hostname">User Name</author>
726 <author email="user@hostname">User Name</author>
727 <date>1970-01-12T13:46:40+00:00</date>
727 <date>1970-01-12T13:46:40+00:00</date>
728 <msg xml:space="preserve">line 1
728 <msg xml:space="preserve">line 1
729 line 2</msg>
729 line 2</msg>
730 <paths>
730 <paths>
731 <path action="A">a</path>
731 <path action="A">a</path>
732 </paths>
732 </paths>
733 </logentry>
733 </logentry>
734 </log>
734 </log>
735
735
736 $ hg log --debug --style xml
736 $ hg log --debug --style xml
737 <?xml version="1.0"?>
737 <?xml version="1.0"?>
738 <log>
738 <log>
739 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
739 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
740 <tag>tip</tag>
740 <tag>tip</tag>
741 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
741 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
742 <parent revision="-1" node="0000000000000000000000000000000000000000" />
742 <parent revision="-1" node="0000000000000000000000000000000000000000" />
743 <author email="test">test</author>
743 <author email="test">test</author>
744 <date>2020-01-01T10:01:00+00:00</date>
744 <date>2020-01-01T10:01:00+00:00</date>
745 <msg xml:space="preserve">third</msg>
745 <msg xml:space="preserve">third</msg>
746 <paths>
746 <paths>
747 <path action="A">fourth</path>
747 <path action="A">fourth</path>
748 <path action="A">third</path>
748 <path action="A">third</path>
749 <path action="R">second</path>
749 <path action="R">second</path>
750 </paths>
750 </paths>
751 <copies>
751 <copies>
752 <copy source="second">fourth</copy>
752 <copy source="second">fourth</copy>
753 </copies>
753 </copies>
754 <extra key="branch">default</extra>
754 <extra key="branch">default</extra>
755 </logentry>
755 </logentry>
756 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
756 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
757 <parent revision="-1" node="0000000000000000000000000000000000000000" />
757 <parent revision="-1" node="0000000000000000000000000000000000000000" />
758 <parent revision="-1" node="0000000000000000000000000000000000000000" />
758 <parent revision="-1" node="0000000000000000000000000000000000000000" />
759 <author email="user@hostname">User Name</author>
759 <author email="user@hostname">User Name</author>
760 <date>1970-01-12T13:46:40+00:00</date>
760 <date>1970-01-12T13:46:40+00:00</date>
761 <msg xml:space="preserve">second</msg>
761 <msg xml:space="preserve">second</msg>
762 <paths>
762 <paths>
763 <path action="A">second</path>
763 <path action="A">second</path>
764 </paths>
764 </paths>
765 <extra key="branch">default</extra>
765 <extra key="branch">default</extra>
766 </logentry>
766 </logentry>
767 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
767 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
768 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
768 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
769 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
769 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
770 <author email="person">person</author>
770 <author email="person">person</author>
771 <date>1970-01-18T08:40:01+00:00</date>
771 <date>1970-01-18T08:40:01+00:00</date>
772 <msg xml:space="preserve">merge</msg>
772 <msg xml:space="preserve">merge</msg>
773 <paths>
773 <paths>
774 </paths>
774 </paths>
775 <extra key="branch">default</extra>
775 <extra key="branch">default</extra>
776 </logentry>
776 </logentry>
777 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
777 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
778 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
778 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
779 <parent revision="-1" node="0000000000000000000000000000000000000000" />
779 <parent revision="-1" node="0000000000000000000000000000000000000000" />
780 <author email="person">person</author>
780 <author email="person">person</author>
781 <date>1970-01-18T08:40:00+00:00</date>
781 <date>1970-01-18T08:40:00+00:00</date>
782 <msg xml:space="preserve">new head</msg>
782 <msg xml:space="preserve">new head</msg>
783 <paths>
783 <paths>
784 <path action="A">d</path>
784 <path action="A">d</path>
785 </paths>
785 </paths>
786 <extra key="branch">default</extra>
786 <extra key="branch">default</extra>
787 </logentry>
787 </logentry>
788 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
788 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
789 <branch>foo</branch>
789 <branch>foo</branch>
790 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
790 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
791 <parent revision="-1" node="0000000000000000000000000000000000000000" />
791 <parent revision="-1" node="0000000000000000000000000000000000000000" />
792 <author email="person">person</author>
792 <author email="person">person</author>
793 <date>1970-01-17T04:53:20+00:00</date>
793 <date>1970-01-17T04:53:20+00:00</date>
794 <msg xml:space="preserve">new branch</msg>
794 <msg xml:space="preserve">new branch</msg>
795 <paths>
795 <paths>
796 </paths>
796 </paths>
797 <extra key="branch">foo</extra>
797 <extra key="branch">foo</extra>
798 </logentry>
798 </logentry>
799 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
799 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
800 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
800 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
801 <parent revision="-1" node="0000000000000000000000000000000000000000" />
801 <parent revision="-1" node="0000000000000000000000000000000000000000" />
802 <author email="person">person</author>
802 <author email="person">person</author>
803 <date>1970-01-16T01:06:40+00:00</date>
803 <date>1970-01-16T01:06:40+00:00</date>
804 <msg xml:space="preserve">no user, no domain</msg>
804 <msg xml:space="preserve">no user, no domain</msg>
805 <paths>
805 <paths>
806 <path action="M">c</path>
806 <path action="M">c</path>
807 </paths>
807 </paths>
808 <extra key="branch">default</extra>
808 <extra key="branch">default</extra>
809 </logentry>
809 </logentry>
810 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
810 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
811 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
811 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
812 <parent revision="-1" node="0000000000000000000000000000000000000000" />
812 <parent revision="-1" node="0000000000000000000000000000000000000000" />
813 <author email="other@place">other</author>
813 <author email="other@place">other</author>
814 <date>1970-01-14T21:20:00+00:00</date>
814 <date>1970-01-14T21:20:00+00:00</date>
815 <msg xml:space="preserve">no person</msg>
815 <msg xml:space="preserve">no person</msg>
816 <paths>
816 <paths>
817 <path action="A">c</path>
817 <path action="A">c</path>
818 </paths>
818 </paths>
819 <extra key="branch">default</extra>
819 <extra key="branch">default</extra>
820 </logentry>
820 </logentry>
821 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
821 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
822 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
822 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
823 <parent revision="-1" node="0000000000000000000000000000000000000000" />
823 <parent revision="-1" node="0000000000000000000000000000000000000000" />
824 <author email="other@place">A. N. Other</author>
824 <author email="other@place">A. N. Other</author>
825 <date>1970-01-13T17:33:20+00:00</date>
825 <date>1970-01-13T17:33:20+00:00</date>
826 <msg xml:space="preserve">other 1
826 <msg xml:space="preserve">other 1
827 other 2
827 other 2
828
828
829 other 3</msg>
829 other 3</msg>
830 <paths>
830 <paths>
831 <path action="A">b</path>
831 <path action="A">b</path>
832 </paths>
832 </paths>
833 <extra key="branch">default</extra>
833 <extra key="branch">default</extra>
834 </logentry>
834 </logentry>
835 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
835 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
836 <parent revision="-1" node="0000000000000000000000000000000000000000" />
836 <parent revision="-1" node="0000000000000000000000000000000000000000" />
837 <parent revision="-1" node="0000000000000000000000000000000000000000" />
837 <parent revision="-1" node="0000000000000000000000000000000000000000" />
838 <author email="user@hostname">User Name</author>
838 <author email="user@hostname">User Name</author>
839 <date>1970-01-12T13:46:40+00:00</date>
839 <date>1970-01-12T13:46:40+00:00</date>
840 <msg xml:space="preserve">line 1
840 <msg xml:space="preserve">line 1
841 line 2</msg>
841 line 2</msg>
842 <paths>
842 <paths>
843 <path action="A">a</path>
843 <path action="A">a</path>
844 </paths>
844 </paths>
845 <extra key="branch">default</extra>
845 <extra key="branch">default</extra>
846 </logentry>
846 </logentry>
847 </log>
847 </log>
848
848
849
849
850 Test JSON style:
850 Test JSON style:
851
851
852 $ hg log -k nosuch -Tjson
852 $ hg log -k nosuch -Tjson
853 []
853 []
854
854
855 $ hg log -qr . -Tjson
855 $ hg log -qr . -Tjson
856 [
856 [
857 {
857 {
858 "rev": 8,
858 "rev": 8,
859 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
859 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
860 }
860 }
861 ]
861 ]
862
862
863 $ hg log -vpr . -Tjson --stat
863 $ hg log -vpr . -Tjson --stat
864 [
864 [
865 {
865 {
866 "rev": 8,
866 "rev": 8,
867 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
867 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
868 "branch": "default",
868 "branch": "default",
869 "phase": "draft",
869 "phase": "draft",
870 "user": "test",
870 "user": "test",
871 "date": [1577872860, 0],
871 "date": [1577872860, 0],
872 "desc": "third",
872 "desc": "third",
873 "bookmarks": [],
873 "bookmarks": [],
874 "tags": ["tip"],
874 "tags": ["tip"],
875 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
875 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
876 "files": ["fourth", "second", "third"],
876 "files": ["fourth", "second", "third"],
877 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
877 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
878 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
878 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
879 }
879 }
880 ]
880 ]
881
881
882 honor --git but not format-breaking diffopts
882 honor --git but not format-breaking diffopts
883 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
883 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
884 [
884 [
885 {
885 {
886 "rev": 8,
886 "rev": 8,
887 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
887 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
888 "branch": "default",
888 "branch": "default",
889 "phase": "draft",
889 "phase": "draft",
890 "user": "test",
890 "user": "test",
891 "date": [1577872860, 0],
891 "date": [1577872860, 0],
892 "desc": "third",
892 "desc": "third",
893 "bookmarks": [],
893 "bookmarks": [],
894 "tags": ["tip"],
894 "tags": ["tip"],
895 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
895 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
896 "files": ["fourth", "second", "third"],
896 "files": ["fourth", "second", "third"],
897 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
897 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
898 }
898 }
899 ]
899 ]
900
900
901 $ hg log -T json
901 $ hg log -T json
902 [
902 [
903 {
903 {
904 "rev": 8,
904 "rev": 8,
905 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
905 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
906 "branch": "default",
906 "branch": "default",
907 "phase": "draft",
907 "phase": "draft",
908 "user": "test",
908 "user": "test",
909 "date": [1577872860, 0],
909 "date": [1577872860, 0],
910 "desc": "third",
910 "desc": "third",
911 "bookmarks": [],
911 "bookmarks": [],
912 "tags": ["tip"],
912 "tags": ["tip"],
913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
914 },
914 },
915 {
915 {
916 "rev": 7,
916 "rev": 7,
917 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
917 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
918 "branch": "default",
918 "branch": "default",
919 "phase": "draft",
919 "phase": "draft",
920 "user": "User Name <user@hostname>",
920 "user": "User Name <user@hostname>",
921 "date": [1000000, 0],
921 "date": [1000000, 0],
922 "desc": "second",
922 "desc": "second",
923 "bookmarks": [],
923 "bookmarks": [],
924 "tags": [],
924 "tags": [],
925 "parents": ["0000000000000000000000000000000000000000"]
925 "parents": ["0000000000000000000000000000000000000000"]
926 },
926 },
927 {
927 {
928 "rev": 6,
928 "rev": 6,
929 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
929 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
930 "branch": "default",
930 "branch": "default",
931 "phase": "draft",
931 "phase": "draft",
932 "user": "person",
932 "user": "person",
933 "date": [1500001, 0],
933 "date": [1500001, 0],
934 "desc": "merge",
934 "desc": "merge",
935 "bookmarks": [],
935 "bookmarks": [],
936 "tags": [],
936 "tags": [],
937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
938 },
938 },
939 {
939 {
940 "rev": 5,
940 "rev": 5,
941 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
941 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
942 "branch": "default",
942 "branch": "default",
943 "phase": "draft",
943 "phase": "draft",
944 "user": "person",
944 "user": "person",
945 "date": [1500000, 0],
945 "date": [1500000, 0],
946 "desc": "new head",
946 "desc": "new head",
947 "bookmarks": [],
947 "bookmarks": [],
948 "tags": [],
948 "tags": [],
949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
950 },
950 },
951 {
951 {
952 "rev": 4,
952 "rev": 4,
953 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
953 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
954 "branch": "foo",
954 "branch": "foo",
955 "phase": "draft",
955 "phase": "draft",
956 "user": "person",
956 "user": "person",
957 "date": [1400000, 0],
957 "date": [1400000, 0],
958 "desc": "new branch",
958 "desc": "new branch",
959 "bookmarks": [],
959 "bookmarks": [],
960 "tags": [],
960 "tags": [],
961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
962 },
962 },
963 {
963 {
964 "rev": 3,
964 "rev": 3,
965 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
965 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
966 "branch": "default",
966 "branch": "default",
967 "phase": "draft",
967 "phase": "draft",
968 "user": "person",
968 "user": "person",
969 "date": [1300000, 0],
969 "date": [1300000, 0],
970 "desc": "no user, no domain",
970 "desc": "no user, no domain",
971 "bookmarks": [],
971 "bookmarks": [],
972 "tags": [],
972 "tags": [],
973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
974 },
974 },
975 {
975 {
976 "rev": 2,
976 "rev": 2,
977 "node": "97054abb4ab824450e9164180baf491ae0078465",
977 "node": "97054abb4ab824450e9164180baf491ae0078465",
978 "branch": "default",
978 "branch": "default",
979 "phase": "draft",
979 "phase": "draft",
980 "user": "other@place",
980 "user": "other@place",
981 "date": [1200000, 0],
981 "date": [1200000, 0],
982 "desc": "no person",
982 "desc": "no person",
983 "bookmarks": [],
983 "bookmarks": [],
984 "tags": [],
984 "tags": [],
985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
986 },
986 },
987 {
987 {
988 "rev": 1,
988 "rev": 1,
989 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
989 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
990 "branch": "default",
990 "branch": "default",
991 "phase": "draft",
991 "phase": "draft",
992 "user": "A. N. Other <other@place>",
992 "user": "A. N. Other <other@place>",
993 "date": [1100000, 0],
993 "date": [1100000, 0],
994 "desc": "other 1\nother 2\n\nother 3",
994 "desc": "other 1\nother 2\n\nother 3",
995 "bookmarks": [],
995 "bookmarks": [],
996 "tags": [],
996 "tags": [],
997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
998 },
998 },
999 {
999 {
1000 "rev": 0,
1000 "rev": 0,
1001 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1001 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1002 "branch": "default",
1002 "branch": "default",
1003 "phase": "draft",
1003 "phase": "draft",
1004 "user": "User Name <user@hostname>",
1004 "user": "User Name <user@hostname>",
1005 "date": [1000000, 0],
1005 "date": [1000000, 0],
1006 "desc": "line 1\nline 2",
1006 "desc": "line 1\nline 2",
1007 "bookmarks": [],
1007 "bookmarks": [],
1008 "tags": [],
1008 "tags": [],
1009 "parents": ["0000000000000000000000000000000000000000"]
1009 "parents": ["0000000000000000000000000000000000000000"]
1010 }
1010 }
1011 ]
1011 ]
1012
1012
1013 $ hg heads -v -Tjson
1013 $ hg heads -v -Tjson
1014 [
1014 [
1015 {
1015 {
1016 "rev": 8,
1016 "rev": 8,
1017 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1017 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1018 "branch": "default",
1018 "branch": "default",
1019 "phase": "draft",
1019 "phase": "draft",
1020 "user": "test",
1020 "user": "test",
1021 "date": [1577872860, 0],
1021 "date": [1577872860, 0],
1022 "desc": "third",
1022 "desc": "third",
1023 "bookmarks": [],
1023 "bookmarks": [],
1024 "tags": ["tip"],
1024 "tags": ["tip"],
1025 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1025 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1026 "files": ["fourth", "second", "third"]
1026 "files": ["fourth", "second", "third"]
1027 },
1027 },
1028 {
1028 {
1029 "rev": 6,
1029 "rev": 6,
1030 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1030 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1031 "branch": "default",
1031 "branch": "default",
1032 "phase": "draft",
1032 "phase": "draft",
1033 "user": "person",
1033 "user": "person",
1034 "date": [1500001, 0],
1034 "date": [1500001, 0],
1035 "desc": "merge",
1035 "desc": "merge",
1036 "bookmarks": [],
1036 "bookmarks": [],
1037 "tags": [],
1037 "tags": [],
1038 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1038 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1039 "files": []
1039 "files": []
1040 },
1040 },
1041 {
1041 {
1042 "rev": 4,
1042 "rev": 4,
1043 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1043 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1044 "branch": "foo",
1044 "branch": "foo",
1045 "phase": "draft",
1045 "phase": "draft",
1046 "user": "person",
1046 "user": "person",
1047 "date": [1400000, 0],
1047 "date": [1400000, 0],
1048 "desc": "new branch",
1048 "desc": "new branch",
1049 "bookmarks": [],
1049 "bookmarks": [],
1050 "tags": [],
1050 "tags": [],
1051 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1051 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1052 "files": []
1052 "files": []
1053 }
1053 }
1054 ]
1054 ]
1055
1055
1056 $ hg log --debug -Tjson
1056 $ hg log --debug -Tjson
1057 [
1057 [
1058 {
1058 {
1059 "rev": 8,
1059 "rev": 8,
1060 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1060 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1061 "branch": "default",
1061 "branch": "default",
1062 "phase": "draft",
1062 "phase": "draft",
1063 "user": "test",
1063 "user": "test",
1064 "date": [1577872860, 0],
1064 "date": [1577872860, 0],
1065 "desc": "third",
1065 "desc": "third",
1066 "bookmarks": [],
1066 "bookmarks": [],
1067 "tags": ["tip"],
1067 "tags": ["tip"],
1068 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1068 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1070 "extra": {"branch": "default"},
1070 "extra": {"branch": "default"},
1071 "modified": [],
1071 "modified": [],
1072 "added": ["fourth", "third"],
1072 "added": ["fourth", "third"],
1073 "removed": ["second"]
1073 "removed": ["second"]
1074 },
1074 },
1075 {
1075 {
1076 "rev": 7,
1076 "rev": 7,
1077 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1077 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1078 "branch": "default",
1078 "branch": "default",
1079 "phase": "draft",
1079 "phase": "draft",
1080 "user": "User Name <user@hostname>",
1080 "user": "User Name <user@hostname>",
1081 "date": [1000000, 0],
1081 "date": [1000000, 0],
1082 "desc": "second",
1082 "desc": "second",
1083 "bookmarks": [],
1083 "bookmarks": [],
1084 "tags": [],
1084 "tags": [],
1085 "parents": ["0000000000000000000000000000000000000000"],
1085 "parents": ["0000000000000000000000000000000000000000"],
1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1087 "extra": {"branch": "default"},
1087 "extra": {"branch": "default"},
1088 "modified": [],
1088 "modified": [],
1089 "added": ["second"],
1089 "added": ["second"],
1090 "removed": []
1090 "removed": []
1091 },
1091 },
1092 {
1092 {
1093 "rev": 6,
1093 "rev": 6,
1094 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1094 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1095 "branch": "default",
1095 "branch": "default",
1096 "phase": "draft",
1096 "phase": "draft",
1097 "user": "person",
1097 "user": "person",
1098 "date": [1500001, 0],
1098 "date": [1500001, 0],
1099 "desc": "merge",
1099 "desc": "merge",
1100 "bookmarks": [],
1100 "bookmarks": [],
1101 "tags": [],
1101 "tags": [],
1102 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1102 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1104 "extra": {"branch": "default"},
1104 "extra": {"branch": "default"},
1105 "modified": [],
1105 "modified": [],
1106 "added": [],
1106 "added": [],
1107 "removed": []
1107 "removed": []
1108 },
1108 },
1109 {
1109 {
1110 "rev": 5,
1110 "rev": 5,
1111 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1111 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1112 "branch": "default",
1112 "branch": "default",
1113 "phase": "draft",
1113 "phase": "draft",
1114 "user": "person",
1114 "user": "person",
1115 "date": [1500000, 0],
1115 "date": [1500000, 0],
1116 "desc": "new head",
1116 "desc": "new head",
1117 "bookmarks": [],
1117 "bookmarks": [],
1118 "tags": [],
1118 "tags": [],
1119 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1119 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1121 "extra": {"branch": "default"},
1121 "extra": {"branch": "default"},
1122 "modified": [],
1122 "modified": [],
1123 "added": ["d"],
1123 "added": ["d"],
1124 "removed": []
1124 "removed": []
1125 },
1125 },
1126 {
1126 {
1127 "rev": 4,
1127 "rev": 4,
1128 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1128 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1129 "branch": "foo",
1129 "branch": "foo",
1130 "phase": "draft",
1130 "phase": "draft",
1131 "user": "person",
1131 "user": "person",
1132 "date": [1400000, 0],
1132 "date": [1400000, 0],
1133 "desc": "new branch",
1133 "desc": "new branch",
1134 "bookmarks": [],
1134 "bookmarks": [],
1135 "tags": [],
1135 "tags": [],
1136 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1136 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1138 "extra": {"branch": "foo"},
1138 "extra": {"branch": "foo"},
1139 "modified": [],
1139 "modified": [],
1140 "added": [],
1140 "added": [],
1141 "removed": []
1141 "removed": []
1142 },
1142 },
1143 {
1143 {
1144 "rev": 3,
1144 "rev": 3,
1145 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1145 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1146 "branch": "default",
1146 "branch": "default",
1147 "phase": "draft",
1147 "phase": "draft",
1148 "user": "person",
1148 "user": "person",
1149 "date": [1300000, 0],
1149 "date": [1300000, 0],
1150 "desc": "no user, no domain",
1150 "desc": "no user, no domain",
1151 "bookmarks": [],
1151 "bookmarks": [],
1152 "tags": [],
1152 "tags": [],
1153 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1153 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1155 "extra": {"branch": "default"},
1155 "extra": {"branch": "default"},
1156 "modified": ["c"],
1156 "modified": ["c"],
1157 "added": [],
1157 "added": [],
1158 "removed": []
1158 "removed": []
1159 },
1159 },
1160 {
1160 {
1161 "rev": 2,
1161 "rev": 2,
1162 "node": "97054abb4ab824450e9164180baf491ae0078465",
1162 "node": "97054abb4ab824450e9164180baf491ae0078465",
1163 "branch": "default",
1163 "branch": "default",
1164 "phase": "draft",
1164 "phase": "draft",
1165 "user": "other@place",
1165 "user": "other@place",
1166 "date": [1200000, 0],
1166 "date": [1200000, 0],
1167 "desc": "no person",
1167 "desc": "no person",
1168 "bookmarks": [],
1168 "bookmarks": [],
1169 "tags": [],
1169 "tags": [],
1170 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1170 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1172 "extra": {"branch": "default"},
1172 "extra": {"branch": "default"},
1173 "modified": [],
1173 "modified": [],
1174 "added": ["c"],
1174 "added": ["c"],
1175 "removed": []
1175 "removed": []
1176 },
1176 },
1177 {
1177 {
1178 "rev": 1,
1178 "rev": 1,
1179 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1179 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1180 "branch": "default",
1180 "branch": "default",
1181 "phase": "draft",
1181 "phase": "draft",
1182 "user": "A. N. Other <other@place>",
1182 "user": "A. N. Other <other@place>",
1183 "date": [1100000, 0],
1183 "date": [1100000, 0],
1184 "desc": "other 1\nother 2\n\nother 3",
1184 "desc": "other 1\nother 2\n\nother 3",
1185 "bookmarks": [],
1185 "bookmarks": [],
1186 "tags": [],
1186 "tags": [],
1187 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1187 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1189 "extra": {"branch": "default"},
1189 "extra": {"branch": "default"},
1190 "modified": [],
1190 "modified": [],
1191 "added": ["b"],
1191 "added": ["b"],
1192 "removed": []
1192 "removed": []
1193 },
1193 },
1194 {
1194 {
1195 "rev": 0,
1195 "rev": 0,
1196 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1196 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1197 "branch": "default",
1197 "branch": "default",
1198 "phase": "draft",
1198 "phase": "draft",
1199 "user": "User Name <user@hostname>",
1199 "user": "User Name <user@hostname>",
1200 "date": [1000000, 0],
1200 "date": [1000000, 0],
1201 "desc": "line 1\nline 2",
1201 "desc": "line 1\nline 2",
1202 "bookmarks": [],
1202 "bookmarks": [],
1203 "tags": [],
1203 "tags": [],
1204 "parents": ["0000000000000000000000000000000000000000"],
1204 "parents": ["0000000000000000000000000000000000000000"],
1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1206 "extra": {"branch": "default"},
1206 "extra": {"branch": "default"},
1207 "modified": [],
1207 "modified": [],
1208 "added": ["a"],
1208 "added": ["a"],
1209 "removed": []
1209 "removed": []
1210 }
1210 }
1211 ]
1211 ]
1212
1212
1213 Error if style not readable:
1213 Error if style not readable:
1214
1214
1215 #if unix-permissions no-root
1215 #if unix-permissions no-root
1216 $ touch q
1216 $ touch q
1217 $ chmod 0 q
1217 $ chmod 0 q
1218 $ hg log --style ./q
1218 $ hg log --style ./q
1219 abort: Permission denied: ./q
1219 abort: Permission denied: ./q
1220 [255]
1220 [255]
1221 #endif
1221 #endif
1222
1222
1223 Error if no style:
1223 Error if no style:
1224
1224
1225 $ hg log --style notexist
1225 $ hg log --style notexist
1226 abort: style 'notexist' not found
1226 abort: style 'notexist' not found
1227 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1227 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1228 [255]
1228 [255]
1229
1229
1230 $ hg log -T list
1230 $ hg log -T list
1231 available styles: bisect, changelog, compact, default, phases, show, status, xml
1231 available styles: bisect, changelog, compact, default, phases, show, status, xml
1232 abort: specify a template
1232 abort: specify a template
1233 [255]
1233 [255]
1234
1234
1235 Error if style missing key:
1235 Error if style missing key:
1236
1236
1237 $ echo 'q = q' > t
1237 $ echo 'q = q' > t
1238 $ hg log --style ./t
1238 $ hg log --style ./t
1239 abort: "changeset" not in template map
1239 abort: "changeset" not in template map
1240 [255]
1240 [255]
1241
1241
1242 Error if style missing value:
1242 Error if style missing value:
1243
1243
1244 $ echo 'changeset =' > t
1244 $ echo 'changeset =' > t
1245 $ hg log --style t
1245 $ hg log --style t
1246 hg: parse error at t:1: missing value
1246 hg: parse error at t:1: missing value
1247 [255]
1247 [255]
1248
1248
1249 Error if include fails:
1249 Error if include fails:
1250
1250
1251 $ echo 'changeset = q' >> t
1251 $ echo 'changeset = q' >> t
1252 #if unix-permissions no-root
1252 #if unix-permissions no-root
1253 $ hg log --style ./t
1253 $ hg log --style ./t
1254 abort: template file ./q: Permission denied
1254 abort: template file ./q: Permission denied
1255 [255]
1255 [255]
1256 $ rm -f q
1256 $ rm -f q
1257 #endif
1257 #endif
1258
1258
1259 Include works:
1259 Include works:
1260
1260
1261 $ echo '{rev}' > q
1261 $ echo '{rev}' > q
1262 $ hg log --style ./t
1262 $ hg log --style ./t
1263 8
1263 8
1264 7
1264 7
1265 6
1265 6
1266 5
1266 5
1267 4
1267 4
1268 3
1268 3
1269 2
1269 2
1270 1
1270 1
1271 0
1271 0
1272
1272
1273 Check that recursive reference does not fall into RuntimeError (issue4758):
1273 Check that recursive reference does not fall into RuntimeError (issue4758):
1274
1274
1275 common mistake:
1275 common mistake:
1276
1276
1277 $ cat << EOF > issue4758
1277 $ cat << EOF > issue4758
1278 > changeset = '{changeset}\n'
1278 > changeset = '{changeset}\n'
1279 > EOF
1279 > EOF
1280 $ hg log --style ./issue4758
1280 $ hg log --style ./issue4758
1281 abort: recursive reference 'changeset' in template
1281 abort: recursive reference 'changeset' in template
1282 [255]
1282 [255]
1283
1283
1284 circular reference:
1284 circular reference:
1285
1285
1286 $ cat << EOF > issue4758
1286 $ cat << EOF > issue4758
1287 > changeset = '{foo}'
1287 > changeset = '{foo}'
1288 > foo = '{changeset}'
1288 > foo = '{changeset}'
1289 > EOF
1289 > EOF
1290 $ hg log --style ./issue4758
1290 $ hg log --style ./issue4758
1291 abort: recursive reference 'foo' in template
1291 abort: recursive reference 'foo' in template
1292 [255]
1292 [255]
1293
1293
1294 buildmap() -> gettemplate(), where no thunk was made:
1294 buildmap() -> gettemplate(), where no thunk was made:
1295
1295
1296 $ cat << EOF > issue4758
1296 $ cat << EOF > issue4758
1297 > changeset = '{files % changeset}\n'
1297 > changeset = '{files % changeset}\n'
1298 > EOF
1298 > EOF
1299 $ hg log --style ./issue4758
1299 $ hg log --style ./issue4758
1300 abort: recursive reference 'changeset' in template
1300 abort: recursive reference 'changeset' in template
1301 [255]
1301 [255]
1302
1302
1303 not a recursion if a keyword of the same name exists:
1303 not a recursion if a keyword of the same name exists:
1304
1304
1305 $ cat << EOF > issue4758
1305 $ cat << EOF > issue4758
1306 > changeset = '{tags % rev}'
1306 > changeset = '{tags % rev}'
1307 > rev = '{rev} {tag}\n'
1307 > rev = '{rev} {tag}\n'
1308 > EOF
1308 > EOF
1309 $ hg log --style ./issue4758 -r tip
1309 $ hg log --style ./issue4758 -r tip
1310 8 tip
1310 8 tip
1311
1311
1312 Check that {phase} works correctly on parents:
1312 Check that {phase} works correctly on parents:
1313
1313
1314 $ cat << EOF > parentphase
1314 $ cat << EOF > parentphase
1315 > changeset_debug = '{rev} ({phase}):{parents}\n'
1315 > changeset_debug = '{rev} ({phase}):{parents}\n'
1316 > parent = ' {rev} ({phase})'
1316 > parent = ' {rev} ({phase})'
1317 > EOF
1317 > EOF
1318 $ hg phase -r 5 --public
1318 $ hg phase -r 5 --public
1319 $ hg phase -r 7 --secret --force
1319 $ hg phase -r 7 --secret --force
1320 $ hg log --debug -G --style ./parentphase
1320 $ hg log --debug -G --style ./parentphase
1321 @ 8 (secret): 7 (secret) -1 (public)
1321 @ 8 (secret): 7 (secret) -1 (public)
1322 |
1322 |
1323 o 7 (secret): -1 (public) -1 (public)
1323 o 7 (secret): -1 (public) -1 (public)
1324
1324
1325 o 6 (draft): 5 (public) 4 (draft)
1325 o 6 (draft): 5 (public) 4 (draft)
1326 |\
1326 |\
1327 | o 5 (public): 3 (public) -1 (public)
1327 | o 5 (public): 3 (public) -1 (public)
1328 | |
1328 | |
1329 o | 4 (draft): 3 (public) -1 (public)
1329 o | 4 (draft): 3 (public) -1 (public)
1330 |/
1330 |/
1331 o 3 (public): 2 (public) -1 (public)
1331 o 3 (public): 2 (public) -1 (public)
1332 |
1332 |
1333 o 2 (public): 1 (public) -1 (public)
1333 o 2 (public): 1 (public) -1 (public)
1334 |
1334 |
1335 o 1 (public): 0 (public) -1 (public)
1335 o 1 (public): 0 (public) -1 (public)
1336 |
1336 |
1337 o 0 (public): -1 (public) -1 (public)
1337 o 0 (public): -1 (public) -1 (public)
1338
1338
1339
1339
1340 Missing non-standard names give no error (backward compatibility):
1340 Missing non-standard names give no error (backward compatibility):
1341
1341
1342 $ echo "changeset = '{c}'" > t
1342 $ echo "changeset = '{c}'" > t
1343 $ hg log --style ./t
1343 $ hg log --style ./t
1344
1344
1345 Defining non-standard name works:
1345 Defining non-standard name works:
1346
1346
1347 $ cat <<EOF > t
1347 $ cat <<EOF > t
1348 > changeset = '{c}'
1348 > changeset = '{c}'
1349 > c = q
1349 > c = q
1350 > EOF
1350 > EOF
1351 $ hg log --style ./t
1351 $ hg log --style ./t
1352 8
1352 8
1353 7
1353 7
1354 6
1354 6
1355 5
1355 5
1356 4
1356 4
1357 3
1357 3
1358 2
1358 2
1359 1
1359 1
1360 0
1360 0
1361
1361
1362 ui.style works:
1362 ui.style works:
1363
1363
1364 $ echo '[ui]' > .hg/hgrc
1364 $ echo '[ui]' > .hg/hgrc
1365 $ echo 'style = t' >> .hg/hgrc
1365 $ echo 'style = t' >> .hg/hgrc
1366 $ hg log
1366 $ hg log
1367 8
1367 8
1368 7
1368 7
1369 6
1369 6
1370 5
1370 5
1371 4
1371 4
1372 3
1372 3
1373 2
1373 2
1374 1
1374 1
1375 0
1375 0
1376
1376
1377
1377
1378 Issue338:
1378 Issue338:
1379
1379
1380 $ hg log --style=changelog > changelog
1380 $ hg log --style=changelog > changelog
1381
1381
1382 $ cat changelog
1382 $ cat changelog
1383 2020-01-01 test <test>
1383 2020-01-01 test <test>
1384
1384
1385 * fourth, second, third:
1385 * fourth, second, third:
1386 third
1386 third
1387 [95c24699272e] [tip]
1387 [95c24699272e] [tip]
1388
1388
1389 1970-01-12 User Name <user@hostname>
1389 1970-01-12 User Name <user@hostname>
1390
1390
1391 * second:
1391 * second:
1392 second
1392 second
1393 [29114dbae42b]
1393 [29114dbae42b]
1394
1394
1395 1970-01-18 person <person>
1395 1970-01-18 person <person>
1396
1396
1397 * merge
1397 * merge
1398 [d41e714fe50d]
1398 [d41e714fe50d]
1399
1399
1400 * d:
1400 * d:
1401 new head
1401 new head
1402 [13207e5a10d9]
1402 [13207e5a10d9]
1403
1403
1404 1970-01-17 person <person>
1404 1970-01-17 person <person>
1405
1405
1406 * new branch
1406 * new branch
1407 [bbe44766e73d] <foo>
1407 [bbe44766e73d] <foo>
1408
1408
1409 1970-01-16 person <person>
1409 1970-01-16 person <person>
1410
1410
1411 * c:
1411 * c:
1412 no user, no domain
1412 no user, no domain
1413 [10e46f2dcbf4]
1413 [10e46f2dcbf4]
1414
1414
1415 1970-01-14 other <other@place>
1415 1970-01-14 other <other@place>
1416
1416
1417 * c:
1417 * c:
1418 no person
1418 no person
1419 [97054abb4ab8]
1419 [97054abb4ab8]
1420
1420
1421 1970-01-13 A. N. Other <other@place>
1421 1970-01-13 A. N. Other <other@place>
1422
1422
1423 * b:
1423 * b:
1424 other 1 other 2
1424 other 1 other 2
1425
1425
1426 other 3
1426 other 3
1427 [b608e9d1a3f0]
1427 [b608e9d1a3f0]
1428
1428
1429 1970-01-12 User Name <user@hostname>
1429 1970-01-12 User Name <user@hostname>
1430
1430
1431 * a:
1431 * a:
1432 line 1 line 2
1432 line 1 line 2
1433 [1e4e1b8f71e0]
1433 [1e4e1b8f71e0]
1434
1434
1435
1435
1436 Issue2130: xml output for 'hg heads' is malformed
1436 Issue2130: xml output for 'hg heads' is malformed
1437
1437
1438 $ hg heads --style changelog
1438 $ hg heads --style changelog
1439 2020-01-01 test <test>
1439 2020-01-01 test <test>
1440
1440
1441 * fourth, second, third:
1441 * fourth, second, third:
1442 third
1442 third
1443 [95c24699272e] [tip]
1443 [95c24699272e] [tip]
1444
1444
1445 1970-01-18 person <person>
1445 1970-01-18 person <person>
1446
1446
1447 * merge
1447 * merge
1448 [d41e714fe50d]
1448 [d41e714fe50d]
1449
1449
1450 1970-01-17 person <person>
1450 1970-01-17 person <person>
1451
1451
1452 * new branch
1452 * new branch
1453 [bbe44766e73d] <foo>
1453 [bbe44766e73d] <foo>
1454
1454
1455
1455
1456 Keys work:
1456 Keys work:
1457
1457
1458 $ for key in author branch branches date desc file_adds file_dels file_mods \
1458 $ for key in author branch branches date desc file_adds file_dels file_mods \
1459 > file_copies file_copies_switch files \
1459 > file_copies file_copies_switch files \
1460 > manifest node parents rev tags diffstat extras \
1460 > manifest node parents rev tags diffstat extras \
1461 > p1rev p2rev p1node p2node; do
1461 > p1rev p2rev p1node p2node; do
1462 > for mode in '' --verbose --debug; do
1462 > for mode in '' --verbose --debug; do
1463 > hg log $mode --template "$key$mode: {$key}\n"
1463 > hg log $mode --template "$key$mode: {$key}\n"
1464 > done
1464 > done
1465 > done
1465 > done
1466 author: test
1466 author: test
1467 author: User Name <user@hostname>
1467 author: User Name <user@hostname>
1468 author: person
1468 author: person
1469 author: person
1469 author: person
1470 author: person
1470 author: person
1471 author: person
1471 author: person
1472 author: other@place
1472 author: other@place
1473 author: A. N. Other <other@place>
1473 author: A. N. Other <other@place>
1474 author: User Name <user@hostname>
1474 author: User Name <user@hostname>
1475 author--verbose: test
1475 author--verbose: test
1476 author--verbose: User Name <user@hostname>
1476 author--verbose: User Name <user@hostname>
1477 author--verbose: person
1477 author--verbose: person
1478 author--verbose: person
1478 author--verbose: person
1479 author--verbose: person
1479 author--verbose: person
1480 author--verbose: person
1480 author--verbose: person
1481 author--verbose: other@place
1481 author--verbose: other@place
1482 author--verbose: A. N. Other <other@place>
1482 author--verbose: A. N. Other <other@place>
1483 author--verbose: User Name <user@hostname>
1483 author--verbose: User Name <user@hostname>
1484 author--debug: test
1484 author--debug: test
1485 author--debug: User Name <user@hostname>
1485 author--debug: User Name <user@hostname>
1486 author--debug: person
1486 author--debug: person
1487 author--debug: person
1487 author--debug: person
1488 author--debug: person
1488 author--debug: person
1489 author--debug: person
1489 author--debug: person
1490 author--debug: other@place
1490 author--debug: other@place
1491 author--debug: A. N. Other <other@place>
1491 author--debug: A. N. Other <other@place>
1492 author--debug: User Name <user@hostname>
1492 author--debug: User Name <user@hostname>
1493 branch: default
1493 branch: default
1494 branch: default
1494 branch: default
1495 branch: default
1495 branch: default
1496 branch: default
1496 branch: default
1497 branch: foo
1497 branch: foo
1498 branch: default
1498 branch: default
1499 branch: default
1499 branch: default
1500 branch: default
1500 branch: default
1501 branch: default
1501 branch: default
1502 branch--verbose: default
1502 branch--verbose: default
1503 branch--verbose: default
1503 branch--verbose: default
1504 branch--verbose: default
1504 branch--verbose: default
1505 branch--verbose: default
1505 branch--verbose: default
1506 branch--verbose: foo
1506 branch--verbose: foo
1507 branch--verbose: default
1507 branch--verbose: default
1508 branch--verbose: default
1508 branch--verbose: default
1509 branch--verbose: default
1509 branch--verbose: default
1510 branch--verbose: default
1510 branch--verbose: default
1511 branch--debug: default
1511 branch--debug: default
1512 branch--debug: default
1512 branch--debug: default
1513 branch--debug: default
1513 branch--debug: default
1514 branch--debug: default
1514 branch--debug: default
1515 branch--debug: foo
1515 branch--debug: foo
1516 branch--debug: default
1516 branch--debug: default
1517 branch--debug: default
1517 branch--debug: default
1518 branch--debug: default
1518 branch--debug: default
1519 branch--debug: default
1519 branch--debug: default
1520 branches:
1520 branches:
1521 branches:
1521 branches:
1522 branches:
1522 branches:
1523 branches:
1523 branches:
1524 branches: foo
1524 branches: foo
1525 branches:
1525 branches:
1526 branches:
1526 branches:
1527 branches:
1527 branches:
1528 branches:
1528 branches:
1529 branches--verbose:
1529 branches--verbose:
1530 branches--verbose:
1530 branches--verbose:
1531 branches--verbose:
1531 branches--verbose:
1532 branches--verbose:
1532 branches--verbose:
1533 branches--verbose: foo
1533 branches--verbose: foo
1534 branches--verbose:
1534 branches--verbose:
1535 branches--verbose:
1535 branches--verbose:
1536 branches--verbose:
1536 branches--verbose:
1537 branches--verbose:
1537 branches--verbose:
1538 branches--debug:
1538 branches--debug:
1539 branches--debug:
1539 branches--debug:
1540 branches--debug:
1540 branches--debug:
1541 branches--debug:
1541 branches--debug:
1542 branches--debug: foo
1542 branches--debug: foo
1543 branches--debug:
1543 branches--debug:
1544 branches--debug:
1544 branches--debug:
1545 branches--debug:
1545 branches--debug:
1546 branches--debug:
1546 branches--debug:
1547 date: 1577872860.00
1547 date: 1577872860.00
1548 date: 1000000.00
1548 date: 1000000.00
1549 date: 1500001.00
1549 date: 1500001.00
1550 date: 1500000.00
1550 date: 1500000.00
1551 date: 1400000.00
1551 date: 1400000.00
1552 date: 1300000.00
1552 date: 1300000.00
1553 date: 1200000.00
1553 date: 1200000.00
1554 date: 1100000.00
1554 date: 1100000.00
1555 date: 1000000.00
1555 date: 1000000.00
1556 date--verbose: 1577872860.00
1556 date--verbose: 1577872860.00
1557 date--verbose: 1000000.00
1557 date--verbose: 1000000.00
1558 date--verbose: 1500001.00
1558 date--verbose: 1500001.00
1559 date--verbose: 1500000.00
1559 date--verbose: 1500000.00
1560 date--verbose: 1400000.00
1560 date--verbose: 1400000.00
1561 date--verbose: 1300000.00
1561 date--verbose: 1300000.00
1562 date--verbose: 1200000.00
1562 date--verbose: 1200000.00
1563 date--verbose: 1100000.00
1563 date--verbose: 1100000.00
1564 date--verbose: 1000000.00
1564 date--verbose: 1000000.00
1565 date--debug: 1577872860.00
1565 date--debug: 1577872860.00
1566 date--debug: 1000000.00
1566 date--debug: 1000000.00
1567 date--debug: 1500001.00
1567 date--debug: 1500001.00
1568 date--debug: 1500000.00
1568 date--debug: 1500000.00
1569 date--debug: 1400000.00
1569 date--debug: 1400000.00
1570 date--debug: 1300000.00
1570 date--debug: 1300000.00
1571 date--debug: 1200000.00
1571 date--debug: 1200000.00
1572 date--debug: 1100000.00
1572 date--debug: 1100000.00
1573 date--debug: 1000000.00
1573 date--debug: 1000000.00
1574 desc: third
1574 desc: third
1575 desc: second
1575 desc: second
1576 desc: merge
1576 desc: merge
1577 desc: new head
1577 desc: new head
1578 desc: new branch
1578 desc: new branch
1579 desc: no user, no domain
1579 desc: no user, no domain
1580 desc: no person
1580 desc: no person
1581 desc: other 1
1581 desc: other 1
1582 other 2
1582 other 2
1583
1583
1584 other 3
1584 other 3
1585 desc: line 1
1585 desc: line 1
1586 line 2
1586 line 2
1587 desc--verbose: third
1587 desc--verbose: third
1588 desc--verbose: second
1588 desc--verbose: second
1589 desc--verbose: merge
1589 desc--verbose: merge
1590 desc--verbose: new head
1590 desc--verbose: new head
1591 desc--verbose: new branch
1591 desc--verbose: new branch
1592 desc--verbose: no user, no domain
1592 desc--verbose: no user, no domain
1593 desc--verbose: no person
1593 desc--verbose: no person
1594 desc--verbose: other 1
1594 desc--verbose: other 1
1595 other 2
1595 other 2
1596
1596
1597 other 3
1597 other 3
1598 desc--verbose: line 1
1598 desc--verbose: line 1
1599 line 2
1599 line 2
1600 desc--debug: third
1600 desc--debug: third
1601 desc--debug: second
1601 desc--debug: second
1602 desc--debug: merge
1602 desc--debug: merge
1603 desc--debug: new head
1603 desc--debug: new head
1604 desc--debug: new branch
1604 desc--debug: new branch
1605 desc--debug: no user, no domain
1605 desc--debug: no user, no domain
1606 desc--debug: no person
1606 desc--debug: no person
1607 desc--debug: other 1
1607 desc--debug: other 1
1608 other 2
1608 other 2
1609
1609
1610 other 3
1610 other 3
1611 desc--debug: line 1
1611 desc--debug: line 1
1612 line 2
1612 line 2
1613 file_adds: fourth third
1613 file_adds: fourth third
1614 file_adds: second
1614 file_adds: second
1615 file_adds:
1615 file_adds:
1616 file_adds: d
1616 file_adds: d
1617 file_adds:
1617 file_adds:
1618 file_adds:
1618 file_adds:
1619 file_adds: c
1619 file_adds: c
1620 file_adds: b
1620 file_adds: b
1621 file_adds: a
1621 file_adds: a
1622 file_adds--verbose: fourth third
1622 file_adds--verbose: fourth third
1623 file_adds--verbose: second
1623 file_adds--verbose: second
1624 file_adds--verbose:
1624 file_adds--verbose:
1625 file_adds--verbose: d
1625 file_adds--verbose: d
1626 file_adds--verbose:
1626 file_adds--verbose:
1627 file_adds--verbose:
1627 file_adds--verbose:
1628 file_adds--verbose: c
1628 file_adds--verbose: c
1629 file_adds--verbose: b
1629 file_adds--verbose: b
1630 file_adds--verbose: a
1630 file_adds--verbose: a
1631 file_adds--debug: fourth third
1631 file_adds--debug: fourth third
1632 file_adds--debug: second
1632 file_adds--debug: second
1633 file_adds--debug:
1633 file_adds--debug:
1634 file_adds--debug: d
1634 file_adds--debug: d
1635 file_adds--debug:
1635 file_adds--debug:
1636 file_adds--debug:
1636 file_adds--debug:
1637 file_adds--debug: c
1637 file_adds--debug: c
1638 file_adds--debug: b
1638 file_adds--debug: b
1639 file_adds--debug: a
1639 file_adds--debug: a
1640 file_dels: second
1640 file_dels: second
1641 file_dels:
1641 file_dels:
1642 file_dels:
1642 file_dels:
1643 file_dels:
1643 file_dels:
1644 file_dels:
1644 file_dels:
1645 file_dels:
1645 file_dels:
1646 file_dels:
1646 file_dels:
1647 file_dels:
1647 file_dels:
1648 file_dels:
1648 file_dels:
1649 file_dels--verbose: second
1649 file_dels--verbose: second
1650 file_dels--verbose:
1650 file_dels--verbose:
1651 file_dels--verbose:
1651 file_dels--verbose:
1652 file_dels--verbose:
1652 file_dels--verbose:
1653 file_dels--verbose:
1653 file_dels--verbose:
1654 file_dels--verbose:
1654 file_dels--verbose:
1655 file_dels--verbose:
1655 file_dels--verbose:
1656 file_dels--verbose:
1656 file_dels--verbose:
1657 file_dels--verbose:
1657 file_dels--verbose:
1658 file_dels--debug: second
1658 file_dels--debug: second
1659 file_dels--debug:
1659 file_dels--debug:
1660 file_dels--debug:
1660 file_dels--debug:
1661 file_dels--debug:
1661 file_dels--debug:
1662 file_dels--debug:
1662 file_dels--debug:
1663 file_dels--debug:
1663 file_dels--debug:
1664 file_dels--debug:
1664 file_dels--debug:
1665 file_dels--debug:
1665 file_dels--debug:
1666 file_dels--debug:
1666 file_dels--debug:
1667 file_mods:
1667 file_mods:
1668 file_mods:
1668 file_mods:
1669 file_mods:
1669 file_mods:
1670 file_mods:
1670 file_mods:
1671 file_mods:
1671 file_mods:
1672 file_mods: c
1672 file_mods: c
1673 file_mods:
1673 file_mods:
1674 file_mods:
1674 file_mods:
1675 file_mods:
1675 file_mods:
1676 file_mods--verbose:
1676 file_mods--verbose:
1677 file_mods--verbose:
1677 file_mods--verbose:
1678 file_mods--verbose:
1678 file_mods--verbose:
1679 file_mods--verbose:
1679 file_mods--verbose:
1680 file_mods--verbose:
1680 file_mods--verbose:
1681 file_mods--verbose: c
1681 file_mods--verbose: c
1682 file_mods--verbose:
1682 file_mods--verbose:
1683 file_mods--verbose:
1683 file_mods--verbose:
1684 file_mods--verbose:
1684 file_mods--verbose:
1685 file_mods--debug:
1685 file_mods--debug:
1686 file_mods--debug:
1686 file_mods--debug:
1687 file_mods--debug:
1687 file_mods--debug:
1688 file_mods--debug:
1688 file_mods--debug:
1689 file_mods--debug:
1689 file_mods--debug:
1690 file_mods--debug: c
1690 file_mods--debug: c
1691 file_mods--debug:
1691 file_mods--debug:
1692 file_mods--debug:
1692 file_mods--debug:
1693 file_mods--debug:
1693 file_mods--debug:
1694 file_copies: fourth (second)
1694 file_copies: fourth (second)
1695 file_copies:
1695 file_copies:
1696 file_copies:
1696 file_copies:
1697 file_copies:
1697 file_copies:
1698 file_copies:
1698 file_copies:
1699 file_copies:
1699 file_copies:
1700 file_copies:
1700 file_copies:
1701 file_copies:
1701 file_copies:
1702 file_copies:
1702 file_copies:
1703 file_copies--verbose: fourth (second)
1703 file_copies--verbose: fourth (second)
1704 file_copies--verbose:
1704 file_copies--verbose:
1705 file_copies--verbose:
1705 file_copies--verbose:
1706 file_copies--verbose:
1706 file_copies--verbose:
1707 file_copies--verbose:
1707 file_copies--verbose:
1708 file_copies--verbose:
1708 file_copies--verbose:
1709 file_copies--verbose:
1709 file_copies--verbose:
1710 file_copies--verbose:
1710 file_copies--verbose:
1711 file_copies--verbose:
1711 file_copies--verbose:
1712 file_copies--debug: fourth (second)
1712 file_copies--debug: fourth (second)
1713 file_copies--debug:
1713 file_copies--debug:
1714 file_copies--debug:
1714 file_copies--debug:
1715 file_copies--debug:
1715 file_copies--debug:
1716 file_copies--debug:
1716 file_copies--debug:
1717 file_copies--debug:
1717 file_copies--debug:
1718 file_copies--debug:
1718 file_copies--debug:
1719 file_copies--debug:
1719 file_copies--debug:
1720 file_copies--debug:
1720 file_copies--debug:
1721 file_copies_switch:
1721 file_copies_switch:
1722 file_copies_switch:
1722 file_copies_switch:
1723 file_copies_switch:
1723 file_copies_switch:
1724 file_copies_switch:
1724 file_copies_switch:
1725 file_copies_switch:
1725 file_copies_switch:
1726 file_copies_switch:
1726 file_copies_switch:
1727 file_copies_switch:
1727 file_copies_switch:
1728 file_copies_switch:
1728 file_copies_switch:
1729 file_copies_switch:
1729 file_copies_switch:
1730 file_copies_switch--verbose:
1730 file_copies_switch--verbose:
1731 file_copies_switch--verbose:
1731 file_copies_switch--verbose:
1732 file_copies_switch--verbose:
1732 file_copies_switch--verbose:
1733 file_copies_switch--verbose:
1733 file_copies_switch--verbose:
1734 file_copies_switch--verbose:
1734 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1739 file_copies_switch--debug:
1739 file_copies_switch--debug:
1740 file_copies_switch--debug:
1740 file_copies_switch--debug:
1741 file_copies_switch--debug:
1741 file_copies_switch--debug:
1742 file_copies_switch--debug:
1742 file_copies_switch--debug:
1743 file_copies_switch--debug:
1743 file_copies_switch--debug:
1744 file_copies_switch--debug:
1744 file_copies_switch--debug:
1745 file_copies_switch--debug:
1745 file_copies_switch--debug:
1746 file_copies_switch--debug:
1746 file_copies_switch--debug:
1747 file_copies_switch--debug:
1747 file_copies_switch--debug:
1748 files: fourth second third
1748 files: fourth second third
1749 files: second
1749 files: second
1750 files:
1750 files:
1751 files: d
1751 files: d
1752 files:
1752 files:
1753 files: c
1753 files: c
1754 files: c
1754 files: c
1755 files: b
1755 files: b
1756 files: a
1756 files: a
1757 files--verbose: fourth second third
1757 files--verbose: fourth second third
1758 files--verbose: second
1758 files--verbose: second
1759 files--verbose:
1759 files--verbose:
1760 files--verbose: d
1760 files--verbose: d
1761 files--verbose:
1761 files--verbose:
1762 files--verbose: c
1762 files--verbose: c
1763 files--verbose: c
1763 files--verbose: c
1764 files--verbose: b
1764 files--verbose: b
1765 files--verbose: a
1765 files--verbose: a
1766 files--debug: fourth second third
1766 files--debug: fourth second third
1767 files--debug: second
1767 files--debug: second
1768 files--debug:
1768 files--debug:
1769 files--debug: d
1769 files--debug: d
1770 files--debug:
1770 files--debug:
1771 files--debug: c
1771 files--debug: c
1772 files--debug: c
1772 files--debug: c
1773 files--debug: b
1773 files--debug: b
1774 files--debug: a
1774 files--debug: a
1775 manifest: 6:94961b75a2da
1775 manifest: 6:94961b75a2da
1776 manifest: 5:f2dbc354b94e
1776 manifest: 5:f2dbc354b94e
1777 manifest: 4:4dc3def4f9b4
1777 manifest: 4:4dc3def4f9b4
1778 manifest: 4:4dc3def4f9b4
1778 manifest: 4:4dc3def4f9b4
1779 manifest: 3:cb5a1327723b
1779 manifest: 3:cb5a1327723b
1780 manifest: 3:cb5a1327723b
1780 manifest: 3:cb5a1327723b
1781 manifest: 2:6e0e82995c35
1781 manifest: 2:6e0e82995c35
1782 manifest: 1:4e8d705b1e53
1782 manifest: 1:4e8d705b1e53
1783 manifest: 0:a0c8bcbbb45c
1783 manifest: 0:a0c8bcbbb45c
1784 manifest--verbose: 6:94961b75a2da
1784 manifest--verbose: 6:94961b75a2da
1785 manifest--verbose: 5:f2dbc354b94e
1785 manifest--verbose: 5:f2dbc354b94e
1786 manifest--verbose: 4:4dc3def4f9b4
1786 manifest--verbose: 4:4dc3def4f9b4
1787 manifest--verbose: 4:4dc3def4f9b4
1787 manifest--verbose: 4:4dc3def4f9b4
1788 manifest--verbose: 3:cb5a1327723b
1788 manifest--verbose: 3:cb5a1327723b
1789 manifest--verbose: 3:cb5a1327723b
1789 manifest--verbose: 3:cb5a1327723b
1790 manifest--verbose: 2:6e0e82995c35
1790 manifest--verbose: 2:6e0e82995c35
1791 manifest--verbose: 1:4e8d705b1e53
1791 manifest--verbose: 1:4e8d705b1e53
1792 manifest--verbose: 0:a0c8bcbbb45c
1792 manifest--verbose: 0:a0c8bcbbb45c
1793 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1793 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1794 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1794 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1795 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1795 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1796 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1796 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1797 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1797 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1798 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1798 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1799 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1799 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1800 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1800 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1801 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1801 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1802 node: 95c24699272ef57d062b8bccc32c878bf841784a
1802 node: 95c24699272ef57d062b8bccc32c878bf841784a
1803 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1803 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1804 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1804 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1805 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1805 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1806 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1806 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1807 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1807 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1808 node: 97054abb4ab824450e9164180baf491ae0078465
1808 node: 97054abb4ab824450e9164180baf491ae0078465
1809 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1809 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1810 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1810 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1811 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1811 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1812 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1812 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1813 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1813 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1814 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1814 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1815 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1815 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1816 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1816 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1817 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1817 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1818 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1818 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1819 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1819 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1820 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1820 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1821 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1821 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1822 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1822 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1823 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1823 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1824 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1824 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1825 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1825 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1826 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1826 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1827 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1827 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1828 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1828 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1829 parents:
1829 parents:
1830 parents: -1:000000000000
1830 parents: -1:000000000000
1831 parents: 5:13207e5a10d9 4:bbe44766e73d
1831 parents: 5:13207e5a10d9 4:bbe44766e73d
1832 parents: 3:10e46f2dcbf4
1832 parents: 3:10e46f2dcbf4
1833 parents:
1833 parents:
1834 parents:
1834 parents:
1835 parents:
1835 parents:
1836 parents:
1836 parents:
1837 parents:
1837 parents:
1838 parents--verbose:
1838 parents--verbose:
1839 parents--verbose: -1:000000000000
1839 parents--verbose: -1:000000000000
1840 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1840 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1841 parents--verbose: 3:10e46f2dcbf4
1841 parents--verbose: 3:10e46f2dcbf4
1842 parents--verbose:
1842 parents--verbose:
1843 parents--verbose:
1843 parents--verbose:
1844 parents--verbose:
1844 parents--verbose:
1845 parents--verbose:
1845 parents--verbose:
1846 parents--verbose:
1846 parents--verbose:
1847 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1847 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1848 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1848 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1849 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1849 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1850 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1850 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1851 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1851 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1852 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1852 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1853 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1853 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1854 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1854 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1855 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1855 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1856 rev: 8
1856 rev: 8
1857 rev: 7
1857 rev: 7
1858 rev: 6
1858 rev: 6
1859 rev: 5
1859 rev: 5
1860 rev: 4
1860 rev: 4
1861 rev: 3
1861 rev: 3
1862 rev: 2
1862 rev: 2
1863 rev: 1
1863 rev: 1
1864 rev: 0
1864 rev: 0
1865 rev--verbose: 8
1865 rev--verbose: 8
1866 rev--verbose: 7
1866 rev--verbose: 7
1867 rev--verbose: 6
1867 rev--verbose: 6
1868 rev--verbose: 5
1868 rev--verbose: 5
1869 rev--verbose: 4
1869 rev--verbose: 4
1870 rev--verbose: 3
1870 rev--verbose: 3
1871 rev--verbose: 2
1871 rev--verbose: 2
1872 rev--verbose: 1
1872 rev--verbose: 1
1873 rev--verbose: 0
1873 rev--verbose: 0
1874 rev--debug: 8
1874 rev--debug: 8
1875 rev--debug: 7
1875 rev--debug: 7
1876 rev--debug: 6
1876 rev--debug: 6
1877 rev--debug: 5
1877 rev--debug: 5
1878 rev--debug: 4
1878 rev--debug: 4
1879 rev--debug: 3
1879 rev--debug: 3
1880 rev--debug: 2
1880 rev--debug: 2
1881 rev--debug: 1
1881 rev--debug: 1
1882 rev--debug: 0
1882 rev--debug: 0
1883 tags: tip
1883 tags: tip
1884 tags:
1884 tags:
1885 tags:
1885 tags:
1886 tags:
1886 tags:
1887 tags:
1887 tags:
1888 tags:
1888 tags:
1889 tags:
1889 tags:
1890 tags:
1890 tags:
1891 tags:
1891 tags:
1892 tags--verbose: tip
1892 tags--verbose: tip
1893 tags--verbose:
1893 tags--verbose:
1894 tags--verbose:
1894 tags--verbose:
1895 tags--verbose:
1895 tags--verbose:
1896 tags--verbose:
1896 tags--verbose:
1897 tags--verbose:
1897 tags--verbose:
1898 tags--verbose:
1898 tags--verbose:
1899 tags--verbose:
1899 tags--verbose:
1900 tags--verbose:
1900 tags--verbose:
1901 tags--debug: tip
1901 tags--debug: tip
1902 tags--debug:
1902 tags--debug:
1903 tags--debug:
1903 tags--debug:
1904 tags--debug:
1904 tags--debug:
1905 tags--debug:
1905 tags--debug:
1906 tags--debug:
1906 tags--debug:
1907 tags--debug:
1907 tags--debug:
1908 tags--debug:
1908 tags--debug:
1909 tags--debug:
1909 tags--debug:
1910 diffstat: 3: +2/-1
1910 diffstat: 3: +2/-1
1911 diffstat: 1: +1/-0
1911 diffstat: 1: +1/-0
1912 diffstat: 0: +0/-0
1912 diffstat: 0: +0/-0
1913 diffstat: 1: +1/-0
1913 diffstat: 1: +1/-0
1914 diffstat: 0: +0/-0
1914 diffstat: 0: +0/-0
1915 diffstat: 1: +1/-0
1915 diffstat: 1: +1/-0
1916 diffstat: 1: +4/-0
1916 diffstat: 1: +4/-0
1917 diffstat: 1: +2/-0
1917 diffstat: 1: +2/-0
1918 diffstat: 1: +1/-0
1918 diffstat: 1: +1/-0
1919 diffstat--verbose: 3: +2/-1
1919 diffstat--verbose: 3: +2/-1
1920 diffstat--verbose: 1: +1/-0
1920 diffstat--verbose: 1: +1/-0
1921 diffstat--verbose: 0: +0/-0
1921 diffstat--verbose: 0: +0/-0
1922 diffstat--verbose: 1: +1/-0
1922 diffstat--verbose: 1: +1/-0
1923 diffstat--verbose: 0: +0/-0
1923 diffstat--verbose: 0: +0/-0
1924 diffstat--verbose: 1: +1/-0
1924 diffstat--verbose: 1: +1/-0
1925 diffstat--verbose: 1: +4/-0
1925 diffstat--verbose: 1: +4/-0
1926 diffstat--verbose: 1: +2/-0
1926 diffstat--verbose: 1: +2/-0
1927 diffstat--verbose: 1: +1/-0
1927 diffstat--verbose: 1: +1/-0
1928 diffstat--debug: 3: +2/-1
1928 diffstat--debug: 3: +2/-1
1929 diffstat--debug: 1: +1/-0
1929 diffstat--debug: 1: +1/-0
1930 diffstat--debug: 0: +0/-0
1930 diffstat--debug: 0: +0/-0
1931 diffstat--debug: 1: +1/-0
1931 diffstat--debug: 1: +1/-0
1932 diffstat--debug: 0: +0/-0
1932 diffstat--debug: 0: +0/-0
1933 diffstat--debug: 1: +1/-0
1933 diffstat--debug: 1: +1/-0
1934 diffstat--debug: 1: +4/-0
1934 diffstat--debug: 1: +4/-0
1935 diffstat--debug: 1: +2/-0
1935 diffstat--debug: 1: +2/-0
1936 diffstat--debug: 1: +1/-0
1936 diffstat--debug: 1: +1/-0
1937 extras: branch=default
1937 extras: branch=default
1938 extras: branch=default
1938 extras: branch=default
1939 extras: branch=default
1939 extras: branch=default
1940 extras: branch=default
1940 extras: branch=default
1941 extras: branch=foo
1941 extras: branch=foo
1942 extras: branch=default
1942 extras: branch=default
1943 extras: branch=default
1943 extras: branch=default
1944 extras: branch=default
1944 extras: branch=default
1945 extras: branch=default
1945 extras: branch=default
1946 extras--verbose: branch=default
1946 extras--verbose: branch=default
1947 extras--verbose: branch=default
1947 extras--verbose: branch=default
1948 extras--verbose: branch=default
1948 extras--verbose: branch=default
1949 extras--verbose: branch=default
1949 extras--verbose: branch=default
1950 extras--verbose: branch=foo
1950 extras--verbose: branch=foo
1951 extras--verbose: branch=default
1951 extras--verbose: branch=default
1952 extras--verbose: branch=default
1952 extras--verbose: branch=default
1953 extras--verbose: branch=default
1953 extras--verbose: branch=default
1954 extras--verbose: branch=default
1954 extras--verbose: branch=default
1955 extras--debug: branch=default
1955 extras--debug: branch=default
1956 extras--debug: branch=default
1956 extras--debug: branch=default
1957 extras--debug: branch=default
1957 extras--debug: branch=default
1958 extras--debug: branch=default
1958 extras--debug: branch=default
1959 extras--debug: branch=foo
1959 extras--debug: branch=foo
1960 extras--debug: branch=default
1960 extras--debug: branch=default
1961 extras--debug: branch=default
1961 extras--debug: branch=default
1962 extras--debug: branch=default
1962 extras--debug: branch=default
1963 extras--debug: branch=default
1963 extras--debug: branch=default
1964 p1rev: 7
1964 p1rev: 7
1965 p1rev: -1
1965 p1rev: -1
1966 p1rev: 5
1966 p1rev: 5
1967 p1rev: 3
1967 p1rev: 3
1968 p1rev: 3
1968 p1rev: 3
1969 p1rev: 2
1969 p1rev: 2
1970 p1rev: 1
1970 p1rev: 1
1971 p1rev: 0
1971 p1rev: 0
1972 p1rev: -1
1972 p1rev: -1
1973 p1rev--verbose: 7
1973 p1rev--verbose: 7
1974 p1rev--verbose: -1
1974 p1rev--verbose: -1
1975 p1rev--verbose: 5
1975 p1rev--verbose: 5
1976 p1rev--verbose: 3
1976 p1rev--verbose: 3
1977 p1rev--verbose: 3
1977 p1rev--verbose: 3
1978 p1rev--verbose: 2
1978 p1rev--verbose: 2
1979 p1rev--verbose: 1
1979 p1rev--verbose: 1
1980 p1rev--verbose: 0
1980 p1rev--verbose: 0
1981 p1rev--verbose: -1
1981 p1rev--verbose: -1
1982 p1rev--debug: 7
1982 p1rev--debug: 7
1983 p1rev--debug: -1
1983 p1rev--debug: -1
1984 p1rev--debug: 5
1984 p1rev--debug: 5
1985 p1rev--debug: 3
1985 p1rev--debug: 3
1986 p1rev--debug: 3
1986 p1rev--debug: 3
1987 p1rev--debug: 2
1987 p1rev--debug: 2
1988 p1rev--debug: 1
1988 p1rev--debug: 1
1989 p1rev--debug: 0
1989 p1rev--debug: 0
1990 p1rev--debug: -1
1990 p1rev--debug: -1
1991 p2rev: -1
1991 p2rev: -1
1992 p2rev: -1
1992 p2rev: -1
1993 p2rev: 4
1993 p2rev: 4
1994 p2rev: -1
1994 p2rev: -1
1995 p2rev: -1
1995 p2rev: -1
1996 p2rev: -1
1996 p2rev: -1
1997 p2rev: -1
1997 p2rev: -1
1998 p2rev: -1
1998 p2rev: -1
1999 p2rev: -1
1999 p2rev: -1
2000 p2rev--verbose: -1
2000 p2rev--verbose: -1
2001 p2rev--verbose: -1
2001 p2rev--verbose: -1
2002 p2rev--verbose: 4
2002 p2rev--verbose: 4
2003 p2rev--verbose: -1
2003 p2rev--verbose: -1
2004 p2rev--verbose: -1
2004 p2rev--verbose: -1
2005 p2rev--verbose: -1
2005 p2rev--verbose: -1
2006 p2rev--verbose: -1
2006 p2rev--verbose: -1
2007 p2rev--verbose: -1
2007 p2rev--verbose: -1
2008 p2rev--verbose: -1
2008 p2rev--verbose: -1
2009 p2rev--debug: -1
2009 p2rev--debug: -1
2010 p2rev--debug: -1
2010 p2rev--debug: -1
2011 p2rev--debug: 4
2011 p2rev--debug: 4
2012 p2rev--debug: -1
2012 p2rev--debug: -1
2013 p2rev--debug: -1
2013 p2rev--debug: -1
2014 p2rev--debug: -1
2014 p2rev--debug: -1
2015 p2rev--debug: -1
2015 p2rev--debug: -1
2016 p2rev--debug: -1
2016 p2rev--debug: -1
2017 p2rev--debug: -1
2017 p2rev--debug: -1
2018 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2018 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2019 p1node: 0000000000000000000000000000000000000000
2019 p1node: 0000000000000000000000000000000000000000
2020 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2020 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2021 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2021 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2022 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2022 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2023 p1node: 97054abb4ab824450e9164180baf491ae0078465
2023 p1node: 97054abb4ab824450e9164180baf491ae0078465
2024 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2024 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2025 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2025 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2026 p1node: 0000000000000000000000000000000000000000
2026 p1node: 0000000000000000000000000000000000000000
2027 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2027 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2028 p1node--verbose: 0000000000000000000000000000000000000000
2028 p1node--verbose: 0000000000000000000000000000000000000000
2029 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2029 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2030 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2030 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2031 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2031 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2032 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2032 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2033 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2033 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2034 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2034 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2035 p1node--verbose: 0000000000000000000000000000000000000000
2035 p1node--verbose: 0000000000000000000000000000000000000000
2036 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2036 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2037 p1node--debug: 0000000000000000000000000000000000000000
2037 p1node--debug: 0000000000000000000000000000000000000000
2038 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2038 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2039 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2039 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2040 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2040 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2041 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2041 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2042 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2042 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2043 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2043 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2044 p1node--debug: 0000000000000000000000000000000000000000
2044 p1node--debug: 0000000000000000000000000000000000000000
2045 p2node: 0000000000000000000000000000000000000000
2045 p2node: 0000000000000000000000000000000000000000
2046 p2node: 0000000000000000000000000000000000000000
2046 p2node: 0000000000000000000000000000000000000000
2047 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2047 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2048 p2node: 0000000000000000000000000000000000000000
2048 p2node: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2050 p2node: 0000000000000000000000000000000000000000
2050 p2node: 0000000000000000000000000000000000000000
2051 p2node: 0000000000000000000000000000000000000000
2051 p2node: 0000000000000000000000000000000000000000
2052 p2node: 0000000000000000000000000000000000000000
2052 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2054 p2node--verbose: 0000000000000000000000000000000000000000
2054 p2node--verbose: 0000000000000000000000000000000000000000
2055 p2node--verbose: 0000000000000000000000000000000000000000
2055 p2node--verbose: 0000000000000000000000000000000000000000
2056 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2056 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2057 p2node--verbose: 0000000000000000000000000000000000000000
2057 p2node--verbose: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: 0000000000000000000000000000000000000000
2060 p2node--verbose: 0000000000000000000000000000000000000000
2060 p2node--verbose: 0000000000000000000000000000000000000000
2061 p2node--verbose: 0000000000000000000000000000000000000000
2061 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--debug: 0000000000000000000000000000000000000000
2063 p2node--debug: 0000000000000000000000000000000000000000
2064 p2node--debug: 0000000000000000000000000000000000000000
2064 p2node--debug: 0000000000000000000000000000000000000000
2065 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2065 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2066 p2node--debug: 0000000000000000000000000000000000000000
2066 p2node--debug: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: 0000000000000000000000000000000000000000
2069 p2node--debug: 0000000000000000000000000000000000000000
2069 p2node--debug: 0000000000000000000000000000000000000000
2070 p2node--debug: 0000000000000000000000000000000000000000
2070 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2072
2072
2073 Filters work:
2073 Filters work:
2074
2074
2075 $ hg log --template '{author|domain}\n'
2075 $ hg log --template '{author|domain}\n'
2076
2076
2077 hostname
2077 hostname
2078
2078
2079
2079
2080
2080
2081
2081
2082 place
2082 place
2083 place
2083 place
2084 hostname
2084 hostname
2085
2085
2086 $ hg log --template '{author|person}\n'
2086 $ hg log --template '{author|person}\n'
2087 test
2087 test
2088 User Name
2088 User Name
2089 person
2089 person
2090 person
2090 person
2091 person
2091 person
2092 person
2092 person
2093 other
2093 other
2094 A. N. Other
2094 A. N. Other
2095 User Name
2095 User Name
2096
2096
2097 $ hg log --template '{author|user}\n'
2097 $ hg log --template '{author|user}\n'
2098 test
2098 test
2099 user
2099 user
2100 person
2100 person
2101 person
2101 person
2102 person
2102 person
2103 person
2103 person
2104 other
2104 other
2105 other
2105 other
2106 user
2106 user
2107
2107
2108 $ hg log --template '{date|date}\n'
2108 $ hg log --template '{date|date}\n'
2109 Wed Jan 01 10:01:00 2020 +0000
2109 Wed Jan 01 10:01:00 2020 +0000
2110 Mon Jan 12 13:46:40 1970 +0000
2110 Mon Jan 12 13:46:40 1970 +0000
2111 Sun Jan 18 08:40:01 1970 +0000
2111 Sun Jan 18 08:40:01 1970 +0000
2112 Sun Jan 18 08:40:00 1970 +0000
2112 Sun Jan 18 08:40:00 1970 +0000
2113 Sat Jan 17 04:53:20 1970 +0000
2113 Sat Jan 17 04:53:20 1970 +0000
2114 Fri Jan 16 01:06:40 1970 +0000
2114 Fri Jan 16 01:06:40 1970 +0000
2115 Wed Jan 14 21:20:00 1970 +0000
2115 Wed Jan 14 21:20:00 1970 +0000
2116 Tue Jan 13 17:33:20 1970 +0000
2116 Tue Jan 13 17:33:20 1970 +0000
2117 Mon Jan 12 13:46:40 1970 +0000
2117 Mon Jan 12 13:46:40 1970 +0000
2118
2118
2119 $ hg log --template '{date|isodate}\n'
2119 $ hg log --template '{date|isodate}\n'
2120 2020-01-01 10:01 +0000
2120 2020-01-01 10:01 +0000
2121 1970-01-12 13:46 +0000
2121 1970-01-12 13:46 +0000
2122 1970-01-18 08:40 +0000
2122 1970-01-18 08:40 +0000
2123 1970-01-18 08:40 +0000
2123 1970-01-18 08:40 +0000
2124 1970-01-17 04:53 +0000
2124 1970-01-17 04:53 +0000
2125 1970-01-16 01:06 +0000
2125 1970-01-16 01:06 +0000
2126 1970-01-14 21:20 +0000
2126 1970-01-14 21:20 +0000
2127 1970-01-13 17:33 +0000
2127 1970-01-13 17:33 +0000
2128 1970-01-12 13:46 +0000
2128 1970-01-12 13:46 +0000
2129
2129
2130 $ hg log --template '{date|isodatesec}\n'
2130 $ hg log --template '{date|isodatesec}\n'
2131 2020-01-01 10:01:00 +0000
2131 2020-01-01 10:01:00 +0000
2132 1970-01-12 13:46:40 +0000
2132 1970-01-12 13:46:40 +0000
2133 1970-01-18 08:40:01 +0000
2133 1970-01-18 08:40:01 +0000
2134 1970-01-18 08:40:00 +0000
2134 1970-01-18 08:40:00 +0000
2135 1970-01-17 04:53:20 +0000
2135 1970-01-17 04:53:20 +0000
2136 1970-01-16 01:06:40 +0000
2136 1970-01-16 01:06:40 +0000
2137 1970-01-14 21:20:00 +0000
2137 1970-01-14 21:20:00 +0000
2138 1970-01-13 17:33:20 +0000
2138 1970-01-13 17:33:20 +0000
2139 1970-01-12 13:46:40 +0000
2139 1970-01-12 13:46:40 +0000
2140
2140
2141 $ hg log --template '{date|rfc822date}\n'
2141 $ hg log --template '{date|rfc822date}\n'
2142 Wed, 01 Jan 2020 10:01:00 +0000
2142 Wed, 01 Jan 2020 10:01:00 +0000
2143 Mon, 12 Jan 1970 13:46:40 +0000
2143 Mon, 12 Jan 1970 13:46:40 +0000
2144 Sun, 18 Jan 1970 08:40:01 +0000
2144 Sun, 18 Jan 1970 08:40:01 +0000
2145 Sun, 18 Jan 1970 08:40:00 +0000
2145 Sun, 18 Jan 1970 08:40:00 +0000
2146 Sat, 17 Jan 1970 04:53:20 +0000
2146 Sat, 17 Jan 1970 04:53:20 +0000
2147 Fri, 16 Jan 1970 01:06:40 +0000
2147 Fri, 16 Jan 1970 01:06:40 +0000
2148 Wed, 14 Jan 1970 21:20:00 +0000
2148 Wed, 14 Jan 1970 21:20:00 +0000
2149 Tue, 13 Jan 1970 17:33:20 +0000
2149 Tue, 13 Jan 1970 17:33:20 +0000
2150 Mon, 12 Jan 1970 13:46:40 +0000
2150 Mon, 12 Jan 1970 13:46:40 +0000
2151
2151
2152 $ hg log --template '{desc|firstline}\n'
2152 $ hg log --template '{desc|firstline}\n'
2153 third
2153 third
2154 second
2154 second
2155 merge
2155 merge
2156 new head
2156 new head
2157 new branch
2157 new branch
2158 no user, no domain
2158 no user, no domain
2159 no person
2159 no person
2160 other 1
2160 other 1
2161 line 1
2161 line 1
2162
2162
2163 $ hg log --template '{node|short}\n'
2163 $ hg log --template '{node|short}\n'
2164 95c24699272e
2164 95c24699272e
2165 29114dbae42b
2165 29114dbae42b
2166 d41e714fe50d
2166 d41e714fe50d
2167 13207e5a10d9
2167 13207e5a10d9
2168 bbe44766e73d
2168 bbe44766e73d
2169 10e46f2dcbf4
2169 10e46f2dcbf4
2170 97054abb4ab8
2170 97054abb4ab8
2171 b608e9d1a3f0
2171 b608e9d1a3f0
2172 1e4e1b8f71e0
2172 1e4e1b8f71e0
2173
2173
2174 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2174 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2175 <changeset author="test"/>
2175 <changeset author="test"/>
2176 <changeset author="User Name &lt;user@hostname&gt;"/>
2176 <changeset author="User Name &lt;user@hostname&gt;"/>
2177 <changeset author="person"/>
2177 <changeset author="person"/>
2178 <changeset author="person"/>
2178 <changeset author="person"/>
2179 <changeset author="person"/>
2179 <changeset author="person"/>
2180 <changeset author="person"/>
2180 <changeset author="person"/>
2181 <changeset author="other@place"/>
2181 <changeset author="other@place"/>
2182 <changeset author="A. N. Other &lt;other@place&gt;"/>
2182 <changeset author="A. N. Other &lt;other@place&gt;"/>
2183 <changeset author="User Name &lt;user@hostname&gt;"/>
2183 <changeset author="User Name &lt;user@hostname&gt;"/>
2184
2184
2185 $ hg log --template '{rev}: {children}\n'
2185 $ hg log --template '{rev}: {children}\n'
2186 8:
2186 8:
2187 7: 8:95c24699272e
2187 7: 8:95c24699272e
2188 6:
2188 6:
2189 5: 6:d41e714fe50d
2189 5: 6:d41e714fe50d
2190 4: 6:d41e714fe50d
2190 4: 6:d41e714fe50d
2191 3: 4:bbe44766e73d 5:13207e5a10d9
2191 3: 4:bbe44766e73d 5:13207e5a10d9
2192 2: 3:10e46f2dcbf4
2192 2: 3:10e46f2dcbf4
2193 1: 2:97054abb4ab8
2193 1: 2:97054abb4ab8
2194 0: 1:b608e9d1a3f0
2194 0: 1:b608e9d1a3f0
2195
2195
2196 Formatnode filter works:
2196 Formatnode filter works:
2197
2197
2198 $ hg -q log -r 0 --template '{node|formatnode}\n'
2198 $ hg -q log -r 0 --template '{node|formatnode}\n'
2199 1e4e1b8f71e0
2199 1e4e1b8f71e0
2200
2200
2201 $ hg log -r 0 --template '{node|formatnode}\n'
2201 $ hg log -r 0 --template '{node|formatnode}\n'
2202 1e4e1b8f71e0
2202 1e4e1b8f71e0
2203
2203
2204 $ hg -v log -r 0 --template '{node|formatnode}\n'
2204 $ hg -v log -r 0 --template '{node|formatnode}\n'
2205 1e4e1b8f71e0
2205 1e4e1b8f71e0
2206
2206
2207 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2207 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2208 1e4e1b8f71e05681d422154f5421e385fec3454f
2208 1e4e1b8f71e05681d422154f5421e385fec3454f
2209
2209
2210 Age filter:
2210 Age filter:
2211
2211
2212 $ hg init unstable-hash
2212 $ hg init unstable-hash
2213 $ cd unstable-hash
2213 $ cd unstable-hash
2214 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2214 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2215
2215
2216 >>> from __future__ import absolute_import
2216 >>> from __future__ import absolute_import
2217 >>> import datetime
2217 >>> import datetime
2218 >>> fp = open('a', 'w')
2218 >>> fp = open('a', 'w')
2219 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2219 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2220 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2220 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2221 >>> fp.close()
2221 >>> fp.close()
2222 $ hg add a
2222 $ hg add a
2223 $ hg commit -m future -d "`cat a`"
2223 $ hg commit -m future -d "`cat a`"
2224
2224
2225 $ hg log -l1 --template '{date|age}\n'
2225 $ hg log -l1 --template '{date|age}\n'
2226 7 years from now
2226 7 years from now
2227
2227
2228 $ cd ..
2228 $ cd ..
2229 $ rm -rf unstable-hash
2229 $ rm -rf unstable-hash
2230
2230
2231 Add a dummy commit to make up for the instability of the above:
2231 Add a dummy commit to make up for the instability of the above:
2232
2232
2233 $ echo a > a
2233 $ echo a > a
2234 $ hg add a
2234 $ hg add a
2235 $ hg ci -m future
2235 $ hg ci -m future
2236
2236
2237 Count filter:
2237 Count filter:
2238
2238
2239 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2239 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2240 40 12
2240 40 12
2241
2241
2242 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2242 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2243 0 1 4
2243 0 1 4
2244
2244
2245 $ hg log -G --template '{rev}: children: {children|count}, \
2245 $ hg log -G --template '{rev}: children: {children|count}, \
2246 > tags: {tags|count}, file_adds: {file_adds|count}, \
2246 > tags: {tags|count}, file_adds: {file_adds|count}, \
2247 > ancestors: {revset("ancestors(%s)", rev)|count}'
2247 > ancestors: {revset("ancestors(%s)", rev)|count}'
2248 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2248 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2249 |
2249 |
2250 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2250 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2251 |
2251 |
2252 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2252 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2253
2253
2254 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2254 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2255 |\
2255 |\
2256 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2256 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2257 | |
2257 | |
2258 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2258 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2259 |/
2259 |/
2260 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2260 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2261 |
2261 |
2262 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2262 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2263 |
2263 |
2264 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2264 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2265 |
2265 |
2266 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2266 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2267
2267
2268
2268
2269 Upper/lower filters:
2269 Upper/lower filters:
2270
2270
2271 $ hg log -r0 --template '{branch|upper}\n'
2271 $ hg log -r0 --template '{branch|upper}\n'
2272 DEFAULT
2272 DEFAULT
2273 $ hg log -r0 --template '{author|lower}\n'
2273 $ hg log -r0 --template '{author|lower}\n'
2274 user name <user@hostname>
2274 user name <user@hostname>
2275 $ hg log -r0 --template '{date|upper}\n'
2275 $ hg log -r0 --template '{date|upper}\n'
2276 abort: template filter 'upper' is not compatible with keyword 'date'
2276 abort: template filter 'upper' is not compatible with keyword 'date'
2277 [255]
2277 [255]
2278
2278
2279 Add a commit that does all possible modifications at once
2279 Add a commit that does all possible modifications at once
2280
2280
2281 $ echo modify >> third
2281 $ echo modify >> third
2282 $ touch b
2282 $ touch b
2283 $ hg add b
2283 $ hg add b
2284 $ hg mv fourth fifth
2284 $ hg mv fourth fifth
2285 $ hg rm a
2285 $ hg rm a
2286 $ hg ci -m "Modify, add, remove, rename"
2286 $ hg ci -m "Modify, add, remove, rename"
2287
2287
2288 Check the status template
2288 Check the status template
2289
2289
2290 $ cat <<EOF >> $HGRCPATH
2290 $ cat <<EOF >> $HGRCPATH
2291 > [extensions]
2291 > [extensions]
2292 > color=
2292 > color=
2293 > EOF
2293 > EOF
2294
2294
2295 $ hg log -T status -r 10
2295 $ hg log -T status -r 10
2296 changeset: 10:0f9759ec227a
2296 changeset: 10:0f9759ec227a
2297 tag: tip
2297 tag: tip
2298 user: test
2298 user: test
2299 date: Thu Jan 01 00:00:00 1970 +0000
2299 date: Thu Jan 01 00:00:00 1970 +0000
2300 summary: Modify, add, remove, rename
2300 summary: Modify, add, remove, rename
2301 files:
2301 files:
2302 M third
2302 M third
2303 A b
2303 A b
2304 A fifth
2304 A fifth
2305 R a
2305 R a
2306 R fourth
2306 R fourth
2307
2307
2308 $ hg log -T status -C -r 10
2308 $ hg log -T status -C -r 10
2309 changeset: 10:0f9759ec227a
2309 changeset: 10:0f9759ec227a
2310 tag: tip
2310 tag: tip
2311 user: test
2311 user: test
2312 date: Thu Jan 01 00:00:00 1970 +0000
2312 date: Thu Jan 01 00:00:00 1970 +0000
2313 summary: Modify, add, remove, rename
2313 summary: Modify, add, remove, rename
2314 files:
2314 files:
2315 M third
2315 M third
2316 A b
2316 A b
2317 A fifth
2317 A fifth
2318 fourth
2318 fourth
2319 R a
2319 R a
2320 R fourth
2320 R fourth
2321
2321
2322 $ hg log -T status -C -r 10 -v
2322 $ hg log -T status -C -r 10 -v
2323 changeset: 10:0f9759ec227a
2323 changeset: 10:0f9759ec227a
2324 tag: tip
2324 tag: tip
2325 user: test
2325 user: test
2326 date: Thu Jan 01 00:00:00 1970 +0000
2326 date: Thu Jan 01 00:00:00 1970 +0000
2327 description:
2327 description:
2328 Modify, add, remove, rename
2328 Modify, add, remove, rename
2329
2329
2330 files:
2330 files:
2331 M third
2331 M third
2332 A b
2332 A b
2333 A fifth
2333 A fifth
2334 fourth
2334 fourth
2335 R a
2335 R a
2336 R fourth
2336 R fourth
2337
2337
2338 $ hg log -T status -C -r 10 --debug
2338 $ hg log -T status -C -r 10 --debug
2339 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2339 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2340 tag: tip
2340 tag: tip
2341 phase: secret
2341 phase: secret
2342 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2342 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2343 parent: -1:0000000000000000000000000000000000000000
2343 parent: -1:0000000000000000000000000000000000000000
2344 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2344 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2345 user: test
2345 user: test
2346 date: Thu Jan 01 00:00:00 1970 +0000
2346 date: Thu Jan 01 00:00:00 1970 +0000
2347 extra: branch=default
2347 extra: branch=default
2348 description:
2348 description:
2349 Modify, add, remove, rename
2349 Modify, add, remove, rename
2350
2350
2351 files:
2351 files:
2352 M third
2352 M third
2353 A b
2353 A b
2354 A fifth
2354 A fifth
2355 fourth
2355 fourth
2356 R a
2356 R a
2357 R fourth
2357 R fourth
2358
2358
2359 $ hg log -T status -C -r 10 --quiet
2359 $ hg log -T status -C -r 10 --quiet
2360 10:0f9759ec227a
2360 10:0f9759ec227a
2361 $ hg --color=debug log -T status -r 10
2361 $ hg --color=debug log -T status -r 10
2362 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2362 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2363 [log.tag|tag: tip]
2363 [log.tag|tag: tip]
2364 [log.user|user: test]
2364 [log.user|user: test]
2365 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2365 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2366 [log.summary|summary: Modify, add, remove, rename]
2366 [log.summary|summary: Modify, add, remove, rename]
2367 [ui.note log.files|files:]
2367 [ui.note log.files|files:]
2368 [status.modified|M third]
2368 [status.modified|M third]
2369 [status.added|A b]
2369 [status.added|A b]
2370 [status.added|A fifth]
2370 [status.added|A fifth]
2371 [status.removed|R a]
2371 [status.removed|R a]
2372 [status.removed|R fourth]
2372 [status.removed|R fourth]
2373
2373
2374 $ hg --color=debug log -T status -C -r 10
2374 $ hg --color=debug log -T status -C -r 10
2375 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2375 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2376 [log.tag|tag: tip]
2376 [log.tag|tag: tip]
2377 [log.user|user: test]
2377 [log.user|user: test]
2378 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2378 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2379 [log.summary|summary: Modify, add, remove, rename]
2379 [log.summary|summary: Modify, add, remove, rename]
2380 [ui.note log.files|files:]
2380 [ui.note log.files|files:]
2381 [status.modified|M third]
2381 [status.modified|M third]
2382 [status.added|A b]
2382 [status.added|A b]
2383 [status.added|A fifth]
2383 [status.added|A fifth]
2384 [status.copied| fourth]
2384 [status.copied| fourth]
2385 [status.removed|R a]
2385 [status.removed|R a]
2386 [status.removed|R fourth]
2386 [status.removed|R fourth]
2387
2387
2388 $ hg --color=debug log -T status -C -r 10 -v
2388 $ hg --color=debug log -T status -C -r 10 -v
2389 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2389 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2390 [log.tag|tag: tip]
2390 [log.tag|tag: tip]
2391 [log.user|user: test]
2391 [log.user|user: test]
2392 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2392 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2393 [ui.note log.description|description:]
2393 [ui.note log.description|description:]
2394 [ui.note log.description|Modify, add, remove, rename]
2394 [ui.note log.description|Modify, add, remove, rename]
2395
2395
2396 [ui.note log.files|files:]
2396 [ui.note log.files|files:]
2397 [status.modified|M third]
2397 [status.modified|M third]
2398 [status.added|A b]
2398 [status.added|A b]
2399 [status.added|A fifth]
2399 [status.added|A fifth]
2400 [status.copied| fourth]
2400 [status.copied| fourth]
2401 [status.removed|R a]
2401 [status.removed|R a]
2402 [status.removed|R fourth]
2402 [status.removed|R fourth]
2403
2403
2404 $ hg --color=debug log -T status -C -r 10 --debug
2404 $ hg --color=debug log -T status -C -r 10 --debug
2405 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2405 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2406 [log.tag|tag: tip]
2406 [log.tag|tag: tip]
2407 [log.phase|phase: secret]
2407 [log.phase|phase: secret]
2408 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2408 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2409 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2409 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2410 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2410 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2411 [log.user|user: test]
2411 [log.user|user: test]
2412 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2412 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2413 [ui.debug log.extra|extra: branch=default]
2413 [ui.debug log.extra|extra: branch=default]
2414 [ui.note log.description|description:]
2414 [ui.note log.description|description:]
2415 [ui.note log.description|Modify, add, remove, rename]
2415 [ui.note log.description|Modify, add, remove, rename]
2416
2416
2417 [ui.note log.files|files:]
2417 [ui.note log.files|files:]
2418 [status.modified|M third]
2418 [status.modified|M third]
2419 [status.added|A b]
2419 [status.added|A b]
2420 [status.added|A fifth]
2420 [status.added|A fifth]
2421 [status.copied| fourth]
2421 [status.copied| fourth]
2422 [status.removed|R a]
2422 [status.removed|R a]
2423 [status.removed|R fourth]
2423 [status.removed|R fourth]
2424
2424
2425 $ hg --color=debug log -T status -C -r 10 --quiet
2425 $ hg --color=debug log -T status -C -r 10 --quiet
2426 [log.node|10:0f9759ec227a]
2426 [log.node|10:0f9759ec227a]
2427
2427
2428 Check the bisect template
2428 Check the bisect template
2429
2429
2430 $ hg bisect -g 1
2430 $ hg bisect -g 1
2431 $ hg bisect -b 3 --noupdate
2431 $ hg bisect -b 3 --noupdate
2432 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2432 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2433 $ hg log -T bisect -r 0:4
2433 $ hg log -T bisect -r 0:4
2434 changeset: 0:1e4e1b8f71e0
2434 changeset: 0:1e4e1b8f71e0
2435 bisect: good (implicit)
2435 bisect: good (implicit)
2436 user: User Name <user@hostname>
2436 user: User Name <user@hostname>
2437 date: Mon Jan 12 13:46:40 1970 +0000
2437 date: Mon Jan 12 13:46:40 1970 +0000
2438 summary: line 1
2438 summary: line 1
2439
2439
2440 changeset: 1:b608e9d1a3f0
2440 changeset: 1:b608e9d1a3f0
2441 bisect: good
2441 bisect: good
2442 user: A. N. Other <other@place>
2442 user: A. N. Other <other@place>
2443 date: Tue Jan 13 17:33:20 1970 +0000
2443 date: Tue Jan 13 17:33:20 1970 +0000
2444 summary: other 1
2444 summary: other 1
2445
2445
2446 changeset: 2:97054abb4ab8
2446 changeset: 2:97054abb4ab8
2447 bisect: untested
2447 bisect: untested
2448 user: other@place
2448 user: other@place
2449 date: Wed Jan 14 21:20:00 1970 +0000
2449 date: Wed Jan 14 21:20:00 1970 +0000
2450 summary: no person
2450 summary: no person
2451
2451
2452 changeset: 3:10e46f2dcbf4
2452 changeset: 3:10e46f2dcbf4
2453 bisect: bad
2453 bisect: bad
2454 user: person
2454 user: person
2455 date: Fri Jan 16 01:06:40 1970 +0000
2455 date: Fri Jan 16 01:06:40 1970 +0000
2456 summary: no user, no domain
2456 summary: no user, no domain
2457
2457
2458 changeset: 4:bbe44766e73d
2458 changeset: 4:bbe44766e73d
2459 bisect: bad (implicit)
2459 bisect: bad (implicit)
2460 branch: foo
2460 branch: foo
2461 user: person
2461 user: person
2462 date: Sat Jan 17 04:53:20 1970 +0000
2462 date: Sat Jan 17 04:53:20 1970 +0000
2463 summary: new branch
2463 summary: new branch
2464
2464
2465 $ hg log --debug -T bisect -r 0:4
2465 $ hg log --debug -T bisect -r 0:4
2466 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2466 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2467 bisect: good (implicit)
2467 bisect: good (implicit)
2468 phase: public
2468 phase: public
2469 parent: -1:0000000000000000000000000000000000000000
2469 parent: -1:0000000000000000000000000000000000000000
2470 parent: -1:0000000000000000000000000000000000000000
2470 parent: -1:0000000000000000000000000000000000000000
2471 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2471 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2472 user: User Name <user@hostname>
2472 user: User Name <user@hostname>
2473 date: Mon Jan 12 13:46:40 1970 +0000
2473 date: Mon Jan 12 13:46:40 1970 +0000
2474 files+: a
2474 files+: a
2475 extra: branch=default
2475 extra: branch=default
2476 description:
2476 description:
2477 line 1
2477 line 1
2478 line 2
2478 line 2
2479
2479
2480
2480
2481 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2481 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2482 bisect: good
2482 bisect: good
2483 phase: public
2483 phase: public
2484 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2484 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2485 parent: -1:0000000000000000000000000000000000000000
2485 parent: -1:0000000000000000000000000000000000000000
2486 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2486 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2487 user: A. N. Other <other@place>
2487 user: A. N. Other <other@place>
2488 date: Tue Jan 13 17:33:20 1970 +0000
2488 date: Tue Jan 13 17:33:20 1970 +0000
2489 files+: b
2489 files+: b
2490 extra: branch=default
2490 extra: branch=default
2491 description:
2491 description:
2492 other 1
2492 other 1
2493 other 2
2493 other 2
2494
2494
2495 other 3
2495 other 3
2496
2496
2497
2497
2498 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2498 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2499 bisect: untested
2499 bisect: untested
2500 phase: public
2500 phase: public
2501 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2501 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2502 parent: -1:0000000000000000000000000000000000000000
2502 parent: -1:0000000000000000000000000000000000000000
2503 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2503 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2504 user: other@place
2504 user: other@place
2505 date: Wed Jan 14 21:20:00 1970 +0000
2505 date: Wed Jan 14 21:20:00 1970 +0000
2506 files+: c
2506 files+: c
2507 extra: branch=default
2507 extra: branch=default
2508 description:
2508 description:
2509 no person
2509 no person
2510
2510
2511
2511
2512 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2512 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2513 bisect: bad
2513 bisect: bad
2514 phase: public
2514 phase: public
2515 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2515 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2516 parent: -1:0000000000000000000000000000000000000000
2516 parent: -1:0000000000000000000000000000000000000000
2517 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2517 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2518 user: person
2518 user: person
2519 date: Fri Jan 16 01:06:40 1970 +0000
2519 date: Fri Jan 16 01:06:40 1970 +0000
2520 files: c
2520 files: c
2521 extra: branch=default
2521 extra: branch=default
2522 description:
2522 description:
2523 no user, no domain
2523 no user, no domain
2524
2524
2525
2525
2526 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2526 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2527 bisect: bad (implicit)
2527 bisect: bad (implicit)
2528 branch: foo
2528 branch: foo
2529 phase: draft
2529 phase: draft
2530 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2530 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2531 parent: -1:0000000000000000000000000000000000000000
2531 parent: -1:0000000000000000000000000000000000000000
2532 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2532 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2533 user: person
2533 user: person
2534 date: Sat Jan 17 04:53:20 1970 +0000
2534 date: Sat Jan 17 04:53:20 1970 +0000
2535 extra: branch=foo
2535 extra: branch=foo
2536 description:
2536 description:
2537 new branch
2537 new branch
2538
2538
2539
2539
2540 $ hg log -v -T bisect -r 0:4
2540 $ hg log -v -T bisect -r 0:4
2541 changeset: 0:1e4e1b8f71e0
2541 changeset: 0:1e4e1b8f71e0
2542 bisect: good (implicit)
2542 bisect: good (implicit)
2543 user: User Name <user@hostname>
2543 user: User Name <user@hostname>
2544 date: Mon Jan 12 13:46:40 1970 +0000
2544 date: Mon Jan 12 13:46:40 1970 +0000
2545 files: a
2545 files: a
2546 description:
2546 description:
2547 line 1
2547 line 1
2548 line 2
2548 line 2
2549
2549
2550
2550
2551 changeset: 1:b608e9d1a3f0
2551 changeset: 1:b608e9d1a3f0
2552 bisect: good
2552 bisect: good
2553 user: A. N. Other <other@place>
2553 user: A. N. Other <other@place>
2554 date: Tue Jan 13 17:33:20 1970 +0000
2554 date: Tue Jan 13 17:33:20 1970 +0000
2555 files: b
2555 files: b
2556 description:
2556 description:
2557 other 1
2557 other 1
2558 other 2
2558 other 2
2559
2559
2560 other 3
2560 other 3
2561
2561
2562
2562
2563 changeset: 2:97054abb4ab8
2563 changeset: 2:97054abb4ab8
2564 bisect: untested
2564 bisect: untested
2565 user: other@place
2565 user: other@place
2566 date: Wed Jan 14 21:20:00 1970 +0000
2566 date: Wed Jan 14 21:20:00 1970 +0000
2567 files: c
2567 files: c
2568 description:
2568 description:
2569 no person
2569 no person
2570
2570
2571
2571
2572 changeset: 3:10e46f2dcbf4
2572 changeset: 3:10e46f2dcbf4
2573 bisect: bad
2573 bisect: bad
2574 user: person
2574 user: person
2575 date: Fri Jan 16 01:06:40 1970 +0000
2575 date: Fri Jan 16 01:06:40 1970 +0000
2576 files: c
2576 files: c
2577 description:
2577 description:
2578 no user, no domain
2578 no user, no domain
2579
2579
2580
2580
2581 changeset: 4:bbe44766e73d
2581 changeset: 4:bbe44766e73d
2582 bisect: bad (implicit)
2582 bisect: bad (implicit)
2583 branch: foo
2583 branch: foo
2584 user: person
2584 user: person
2585 date: Sat Jan 17 04:53:20 1970 +0000
2585 date: Sat Jan 17 04:53:20 1970 +0000
2586 description:
2586 description:
2587 new branch
2587 new branch
2588
2588
2589
2589
2590 $ hg --color=debug log -T bisect -r 0:4
2590 $ hg --color=debug log -T bisect -r 0:4
2591 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2591 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2592 [log.bisect bisect.good|bisect: good (implicit)]
2592 [log.bisect bisect.good|bisect: good (implicit)]
2593 [log.user|user: User Name <user@hostname>]
2593 [log.user|user: User Name <user@hostname>]
2594 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2594 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2595 [log.summary|summary: line 1]
2595 [log.summary|summary: line 1]
2596
2596
2597 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2597 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2598 [log.bisect bisect.good|bisect: good]
2598 [log.bisect bisect.good|bisect: good]
2599 [log.user|user: A. N. Other <other@place>]
2599 [log.user|user: A. N. Other <other@place>]
2600 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2600 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2601 [log.summary|summary: other 1]
2601 [log.summary|summary: other 1]
2602
2602
2603 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2603 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2604 [log.bisect bisect.untested|bisect: untested]
2604 [log.bisect bisect.untested|bisect: untested]
2605 [log.user|user: other@place]
2605 [log.user|user: other@place]
2606 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2606 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2607 [log.summary|summary: no person]
2607 [log.summary|summary: no person]
2608
2608
2609 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2609 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2610 [log.bisect bisect.bad|bisect: bad]
2610 [log.bisect bisect.bad|bisect: bad]
2611 [log.user|user: person]
2611 [log.user|user: person]
2612 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2612 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2613 [log.summary|summary: no user, no domain]
2613 [log.summary|summary: no user, no domain]
2614
2614
2615 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2615 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2616 [log.bisect bisect.bad|bisect: bad (implicit)]
2616 [log.bisect bisect.bad|bisect: bad (implicit)]
2617 [log.branch|branch: foo]
2617 [log.branch|branch: foo]
2618 [log.user|user: person]
2618 [log.user|user: person]
2619 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2619 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2620 [log.summary|summary: new branch]
2620 [log.summary|summary: new branch]
2621
2621
2622 $ hg --color=debug log --debug -T bisect -r 0:4
2622 $ hg --color=debug log --debug -T bisect -r 0:4
2623 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2623 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2624 [log.bisect bisect.good|bisect: good (implicit)]
2624 [log.bisect bisect.good|bisect: good (implicit)]
2625 [log.phase|phase: public]
2625 [log.phase|phase: public]
2626 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2626 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2627 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2627 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2628 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2628 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2629 [log.user|user: User Name <user@hostname>]
2629 [log.user|user: User Name <user@hostname>]
2630 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2630 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2631 [ui.debug log.files|files+: a]
2631 [ui.debug log.files|files+: a]
2632 [ui.debug log.extra|extra: branch=default]
2632 [ui.debug log.extra|extra: branch=default]
2633 [ui.note log.description|description:]
2633 [ui.note log.description|description:]
2634 [ui.note log.description|line 1
2634 [ui.note log.description|line 1
2635 line 2]
2635 line 2]
2636
2636
2637
2637
2638 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2638 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2639 [log.bisect bisect.good|bisect: good]
2639 [log.bisect bisect.good|bisect: good]
2640 [log.phase|phase: public]
2640 [log.phase|phase: public]
2641 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2641 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2642 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2642 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2643 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2643 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2644 [log.user|user: A. N. Other <other@place>]
2644 [log.user|user: A. N. Other <other@place>]
2645 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2645 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2646 [ui.debug log.files|files+: b]
2646 [ui.debug log.files|files+: b]
2647 [ui.debug log.extra|extra: branch=default]
2647 [ui.debug log.extra|extra: branch=default]
2648 [ui.note log.description|description:]
2648 [ui.note log.description|description:]
2649 [ui.note log.description|other 1
2649 [ui.note log.description|other 1
2650 other 2
2650 other 2
2651
2651
2652 other 3]
2652 other 3]
2653
2653
2654
2654
2655 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2655 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2656 [log.bisect bisect.untested|bisect: untested]
2656 [log.bisect bisect.untested|bisect: untested]
2657 [log.phase|phase: public]
2657 [log.phase|phase: public]
2658 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2658 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2660 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2660 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2661 [log.user|user: other@place]
2661 [log.user|user: other@place]
2662 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2662 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2663 [ui.debug log.files|files+: c]
2663 [ui.debug log.files|files+: c]
2664 [ui.debug log.extra|extra: branch=default]
2664 [ui.debug log.extra|extra: branch=default]
2665 [ui.note log.description|description:]
2665 [ui.note log.description|description:]
2666 [ui.note log.description|no person]
2666 [ui.note log.description|no person]
2667
2667
2668
2668
2669 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2669 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2670 [log.bisect bisect.bad|bisect: bad]
2670 [log.bisect bisect.bad|bisect: bad]
2671 [log.phase|phase: public]
2671 [log.phase|phase: public]
2672 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2672 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2673 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2673 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2674 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2674 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2675 [log.user|user: person]
2675 [log.user|user: person]
2676 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2676 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2677 [ui.debug log.files|files: c]
2677 [ui.debug log.files|files: c]
2678 [ui.debug log.extra|extra: branch=default]
2678 [ui.debug log.extra|extra: branch=default]
2679 [ui.note log.description|description:]
2679 [ui.note log.description|description:]
2680 [ui.note log.description|no user, no domain]
2680 [ui.note log.description|no user, no domain]
2681
2681
2682
2682
2683 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2683 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2684 [log.bisect bisect.bad|bisect: bad (implicit)]
2684 [log.bisect bisect.bad|bisect: bad (implicit)]
2685 [log.branch|branch: foo]
2685 [log.branch|branch: foo]
2686 [log.phase|phase: draft]
2686 [log.phase|phase: draft]
2687 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2687 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2688 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2688 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2689 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2689 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2690 [log.user|user: person]
2690 [log.user|user: person]
2691 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2691 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2692 [ui.debug log.extra|extra: branch=foo]
2692 [ui.debug log.extra|extra: branch=foo]
2693 [ui.note log.description|description:]
2693 [ui.note log.description|description:]
2694 [ui.note log.description|new branch]
2694 [ui.note log.description|new branch]
2695
2695
2696
2696
2697 $ hg --color=debug log -v -T bisect -r 0:4
2697 $ hg --color=debug log -v -T bisect -r 0:4
2698 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2698 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2699 [log.bisect bisect.good|bisect: good (implicit)]
2699 [log.bisect bisect.good|bisect: good (implicit)]
2700 [log.user|user: User Name <user@hostname>]
2700 [log.user|user: User Name <user@hostname>]
2701 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2701 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2702 [ui.note log.files|files: a]
2702 [ui.note log.files|files: a]
2703 [ui.note log.description|description:]
2703 [ui.note log.description|description:]
2704 [ui.note log.description|line 1
2704 [ui.note log.description|line 1
2705 line 2]
2705 line 2]
2706
2706
2707
2707
2708 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2708 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2709 [log.bisect bisect.good|bisect: good]
2709 [log.bisect bisect.good|bisect: good]
2710 [log.user|user: A. N. Other <other@place>]
2710 [log.user|user: A. N. Other <other@place>]
2711 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2711 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2712 [ui.note log.files|files: b]
2712 [ui.note log.files|files: b]
2713 [ui.note log.description|description:]
2713 [ui.note log.description|description:]
2714 [ui.note log.description|other 1
2714 [ui.note log.description|other 1
2715 other 2
2715 other 2
2716
2716
2717 other 3]
2717 other 3]
2718
2718
2719
2719
2720 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2720 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2721 [log.bisect bisect.untested|bisect: untested]
2721 [log.bisect bisect.untested|bisect: untested]
2722 [log.user|user: other@place]
2722 [log.user|user: other@place]
2723 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2723 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2724 [ui.note log.files|files: c]
2724 [ui.note log.files|files: c]
2725 [ui.note log.description|description:]
2725 [ui.note log.description|description:]
2726 [ui.note log.description|no person]
2726 [ui.note log.description|no person]
2727
2727
2728
2728
2729 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2729 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2730 [log.bisect bisect.bad|bisect: bad]
2730 [log.bisect bisect.bad|bisect: bad]
2731 [log.user|user: person]
2731 [log.user|user: person]
2732 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2732 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2733 [ui.note log.files|files: c]
2733 [ui.note log.files|files: c]
2734 [ui.note log.description|description:]
2734 [ui.note log.description|description:]
2735 [ui.note log.description|no user, no domain]
2735 [ui.note log.description|no user, no domain]
2736
2736
2737
2737
2738 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2738 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2739 [log.bisect bisect.bad|bisect: bad (implicit)]
2739 [log.bisect bisect.bad|bisect: bad (implicit)]
2740 [log.branch|branch: foo]
2740 [log.branch|branch: foo]
2741 [log.user|user: person]
2741 [log.user|user: person]
2742 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2742 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2743 [ui.note log.description|description:]
2743 [ui.note log.description|description:]
2744 [ui.note log.description|new branch]
2744 [ui.note log.description|new branch]
2745
2745
2746
2746
2747 $ hg bisect --reset
2747 $ hg bisect --reset
2748
2748
2749 Error on syntax:
2749 Error on syntax:
2750
2750
2751 $ echo 'x = "f' >> t
2751 $ echo 'x = "f' >> t
2752 $ hg log
2752 $ hg log
2753 hg: parse error at t:3: unmatched quotes
2753 hg: parse error at t:3: unmatched quotes
2754 [255]
2754 [255]
2755
2755
2756 $ hg log -T '{date'
2756 $ hg log -T '{date'
2757 hg: parse error at 1: unterminated template expansion
2757 hg: parse error at 1: unterminated template expansion
2758 [255]
2758 [255]
2759 $ hg log -T '{date(}'
2759 $ hg log -T '{date(}'
2760 hg: parse error at 7: not a prefix: end
2760 hg: parse error at 7: not a prefix: end
2761 [255]
2761 [255]
2762 $ hg log -T '{date)}'
2762 $ hg log -T '{date)}'
2763 hg: parse error at 5: invalid token
2763 hg: parse error at 5: invalid token
2764 [255]
2764 [255]
2765 $ hg log -T '{date date}'
2765 $ hg log -T '{date date}'
2766 hg: parse error at 6: invalid token
2766 hg: parse error at 6: invalid token
2767 [255]
2767 [255]
2768
2768
2769 $ hg log -T '{}'
2770 hg: parse error at 2: not a prefix: end
2771 [255]
2772 $ hg debugtemplate -v '{()}'
2773 (template
2774 (group
2775 None))
2776 hg: parse error: missing argument
2777 [255]
2778
2769 Behind the scenes, this will throw TypeError
2779 Behind the scenes, this will throw TypeError
2770
2780
2771 $ hg log -l 3 --template '{date|obfuscate}\n'
2781 $ hg log -l 3 --template '{date|obfuscate}\n'
2772 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2782 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2773 [255]
2783 [255]
2774
2784
2775 Behind the scenes, this will throw a ValueError
2785 Behind the scenes, this will throw a ValueError
2776
2786
2777 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2787 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2778 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2788 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2779 [255]
2789 [255]
2780
2790
2781 Behind the scenes, this will throw AttributeError
2791 Behind the scenes, this will throw AttributeError
2782
2792
2783 $ hg log -l 3 --template 'line: {date|escape}\n'
2793 $ hg log -l 3 --template 'line: {date|escape}\n'
2784 abort: template filter 'escape' is not compatible with keyword 'date'
2794 abort: template filter 'escape' is not compatible with keyword 'date'
2785 [255]
2795 [255]
2786
2796
2787 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2797 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2788 hg: parse error: localdate expects a date information
2798 hg: parse error: localdate expects a date information
2789 [255]
2799 [255]
2790
2800
2791 Behind the scenes, this will throw ValueError
2801 Behind the scenes, this will throw ValueError
2792
2802
2793 $ hg tip --template '{author|email|date}\n'
2803 $ hg tip --template '{author|email|date}\n'
2794 hg: parse error: date expects a date information
2804 hg: parse error: date expects a date information
2795 [255]
2805 [255]
2796
2806
2797 $ hg tip -T '{author|email|shortdate}\n'
2807 $ hg tip -T '{author|email|shortdate}\n'
2798 abort: template filter 'shortdate' is not compatible with keyword 'author'
2808 abort: template filter 'shortdate' is not compatible with keyword 'author'
2799 [255]
2809 [255]
2800
2810
2801 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2811 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2802 abort: incompatible use of template filter 'shortdate'
2812 abort: incompatible use of template filter 'shortdate'
2803 [255]
2813 [255]
2804
2814
2805 Error in nested template:
2815 Error in nested template:
2806
2816
2807 $ hg log -T '{"date'
2817 $ hg log -T '{"date'
2808 hg: parse error at 2: unterminated string
2818 hg: parse error at 2: unterminated string
2809 [255]
2819 [255]
2810
2820
2811 $ hg log -T '{"foo{date|?}"}'
2821 $ hg log -T '{"foo{date|?}"}'
2812 hg: parse error at 11: syntax error
2822 hg: parse error at 11: syntax error
2813 [255]
2823 [255]
2814
2824
2815 Thrown an error if a template function doesn't exist
2825 Thrown an error if a template function doesn't exist
2816
2826
2817 $ hg tip --template '{foo()}\n'
2827 $ hg tip --template '{foo()}\n'
2818 hg: parse error: unknown function 'foo'
2828 hg: parse error: unknown function 'foo'
2819 [255]
2829 [255]
2820
2830
2821 Pass generator object created by template function to filter
2831 Pass generator object created by template function to filter
2822
2832
2823 $ hg log -l 1 --template '{if(author, author)|user}\n'
2833 $ hg log -l 1 --template '{if(author, author)|user}\n'
2824 test
2834 test
2825
2835
2826 Test index keyword:
2836 Test index keyword:
2827
2837
2828 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2838 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2829 10 0:a 1:b 2:fifth 3:fourth 4:third
2839 10 0:a 1:b 2:fifth 3:fourth 4:third
2830 11 0:a
2840 11 0:a
2831
2841
2832 $ hg branches -T '{index} {branch}\n'
2842 $ hg branches -T '{index} {branch}\n'
2833 0 default
2843 0 default
2834 1 foo
2844 1 foo
2835
2845
2836 Test diff function:
2846 Test diff function:
2837
2847
2838 $ hg diff -c 8
2848 $ hg diff -c 8
2839 diff -r 29114dbae42b -r 95c24699272e fourth
2849 diff -r 29114dbae42b -r 95c24699272e fourth
2840 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2850 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2841 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2851 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2842 @@ -0,0 +1,1 @@
2852 @@ -0,0 +1,1 @@
2843 +second
2853 +second
2844 diff -r 29114dbae42b -r 95c24699272e second
2854 diff -r 29114dbae42b -r 95c24699272e second
2845 --- a/second Mon Jan 12 13:46:40 1970 +0000
2855 --- a/second Mon Jan 12 13:46:40 1970 +0000
2846 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2856 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2847 @@ -1,1 +0,0 @@
2857 @@ -1,1 +0,0 @@
2848 -second
2858 -second
2849 diff -r 29114dbae42b -r 95c24699272e third
2859 diff -r 29114dbae42b -r 95c24699272e third
2850 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2860 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2851 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2861 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2852 @@ -0,0 +1,1 @@
2862 @@ -0,0 +1,1 @@
2853 +third
2863 +third
2854
2864
2855 $ hg log -r 8 -T "{diff()}"
2865 $ hg log -r 8 -T "{diff()}"
2856 diff -r 29114dbae42b -r 95c24699272e fourth
2866 diff -r 29114dbae42b -r 95c24699272e fourth
2857 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2867 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2858 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2868 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2859 @@ -0,0 +1,1 @@
2869 @@ -0,0 +1,1 @@
2860 +second
2870 +second
2861 diff -r 29114dbae42b -r 95c24699272e second
2871 diff -r 29114dbae42b -r 95c24699272e second
2862 --- a/second Mon Jan 12 13:46:40 1970 +0000
2872 --- a/second Mon Jan 12 13:46:40 1970 +0000
2863 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2873 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2864 @@ -1,1 +0,0 @@
2874 @@ -1,1 +0,0 @@
2865 -second
2875 -second
2866 diff -r 29114dbae42b -r 95c24699272e third
2876 diff -r 29114dbae42b -r 95c24699272e third
2867 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2877 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2868 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2878 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2869 @@ -0,0 +1,1 @@
2879 @@ -0,0 +1,1 @@
2870 +third
2880 +third
2871
2881
2872 $ hg log -r 8 -T "{diff('glob:f*')}"
2882 $ hg log -r 8 -T "{diff('glob:f*')}"
2873 diff -r 29114dbae42b -r 95c24699272e fourth
2883 diff -r 29114dbae42b -r 95c24699272e fourth
2874 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2884 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2875 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2885 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2876 @@ -0,0 +1,1 @@
2886 @@ -0,0 +1,1 @@
2877 +second
2887 +second
2878
2888
2879 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2889 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2880 diff -r 29114dbae42b -r 95c24699272e second
2890 diff -r 29114dbae42b -r 95c24699272e second
2881 --- a/second Mon Jan 12 13:46:40 1970 +0000
2891 --- a/second Mon Jan 12 13:46:40 1970 +0000
2882 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2892 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2883 @@ -1,1 +0,0 @@
2893 @@ -1,1 +0,0 @@
2884 -second
2894 -second
2885 diff -r 29114dbae42b -r 95c24699272e third
2895 diff -r 29114dbae42b -r 95c24699272e third
2886 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2896 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2887 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2897 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2888 @@ -0,0 +1,1 @@
2898 @@ -0,0 +1,1 @@
2889 +third
2899 +third
2890
2900
2891 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2901 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2892 diff -r 29114dbae42b -r 95c24699272e fourth
2902 diff -r 29114dbae42b -r 95c24699272e fourth
2893 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2903 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2894 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2904 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2895 @@ -0,0 +1,1 @@
2905 @@ -0,0 +1,1 @@
2896 +second
2906 +second
2897
2907
2898 ui verbosity:
2908 ui verbosity:
2899
2909
2900 $ hg log -l1 -T '{verbosity}\n'
2910 $ hg log -l1 -T '{verbosity}\n'
2901
2911
2902 $ hg log -l1 -T '{verbosity}\n' --debug
2912 $ hg log -l1 -T '{verbosity}\n' --debug
2903 debug
2913 debug
2904 $ hg log -l1 -T '{verbosity}\n' --quiet
2914 $ hg log -l1 -T '{verbosity}\n' --quiet
2905 quiet
2915 quiet
2906 $ hg log -l1 -T '{verbosity}\n' --verbose
2916 $ hg log -l1 -T '{verbosity}\n' --verbose
2907 verbose
2917 verbose
2908
2918
2909 $ cd ..
2919 $ cd ..
2910
2920
2911
2921
2912 latesttag:
2922 latesttag:
2913
2923
2914 $ hg init latesttag
2924 $ hg init latesttag
2915 $ cd latesttag
2925 $ cd latesttag
2916
2926
2917 $ echo a > file
2927 $ echo a > file
2918 $ hg ci -Am a -d '0 0'
2928 $ hg ci -Am a -d '0 0'
2919 adding file
2929 adding file
2920
2930
2921 $ echo b >> file
2931 $ echo b >> file
2922 $ hg ci -m b -d '1 0'
2932 $ hg ci -m b -d '1 0'
2923
2933
2924 $ echo c >> head1
2934 $ echo c >> head1
2925 $ hg ci -Am h1c -d '2 0'
2935 $ hg ci -Am h1c -d '2 0'
2926 adding head1
2936 adding head1
2927
2937
2928 $ hg update -q 1
2938 $ hg update -q 1
2929 $ echo d >> head2
2939 $ echo d >> head2
2930 $ hg ci -Am h2d -d '3 0'
2940 $ hg ci -Am h2d -d '3 0'
2931 adding head2
2941 adding head2
2932 created new head
2942 created new head
2933
2943
2934 $ echo e >> head2
2944 $ echo e >> head2
2935 $ hg ci -m h2e -d '4 0'
2945 $ hg ci -m h2e -d '4 0'
2936
2946
2937 $ hg merge -q
2947 $ hg merge -q
2938 $ hg ci -m merge -d '5 -3600'
2948 $ hg ci -m merge -d '5 -3600'
2939
2949
2940 No tag set:
2950 No tag set:
2941
2951
2942 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2952 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2943 @ 5: null+5
2953 @ 5: null+5
2944 |\
2954 |\
2945 | o 4: null+4
2955 | o 4: null+4
2946 | |
2956 | |
2947 | o 3: null+3
2957 | o 3: null+3
2948 | |
2958 | |
2949 o | 2: null+3
2959 o | 2: null+3
2950 |/
2960 |/
2951 o 1: null+2
2961 o 1: null+2
2952 |
2962 |
2953 o 0: null+1
2963 o 0: null+1
2954
2964
2955
2965
2956 One common tag: longest path wins for {latesttagdistance}:
2966 One common tag: longest path wins for {latesttagdistance}:
2957
2967
2958 $ hg tag -r 1 -m t1 -d '6 0' t1
2968 $ hg tag -r 1 -m t1 -d '6 0' t1
2959 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2969 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2960 @ 6: t1+4
2970 @ 6: t1+4
2961 |
2971 |
2962 o 5: t1+3
2972 o 5: t1+3
2963 |\
2973 |\
2964 | o 4: t1+2
2974 | o 4: t1+2
2965 | |
2975 | |
2966 | o 3: t1+1
2976 | o 3: t1+1
2967 | |
2977 | |
2968 o | 2: t1+1
2978 o | 2: t1+1
2969 |/
2979 |/
2970 o 1: t1+0
2980 o 1: t1+0
2971 |
2981 |
2972 o 0: null+1
2982 o 0: null+1
2973
2983
2974
2984
2975 One ancestor tag: closest wins:
2985 One ancestor tag: closest wins:
2976
2986
2977 $ hg tag -r 2 -m t2 -d '7 0' t2
2987 $ hg tag -r 2 -m t2 -d '7 0' t2
2978 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2988 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2979 @ 7: t2+3
2989 @ 7: t2+3
2980 |
2990 |
2981 o 6: t2+2
2991 o 6: t2+2
2982 |
2992 |
2983 o 5: t2+1
2993 o 5: t2+1
2984 |\
2994 |\
2985 | o 4: t1+2
2995 | o 4: t1+2
2986 | |
2996 | |
2987 | o 3: t1+1
2997 | o 3: t1+1
2988 | |
2998 | |
2989 o | 2: t2+0
2999 o | 2: t2+0
2990 |/
3000 |/
2991 o 1: t1+0
3001 o 1: t1+0
2992 |
3002 |
2993 o 0: null+1
3003 o 0: null+1
2994
3004
2995
3005
2996 Two branch tags: more recent wins if same number of changes:
3006 Two branch tags: more recent wins if same number of changes:
2997
3007
2998 $ hg tag -r 3 -m t3 -d '8 0' t3
3008 $ hg tag -r 3 -m t3 -d '8 0' t3
2999 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3009 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3000 @ 8: t3+5
3010 @ 8: t3+5
3001 |
3011 |
3002 o 7: t3+4
3012 o 7: t3+4
3003 |
3013 |
3004 o 6: t3+3
3014 o 6: t3+3
3005 |
3015 |
3006 o 5: t3+2
3016 o 5: t3+2
3007 |\
3017 |\
3008 | o 4: t3+1
3018 | o 4: t3+1
3009 | |
3019 | |
3010 | o 3: t3+0
3020 | o 3: t3+0
3011 | |
3021 | |
3012 o | 2: t2+0
3022 o | 2: t2+0
3013 |/
3023 |/
3014 o 1: t1+0
3024 o 1: t1+0
3015 |
3025 |
3016 o 0: null+1
3026 o 0: null+1
3017
3027
3018
3028
3019 Two branch tags: fewest changes wins:
3029 Two branch tags: fewest changes wins:
3020
3030
3021 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3031 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3022 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3032 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3023 @ 9: t4+5,6
3033 @ 9: t4+5,6
3024 |
3034 |
3025 o 8: t4+4,5
3035 o 8: t4+4,5
3026 |
3036 |
3027 o 7: t4+3,4
3037 o 7: t4+3,4
3028 |
3038 |
3029 o 6: t4+2,3
3039 o 6: t4+2,3
3030 |
3040 |
3031 o 5: t4+1,2
3041 o 5: t4+1,2
3032 |\
3042 |\
3033 | o 4: t4+0,0
3043 | o 4: t4+0,0
3034 | |
3044 | |
3035 | o 3: t3+0,0
3045 | o 3: t3+0,0
3036 | |
3046 | |
3037 o | 2: t2+0,0
3047 o | 2: t2+0,0
3038 |/
3048 |/
3039 o 1: t1+0,0
3049 o 1: t1+0,0
3040 |
3050 |
3041 o 0: null+1,1
3051 o 0: null+1,1
3042
3052
3043
3053
3044 Merged tag overrides:
3054 Merged tag overrides:
3045
3055
3046 $ hg tag -r 5 -m t5 -d '9 0' t5
3056 $ hg tag -r 5 -m t5 -d '9 0' t5
3047 $ hg tag -r 3 -m at3 -d '10 0' at3
3057 $ hg tag -r 3 -m at3 -d '10 0' at3
3048 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3058 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3049 @ 11: t5+6
3059 @ 11: t5+6
3050 |
3060 |
3051 o 10: t5+5
3061 o 10: t5+5
3052 |
3062 |
3053 o 9: t5+4
3063 o 9: t5+4
3054 |
3064 |
3055 o 8: t5+3
3065 o 8: t5+3
3056 |
3066 |
3057 o 7: t5+2
3067 o 7: t5+2
3058 |
3068 |
3059 o 6: t5+1
3069 o 6: t5+1
3060 |
3070 |
3061 o 5: t5+0
3071 o 5: t5+0
3062 |\
3072 |\
3063 | o 4: t4+0
3073 | o 4: t4+0
3064 | |
3074 | |
3065 | o 3: at3:t3+0
3075 | o 3: at3:t3+0
3066 | |
3076 | |
3067 o | 2: t2+0
3077 o | 2: t2+0
3068 |/
3078 |/
3069 o 1: t1+0
3079 o 1: t1+0
3070 |
3080 |
3071 o 0: null+1
3081 o 0: null+1
3072
3082
3073
3083
3074 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3084 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3075 @ 11: t5+6,6
3085 @ 11: t5+6,6
3076 |
3086 |
3077 o 10: t5+5,5
3087 o 10: t5+5,5
3078 |
3088 |
3079 o 9: t5+4,4
3089 o 9: t5+4,4
3080 |
3090 |
3081 o 8: t5+3,3
3091 o 8: t5+3,3
3082 |
3092 |
3083 o 7: t5+2,2
3093 o 7: t5+2,2
3084 |
3094 |
3085 o 6: t5+1,1
3095 o 6: t5+1,1
3086 |
3096 |
3087 o 5: t5+0,0
3097 o 5: t5+0,0
3088 |\
3098 |\
3089 | o 4: t4+0,0
3099 | o 4: t4+0,0
3090 | |
3100 | |
3091 | o 3: at3+0,0 t3+0,0
3101 | o 3: at3+0,0 t3+0,0
3092 | |
3102 | |
3093 o | 2: t2+0,0
3103 o | 2: t2+0,0
3094 |/
3104 |/
3095 o 1: t1+0,0
3105 o 1: t1+0,0
3096 |
3106 |
3097 o 0: null+1,1
3107 o 0: null+1,1
3098
3108
3099
3109
3100 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3110 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3101 @ 11: t3, C: 9, D: 8
3111 @ 11: t3, C: 9, D: 8
3102 |
3112 |
3103 o 10: t3, C: 8, D: 7
3113 o 10: t3, C: 8, D: 7
3104 |
3114 |
3105 o 9: t3, C: 7, D: 6
3115 o 9: t3, C: 7, D: 6
3106 |
3116 |
3107 o 8: t3, C: 6, D: 5
3117 o 8: t3, C: 6, D: 5
3108 |
3118 |
3109 o 7: t3, C: 5, D: 4
3119 o 7: t3, C: 5, D: 4
3110 |
3120 |
3111 o 6: t3, C: 4, D: 3
3121 o 6: t3, C: 4, D: 3
3112 |
3122 |
3113 o 5: t3, C: 3, D: 2
3123 o 5: t3, C: 3, D: 2
3114 |\
3124 |\
3115 | o 4: t3, C: 1, D: 1
3125 | o 4: t3, C: 1, D: 1
3116 | |
3126 | |
3117 | o 3: t3, C: 0, D: 0
3127 | o 3: t3, C: 0, D: 0
3118 | |
3128 | |
3119 o | 2: t1, C: 1, D: 1
3129 o | 2: t1, C: 1, D: 1
3120 |/
3130 |/
3121 o 1: t1, C: 0, D: 0
3131 o 1: t1, C: 0, D: 0
3122 |
3132 |
3123 o 0: null, C: 1, D: 1
3133 o 0: null, C: 1, D: 1
3124
3134
3125
3135
3126 $ cd ..
3136 $ cd ..
3127
3137
3128
3138
3129 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3139 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3130 if it is a relative path
3140 if it is a relative path
3131
3141
3132 $ mkdir -p home/styles
3142 $ mkdir -p home/styles
3133
3143
3134 $ cat > home/styles/teststyle <<EOF
3144 $ cat > home/styles/teststyle <<EOF
3135 > changeset = 'test {rev}:{node|short}\n'
3145 > changeset = 'test {rev}:{node|short}\n'
3136 > EOF
3146 > EOF
3137
3147
3138 $ HOME=`pwd`/home; export HOME
3148 $ HOME=`pwd`/home; export HOME
3139
3149
3140 $ cat > latesttag/.hg/hgrc <<EOF
3150 $ cat > latesttag/.hg/hgrc <<EOF
3141 > [ui]
3151 > [ui]
3142 > style = ~/styles/teststyle
3152 > style = ~/styles/teststyle
3143 > EOF
3153 > EOF
3144
3154
3145 $ hg -R latesttag tip
3155 $ hg -R latesttag tip
3146 test 11:97e5943b523a
3156 test 11:97e5943b523a
3147
3157
3148 Test recursive showlist template (issue1989):
3158 Test recursive showlist template (issue1989):
3149
3159
3150 $ cat > style1989 <<EOF
3160 $ cat > style1989 <<EOF
3151 > changeset = '{file_mods}{manifest}{extras}'
3161 > changeset = '{file_mods}{manifest}{extras}'
3152 > file_mod = 'M|{author|person}\n'
3162 > file_mod = 'M|{author|person}\n'
3153 > manifest = '{rev},{author}\n'
3163 > manifest = '{rev},{author}\n'
3154 > extra = '{key}: {author}\n'
3164 > extra = '{key}: {author}\n'
3155 > EOF
3165 > EOF
3156
3166
3157 $ hg -R latesttag log -r tip --style=style1989
3167 $ hg -R latesttag log -r tip --style=style1989
3158 M|test
3168 M|test
3159 11,test
3169 11,test
3160 branch: test
3170 branch: test
3161
3171
3162 Test new-style inline templating:
3172 Test new-style inline templating:
3163
3173
3164 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3174 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3165 modified files: .hgtags
3175 modified files: .hgtags
3166
3176
3167
3177
3168 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3178 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3169 hg: parse error: keyword 'rev' is not iterable
3179 hg: parse error: keyword 'rev' is not iterable
3170 [255]
3180 [255]
3171 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3181 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3172 hg: parse error: None is not iterable
3182 hg: parse error: None is not iterable
3173 [255]
3183 [255]
3174
3184
3175 Test new-style inline templating of non-list/dict type:
3185 Test new-style inline templating of non-list/dict type:
3176
3186
3177 $ hg log -R latesttag -r tip -T '{manifest}\n'
3187 $ hg log -R latesttag -r tip -T '{manifest}\n'
3178 11:2bc6e9006ce2
3188 11:2bc6e9006ce2
3179 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3189 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3180 string length: 15
3190 string length: 15
3181 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3191 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3182 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3192 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3183
3193
3184 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3194 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3185 branch: default
3195 branch: default
3186 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3196 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3187 hg: parse error: None is not iterable
3197 hg: parse error: None is not iterable
3188 [255]
3198 [255]
3189 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3199 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3190 branch: default
3200 branch: default
3191 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3201 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3192 0:ce3cec86e6c2
3202 0:ce3cec86e6c2
3193 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3203 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3194 9:fbc7cd862e9c
3204 9:fbc7cd862e9c
3195
3205
3196 Test manifest/get() can be join()-ed as before, though it's silly:
3206 Test manifest/get() can be join()-ed as before, though it's silly:
3197
3207
3198 $ hg log -R latesttag -r tip -T '{join(manifest, "")}\n'
3208 $ hg log -R latesttag -r tip -T '{join(manifest, "")}\n'
3199 11:2bc6e9006ce2
3209 11:2bc6e9006ce2
3200 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3210 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3201 default
3211 default
3202
3212
3203 Test min/max of integers
3213 Test min/max of integers
3204
3214
3205 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3215 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3206 9
3216 9
3207 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3217 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3208 10
3218 10
3209
3219
3210 Test dot operator precedence:
3220 Test dot operator precedence:
3211
3221
3212 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3222 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3213 (template
3223 (template
3214 (|
3224 (|
3215 (.
3225 (.
3216 (symbol 'manifest')
3226 (symbol 'manifest')
3217 (symbol 'node'))
3227 (symbol 'node'))
3218 (symbol 'short'))
3228 (symbol 'short'))
3219 (string '\n'))
3229 (string '\n'))
3220 89f4071fec70
3230 89f4071fec70
3221
3231
3222 (the following examples are invalid, but seem natural in parsing POV)
3232 (the following examples are invalid, but seem natural in parsing POV)
3223
3233
3224 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3234 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3225 (template
3235 (template
3226 (|
3236 (|
3227 (symbol 'foo')
3237 (symbol 'foo')
3228 (.
3238 (.
3229 (symbol 'bar')
3239 (symbol 'bar')
3230 (symbol 'baz')))
3240 (symbol 'baz')))
3231 (string '\n'))
3241 (string '\n'))
3232 [255]
3242 [255]
3233 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3243 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3234 (template
3244 (template
3235 (.
3245 (.
3236 (symbol 'foo')
3246 (symbol 'foo')
3237 (func
3247 (func
3238 (symbol 'bar')
3248 (symbol 'bar')
3239 None))
3249 None))
3240 (string '\n'))
3250 (string '\n'))
3241 [255]
3251 [255]
3242
3252
3243 Test evaluation of dot operator:
3253 Test evaluation of dot operator:
3244
3254
3245 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3255 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3246 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3256 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3247 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3257 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3248 default
3258 default
3249
3259
3250 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3260 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3251 hg: parse error: keyword 'author' has no member
3261 hg: parse error: keyword 'author' has no member
3252 [255]
3262 [255]
3253 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3263 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3254 hg: parse error: 'a' has no member
3264 hg: parse error: 'a' has no member
3255 [255]
3265 [255]
3256
3266
3257 Test the sub function of templating for expansion:
3267 Test the sub function of templating for expansion:
3258
3268
3259 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3269 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3260 xx
3270 xx
3261
3271
3262 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3272 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3263 hg: parse error: sub got an invalid pattern: [
3273 hg: parse error: sub got an invalid pattern: [
3264 [255]
3274 [255]
3265 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3275 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3266 hg: parse error: sub got an invalid replacement: \1
3276 hg: parse error: sub got an invalid replacement: \1
3267 [255]
3277 [255]
3268
3278
3269 Test the strip function with chars specified:
3279 Test the strip function with chars specified:
3270
3280
3271 $ hg log -R latesttag --template '{desc}\n'
3281 $ hg log -R latesttag --template '{desc}\n'
3272 at3
3282 at3
3273 t5
3283 t5
3274 t4
3284 t4
3275 t3
3285 t3
3276 t2
3286 t2
3277 t1
3287 t1
3278 merge
3288 merge
3279 h2e
3289 h2e
3280 h2d
3290 h2d
3281 h1c
3291 h1c
3282 b
3292 b
3283 a
3293 a
3284
3294
3285 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3295 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3286 at3
3296 at3
3287 5
3297 5
3288 4
3298 4
3289 3
3299 3
3290 2
3300 2
3291 1
3301 1
3292 merg
3302 merg
3293 h2
3303 h2
3294 h2d
3304 h2d
3295 h1c
3305 h1c
3296 b
3306 b
3297 a
3307 a
3298
3308
3299 Test date format:
3309 Test date format:
3300
3310
3301 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3311 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3302 date: 70 01 01 10 +0000
3312 date: 70 01 01 10 +0000
3303 date: 70 01 01 09 +0000
3313 date: 70 01 01 09 +0000
3304 date: 70 01 01 04 +0000
3314 date: 70 01 01 04 +0000
3305 date: 70 01 01 08 +0000
3315 date: 70 01 01 08 +0000
3306 date: 70 01 01 07 +0000
3316 date: 70 01 01 07 +0000
3307 date: 70 01 01 06 +0000
3317 date: 70 01 01 06 +0000
3308 date: 70 01 01 05 +0100
3318 date: 70 01 01 05 +0100
3309 date: 70 01 01 04 +0000
3319 date: 70 01 01 04 +0000
3310 date: 70 01 01 03 +0000
3320 date: 70 01 01 03 +0000
3311 date: 70 01 01 02 +0000
3321 date: 70 01 01 02 +0000
3312 date: 70 01 01 01 +0000
3322 date: 70 01 01 01 +0000
3313 date: 70 01 01 00 +0000
3323 date: 70 01 01 00 +0000
3314
3324
3315 Test invalid date:
3325 Test invalid date:
3316
3326
3317 $ hg log -R latesttag -T '{date(rev)}\n'
3327 $ hg log -R latesttag -T '{date(rev)}\n'
3318 hg: parse error: date expects a date information
3328 hg: parse error: date expects a date information
3319 [255]
3329 [255]
3320
3330
3321 Test integer literal:
3331 Test integer literal:
3322
3332
3323 $ hg debugtemplate -v '{(0)}\n'
3333 $ hg debugtemplate -v '{(0)}\n'
3324 (template
3334 (template
3325 (group
3335 (group
3326 (integer '0'))
3336 (integer '0'))
3327 (string '\n'))
3337 (string '\n'))
3328 0
3338 0
3329 $ hg debugtemplate -v '{(123)}\n'
3339 $ hg debugtemplate -v '{(123)}\n'
3330 (template
3340 (template
3331 (group
3341 (group
3332 (integer '123'))
3342 (integer '123'))
3333 (string '\n'))
3343 (string '\n'))
3334 123
3344 123
3335 $ hg debugtemplate -v '{(-4)}\n'
3345 $ hg debugtemplate -v '{(-4)}\n'
3336 (template
3346 (template
3337 (group
3347 (group
3338 (negate
3348 (negate
3339 (integer '4')))
3349 (integer '4')))
3340 (string '\n'))
3350 (string '\n'))
3341 -4
3351 -4
3342 $ hg debugtemplate '{(-)}\n'
3352 $ hg debugtemplate '{(-)}\n'
3343 hg: parse error at 3: not a prefix: )
3353 hg: parse error at 3: not a prefix: )
3344 [255]
3354 [255]
3345 $ hg debugtemplate '{(-a)}\n'
3355 $ hg debugtemplate '{(-a)}\n'
3346 hg: parse error: negation needs an integer argument
3356 hg: parse error: negation needs an integer argument
3347 [255]
3357 [255]
3348
3358
3349 top-level integer literal is interpreted as symbol (i.e. variable name):
3359 top-level integer literal is interpreted as symbol (i.e. variable name):
3350
3360
3351 $ hg debugtemplate -D 1=one -v '{1}\n'
3361 $ hg debugtemplate -D 1=one -v '{1}\n'
3352 (template
3362 (template
3353 (integer '1')
3363 (integer '1')
3354 (string '\n'))
3364 (string '\n'))
3355 one
3365 one
3356 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3366 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3357 (template
3367 (template
3358 (func
3368 (func
3359 (symbol 'if')
3369 (symbol 'if')
3360 (list
3370 (list
3361 (string 't')
3371 (string 't')
3362 (template
3372 (template
3363 (integer '1'))))
3373 (integer '1'))))
3364 (string '\n'))
3374 (string '\n'))
3365 one
3375 one
3366 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3376 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3367 (template
3377 (template
3368 (|
3378 (|
3369 (integer '1')
3379 (integer '1')
3370 (symbol 'stringify'))
3380 (symbol 'stringify'))
3371 (string '\n'))
3381 (string '\n'))
3372 one
3382 one
3373
3383
3374 unless explicit symbol is expected:
3384 unless explicit symbol is expected:
3375
3385
3376 $ hg log -Ra -r0 -T '{desc|1}\n'
3386 $ hg log -Ra -r0 -T '{desc|1}\n'
3377 hg: parse error: expected a symbol, got 'integer'
3387 hg: parse error: expected a symbol, got 'integer'
3378 [255]
3388 [255]
3379 $ hg log -Ra -r0 -T '{1()}\n'
3389 $ hg log -Ra -r0 -T '{1()}\n'
3380 hg: parse error: expected a symbol, got 'integer'
3390 hg: parse error: expected a symbol, got 'integer'
3381 [255]
3391 [255]
3382
3392
3383 Test string literal:
3393 Test string literal:
3384
3394
3385 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3395 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3386 (template
3396 (template
3387 (string 'string with no template fragment')
3397 (string 'string with no template fragment')
3388 (string '\n'))
3398 (string '\n'))
3389 string with no template fragment
3399 string with no template fragment
3390 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3400 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3391 (template
3401 (template
3392 (template
3402 (template
3393 (string 'template: ')
3403 (string 'template: ')
3394 (symbol 'rev'))
3404 (symbol 'rev'))
3395 (string '\n'))
3405 (string '\n'))
3396 template: 0
3406 template: 0
3397 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3407 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3398 (template
3408 (template
3399 (string 'rawstring: {rev}')
3409 (string 'rawstring: {rev}')
3400 (string '\n'))
3410 (string '\n'))
3401 rawstring: {rev}
3411 rawstring: {rev}
3402 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3412 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3403 (template
3413 (template
3404 (%
3414 (%
3405 (symbol 'files')
3415 (symbol 'files')
3406 (string 'rawstring: {file}'))
3416 (string 'rawstring: {file}'))
3407 (string '\n'))
3417 (string '\n'))
3408 rawstring: {file}
3418 rawstring: {file}
3409
3419
3410 Test string escaping:
3420 Test string escaping:
3411
3421
3412 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3422 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3413 >
3423 >
3414 <>\n<[>
3424 <>\n<[>
3415 <>\n<]>
3425 <>\n<]>
3416 <>\n<
3426 <>\n<
3417
3427
3418 $ hg log -R latesttag -r 0 \
3428 $ hg log -R latesttag -r 0 \
3419 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3429 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3420 >
3430 >
3421 <>\n<[>
3431 <>\n<[>
3422 <>\n<]>
3432 <>\n<]>
3423 <>\n<
3433 <>\n<
3424
3434
3425 $ hg log -R latesttag -r 0 -T esc \
3435 $ hg log -R latesttag -r 0 -T esc \
3426 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3436 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3427 >
3437 >
3428 <>\n<[>
3438 <>\n<[>
3429 <>\n<]>
3439 <>\n<]>
3430 <>\n<
3440 <>\n<
3431
3441
3432 $ cat <<'EOF' > esctmpl
3442 $ cat <<'EOF' > esctmpl
3433 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3443 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3434 > EOF
3444 > EOF
3435 $ hg log -R latesttag -r 0 --style ./esctmpl
3445 $ hg log -R latesttag -r 0 --style ./esctmpl
3436 >
3446 >
3437 <>\n<[>
3447 <>\n<[>
3438 <>\n<]>
3448 <>\n<]>
3439 <>\n<
3449 <>\n<
3440
3450
3441 Test string escaping of quotes:
3451 Test string escaping of quotes:
3442
3452
3443 $ hg log -Ra -r0 -T '{"\""}\n'
3453 $ hg log -Ra -r0 -T '{"\""}\n'
3444 "
3454 "
3445 $ hg log -Ra -r0 -T '{"\\\""}\n'
3455 $ hg log -Ra -r0 -T '{"\\\""}\n'
3446 \"
3456 \"
3447 $ hg log -Ra -r0 -T '{r"\""}\n'
3457 $ hg log -Ra -r0 -T '{r"\""}\n'
3448 \"
3458 \"
3449 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3459 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3450 \\\"
3460 \\\"
3451
3461
3452
3462
3453 $ hg log -Ra -r0 -T '{"\""}\n'
3463 $ hg log -Ra -r0 -T '{"\""}\n'
3454 "
3464 "
3455 $ hg log -Ra -r0 -T '{"\\\""}\n'
3465 $ hg log -Ra -r0 -T '{"\\\""}\n'
3456 \"
3466 \"
3457 $ hg log -Ra -r0 -T '{r"\""}\n'
3467 $ hg log -Ra -r0 -T '{r"\""}\n'
3458 \"
3468 \"
3459 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3469 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3460 \\\"
3470 \\\"
3461
3471
3462 Test exception in quoted template. single backslash before quotation mark is
3472 Test exception in quoted template. single backslash before quotation mark is
3463 stripped before parsing:
3473 stripped before parsing:
3464
3474
3465 $ cat <<'EOF' > escquotetmpl
3475 $ cat <<'EOF' > escquotetmpl
3466 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3476 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3467 > EOF
3477 > EOF
3468 $ cd latesttag
3478 $ cd latesttag
3469 $ hg log -r 2 --style ../escquotetmpl
3479 $ hg log -r 2 --style ../escquotetmpl
3470 " \" \" \\" head1
3480 " \" \" \\" head1
3471
3481
3472 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3482 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3473 valid
3483 valid
3474 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3484 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3475 valid
3485 valid
3476
3486
3477 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3487 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3478 _evalifliteral() templates (issue4733):
3488 _evalifliteral() templates (issue4733):
3479
3489
3480 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3490 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3481 "2
3491 "2
3482 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3492 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3483 "2
3493 "2
3484 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3494 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3485 "2
3495 "2
3486
3496
3487 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3497 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3488 \"
3498 \"
3489 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3499 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3490 \"
3500 \"
3491 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3501 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3492 \"
3502 \"
3493
3503
3494 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3504 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3495 \\\"
3505 \\\"
3496 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3506 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3497 \\\"
3507 \\\"
3498 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3508 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3499 \\\"
3509 \\\"
3500
3510
3501 escaped single quotes and errors:
3511 escaped single quotes and errors:
3502
3512
3503 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3513 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3504 foo
3514 foo
3505 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3515 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3506 foo
3516 foo
3507 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3517 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3508 hg: parse error at 21: unterminated string
3518 hg: parse error at 21: unterminated string
3509 [255]
3519 [255]
3510 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3520 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3511 hg: parse error: trailing \ in string
3521 hg: parse error: trailing \ in string
3512 [255]
3522 [255]
3513 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3523 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3514 hg: parse error: trailing \ in string
3524 hg: parse error: trailing \ in string
3515 [255]
3525 [255]
3516
3526
3517 $ cd ..
3527 $ cd ..
3518
3528
3519 Test leading backslashes:
3529 Test leading backslashes:
3520
3530
3521 $ cd latesttag
3531 $ cd latesttag
3522 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3532 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3523 {rev} {file}
3533 {rev} {file}
3524 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3534 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3525 \2 \head1
3535 \2 \head1
3526 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3536 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3527 \{rev} \{file}
3537 \{rev} \{file}
3528 $ cd ..
3538 $ cd ..
3529
3539
3530 Test leading backslashes in "if" expression (issue4714):
3540 Test leading backslashes in "if" expression (issue4714):
3531
3541
3532 $ cd latesttag
3542 $ cd latesttag
3533 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3543 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3534 {rev} \{rev}
3544 {rev} \{rev}
3535 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3545 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3536 \2 \\{rev}
3546 \2 \\{rev}
3537 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3547 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3538 \{rev} \\\{rev}
3548 \{rev} \\\{rev}
3539 $ cd ..
3549 $ cd ..
3540
3550
3541 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3551 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3542
3552
3543 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3553 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3544 \x6e
3554 \x6e
3545 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3555 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3546 \x5c\x786e
3556 \x5c\x786e
3547 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3557 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3548 \x6e
3558 \x6e
3549 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3559 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3550 \x5c\x786e
3560 \x5c\x786e
3551
3561
3552 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3562 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3553 \x6e
3563 \x6e
3554 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3564 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3555 \x5c\x786e
3565 \x5c\x786e
3556 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3566 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3557 \x6e
3567 \x6e
3558 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3568 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3559 \x5c\x786e
3569 \x5c\x786e
3560
3570
3561 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3571 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3562 fourth
3572 fourth
3563 second
3573 second
3564 third
3574 third
3565 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3575 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3566 fourth\nsecond\nthird
3576 fourth\nsecond\nthird
3567
3577
3568 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3578 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3569 <p>
3579 <p>
3570 1st
3580 1st
3571 </p>
3581 </p>
3572 <p>
3582 <p>
3573 2nd
3583 2nd
3574 </p>
3584 </p>
3575 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3585 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3576 <p>
3586 <p>
3577 1st\n\n2nd
3587 1st\n\n2nd
3578 </p>
3588 </p>
3579 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3589 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3580 1st
3590 1st
3581
3591
3582 2nd
3592 2nd
3583
3593
3584 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3594 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3585 o perso
3595 o perso
3586 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3596 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3587 no person
3597 no person
3588 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3598 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3589 o perso
3599 o perso
3590 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3600 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3591 no perso
3601 no perso
3592
3602
3593 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3603 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3594 -o perso-
3604 -o perso-
3595 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3605 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3596 no person
3606 no person
3597 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3607 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3598 \x2do perso\x2d
3608 \x2do perso\x2d
3599 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3609 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3600 -o perso-
3610 -o perso-
3601 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3611 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3602 \x2do perso\x6e
3612 \x2do perso\x6e
3603
3613
3604 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3614 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3605 fourth
3615 fourth
3606 second
3616 second
3607 third
3617 third
3608
3618
3609 Test string escaping in nested expression:
3619 Test string escaping in nested expression:
3610
3620
3611 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3621 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3612 fourth\x6esecond\x6ethird
3622 fourth\x6esecond\x6ethird
3613 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3623 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3614 fourth\x6esecond\x6ethird
3624 fourth\x6esecond\x6ethird
3615
3625
3616 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3626 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3617 fourth\x6esecond\x6ethird
3627 fourth\x6esecond\x6ethird
3618 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3628 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3619 fourth\x5c\x786esecond\x5c\x786ethird
3629 fourth\x5c\x786esecond\x5c\x786ethird
3620
3630
3621 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3631 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3622 3:\x6eo user, \x6eo domai\x6e
3632 3:\x6eo user, \x6eo domai\x6e
3623 4:\x5c\x786eew bra\x5c\x786ech
3633 4:\x5c\x786eew bra\x5c\x786ech
3624
3634
3625 Test quotes in nested expression are evaluated just like a $(command)
3635 Test quotes in nested expression are evaluated just like a $(command)
3626 substitution in POSIX shells:
3636 substitution in POSIX shells:
3627
3637
3628 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3638 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3629 8:95c24699272e
3639 8:95c24699272e
3630 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3640 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3631 {8} "95c24699272e"
3641 {8} "95c24699272e"
3632
3642
3633 Test recursive evaluation:
3643 Test recursive evaluation:
3634
3644
3635 $ hg init r
3645 $ hg init r
3636 $ cd r
3646 $ cd r
3637 $ echo a > a
3647 $ echo a > a
3638 $ hg ci -Am '{rev}'
3648 $ hg ci -Am '{rev}'
3639 adding a
3649 adding a
3640 $ hg log -r 0 --template '{if(rev, desc)}\n'
3650 $ hg log -r 0 --template '{if(rev, desc)}\n'
3641 {rev}
3651 {rev}
3642 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3652 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3643 test 0
3653 test 0
3644
3654
3645 $ hg branch -q 'text.{rev}'
3655 $ hg branch -q 'text.{rev}'
3646 $ echo aa >> aa
3656 $ echo aa >> aa
3647 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3657 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3648
3658
3649 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3659 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3650 {node|short}desc to
3660 {node|short}desc to
3651 text.{rev}be wrapped
3661 text.{rev}be wrapped
3652 text.{rev}desc to be
3662 text.{rev}desc to be
3653 text.{rev}wrapped (no-eol)
3663 text.{rev}wrapped (no-eol)
3654 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3664 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3655 bcc7ff960b8e:desc to
3665 bcc7ff960b8e:desc to
3656 text.1:be wrapped
3666 text.1:be wrapped
3657 text.1:desc to be
3667 text.1:desc to be
3658 text.1:wrapped (no-eol)
3668 text.1:wrapped (no-eol)
3659 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3669 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3660 hg: parse error: fill expects an integer width
3670 hg: parse error: fill expects an integer width
3661 [255]
3671 [255]
3662
3672
3663 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3673 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3664 bcc7ff960b8e:desc to be
3674 bcc7ff960b8e:desc to be
3665 termwidth.1:wrapped desc
3675 termwidth.1:wrapped desc
3666 termwidth.1:to be wrapped (no-eol)
3676 termwidth.1:to be wrapped (no-eol)
3667
3677
3668 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3678 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3669 {node|short} (no-eol)
3679 {node|short} (no-eol)
3670 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3680 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3671 bcc-ff---b-e (no-eol)
3681 bcc-ff---b-e (no-eol)
3672
3682
3673 $ cat >> .hg/hgrc <<EOF
3683 $ cat >> .hg/hgrc <<EOF
3674 > [extensions]
3684 > [extensions]
3675 > color=
3685 > color=
3676 > [color]
3686 > [color]
3677 > mode=ansi
3687 > mode=ansi
3678 > text.{rev} = red
3688 > text.{rev} = red
3679 > text.1 = green
3689 > text.1 = green
3680 > EOF
3690 > EOF
3681 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3691 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3682 \x1b[0;31mtext\x1b[0m (esc)
3692 \x1b[0;31mtext\x1b[0m (esc)
3683 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3693 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3684 \x1b[0;32mtext\x1b[0m (esc)
3694 \x1b[0;32mtext\x1b[0m (esc)
3685
3695
3686 color effect can be specified without quoting:
3696 color effect can be specified without quoting:
3687
3697
3688 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3698 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3689 \x1b[0;31mtext\x1b[0m (esc)
3699 \x1b[0;31mtext\x1b[0m (esc)
3690
3700
3691 color effects can be nested (issue5413)
3701 color effects can be nested (issue5413)
3692
3702
3693 $ hg debugtemplate --color=always \
3703 $ hg debugtemplate --color=always \
3694 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3704 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3695 \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)
3705 \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)
3696
3706
3697 pad() should interact well with color codes (issue5416)
3707 pad() should interact well with color codes (issue5416)
3698
3708
3699 $ hg debugtemplate --color=always \
3709 $ hg debugtemplate --color=always \
3700 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3710 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3701 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3711 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3702
3712
3703 label should be no-op if color is disabled:
3713 label should be no-op if color is disabled:
3704
3714
3705 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3715 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3706 text
3716 text
3707 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3717 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3708 text
3718 text
3709
3719
3710 Test branches inside if statement:
3720 Test branches inside if statement:
3711
3721
3712 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3722 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3713 no
3723 no
3714
3724
3715 Test dict constructor:
3725 Test dict constructor:
3716
3726
3717 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3727 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3718 y=f7769ec2ab97 x=0
3728 y=f7769ec2ab97 x=0
3719 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3729 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3720 x=0
3730 x=0
3721 y=f7769ec2ab97
3731 y=f7769ec2ab97
3722 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3732 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3723 {"x": 0, "y": "f7769ec2ab97"}
3733 {"x": 0, "y": "f7769ec2ab97"}
3724 $ hg log -r 0 -T '{dict()|json}\n'
3734 $ hg log -r 0 -T '{dict()|json}\n'
3725 {}
3735 {}
3726
3736
3727 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3737 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3728 rev=0 node=f7769ec2ab97
3738 rev=0 node=f7769ec2ab97
3729 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3739 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3730 rev=0 node=f7769ec2ab97
3740 rev=0 node=f7769ec2ab97
3731
3741
3732 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3742 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3733 hg: parse error: duplicated dict key 'rev' inferred
3743 hg: parse error: duplicated dict key 'rev' inferred
3734 [255]
3744 [255]
3735 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3745 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3736 hg: parse error: duplicated dict key 'node' inferred
3746 hg: parse error: duplicated dict key 'node' inferred
3737 [255]
3747 [255]
3738 $ hg log -r 0 -T '{dict(1 + 2)}'
3748 $ hg log -r 0 -T '{dict(1 + 2)}'
3739 hg: parse error: dict key cannot be inferred
3749 hg: parse error: dict key cannot be inferred
3740 [255]
3750 [255]
3741
3751
3742 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3752 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3743 hg: parse error: dict got multiple values for keyword argument 'x'
3753 hg: parse error: dict got multiple values for keyword argument 'x'
3744 [255]
3754 [255]
3745
3755
3746 Test get function:
3756 Test get function:
3747
3757
3748 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3758 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3749 default
3759 default
3750 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3760 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3751 default
3761 default
3752 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3762 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3753 hg: parse error: get() expects a dict as first argument
3763 hg: parse error: get() expects a dict as first argument
3754 [255]
3764 [255]
3755
3765
3756 Test json filter applied to hybrid object:
3766 Test json filter applied to hybrid object:
3757
3767
3758 $ hg log -r0 -T '{files|json}\n'
3768 $ hg log -r0 -T '{files|json}\n'
3759 ["a"]
3769 ["a"]
3760 $ hg log -r0 -T '{extras|json}\n'
3770 $ hg log -r0 -T '{extras|json}\n'
3761 {"branch": "default"}
3771 {"branch": "default"}
3762
3772
3763 Test localdate(date, tz) function:
3773 Test localdate(date, tz) function:
3764
3774
3765 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3775 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3766 1970-01-01 09:00 +0900
3776 1970-01-01 09:00 +0900
3767 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3777 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3768 1970-01-01 00:00 +0000
3778 1970-01-01 00:00 +0000
3769 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3779 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3770 hg: parse error: localdate expects a timezone
3780 hg: parse error: localdate expects a timezone
3771 [255]
3781 [255]
3772 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3782 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3773 1970-01-01 02:00 +0200
3783 1970-01-01 02:00 +0200
3774 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3784 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3775 1970-01-01 00:00 +0000
3785 1970-01-01 00:00 +0000
3776 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3786 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3777 1970-01-01 00:00 +0000
3787 1970-01-01 00:00 +0000
3778 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3788 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3779 hg: parse error: localdate expects a timezone
3789 hg: parse error: localdate expects a timezone
3780 [255]
3790 [255]
3781 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3791 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3782 hg: parse error: localdate expects a timezone
3792 hg: parse error: localdate expects a timezone
3783 [255]
3793 [255]
3784
3794
3785 Test shortest(node) function:
3795 Test shortest(node) function:
3786
3796
3787 $ echo b > b
3797 $ echo b > b
3788 $ hg ci -qAm b
3798 $ hg ci -qAm b
3789 $ hg log --template '{shortest(node)}\n'
3799 $ hg log --template '{shortest(node)}\n'
3790 e777
3800 e777
3791 bcc7
3801 bcc7
3792 f776
3802 f776
3793 $ hg log --template '{shortest(node, 10)}\n'
3803 $ hg log --template '{shortest(node, 10)}\n'
3794 e777603221
3804 e777603221
3795 bcc7ff960b
3805 bcc7ff960b
3796 f7769ec2ab
3806 f7769ec2ab
3797 $ hg log --template '{node|shortest}\n' -l1
3807 $ hg log --template '{node|shortest}\n' -l1
3798 e777
3808 e777
3799
3809
3800 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3810 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3801 f7769ec2ab
3811 f7769ec2ab
3802 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3812 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3803 hg: parse error: shortest() expects an integer minlength
3813 hg: parse error: shortest() expects an integer minlength
3804 [255]
3814 [255]
3805
3815
3806 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3816 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3807 ffff
3817 ffff
3808
3818
3809 $ cd ..
3819 $ cd ..
3810
3820
3811 Test shortest(node) with the repo having short hash collision:
3821 Test shortest(node) with the repo having short hash collision:
3812
3822
3813 $ hg init hashcollision
3823 $ hg init hashcollision
3814 $ cd hashcollision
3824 $ cd hashcollision
3815 $ cat <<EOF >> .hg/hgrc
3825 $ cat <<EOF >> .hg/hgrc
3816 > [experimental]
3826 > [experimental]
3817 > evolution.createmarkers=True
3827 > evolution.createmarkers=True
3818 > EOF
3828 > EOF
3819 $ echo 0 > a
3829 $ echo 0 > a
3820 $ hg ci -qAm 0
3830 $ hg ci -qAm 0
3821 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3831 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3822 > hg up -q 0
3832 > hg up -q 0
3823 > echo $i > a
3833 > echo $i > a
3824 > hg ci -qm $i
3834 > hg ci -qm $i
3825 > done
3835 > done
3826 $ hg up -q null
3836 $ hg up -q null
3827 $ hg log -r0: -T '{rev}:{node}\n'
3837 $ hg log -r0: -T '{rev}:{node}\n'
3828 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3838 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3829 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3839 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3830 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3840 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3831 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3841 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3832 4:10776689e627b465361ad5c296a20a487e153ca4
3842 4:10776689e627b465361ad5c296a20a487e153ca4
3833 5:a00be79088084cb3aff086ab799f8790e01a976b
3843 5:a00be79088084cb3aff086ab799f8790e01a976b
3834 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3844 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3835 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3845 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3836 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3846 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3837 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3847 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3838 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3848 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3839 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3849 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3840 obsoleted 1 changesets
3850 obsoleted 1 changesets
3841 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3851 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3842 obsoleted 1 changesets
3852 obsoleted 1 changesets
3843 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3853 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3844 obsoleted 1 changesets
3854 obsoleted 1 changesets
3845
3855
3846 nodes starting with '11' (we don't have the revision number '11' though)
3856 nodes starting with '11' (we don't have the revision number '11' though)
3847
3857
3848 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3858 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3849 1:1142
3859 1:1142
3850 2:1140
3860 2:1140
3851 3:11d
3861 3:11d
3852
3862
3853 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3863 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3854
3864
3855 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3865 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3856 6:a0b
3866 6:a0b
3857 7:a04
3867 7:a04
3858
3868
3859 node '10' conflicts with the revision number '10' even if it is hidden
3869 node '10' conflicts with the revision number '10' even if it is hidden
3860 (we could exclude hidden revision numbers, but currently we don't)
3870 (we could exclude hidden revision numbers, but currently we don't)
3861
3871
3862 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3872 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3863 4:107
3873 4:107
3864 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3874 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3865 4:107
3875 4:107
3866
3876
3867 node 'c562' should be unique if the other 'c562' nodes are hidden
3877 node 'c562' should be unique if the other 'c562' nodes are hidden
3868 (but we don't try the slow path to filter out hidden nodes for now)
3878 (but we don't try the slow path to filter out hidden nodes for now)
3869
3879
3870 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3880 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3871 8:c5625
3881 8:c5625
3872 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3882 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3873 8:c5625
3883 8:c5625
3874 9:c5623
3884 9:c5623
3875 10:c562d
3885 10:c562d
3876
3886
3877 $ cd ..
3887 $ cd ..
3878
3888
3879 Test pad function
3889 Test pad function
3880
3890
3881 $ cd r
3891 $ cd r
3882
3892
3883 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3893 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3884 2 test
3894 2 test
3885 1 {node|short}
3895 1 {node|short}
3886 0 test
3896 0 test
3887
3897
3888 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3898 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3889 2 test
3899 2 test
3890 1 {node|short}
3900 1 {node|short}
3891 0 test
3901 0 test
3892
3902
3893 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3903 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3894 2------------------- test
3904 2------------------- test
3895 1------------------- {node|short}
3905 1------------------- {node|short}
3896 0------------------- test
3906 0------------------- test
3897
3907
3898 Test template string in pad function
3908 Test template string in pad function
3899
3909
3900 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3910 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3901 {0} test
3911 {0} test
3902
3912
3903 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3913 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3904 \{rev} test
3914 \{rev} test
3905
3915
3906 Test width argument passed to pad function
3916 Test width argument passed to pad function
3907
3917
3908 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3918 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3909 0 test
3919 0 test
3910 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3920 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3911 hg: parse error: pad() expects an integer width
3921 hg: parse error: pad() expects an integer width
3912 [255]
3922 [255]
3913
3923
3914 Test invalid fillchar passed to pad function
3924 Test invalid fillchar passed to pad function
3915
3925
3916 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3926 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3917 hg: parse error: pad() expects a single fill character
3927 hg: parse error: pad() expects a single fill character
3918 [255]
3928 [255]
3919 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3929 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3920 hg: parse error: pad() expects a single fill character
3930 hg: parse error: pad() expects a single fill character
3921 [255]
3931 [255]
3922
3932
3923 Test boolean argument passed to pad function
3933 Test boolean argument passed to pad function
3924
3934
3925 no crash
3935 no crash
3926
3936
3927 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3937 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3928 ---------0
3938 ---------0
3929
3939
3930 string/literal
3940 string/literal
3931
3941
3932 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3942 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3933 ---------0
3943 ---------0
3934 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3944 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3935 0---------
3945 0---------
3936 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3946 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3937 0---------
3947 0---------
3938
3948
3939 unknown keyword is evaluated to ''
3949 unknown keyword is evaluated to ''
3940
3950
3941 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3951 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3942 0---------
3952 0---------
3943
3953
3944 Test separate function
3954 Test separate function
3945
3955
3946 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3956 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3947 a-b-c
3957 a-b-c
3948 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3958 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3949 0:f7769ec2ab97 test default
3959 0:f7769ec2ab97 test default
3950 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3960 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3951 a \x1b[0;31mb\x1b[0m c d (esc)
3961 a \x1b[0;31mb\x1b[0m c d (esc)
3952
3962
3953 Test boolean expression/literal passed to if function
3963 Test boolean expression/literal passed to if function
3954
3964
3955 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3965 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3956 rev 0 is True
3966 rev 0 is True
3957 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3967 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3958 literal 0 is True as well
3968 literal 0 is True as well
3959 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3969 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3960 empty string is False
3970 empty string is False
3961 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3971 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3962 empty list is False
3972 empty list is False
3963 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3973 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3964 true is True
3974 true is True
3965 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3975 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3966 false is False
3976 false is False
3967 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3977 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3968 non-empty string is True
3978 non-empty string is True
3969
3979
3970 Test ifcontains function
3980 Test ifcontains function
3971
3981
3972 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3982 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3973 2 is in the string
3983 2 is in the string
3974 1 is not
3984 1 is not
3975 0 is in the string
3985 0 is in the string
3976
3986
3977 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3987 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3978 2 is in the string
3988 2 is in the string
3979 1 is not
3989 1 is not
3980 0 is in the string
3990 0 is in the string
3981
3991
3982 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3992 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3983 2 did not add a
3993 2 did not add a
3984 1 did not add a
3994 1 did not add a
3985 0 added a
3995 0 added a
3986
3996
3987 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3997 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3988 2 is parent of 1
3998 2 is parent of 1
3989 1
3999 1
3990 0
4000 0
3991
4001
3992 Test revset function
4002 Test revset function
3993
4003
3994 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4004 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3995 2 current rev
4005 2 current rev
3996 1 not current rev
4006 1 not current rev
3997 0 not current rev
4007 0 not current rev
3998
4008
3999 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4009 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4000 2 match rev
4010 2 match rev
4001 1 match rev
4011 1 match rev
4002 0 not match rev
4012 0 not match rev
4003
4013
4004 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4014 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4005 type not match
4015 type not match
4006
4016
4007 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4017 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4008 2 Parents: 1
4018 2 Parents: 1
4009 1 Parents: 0
4019 1 Parents: 0
4010 0 Parents:
4020 0 Parents:
4011
4021
4012 $ cat >> .hg/hgrc <<EOF
4022 $ cat >> .hg/hgrc <<EOF
4013 > [revsetalias]
4023 > [revsetalias]
4014 > myparents(\$1) = parents(\$1)
4024 > myparents(\$1) = parents(\$1)
4015 > EOF
4025 > EOF
4016 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4026 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4017 2 Parents: 1
4027 2 Parents: 1
4018 1 Parents: 0
4028 1 Parents: 0
4019 0 Parents:
4029 0 Parents:
4020
4030
4021 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4031 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4022 Rev: 2
4032 Rev: 2
4023 Ancestor: 0
4033 Ancestor: 0
4024 Ancestor: 1
4034 Ancestor: 1
4025 Ancestor: 2
4035 Ancestor: 2
4026
4036
4027 Rev: 1
4037 Rev: 1
4028 Ancestor: 0
4038 Ancestor: 0
4029 Ancestor: 1
4039 Ancestor: 1
4030
4040
4031 Rev: 0
4041 Rev: 0
4032 Ancestor: 0
4042 Ancestor: 0
4033
4043
4034 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4044 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4035 2
4045 2
4036
4046
4037 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4047 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4038 2
4048 2
4039
4049
4040 a list template is evaluated for each item of revset/parents
4050 a list template is evaluated for each item of revset/parents
4041
4051
4042 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4052 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4043 2 p: 1:bcc7ff960b8e
4053 2 p: 1:bcc7ff960b8e
4044 1 p: 0:f7769ec2ab97
4054 1 p: 0:f7769ec2ab97
4045 0 p:
4055 0 p:
4046
4056
4047 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4057 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4048 2 p: 1:bcc7ff960b8e -1:000000000000
4058 2 p: 1:bcc7ff960b8e -1:000000000000
4049 1 p: 0:f7769ec2ab97 -1:000000000000
4059 1 p: 0:f7769ec2ab97 -1:000000000000
4050 0 p: -1:000000000000 -1:000000000000
4060 0 p: -1:000000000000 -1:000000000000
4051
4061
4052 therefore, 'revcache' should be recreated for each rev
4062 therefore, 'revcache' should be recreated for each rev
4053
4063
4054 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4064 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4055 2 aa b
4065 2 aa b
4056 p
4066 p
4057 1
4067 1
4058 p a
4068 p a
4059 0 a
4069 0 a
4060 p
4070 p
4061
4071
4062 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4072 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4063 2 aa b
4073 2 aa b
4064 p
4074 p
4065 1
4075 1
4066 p a
4076 p a
4067 0 a
4077 0 a
4068 p
4078 p
4069
4079
4070 a revset item must be evaluated as an integer revision, not an offset from tip
4080 a revset item must be evaluated as an integer revision, not an offset from tip
4071
4081
4072 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4082 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4073 -1:000000000000
4083 -1:000000000000
4074 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4084 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4075 -1:000000000000
4085 -1:000000000000
4076
4086
4077 join() should pick '{rev}' from revset items:
4087 join() should pick '{rev}' from revset items:
4078
4088
4079 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4089 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4080 4, 5
4090 4, 5
4081
4091
4082 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4092 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4083 default. join() should agree with the default formatting:
4093 default. join() should agree with the default formatting:
4084
4094
4085 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4095 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4086 5:13207e5a10d9, 4:bbe44766e73d
4096 5:13207e5a10d9, 4:bbe44766e73d
4087
4097
4088 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4098 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4089 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4099 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4090 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4100 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4091
4101
4092 Invalid arguments passed to revset()
4102 Invalid arguments passed to revset()
4093
4103
4094 $ hg log -T '{revset("%whatever", 0)}\n'
4104 $ hg log -T '{revset("%whatever", 0)}\n'
4095 hg: parse error: unexpected revspec format character w
4105 hg: parse error: unexpected revspec format character w
4096 [255]
4106 [255]
4097 $ hg log -T '{revset("%lwhatever", files)}\n'
4107 $ hg log -T '{revset("%lwhatever", files)}\n'
4098 hg: parse error: unexpected revspec format character w
4108 hg: parse error: unexpected revspec format character w
4099 [255]
4109 [255]
4100 $ hg log -T '{revset("%s %s", 0)}\n'
4110 $ hg log -T '{revset("%s %s", 0)}\n'
4101 hg: parse error: missing argument for revspec
4111 hg: parse error: missing argument for revspec
4102 [255]
4112 [255]
4103 $ hg log -T '{revset("", 0)}\n'
4113 $ hg log -T '{revset("", 0)}\n'
4104 hg: parse error: too many revspec arguments specified
4114 hg: parse error: too many revspec arguments specified
4105 [255]
4115 [255]
4106 $ hg log -T '{revset("%s", 0, 1)}\n'
4116 $ hg log -T '{revset("%s", 0, 1)}\n'
4107 hg: parse error: too many revspec arguments specified
4117 hg: parse error: too many revspec arguments specified
4108 [255]
4118 [255]
4109 $ hg log -T '{revset("%", 0)}\n'
4119 $ hg log -T '{revset("%", 0)}\n'
4110 hg: parse error: incomplete revspec format character
4120 hg: parse error: incomplete revspec format character
4111 [255]
4121 [255]
4112 $ hg log -T '{revset("%l", 0)}\n'
4122 $ hg log -T '{revset("%l", 0)}\n'
4113 hg: parse error: incomplete revspec format character
4123 hg: parse error: incomplete revspec format character
4114 [255]
4124 [255]
4115 $ hg log -T '{revset("%d", 'foo')}\n'
4125 $ hg log -T '{revset("%d", 'foo')}\n'
4116 hg: parse error: invalid argument for revspec
4126 hg: parse error: invalid argument for revspec
4117 [255]
4127 [255]
4118 $ hg log -T '{revset("%ld", files)}\n'
4128 $ hg log -T '{revset("%ld", files)}\n'
4119 hg: parse error: invalid argument for revspec
4129 hg: parse error: invalid argument for revspec
4120 [255]
4130 [255]
4121 $ hg log -T '{revset("%ls", 0)}\n'
4131 $ hg log -T '{revset("%ls", 0)}\n'
4122 hg: parse error: invalid argument for revspec
4132 hg: parse error: invalid argument for revspec
4123 [255]
4133 [255]
4124 $ hg log -T '{revset("%b", 'foo')}\n'
4134 $ hg log -T '{revset("%b", 'foo')}\n'
4125 hg: parse error: invalid argument for revspec
4135 hg: parse error: invalid argument for revspec
4126 [255]
4136 [255]
4127 $ hg log -T '{revset("%lb", files)}\n'
4137 $ hg log -T '{revset("%lb", files)}\n'
4128 hg: parse error: invalid argument for revspec
4138 hg: parse error: invalid argument for revspec
4129 [255]
4139 [255]
4130 $ hg log -T '{revset("%r", 0)}\n'
4140 $ hg log -T '{revset("%r", 0)}\n'
4131 hg: parse error: invalid argument for revspec
4141 hg: parse error: invalid argument for revspec
4132 [255]
4142 [255]
4133
4143
4134 Test files function
4144 Test files function
4135
4145
4136 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4146 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4137 2
4147 2
4138 a
4148 a
4139 aa
4149 aa
4140 b
4150 b
4141 1
4151 1
4142 a
4152 a
4143 0
4153 0
4144 a
4154 a
4145
4155
4146 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4156 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4147 2
4157 2
4148 aa
4158 aa
4149 1
4159 1
4150
4160
4151 0
4161 0
4152
4162
4153
4163
4154 Test relpath function
4164 Test relpath function
4155
4165
4156 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4166 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4157 a
4167 a
4158 $ cd ..
4168 $ cd ..
4159 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4169 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4160 r/a
4170 r/a
4161 $ cd r
4171 $ cd r
4162
4172
4163 Test active bookmark templating
4173 Test active bookmark templating
4164
4174
4165 $ hg book foo
4175 $ hg book foo
4166 $ hg book bar
4176 $ hg book bar
4167 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4177 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4168 2 bar* foo
4178 2 bar* foo
4169 1
4179 1
4170 0
4180 0
4171 $ hg log --template "{rev} {activebookmark}\n"
4181 $ hg log --template "{rev} {activebookmark}\n"
4172 2 bar
4182 2 bar
4173 1
4183 1
4174 0
4184 0
4175 $ hg bookmarks --inactive bar
4185 $ hg bookmarks --inactive bar
4176 $ hg log --template "{rev} {activebookmark}\n"
4186 $ hg log --template "{rev} {activebookmark}\n"
4177 2
4187 2
4178 1
4188 1
4179 0
4189 0
4180 $ hg book -r1 baz
4190 $ hg book -r1 baz
4181 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4191 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4182 2 bar foo
4192 2 bar foo
4183 1 baz
4193 1 baz
4184 0
4194 0
4185 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4195 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4186 2 t
4196 2 t
4187 1 f
4197 1 f
4188 0 f
4198 0 f
4189
4199
4190 Test namespaces dict
4200 Test namespaces dict
4191
4201
4192 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4202 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4193 2
4203 2
4194 bookmarks color=bookmark builtin=True
4204 bookmarks color=bookmark builtin=True
4195 bar,foo
4205 bar,foo
4196 tags color=tag builtin=True
4206 tags color=tag builtin=True
4197 tip
4207 tip
4198 branches color=branch builtin=True
4208 branches color=branch builtin=True
4199 text.{rev}
4209 text.{rev}
4200 revnames color=revname builtin=False
4210 revnames color=revname builtin=False
4201 r2
4211 r2
4202
4212
4203 1
4213 1
4204 bookmarks color=bookmark builtin=True
4214 bookmarks color=bookmark builtin=True
4205 baz
4215 baz
4206 tags color=tag builtin=True
4216 tags color=tag builtin=True
4207
4217
4208 branches color=branch builtin=True
4218 branches color=branch builtin=True
4209 text.{rev}
4219 text.{rev}
4210 revnames color=revname builtin=False
4220 revnames color=revname builtin=False
4211 r1
4221 r1
4212
4222
4213 0
4223 0
4214 bookmarks color=bookmark builtin=True
4224 bookmarks color=bookmark builtin=True
4215
4225
4216 tags color=tag builtin=True
4226 tags color=tag builtin=True
4217
4227
4218 branches color=branch builtin=True
4228 branches color=branch builtin=True
4219 default
4229 default
4220 revnames color=revname builtin=False
4230 revnames color=revname builtin=False
4221 r0
4231 r0
4222
4232
4223 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4233 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4224 bookmarks: bar foo
4234 bookmarks: bar foo
4225 tags: tip
4235 tags: tip
4226 branches: text.{rev}
4236 branches: text.{rev}
4227 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4237 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4228 bookmarks:
4238 bookmarks:
4229 bar
4239 bar
4230 foo
4240 foo
4231 tags:
4241 tags:
4232 tip
4242 tip
4233 branches:
4243 branches:
4234 text.{rev}
4244 text.{rev}
4235 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4245 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4236 bar
4246 bar
4237 foo
4247 foo
4238 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4248 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4239 bar
4249 bar
4240 foo
4250 foo
4241
4251
4242 Test stringify on sub expressions
4252 Test stringify on sub expressions
4243
4253
4244 $ cd ..
4254 $ cd ..
4245 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4255 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4246 fourth, second, third
4256 fourth, second, third
4247 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4257 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4248 abc
4258 abc
4249
4259
4250 Test splitlines
4260 Test splitlines
4251
4261
4252 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4262 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4253 @ foo Modify, add, remove, rename
4263 @ foo Modify, add, remove, rename
4254 |
4264 |
4255 o foo future
4265 o foo future
4256 |
4266 |
4257 o foo third
4267 o foo third
4258 |
4268 |
4259 o foo second
4269 o foo second
4260
4270
4261 o foo merge
4271 o foo merge
4262 |\
4272 |\
4263 | o foo new head
4273 | o foo new head
4264 | |
4274 | |
4265 o | foo new branch
4275 o | foo new branch
4266 |/
4276 |/
4267 o foo no user, no domain
4277 o foo no user, no domain
4268 |
4278 |
4269 o foo no person
4279 o foo no person
4270 |
4280 |
4271 o foo other 1
4281 o foo other 1
4272 | foo other 2
4282 | foo other 2
4273 | foo
4283 | foo
4274 | foo other 3
4284 | foo other 3
4275 o foo line 1
4285 o foo line 1
4276 foo line 2
4286 foo line 2
4277
4287
4278 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4288 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4279 line 1 line 2
4289 line 1 line 2
4280 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4290 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4281 line 1|line 2
4291 line 1|line 2
4282
4292
4283 Test startswith
4293 Test startswith
4284 $ hg log -Gv -R a --template "{startswith(desc)}"
4294 $ hg log -Gv -R a --template "{startswith(desc)}"
4285 hg: parse error: startswith expects two arguments
4295 hg: parse error: startswith expects two arguments
4286 [255]
4296 [255]
4287
4297
4288 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4298 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4289 @
4299 @
4290 |
4300 |
4291 o
4301 o
4292 |
4302 |
4293 o
4303 o
4294 |
4304 |
4295 o
4305 o
4296
4306
4297 o
4307 o
4298 |\
4308 |\
4299 | o
4309 | o
4300 | |
4310 | |
4301 o |
4311 o |
4302 |/
4312 |/
4303 o
4313 o
4304 |
4314 |
4305 o
4315 o
4306 |
4316 |
4307 o
4317 o
4308 |
4318 |
4309 o line 1
4319 o line 1
4310 line 2
4320 line 2
4311
4321
4312 Test bad template with better error message
4322 Test bad template with better error message
4313
4323
4314 $ hg log -Gv -R a --template '{desc|user()}'
4324 $ hg log -Gv -R a --template '{desc|user()}'
4315 hg: parse error: expected a symbol, got 'func'
4325 hg: parse error: expected a symbol, got 'func'
4316 [255]
4326 [255]
4317
4327
4318 Test word function (including index out of bounds graceful failure)
4328 Test word function (including index out of bounds graceful failure)
4319
4329
4320 $ hg log -Gv -R a --template "{word('1', desc)}"
4330 $ hg log -Gv -R a --template "{word('1', desc)}"
4321 @ add,
4331 @ add,
4322 |
4332 |
4323 o
4333 o
4324 |
4334 |
4325 o
4335 o
4326 |
4336 |
4327 o
4337 o
4328
4338
4329 o
4339 o
4330 |\
4340 |\
4331 | o head
4341 | o head
4332 | |
4342 | |
4333 o | branch
4343 o | branch
4334 |/
4344 |/
4335 o user,
4345 o user,
4336 |
4346 |
4337 o person
4347 o person
4338 |
4348 |
4339 o 1
4349 o 1
4340 |
4350 |
4341 o 1
4351 o 1
4342
4352
4343
4353
4344 Test word third parameter used as splitter
4354 Test word third parameter used as splitter
4345
4355
4346 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4356 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4347 @ M
4357 @ M
4348 |
4358 |
4349 o future
4359 o future
4350 |
4360 |
4351 o third
4361 o third
4352 |
4362 |
4353 o sec
4363 o sec
4354
4364
4355 o merge
4365 o merge
4356 |\
4366 |\
4357 | o new head
4367 | o new head
4358 | |
4368 | |
4359 o | new branch
4369 o | new branch
4360 |/
4370 |/
4361 o n
4371 o n
4362 |
4372 |
4363 o n
4373 o n
4364 |
4374 |
4365 o
4375 o
4366 |
4376 |
4367 o line 1
4377 o line 1
4368 line 2
4378 line 2
4369
4379
4370 Test word error messages for not enough and too many arguments
4380 Test word error messages for not enough and too many arguments
4371
4381
4372 $ hg log -Gv -R a --template "{word('0')}"
4382 $ hg log -Gv -R a --template "{word('0')}"
4373 hg: parse error: word expects two or three arguments, got 1
4383 hg: parse error: word expects two or three arguments, got 1
4374 [255]
4384 [255]
4375
4385
4376 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4386 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4377 hg: parse error: word expects two or three arguments, got 7
4387 hg: parse error: word expects two or three arguments, got 7
4378 [255]
4388 [255]
4379
4389
4380 Test word for integer literal
4390 Test word for integer literal
4381
4391
4382 $ hg log -R a --template "{word(2, desc)}\n" -r0
4392 $ hg log -R a --template "{word(2, desc)}\n" -r0
4383 line
4393 line
4384
4394
4385 Test word for invalid numbers
4395 Test word for invalid numbers
4386
4396
4387 $ hg log -Gv -R a --template "{word('a', desc)}"
4397 $ hg log -Gv -R a --template "{word('a', desc)}"
4388 hg: parse error: word expects an integer index
4398 hg: parse error: word expects an integer index
4389 [255]
4399 [255]
4390
4400
4391 Test word for out of range
4401 Test word for out of range
4392
4402
4393 $ hg log -R a --template "{word(10000, desc)}"
4403 $ hg log -R a --template "{word(10000, desc)}"
4394 $ hg log -R a --template "{word(-10000, desc)}"
4404 $ hg log -R a --template "{word(-10000, desc)}"
4395
4405
4396 Test indent and not adding to empty lines
4406 Test indent and not adding to empty lines
4397
4407
4398 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4408 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4399 -----
4409 -----
4400 > line 1
4410 > line 1
4401 >> line 2
4411 >> line 2
4402 -----
4412 -----
4403 > other 1
4413 > other 1
4404 >> other 2
4414 >> other 2
4405
4415
4406 >> other 3
4416 >> other 3
4407
4417
4408 Test with non-strings like dates
4418 Test with non-strings like dates
4409
4419
4410 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4420 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4411 1200000.00
4421 1200000.00
4412 1300000.00
4422 1300000.00
4413
4423
4414 Test broken string escapes:
4424 Test broken string escapes:
4415
4425
4416 $ hg log -T "bogus\\" -R a
4426 $ hg log -T "bogus\\" -R a
4417 hg: parse error: trailing \ in string
4427 hg: parse error: trailing \ in string
4418 [255]
4428 [255]
4419 $ hg log -T "\\xy" -R a
4429 $ hg log -T "\\xy" -R a
4420 hg: parse error: invalid \x escape
4430 hg: parse error: invalid \x escape
4421 [255]
4431 [255]
4422
4432
4423 json filter should escape HTML tags so that the output can be embedded in hgweb:
4433 json filter should escape HTML tags so that the output can be embedded in hgweb:
4424
4434
4425 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4435 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4426 "\u003cfoo@example.org\u003e"
4436 "\u003cfoo@example.org\u003e"
4427
4437
4428 Templater supports aliases of symbol and func() styles:
4438 Templater supports aliases of symbol and func() styles:
4429
4439
4430 $ hg clone -q a aliases
4440 $ hg clone -q a aliases
4431 $ cd aliases
4441 $ cd aliases
4432 $ cat <<EOF >> .hg/hgrc
4442 $ cat <<EOF >> .hg/hgrc
4433 > [templatealias]
4443 > [templatealias]
4434 > r = rev
4444 > r = rev
4435 > rn = "{r}:{node|short}"
4445 > rn = "{r}:{node|short}"
4436 > status(c, files) = files % "{c} {file}\n"
4446 > status(c, files) = files % "{c} {file}\n"
4437 > utcdate(d) = localdate(d, "UTC")
4447 > utcdate(d) = localdate(d, "UTC")
4438 > EOF
4448 > EOF
4439
4449
4440 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4450 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4441 (template
4451 (template
4442 (symbol 'rn')
4452 (symbol 'rn')
4443 (string ' ')
4453 (string ' ')
4444 (|
4454 (|
4445 (func
4455 (func
4446 (symbol 'utcdate')
4456 (symbol 'utcdate')
4447 (symbol 'date'))
4457 (symbol 'date'))
4448 (symbol 'isodate'))
4458 (symbol 'isodate'))
4449 (string '\n'))
4459 (string '\n'))
4450 * expanded:
4460 * expanded:
4451 (template
4461 (template
4452 (template
4462 (template
4453 (symbol 'rev')
4463 (symbol 'rev')
4454 (string ':')
4464 (string ':')
4455 (|
4465 (|
4456 (symbol 'node')
4466 (symbol 'node')
4457 (symbol 'short')))
4467 (symbol 'short')))
4458 (string ' ')
4468 (string ' ')
4459 (|
4469 (|
4460 (func
4470 (func
4461 (symbol 'localdate')
4471 (symbol 'localdate')
4462 (list
4472 (list
4463 (symbol 'date')
4473 (symbol 'date')
4464 (string 'UTC')))
4474 (string 'UTC')))
4465 (symbol 'isodate'))
4475 (symbol 'isodate'))
4466 (string '\n'))
4476 (string '\n'))
4467 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4477 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4468
4478
4469 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4479 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4470 (template
4480 (template
4471 (func
4481 (func
4472 (symbol 'status')
4482 (symbol 'status')
4473 (list
4483 (list
4474 (string 'A')
4484 (string 'A')
4475 (symbol 'file_adds'))))
4485 (symbol 'file_adds'))))
4476 * expanded:
4486 * expanded:
4477 (template
4487 (template
4478 (%
4488 (%
4479 (symbol 'file_adds')
4489 (symbol 'file_adds')
4480 (template
4490 (template
4481 (string 'A')
4491 (string 'A')
4482 (string ' ')
4492 (string ' ')
4483 (symbol 'file')
4493 (symbol 'file')
4484 (string '\n'))))
4494 (string '\n'))))
4485 A a
4495 A a
4486
4496
4487 A unary function alias can be called as a filter:
4497 A unary function alias can be called as a filter:
4488
4498
4489 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4499 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4490 (template
4500 (template
4491 (|
4501 (|
4492 (|
4502 (|
4493 (symbol 'date')
4503 (symbol 'date')
4494 (symbol 'utcdate'))
4504 (symbol 'utcdate'))
4495 (symbol 'isodate'))
4505 (symbol 'isodate'))
4496 (string '\n'))
4506 (string '\n'))
4497 * expanded:
4507 * expanded:
4498 (template
4508 (template
4499 (|
4509 (|
4500 (func
4510 (func
4501 (symbol 'localdate')
4511 (symbol 'localdate')
4502 (list
4512 (list
4503 (symbol 'date')
4513 (symbol 'date')
4504 (string 'UTC')))
4514 (string 'UTC')))
4505 (symbol 'isodate'))
4515 (symbol 'isodate'))
4506 (string '\n'))
4516 (string '\n'))
4507 1970-01-12 13:46 +0000
4517 1970-01-12 13:46 +0000
4508
4518
4509 Aliases should be applied only to command arguments and templates in hgrc.
4519 Aliases should be applied only to command arguments and templates in hgrc.
4510 Otherwise, our stock styles and web templates could be corrupted:
4520 Otherwise, our stock styles and web templates could be corrupted:
4511
4521
4512 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4522 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4513 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4523 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4514
4524
4515 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4525 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4516 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4526 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4517
4527
4518 $ cat <<EOF > tmpl
4528 $ cat <<EOF > tmpl
4519 > changeset = 'nothing expanded:{rn}\n'
4529 > changeset = 'nothing expanded:{rn}\n'
4520 > EOF
4530 > EOF
4521 $ hg log -r0 --style ./tmpl
4531 $ hg log -r0 --style ./tmpl
4522 nothing expanded:
4532 nothing expanded:
4523
4533
4524 Aliases in formatter:
4534 Aliases in formatter:
4525
4535
4526 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4536 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4527 default 6:d41e714fe50d
4537 default 6:d41e714fe50d
4528 foo 4:bbe44766e73d
4538 foo 4:bbe44766e73d
4529
4539
4530 Aliases should honor HGPLAIN:
4540 Aliases should honor HGPLAIN:
4531
4541
4532 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4542 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4533 nothing expanded:
4543 nothing expanded:
4534 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4544 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4535 0:1e4e1b8f71e0
4545 0:1e4e1b8f71e0
4536
4546
4537 Unparsable alias:
4547 Unparsable alias:
4538
4548
4539 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4549 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4540 (template
4550 (template
4541 (symbol 'bad'))
4551 (symbol 'bad'))
4542 abort: bad definition of template alias "bad": at 2: not a prefix: end
4552 abort: bad definition of template alias "bad": at 2: not a prefix: end
4543 [255]
4553 [255]
4544 $ hg log --config templatealias.bad='x(' -T '{bad}'
4554 $ hg log --config templatealias.bad='x(' -T '{bad}'
4545 abort: bad definition of template alias "bad": at 2: not a prefix: end
4555 abort: bad definition of template alias "bad": at 2: not a prefix: end
4546 [255]
4556 [255]
4547
4557
4548 $ cd ..
4558 $ cd ..
4549
4559
4550 Set up repository for non-ascii encoding tests:
4560 Set up repository for non-ascii encoding tests:
4551
4561
4552 $ hg init nonascii
4562 $ hg init nonascii
4553 $ cd nonascii
4563 $ cd nonascii
4554 $ $PYTHON <<EOF
4564 $ $PYTHON <<EOF
4555 > open('latin1', 'w').write('\xe9')
4565 > open('latin1', 'w').write('\xe9')
4556 > open('utf-8', 'w').write('\xc3\xa9')
4566 > open('utf-8', 'w').write('\xc3\xa9')
4557 > EOF
4567 > EOF
4558 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4568 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4559 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4569 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4560
4570
4561 json filter should try round-trip conversion to utf-8:
4571 json filter should try round-trip conversion to utf-8:
4562
4572
4563 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4573 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4564 "\u00e9"
4574 "\u00e9"
4565 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4575 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4566 "non-ascii branch: \u00e9"
4576 "non-ascii branch: \u00e9"
4567
4577
4568 json filter takes input as utf-8b:
4578 json filter takes input as utf-8b:
4569
4579
4570 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4580 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4571 "\u00e9"
4581 "\u00e9"
4572 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4582 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4573 "\udce9"
4583 "\udce9"
4574
4584
4575 utf8 filter:
4585 utf8 filter:
4576
4586
4577 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4587 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4578 round-trip: c3a9
4588 round-trip: c3a9
4579 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4589 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4580 decoded: c3a9
4590 decoded: c3a9
4581 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4591 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4582 abort: decoding near * (glob)
4592 abort: decoding near * (glob)
4583 [255]
4593 [255]
4584 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4594 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4585 abort: template filter 'utf8' is not compatible with keyword 'rev'
4595 abort: template filter 'utf8' is not compatible with keyword 'rev'
4586 [255]
4596 [255]
4587
4597
4588 pad width:
4598 pad width:
4589
4599
4590 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4600 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4591 \xc3\xa9- (esc)
4601 \xc3\xa9- (esc)
4592
4602
4593 $ cd ..
4603 $ cd ..
4594
4604
4595 Test that template function in extension is registered as expected
4605 Test that template function in extension is registered as expected
4596
4606
4597 $ cd a
4607 $ cd a
4598
4608
4599 $ cat <<EOF > $TESTTMP/customfunc.py
4609 $ cat <<EOF > $TESTTMP/customfunc.py
4600 > from mercurial import registrar
4610 > from mercurial import registrar
4601 >
4611 >
4602 > templatefunc = registrar.templatefunc()
4612 > templatefunc = registrar.templatefunc()
4603 >
4613 >
4604 > @templatefunc('custom()')
4614 > @templatefunc('custom()')
4605 > def custom(context, mapping, args):
4615 > def custom(context, mapping, args):
4606 > return 'custom'
4616 > return 'custom'
4607 > EOF
4617 > EOF
4608 $ cat <<EOF > .hg/hgrc
4618 $ cat <<EOF > .hg/hgrc
4609 > [extensions]
4619 > [extensions]
4610 > customfunc = $TESTTMP/customfunc.py
4620 > customfunc = $TESTTMP/customfunc.py
4611 > EOF
4621 > EOF
4612
4622
4613 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4623 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4614 custom
4624 custom
4615
4625
4616 $ cd ..
4626 $ cd ..
4617
4627
4618 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4628 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4619 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4629 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4620 columns. We don't care about other aspects of the graph rendering here.
4630 columns. We don't care about other aspects of the graph rendering here.
4621
4631
4622 $ hg init graphwidth
4632 $ hg init graphwidth
4623 $ cd graphwidth
4633 $ cd graphwidth
4624
4634
4625 $ wrappabletext="a a a a a a a a a a a a"
4635 $ wrappabletext="a a a a a a a a a a a a"
4626
4636
4627 $ printf "first\n" > file
4637 $ printf "first\n" > file
4628 $ hg add file
4638 $ hg add file
4629 $ hg commit -m "$wrappabletext"
4639 $ hg commit -m "$wrappabletext"
4630
4640
4631 $ printf "first\nsecond\n" > file
4641 $ printf "first\nsecond\n" > file
4632 $ hg commit -m "$wrappabletext"
4642 $ hg commit -m "$wrappabletext"
4633
4643
4634 $ hg checkout 0
4644 $ hg checkout 0
4635 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4645 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4636 $ printf "third\nfirst\n" > file
4646 $ printf "third\nfirst\n" > file
4637 $ hg commit -m "$wrappabletext"
4647 $ hg commit -m "$wrappabletext"
4638 created new head
4648 created new head
4639
4649
4640 $ hg merge
4650 $ hg merge
4641 merging file
4651 merging file
4642 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4652 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4643 (branch merge, don't forget to commit)
4653 (branch merge, don't forget to commit)
4644
4654
4645 $ hg log --graph -T "{graphwidth}"
4655 $ hg log --graph -T "{graphwidth}"
4646 @ 3
4656 @ 3
4647 |
4657 |
4648 | @ 5
4658 | @ 5
4649 |/
4659 |/
4650 o 3
4660 o 3
4651
4661
4652 $ hg commit -m "$wrappabletext"
4662 $ hg commit -m "$wrappabletext"
4653
4663
4654 $ hg log --graph -T "{graphwidth}"
4664 $ hg log --graph -T "{graphwidth}"
4655 @ 5
4665 @ 5
4656 |\
4666 |\
4657 | o 5
4667 | o 5
4658 | |
4668 | |
4659 o | 5
4669 o | 5
4660 |/
4670 |/
4661 o 3
4671 o 3
4662
4672
4663
4673
4664 $ hg checkout 0
4674 $ hg checkout 0
4665 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4675 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4666 $ printf "third\nfirst\nsecond\n" > file
4676 $ printf "third\nfirst\nsecond\n" > file
4667 $ hg commit -m "$wrappabletext"
4677 $ hg commit -m "$wrappabletext"
4668 created new head
4678 created new head
4669
4679
4670 $ hg log --graph -T "{graphwidth}"
4680 $ hg log --graph -T "{graphwidth}"
4671 @ 3
4681 @ 3
4672 |
4682 |
4673 | o 7
4683 | o 7
4674 | |\
4684 | |\
4675 +---o 7
4685 +---o 7
4676 | |
4686 | |
4677 | o 5
4687 | o 5
4678 |/
4688 |/
4679 o 3
4689 o 3
4680
4690
4681
4691
4682 $ hg log --graph -T "{graphwidth}" -r 3
4692 $ hg log --graph -T "{graphwidth}" -r 3
4683 o 5
4693 o 5
4684 |\
4694 |\
4685 ~ ~
4695 ~ ~
4686
4696
4687 $ hg log --graph -T "{graphwidth}" -r 1
4697 $ hg log --graph -T "{graphwidth}" -r 1
4688 o 3
4698 o 3
4689 |
4699 |
4690 ~
4700 ~
4691
4701
4692 $ hg merge
4702 $ hg merge
4693 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4703 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4694 (branch merge, don't forget to commit)
4704 (branch merge, don't forget to commit)
4695 $ hg commit -m "$wrappabletext"
4705 $ hg commit -m "$wrappabletext"
4696
4706
4697 $ printf "seventh\n" >> file
4707 $ printf "seventh\n" >> file
4698 $ hg commit -m "$wrappabletext"
4708 $ hg commit -m "$wrappabletext"
4699
4709
4700 $ hg log --graph -T "{graphwidth}"
4710 $ hg log --graph -T "{graphwidth}"
4701 @ 3
4711 @ 3
4702 |
4712 |
4703 o 5
4713 o 5
4704 |\
4714 |\
4705 | o 5
4715 | o 5
4706 | |
4716 | |
4707 o | 7
4717 o | 7
4708 |\ \
4718 |\ \
4709 | o | 7
4719 | o | 7
4710 | |/
4720 | |/
4711 o / 5
4721 o / 5
4712 |/
4722 |/
4713 o 3
4723 o 3
4714
4724
4715
4725
4716 The point of graphwidth is to allow wrapping that accounts for the space taken
4726 The point of graphwidth is to allow wrapping that accounts for the space taken
4717 by the graph.
4727 by the graph.
4718
4728
4719 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4729 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4720 @ a a a a
4730 @ a a a a
4721 | a a a a
4731 | a a a a
4722 | a a a a
4732 | a a a a
4723 o a a a
4733 o a a a
4724 |\ a a a
4734 |\ a a a
4725 | | a a a
4735 | | a a a
4726 | | a a a
4736 | | a a a
4727 | o a a a
4737 | o a a a
4728 | | a a a
4738 | | a a a
4729 | | a a a
4739 | | a a a
4730 | | a a a
4740 | | a a a
4731 o | a a
4741 o | a a
4732 |\ \ a a
4742 |\ \ a a
4733 | | | a a
4743 | | | a a
4734 | | | a a
4744 | | | a a
4735 | | | a a
4745 | | | a a
4736 | | | a a
4746 | | | a a
4737 | o | a a
4747 | o | a a
4738 | |/ a a
4748 | |/ a a
4739 | | a a
4749 | | a a
4740 | | a a
4750 | | a a
4741 | | a a
4751 | | a a
4742 | | a a
4752 | | a a
4743 o | a a a
4753 o | a a a
4744 |/ a a a
4754 |/ a a a
4745 | a a a
4755 | a a a
4746 | a a a
4756 | a a a
4747 o a a a a
4757 o a a a a
4748 a a a a
4758 a a a a
4749 a a a a
4759 a a a a
4750
4760
4751 Something tricky happens when there are elided nodes; the next drawn row of
4761 Something tricky happens when there are elided nodes; the next drawn row of
4752 edges can be more than one column wider, but the graph width only increases by
4762 edges can be more than one column wider, but the graph width only increases by
4753 one column. The remaining columns are added in between the nodes.
4763 one column. The remaining columns are added in between the nodes.
4754
4764
4755 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4765 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4756 o 5
4766 o 5
4757 |\
4767 |\
4758 | \
4768 | \
4759 | :\
4769 | :\
4760 o : : 7
4770 o : : 7
4761 :/ /
4771 :/ /
4762 : o 5
4772 : o 5
4763 :/
4773 :/
4764 o 3
4774 o 3
4765
4775
4766
4776
4767 $ cd ..
4777 $ cd ..
4768
4778
General Comments 0
You need to be logged in to leave comments. Login now