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