##// END OF EJS Templates
templater: adjust binding strength of '%' and '|' operators (BC)...
Yuya Nishihara -
r34330:63673183 default
parent child Browse files
Show More
@@ -1,1448 +1,1448
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import os
10 import os
11 import re
11 import re
12 import types
12 import types
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 color,
16 color,
17 config,
17 config,
18 encoding,
18 encoding,
19 error,
19 error,
20 minirst,
20 minirst,
21 obsutil,
21 obsutil,
22 parser,
22 parser,
23 pycompat,
23 pycompat,
24 registrar,
24 registrar,
25 revset as revsetmod,
25 revset as revsetmod,
26 revsetlang,
26 revsetlang,
27 templatefilters,
27 templatefilters,
28 templatekw,
28 templatekw,
29 util,
29 util,
30 )
30 )
31
31
32 # template parsing
32 # template parsing
33
33
34 elements = {
34 elements = {
35 # token-type: binding-strength, primary, prefix, infix, suffix
35 # token-type: binding-strength, primary, prefix, infix, suffix
36 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
36 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
37 "%": (16, None, None, ("%", 16), None),
37 "%": (15, None, None, ("%", 15), None),
38 "|": (15, None, None, ("|", 15), None),
38 "|": (15, None, None, ("|", 15), None),
39 "*": (5, None, None, ("*", 5), None),
39 "*": (5, None, None, ("*", 5), None),
40 "/": (5, None, None, ("/", 5), None),
40 "/": (5, None, None, ("/", 5), None),
41 "+": (4, None, None, ("+", 4), None),
41 "+": (4, None, None, ("+", 4), None),
42 "-": (4, None, ("negate", 19), ("-", 4), None),
42 "-": (4, None, ("negate", 19), ("-", 4), None),
43 "=": (3, None, None, ("keyvalue", 3), None),
43 "=": (3, None, None, ("keyvalue", 3), None),
44 ",": (2, None, None, ("list", 2), None),
44 ",": (2, None, None, ("list", 2), None),
45 ")": (0, None, None, None, None),
45 ")": (0, None, None, None, None),
46 "integer": (0, "integer", None, None, None),
46 "integer": (0, "integer", None, None, None),
47 "symbol": (0, "symbol", None, None, None),
47 "symbol": (0, "symbol", None, None, None),
48 "string": (0, "string", None, None, None),
48 "string": (0, "string", None, None, None),
49 "template": (0, "template", None, None, None),
49 "template": (0, "template", None, None, None),
50 "end": (0, None, None, None, None),
50 "end": (0, None, None, None, None),
51 }
51 }
52
52
53 def tokenize(program, start, end, term=None):
53 def tokenize(program, start, end, term=None):
54 """Parse a template expression into a stream of tokens, which must end
54 """Parse a template expression into a stream of tokens, which must end
55 with term if specified"""
55 with term if specified"""
56 pos = start
56 pos = start
57 program = pycompat.bytestr(program)
57 program = pycompat.bytestr(program)
58 while pos < end:
58 while pos < end:
59 c = program[pos]
59 c = program[pos]
60 if c.isspace(): # skip inter-token whitespace
60 if c.isspace(): # skip inter-token whitespace
61 pass
61 pass
62 elif c in "(=,)%|+-*/": # handle simple operators
62 elif c in "(=,)%|+-*/": # handle simple operators
63 yield (c, None, pos)
63 yield (c, None, pos)
64 elif c in '"\'': # handle quoted templates
64 elif c in '"\'': # handle quoted templates
65 s = pos + 1
65 s = pos + 1
66 data, pos = _parsetemplate(program, s, end, c)
66 data, pos = _parsetemplate(program, s, end, c)
67 yield ('template', data, s)
67 yield ('template', data, s)
68 pos -= 1
68 pos -= 1
69 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
69 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
70 # handle quoted strings
70 # handle quoted strings
71 c = program[pos + 1]
71 c = program[pos + 1]
72 s = pos = pos + 2
72 s = pos = pos + 2
73 while pos < end: # find closing quote
73 while pos < end: # find closing quote
74 d = program[pos]
74 d = program[pos]
75 if d == '\\': # skip over escaped characters
75 if d == '\\': # skip over escaped characters
76 pos += 2
76 pos += 2
77 continue
77 continue
78 if d == c:
78 if d == c:
79 yield ('string', program[s:pos], s)
79 yield ('string', program[s:pos], s)
80 break
80 break
81 pos += 1
81 pos += 1
82 else:
82 else:
83 raise error.ParseError(_("unterminated string"), s)
83 raise error.ParseError(_("unterminated string"), s)
84 elif c.isdigit():
84 elif c.isdigit():
85 s = pos
85 s = pos
86 while pos < end:
86 while pos < end:
87 d = program[pos]
87 d = program[pos]
88 if not d.isdigit():
88 if not d.isdigit():
89 break
89 break
90 pos += 1
90 pos += 1
91 yield ('integer', program[s:pos], s)
91 yield ('integer', program[s:pos], s)
92 pos -= 1
92 pos -= 1
93 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
93 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
94 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
94 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
95 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
95 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
96 # where some of nested templates were preprocessed as strings and
96 # where some of nested templates were preprocessed as strings and
97 # then compiled. therefore, \"...\" was allowed. (issue4733)
97 # then compiled. therefore, \"...\" was allowed. (issue4733)
98 #
98 #
99 # processing flow of _evalifliteral() at 5ab28a2e9962:
99 # processing flow of _evalifliteral() at 5ab28a2e9962:
100 # outer template string -> stringify() -> compiletemplate()
100 # outer template string -> stringify() -> compiletemplate()
101 # ------------------------ ------------ ------------------
101 # ------------------------ ------------ ------------------
102 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
102 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
103 # ~~~~~~~~
103 # ~~~~~~~~
104 # escaped quoted string
104 # escaped quoted string
105 if c == 'r':
105 if c == 'r':
106 pos += 1
106 pos += 1
107 token = 'string'
107 token = 'string'
108 else:
108 else:
109 token = 'template'
109 token = 'template'
110 quote = program[pos:pos + 2]
110 quote = program[pos:pos + 2]
111 s = pos = pos + 2
111 s = pos = pos + 2
112 while pos < end: # find closing escaped quote
112 while pos < end: # find closing escaped quote
113 if program.startswith('\\\\\\', pos, end):
113 if program.startswith('\\\\\\', pos, end):
114 pos += 4 # skip over double escaped characters
114 pos += 4 # skip over double escaped characters
115 continue
115 continue
116 if program.startswith(quote, pos, end):
116 if program.startswith(quote, pos, end):
117 # interpret as if it were a part of an outer string
117 # interpret as if it were a part of an outer string
118 data = parser.unescapestr(program[s:pos])
118 data = parser.unescapestr(program[s:pos])
119 if token == 'template':
119 if token == 'template':
120 data = _parsetemplate(data, 0, len(data))[0]
120 data = _parsetemplate(data, 0, len(data))[0]
121 yield (token, data, s)
121 yield (token, data, s)
122 pos += 1
122 pos += 1
123 break
123 break
124 pos += 1
124 pos += 1
125 else:
125 else:
126 raise error.ParseError(_("unterminated string"), s)
126 raise error.ParseError(_("unterminated string"), s)
127 elif c.isalnum() or c in '_':
127 elif c.isalnum() or c in '_':
128 s = pos
128 s = pos
129 pos += 1
129 pos += 1
130 while pos < end: # find end of symbol
130 while pos < end: # find end of symbol
131 d = program[pos]
131 d = program[pos]
132 if not (d.isalnum() or d == "_"):
132 if not (d.isalnum() or d == "_"):
133 break
133 break
134 pos += 1
134 pos += 1
135 sym = program[s:pos]
135 sym = program[s:pos]
136 yield ('symbol', sym, s)
136 yield ('symbol', sym, s)
137 pos -= 1
137 pos -= 1
138 elif c == term:
138 elif c == term:
139 yield ('end', None, pos + 1)
139 yield ('end', None, pos + 1)
140 return
140 return
141 else:
141 else:
142 raise error.ParseError(_("syntax error"), pos)
142 raise error.ParseError(_("syntax error"), pos)
143 pos += 1
143 pos += 1
144 if term:
144 if term:
145 raise error.ParseError(_("unterminated template expansion"), start)
145 raise error.ParseError(_("unterminated template expansion"), start)
146 yield ('end', None, pos)
146 yield ('end', None, pos)
147
147
148 def _parsetemplate(tmpl, start, stop, quote=''):
148 def _parsetemplate(tmpl, start, stop, quote=''):
149 r"""
149 r"""
150 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
150 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
151 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
151 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
152 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
152 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
153 ([('string', 'foo'), ('symbol', 'bar')], 9)
153 ([('string', 'foo'), ('symbol', 'bar')], 9)
154 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
154 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
155 ([('string', 'foo')], 4)
155 ([('string', 'foo')], 4)
156 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
156 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
157 ([('string', 'foo"'), ('string', 'bar')], 9)
157 ([('string', 'foo"'), ('string', 'bar')], 9)
158 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
158 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
159 ([('string', 'foo\\')], 6)
159 ([('string', 'foo\\')], 6)
160 """
160 """
161 parsed = []
161 parsed = []
162 sepchars = '{' + quote
162 sepchars = '{' + quote
163 pos = start
163 pos = start
164 p = parser.parser(elements)
164 p = parser.parser(elements)
165 while pos < stop:
165 while pos < stop:
166 n = min((tmpl.find(c, pos, stop) for c in sepchars),
166 n = min((tmpl.find(c, pos, stop) for c in sepchars),
167 key=lambda n: (n < 0, n))
167 key=lambda n: (n < 0, n))
168 if n < 0:
168 if n < 0:
169 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
169 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
170 pos = stop
170 pos = stop
171 break
171 break
172 c = tmpl[n:n + 1]
172 c = tmpl[n:n + 1]
173 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
173 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
174 if bs % 2 == 1:
174 if bs % 2 == 1:
175 # escaped (e.g. '\{', '\\\{', but not '\\{')
175 # escaped (e.g. '\{', '\\\{', but not '\\{')
176 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
176 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
177 pos = n + 1
177 pos = n + 1
178 continue
178 continue
179 if n > pos:
179 if n > pos:
180 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
180 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
181 if c == quote:
181 if c == quote:
182 return parsed, n + 1
182 return parsed, n + 1
183
183
184 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
184 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
185 parsed.append(parseres)
185 parsed.append(parseres)
186
186
187 if quote:
187 if quote:
188 raise error.ParseError(_("unterminated string"), start)
188 raise error.ParseError(_("unterminated string"), start)
189 return parsed, pos
189 return parsed, pos
190
190
191 def _unnesttemplatelist(tree):
191 def _unnesttemplatelist(tree):
192 """Expand list of templates to node tuple
192 """Expand list of templates to node tuple
193
193
194 >>> def f(tree):
194 >>> def f(tree):
195 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
195 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
196 >>> f((b'template', []))
196 >>> f((b'template', []))
197 (string '')
197 (string '')
198 >>> f((b'template', [(b'string', b'foo')]))
198 >>> f((b'template', [(b'string', b'foo')]))
199 (string 'foo')
199 (string 'foo')
200 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
200 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
201 (template
201 (template
202 (string 'foo')
202 (string 'foo')
203 (symbol 'rev'))
203 (symbol 'rev'))
204 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
204 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
205 (template
205 (template
206 (symbol 'rev'))
206 (symbol 'rev'))
207 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
207 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
208 (string 'foo')
208 (string 'foo')
209 """
209 """
210 if not isinstance(tree, tuple):
210 if not isinstance(tree, tuple):
211 return tree
211 return tree
212 op = tree[0]
212 op = tree[0]
213 if op != 'template':
213 if op != 'template':
214 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
214 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
215
215
216 assert len(tree) == 2
216 assert len(tree) == 2
217 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
217 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
218 if not xs:
218 if not xs:
219 return ('string', '') # empty template ""
219 return ('string', '') # empty template ""
220 elif len(xs) == 1 and xs[0][0] == 'string':
220 elif len(xs) == 1 and xs[0][0] == 'string':
221 return xs[0] # fast path for string with no template fragment "x"
221 return xs[0] # fast path for string with no template fragment "x"
222 else:
222 else:
223 return (op,) + xs
223 return (op,) + xs
224
224
225 def parse(tmpl):
225 def parse(tmpl):
226 """Parse template string into tree"""
226 """Parse template string into tree"""
227 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
227 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
228 assert pos == len(tmpl), 'unquoted template should be consumed'
228 assert pos == len(tmpl), 'unquoted template should be consumed'
229 return _unnesttemplatelist(('template', parsed))
229 return _unnesttemplatelist(('template', parsed))
230
230
231 def _parseexpr(expr):
231 def _parseexpr(expr):
232 """Parse a template expression into tree
232 """Parse a template expression into tree
233
233
234 >>> _parseexpr(b'"foo"')
234 >>> _parseexpr(b'"foo"')
235 ('string', 'foo')
235 ('string', 'foo')
236 >>> _parseexpr(b'foo(bar)')
236 >>> _parseexpr(b'foo(bar)')
237 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
237 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
238 >>> _parseexpr(b'foo(')
238 >>> _parseexpr(b'foo(')
239 Traceback (most recent call last):
239 Traceback (most recent call last):
240 ...
240 ...
241 ParseError: ('not a prefix: end', 4)
241 ParseError: ('not a prefix: end', 4)
242 >>> _parseexpr(b'"foo" "bar"')
242 >>> _parseexpr(b'"foo" "bar"')
243 Traceback (most recent call last):
243 Traceback (most recent call last):
244 ...
244 ...
245 ParseError: ('invalid token', 7)
245 ParseError: ('invalid token', 7)
246 """
246 """
247 p = parser.parser(elements)
247 p = parser.parser(elements)
248 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
248 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
249 if pos != len(expr):
249 if pos != len(expr):
250 raise error.ParseError(_('invalid token'), pos)
250 raise error.ParseError(_('invalid token'), pos)
251 return _unnesttemplatelist(tree)
251 return _unnesttemplatelist(tree)
252
252
253 def prettyformat(tree):
253 def prettyformat(tree):
254 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
254 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
255
255
256 def compileexp(exp, context, curmethods):
256 def compileexp(exp, context, curmethods):
257 """Compile parsed template tree to (func, data) pair"""
257 """Compile parsed template tree to (func, data) pair"""
258 t = exp[0]
258 t = exp[0]
259 if t in curmethods:
259 if t in curmethods:
260 return curmethods[t](exp, context)
260 return curmethods[t](exp, context)
261 raise error.ParseError(_("unknown method '%s'") % t)
261 raise error.ParseError(_("unknown method '%s'") % t)
262
262
263 # template evaluation
263 # template evaluation
264
264
265 def getsymbol(exp):
265 def getsymbol(exp):
266 if exp[0] == 'symbol':
266 if exp[0] == 'symbol':
267 return exp[1]
267 return exp[1]
268 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
268 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
269
269
270 def getlist(x):
270 def getlist(x):
271 if not x:
271 if not x:
272 return []
272 return []
273 if x[0] == 'list':
273 if x[0] == 'list':
274 return getlist(x[1]) + [x[2]]
274 return getlist(x[1]) + [x[2]]
275 return [x]
275 return [x]
276
276
277 def gettemplate(exp, context):
277 def gettemplate(exp, context):
278 """Compile given template tree or load named template from map file;
278 """Compile given template tree or load named template from map file;
279 returns (func, data) pair"""
279 returns (func, data) pair"""
280 if exp[0] in ('template', 'string'):
280 if exp[0] in ('template', 'string'):
281 return compileexp(exp, context, methods)
281 return compileexp(exp, context, methods)
282 if exp[0] == 'symbol':
282 if exp[0] == 'symbol':
283 # unlike runsymbol(), here 'symbol' is always taken as template name
283 # unlike runsymbol(), here 'symbol' is always taken as template name
284 # even if it exists in mapping. this allows us to override mapping
284 # even if it exists in mapping. this allows us to override mapping
285 # by web templates, e.g. 'changelogtag' is redefined in map file.
285 # by web templates, e.g. 'changelogtag' is redefined in map file.
286 return context._load(exp[1])
286 return context._load(exp[1])
287 raise error.ParseError(_("expected template specifier"))
287 raise error.ParseError(_("expected template specifier"))
288
288
289 def findsymbolicname(arg):
289 def findsymbolicname(arg):
290 """Find symbolic name for the given compiled expression; returns None
290 """Find symbolic name for the given compiled expression; returns None
291 if nothing found reliably"""
291 if nothing found reliably"""
292 while True:
292 while True:
293 func, data = arg
293 func, data = arg
294 if func is runsymbol:
294 if func is runsymbol:
295 return data
295 return data
296 elif func is runfilter:
296 elif func is runfilter:
297 arg = data[0]
297 arg = data[0]
298 else:
298 else:
299 return None
299 return None
300
300
301 def evalrawexp(context, mapping, arg):
301 def evalrawexp(context, mapping, arg):
302 """Evaluate given argument as a bare template object which may require
302 """Evaluate given argument as a bare template object which may require
303 further processing (such as folding generator of strings)"""
303 further processing (such as folding generator of strings)"""
304 func, data = arg
304 func, data = arg
305 return func(context, mapping, data)
305 return func(context, mapping, data)
306
306
307 def evalfuncarg(context, mapping, arg):
307 def evalfuncarg(context, mapping, arg):
308 """Evaluate given argument as value type"""
308 """Evaluate given argument as value type"""
309 thing = evalrawexp(context, mapping, arg)
309 thing = evalrawexp(context, mapping, arg)
310 # evalrawexp() may return string, generator of strings or arbitrary object
310 # evalrawexp() may return string, generator of strings or arbitrary object
311 # such as date tuple, but filter does not want generator.
311 # such as date tuple, but filter does not want generator.
312 if isinstance(thing, types.GeneratorType):
312 if isinstance(thing, types.GeneratorType):
313 thing = stringify(thing)
313 thing = stringify(thing)
314 return thing
314 return thing
315
315
316 def evalboolean(context, mapping, arg):
316 def evalboolean(context, mapping, arg):
317 """Evaluate given argument as boolean, but also takes boolean literals"""
317 """Evaluate given argument as boolean, but also takes boolean literals"""
318 func, data = arg
318 func, data = arg
319 if func is runsymbol:
319 if func is runsymbol:
320 thing = func(context, mapping, data, default=None)
320 thing = func(context, mapping, data, default=None)
321 if thing is None:
321 if thing is None:
322 # not a template keyword, takes as a boolean literal
322 # not a template keyword, takes as a boolean literal
323 thing = util.parsebool(data)
323 thing = util.parsebool(data)
324 else:
324 else:
325 thing = func(context, mapping, data)
325 thing = func(context, mapping, data)
326 if isinstance(thing, bool):
326 if isinstance(thing, bool):
327 return thing
327 return thing
328 # other objects are evaluated as strings, which means 0 is True, but
328 # other objects are evaluated as strings, which means 0 is True, but
329 # empty dict/list should be False as they are expected to be ''
329 # empty dict/list should be False as they are expected to be ''
330 return bool(stringify(thing))
330 return bool(stringify(thing))
331
331
332 def evalinteger(context, mapping, arg, err):
332 def evalinteger(context, mapping, arg, err):
333 v = evalfuncarg(context, mapping, arg)
333 v = evalfuncarg(context, mapping, arg)
334 try:
334 try:
335 return int(v)
335 return int(v)
336 except (TypeError, ValueError):
336 except (TypeError, ValueError):
337 raise error.ParseError(err)
337 raise error.ParseError(err)
338
338
339 def evalstring(context, mapping, arg):
339 def evalstring(context, mapping, arg):
340 return stringify(evalrawexp(context, mapping, arg))
340 return stringify(evalrawexp(context, mapping, arg))
341
341
342 def evalstringliteral(context, mapping, arg):
342 def evalstringliteral(context, mapping, arg):
343 """Evaluate given argument as string template, but returns symbol name
343 """Evaluate given argument as string template, but returns symbol name
344 if it is unknown"""
344 if it is unknown"""
345 func, data = arg
345 func, data = arg
346 if func is runsymbol:
346 if func is runsymbol:
347 thing = func(context, mapping, data, default=data)
347 thing = func(context, mapping, data, default=data)
348 else:
348 else:
349 thing = func(context, mapping, data)
349 thing = func(context, mapping, data)
350 return stringify(thing)
350 return stringify(thing)
351
351
352 def runinteger(context, mapping, data):
352 def runinteger(context, mapping, data):
353 return int(data)
353 return int(data)
354
354
355 def runstring(context, mapping, data):
355 def runstring(context, mapping, data):
356 return data
356 return data
357
357
358 def _recursivesymbolblocker(key):
358 def _recursivesymbolblocker(key):
359 def showrecursion(**args):
359 def showrecursion(**args):
360 raise error.Abort(_("recursive reference '%s' in template") % key)
360 raise error.Abort(_("recursive reference '%s' in template") % key)
361 return showrecursion
361 return showrecursion
362
362
363 def _runrecursivesymbol(context, mapping, key):
363 def _runrecursivesymbol(context, mapping, key):
364 raise error.Abort(_("recursive reference '%s' in template") % key)
364 raise error.Abort(_("recursive reference '%s' in template") % key)
365
365
366 def runsymbol(context, mapping, key, default=''):
366 def runsymbol(context, mapping, key, default=''):
367 v = mapping.get(key)
367 v = mapping.get(key)
368 if v is None:
368 if v is None:
369 v = context._defaults.get(key)
369 v = context._defaults.get(key)
370 if v is None:
370 if v is None:
371 # put poison to cut recursion. we can't move this to parsing phase
371 # put poison to cut recursion. we can't move this to parsing phase
372 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
372 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
373 safemapping = mapping.copy()
373 safemapping = mapping.copy()
374 safemapping[key] = _recursivesymbolblocker(key)
374 safemapping[key] = _recursivesymbolblocker(key)
375 try:
375 try:
376 v = context.process(key, safemapping)
376 v = context.process(key, safemapping)
377 except TemplateNotFound:
377 except TemplateNotFound:
378 v = default
378 v = default
379 if callable(v):
379 if callable(v):
380 return v(**pycompat.strkwargs(mapping))
380 return v(**pycompat.strkwargs(mapping))
381 return v
381 return v
382
382
383 def buildtemplate(exp, context):
383 def buildtemplate(exp, context):
384 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
384 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
385 return (runtemplate, ctmpl)
385 return (runtemplate, ctmpl)
386
386
387 def runtemplate(context, mapping, template):
387 def runtemplate(context, mapping, template):
388 for arg in template:
388 for arg in template:
389 yield evalrawexp(context, mapping, arg)
389 yield evalrawexp(context, mapping, arg)
390
390
391 def buildfilter(exp, context):
391 def buildfilter(exp, context):
392 n = getsymbol(exp[2])
392 n = getsymbol(exp[2])
393 if n in context._filters:
393 if n in context._filters:
394 filt = context._filters[n]
394 filt = context._filters[n]
395 arg = compileexp(exp[1], context, methods)
395 arg = compileexp(exp[1], context, methods)
396 return (runfilter, (arg, filt))
396 return (runfilter, (arg, filt))
397 if n in funcs:
397 if n in funcs:
398 f = funcs[n]
398 f = funcs[n]
399 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
399 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
400 return (f, args)
400 return (f, args)
401 raise error.ParseError(_("unknown function '%s'") % n)
401 raise error.ParseError(_("unknown function '%s'") % n)
402
402
403 def runfilter(context, mapping, data):
403 def runfilter(context, mapping, data):
404 arg, filt = data
404 arg, filt = data
405 thing = evalfuncarg(context, mapping, arg)
405 thing = evalfuncarg(context, mapping, arg)
406 try:
406 try:
407 return filt(thing)
407 return filt(thing)
408 except (ValueError, AttributeError, TypeError):
408 except (ValueError, AttributeError, TypeError):
409 sym = findsymbolicname(arg)
409 sym = findsymbolicname(arg)
410 if sym:
410 if sym:
411 msg = (_("template filter '%s' is not compatible with keyword '%s'")
411 msg = (_("template filter '%s' is not compatible with keyword '%s'")
412 % (filt.func_name, sym))
412 % (filt.func_name, sym))
413 else:
413 else:
414 msg = _("incompatible use of template filter '%s'") % filt.func_name
414 msg = _("incompatible use of template filter '%s'") % filt.func_name
415 raise error.Abort(msg)
415 raise error.Abort(msg)
416
416
417 def buildmap(exp, context):
417 def buildmap(exp, context):
418 darg = compileexp(exp[1], context, methods)
418 darg = compileexp(exp[1], context, methods)
419 targ = gettemplate(exp[2], context)
419 targ = gettemplate(exp[2], context)
420 return (runmap, (darg, targ))
420 return (runmap, (darg, targ))
421
421
422 def runmap(context, mapping, data):
422 def runmap(context, mapping, data):
423 darg, targ = data
423 darg, targ = data
424 d = evalrawexp(context, mapping, darg)
424 d = evalrawexp(context, mapping, darg)
425 if util.safehasattr(d, 'itermaps'):
425 if util.safehasattr(d, 'itermaps'):
426 diter = d.itermaps()
426 diter = d.itermaps()
427 else:
427 else:
428 try:
428 try:
429 diter = iter(d)
429 diter = iter(d)
430 except TypeError:
430 except TypeError:
431 sym = findsymbolicname(darg)
431 sym = findsymbolicname(darg)
432 if sym:
432 if sym:
433 raise error.ParseError(_("keyword '%s' is not iterable") % sym)
433 raise error.ParseError(_("keyword '%s' is not iterable") % sym)
434 else:
434 else:
435 raise error.ParseError(_("%r is not iterable") % d)
435 raise error.ParseError(_("%r is not iterable") % d)
436
436
437 for i, v in enumerate(diter):
437 for i, v in enumerate(diter):
438 lm = mapping.copy()
438 lm = mapping.copy()
439 lm['index'] = i
439 lm['index'] = i
440 if isinstance(v, dict):
440 if isinstance(v, dict):
441 lm.update(v)
441 lm.update(v)
442 lm['originalnode'] = mapping.get('node')
442 lm['originalnode'] = mapping.get('node')
443 yield evalrawexp(context, lm, targ)
443 yield evalrawexp(context, lm, targ)
444 else:
444 else:
445 # v is not an iterable of dicts, this happen when 'key'
445 # v is not an iterable of dicts, this happen when 'key'
446 # has been fully expanded already and format is useless.
446 # has been fully expanded already and format is useless.
447 # If so, return the expanded value.
447 # If so, return the expanded value.
448 yield v
448 yield v
449
449
450 def buildnegate(exp, context):
450 def buildnegate(exp, context):
451 arg = compileexp(exp[1], context, exprmethods)
451 arg = compileexp(exp[1], context, exprmethods)
452 return (runnegate, arg)
452 return (runnegate, arg)
453
453
454 def runnegate(context, mapping, data):
454 def runnegate(context, mapping, data):
455 data = evalinteger(context, mapping, data,
455 data = evalinteger(context, mapping, data,
456 _('negation needs an integer argument'))
456 _('negation needs an integer argument'))
457 return -data
457 return -data
458
458
459 def buildarithmetic(exp, context, func):
459 def buildarithmetic(exp, context, func):
460 left = compileexp(exp[1], context, exprmethods)
460 left = compileexp(exp[1], context, exprmethods)
461 right = compileexp(exp[2], context, exprmethods)
461 right = compileexp(exp[2], context, exprmethods)
462 return (runarithmetic, (func, left, right))
462 return (runarithmetic, (func, left, right))
463
463
464 def runarithmetic(context, mapping, data):
464 def runarithmetic(context, mapping, data):
465 func, left, right = data
465 func, left, right = data
466 left = evalinteger(context, mapping, left,
466 left = evalinteger(context, mapping, left,
467 _('arithmetic only defined on integers'))
467 _('arithmetic only defined on integers'))
468 right = evalinteger(context, mapping, right,
468 right = evalinteger(context, mapping, right,
469 _('arithmetic only defined on integers'))
469 _('arithmetic only defined on integers'))
470 try:
470 try:
471 return func(left, right)
471 return func(left, right)
472 except ZeroDivisionError:
472 except ZeroDivisionError:
473 raise error.Abort(_('division by zero is not defined'))
473 raise error.Abort(_('division by zero is not defined'))
474
474
475 def buildfunc(exp, context):
475 def buildfunc(exp, context):
476 n = getsymbol(exp[1])
476 n = getsymbol(exp[1])
477 if n in funcs:
477 if n in funcs:
478 f = funcs[n]
478 f = funcs[n]
479 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
479 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
480 return (f, args)
480 return (f, args)
481 if n in context._filters:
481 if n in context._filters:
482 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
482 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
483 if len(args) != 1:
483 if len(args) != 1:
484 raise error.ParseError(_("filter %s expects one argument") % n)
484 raise error.ParseError(_("filter %s expects one argument") % n)
485 f = context._filters[n]
485 f = context._filters[n]
486 return (runfilter, (args[0], f))
486 return (runfilter, (args[0], f))
487 raise error.ParseError(_("unknown function '%s'") % n)
487 raise error.ParseError(_("unknown function '%s'") % n)
488
488
489 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
489 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
490 """Compile parsed tree of function arguments into list or dict of
490 """Compile parsed tree of function arguments into list or dict of
491 (func, data) pairs
491 (func, data) pairs
492
492
493 >>> context = engine(lambda t: (runsymbol, t))
493 >>> context = engine(lambda t: (runsymbol, t))
494 >>> def fargs(expr, argspec):
494 >>> def fargs(expr, argspec):
495 ... x = _parseexpr(expr)
495 ... x = _parseexpr(expr)
496 ... n = getsymbol(x[1])
496 ... n = getsymbol(x[1])
497 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
497 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
498 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
498 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
499 ['l', 'k']
499 ['l', 'k']
500 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
500 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
501 >>> list(args.keys()), list(args[b'opts'].keys())
501 >>> list(args.keys()), list(args[b'opts'].keys())
502 (['opts'], ['opts', 'k'])
502 (['opts'], ['opts', 'k'])
503 """
503 """
504 def compiledict(xs):
504 def compiledict(xs):
505 return util.sortdict((k, compileexp(x, context, curmethods))
505 return util.sortdict((k, compileexp(x, context, curmethods))
506 for k, x in xs.iteritems())
506 for k, x in xs.iteritems())
507 def compilelist(xs):
507 def compilelist(xs):
508 return [compileexp(x, context, curmethods) for x in xs]
508 return [compileexp(x, context, curmethods) for x in xs]
509
509
510 if not argspec:
510 if not argspec:
511 # filter or function with no argspec: return list of positional args
511 # filter or function with no argspec: return list of positional args
512 return compilelist(getlist(exp))
512 return compilelist(getlist(exp))
513
513
514 # function with argspec: return dict of named args
514 # function with argspec: return dict of named args
515 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
515 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
516 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
516 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
517 keyvaluenode='keyvalue', keynode='symbol')
517 keyvaluenode='keyvalue', keynode='symbol')
518 compargs = util.sortdict()
518 compargs = util.sortdict()
519 if varkey:
519 if varkey:
520 compargs[varkey] = compilelist(treeargs.pop(varkey))
520 compargs[varkey] = compilelist(treeargs.pop(varkey))
521 if optkey:
521 if optkey:
522 compargs[optkey] = compiledict(treeargs.pop(optkey))
522 compargs[optkey] = compiledict(treeargs.pop(optkey))
523 compargs.update(compiledict(treeargs))
523 compargs.update(compiledict(treeargs))
524 return compargs
524 return compargs
525
525
526 def buildkeyvaluepair(exp, content):
526 def buildkeyvaluepair(exp, content):
527 raise error.ParseError(_("can't use a key-value pair in this context"))
527 raise error.ParseError(_("can't use a key-value pair in this context"))
528
528
529 # dict of template built-in functions
529 # dict of template built-in functions
530 funcs = {}
530 funcs = {}
531
531
532 templatefunc = registrar.templatefunc(funcs)
532 templatefunc = registrar.templatefunc(funcs)
533
533
534 @templatefunc('date(date[, fmt])')
534 @templatefunc('date(date[, fmt])')
535 def date(context, mapping, args):
535 def date(context, mapping, args):
536 """Format a date. See :hg:`help dates` for formatting
536 """Format a date. See :hg:`help dates` for formatting
537 strings. The default is a Unix date format, including the timezone:
537 strings. The default is a Unix date format, including the timezone:
538 "Mon Sep 04 15:13:13 2006 0700"."""
538 "Mon Sep 04 15:13:13 2006 0700"."""
539 if not (1 <= len(args) <= 2):
539 if not (1 <= len(args) <= 2):
540 # i18n: "date" is a keyword
540 # i18n: "date" is a keyword
541 raise error.ParseError(_("date expects one or two arguments"))
541 raise error.ParseError(_("date expects one or two arguments"))
542
542
543 date = evalfuncarg(context, mapping, args[0])
543 date = evalfuncarg(context, mapping, args[0])
544 fmt = None
544 fmt = None
545 if len(args) == 2:
545 if len(args) == 2:
546 fmt = evalstring(context, mapping, args[1])
546 fmt = evalstring(context, mapping, args[1])
547 try:
547 try:
548 if fmt is None:
548 if fmt is None:
549 return util.datestr(date)
549 return util.datestr(date)
550 else:
550 else:
551 return util.datestr(date, fmt)
551 return util.datestr(date, fmt)
552 except (TypeError, ValueError):
552 except (TypeError, ValueError):
553 # i18n: "date" is a keyword
553 # i18n: "date" is a keyword
554 raise error.ParseError(_("date expects a date information"))
554 raise error.ParseError(_("date expects a date information"))
555
555
556 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
556 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
557 def dict_(context, mapping, args):
557 def dict_(context, mapping, args):
558 """Construct a dict from key-value pairs. A key may be omitted if
558 """Construct a dict from key-value pairs. A key may be omitted if
559 a value expression can provide an unambiguous name."""
559 a value expression can provide an unambiguous name."""
560 data = util.sortdict()
560 data = util.sortdict()
561
561
562 for v in args['args']:
562 for v in args['args']:
563 k = findsymbolicname(v)
563 k = findsymbolicname(v)
564 if not k:
564 if not k:
565 raise error.ParseError(_('dict key cannot be inferred'))
565 raise error.ParseError(_('dict key cannot be inferred'))
566 if k in data or k in args['kwargs']:
566 if k in data or k in args['kwargs']:
567 raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
567 raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
568 data[k] = evalfuncarg(context, mapping, v)
568 data[k] = evalfuncarg(context, mapping, v)
569
569
570 data.update((k, evalfuncarg(context, mapping, v))
570 data.update((k, evalfuncarg(context, mapping, v))
571 for k, v in args['kwargs'].iteritems())
571 for k, v in args['kwargs'].iteritems())
572 return templatekw.hybriddict(data)
572 return templatekw.hybriddict(data)
573
573
574 @templatefunc('diff([includepattern [, excludepattern]])')
574 @templatefunc('diff([includepattern [, excludepattern]])')
575 def diff(context, mapping, args):
575 def diff(context, mapping, args):
576 """Show a diff, optionally
576 """Show a diff, optionally
577 specifying files to include or exclude."""
577 specifying files to include or exclude."""
578 if len(args) > 2:
578 if len(args) > 2:
579 # i18n: "diff" is a keyword
579 # i18n: "diff" is a keyword
580 raise error.ParseError(_("diff expects zero, one, or two arguments"))
580 raise error.ParseError(_("diff expects zero, one, or two arguments"))
581
581
582 def getpatterns(i):
582 def getpatterns(i):
583 if i < len(args):
583 if i < len(args):
584 s = evalstring(context, mapping, args[i]).strip()
584 s = evalstring(context, mapping, args[i]).strip()
585 if s:
585 if s:
586 return [s]
586 return [s]
587 return []
587 return []
588
588
589 ctx = mapping['ctx']
589 ctx = mapping['ctx']
590 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
590 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
591
591
592 return ''.join(chunks)
592 return ''.join(chunks)
593
593
594 @templatefunc('files(pattern)')
594 @templatefunc('files(pattern)')
595 def files(context, mapping, args):
595 def files(context, mapping, args):
596 """All files of the current changeset matching the pattern. See
596 """All files of the current changeset matching the pattern. See
597 :hg:`help patterns`."""
597 :hg:`help patterns`."""
598 if not len(args) == 1:
598 if not len(args) == 1:
599 # i18n: "files" is a keyword
599 # i18n: "files" is a keyword
600 raise error.ParseError(_("files expects one argument"))
600 raise error.ParseError(_("files expects one argument"))
601
601
602 raw = evalstring(context, mapping, args[0])
602 raw = evalstring(context, mapping, args[0])
603 ctx = mapping['ctx']
603 ctx = mapping['ctx']
604 m = ctx.match([raw])
604 m = ctx.match([raw])
605 files = list(ctx.matches(m))
605 files = list(ctx.matches(m))
606 return templatekw.showlist("file", files, mapping)
606 return templatekw.showlist("file", files, mapping)
607
607
608 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
608 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
609 def fill(context, mapping, args):
609 def fill(context, mapping, args):
610 """Fill many
610 """Fill many
611 paragraphs with optional indentation. See the "fill" filter."""
611 paragraphs with optional indentation. See the "fill" filter."""
612 if not (1 <= len(args) <= 4):
612 if not (1 <= len(args) <= 4):
613 # i18n: "fill" is a keyword
613 # i18n: "fill" is a keyword
614 raise error.ParseError(_("fill expects one to four arguments"))
614 raise error.ParseError(_("fill expects one to four arguments"))
615
615
616 text = evalstring(context, mapping, args[0])
616 text = evalstring(context, mapping, args[0])
617 width = 76
617 width = 76
618 initindent = ''
618 initindent = ''
619 hangindent = ''
619 hangindent = ''
620 if 2 <= len(args) <= 4:
620 if 2 <= len(args) <= 4:
621 width = evalinteger(context, mapping, args[1],
621 width = evalinteger(context, mapping, args[1],
622 # i18n: "fill" is a keyword
622 # i18n: "fill" is a keyword
623 _("fill expects an integer width"))
623 _("fill expects an integer width"))
624 try:
624 try:
625 initindent = evalstring(context, mapping, args[2])
625 initindent = evalstring(context, mapping, args[2])
626 hangindent = evalstring(context, mapping, args[3])
626 hangindent = evalstring(context, mapping, args[3])
627 except IndexError:
627 except IndexError:
628 pass
628 pass
629
629
630 return templatefilters.fill(text, width, initindent, hangindent)
630 return templatefilters.fill(text, width, initindent, hangindent)
631
631
632 @templatefunc('formatnode(node)')
632 @templatefunc('formatnode(node)')
633 def formatnode(context, mapping, args):
633 def formatnode(context, mapping, args):
634 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
634 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
635 if len(args) != 1:
635 if len(args) != 1:
636 # i18n: "formatnode" is a keyword
636 # i18n: "formatnode" is a keyword
637 raise error.ParseError(_("formatnode expects one argument"))
637 raise error.ParseError(_("formatnode expects one argument"))
638
638
639 ui = mapping['ui']
639 ui = mapping['ui']
640 node = evalstring(context, mapping, args[0])
640 node = evalstring(context, mapping, args[0])
641 if ui.debugflag:
641 if ui.debugflag:
642 return node
642 return node
643 return templatefilters.short(node)
643 return templatefilters.short(node)
644
644
645 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
645 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
646 argspec='text width fillchar left')
646 argspec='text width fillchar left')
647 def pad(context, mapping, args):
647 def pad(context, mapping, args):
648 """Pad text with a
648 """Pad text with a
649 fill character."""
649 fill character."""
650 if 'text' not in args or 'width' not in args:
650 if 'text' not in args or 'width' not in args:
651 # i18n: "pad" is a keyword
651 # i18n: "pad" is a keyword
652 raise error.ParseError(_("pad() expects two to four arguments"))
652 raise error.ParseError(_("pad() expects two to four arguments"))
653
653
654 width = evalinteger(context, mapping, args['width'],
654 width = evalinteger(context, mapping, args['width'],
655 # i18n: "pad" is a keyword
655 # i18n: "pad" is a keyword
656 _("pad() expects an integer width"))
656 _("pad() expects an integer width"))
657
657
658 text = evalstring(context, mapping, args['text'])
658 text = evalstring(context, mapping, args['text'])
659
659
660 left = False
660 left = False
661 fillchar = ' '
661 fillchar = ' '
662 if 'fillchar' in args:
662 if 'fillchar' in args:
663 fillchar = evalstring(context, mapping, args['fillchar'])
663 fillchar = evalstring(context, mapping, args['fillchar'])
664 if len(color.stripeffects(fillchar)) != 1:
664 if len(color.stripeffects(fillchar)) != 1:
665 # i18n: "pad" is a keyword
665 # i18n: "pad" is a keyword
666 raise error.ParseError(_("pad() expects a single fill character"))
666 raise error.ParseError(_("pad() expects a single fill character"))
667 if 'left' in args:
667 if 'left' in args:
668 left = evalboolean(context, mapping, args['left'])
668 left = evalboolean(context, mapping, args['left'])
669
669
670 fillwidth = width - encoding.colwidth(color.stripeffects(text))
670 fillwidth = width - encoding.colwidth(color.stripeffects(text))
671 if fillwidth <= 0:
671 if fillwidth <= 0:
672 return text
672 return text
673 if left:
673 if left:
674 return fillchar * fillwidth + text
674 return fillchar * fillwidth + text
675 else:
675 else:
676 return text + fillchar * fillwidth
676 return text + fillchar * fillwidth
677
677
678 @templatefunc('indent(text, indentchars[, firstline])')
678 @templatefunc('indent(text, indentchars[, firstline])')
679 def indent(context, mapping, args):
679 def indent(context, mapping, args):
680 """Indents all non-empty lines
680 """Indents all non-empty lines
681 with the characters given in the indentchars string. An optional
681 with the characters given in the indentchars string. An optional
682 third parameter will override the indent for the first line only
682 third parameter will override the indent for the first line only
683 if present."""
683 if present."""
684 if not (2 <= len(args) <= 3):
684 if not (2 <= len(args) <= 3):
685 # i18n: "indent" is a keyword
685 # i18n: "indent" is a keyword
686 raise error.ParseError(_("indent() expects two or three arguments"))
686 raise error.ParseError(_("indent() expects two or three arguments"))
687
687
688 text = evalstring(context, mapping, args[0])
688 text = evalstring(context, mapping, args[0])
689 indent = evalstring(context, mapping, args[1])
689 indent = evalstring(context, mapping, args[1])
690
690
691 if len(args) == 3:
691 if len(args) == 3:
692 firstline = evalstring(context, mapping, args[2])
692 firstline = evalstring(context, mapping, args[2])
693 else:
693 else:
694 firstline = indent
694 firstline = indent
695
695
696 # the indent function doesn't indent the first line, so we do it here
696 # the indent function doesn't indent the first line, so we do it here
697 return templatefilters.indent(firstline + text, indent)
697 return templatefilters.indent(firstline + text, indent)
698
698
699 @templatefunc('get(dict, key)')
699 @templatefunc('get(dict, key)')
700 def get(context, mapping, args):
700 def get(context, mapping, args):
701 """Get an attribute/key from an object. Some keywords
701 """Get an attribute/key from an object. Some keywords
702 are complex types. This function allows you to obtain the value of an
702 are complex types. This function allows you to obtain the value of an
703 attribute on these types."""
703 attribute on these types."""
704 if len(args) != 2:
704 if len(args) != 2:
705 # i18n: "get" is a keyword
705 # i18n: "get" is a keyword
706 raise error.ParseError(_("get() expects two arguments"))
706 raise error.ParseError(_("get() expects two arguments"))
707
707
708 dictarg = evalfuncarg(context, mapping, args[0])
708 dictarg = evalfuncarg(context, mapping, args[0])
709 if not util.safehasattr(dictarg, 'get'):
709 if not util.safehasattr(dictarg, 'get'):
710 # i18n: "get" is a keyword
710 # i18n: "get" is a keyword
711 raise error.ParseError(_("get() expects a dict as first argument"))
711 raise error.ParseError(_("get() expects a dict as first argument"))
712
712
713 key = evalfuncarg(context, mapping, args[1])
713 key = evalfuncarg(context, mapping, args[1])
714 return dictarg.get(key)
714 return dictarg.get(key)
715
715
716 @templatefunc('if(expr, then[, else])')
716 @templatefunc('if(expr, then[, else])')
717 def if_(context, mapping, args):
717 def if_(context, mapping, args):
718 """Conditionally execute based on the result of
718 """Conditionally execute based on the result of
719 an expression."""
719 an expression."""
720 if not (2 <= len(args) <= 3):
720 if not (2 <= len(args) <= 3):
721 # i18n: "if" is a keyword
721 # i18n: "if" is a keyword
722 raise error.ParseError(_("if expects two or three arguments"))
722 raise error.ParseError(_("if expects two or three arguments"))
723
723
724 test = evalboolean(context, mapping, args[0])
724 test = evalboolean(context, mapping, args[0])
725 if test:
725 if test:
726 yield evalrawexp(context, mapping, args[1])
726 yield evalrawexp(context, mapping, args[1])
727 elif len(args) == 3:
727 elif len(args) == 3:
728 yield evalrawexp(context, mapping, args[2])
728 yield evalrawexp(context, mapping, args[2])
729
729
730 @templatefunc('ifcontains(needle, haystack, then[, else])')
730 @templatefunc('ifcontains(needle, haystack, then[, else])')
731 def ifcontains(context, mapping, args):
731 def ifcontains(context, mapping, args):
732 """Conditionally execute based
732 """Conditionally execute based
733 on whether the item "needle" is in "haystack"."""
733 on whether the item "needle" is in "haystack"."""
734 if not (3 <= len(args) <= 4):
734 if not (3 <= len(args) <= 4):
735 # i18n: "ifcontains" is a keyword
735 # i18n: "ifcontains" is a keyword
736 raise error.ParseError(_("ifcontains expects three or four arguments"))
736 raise error.ParseError(_("ifcontains expects three or four arguments"))
737
737
738 needle = evalstring(context, mapping, args[0])
738 needle = evalstring(context, mapping, args[0])
739 haystack = evalfuncarg(context, mapping, args[1])
739 haystack = evalfuncarg(context, mapping, args[1])
740
740
741 if needle in haystack:
741 if needle in haystack:
742 yield evalrawexp(context, mapping, args[2])
742 yield evalrawexp(context, mapping, args[2])
743 elif len(args) == 4:
743 elif len(args) == 4:
744 yield evalrawexp(context, mapping, args[3])
744 yield evalrawexp(context, mapping, args[3])
745
745
746 @templatefunc('ifeq(expr1, expr2, then[, else])')
746 @templatefunc('ifeq(expr1, expr2, then[, else])')
747 def ifeq(context, mapping, args):
747 def ifeq(context, mapping, args):
748 """Conditionally execute based on
748 """Conditionally execute based on
749 whether 2 items are equivalent."""
749 whether 2 items are equivalent."""
750 if not (3 <= len(args) <= 4):
750 if not (3 <= len(args) <= 4):
751 # i18n: "ifeq" is a keyword
751 # i18n: "ifeq" is a keyword
752 raise error.ParseError(_("ifeq expects three or four arguments"))
752 raise error.ParseError(_("ifeq expects three or four arguments"))
753
753
754 test = evalstring(context, mapping, args[0])
754 test = evalstring(context, mapping, args[0])
755 match = evalstring(context, mapping, args[1])
755 match = evalstring(context, mapping, args[1])
756 if test == match:
756 if test == match:
757 yield evalrawexp(context, mapping, args[2])
757 yield evalrawexp(context, mapping, args[2])
758 elif len(args) == 4:
758 elif len(args) == 4:
759 yield evalrawexp(context, mapping, args[3])
759 yield evalrawexp(context, mapping, args[3])
760
760
761 @templatefunc('join(list, sep)')
761 @templatefunc('join(list, sep)')
762 def join(context, mapping, args):
762 def join(context, mapping, args):
763 """Join items in a list with a delimiter."""
763 """Join items in a list with a delimiter."""
764 if not (1 <= len(args) <= 2):
764 if not (1 <= len(args) <= 2):
765 # i18n: "join" is a keyword
765 # i18n: "join" is a keyword
766 raise error.ParseError(_("join expects one or two arguments"))
766 raise error.ParseError(_("join expects one or two arguments"))
767
767
768 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
768 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
769 # abuses generator as a keyword that returns a list of dicts.
769 # abuses generator as a keyword that returns a list of dicts.
770 joinset = evalrawexp(context, mapping, args[0])
770 joinset = evalrawexp(context, mapping, args[0])
771 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
771 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
772 joiner = " "
772 joiner = " "
773 if len(args) > 1:
773 if len(args) > 1:
774 joiner = evalstring(context, mapping, args[1])
774 joiner = evalstring(context, mapping, args[1])
775
775
776 first = True
776 first = True
777 for x in joinset:
777 for x in joinset:
778 if first:
778 if first:
779 first = False
779 first = False
780 else:
780 else:
781 yield joiner
781 yield joiner
782 yield joinfmt(x)
782 yield joinfmt(x)
783
783
784 @templatefunc('label(label, expr)')
784 @templatefunc('label(label, expr)')
785 def label(context, mapping, args):
785 def label(context, mapping, args):
786 """Apply a label to generated content. Content with
786 """Apply a label to generated content. Content with
787 a label applied can result in additional post-processing, such as
787 a label applied can result in additional post-processing, such as
788 automatic colorization."""
788 automatic colorization."""
789 if len(args) != 2:
789 if len(args) != 2:
790 # i18n: "label" is a keyword
790 # i18n: "label" is a keyword
791 raise error.ParseError(_("label expects two arguments"))
791 raise error.ParseError(_("label expects two arguments"))
792
792
793 ui = mapping['ui']
793 ui = mapping['ui']
794 thing = evalstring(context, mapping, args[1])
794 thing = evalstring(context, mapping, args[1])
795 # preserve unknown symbol as literal so effects like 'red', 'bold',
795 # preserve unknown symbol as literal so effects like 'red', 'bold',
796 # etc. don't need to be quoted
796 # etc. don't need to be quoted
797 label = evalstringliteral(context, mapping, args[0])
797 label = evalstringliteral(context, mapping, args[0])
798
798
799 return ui.label(thing, label)
799 return ui.label(thing, label)
800
800
801 @templatefunc('latesttag([pattern])')
801 @templatefunc('latesttag([pattern])')
802 def latesttag(context, mapping, args):
802 def latesttag(context, mapping, args):
803 """The global tags matching the given pattern on the
803 """The global tags matching the given pattern on the
804 most recent globally tagged ancestor of this changeset.
804 most recent globally tagged ancestor of this changeset.
805 If no such tags exist, the "{tag}" template resolves to
805 If no such tags exist, the "{tag}" template resolves to
806 the string "null"."""
806 the string "null"."""
807 if len(args) > 1:
807 if len(args) > 1:
808 # i18n: "latesttag" is a keyword
808 # i18n: "latesttag" is a keyword
809 raise error.ParseError(_("latesttag expects at most one argument"))
809 raise error.ParseError(_("latesttag expects at most one argument"))
810
810
811 pattern = None
811 pattern = None
812 if len(args) == 1:
812 if len(args) == 1:
813 pattern = evalstring(context, mapping, args[0])
813 pattern = evalstring(context, mapping, args[0])
814
814
815 return templatekw.showlatesttags(pattern, **mapping)
815 return templatekw.showlatesttags(pattern, **mapping)
816
816
817 @templatefunc('localdate(date[, tz])')
817 @templatefunc('localdate(date[, tz])')
818 def localdate(context, mapping, args):
818 def localdate(context, mapping, args):
819 """Converts a date to the specified timezone.
819 """Converts a date to the specified timezone.
820 The default is local date."""
820 The default is local date."""
821 if not (1 <= len(args) <= 2):
821 if not (1 <= len(args) <= 2):
822 # i18n: "localdate" is a keyword
822 # i18n: "localdate" is a keyword
823 raise error.ParseError(_("localdate expects one or two arguments"))
823 raise error.ParseError(_("localdate expects one or two arguments"))
824
824
825 date = evalfuncarg(context, mapping, args[0])
825 date = evalfuncarg(context, mapping, args[0])
826 try:
826 try:
827 date = util.parsedate(date)
827 date = util.parsedate(date)
828 except AttributeError: # not str nor date tuple
828 except AttributeError: # not str nor date tuple
829 # i18n: "localdate" is a keyword
829 # i18n: "localdate" is a keyword
830 raise error.ParseError(_("localdate expects a date information"))
830 raise error.ParseError(_("localdate expects a date information"))
831 if len(args) >= 2:
831 if len(args) >= 2:
832 tzoffset = None
832 tzoffset = None
833 tz = evalfuncarg(context, mapping, args[1])
833 tz = evalfuncarg(context, mapping, args[1])
834 if isinstance(tz, str):
834 if isinstance(tz, str):
835 tzoffset, remainder = util.parsetimezone(tz)
835 tzoffset, remainder = util.parsetimezone(tz)
836 if remainder:
836 if remainder:
837 tzoffset = None
837 tzoffset = None
838 if tzoffset is None:
838 if tzoffset is None:
839 try:
839 try:
840 tzoffset = int(tz)
840 tzoffset = int(tz)
841 except (TypeError, ValueError):
841 except (TypeError, ValueError):
842 # i18n: "localdate" is a keyword
842 # i18n: "localdate" is a keyword
843 raise error.ParseError(_("localdate expects a timezone"))
843 raise error.ParseError(_("localdate expects a timezone"))
844 else:
844 else:
845 tzoffset = util.makedate()[1]
845 tzoffset = util.makedate()[1]
846 return (date[0], tzoffset)
846 return (date[0], tzoffset)
847
847
848 @templatefunc('max(iterable)')
848 @templatefunc('max(iterable)')
849 def max_(context, mapping, args, **kwargs):
849 def max_(context, mapping, args, **kwargs):
850 """Return the max of an iterable"""
850 """Return the max of an iterable"""
851 if len(args) != 1:
851 if len(args) != 1:
852 # i18n: "max" is a keyword
852 # i18n: "max" is a keyword
853 raise error.ParseError(_("max expects one arguments"))
853 raise error.ParseError(_("max expects one arguments"))
854
854
855 iterable = evalfuncarg(context, mapping, args[0])
855 iterable = evalfuncarg(context, mapping, args[0])
856 try:
856 try:
857 return max(iterable)
857 return max(iterable)
858 except (TypeError, ValueError):
858 except (TypeError, ValueError):
859 # i18n: "max" is a keyword
859 # i18n: "max" is a keyword
860 raise error.ParseError(_("max first argument should be an iterable"))
860 raise error.ParseError(_("max first argument should be an iterable"))
861
861
862 @templatefunc('min(iterable)')
862 @templatefunc('min(iterable)')
863 def min_(context, mapping, args, **kwargs):
863 def min_(context, mapping, args, **kwargs):
864 """Return the min of an iterable"""
864 """Return the min of an iterable"""
865 if len(args) != 1:
865 if len(args) != 1:
866 # i18n: "min" is a keyword
866 # i18n: "min" is a keyword
867 raise error.ParseError(_("min expects one arguments"))
867 raise error.ParseError(_("min expects one arguments"))
868
868
869 iterable = evalfuncarg(context, mapping, args[0])
869 iterable = evalfuncarg(context, mapping, args[0])
870 try:
870 try:
871 return min(iterable)
871 return min(iterable)
872 except (TypeError, ValueError):
872 except (TypeError, ValueError):
873 # i18n: "min" is a keyword
873 # i18n: "min" is a keyword
874 raise error.ParseError(_("min first argument should be an iterable"))
874 raise error.ParseError(_("min first argument should be an iterable"))
875
875
876 @templatefunc('mod(a, b)')
876 @templatefunc('mod(a, b)')
877 def mod(context, mapping, args):
877 def mod(context, mapping, args):
878 """Calculate a mod b such that a / b + a mod b == a"""
878 """Calculate a mod b such that a / b + a mod b == a"""
879 if not len(args) == 2:
879 if not len(args) == 2:
880 # i18n: "mod" is a keyword
880 # i18n: "mod" is a keyword
881 raise error.ParseError(_("mod expects two arguments"))
881 raise error.ParseError(_("mod expects two arguments"))
882
882
883 func = lambda a, b: a % b
883 func = lambda a, b: a % b
884 return runarithmetic(context, mapping, (func, args[0], args[1]))
884 return runarithmetic(context, mapping, (func, args[0], args[1]))
885
885
886 @templatefunc('obsfateoperations(markers)')
886 @templatefunc('obsfateoperations(markers)')
887 def obsfateoperations(context, mapping, args):
887 def obsfateoperations(context, mapping, args):
888 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
888 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
889 if len(args) != 1:
889 if len(args) != 1:
890 # i18n: "obsfateoperations" is a keyword
890 # i18n: "obsfateoperations" is a keyword
891 raise error.ParseError(_("obsfateoperations expects one arguments"))
891 raise error.ParseError(_("obsfateoperations expects one arguments"))
892
892
893 markers = evalfuncarg(context, mapping, args[0])
893 markers = evalfuncarg(context, mapping, args[0])
894
894
895 try:
895 try:
896 data = obsutil.markersoperations(markers)
896 data = obsutil.markersoperations(markers)
897 return templatekw.hybridlist(data, name='operation')
897 return templatekw.hybridlist(data, name='operation')
898 except (TypeError, KeyError):
898 except (TypeError, KeyError):
899 # i18n: "obsfateoperations" is a keyword
899 # i18n: "obsfateoperations" is a keyword
900 errmsg = _("obsfateoperations first argument should be an iterable")
900 errmsg = _("obsfateoperations first argument should be an iterable")
901 raise error.ParseError(errmsg)
901 raise error.ParseError(errmsg)
902
902
903 @templatefunc('obsfatedate(markers)')
903 @templatefunc('obsfatedate(markers)')
904 def obsfatedate(context, mapping, args):
904 def obsfatedate(context, mapping, args):
905 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
905 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
906 if len(args) != 1:
906 if len(args) != 1:
907 # i18n: "obsfatedate" is a keyword
907 # i18n: "obsfatedate" is a keyword
908 raise error.ParseError(_("obsfatedate expects one arguments"))
908 raise error.ParseError(_("obsfatedate expects one arguments"))
909
909
910 markers = evalfuncarg(context, mapping, args[0])
910 markers = evalfuncarg(context, mapping, args[0])
911
911
912 try:
912 try:
913 data = obsutil.markersdates(markers)
913 data = obsutil.markersdates(markers)
914 return templatekw.hybridlist(data, name='date', fmt='%d %d')
914 return templatekw.hybridlist(data, name='date', fmt='%d %d')
915 except (TypeError, KeyError):
915 except (TypeError, KeyError):
916 # i18n: "obsfatedate" is a keyword
916 # i18n: "obsfatedate" is a keyword
917 errmsg = _("obsfatedate first argument should be an iterable")
917 errmsg = _("obsfatedate first argument should be an iterable")
918 raise error.ParseError(errmsg)
918 raise error.ParseError(errmsg)
919
919
920 @templatefunc('obsfateusers(markers)')
920 @templatefunc('obsfateusers(markers)')
921 def obsfateusers(context, mapping, args):
921 def obsfateusers(context, mapping, args):
922 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
922 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
923 if len(args) != 1:
923 if len(args) != 1:
924 # i18n: "obsfateusers" is a keyword
924 # i18n: "obsfateusers" is a keyword
925 raise error.ParseError(_("obsfateusers expects one arguments"))
925 raise error.ParseError(_("obsfateusers expects one arguments"))
926
926
927 markers = evalfuncarg(context, mapping, args[0])
927 markers = evalfuncarg(context, mapping, args[0])
928
928
929 try:
929 try:
930 data = obsutil.markersusers(markers)
930 data = obsutil.markersusers(markers)
931 return templatekw.hybridlist(data, name='user')
931 return templatekw.hybridlist(data, name='user')
932 except (TypeError, KeyError, ValueError):
932 except (TypeError, KeyError, ValueError):
933 # i18n: "obsfateusers" is a keyword
933 # i18n: "obsfateusers" is a keyword
934 msg = _("obsfateusers first argument should be an iterable of "
934 msg = _("obsfateusers first argument should be an iterable of "
935 "obsmakers")
935 "obsmakers")
936 raise error.ParseError(msg)
936 raise error.ParseError(msg)
937
937
938 @templatefunc('obsfateverb(successors)')
938 @templatefunc('obsfateverb(successors)')
939 def obsfateverb(context, mapping, args):
939 def obsfateverb(context, mapping, args):
940 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
940 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
941 if len(args) != 1:
941 if len(args) != 1:
942 # i18n: "obsfateverb" is a keyword
942 # i18n: "obsfateverb" is a keyword
943 raise error.ParseError(_("obsfateverb expects one arguments"))
943 raise error.ParseError(_("obsfateverb expects one arguments"))
944
944
945 successors = evalfuncarg(context, mapping, args[0])
945 successors = evalfuncarg(context, mapping, args[0])
946
946
947 try:
947 try:
948 return obsutil.successorsetverb(successors)
948 return obsutil.successorsetverb(successors)
949 except TypeError:
949 except TypeError:
950 # i18n: "obsfateverb" is a keyword
950 # i18n: "obsfateverb" is a keyword
951 errmsg = _("obsfateverb first argument should be countable")
951 errmsg = _("obsfateverb first argument should be countable")
952 raise error.ParseError(errmsg)
952 raise error.ParseError(errmsg)
953
953
954 @templatefunc('relpath(path)')
954 @templatefunc('relpath(path)')
955 def relpath(context, mapping, args):
955 def relpath(context, mapping, args):
956 """Convert a repository-absolute path into a filesystem path relative to
956 """Convert a repository-absolute path into a filesystem path relative to
957 the current working directory."""
957 the current working directory."""
958 if len(args) != 1:
958 if len(args) != 1:
959 # i18n: "relpath" is a keyword
959 # i18n: "relpath" is a keyword
960 raise error.ParseError(_("relpath expects one argument"))
960 raise error.ParseError(_("relpath expects one argument"))
961
961
962 repo = mapping['ctx'].repo()
962 repo = mapping['ctx'].repo()
963 path = evalstring(context, mapping, args[0])
963 path = evalstring(context, mapping, args[0])
964 return repo.pathto(path)
964 return repo.pathto(path)
965
965
966 @templatefunc('revset(query[, formatargs...])')
966 @templatefunc('revset(query[, formatargs...])')
967 def revset(context, mapping, args):
967 def revset(context, mapping, args):
968 """Execute a revision set query. See
968 """Execute a revision set query. See
969 :hg:`help revset`."""
969 :hg:`help revset`."""
970 if not len(args) > 0:
970 if not len(args) > 0:
971 # i18n: "revset" is a keyword
971 # i18n: "revset" is a keyword
972 raise error.ParseError(_("revset expects one or more arguments"))
972 raise error.ParseError(_("revset expects one or more arguments"))
973
973
974 raw = evalstring(context, mapping, args[0])
974 raw = evalstring(context, mapping, args[0])
975 ctx = mapping['ctx']
975 ctx = mapping['ctx']
976 repo = ctx.repo()
976 repo = ctx.repo()
977
977
978 def query(expr):
978 def query(expr):
979 m = revsetmod.match(repo.ui, expr, repo=repo)
979 m = revsetmod.match(repo.ui, expr, repo=repo)
980 return m(repo)
980 return m(repo)
981
981
982 if len(args) > 1:
982 if len(args) > 1:
983 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
983 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
984 revs = query(revsetlang.formatspec(raw, *formatargs))
984 revs = query(revsetlang.formatspec(raw, *formatargs))
985 revs = list(revs)
985 revs = list(revs)
986 else:
986 else:
987 revsetcache = mapping['cache'].setdefault("revsetcache", {})
987 revsetcache = mapping['cache'].setdefault("revsetcache", {})
988 if raw in revsetcache:
988 if raw in revsetcache:
989 revs = revsetcache[raw]
989 revs = revsetcache[raw]
990 else:
990 else:
991 revs = query(raw)
991 revs = query(raw)
992 revs = list(revs)
992 revs = list(revs)
993 revsetcache[raw] = revs
993 revsetcache[raw] = revs
994
994
995 return templatekw.showrevslist("revision", revs, **mapping)
995 return templatekw.showrevslist("revision", revs, **mapping)
996
996
997 @templatefunc('rstdoc(text, style)')
997 @templatefunc('rstdoc(text, style)')
998 def rstdoc(context, mapping, args):
998 def rstdoc(context, mapping, args):
999 """Format reStructuredText."""
999 """Format reStructuredText."""
1000 if len(args) != 2:
1000 if len(args) != 2:
1001 # i18n: "rstdoc" is a keyword
1001 # i18n: "rstdoc" is a keyword
1002 raise error.ParseError(_("rstdoc expects two arguments"))
1002 raise error.ParseError(_("rstdoc expects two arguments"))
1003
1003
1004 text = evalstring(context, mapping, args[0])
1004 text = evalstring(context, mapping, args[0])
1005 style = evalstring(context, mapping, args[1])
1005 style = evalstring(context, mapping, args[1])
1006
1006
1007 return minirst.format(text, style=style, keep=['verbose'])
1007 return minirst.format(text, style=style, keep=['verbose'])
1008
1008
1009 @templatefunc('separate(sep, args)', argspec='sep *args')
1009 @templatefunc('separate(sep, args)', argspec='sep *args')
1010 def separate(context, mapping, args):
1010 def separate(context, mapping, args):
1011 """Add a separator between non-empty arguments."""
1011 """Add a separator between non-empty arguments."""
1012 if 'sep' not in args:
1012 if 'sep' not in args:
1013 # i18n: "separate" is a keyword
1013 # i18n: "separate" is a keyword
1014 raise error.ParseError(_("separate expects at least one argument"))
1014 raise error.ParseError(_("separate expects at least one argument"))
1015
1015
1016 sep = evalstring(context, mapping, args['sep'])
1016 sep = evalstring(context, mapping, args['sep'])
1017 first = True
1017 first = True
1018 for arg in args['args']:
1018 for arg in args['args']:
1019 argstr = evalstring(context, mapping, arg)
1019 argstr = evalstring(context, mapping, arg)
1020 if not argstr:
1020 if not argstr:
1021 continue
1021 continue
1022 if first:
1022 if first:
1023 first = False
1023 first = False
1024 else:
1024 else:
1025 yield sep
1025 yield sep
1026 yield argstr
1026 yield argstr
1027
1027
1028 @templatefunc('shortest(node, minlength=4)')
1028 @templatefunc('shortest(node, minlength=4)')
1029 def shortest(context, mapping, args):
1029 def shortest(context, mapping, args):
1030 """Obtain the shortest representation of
1030 """Obtain the shortest representation of
1031 a node."""
1031 a node."""
1032 if not (1 <= len(args) <= 2):
1032 if not (1 <= len(args) <= 2):
1033 # i18n: "shortest" is a keyword
1033 # i18n: "shortest" is a keyword
1034 raise error.ParseError(_("shortest() expects one or two arguments"))
1034 raise error.ParseError(_("shortest() expects one or two arguments"))
1035
1035
1036 node = evalstring(context, mapping, args[0])
1036 node = evalstring(context, mapping, args[0])
1037
1037
1038 minlength = 4
1038 minlength = 4
1039 if len(args) > 1:
1039 if len(args) > 1:
1040 minlength = evalinteger(context, mapping, args[1],
1040 minlength = evalinteger(context, mapping, args[1],
1041 # i18n: "shortest" is a keyword
1041 # i18n: "shortest" is a keyword
1042 _("shortest() expects an integer minlength"))
1042 _("shortest() expects an integer minlength"))
1043
1043
1044 # _partialmatch() of filtered changelog could take O(len(repo)) time,
1044 # _partialmatch() of filtered changelog could take O(len(repo)) time,
1045 # which would be unacceptably slow. so we look for hash collision in
1045 # which would be unacceptably slow. so we look for hash collision in
1046 # unfiltered space, which means some hashes may be slightly longer.
1046 # unfiltered space, which means some hashes may be slightly longer.
1047 cl = mapping['ctx']._repo.unfiltered().changelog
1047 cl = mapping['ctx']._repo.unfiltered().changelog
1048 return cl.shortest(node, minlength)
1048 return cl.shortest(node, minlength)
1049
1049
1050 @templatefunc('strip(text[, chars])')
1050 @templatefunc('strip(text[, chars])')
1051 def strip(context, mapping, args):
1051 def strip(context, mapping, args):
1052 """Strip characters from a string. By default,
1052 """Strip characters from a string. By default,
1053 strips all leading and trailing whitespace."""
1053 strips all leading and trailing whitespace."""
1054 if not (1 <= len(args) <= 2):
1054 if not (1 <= len(args) <= 2):
1055 # i18n: "strip" is a keyword
1055 # i18n: "strip" is a keyword
1056 raise error.ParseError(_("strip expects one or two arguments"))
1056 raise error.ParseError(_("strip expects one or two arguments"))
1057
1057
1058 text = evalstring(context, mapping, args[0])
1058 text = evalstring(context, mapping, args[0])
1059 if len(args) == 2:
1059 if len(args) == 2:
1060 chars = evalstring(context, mapping, args[1])
1060 chars = evalstring(context, mapping, args[1])
1061 return text.strip(chars)
1061 return text.strip(chars)
1062 return text.strip()
1062 return text.strip()
1063
1063
1064 @templatefunc('sub(pattern, replacement, expression)')
1064 @templatefunc('sub(pattern, replacement, expression)')
1065 def sub(context, mapping, args):
1065 def sub(context, mapping, args):
1066 """Perform text substitution
1066 """Perform text substitution
1067 using regular expressions."""
1067 using regular expressions."""
1068 if len(args) != 3:
1068 if len(args) != 3:
1069 # i18n: "sub" is a keyword
1069 # i18n: "sub" is a keyword
1070 raise error.ParseError(_("sub expects three arguments"))
1070 raise error.ParseError(_("sub expects three arguments"))
1071
1071
1072 pat = evalstring(context, mapping, args[0])
1072 pat = evalstring(context, mapping, args[0])
1073 rpl = evalstring(context, mapping, args[1])
1073 rpl = evalstring(context, mapping, args[1])
1074 src = evalstring(context, mapping, args[2])
1074 src = evalstring(context, mapping, args[2])
1075 try:
1075 try:
1076 patre = re.compile(pat)
1076 patre = re.compile(pat)
1077 except re.error:
1077 except re.error:
1078 # i18n: "sub" is a keyword
1078 # i18n: "sub" is a keyword
1079 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
1079 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
1080 try:
1080 try:
1081 yield patre.sub(rpl, src)
1081 yield patre.sub(rpl, src)
1082 except re.error:
1082 except re.error:
1083 # i18n: "sub" is a keyword
1083 # i18n: "sub" is a keyword
1084 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
1084 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
1085
1085
1086 @templatefunc('startswith(pattern, text)')
1086 @templatefunc('startswith(pattern, text)')
1087 def startswith(context, mapping, args):
1087 def startswith(context, mapping, args):
1088 """Returns the value from the "text" argument
1088 """Returns the value from the "text" argument
1089 if it begins with the content from the "pattern" argument."""
1089 if it begins with the content from the "pattern" argument."""
1090 if len(args) != 2:
1090 if len(args) != 2:
1091 # i18n: "startswith" is a keyword
1091 # i18n: "startswith" is a keyword
1092 raise error.ParseError(_("startswith expects two arguments"))
1092 raise error.ParseError(_("startswith expects two arguments"))
1093
1093
1094 patn = evalstring(context, mapping, args[0])
1094 patn = evalstring(context, mapping, args[0])
1095 text = evalstring(context, mapping, args[1])
1095 text = evalstring(context, mapping, args[1])
1096 if text.startswith(patn):
1096 if text.startswith(patn):
1097 return text
1097 return text
1098 return ''
1098 return ''
1099
1099
1100 @templatefunc('word(number, text[, separator])')
1100 @templatefunc('word(number, text[, separator])')
1101 def word(context, mapping, args):
1101 def word(context, mapping, args):
1102 """Return the nth word from a string."""
1102 """Return the nth word from a string."""
1103 if not (2 <= len(args) <= 3):
1103 if not (2 <= len(args) <= 3):
1104 # i18n: "word" is a keyword
1104 # i18n: "word" is a keyword
1105 raise error.ParseError(_("word expects two or three arguments, got %d")
1105 raise error.ParseError(_("word expects two or three arguments, got %d")
1106 % len(args))
1106 % len(args))
1107
1107
1108 num = evalinteger(context, mapping, args[0],
1108 num = evalinteger(context, mapping, args[0],
1109 # i18n: "word" is a keyword
1109 # i18n: "word" is a keyword
1110 _("word expects an integer index"))
1110 _("word expects an integer index"))
1111 text = evalstring(context, mapping, args[1])
1111 text = evalstring(context, mapping, args[1])
1112 if len(args) == 3:
1112 if len(args) == 3:
1113 splitter = evalstring(context, mapping, args[2])
1113 splitter = evalstring(context, mapping, args[2])
1114 else:
1114 else:
1115 splitter = None
1115 splitter = None
1116
1116
1117 tokens = text.split(splitter)
1117 tokens = text.split(splitter)
1118 if num >= len(tokens) or num < -len(tokens):
1118 if num >= len(tokens) or num < -len(tokens):
1119 return ''
1119 return ''
1120 else:
1120 else:
1121 return tokens[num]
1121 return tokens[num]
1122
1122
1123 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1123 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1124 exprmethods = {
1124 exprmethods = {
1125 "integer": lambda e, c: (runinteger, e[1]),
1125 "integer": lambda e, c: (runinteger, e[1]),
1126 "string": lambda e, c: (runstring, e[1]),
1126 "string": lambda e, c: (runstring, e[1]),
1127 "symbol": lambda e, c: (runsymbol, e[1]),
1127 "symbol": lambda e, c: (runsymbol, e[1]),
1128 "template": buildtemplate,
1128 "template": buildtemplate,
1129 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1129 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1130 # ".": buildmember,
1130 # ".": buildmember,
1131 "|": buildfilter,
1131 "|": buildfilter,
1132 "%": buildmap,
1132 "%": buildmap,
1133 "func": buildfunc,
1133 "func": buildfunc,
1134 "keyvalue": buildkeyvaluepair,
1134 "keyvalue": buildkeyvaluepair,
1135 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1135 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1136 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1136 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1137 "negate": buildnegate,
1137 "negate": buildnegate,
1138 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1138 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1139 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1139 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1140 }
1140 }
1141
1141
1142 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1142 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1143 methods = exprmethods.copy()
1143 methods = exprmethods.copy()
1144 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1144 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1145
1145
1146 class _aliasrules(parser.basealiasrules):
1146 class _aliasrules(parser.basealiasrules):
1147 """Parsing and expansion rule set of template aliases"""
1147 """Parsing and expansion rule set of template aliases"""
1148 _section = _('template alias')
1148 _section = _('template alias')
1149 _parse = staticmethod(_parseexpr)
1149 _parse = staticmethod(_parseexpr)
1150
1150
1151 @staticmethod
1151 @staticmethod
1152 def _trygetfunc(tree):
1152 def _trygetfunc(tree):
1153 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1153 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1154 None"""
1154 None"""
1155 if tree[0] == 'func' and tree[1][0] == 'symbol':
1155 if tree[0] == 'func' and tree[1][0] == 'symbol':
1156 return tree[1][1], getlist(tree[2])
1156 return tree[1][1], getlist(tree[2])
1157 if tree[0] == '|' and tree[2][0] == 'symbol':
1157 if tree[0] == '|' and tree[2][0] == 'symbol':
1158 return tree[2][1], [tree[1]]
1158 return tree[2][1], [tree[1]]
1159
1159
1160 def expandaliases(tree, aliases):
1160 def expandaliases(tree, aliases):
1161 """Return new tree of aliases are expanded"""
1161 """Return new tree of aliases are expanded"""
1162 aliasmap = _aliasrules.buildmap(aliases)
1162 aliasmap = _aliasrules.buildmap(aliases)
1163 return _aliasrules.expand(aliasmap, tree)
1163 return _aliasrules.expand(aliasmap, tree)
1164
1164
1165 # template engine
1165 # template engine
1166
1166
1167 stringify = templatefilters.stringify
1167 stringify = templatefilters.stringify
1168
1168
1169 def _flatten(thing):
1169 def _flatten(thing):
1170 '''yield a single stream from a possibly nested set of iterators'''
1170 '''yield a single stream from a possibly nested set of iterators'''
1171 thing = templatekw.unwraphybrid(thing)
1171 thing = templatekw.unwraphybrid(thing)
1172 if isinstance(thing, bytes):
1172 if isinstance(thing, bytes):
1173 yield thing
1173 yield thing
1174 elif thing is None:
1174 elif thing is None:
1175 pass
1175 pass
1176 elif not util.safehasattr(thing, '__iter__'):
1176 elif not util.safehasattr(thing, '__iter__'):
1177 yield pycompat.bytestr(thing)
1177 yield pycompat.bytestr(thing)
1178 else:
1178 else:
1179 for i in thing:
1179 for i in thing:
1180 i = templatekw.unwraphybrid(i)
1180 i = templatekw.unwraphybrid(i)
1181 if isinstance(i, bytes):
1181 if isinstance(i, bytes):
1182 yield i
1182 yield i
1183 elif i is None:
1183 elif i is None:
1184 pass
1184 pass
1185 elif not util.safehasattr(i, '__iter__'):
1185 elif not util.safehasattr(i, '__iter__'):
1186 yield pycompat.bytestr(i)
1186 yield pycompat.bytestr(i)
1187 else:
1187 else:
1188 for j in _flatten(i):
1188 for j in _flatten(i):
1189 yield j
1189 yield j
1190
1190
1191 def unquotestring(s):
1191 def unquotestring(s):
1192 '''unwrap quotes if any; otherwise returns unmodified string'''
1192 '''unwrap quotes if any; otherwise returns unmodified string'''
1193 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1193 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1194 return s
1194 return s
1195 return s[1:-1]
1195 return s[1:-1]
1196
1196
1197 class engine(object):
1197 class engine(object):
1198 '''template expansion engine.
1198 '''template expansion engine.
1199
1199
1200 template expansion works like this. a map file contains key=value
1200 template expansion works like this. a map file contains key=value
1201 pairs. if value is quoted, it is treated as string. otherwise, it
1201 pairs. if value is quoted, it is treated as string. otherwise, it
1202 is treated as name of template file.
1202 is treated as name of template file.
1203
1203
1204 templater is asked to expand a key in map. it looks up key, and
1204 templater is asked to expand a key in map. it looks up key, and
1205 looks for strings like this: {foo}. it expands {foo} by looking up
1205 looks for strings like this: {foo}. it expands {foo} by looking up
1206 foo in map, and substituting it. expansion is recursive: it stops
1206 foo in map, and substituting it. expansion is recursive: it stops
1207 when there is no more {foo} to replace.
1207 when there is no more {foo} to replace.
1208
1208
1209 expansion also allows formatting and filtering.
1209 expansion also allows formatting and filtering.
1210
1210
1211 format uses key to expand each item in list. syntax is
1211 format uses key to expand each item in list. syntax is
1212 {key%format}.
1212 {key%format}.
1213
1213
1214 filter uses function to transform value. syntax is
1214 filter uses function to transform value. syntax is
1215 {key|filter1|filter2|...}.'''
1215 {key|filter1|filter2|...}.'''
1216
1216
1217 def __init__(self, loader, filters=None, defaults=None, aliases=()):
1217 def __init__(self, loader, filters=None, defaults=None, aliases=()):
1218 self._loader = loader
1218 self._loader = loader
1219 if filters is None:
1219 if filters is None:
1220 filters = {}
1220 filters = {}
1221 self._filters = filters
1221 self._filters = filters
1222 if defaults is None:
1222 if defaults is None:
1223 defaults = {}
1223 defaults = {}
1224 self._defaults = defaults
1224 self._defaults = defaults
1225 self._aliasmap = _aliasrules.buildmap(aliases)
1225 self._aliasmap = _aliasrules.buildmap(aliases)
1226 self._cache = {} # key: (func, data)
1226 self._cache = {} # key: (func, data)
1227
1227
1228 def _load(self, t):
1228 def _load(self, t):
1229 '''load, parse, and cache a template'''
1229 '''load, parse, and cache a template'''
1230 if t not in self._cache:
1230 if t not in self._cache:
1231 # put poison to cut recursion while compiling 't'
1231 # put poison to cut recursion while compiling 't'
1232 self._cache[t] = (_runrecursivesymbol, t)
1232 self._cache[t] = (_runrecursivesymbol, t)
1233 try:
1233 try:
1234 x = parse(self._loader(t))
1234 x = parse(self._loader(t))
1235 if self._aliasmap:
1235 if self._aliasmap:
1236 x = _aliasrules.expand(self._aliasmap, x)
1236 x = _aliasrules.expand(self._aliasmap, x)
1237 self._cache[t] = compileexp(x, self, methods)
1237 self._cache[t] = compileexp(x, self, methods)
1238 except: # re-raises
1238 except: # re-raises
1239 del self._cache[t]
1239 del self._cache[t]
1240 raise
1240 raise
1241 return self._cache[t]
1241 return self._cache[t]
1242
1242
1243 def process(self, t, mapping):
1243 def process(self, t, mapping):
1244 '''Perform expansion. t is name of map element to expand.
1244 '''Perform expansion. t is name of map element to expand.
1245 mapping contains added elements for use during expansion. Is a
1245 mapping contains added elements for use during expansion. Is a
1246 generator.'''
1246 generator.'''
1247 func, data = self._load(t)
1247 func, data = self._load(t)
1248 return _flatten(func(self, mapping, data))
1248 return _flatten(func(self, mapping, data))
1249
1249
1250 engines = {'default': engine}
1250 engines = {'default': engine}
1251
1251
1252 def stylelist():
1252 def stylelist():
1253 paths = templatepaths()
1253 paths = templatepaths()
1254 if not paths:
1254 if not paths:
1255 return _('no templates found, try `hg debuginstall` for more info')
1255 return _('no templates found, try `hg debuginstall` for more info')
1256 dirlist = os.listdir(paths[0])
1256 dirlist = os.listdir(paths[0])
1257 stylelist = []
1257 stylelist = []
1258 for file in dirlist:
1258 for file in dirlist:
1259 split = file.split(".")
1259 split = file.split(".")
1260 if split[-1] in ('orig', 'rej'):
1260 if split[-1] in ('orig', 'rej'):
1261 continue
1261 continue
1262 if split[0] == "map-cmdline":
1262 if split[0] == "map-cmdline":
1263 stylelist.append(split[1])
1263 stylelist.append(split[1])
1264 return ", ".join(sorted(stylelist))
1264 return ", ".join(sorted(stylelist))
1265
1265
1266 def _readmapfile(mapfile):
1266 def _readmapfile(mapfile):
1267 """Load template elements from the given map file"""
1267 """Load template elements from the given map file"""
1268 if not os.path.exists(mapfile):
1268 if not os.path.exists(mapfile):
1269 raise error.Abort(_("style '%s' not found") % mapfile,
1269 raise error.Abort(_("style '%s' not found") % mapfile,
1270 hint=_("available styles: %s") % stylelist())
1270 hint=_("available styles: %s") % stylelist())
1271
1271
1272 base = os.path.dirname(mapfile)
1272 base = os.path.dirname(mapfile)
1273 conf = config.config(includepaths=templatepaths())
1273 conf = config.config(includepaths=templatepaths())
1274 conf.read(mapfile)
1274 conf.read(mapfile)
1275
1275
1276 cache = {}
1276 cache = {}
1277 tmap = {}
1277 tmap = {}
1278 for key, val in conf[''].items():
1278 for key, val in conf[''].items():
1279 if not val:
1279 if not val:
1280 raise error.ParseError(_('missing value'), conf.source('', key))
1280 raise error.ParseError(_('missing value'), conf.source('', key))
1281 if val[0] in "'\"":
1281 if val[0] in "'\"":
1282 if val[0] != val[-1]:
1282 if val[0] != val[-1]:
1283 raise error.ParseError(_('unmatched quotes'),
1283 raise error.ParseError(_('unmatched quotes'),
1284 conf.source('', key))
1284 conf.source('', key))
1285 cache[key] = unquotestring(val)
1285 cache[key] = unquotestring(val)
1286 elif key == "__base__":
1286 elif key == "__base__":
1287 # treat as a pointer to a base class for this style
1287 # treat as a pointer to a base class for this style
1288 path = util.normpath(os.path.join(base, val))
1288 path = util.normpath(os.path.join(base, val))
1289
1289
1290 # fallback check in template paths
1290 # fallback check in template paths
1291 if not os.path.exists(path):
1291 if not os.path.exists(path):
1292 for p in templatepaths():
1292 for p in templatepaths():
1293 p2 = util.normpath(os.path.join(p, val))
1293 p2 = util.normpath(os.path.join(p, val))
1294 if os.path.isfile(p2):
1294 if os.path.isfile(p2):
1295 path = p2
1295 path = p2
1296 break
1296 break
1297 p3 = util.normpath(os.path.join(p2, "map"))
1297 p3 = util.normpath(os.path.join(p2, "map"))
1298 if os.path.isfile(p3):
1298 if os.path.isfile(p3):
1299 path = p3
1299 path = p3
1300 break
1300 break
1301
1301
1302 bcache, btmap = _readmapfile(path)
1302 bcache, btmap = _readmapfile(path)
1303 for k in bcache:
1303 for k in bcache:
1304 if k not in cache:
1304 if k not in cache:
1305 cache[k] = bcache[k]
1305 cache[k] = bcache[k]
1306 for k in btmap:
1306 for k in btmap:
1307 if k not in tmap:
1307 if k not in tmap:
1308 tmap[k] = btmap[k]
1308 tmap[k] = btmap[k]
1309 else:
1309 else:
1310 val = 'default', val
1310 val = 'default', val
1311 if ':' in val[1]:
1311 if ':' in val[1]:
1312 val = val[1].split(':', 1)
1312 val = val[1].split(':', 1)
1313 tmap[key] = val[0], os.path.join(base, val[1])
1313 tmap[key] = val[0], os.path.join(base, val[1])
1314 return cache, tmap
1314 return cache, tmap
1315
1315
1316 class TemplateNotFound(error.Abort):
1316 class TemplateNotFound(error.Abort):
1317 pass
1317 pass
1318
1318
1319 class templater(object):
1319 class templater(object):
1320
1320
1321 def __init__(self, filters=None, defaults=None, cache=None, aliases=(),
1321 def __init__(self, filters=None, defaults=None, cache=None, aliases=(),
1322 minchunk=1024, maxchunk=65536):
1322 minchunk=1024, maxchunk=65536):
1323 '''set up template engine.
1323 '''set up template engine.
1324 filters is dict of functions. each transforms a value into another.
1324 filters is dict of functions. each transforms a value into another.
1325 defaults is dict of default map definitions.
1325 defaults is dict of default map definitions.
1326 aliases is list of alias (name, replacement) pairs.
1326 aliases is list of alias (name, replacement) pairs.
1327 '''
1327 '''
1328 if filters is None:
1328 if filters is None:
1329 filters = {}
1329 filters = {}
1330 if defaults is None:
1330 if defaults is None:
1331 defaults = {}
1331 defaults = {}
1332 if cache is None:
1332 if cache is None:
1333 cache = {}
1333 cache = {}
1334 self.cache = cache.copy()
1334 self.cache = cache.copy()
1335 self.map = {}
1335 self.map = {}
1336 self.filters = templatefilters.filters.copy()
1336 self.filters = templatefilters.filters.copy()
1337 self.filters.update(filters)
1337 self.filters.update(filters)
1338 self.defaults = defaults
1338 self.defaults = defaults
1339 self._aliases = aliases
1339 self._aliases = aliases
1340 self.minchunk, self.maxchunk = minchunk, maxchunk
1340 self.minchunk, self.maxchunk = minchunk, maxchunk
1341 self.ecache = {}
1341 self.ecache = {}
1342
1342
1343 @classmethod
1343 @classmethod
1344 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None,
1344 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None,
1345 minchunk=1024, maxchunk=65536):
1345 minchunk=1024, maxchunk=65536):
1346 """Create templater from the specified map file"""
1346 """Create templater from the specified map file"""
1347 t = cls(filters, defaults, cache, [], minchunk, maxchunk)
1347 t = cls(filters, defaults, cache, [], minchunk, maxchunk)
1348 cache, tmap = _readmapfile(mapfile)
1348 cache, tmap = _readmapfile(mapfile)
1349 t.cache.update(cache)
1349 t.cache.update(cache)
1350 t.map = tmap
1350 t.map = tmap
1351 return t
1351 return t
1352
1352
1353 def __contains__(self, key):
1353 def __contains__(self, key):
1354 return key in self.cache or key in self.map
1354 return key in self.cache or key in self.map
1355
1355
1356 def load(self, t):
1356 def load(self, t):
1357 '''Get the template for the given template name. Use a local cache.'''
1357 '''Get the template for the given template name. Use a local cache.'''
1358 if t not in self.cache:
1358 if t not in self.cache:
1359 try:
1359 try:
1360 self.cache[t] = util.readfile(self.map[t][1])
1360 self.cache[t] = util.readfile(self.map[t][1])
1361 except KeyError as inst:
1361 except KeyError as inst:
1362 raise TemplateNotFound(_('"%s" not in template map') %
1362 raise TemplateNotFound(_('"%s" not in template map') %
1363 inst.args[0])
1363 inst.args[0])
1364 except IOError as inst:
1364 except IOError as inst:
1365 raise IOError(inst.args[0], _('template file %s: %s') %
1365 raise IOError(inst.args[0], _('template file %s: %s') %
1366 (self.map[t][1], inst.args[1]))
1366 (self.map[t][1], inst.args[1]))
1367 return self.cache[t]
1367 return self.cache[t]
1368
1368
1369 def render(self, mapping):
1369 def render(self, mapping):
1370 """Render the default unnamed template and return result as string"""
1370 """Render the default unnamed template and return result as string"""
1371 return stringify(self('', **mapping))
1371 return stringify(self('', **mapping))
1372
1372
1373 def __call__(self, t, **mapping):
1373 def __call__(self, t, **mapping):
1374 mapping = pycompat.byteskwargs(mapping)
1374 mapping = pycompat.byteskwargs(mapping)
1375 ttype = t in self.map and self.map[t][0] or 'default'
1375 ttype = t in self.map and self.map[t][0] or 'default'
1376 if ttype not in self.ecache:
1376 if ttype not in self.ecache:
1377 try:
1377 try:
1378 ecls = engines[ttype]
1378 ecls = engines[ttype]
1379 except KeyError:
1379 except KeyError:
1380 raise error.Abort(_('invalid template engine: %s') % ttype)
1380 raise error.Abort(_('invalid template engine: %s') % ttype)
1381 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1381 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1382 self._aliases)
1382 self._aliases)
1383 proc = self.ecache[ttype]
1383 proc = self.ecache[ttype]
1384
1384
1385 stream = proc.process(t, mapping)
1385 stream = proc.process(t, mapping)
1386 if self.minchunk:
1386 if self.minchunk:
1387 stream = util.increasingchunks(stream, min=self.minchunk,
1387 stream = util.increasingchunks(stream, min=self.minchunk,
1388 max=self.maxchunk)
1388 max=self.maxchunk)
1389 return stream
1389 return stream
1390
1390
1391 def templatepaths():
1391 def templatepaths():
1392 '''return locations used for template files.'''
1392 '''return locations used for template files.'''
1393 pathsrel = ['templates']
1393 pathsrel = ['templates']
1394 paths = [os.path.normpath(os.path.join(util.datapath, f))
1394 paths = [os.path.normpath(os.path.join(util.datapath, f))
1395 for f in pathsrel]
1395 for f in pathsrel]
1396 return [p for p in paths if os.path.isdir(p)]
1396 return [p for p in paths if os.path.isdir(p)]
1397
1397
1398 def templatepath(name):
1398 def templatepath(name):
1399 '''return location of template file. returns None if not found.'''
1399 '''return location of template file. returns None if not found.'''
1400 for p in templatepaths():
1400 for p in templatepaths():
1401 f = os.path.join(p, name)
1401 f = os.path.join(p, name)
1402 if os.path.exists(f):
1402 if os.path.exists(f):
1403 return f
1403 return f
1404 return None
1404 return None
1405
1405
1406 def stylemap(styles, paths=None):
1406 def stylemap(styles, paths=None):
1407 """Return path to mapfile for a given style.
1407 """Return path to mapfile for a given style.
1408
1408
1409 Searches mapfile in the following locations:
1409 Searches mapfile in the following locations:
1410 1. templatepath/style/map
1410 1. templatepath/style/map
1411 2. templatepath/map-style
1411 2. templatepath/map-style
1412 3. templatepath/map
1412 3. templatepath/map
1413 """
1413 """
1414
1414
1415 if paths is None:
1415 if paths is None:
1416 paths = templatepaths()
1416 paths = templatepaths()
1417 elif isinstance(paths, str):
1417 elif isinstance(paths, str):
1418 paths = [paths]
1418 paths = [paths]
1419
1419
1420 if isinstance(styles, str):
1420 if isinstance(styles, str):
1421 styles = [styles]
1421 styles = [styles]
1422
1422
1423 for style in styles:
1423 for style in styles:
1424 # only plain name is allowed to honor template paths
1424 # only plain name is allowed to honor template paths
1425 if (not style
1425 if (not style
1426 or style in (os.curdir, os.pardir)
1426 or style in (os.curdir, os.pardir)
1427 or pycompat.ossep in style
1427 or pycompat.ossep in style
1428 or pycompat.osaltsep and pycompat.osaltsep in style):
1428 or pycompat.osaltsep and pycompat.osaltsep in style):
1429 continue
1429 continue
1430 locations = [os.path.join(style, 'map'), 'map-' + style]
1430 locations = [os.path.join(style, 'map'), 'map-' + style]
1431 locations.append('map')
1431 locations.append('map')
1432
1432
1433 for path in paths:
1433 for path in paths:
1434 for location in locations:
1434 for location in locations:
1435 mapfile = os.path.join(path, location)
1435 mapfile = os.path.join(path, location)
1436 if os.path.isfile(mapfile):
1436 if os.path.isfile(mapfile):
1437 return style, mapfile
1437 return style, mapfile
1438
1438
1439 raise RuntimeError("No hgweb templates found in %r" % paths)
1439 raise RuntimeError("No hgweb templates found in %r" % paths)
1440
1440
1441 def loadfunction(ui, extname, registrarobj):
1441 def loadfunction(ui, extname, registrarobj):
1442 """Load template function from specified registrarobj
1442 """Load template function from specified registrarobj
1443 """
1443 """
1444 for name, func in registrarobj._table.iteritems():
1444 for name, func in registrarobj._table.iteritems():
1445 funcs[name] = func
1445 funcs[name] = func
1446
1446
1447 # tell hggettext to extract docstrings from these functions:
1447 # tell hggettext to extract docstrings from these functions:
1448 i18nfunctions = funcs.values()
1448 i18nfunctions = funcs.values()
@@ -1,4571 +1,4585
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Test arithmetic operators have the right precedence:
32 Test arithmetic operators have the right precedence:
33
33
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
35 2020 1964
35 2020 1964
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
37 9860 5908
37 9860 5908
38
38
39 Test division:
39 Test division:
40
40
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
42 (template
42 (template
43 (/
43 (/
44 (integer '5')
44 (integer '5')
45 (integer '2'))
45 (integer '2'))
46 (string ' ')
46 (string ' ')
47 (func
47 (func
48 (symbol 'mod')
48 (symbol 'mod')
49 (list
49 (list
50 (integer '5')
50 (integer '5')
51 (integer '2')))
51 (integer '2')))
52 (string '\n'))
52 (string '\n'))
53 2 1
53 2 1
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
55 (template
55 (template
56 (/
56 (/
57 (integer '5')
57 (integer '5')
58 (negate
58 (negate
59 (integer '2')))
59 (integer '2')))
60 (string ' ')
60 (string ' ')
61 (func
61 (func
62 (symbol 'mod')
62 (symbol 'mod')
63 (list
63 (list
64 (integer '5')
64 (integer '5')
65 (negate
65 (negate
66 (integer '2'))))
66 (integer '2'))))
67 (string '\n'))
67 (string '\n'))
68 -3 -1
68 -3 -1
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
70 (template
70 (template
71 (/
71 (/
72 (negate
72 (negate
73 (integer '5'))
73 (integer '5'))
74 (integer '2'))
74 (integer '2'))
75 (string ' ')
75 (string ' ')
76 (func
76 (func
77 (symbol 'mod')
77 (symbol 'mod')
78 (list
78 (list
79 (negate
79 (negate
80 (integer '5'))
80 (integer '5'))
81 (integer '2')))
81 (integer '2')))
82 (string '\n'))
82 (string '\n'))
83 -3 1
83 -3 1
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
85 (template
85 (template
86 (/
86 (/
87 (negate
87 (negate
88 (integer '5'))
88 (integer '5'))
89 (negate
89 (negate
90 (integer '2')))
90 (integer '2')))
91 (string ' ')
91 (string ' ')
92 (func
92 (func
93 (symbol 'mod')
93 (symbol 'mod')
94 (list
94 (list
95 (negate
95 (negate
96 (integer '5'))
96 (integer '5'))
97 (negate
97 (negate
98 (integer '2'))))
98 (integer '2'))))
99 (string '\n'))
99 (string '\n'))
100 2 -1
100 2 -1
101
101
102 Filters bind closer than arithmetic:
102 Filters bind closer than arithmetic:
103
103
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
105 (template
105 (template
106 (-
106 (-
107 (|
107 (|
108 (func
108 (func
109 (symbol 'revset')
109 (symbol 'revset')
110 (string '.'))
110 (string '.'))
111 (symbol 'count'))
111 (symbol 'count'))
112 (integer '1'))
112 (integer '1'))
113 (string '\n'))
113 (string '\n'))
114 0
114 0
115
115
116 But negate binds closer still:
116 But negate binds closer still:
117
117
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
119 (template
119 (template
120 (-
120 (-
121 (integer '1')
121 (integer '1')
122 (|
122 (|
123 (integer '3')
123 (integer '3')
124 (symbol 'stringify')))
124 (symbol 'stringify')))
125 (string '\n'))
125 (string '\n'))
126 hg: parse error: arithmetic only defined on integers
126 hg: parse error: arithmetic only defined on integers
127 [255]
127 [255]
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
129 (template
129 (template
130 (|
130 (|
131 (negate
131 (negate
132 (integer '3'))
132 (integer '3'))
133 (symbol 'stringify'))
133 (symbol 'stringify'))
134 (string '\n'))
134 (string '\n'))
135 -3
135 -3
136
136
137 Filters bind as close as map operator:
138
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
140 (template
141 (%
142 (|
143 (symbol 'desc')
144 (symbol 'splitlines'))
145 (template
146 (symbol 'line')
147 (string '\n'))))
148 line 1
149 line 2
150
137 Keyword arguments:
151 Keyword arguments:
138
152
139 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
140 (template
154 (template
141 (keyvalue
155 (keyvalue
142 (symbol 'foo')
156 (symbol 'foo')
143 (|
157 (|
144 (symbol 'bar')
158 (symbol 'bar')
145 (symbol 'baz'))))
159 (symbol 'baz'))))
146 hg: parse error: can't use a key-value pair in this context
160 hg: parse error: can't use a key-value pair in this context
147 [255]
161 [255]
148
162
149 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
150 foo
164 foo
151
165
152 Call function which takes named arguments by filter syntax:
166 Call function which takes named arguments by filter syntax:
153
167
154 $ hg debugtemplate '{" "|separate}'
168 $ hg debugtemplate '{" "|separate}'
155 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
156 hg: parse error: unknown method 'list'
170 hg: parse error: unknown method 'list'
157 [255]
171 [255]
158
172
159 Second branch starting at nullrev:
173 Second branch starting at nullrev:
160
174
161 $ hg update null
175 $ hg update null
162 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
163 $ echo second > second
177 $ echo second > second
164 $ hg add second
178 $ hg add second
165 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
166 created new head
180 created new head
167
181
168 $ echo third > third
182 $ echo third > third
169 $ hg add third
183 $ hg add third
170 $ hg mv second fourth
184 $ hg mv second fourth
171 $ hg commit -m third -d "2020-01-01 10:01"
185 $ hg commit -m third -d "2020-01-01 10:01"
172
186
173 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
174 fourth (second)
188 fourth (second)
175 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
176 second -> fourth
190 second -> fourth
177 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
178 8 t
192 8 t
179 7 f
193 7 f
180
194
181 Working-directory revision has special identifiers, though they are still
195 Working-directory revision has special identifiers, though they are still
182 experimental:
196 experimental:
183
197
184 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
185 2147483647:ffffffffffffffffffffffffffffffffffffffff
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
186
200
187 Some keywords are invalid for working-directory revision, but they should
201 Some keywords are invalid for working-directory revision, but they should
188 never cause crash:
202 never cause crash:
189
203
190 $ hg log -r 'wdir()' -T '{manifest}\n'
204 $ hg log -r 'wdir()' -T '{manifest}\n'
191
205
192
206
193 Quoting for ui.logtemplate
207 Quoting for ui.logtemplate
194
208
195 $ hg tip --config "ui.logtemplate={rev}\n"
209 $ hg tip --config "ui.logtemplate={rev}\n"
196 8
210 8
197 $ hg tip --config "ui.logtemplate='{rev}\n'"
211 $ hg tip --config "ui.logtemplate='{rev}\n'"
198 8
212 8
199 $ hg tip --config 'ui.logtemplate="{rev}\n"'
213 $ hg tip --config 'ui.logtemplate="{rev}\n"'
200 8
214 8
201 $ hg tip --config 'ui.logtemplate=n{rev}\n'
215 $ hg tip --config 'ui.logtemplate=n{rev}\n'
202 n8
216 n8
203
217
204 Make sure user/global hgrc does not affect tests
218 Make sure user/global hgrc does not affect tests
205
219
206 $ echo '[ui]' > .hg/hgrc
220 $ echo '[ui]' > .hg/hgrc
207 $ echo 'logtemplate =' >> .hg/hgrc
221 $ echo 'logtemplate =' >> .hg/hgrc
208 $ echo 'style =' >> .hg/hgrc
222 $ echo 'style =' >> .hg/hgrc
209
223
210 Add some simple styles to settings
224 Add some simple styles to settings
211
225
212 $ cat <<'EOF' >> .hg/hgrc
226 $ cat <<'EOF' >> .hg/hgrc
213 > [templates]
227 > [templates]
214 > simple = "{rev}\n"
228 > simple = "{rev}\n"
215 > simple2 = {rev}\n
229 > simple2 = {rev}\n
216 > rev = "should not precede {rev} keyword\n"
230 > rev = "should not precede {rev} keyword\n"
217 > EOF
231 > EOF
218
232
219 $ hg log -l1 -Tsimple
233 $ hg log -l1 -Tsimple
220 8
234 8
221 $ hg log -l1 -Tsimple2
235 $ hg log -l1 -Tsimple2
222 8
236 8
223 $ hg log -l1 -Trev
237 $ hg log -l1 -Trev
224 should not precede 8 keyword
238 should not precede 8 keyword
225 $ hg log -l1 -T '{simple}'
239 $ hg log -l1 -T '{simple}'
226 8
240 8
227
241
228 Map file shouldn't see user templates:
242 Map file shouldn't see user templates:
229
243
230 $ cat <<EOF > tmpl
244 $ cat <<EOF > tmpl
231 > changeset = 'nothing expanded:{simple}\n'
245 > changeset = 'nothing expanded:{simple}\n'
232 > EOF
246 > EOF
233 $ hg log -l1 --style ./tmpl
247 $ hg log -l1 --style ./tmpl
234 nothing expanded:
248 nothing expanded:
235
249
236 Test templates and style maps in files:
250 Test templates and style maps in files:
237
251
238 $ echo "{rev}" > tmpl
252 $ echo "{rev}" > tmpl
239 $ hg log -l1 -T./tmpl
253 $ hg log -l1 -T./tmpl
240 8
254 8
241 $ hg log -l1 -Tblah/blah
255 $ hg log -l1 -Tblah/blah
242 blah/blah (no-eol)
256 blah/blah (no-eol)
243
257
244 $ printf 'changeset = "{rev}\\n"\n' > map-simple
258 $ printf 'changeset = "{rev}\\n"\n' > map-simple
245 $ hg log -l1 -T./map-simple
259 $ hg log -l1 -T./map-simple
246 8
260 8
247
261
248 Test template map inheritance
262 Test template map inheritance
249
263
250 $ echo "__base__ = map-cmdline.default" > map-simple
264 $ echo "__base__ = map-cmdline.default" > map-simple
251 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
265 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
252 $ hg log -l1 -T./map-simple
266 $ hg log -l1 -T./map-simple
253 changeset: ***8***
267 changeset: ***8***
254 tag: tip
268 tag: tip
255 user: test
269 user: test
256 date: Wed Jan 01 10:01:00 2020 +0000
270 date: Wed Jan 01 10:01:00 2020 +0000
257 summary: third
271 summary: third
258
272
259
273
260 Test docheader, docfooter and separator in template map
274 Test docheader, docfooter and separator in template map
261
275
262 $ cat <<'EOF' > map-myjson
276 $ cat <<'EOF' > map-myjson
263 > docheader = '\{\n'
277 > docheader = '\{\n'
264 > docfooter = '\n}\n'
278 > docfooter = '\n}\n'
265 > separator = ',\n'
279 > separator = ',\n'
266 > changeset = ' {dict(rev, node|short)|json}'
280 > changeset = ' {dict(rev, node|short)|json}'
267 > EOF
281 > EOF
268 $ hg log -l2 -T./map-myjson
282 $ hg log -l2 -T./map-myjson
269 {
283 {
270 {"node": "95c24699272e", "rev": 8},
284 {"node": "95c24699272e", "rev": 8},
271 {"node": "29114dbae42b", "rev": 7}
285 {"node": "29114dbae42b", "rev": 7}
272 }
286 }
273
287
274 Test docheader, docfooter and separator in [templates] section
288 Test docheader, docfooter and separator in [templates] section
275
289
276 $ cat <<'EOF' >> .hg/hgrc
290 $ cat <<'EOF' >> .hg/hgrc
277 > [templates]
291 > [templates]
278 > myjson = ' {dict(rev, node|short)|json}'
292 > myjson = ' {dict(rev, node|short)|json}'
279 > myjson:docheader = '\{\n'
293 > myjson:docheader = '\{\n'
280 > myjson:docfooter = '\n}\n'
294 > myjson:docfooter = '\n}\n'
281 > myjson:separator = ',\n'
295 > myjson:separator = ',\n'
282 > :docheader = 'should not be selected as a docheader for literal templates\n'
296 > :docheader = 'should not be selected as a docheader for literal templates\n'
283 > EOF
297 > EOF
284 $ hg log -l2 -Tmyjson
298 $ hg log -l2 -Tmyjson
285 {
299 {
286 {"node": "95c24699272e", "rev": 8},
300 {"node": "95c24699272e", "rev": 8},
287 {"node": "29114dbae42b", "rev": 7}
301 {"node": "29114dbae42b", "rev": 7}
288 }
302 }
289 $ hg log -l1 -T'{rev}\n'
303 $ hg log -l1 -T'{rev}\n'
290 8
304 8
291
305
292 Template should precede style option
306 Template should precede style option
293
307
294 $ hg log -l1 --style default -T '{rev}\n'
308 $ hg log -l1 --style default -T '{rev}\n'
295 8
309 8
296
310
297 Add a commit with empty description, to ensure that the templates
311 Add a commit with empty description, to ensure that the templates
298 below will omit the description line.
312 below will omit the description line.
299
313
300 $ echo c >> c
314 $ echo c >> c
301 $ hg add c
315 $ hg add c
302 $ hg commit -qm ' '
316 $ hg commit -qm ' '
303
317
304 Default style is like normal output. Phases style should be the same
318 Default style is like normal output. Phases style should be the same
305 as default style, except for extra phase lines.
319 as default style, except for extra phase lines.
306
320
307 $ hg log > log.out
321 $ hg log > log.out
308 $ hg log --style default > style.out
322 $ hg log --style default > style.out
309 $ cmp log.out style.out || diff -u log.out style.out
323 $ cmp log.out style.out || diff -u log.out style.out
310 $ hg log -T phases > phases.out
324 $ hg log -T phases > phases.out
311 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
325 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
312 +phase: draft
326 +phase: draft
313 +phase: draft
327 +phase: draft
314 +phase: draft
328 +phase: draft
315 +phase: draft
329 +phase: draft
316 +phase: draft
330 +phase: draft
317 +phase: draft
331 +phase: draft
318 +phase: draft
332 +phase: draft
319 +phase: draft
333 +phase: draft
320 +phase: draft
334 +phase: draft
321 +phase: draft
335 +phase: draft
322
336
323 $ hg log -v > log.out
337 $ hg log -v > log.out
324 $ hg log -v --style default > style.out
338 $ hg log -v --style default > style.out
325 $ cmp log.out style.out || diff -u log.out style.out
339 $ cmp log.out style.out || diff -u log.out style.out
326 $ hg log -v -T phases > phases.out
340 $ hg log -v -T phases > phases.out
327 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
341 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
328 +phase: draft
342 +phase: draft
329 +phase: draft
343 +phase: draft
330 +phase: draft
344 +phase: draft
331 +phase: draft
345 +phase: draft
332 +phase: draft
346 +phase: draft
333 +phase: draft
347 +phase: draft
334 +phase: draft
348 +phase: draft
335 +phase: draft
349 +phase: draft
336 +phase: draft
350 +phase: draft
337 +phase: draft
351 +phase: draft
338
352
339 $ hg log -q > log.out
353 $ hg log -q > log.out
340 $ hg log -q --style default > style.out
354 $ hg log -q --style default > style.out
341 $ cmp log.out style.out || diff -u log.out style.out
355 $ cmp log.out style.out || diff -u log.out style.out
342 $ hg log -q -T phases > phases.out
356 $ hg log -q -T phases > phases.out
343 $ cmp log.out phases.out || diff -u log.out phases.out
357 $ cmp log.out phases.out || diff -u log.out phases.out
344
358
345 $ hg log --debug > log.out
359 $ hg log --debug > log.out
346 $ hg log --debug --style default > style.out
360 $ hg log --debug --style default > style.out
347 $ cmp log.out style.out || diff -u log.out style.out
361 $ cmp log.out style.out || diff -u log.out style.out
348 $ hg log --debug -T phases > phases.out
362 $ hg log --debug -T phases > phases.out
349 $ cmp log.out phases.out || diff -u log.out phases.out
363 $ cmp log.out phases.out || diff -u log.out phases.out
350
364
351 Default style of working-directory revision should also be the same (but
365 Default style of working-directory revision should also be the same (but
352 date may change while running tests):
366 date may change while running tests):
353
367
354 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
368 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
355 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
369 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
356 $ cmp log.out style.out || diff -u log.out style.out
370 $ cmp log.out style.out || diff -u log.out style.out
357
371
358 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
372 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
359 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
373 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
360 $ cmp log.out style.out || diff -u log.out style.out
374 $ cmp log.out style.out || diff -u log.out style.out
361
375
362 $ hg log -r 'wdir()' -q > log.out
376 $ hg log -r 'wdir()' -q > log.out
363 $ hg log -r 'wdir()' -q --style default > style.out
377 $ hg log -r 'wdir()' -q --style default > style.out
364 $ cmp log.out style.out || diff -u log.out style.out
378 $ cmp log.out style.out || diff -u log.out style.out
365
379
366 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
380 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
367 $ hg log -r 'wdir()' --debug --style default \
381 $ hg log -r 'wdir()' --debug --style default \
368 > | sed 's|^date:.*|date:|' > style.out
382 > | sed 's|^date:.*|date:|' > style.out
369 $ cmp log.out style.out || diff -u log.out style.out
383 $ cmp log.out style.out || diff -u log.out style.out
370
384
371 Default style should also preserve color information (issue2866):
385 Default style should also preserve color information (issue2866):
372
386
373 $ cp $HGRCPATH $HGRCPATH-bak
387 $ cp $HGRCPATH $HGRCPATH-bak
374 $ cat <<EOF >> $HGRCPATH
388 $ cat <<EOF >> $HGRCPATH
375 > [extensions]
389 > [extensions]
376 > color=
390 > color=
377 > EOF
391 > EOF
378
392
379 $ hg --color=debug log > log.out
393 $ hg --color=debug log > log.out
380 $ hg --color=debug log --style default > style.out
394 $ hg --color=debug log --style default > style.out
381 $ cmp log.out style.out || diff -u log.out style.out
395 $ cmp log.out style.out || diff -u log.out style.out
382 $ hg --color=debug log -T phases > phases.out
396 $ hg --color=debug log -T phases > phases.out
383 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
397 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
384 +[log.phase|phase: draft]
398 +[log.phase|phase: draft]
385 +[log.phase|phase: draft]
399 +[log.phase|phase: draft]
386 +[log.phase|phase: draft]
400 +[log.phase|phase: draft]
387 +[log.phase|phase: draft]
401 +[log.phase|phase: draft]
388 +[log.phase|phase: draft]
402 +[log.phase|phase: draft]
389 +[log.phase|phase: draft]
403 +[log.phase|phase: draft]
390 +[log.phase|phase: draft]
404 +[log.phase|phase: draft]
391 +[log.phase|phase: draft]
405 +[log.phase|phase: draft]
392 +[log.phase|phase: draft]
406 +[log.phase|phase: draft]
393 +[log.phase|phase: draft]
407 +[log.phase|phase: draft]
394
408
395 $ hg --color=debug -v log > log.out
409 $ hg --color=debug -v log > log.out
396 $ hg --color=debug -v log --style default > style.out
410 $ hg --color=debug -v log --style default > style.out
397 $ cmp log.out style.out || diff -u log.out style.out
411 $ cmp log.out style.out || diff -u log.out style.out
398 $ hg --color=debug -v log -T phases > phases.out
412 $ hg --color=debug -v log -T phases > phases.out
399 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
413 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
400 +[log.phase|phase: draft]
414 +[log.phase|phase: draft]
401 +[log.phase|phase: draft]
415 +[log.phase|phase: draft]
402 +[log.phase|phase: draft]
416 +[log.phase|phase: draft]
403 +[log.phase|phase: draft]
417 +[log.phase|phase: draft]
404 +[log.phase|phase: draft]
418 +[log.phase|phase: draft]
405 +[log.phase|phase: draft]
419 +[log.phase|phase: draft]
406 +[log.phase|phase: draft]
420 +[log.phase|phase: draft]
407 +[log.phase|phase: draft]
421 +[log.phase|phase: draft]
408 +[log.phase|phase: draft]
422 +[log.phase|phase: draft]
409 +[log.phase|phase: draft]
423 +[log.phase|phase: draft]
410
424
411 $ hg --color=debug -q log > log.out
425 $ hg --color=debug -q log > log.out
412 $ hg --color=debug -q log --style default > style.out
426 $ hg --color=debug -q log --style default > style.out
413 $ cmp log.out style.out || diff -u log.out style.out
427 $ cmp log.out style.out || diff -u log.out style.out
414 $ hg --color=debug -q log -T phases > phases.out
428 $ hg --color=debug -q log -T phases > phases.out
415 $ cmp log.out phases.out || diff -u log.out phases.out
429 $ cmp log.out phases.out || diff -u log.out phases.out
416
430
417 $ hg --color=debug --debug log > log.out
431 $ hg --color=debug --debug log > log.out
418 $ hg --color=debug --debug log --style default > style.out
432 $ hg --color=debug --debug log --style default > style.out
419 $ cmp log.out style.out || diff -u log.out style.out
433 $ cmp log.out style.out || diff -u log.out style.out
420 $ hg --color=debug --debug log -T phases > phases.out
434 $ hg --color=debug --debug log -T phases > phases.out
421 $ cmp log.out phases.out || diff -u log.out phases.out
435 $ cmp log.out phases.out || diff -u log.out phases.out
422
436
423 $ mv $HGRCPATH-bak $HGRCPATH
437 $ mv $HGRCPATH-bak $HGRCPATH
424
438
425 Remove commit with empty commit message, so as to not pollute further
439 Remove commit with empty commit message, so as to not pollute further
426 tests.
440 tests.
427
441
428 $ hg --config extensions.strip= strip -q .
442 $ hg --config extensions.strip= strip -q .
429
443
430 Revision with no copies (used to print a traceback):
444 Revision with no copies (used to print a traceback):
431
445
432 $ hg tip -v --template '\n'
446 $ hg tip -v --template '\n'
433
447
434
448
435 Compact style works:
449 Compact style works:
436
450
437 $ hg log -Tcompact
451 $ hg log -Tcompact
438 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
452 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
439 third
453 third
440
454
441 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
455 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
442 second
456 second
443
457
444 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
458 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
445 merge
459 merge
446
460
447 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
461 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
448 new head
462 new head
449
463
450 4 bbe44766e73d 1970-01-17 04:53 +0000 person
464 4 bbe44766e73d 1970-01-17 04:53 +0000 person
451 new branch
465 new branch
452
466
453 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
467 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
454 no user, no domain
468 no user, no domain
455
469
456 2 97054abb4ab8 1970-01-14 21:20 +0000 other
470 2 97054abb4ab8 1970-01-14 21:20 +0000 other
457 no person
471 no person
458
472
459 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
473 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
460 other 1
474 other 1
461
475
462 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
476 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
463 line 1
477 line 1
464
478
465
479
466 $ hg log -v --style compact
480 $ hg log -v --style compact
467 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
481 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
468 third
482 third
469
483
470 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
484 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
471 second
485 second
472
486
473 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
487 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
474 merge
488 merge
475
489
476 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
490 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
477 new head
491 new head
478
492
479 4 bbe44766e73d 1970-01-17 04:53 +0000 person
493 4 bbe44766e73d 1970-01-17 04:53 +0000 person
480 new branch
494 new branch
481
495
482 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
496 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
483 no user, no domain
497 no user, no domain
484
498
485 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
499 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
486 no person
500 no person
487
501
488 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
502 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
489 other 1
503 other 1
490 other 2
504 other 2
491
505
492 other 3
506 other 3
493
507
494 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
508 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
495 line 1
509 line 1
496 line 2
510 line 2
497
511
498
512
499 $ hg log --debug --style compact
513 $ hg log --debug --style compact
500 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
514 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
501 third
515 third
502
516
503 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
517 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
504 second
518 second
505
519
506 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
520 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
507 merge
521 merge
508
522
509 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
523 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
510 new head
524 new head
511
525
512 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
526 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
513 new branch
527 new branch
514
528
515 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
529 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
516 no user, no domain
530 no user, no domain
517
531
518 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
532 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
519 no person
533 no person
520
534
521 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
535 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
522 other 1
536 other 1
523 other 2
537 other 2
524
538
525 other 3
539 other 3
526
540
527 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
541 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
528 line 1
542 line 1
529 line 2
543 line 2
530
544
531
545
532 Test xml styles:
546 Test xml styles:
533
547
534 $ hg log --style xml -r 'not all()'
548 $ hg log --style xml -r 'not all()'
535 <?xml version="1.0"?>
549 <?xml version="1.0"?>
536 <log>
550 <log>
537 </log>
551 </log>
538
552
539 $ hg log --style xml
553 $ hg log --style xml
540 <?xml version="1.0"?>
554 <?xml version="1.0"?>
541 <log>
555 <log>
542 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
556 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
543 <tag>tip</tag>
557 <tag>tip</tag>
544 <author email="test">test</author>
558 <author email="test">test</author>
545 <date>2020-01-01T10:01:00+00:00</date>
559 <date>2020-01-01T10:01:00+00:00</date>
546 <msg xml:space="preserve">third</msg>
560 <msg xml:space="preserve">third</msg>
547 </logentry>
561 </logentry>
548 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
562 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
549 <parent revision="-1" node="0000000000000000000000000000000000000000" />
563 <parent revision="-1" node="0000000000000000000000000000000000000000" />
550 <author email="user@hostname">User Name</author>
564 <author email="user@hostname">User Name</author>
551 <date>1970-01-12T13:46:40+00:00</date>
565 <date>1970-01-12T13:46:40+00:00</date>
552 <msg xml:space="preserve">second</msg>
566 <msg xml:space="preserve">second</msg>
553 </logentry>
567 </logentry>
554 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
568 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
555 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
569 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
556 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
570 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
557 <author email="person">person</author>
571 <author email="person">person</author>
558 <date>1970-01-18T08:40:01+00:00</date>
572 <date>1970-01-18T08:40:01+00:00</date>
559 <msg xml:space="preserve">merge</msg>
573 <msg xml:space="preserve">merge</msg>
560 </logentry>
574 </logentry>
561 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
575 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
562 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
576 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
563 <author email="person">person</author>
577 <author email="person">person</author>
564 <date>1970-01-18T08:40:00+00:00</date>
578 <date>1970-01-18T08:40:00+00:00</date>
565 <msg xml:space="preserve">new head</msg>
579 <msg xml:space="preserve">new head</msg>
566 </logentry>
580 </logentry>
567 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
581 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
568 <branch>foo</branch>
582 <branch>foo</branch>
569 <author email="person">person</author>
583 <author email="person">person</author>
570 <date>1970-01-17T04:53:20+00:00</date>
584 <date>1970-01-17T04:53:20+00:00</date>
571 <msg xml:space="preserve">new branch</msg>
585 <msg xml:space="preserve">new branch</msg>
572 </logentry>
586 </logentry>
573 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
587 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
574 <author email="person">person</author>
588 <author email="person">person</author>
575 <date>1970-01-16T01:06:40+00:00</date>
589 <date>1970-01-16T01:06:40+00:00</date>
576 <msg xml:space="preserve">no user, no domain</msg>
590 <msg xml:space="preserve">no user, no domain</msg>
577 </logentry>
591 </logentry>
578 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
592 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
579 <author email="other@place">other</author>
593 <author email="other@place">other</author>
580 <date>1970-01-14T21:20:00+00:00</date>
594 <date>1970-01-14T21:20:00+00:00</date>
581 <msg xml:space="preserve">no person</msg>
595 <msg xml:space="preserve">no person</msg>
582 </logentry>
596 </logentry>
583 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
597 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
584 <author email="other@place">A. N. Other</author>
598 <author email="other@place">A. N. Other</author>
585 <date>1970-01-13T17:33:20+00:00</date>
599 <date>1970-01-13T17:33:20+00:00</date>
586 <msg xml:space="preserve">other 1
600 <msg xml:space="preserve">other 1
587 other 2
601 other 2
588
602
589 other 3</msg>
603 other 3</msg>
590 </logentry>
604 </logentry>
591 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
605 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
592 <author email="user@hostname">User Name</author>
606 <author email="user@hostname">User Name</author>
593 <date>1970-01-12T13:46:40+00:00</date>
607 <date>1970-01-12T13:46:40+00:00</date>
594 <msg xml:space="preserve">line 1
608 <msg xml:space="preserve">line 1
595 line 2</msg>
609 line 2</msg>
596 </logentry>
610 </logentry>
597 </log>
611 </log>
598
612
599 $ hg log -v --style xml
613 $ hg log -v --style xml
600 <?xml version="1.0"?>
614 <?xml version="1.0"?>
601 <log>
615 <log>
602 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
616 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
603 <tag>tip</tag>
617 <tag>tip</tag>
604 <author email="test">test</author>
618 <author email="test">test</author>
605 <date>2020-01-01T10:01:00+00:00</date>
619 <date>2020-01-01T10:01:00+00:00</date>
606 <msg xml:space="preserve">third</msg>
620 <msg xml:space="preserve">third</msg>
607 <paths>
621 <paths>
608 <path action="A">fourth</path>
622 <path action="A">fourth</path>
609 <path action="A">third</path>
623 <path action="A">third</path>
610 <path action="R">second</path>
624 <path action="R">second</path>
611 </paths>
625 </paths>
612 <copies>
626 <copies>
613 <copy source="second">fourth</copy>
627 <copy source="second">fourth</copy>
614 </copies>
628 </copies>
615 </logentry>
629 </logentry>
616 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
630 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
617 <parent revision="-1" node="0000000000000000000000000000000000000000" />
631 <parent revision="-1" node="0000000000000000000000000000000000000000" />
618 <author email="user@hostname">User Name</author>
632 <author email="user@hostname">User Name</author>
619 <date>1970-01-12T13:46:40+00:00</date>
633 <date>1970-01-12T13:46:40+00:00</date>
620 <msg xml:space="preserve">second</msg>
634 <msg xml:space="preserve">second</msg>
621 <paths>
635 <paths>
622 <path action="A">second</path>
636 <path action="A">second</path>
623 </paths>
637 </paths>
624 </logentry>
638 </logentry>
625 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
639 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
626 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
640 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
627 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
641 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
628 <author email="person">person</author>
642 <author email="person">person</author>
629 <date>1970-01-18T08:40:01+00:00</date>
643 <date>1970-01-18T08:40:01+00:00</date>
630 <msg xml:space="preserve">merge</msg>
644 <msg xml:space="preserve">merge</msg>
631 <paths>
645 <paths>
632 </paths>
646 </paths>
633 </logentry>
647 </logentry>
634 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
648 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
635 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
649 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
636 <author email="person">person</author>
650 <author email="person">person</author>
637 <date>1970-01-18T08:40:00+00:00</date>
651 <date>1970-01-18T08:40:00+00:00</date>
638 <msg xml:space="preserve">new head</msg>
652 <msg xml:space="preserve">new head</msg>
639 <paths>
653 <paths>
640 <path action="A">d</path>
654 <path action="A">d</path>
641 </paths>
655 </paths>
642 </logentry>
656 </logentry>
643 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
657 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
644 <branch>foo</branch>
658 <branch>foo</branch>
645 <author email="person">person</author>
659 <author email="person">person</author>
646 <date>1970-01-17T04:53:20+00:00</date>
660 <date>1970-01-17T04:53:20+00:00</date>
647 <msg xml:space="preserve">new branch</msg>
661 <msg xml:space="preserve">new branch</msg>
648 <paths>
662 <paths>
649 </paths>
663 </paths>
650 </logentry>
664 </logentry>
651 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
665 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
652 <author email="person">person</author>
666 <author email="person">person</author>
653 <date>1970-01-16T01:06:40+00:00</date>
667 <date>1970-01-16T01:06:40+00:00</date>
654 <msg xml:space="preserve">no user, no domain</msg>
668 <msg xml:space="preserve">no user, no domain</msg>
655 <paths>
669 <paths>
656 <path action="M">c</path>
670 <path action="M">c</path>
657 </paths>
671 </paths>
658 </logentry>
672 </logentry>
659 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
673 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
660 <author email="other@place">other</author>
674 <author email="other@place">other</author>
661 <date>1970-01-14T21:20:00+00:00</date>
675 <date>1970-01-14T21:20:00+00:00</date>
662 <msg xml:space="preserve">no person</msg>
676 <msg xml:space="preserve">no person</msg>
663 <paths>
677 <paths>
664 <path action="A">c</path>
678 <path action="A">c</path>
665 </paths>
679 </paths>
666 </logentry>
680 </logentry>
667 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
681 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
668 <author email="other@place">A. N. Other</author>
682 <author email="other@place">A. N. Other</author>
669 <date>1970-01-13T17:33:20+00:00</date>
683 <date>1970-01-13T17:33:20+00:00</date>
670 <msg xml:space="preserve">other 1
684 <msg xml:space="preserve">other 1
671 other 2
685 other 2
672
686
673 other 3</msg>
687 other 3</msg>
674 <paths>
688 <paths>
675 <path action="A">b</path>
689 <path action="A">b</path>
676 </paths>
690 </paths>
677 </logentry>
691 </logentry>
678 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
692 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
679 <author email="user@hostname">User Name</author>
693 <author email="user@hostname">User Name</author>
680 <date>1970-01-12T13:46:40+00:00</date>
694 <date>1970-01-12T13:46:40+00:00</date>
681 <msg xml:space="preserve">line 1
695 <msg xml:space="preserve">line 1
682 line 2</msg>
696 line 2</msg>
683 <paths>
697 <paths>
684 <path action="A">a</path>
698 <path action="A">a</path>
685 </paths>
699 </paths>
686 </logentry>
700 </logentry>
687 </log>
701 </log>
688
702
689 $ hg log --debug --style xml
703 $ hg log --debug --style xml
690 <?xml version="1.0"?>
704 <?xml version="1.0"?>
691 <log>
705 <log>
692 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
706 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
693 <tag>tip</tag>
707 <tag>tip</tag>
694 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
708 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
695 <parent revision="-1" node="0000000000000000000000000000000000000000" />
709 <parent revision="-1" node="0000000000000000000000000000000000000000" />
696 <author email="test">test</author>
710 <author email="test">test</author>
697 <date>2020-01-01T10:01:00+00:00</date>
711 <date>2020-01-01T10:01:00+00:00</date>
698 <msg xml:space="preserve">third</msg>
712 <msg xml:space="preserve">third</msg>
699 <paths>
713 <paths>
700 <path action="A">fourth</path>
714 <path action="A">fourth</path>
701 <path action="A">third</path>
715 <path action="A">third</path>
702 <path action="R">second</path>
716 <path action="R">second</path>
703 </paths>
717 </paths>
704 <copies>
718 <copies>
705 <copy source="second">fourth</copy>
719 <copy source="second">fourth</copy>
706 </copies>
720 </copies>
707 <extra key="branch">default</extra>
721 <extra key="branch">default</extra>
708 </logentry>
722 </logentry>
709 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
723 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
710 <parent revision="-1" node="0000000000000000000000000000000000000000" />
724 <parent revision="-1" node="0000000000000000000000000000000000000000" />
711 <parent revision="-1" node="0000000000000000000000000000000000000000" />
725 <parent revision="-1" node="0000000000000000000000000000000000000000" />
712 <author email="user@hostname">User Name</author>
726 <author email="user@hostname">User Name</author>
713 <date>1970-01-12T13:46:40+00:00</date>
727 <date>1970-01-12T13:46:40+00:00</date>
714 <msg xml:space="preserve">second</msg>
728 <msg xml:space="preserve">second</msg>
715 <paths>
729 <paths>
716 <path action="A">second</path>
730 <path action="A">second</path>
717 </paths>
731 </paths>
718 <extra key="branch">default</extra>
732 <extra key="branch">default</extra>
719 </logentry>
733 </logentry>
720 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
734 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
721 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
735 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
722 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
736 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
723 <author email="person">person</author>
737 <author email="person">person</author>
724 <date>1970-01-18T08:40:01+00:00</date>
738 <date>1970-01-18T08:40:01+00:00</date>
725 <msg xml:space="preserve">merge</msg>
739 <msg xml:space="preserve">merge</msg>
726 <paths>
740 <paths>
727 </paths>
741 </paths>
728 <extra key="branch">default</extra>
742 <extra key="branch">default</extra>
729 </logentry>
743 </logentry>
730 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
744 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
731 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
745 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
732 <parent revision="-1" node="0000000000000000000000000000000000000000" />
746 <parent revision="-1" node="0000000000000000000000000000000000000000" />
733 <author email="person">person</author>
747 <author email="person">person</author>
734 <date>1970-01-18T08:40:00+00:00</date>
748 <date>1970-01-18T08:40:00+00:00</date>
735 <msg xml:space="preserve">new head</msg>
749 <msg xml:space="preserve">new head</msg>
736 <paths>
750 <paths>
737 <path action="A">d</path>
751 <path action="A">d</path>
738 </paths>
752 </paths>
739 <extra key="branch">default</extra>
753 <extra key="branch">default</extra>
740 </logentry>
754 </logentry>
741 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
755 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
742 <branch>foo</branch>
756 <branch>foo</branch>
743 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
757 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
744 <parent revision="-1" node="0000000000000000000000000000000000000000" />
758 <parent revision="-1" node="0000000000000000000000000000000000000000" />
745 <author email="person">person</author>
759 <author email="person">person</author>
746 <date>1970-01-17T04:53:20+00:00</date>
760 <date>1970-01-17T04:53:20+00:00</date>
747 <msg xml:space="preserve">new branch</msg>
761 <msg xml:space="preserve">new branch</msg>
748 <paths>
762 <paths>
749 </paths>
763 </paths>
750 <extra key="branch">foo</extra>
764 <extra key="branch">foo</extra>
751 </logentry>
765 </logentry>
752 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
766 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
753 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
767 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
754 <parent revision="-1" node="0000000000000000000000000000000000000000" />
768 <parent revision="-1" node="0000000000000000000000000000000000000000" />
755 <author email="person">person</author>
769 <author email="person">person</author>
756 <date>1970-01-16T01:06:40+00:00</date>
770 <date>1970-01-16T01:06:40+00:00</date>
757 <msg xml:space="preserve">no user, no domain</msg>
771 <msg xml:space="preserve">no user, no domain</msg>
758 <paths>
772 <paths>
759 <path action="M">c</path>
773 <path action="M">c</path>
760 </paths>
774 </paths>
761 <extra key="branch">default</extra>
775 <extra key="branch">default</extra>
762 </logentry>
776 </logentry>
763 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
777 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
764 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
778 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
765 <parent revision="-1" node="0000000000000000000000000000000000000000" />
779 <parent revision="-1" node="0000000000000000000000000000000000000000" />
766 <author email="other@place">other</author>
780 <author email="other@place">other</author>
767 <date>1970-01-14T21:20:00+00:00</date>
781 <date>1970-01-14T21:20:00+00:00</date>
768 <msg xml:space="preserve">no person</msg>
782 <msg xml:space="preserve">no person</msg>
769 <paths>
783 <paths>
770 <path action="A">c</path>
784 <path action="A">c</path>
771 </paths>
785 </paths>
772 <extra key="branch">default</extra>
786 <extra key="branch">default</extra>
773 </logentry>
787 </logentry>
774 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
788 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
775 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
789 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
776 <parent revision="-1" node="0000000000000000000000000000000000000000" />
790 <parent revision="-1" node="0000000000000000000000000000000000000000" />
777 <author email="other@place">A. N. Other</author>
791 <author email="other@place">A. N. Other</author>
778 <date>1970-01-13T17:33:20+00:00</date>
792 <date>1970-01-13T17:33:20+00:00</date>
779 <msg xml:space="preserve">other 1
793 <msg xml:space="preserve">other 1
780 other 2
794 other 2
781
795
782 other 3</msg>
796 other 3</msg>
783 <paths>
797 <paths>
784 <path action="A">b</path>
798 <path action="A">b</path>
785 </paths>
799 </paths>
786 <extra key="branch">default</extra>
800 <extra key="branch">default</extra>
787 </logentry>
801 </logentry>
788 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
802 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
789 <parent revision="-1" node="0000000000000000000000000000000000000000" />
803 <parent revision="-1" node="0000000000000000000000000000000000000000" />
790 <parent revision="-1" node="0000000000000000000000000000000000000000" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
791 <author email="user@hostname">User Name</author>
805 <author email="user@hostname">User Name</author>
792 <date>1970-01-12T13:46:40+00:00</date>
806 <date>1970-01-12T13:46:40+00:00</date>
793 <msg xml:space="preserve">line 1
807 <msg xml:space="preserve">line 1
794 line 2</msg>
808 line 2</msg>
795 <paths>
809 <paths>
796 <path action="A">a</path>
810 <path action="A">a</path>
797 </paths>
811 </paths>
798 <extra key="branch">default</extra>
812 <extra key="branch">default</extra>
799 </logentry>
813 </logentry>
800 </log>
814 </log>
801
815
802
816
803 Test JSON style:
817 Test JSON style:
804
818
805 $ hg log -k nosuch -Tjson
819 $ hg log -k nosuch -Tjson
806 []
820 []
807
821
808 $ hg log -qr . -Tjson
822 $ hg log -qr . -Tjson
809 [
823 [
810 {
824 {
811 "rev": 8,
825 "rev": 8,
812 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
826 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
813 }
827 }
814 ]
828 ]
815
829
816 $ hg log -vpr . -Tjson --stat
830 $ hg log -vpr . -Tjson --stat
817 [
831 [
818 {
832 {
819 "rev": 8,
833 "rev": 8,
820 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
834 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
821 "branch": "default",
835 "branch": "default",
822 "phase": "draft",
836 "phase": "draft",
823 "user": "test",
837 "user": "test",
824 "date": [1577872860, 0],
838 "date": [1577872860, 0],
825 "desc": "third",
839 "desc": "third",
826 "bookmarks": [],
840 "bookmarks": [],
827 "tags": ["tip"],
841 "tags": ["tip"],
828 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
842 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
829 "files": ["fourth", "second", "third"],
843 "files": ["fourth", "second", "third"],
830 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
844 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
831 "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"
845 "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"
832 }
846 }
833 ]
847 ]
834
848
835 honor --git but not format-breaking diffopts
849 honor --git but not format-breaking diffopts
836 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
850 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
837 [
851 [
838 {
852 {
839 "rev": 8,
853 "rev": 8,
840 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
854 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
841 "branch": "default",
855 "branch": "default",
842 "phase": "draft",
856 "phase": "draft",
843 "user": "test",
857 "user": "test",
844 "date": [1577872860, 0],
858 "date": [1577872860, 0],
845 "desc": "third",
859 "desc": "third",
846 "bookmarks": [],
860 "bookmarks": [],
847 "tags": ["tip"],
861 "tags": ["tip"],
848 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
862 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
849 "files": ["fourth", "second", "third"],
863 "files": ["fourth", "second", "third"],
850 "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"
864 "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"
851 }
865 }
852 ]
866 ]
853
867
854 $ hg log -T json
868 $ hg log -T json
855 [
869 [
856 {
870 {
857 "rev": 8,
871 "rev": 8,
858 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
872 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
859 "branch": "default",
873 "branch": "default",
860 "phase": "draft",
874 "phase": "draft",
861 "user": "test",
875 "user": "test",
862 "date": [1577872860, 0],
876 "date": [1577872860, 0],
863 "desc": "third",
877 "desc": "third",
864 "bookmarks": [],
878 "bookmarks": [],
865 "tags": ["tip"],
879 "tags": ["tip"],
866 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
880 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
867 },
881 },
868 {
882 {
869 "rev": 7,
883 "rev": 7,
870 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
884 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
871 "branch": "default",
885 "branch": "default",
872 "phase": "draft",
886 "phase": "draft",
873 "user": "User Name <user@hostname>",
887 "user": "User Name <user@hostname>",
874 "date": [1000000, 0],
888 "date": [1000000, 0],
875 "desc": "second",
889 "desc": "second",
876 "bookmarks": [],
890 "bookmarks": [],
877 "tags": [],
891 "tags": [],
878 "parents": ["0000000000000000000000000000000000000000"]
892 "parents": ["0000000000000000000000000000000000000000"]
879 },
893 },
880 {
894 {
881 "rev": 6,
895 "rev": 6,
882 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
896 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
883 "branch": "default",
897 "branch": "default",
884 "phase": "draft",
898 "phase": "draft",
885 "user": "person",
899 "user": "person",
886 "date": [1500001, 0],
900 "date": [1500001, 0],
887 "desc": "merge",
901 "desc": "merge",
888 "bookmarks": [],
902 "bookmarks": [],
889 "tags": [],
903 "tags": [],
890 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
904 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
891 },
905 },
892 {
906 {
893 "rev": 5,
907 "rev": 5,
894 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
908 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
895 "branch": "default",
909 "branch": "default",
896 "phase": "draft",
910 "phase": "draft",
897 "user": "person",
911 "user": "person",
898 "date": [1500000, 0],
912 "date": [1500000, 0],
899 "desc": "new head",
913 "desc": "new head",
900 "bookmarks": [],
914 "bookmarks": [],
901 "tags": [],
915 "tags": [],
902 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
916 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
903 },
917 },
904 {
918 {
905 "rev": 4,
919 "rev": 4,
906 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
920 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
907 "branch": "foo",
921 "branch": "foo",
908 "phase": "draft",
922 "phase": "draft",
909 "user": "person",
923 "user": "person",
910 "date": [1400000, 0],
924 "date": [1400000, 0],
911 "desc": "new branch",
925 "desc": "new branch",
912 "bookmarks": [],
926 "bookmarks": [],
913 "tags": [],
927 "tags": [],
914 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
928 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
915 },
929 },
916 {
930 {
917 "rev": 3,
931 "rev": 3,
918 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
932 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
919 "branch": "default",
933 "branch": "default",
920 "phase": "draft",
934 "phase": "draft",
921 "user": "person",
935 "user": "person",
922 "date": [1300000, 0],
936 "date": [1300000, 0],
923 "desc": "no user, no domain",
937 "desc": "no user, no domain",
924 "bookmarks": [],
938 "bookmarks": [],
925 "tags": [],
939 "tags": [],
926 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
940 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
927 },
941 },
928 {
942 {
929 "rev": 2,
943 "rev": 2,
930 "node": "97054abb4ab824450e9164180baf491ae0078465",
944 "node": "97054abb4ab824450e9164180baf491ae0078465",
931 "branch": "default",
945 "branch": "default",
932 "phase": "draft",
946 "phase": "draft",
933 "user": "other@place",
947 "user": "other@place",
934 "date": [1200000, 0],
948 "date": [1200000, 0],
935 "desc": "no person",
949 "desc": "no person",
936 "bookmarks": [],
950 "bookmarks": [],
937 "tags": [],
951 "tags": [],
938 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
952 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
939 },
953 },
940 {
954 {
941 "rev": 1,
955 "rev": 1,
942 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
956 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
943 "branch": "default",
957 "branch": "default",
944 "phase": "draft",
958 "phase": "draft",
945 "user": "A. N. Other <other@place>",
959 "user": "A. N. Other <other@place>",
946 "date": [1100000, 0],
960 "date": [1100000, 0],
947 "desc": "other 1\nother 2\n\nother 3",
961 "desc": "other 1\nother 2\n\nother 3",
948 "bookmarks": [],
962 "bookmarks": [],
949 "tags": [],
963 "tags": [],
950 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
964 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
951 },
965 },
952 {
966 {
953 "rev": 0,
967 "rev": 0,
954 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
968 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
955 "branch": "default",
969 "branch": "default",
956 "phase": "draft",
970 "phase": "draft",
957 "user": "User Name <user@hostname>",
971 "user": "User Name <user@hostname>",
958 "date": [1000000, 0],
972 "date": [1000000, 0],
959 "desc": "line 1\nline 2",
973 "desc": "line 1\nline 2",
960 "bookmarks": [],
974 "bookmarks": [],
961 "tags": [],
975 "tags": [],
962 "parents": ["0000000000000000000000000000000000000000"]
976 "parents": ["0000000000000000000000000000000000000000"]
963 }
977 }
964 ]
978 ]
965
979
966 $ hg heads -v -Tjson
980 $ hg heads -v -Tjson
967 [
981 [
968 {
982 {
969 "rev": 8,
983 "rev": 8,
970 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
984 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
971 "branch": "default",
985 "branch": "default",
972 "phase": "draft",
986 "phase": "draft",
973 "user": "test",
987 "user": "test",
974 "date": [1577872860, 0],
988 "date": [1577872860, 0],
975 "desc": "third",
989 "desc": "third",
976 "bookmarks": [],
990 "bookmarks": [],
977 "tags": ["tip"],
991 "tags": ["tip"],
978 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
992 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
979 "files": ["fourth", "second", "third"]
993 "files": ["fourth", "second", "third"]
980 },
994 },
981 {
995 {
982 "rev": 6,
996 "rev": 6,
983 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
997 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
984 "branch": "default",
998 "branch": "default",
985 "phase": "draft",
999 "phase": "draft",
986 "user": "person",
1000 "user": "person",
987 "date": [1500001, 0],
1001 "date": [1500001, 0],
988 "desc": "merge",
1002 "desc": "merge",
989 "bookmarks": [],
1003 "bookmarks": [],
990 "tags": [],
1004 "tags": [],
991 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1005 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
992 "files": []
1006 "files": []
993 },
1007 },
994 {
1008 {
995 "rev": 4,
1009 "rev": 4,
996 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1010 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
997 "branch": "foo",
1011 "branch": "foo",
998 "phase": "draft",
1012 "phase": "draft",
999 "user": "person",
1013 "user": "person",
1000 "date": [1400000, 0],
1014 "date": [1400000, 0],
1001 "desc": "new branch",
1015 "desc": "new branch",
1002 "bookmarks": [],
1016 "bookmarks": [],
1003 "tags": [],
1017 "tags": [],
1004 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1018 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1005 "files": []
1019 "files": []
1006 }
1020 }
1007 ]
1021 ]
1008
1022
1009 $ hg log --debug -Tjson
1023 $ hg log --debug -Tjson
1010 [
1024 [
1011 {
1025 {
1012 "rev": 8,
1026 "rev": 8,
1013 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1027 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1014 "branch": "default",
1028 "branch": "default",
1015 "phase": "draft",
1029 "phase": "draft",
1016 "user": "test",
1030 "user": "test",
1017 "date": [1577872860, 0],
1031 "date": [1577872860, 0],
1018 "desc": "third",
1032 "desc": "third",
1019 "bookmarks": [],
1033 "bookmarks": [],
1020 "tags": ["tip"],
1034 "tags": ["tip"],
1021 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1035 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1022 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1036 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1023 "extra": {"branch": "default"},
1037 "extra": {"branch": "default"},
1024 "modified": [],
1038 "modified": [],
1025 "added": ["fourth", "third"],
1039 "added": ["fourth", "third"],
1026 "removed": ["second"]
1040 "removed": ["second"]
1027 },
1041 },
1028 {
1042 {
1029 "rev": 7,
1043 "rev": 7,
1030 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1044 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1031 "branch": "default",
1045 "branch": "default",
1032 "phase": "draft",
1046 "phase": "draft",
1033 "user": "User Name <user@hostname>",
1047 "user": "User Name <user@hostname>",
1034 "date": [1000000, 0],
1048 "date": [1000000, 0],
1035 "desc": "second",
1049 "desc": "second",
1036 "bookmarks": [],
1050 "bookmarks": [],
1037 "tags": [],
1051 "tags": [],
1038 "parents": ["0000000000000000000000000000000000000000"],
1052 "parents": ["0000000000000000000000000000000000000000"],
1039 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1053 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1040 "extra": {"branch": "default"},
1054 "extra": {"branch": "default"},
1041 "modified": [],
1055 "modified": [],
1042 "added": ["second"],
1056 "added": ["second"],
1043 "removed": []
1057 "removed": []
1044 },
1058 },
1045 {
1059 {
1046 "rev": 6,
1060 "rev": 6,
1047 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1061 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1048 "branch": "default",
1062 "branch": "default",
1049 "phase": "draft",
1063 "phase": "draft",
1050 "user": "person",
1064 "user": "person",
1051 "date": [1500001, 0],
1065 "date": [1500001, 0],
1052 "desc": "merge",
1066 "desc": "merge",
1053 "bookmarks": [],
1067 "bookmarks": [],
1054 "tags": [],
1068 "tags": [],
1055 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1069 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1056 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1070 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1057 "extra": {"branch": "default"},
1071 "extra": {"branch": "default"},
1058 "modified": [],
1072 "modified": [],
1059 "added": [],
1073 "added": [],
1060 "removed": []
1074 "removed": []
1061 },
1075 },
1062 {
1076 {
1063 "rev": 5,
1077 "rev": 5,
1064 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1078 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1065 "branch": "default",
1079 "branch": "default",
1066 "phase": "draft",
1080 "phase": "draft",
1067 "user": "person",
1081 "user": "person",
1068 "date": [1500000, 0],
1082 "date": [1500000, 0],
1069 "desc": "new head",
1083 "desc": "new head",
1070 "bookmarks": [],
1084 "bookmarks": [],
1071 "tags": [],
1085 "tags": [],
1072 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1086 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1073 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1087 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1074 "extra": {"branch": "default"},
1088 "extra": {"branch": "default"},
1075 "modified": [],
1089 "modified": [],
1076 "added": ["d"],
1090 "added": ["d"],
1077 "removed": []
1091 "removed": []
1078 },
1092 },
1079 {
1093 {
1080 "rev": 4,
1094 "rev": 4,
1081 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1095 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1082 "branch": "foo",
1096 "branch": "foo",
1083 "phase": "draft",
1097 "phase": "draft",
1084 "user": "person",
1098 "user": "person",
1085 "date": [1400000, 0],
1099 "date": [1400000, 0],
1086 "desc": "new branch",
1100 "desc": "new branch",
1087 "bookmarks": [],
1101 "bookmarks": [],
1088 "tags": [],
1102 "tags": [],
1089 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1103 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1090 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1104 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1091 "extra": {"branch": "foo"},
1105 "extra": {"branch": "foo"},
1092 "modified": [],
1106 "modified": [],
1093 "added": [],
1107 "added": [],
1094 "removed": []
1108 "removed": []
1095 },
1109 },
1096 {
1110 {
1097 "rev": 3,
1111 "rev": 3,
1098 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1112 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1099 "branch": "default",
1113 "branch": "default",
1100 "phase": "draft",
1114 "phase": "draft",
1101 "user": "person",
1115 "user": "person",
1102 "date": [1300000, 0],
1116 "date": [1300000, 0],
1103 "desc": "no user, no domain",
1117 "desc": "no user, no domain",
1104 "bookmarks": [],
1118 "bookmarks": [],
1105 "tags": [],
1119 "tags": [],
1106 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1120 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1107 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1121 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1108 "extra": {"branch": "default"},
1122 "extra": {"branch": "default"},
1109 "modified": ["c"],
1123 "modified": ["c"],
1110 "added": [],
1124 "added": [],
1111 "removed": []
1125 "removed": []
1112 },
1126 },
1113 {
1127 {
1114 "rev": 2,
1128 "rev": 2,
1115 "node": "97054abb4ab824450e9164180baf491ae0078465",
1129 "node": "97054abb4ab824450e9164180baf491ae0078465",
1116 "branch": "default",
1130 "branch": "default",
1117 "phase": "draft",
1131 "phase": "draft",
1118 "user": "other@place",
1132 "user": "other@place",
1119 "date": [1200000, 0],
1133 "date": [1200000, 0],
1120 "desc": "no person",
1134 "desc": "no person",
1121 "bookmarks": [],
1135 "bookmarks": [],
1122 "tags": [],
1136 "tags": [],
1123 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1137 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1124 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1138 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1125 "extra": {"branch": "default"},
1139 "extra": {"branch": "default"},
1126 "modified": [],
1140 "modified": [],
1127 "added": ["c"],
1141 "added": ["c"],
1128 "removed": []
1142 "removed": []
1129 },
1143 },
1130 {
1144 {
1131 "rev": 1,
1145 "rev": 1,
1132 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1146 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1133 "branch": "default",
1147 "branch": "default",
1134 "phase": "draft",
1148 "phase": "draft",
1135 "user": "A. N. Other <other@place>",
1149 "user": "A. N. Other <other@place>",
1136 "date": [1100000, 0],
1150 "date": [1100000, 0],
1137 "desc": "other 1\nother 2\n\nother 3",
1151 "desc": "other 1\nother 2\n\nother 3",
1138 "bookmarks": [],
1152 "bookmarks": [],
1139 "tags": [],
1153 "tags": [],
1140 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1154 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1141 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1155 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1142 "extra": {"branch": "default"},
1156 "extra": {"branch": "default"},
1143 "modified": [],
1157 "modified": [],
1144 "added": ["b"],
1158 "added": ["b"],
1145 "removed": []
1159 "removed": []
1146 },
1160 },
1147 {
1161 {
1148 "rev": 0,
1162 "rev": 0,
1149 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1163 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1150 "branch": "default",
1164 "branch": "default",
1151 "phase": "draft",
1165 "phase": "draft",
1152 "user": "User Name <user@hostname>",
1166 "user": "User Name <user@hostname>",
1153 "date": [1000000, 0],
1167 "date": [1000000, 0],
1154 "desc": "line 1\nline 2",
1168 "desc": "line 1\nline 2",
1155 "bookmarks": [],
1169 "bookmarks": [],
1156 "tags": [],
1170 "tags": [],
1157 "parents": ["0000000000000000000000000000000000000000"],
1171 "parents": ["0000000000000000000000000000000000000000"],
1158 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1172 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1159 "extra": {"branch": "default"},
1173 "extra": {"branch": "default"},
1160 "modified": [],
1174 "modified": [],
1161 "added": ["a"],
1175 "added": ["a"],
1162 "removed": []
1176 "removed": []
1163 }
1177 }
1164 ]
1178 ]
1165
1179
1166 Error if style not readable:
1180 Error if style not readable:
1167
1181
1168 #if unix-permissions no-root
1182 #if unix-permissions no-root
1169 $ touch q
1183 $ touch q
1170 $ chmod 0 q
1184 $ chmod 0 q
1171 $ hg log --style ./q
1185 $ hg log --style ./q
1172 abort: Permission denied: ./q
1186 abort: Permission denied: ./q
1173 [255]
1187 [255]
1174 #endif
1188 #endif
1175
1189
1176 Error if no style:
1190 Error if no style:
1177
1191
1178 $ hg log --style notexist
1192 $ hg log --style notexist
1179 abort: style 'notexist' not found
1193 abort: style 'notexist' not found
1180 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1194 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1181 [255]
1195 [255]
1182
1196
1183 $ hg log -T list
1197 $ hg log -T list
1184 available styles: bisect, changelog, compact, default, phases, show, status, xml
1198 available styles: bisect, changelog, compact, default, phases, show, status, xml
1185 abort: specify a template
1199 abort: specify a template
1186 [255]
1200 [255]
1187
1201
1188 Error if style missing key:
1202 Error if style missing key:
1189
1203
1190 $ echo 'q = q' > t
1204 $ echo 'q = q' > t
1191 $ hg log --style ./t
1205 $ hg log --style ./t
1192 abort: "changeset" not in template map
1206 abort: "changeset" not in template map
1193 [255]
1207 [255]
1194
1208
1195 Error if style missing value:
1209 Error if style missing value:
1196
1210
1197 $ echo 'changeset =' > t
1211 $ echo 'changeset =' > t
1198 $ hg log --style t
1212 $ hg log --style t
1199 hg: parse error at t:1: missing value
1213 hg: parse error at t:1: missing value
1200 [255]
1214 [255]
1201
1215
1202 Error if include fails:
1216 Error if include fails:
1203
1217
1204 $ echo 'changeset = q' >> t
1218 $ echo 'changeset = q' >> t
1205 #if unix-permissions no-root
1219 #if unix-permissions no-root
1206 $ hg log --style ./t
1220 $ hg log --style ./t
1207 abort: template file ./q: Permission denied
1221 abort: template file ./q: Permission denied
1208 [255]
1222 [255]
1209 $ rm -f q
1223 $ rm -f q
1210 #endif
1224 #endif
1211
1225
1212 Include works:
1226 Include works:
1213
1227
1214 $ echo '{rev}' > q
1228 $ echo '{rev}' > q
1215 $ hg log --style ./t
1229 $ hg log --style ./t
1216 8
1230 8
1217 7
1231 7
1218 6
1232 6
1219 5
1233 5
1220 4
1234 4
1221 3
1235 3
1222 2
1236 2
1223 1
1237 1
1224 0
1238 0
1225
1239
1226 Check that recursive reference does not fall into RuntimeError (issue4758):
1240 Check that recursive reference does not fall into RuntimeError (issue4758):
1227
1241
1228 common mistake:
1242 common mistake:
1229
1243
1230 $ cat << EOF > issue4758
1244 $ cat << EOF > issue4758
1231 > changeset = '{changeset}\n'
1245 > changeset = '{changeset}\n'
1232 > EOF
1246 > EOF
1233 $ hg log --style ./issue4758
1247 $ hg log --style ./issue4758
1234 abort: recursive reference 'changeset' in template
1248 abort: recursive reference 'changeset' in template
1235 [255]
1249 [255]
1236
1250
1237 circular reference:
1251 circular reference:
1238
1252
1239 $ cat << EOF > issue4758
1253 $ cat << EOF > issue4758
1240 > changeset = '{foo}'
1254 > changeset = '{foo}'
1241 > foo = '{changeset}'
1255 > foo = '{changeset}'
1242 > EOF
1256 > EOF
1243 $ hg log --style ./issue4758
1257 $ hg log --style ./issue4758
1244 abort: recursive reference 'foo' in template
1258 abort: recursive reference 'foo' in template
1245 [255]
1259 [255]
1246
1260
1247 buildmap() -> gettemplate(), where no thunk was made:
1261 buildmap() -> gettemplate(), where no thunk was made:
1248
1262
1249 $ cat << EOF > issue4758
1263 $ cat << EOF > issue4758
1250 > changeset = '{files % changeset}\n'
1264 > changeset = '{files % changeset}\n'
1251 > EOF
1265 > EOF
1252 $ hg log --style ./issue4758
1266 $ hg log --style ./issue4758
1253 abort: recursive reference 'changeset' in template
1267 abort: recursive reference 'changeset' in template
1254 [255]
1268 [255]
1255
1269
1256 not a recursion if a keyword of the same name exists:
1270 not a recursion if a keyword of the same name exists:
1257
1271
1258 $ cat << EOF > issue4758
1272 $ cat << EOF > issue4758
1259 > changeset = '{tags % rev}'
1273 > changeset = '{tags % rev}'
1260 > rev = '{rev} {tag}\n'
1274 > rev = '{rev} {tag}\n'
1261 > EOF
1275 > EOF
1262 $ hg log --style ./issue4758 -r tip
1276 $ hg log --style ./issue4758 -r tip
1263 8 tip
1277 8 tip
1264
1278
1265 Check that {phase} works correctly on parents:
1279 Check that {phase} works correctly on parents:
1266
1280
1267 $ cat << EOF > parentphase
1281 $ cat << EOF > parentphase
1268 > changeset_debug = '{rev} ({phase}):{parents}\n'
1282 > changeset_debug = '{rev} ({phase}):{parents}\n'
1269 > parent = ' {rev} ({phase})'
1283 > parent = ' {rev} ({phase})'
1270 > EOF
1284 > EOF
1271 $ hg phase -r 5 --public
1285 $ hg phase -r 5 --public
1272 $ hg phase -r 7 --secret --force
1286 $ hg phase -r 7 --secret --force
1273 $ hg log --debug -G --style ./parentphase
1287 $ hg log --debug -G --style ./parentphase
1274 @ 8 (secret): 7 (secret) -1 (public)
1288 @ 8 (secret): 7 (secret) -1 (public)
1275 |
1289 |
1276 o 7 (secret): -1 (public) -1 (public)
1290 o 7 (secret): -1 (public) -1 (public)
1277
1291
1278 o 6 (draft): 5 (public) 4 (draft)
1292 o 6 (draft): 5 (public) 4 (draft)
1279 |\
1293 |\
1280 | o 5 (public): 3 (public) -1 (public)
1294 | o 5 (public): 3 (public) -1 (public)
1281 | |
1295 | |
1282 o | 4 (draft): 3 (public) -1 (public)
1296 o | 4 (draft): 3 (public) -1 (public)
1283 |/
1297 |/
1284 o 3 (public): 2 (public) -1 (public)
1298 o 3 (public): 2 (public) -1 (public)
1285 |
1299 |
1286 o 2 (public): 1 (public) -1 (public)
1300 o 2 (public): 1 (public) -1 (public)
1287 |
1301 |
1288 o 1 (public): 0 (public) -1 (public)
1302 o 1 (public): 0 (public) -1 (public)
1289 |
1303 |
1290 o 0 (public): -1 (public) -1 (public)
1304 o 0 (public): -1 (public) -1 (public)
1291
1305
1292
1306
1293 Missing non-standard names give no error (backward compatibility):
1307 Missing non-standard names give no error (backward compatibility):
1294
1308
1295 $ echo "changeset = '{c}'" > t
1309 $ echo "changeset = '{c}'" > t
1296 $ hg log --style ./t
1310 $ hg log --style ./t
1297
1311
1298 Defining non-standard name works:
1312 Defining non-standard name works:
1299
1313
1300 $ cat <<EOF > t
1314 $ cat <<EOF > t
1301 > changeset = '{c}'
1315 > changeset = '{c}'
1302 > c = q
1316 > c = q
1303 > EOF
1317 > EOF
1304 $ hg log --style ./t
1318 $ hg log --style ./t
1305 8
1319 8
1306 7
1320 7
1307 6
1321 6
1308 5
1322 5
1309 4
1323 4
1310 3
1324 3
1311 2
1325 2
1312 1
1326 1
1313 0
1327 0
1314
1328
1315 ui.style works:
1329 ui.style works:
1316
1330
1317 $ echo '[ui]' > .hg/hgrc
1331 $ echo '[ui]' > .hg/hgrc
1318 $ echo 'style = t' >> .hg/hgrc
1332 $ echo 'style = t' >> .hg/hgrc
1319 $ hg log
1333 $ hg log
1320 8
1334 8
1321 7
1335 7
1322 6
1336 6
1323 5
1337 5
1324 4
1338 4
1325 3
1339 3
1326 2
1340 2
1327 1
1341 1
1328 0
1342 0
1329
1343
1330
1344
1331 Issue338:
1345 Issue338:
1332
1346
1333 $ hg log --style=changelog > changelog
1347 $ hg log --style=changelog > changelog
1334
1348
1335 $ cat changelog
1349 $ cat changelog
1336 2020-01-01 test <test>
1350 2020-01-01 test <test>
1337
1351
1338 * fourth, second, third:
1352 * fourth, second, third:
1339 third
1353 third
1340 [95c24699272e] [tip]
1354 [95c24699272e] [tip]
1341
1355
1342 1970-01-12 User Name <user@hostname>
1356 1970-01-12 User Name <user@hostname>
1343
1357
1344 * second:
1358 * second:
1345 second
1359 second
1346 [29114dbae42b]
1360 [29114dbae42b]
1347
1361
1348 1970-01-18 person <person>
1362 1970-01-18 person <person>
1349
1363
1350 * merge
1364 * merge
1351 [d41e714fe50d]
1365 [d41e714fe50d]
1352
1366
1353 * d:
1367 * d:
1354 new head
1368 new head
1355 [13207e5a10d9]
1369 [13207e5a10d9]
1356
1370
1357 1970-01-17 person <person>
1371 1970-01-17 person <person>
1358
1372
1359 * new branch
1373 * new branch
1360 [bbe44766e73d] <foo>
1374 [bbe44766e73d] <foo>
1361
1375
1362 1970-01-16 person <person>
1376 1970-01-16 person <person>
1363
1377
1364 * c:
1378 * c:
1365 no user, no domain
1379 no user, no domain
1366 [10e46f2dcbf4]
1380 [10e46f2dcbf4]
1367
1381
1368 1970-01-14 other <other@place>
1382 1970-01-14 other <other@place>
1369
1383
1370 * c:
1384 * c:
1371 no person
1385 no person
1372 [97054abb4ab8]
1386 [97054abb4ab8]
1373
1387
1374 1970-01-13 A. N. Other <other@place>
1388 1970-01-13 A. N. Other <other@place>
1375
1389
1376 * b:
1390 * b:
1377 other 1 other 2
1391 other 1 other 2
1378
1392
1379 other 3
1393 other 3
1380 [b608e9d1a3f0]
1394 [b608e9d1a3f0]
1381
1395
1382 1970-01-12 User Name <user@hostname>
1396 1970-01-12 User Name <user@hostname>
1383
1397
1384 * a:
1398 * a:
1385 line 1 line 2
1399 line 1 line 2
1386 [1e4e1b8f71e0]
1400 [1e4e1b8f71e0]
1387
1401
1388
1402
1389 Issue2130: xml output for 'hg heads' is malformed
1403 Issue2130: xml output for 'hg heads' is malformed
1390
1404
1391 $ hg heads --style changelog
1405 $ hg heads --style changelog
1392 2020-01-01 test <test>
1406 2020-01-01 test <test>
1393
1407
1394 * fourth, second, third:
1408 * fourth, second, third:
1395 third
1409 third
1396 [95c24699272e] [tip]
1410 [95c24699272e] [tip]
1397
1411
1398 1970-01-18 person <person>
1412 1970-01-18 person <person>
1399
1413
1400 * merge
1414 * merge
1401 [d41e714fe50d]
1415 [d41e714fe50d]
1402
1416
1403 1970-01-17 person <person>
1417 1970-01-17 person <person>
1404
1418
1405 * new branch
1419 * new branch
1406 [bbe44766e73d] <foo>
1420 [bbe44766e73d] <foo>
1407
1421
1408
1422
1409 Keys work:
1423 Keys work:
1410
1424
1411 $ for key in author branch branches date desc file_adds file_dels file_mods \
1425 $ for key in author branch branches date desc file_adds file_dels file_mods \
1412 > file_copies file_copies_switch files \
1426 > file_copies file_copies_switch files \
1413 > manifest node parents rev tags diffstat extras \
1427 > manifest node parents rev tags diffstat extras \
1414 > p1rev p2rev p1node p2node; do
1428 > p1rev p2rev p1node p2node; do
1415 > for mode in '' --verbose --debug; do
1429 > for mode in '' --verbose --debug; do
1416 > hg log $mode --template "$key$mode: {$key}\n"
1430 > hg log $mode --template "$key$mode: {$key}\n"
1417 > done
1431 > done
1418 > done
1432 > done
1419 author: test
1433 author: test
1420 author: User Name <user@hostname>
1434 author: User Name <user@hostname>
1421 author: person
1435 author: person
1422 author: person
1436 author: person
1423 author: person
1437 author: person
1424 author: person
1438 author: person
1425 author: other@place
1439 author: other@place
1426 author: A. N. Other <other@place>
1440 author: A. N. Other <other@place>
1427 author: User Name <user@hostname>
1441 author: User Name <user@hostname>
1428 author--verbose: test
1442 author--verbose: test
1429 author--verbose: User Name <user@hostname>
1443 author--verbose: User Name <user@hostname>
1430 author--verbose: person
1444 author--verbose: person
1431 author--verbose: person
1445 author--verbose: person
1432 author--verbose: person
1446 author--verbose: person
1433 author--verbose: person
1447 author--verbose: person
1434 author--verbose: other@place
1448 author--verbose: other@place
1435 author--verbose: A. N. Other <other@place>
1449 author--verbose: A. N. Other <other@place>
1436 author--verbose: User Name <user@hostname>
1450 author--verbose: User Name <user@hostname>
1437 author--debug: test
1451 author--debug: test
1438 author--debug: User Name <user@hostname>
1452 author--debug: User Name <user@hostname>
1439 author--debug: person
1453 author--debug: person
1440 author--debug: person
1454 author--debug: person
1441 author--debug: person
1455 author--debug: person
1442 author--debug: person
1456 author--debug: person
1443 author--debug: other@place
1457 author--debug: other@place
1444 author--debug: A. N. Other <other@place>
1458 author--debug: A. N. Other <other@place>
1445 author--debug: User Name <user@hostname>
1459 author--debug: User Name <user@hostname>
1446 branch: default
1460 branch: default
1447 branch: default
1461 branch: default
1448 branch: default
1462 branch: default
1449 branch: default
1463 branch: default
1450 branch: foo
1464 branch: foo
1451 branch: default
1465 branch: default
1452 branch: default
1466 branch: default
1453 branch: default
1467 branch: default
1454 branch: default
1468 branch: default
1455 branch--verbose: default
1469 branch--verbose: default
1456 branch--verbose: default
1470 branch--verbose: default
1457 branch--verbose: default
1471 branch--verbose: default
1458 branch--verbose: default
1472 branch--verbose: default
1459 branch--verbose: foo
1473 branch--verbose: foo
1460 branch--verbose: default
1474 branch--verbose: default
1461 branch--verbose: default
1475 branch--verbose: default
1462 branch--verbose: default
1476 branch--verbose: default
1463 branch--verbose: default
1477 branch--verbose: default
1464 branch--debug: default
1478 branch--debug: default
1465 branch--debug: default
1479 branch--debug: default
1466 branch--debug: default
1480 branch--debug: default
1467 branch--debug: default
1481 branch--debug: default
1468 branch--debug: foo
1482 branch--debug: foo
1469 branch--debug: default
1483 branch--debug: default
1470 branch--debug: default
1484 branch--debug: default
1471 branch--debug: default
1485 branch--debug: default
1472 branch--debug: default
1486 branch--debug: default
1473 branches:
1487 branches:
1474 branches:
1488 branches:
1475 branches:
1489 branches:
1476 branches:
1490 branches:
1477 branches: foo
1491 branches: foo
1478 branches:
1492 branches:
1479 branches:
1493 branches:
1480 branches:
1494 branches:
1481 branches:
1495 branches:
1482 branches--verbose:
1496 branches--verbose:
1483 branches--verbose:
1497 branches--verbose:
1484 branches--verbose:
1498 branches--verbose:
1485 branches--verbose:
1499 branches--verbose:
1486 branches--verbose: foo
1500 branches--verbose: foo
1487 branches--verbose:
1501 branches--verbose:
1488 branches--verbose:
1502 branches--verbose:
1489 branches--verbose:
1503 branches--verbose:
1490 branches--verbose:
1504 branches--verbose:
1491 branches--debug:
1505 branches--debug:
1492 branches--debug:
1506 branches--debug:
1493 branches--debug:
1507 branches--debug:
1494 branches--debug:
1508 branches--debug:
1495 branches--debug: foo
1509 branches--debug: foo
1496 branches--debug:
1510 branches--debug:
1497 branches--debug:
1511 branches--debug:
1498 branches--debug:
1512 branches--debug:
1499 branches--debug:
1513 branches--debug:
1500 date: 1577872860.00
1514 date: 1577872860.00
1501 date: 1000000.00
1515 date: 1000000.00
1502 date: 1500001.00
1516 date: 1500001.00
1503 date: 1500000.00
1517 date: 1500000.00
1504 date: 1400000.00
1518 date: 1400000.00
1505 date: 1300000.00
1519 date: 1300000.00
1506 date: 1200000.00
1520 date: 1200000.00
1507 date: 1100000.00
1521 date: 1100000.00
1508 date: 1000000.00
1522 date: 1000000.00
1509 date--verbose: 1577872860.00
1523 date--verbose: 1577872860.00
1510 date--verbose: 1000000.00
1524 date--verbose: 1000000.00
1511 date--verbose: 1500001.00
1525 date--verbose: 1500001.00
1512 date--verbose: 1500000.00
1526 date--verbose: 1500000.00
1513 date--verbose: 1400000.00
1527 date--verbose: 1400000.00
1514 date--verbose: 1300000.00
1528 date--verbose: 1300000.00
1515 date--verbose: 1200000.00
1529 date--verbose: 1200000.00
1516 date--verbose: 1100000.00
1530 date--verbose: 1100000.00
1517 date--verbose: 1000000.00
1531 date--verbose: 1000000.00
1518 date--debug: 1577872860.00
1532 date--debug: 1577872860.00
1519 date--debug: 1000000.00
1533 date--debug: 1000000.00
1520 date--debug: 1500001.00
1534 date--debug: 1500001.00
1521 date--debug: 1500000.00
1535 date--debug: 1500000.00
1522 date--debug: 1400000.00
1536 date--debug: 1400000.00
1523 date--debug: 1300000.00
1537 date--debug: 1300000.00
1524 date--debug: 1200000.00
1538 date--debug: 1200000.00
1525 date--debug: 1100000.00
1539 date--debug: 1100000.00
1526 date--debug: 1000000.00
1540 date--debug: 1000000.00
1527 desc: third
1541 desc: third
1528 desc: second
1542 desc: second
1529 desc: merge
1543 desc: merge
1530 desc: new head
1544 desc: new head
1531 desc: new branch
1545 desc: new branch
1532 desc: no user, no domain
1546 desc: no user, no domain
1533 desc: no person
1547 desc: no person
1534 desc: other 1
1548 desc: other 1
1535 other 2
1549 other 2
1536
1550
1537 other 3
1551 other 3
1538 desc: line 1
1552 desc: line 1
1539 line 2
1553 line 2
1540 desc--verbose: third
1554 desc--verbose: third
1541 desc--verbose: second
1555 desc--verbose: second
1542 desc--verbose: merge
1556 desc--verbose: merge
1543 desc--verbose: new head
1557 desc--verbose: new head
1544 desc--verbose: new branch
1558 desc--verbose: new branch
1545 desc--verbose: no user, no domain
1559 desc--verbose: no user, no domain
1546 desc--verbose: no person
1560 desc--verbose: no person
1547 desc--verbose: other 1
1561 desc--verbose: other 1
1548 other 2
1562 other 2
1549
1563
1550 other 3
1564 other 3
1551 desc--verbose: line 1
1565 desc--verbose: line 1
1552 line 2
1566 line 2
1553 desc--debug: third
1567 desc--debug: third
1554 desc--debug: second
1568 desc--debug: second
1555 desc--debug: merge
1569 desc--debug: merge
1556 desc--debug: new head
1570 desc--debug: new head
1557 desc--debug: new branch
1571 desc--debug: new branch
1558 desc--debug: no user, no domain
1572 desc--debug: no user, no domain
1559 desc--debug: no person
1573 desc--debug: no person
1560 desc--debug: other 1
1574 desc--debug: other 1
1561 other 2
1575 other 2
1562
1576
1563 other 3
1577 other 3
1564 desc--debug: line 1
1578 desc--debug: line 1
1565 line 2
1579 line 2
1566 file_adds: fourth third
1580 file_adds: fourth third
1567 file_adds: second
1581 file_adds: second
1568 file_adds:
1582 file_adds:
1569 file_adds: d
1583 file_adds: d
1570 file_adds:
1584 file_adds:
1571 file_adds:
1585 file_adds:
1572 file_adds: c
1586 file_adds: c
1573 file_adds: b
1587 file_adds: b
1574 file_adds: a
1588 file_adds: a
1575 file_adds--verbose: fourth third
1589 file_adds--verbose: fourth third
1576 file_adds--verbose: second
1590 file_adds--verbose: second
1577 file_adds--verbose:
1591 file_adds--verbose:
1578 file_adds--verbose: d
1592 file_adds--verbose: d
1579 file_adds--verbose:
1593 file_adds--verbose:
1580 file_adds--verbose:
1594 file_adds--verbose:
1581 file_adds--verbose: c
1595 file_adds--verbose: c
1582 file_adds--verbose: b
1596 file_adds--verbose: b
1583 file_adds--verbose: a
1597 file_adds--verbose: a
1584 file_adds--debug: fourth third
1598 file_adds--debug: fourth third
1585 file_adds--debug: second
1599 file_adds--debug: second
1586 file_adds--debug:
1600 file_adds--debug:
1587 file_adds--debug: d
1601 file_adds--debug: d
1588 file_adds--debug:
1602 file_adds--debug:
1589 file_adds--debug:
1603 file_adds--debug:
1590 file_adds--debug: c
1604 file_adds--debug: c
1591 file_adds--debug: b
1605 file_adds--debug: b
1592 file_adds--debug: a
1606 file_adds--debug: a
1593 file_dels: second
1607 file_dels: second
1594 file_dels:
1608 file_dels:
1595 file_dels:
1609 file_dels:
1596 file_dels:
1610 file_dels:
1597 file_dels:
1611 file_dels:
1598 file_dels:
1612 file_dels:
1599 file_dels:
1613 file_dels:
1600 file_dels:
1614 file_dels:
1601 file_dels:
1615 file_dels:
1602 file_dels--verbose: second
1616 file_dels--verbose: second
1603 file_dels--verbose:
1617 file_dels--verbose:
1604 file_dels--verbose:
1618 file_dels--verbose:
1605 file_dels--verbose:
1619 file_dels--verbose:
1606 file_dels--verbose:
1620 file_dels--verbose:
1607 file_dels--verbose:
1621 file_dels--verbose:
1608 file_dels--verbose:
1622 file_dels--verbose:
1609 file_dels--verbose:
1623 file_dels--verbose:
1610 file_dels--verbose:
1624 file_dels--verbose:
1611 file_dels--debug: second
1625 file_dels--debug: second
1612 file_dels--debug:
1626 file_dels--debug:
1613 file_dels--debug:
1627 file_dels--debug:
1614 file_dels--debug:
1628 file_dels--debug:
1615 file_dels--debug:
1629 file_dels--debug:
1616 file_dels--debug:
1630 file_dels--debug:
1617 file_dels--debug:
1631 file_dels--debug:
1618 file_dels--debug:
1632 file_dels--debug:
1619 file_dels--debug:
1633 file_dels--debug:
1620 file_mods:
1634 file_mods:
1621 file_mods:
1635 file_mods:
1622 file_mods:
1636 file_mods:
1623 file_mods:
1637 file_mods:
1624 file_mods:
1638 file_mods:
1625 file_mods: c
1639 file_mods: c
1626 file_mods:
1640 file_mods:
1627 file_mods:
1641 file_mods:
1628 file_mods:
1642 file_mods:
1629 file_mods--verbose:
1643 file_mods--verbose:
1630 file_mods--verbose:
1644 file_mods--verbose:
1631 file_mods--verbose:
1645 file_mods--verbose:
1632 file_mods--verbose:
1646 file_mods--verbose:
1633 file_mods--verbose:
1647 file_mods--verbose:
1634 file_mods--verbose: c
1648 file_mods--verbose: c
1635 file_mods--verbose:
1649 file_mods--verbose:
1636 file_mods--verbose:
1650 file_mods--verbose:
1637 file_mods--verbose:
1651 file_mods--verbose:
1638 file_mods--debug:
1652 file_mods--debug:
1639 file_mods--debug:
1653 file_mods--debug:
1640 file_mods--debug:
1654 file_mods--debug:
1641 file_mods--debug:
1655 file_mods--debug:
1642 file_mods--debug:
1656 file_mods--debug:
1643 file_mods--debug: c
1657 file_mods--debug: c
1644 file_mods--debug:
1658 file_mods--debug:
1645 file_mods--debug:
1659 file_mods--debug:
1646 file_mods--debug:
1660 file_mods--debug:
1647 file_copies: fourth (second)
1661 file_copies: fourth (second)
1648 file_copies:
1662 file_copies:
1649 file_copies:
1663 file_copies:
1650 file_copies:
1664 file_copies:
1651 file_copies:
1665 file_copies:
1652 file_copies:
1666 file_copies:
1653 file_copies:
1667 file_copies:
1654 file_copies:
1668 file_copies:
1655 file_copies:
1669 file_copies:
1656 file_copies--verbose: fourth (second)
1670 file_copies--verbose: fourth (second)
1657 file_copies--verbose:
1671 file_copies--verbose:
1658 file_copies--verbose:
1672 file_copies--verbose:
1659 file_copies--verbose:
1673 file_copies--verbose:
1660 file_copies--verbose:
1674 file_copies--verbose:
1661 file_copies--verbose:
1675 file_copies--verbose:
1662 file_copies--verbose:
1676 file_copies--verbose:
1663 file_copies--verbose:
1677 file_copies--verbose:
1664 file_copies--verbose:
1678 file_copies--verbose:
1665 file_copies--debug: fourth (second)
1679 file_copies--debug: fourth (second)
1666 file_copies--debug:
1680 file_copies--debug:
1667 file_copies--debug:
1681 file_copies--debug:
1668 file_copies--debug:
1682 file_copies--debug:
1669 file_copies--debug:
1683 file_copies--debug:
1670 file_copies--debug:
1684 file_copies--debug:
1671 file_copies--debug:
1685 file_copies--debug:
1672 file_copies--debug:
1686 file_copies--debug:
1673 file_copies--debug:
1687 file_copies--debug:
1674 file_copies_switch:
1688 file_copies_switch:
1675 file_copies_switch:
1689 file_copies_switch:
1676 file_copies_switch:
1690 file_copies_switch:
1677 file_copies_switch:
1691 file_copies_switch:
1678 file_copies_switch:
1692 file_copies_switch:
1679 file_copies_switch:
1693 file_copies_switch:
1680 file_copies_switch:
1694 file_copies_switch:
1681 file_copies_switch:
1695 file_copies_switch:
1682 file_copies_switch:
1696 file_copies_switch:
1683 file_copies_switch--verbose:
1697 file_copies_switch--verbose:
1684 file_copies_switch--verbose:
1698 file_copies_switch--verbose:
1685 file_copies_switch--verbose:
1699 file_copies_switch--verbose:
1686 file_copies_switch--verbose:
1700 file_copies_switch--verbose:
1687 file_copies_switch--verbose:
1701 file_copies_switch--verbose:
1688 file_copies_switch--verbose:
1702 file_copies_switch--verbose:
1689 file_copies_switch--verbose:
1703 file_copies_switch--verbose:
1690 file_copies_switch--verbose:
1704 file_copies_switch--verbose:
1691 file_copies_switch--verbose:
1705 file_copies_switch--verbose:
1692 file_copies_switch--debug:
1706 file_copies_switch--debug:
1693 file_copies_switch--debug:
1707 file_copies_switch--debug:
1694 file_copies_switch--debug:
1708 file_copies_switch--debug:
1695 file_copies_switch--debug:
1709 file_copies_switch--debug:
1696 file_copies_switch--debug:
1710 file_copies_switch--debug:
1697 file_copies_switch--debug:
1711 file_copies_switch--debug:
1698 file_copies_switch--debug:
1712 file_copies_switch--debug:
1699 file_copies_switch--debug:
1713 file_copies_switch--debug:
1700 file_copies_switch--debug:
1714 file_copies_switch--debug:
1701 files: fourth second third
1715 files: fourth second third
1702 files: second
1716 files: second
1703 files:
1717 files:
1704 files: d
1718 files: d
1705 files:
1719 files:
1706 files: c
1720 files: c
1707 files: c
1721 files: c
1708 files: b
1722 files: b
1709 files: a
1723 files: a
1710 files--verbose: fourth second third
1724 files--verbose: fourth second third
1711 files--verbose: second
1725 files--verbose: second
1712 files--verbose:
1726 files--verbose:
1713 files--verbose: d
1727 files--verbose: d
1714 files--verbose:
1728 files--verbose:
1715 files--verbose: c
1729 files--verbose: c
1716 files--verbose: c
1730 files--verbose: c
1717 files--verbose: b
1731 files--verbose: b
1718 files--verbose: a
1732 files--verbose: a
1719 files--debug: fourth second third
1733 files--debug: fourth second third
1720 files--debug: second
1734 files--debug: second
1721 files--debug:
1735 files--debug:
1722 files--debug: d
1736 files--debug: d
1723 files--debug:
1737 files--debug:
1724 files--debug: c
1738 files--debug: c
1725 files--debug: c
1739 files--debug: c
1726 files--debug: b
1740 files--debug: b
1727 files--debug: a
1741 files--debug: a
1728 manifest: 6:94961b75a2da
1742 manifest: 6:94961b75a2da
1729 manifest: 5:f2dbc354b94e
1743 manifest: 5:f2dbc354b94e
1730 manifest: 4:4dc3def4f9b4
1744 manifest: 4:4dc3def4f9b4
1731 manifest: 4:4dc3def4f9b4
1745 manifest: 4:4dc3def4f9b4
1732 manifest: 3:cb5a1327723b
1746 manifest: 3:cb5a1327723b
1733 manifest: 3:cb5a1327723b
1747 manifest: 3:cb5a1327723b
1734 manifest: 2:6e0e82995c35
1748 manifest: 2:6e0e82995c35
1735 manifest: 1:4e8d705b1e53
1749 manifest: 1:4e8d705b1e53
1736 manifest: 0:a0c8bcbbb45c
1750 manifest: 0:a0c8bcbbb45c
1737 manifest--verbose: 6:94961b75a2da
1751 manifest--verbose: 6:94961b75a2da
1738 manifest--verbose: 5:f2dbc354b94e
1752 manifest--verbose: 5:f2dbc354b94e
1739 manifest--verbose: 4:4dc3def4f9b4
1753 manifest--verbose: 4:4dc3def4f9b4
1740 manifest--verbose: 4:4dc3def4f9b4
1754 manifest--verbose: 4:4dc3def4f9b4
1741 manifest--verbose: 3:cb5a1327723b
1755 manifest--verbose: 3:cb5a1327723b
1742 manifest--verbose: 3:cb5a1327723b
1756 manifest--verbose: 3:cb5a1327723b
1743 manifest--verbose: 2:6e0e82995c35
1757 manifest--verbose: 2:6e0e82995c35
1744 manifest--verbose: 1:4e8d705b1e53
1758 manifest--verbose: 1:4e8d705b1e53
1745 manifest--verbose: 0:a0c8bcbbb45c
1759 manifest--verbose: 0:a0c8bcbbb45c
1746 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1760 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1747 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1761 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1748 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1762 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1749 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1763 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1750 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1764 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1751 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1765 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1752 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1766 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1753 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1767 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1754 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1768 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1755 node: 95c24699272ef57d062b8bccc32c878bf841784a
1769 node: 95c24699272ef57d062b8bccc32c878bf841784a
1756 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1770 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1757 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1771 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1758 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1772 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1759 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1773 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1760 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1774 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1761 node: 97054abb4ab824450e9164180baf491ae0078465
1775 node: 97054abb4ab824450e9164180baf491ae0078465
1762 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1776 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1763 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1777 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1764 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1778 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1765 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1779 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1766 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1780 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1767 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1781 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1768 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1782 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1769 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1783 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1770 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1784 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1771 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1785 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1772 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1786 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1773 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1787 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1774 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1788 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1775 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1789 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1776 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1790 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1777 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1791 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1778 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1792 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1779 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1793 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1780 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1794 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1781 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1795 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1782 parents:
1796 parents:
1783 parents: -1:000000000000
1797 parents: -1:000000000000
1784 parents: 5:13207e5a10d9 4:bbe44766e73d
1798 parents: 5:13207e5a10d9 4:bbe44766e73d
1785 parents: 3:10e46f2dcbf4
1799 parents: 3:10e46f2dcbf4
1786 parents:
1800 parents:
1787 parents:
1801 parents:
1788 parents:
1802 parents:
1789 parents:
1803 parents:
1790 parents:
1804 parents:
1791 parents--verbose:
1805 parents--verbose:
1792 parents--verbose: -1:000000000000
1806 parents--verbose: -1:000000000000
1793 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1807 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1794 parents--verbose: 3:10e46f2dcbf4
1808 parents--verbose: 3:10e46f2dcbf4
1795 parents--verbose:
1809 parents--verbose:
1796 parents--verbose:
1810 parents--verbose:
1797 parents--verbose:
1811 parents--verbose:
1798 parents--verbose:
1812 parents--verbose:
1799 parents--verbose:
1813 parents--verbose:
1800 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1814 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1801 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1815 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1802 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1816 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1803 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1817 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1804 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1818 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1805 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1819 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1806 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1820 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1807 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1821 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1808 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1822 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1809 rev: 8
1823 rev: 8
1810 rev: 7
1824 rev: 7
1811 rev: 6
1825 rev: 6
1812 rev: 5
1826 rev: 5
1813 rev: 4
1827 rev: 4
1814 rev: 3
1828 rev: 3
1815 rev: 2
1829 rev: 2
1816 rev: 1
1830 rev: 1
1817 rev: 0
1831 rev: 0
1818 rev--verbose: 8
1832 rev--verbose: 8
1819 rev--verbose: 7
1833 rev--verbose: 7
1820 rev--verbose: 6
1834 rev--verbose: 6
1821 rev--verbose: 5
1835 rev--verbose: 5
1822 rev--verbose: 4
1836 rev--verbose: 4
1823 rev--verbose: 3
1837 rev--verbose: 3
1824 rev--verbose: 2
1838 rev--verbose: 2
1825 rev--verbose: 1
1839 rev--verbose: 1
1826 rev--verbose: 0
1840 rev--verbose: 0
1827 rev--debug: 8
1841 rev--debug: 8
1828 rev--debug: 7
1842 rev--debug: 7
1829 rev--debug: 6
1843 rev--debug: 6
1830 rev--debug: 5
1844 rev--debug: 5
1831 rev--debug: 4
1845 rev--debug: 4
1832 rev--debug: 3
1846 rev--debug: 3
1833 rev--debug: 2
1847 rev--debug: 2
1834 rev--debug: 1
1848 rev--debug: 1
1835 rev--debug: 0
1849 rev--debug: 0
1836 tags: tip
1850 tags: tip
1837 tags:
1851 tags:
1838 tags:
1852 tags:
1839 tags:
1853 tags:
1840 tags:
1854 tags:
1841 tags:
1855 tags:
1842 tags:
1856 tags:
1843 tags:
1857 tags:
1844 tags:
1858 tags:
1845 tags--verbose: tip
1859 tags--verbose: tip
1846 tags--verbose:
1860 tags--verbose:
1847 tags--verbose:
1861 tags--verbose:
1848 tags--verbose:
1862 tags--verbose:
1849 tags--verbose:
1863 tags--verbose:
1850 tags--verbose:
1864 tags--verbose:
1851 tags--verbose:
1865 tags--verbose:
1852 tags--verbose:
1866 tags--verbose:
1853 tags--verbose:
1867 tags--verbose:
1854 tags--debug: tip
1868 tags--debug: tip
1855 tags--debug:
1869 tags--debug:
1856 tags--debug:
1870 tags--debug:
1857 tags--debug:
1871 tags--debug:
1858 tags--debug:
1872 tags--debug:
1859 tags--debug:
1873 tags--debug:
1860 tags--debug:
1874 tags--debug:
1861 tags--debug:
1875 tags--debug:
1862 tags--debug:
1876 tags--debug:
1863 diffstat: 3: +2/-1
1877 diffstat: 3: +2/-1
1864 diffstat: 1: +1/-0
1878 diffstat: 1: +1/-0
1865 diffstat: 0: +0/-0
1879 diffstat: 0: +0/-0
1866 diffstat: 1: +1/-0
1880 diffstat: 1: +1/-0
1867 diffstat: 0: +0/-0
1881 diffstat: 0: +0/-0
1868 diffstat: 1: +1/-0
1882 diffstat: 1: +1/-0
1869 diffstat: 1: +4/-0
1883 diffstat: 1: +4/-0
1870 diffstat: 1: +2/-0
1884 diffstat: 1: +2/-0
1871 diffstat: 1: +1/-0
1885 diffstat: 1: +1/-0
1872 diffstat--verbose: 3: +2/-1
1886 diffstat--verbose: 3: +2/-1
1873 diffstat--verbose: 1: +1/-0
1887 diffstat--verbose: 1: +1/-0
1874 diffstat--verbose: 0: +0/-0
1888 diffstat--verbose: 0: +0/-0
1875 diffstat--verbose: 1: +1/-0
1889 diffstat--verbose: 1: +1/-0
1876 diffstat--verbose: 0: +0/-0
1890 diffstat--verbose: 0: +0/-0
1877 diffstat--verbose: 1: +1/-0
1891 diffstat--verbose: 1: +1/-0
1878 diffstat--verbose: 1: +4/-0
1892 diffstat--verbose: 1: +4/-0
1879 diffstat--verbose: 1: +2/-0
1893 diffstat--verbose: 1: +2/-0
1880 diffstat--verbose: 1: +1/-0
1894 diffstat--verbose: 1: +1/-0
1881 diffstat--debug: 3: +2/-1
1895 diffstat--debug: 3: +2/-1
1882 diffstat--debug: 1: +1/-0
1896 diffstat--debug: 1: +1/-0
1883 diffstat--debug: 0: +0/-0
1897 diffstat--debug: 0: +0/-0
1884 diffstat--debug: 1: +1/-0
1898 diffstat--debug: 1: +1/-0
1885 diffstat--debug: 0: +0/-0
1899 diffstat--debug: 0: +0/-0
1886 diffstat--debug: 1: +1/-0
1900 diffstat--debug: 1: +1/-0
1887 diffstat--debug: 1: +4/-0
1901 diffstat--debug: 1: +4/-0
1888 diffstat--debug: 1: +2/-0
1902 diffstat--debug: 1: +2/-0
1889 diffstat--debug: 1: +1/-0
1903 diffstat--debug: 1: +1/-0
1890 extras: branch=default
1904 extras: branch=default
1891 extras: branch=default
1905 extras: branch=default
1892 extras: branch=default
1906 extras: branch=default
1893 extras: branch=default
1907 extras: branch=default
1894 extras: branch=foo
1908 extras: branch=foo
1895 extras: branch=default
1909 extras: branch=default
1896 extras: branch=default
1910 extras: branch=default
1897 extras: branch=default
1911 extras: branch=default
1898 extras: branch=default
1912 extras: branch=default
1899 extras--verbose: branch=default
1913 extras--verbose: branch=default
1900 extras--verbose: branch=default
1914 extras--verbose: branch=default
1901 extras--verbose: branch=default
1915 extras--verbose: branch=default
1902 extras--verbose: branch=default
1916 extras--verbose: branch=default
1903 extras--verbose: branch=foo
1917 extras--verbose: branch=foo
1904 extras--verbose: branch=default
1918 extras--verbose: branch=default
1905 extras--verbose: branch=default
1919 extras--verbose: branch=default
1906 extras--verbose: branch=default
1920 extras--verbose: branch=default
1907 extras--verbose: branch=default
1921 extras--verbose: branch=default
1908 extras--debug: branch=default
1922 extras--debug: branch=default
1909 extras--debug: branch=default
1923 extras--debug: branch=default
1910 extras--debug: branch=default
1924 extras--debug: branch=default
1911 extras--debug: branch=default
1925 extras--debug: branch=default
1912 extras--debug: branch=foo
1926 extras--debug: branch=foo
1913 extras--debug: branch=default
1927 extras--debug: branch=default
1914 extras--debug: branch=default
1928 extras--debug: branch=default
1915 extras--debug: branch=default
1929 extras--debug: branch=default
1916 extras--debug: branch=default
1930 extras--debug: branch=default
1917 p1rev: 7
1931 p1rev: 7
1918 p1rev: -1
1932 p1rev: -1
1919 p1rev: 5
1933 p1rev: 5
1920 p1rev: 3
1934 p1rev: 3
1921 p1rev: 3
1935 p1rev: 3
1922 p1rev: 2
1936 p1rev: 2
1923 p1rev: 1
1937 p1rev: 1
1924 p1rev: 0
1938 p1rev: 0
1925 p1rev: -1
1939 p1rev: -1
1926 p1rev--verbose: 7
1940 p1rev--verbose: 7
1927 p1rev--verbose: -1
1941 p1rev--verbose: -1
1928 p1rev--verbose: 5
1942 p1rev--verbose: 5
1929 p1rev--verbose: 3
1943 p1rev--verbose: 3
1930 p1rev--verbose: 3
1944 p1rev--verbose: 3
1931 p1rev--verbose: 2
1945 p1rev--verbose: 2
1932 p1rev--verbose: 1
1946 p1rev--verbose: 1
1933 p1rev--verbose: 0
1947 p1rev--verbose: 0
1934 p1rev--verbose: -1
1948 p1rev--verbose: -1
1935 p1rev--debug: 7
1949 p1rev--debug: 7
1936 p1rev--debug: -1
1950 p1rev--debug: -1
1937 p1rev--debug: 5
1951 p1rev--debug: 5
1938 p1rev--debug: 3
1952 p1rev--debug: 3
1939 p1rev--debug: 3
1953 p1rev--debug: 3
1940 p1rev--debug: 2
1954 p1rev--debug: 2
1941 p1rev--debug: 1
1955 p1rev--debug: 1
1942 p1rev--debug: 0
1956 p1rev--debug: 0
1943 p1rev--debug: -1
1957 p1rev--debug: -1
1944 p2rev: -1
1958 p2rev: -1
1945 p2rev: -1
1959 p2rev: -1
1946 p2rev: 4
1960 p2rev: 4
1947 p2rev: -1
1961 p2rev: -1
1948 p2rev: -1
1962 p2rev: -1
1949 p2rev: -1
1963 p2rev: -1
1950 p2rev: -1
1964 p2rev: -1
1951 p2rev: -1
1965 p2rev: -1
1952 p2rev: -1
1966 p2rev: -1
1953 p2rev--verbose: -1
1967 p2rev--verbose: -1
1954 p2rev--verbose: -1
1968 p2rev--verbose: -1
1955 p2rev--verbose: 4
1969 p2rev--verbose: 4
1956 p2rev--verbose: -1
1970 p2rev--verbose: -1
1957 p2rev--verbose: -1
1971 p2rev--verbose: -1
1958 p2rev--verbose: -1
1972 p2rev--verbose: -1
1959 p2rev--verbose: -1
1973 p2rev--verbose: -1
1960 p2rev--verbose: -1
1974 p2rev--verbose: -1
1961 p2rev--verbose: -1
1975 p2rev--verbose: -1
1962 p2rev--debug: -1
1976 p2rev--debug: -1
1963 p2rev--debug: -1
1977 p2rev--debug: -1
1964 p2rev--debug: 4
1978 p2rev--debug: 4
1965 p2rev--debug: -1
1979 p2rev--debug: -1
1966 p2rev--debug: -1
1980 p2rev--debug: -1
1967 p2rev--debug: -1
1981 p2rev--debug: -1
1968 p2rev--debug: -1
1982 p2rev--debug: -1
1969 p2rev--debug: -1
1983 p2rev--debug: -1
1970 p2rev--debug: -1
1984 p2rev--debug: -1
1971 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1985 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1972 p1node: 0000000000000000000000000000000000000000
1986 p1node: 0000000000000000000000000000000000000000
1973 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1987 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1974 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1988 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1975 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1989 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1976 p1node: 97054abb4ab824450e9164180baf491ae0078465
1990 p1node: 97054abb4ab824450e9164180baf491ae0078465
1977 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1991 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1978 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1992 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1979 p1node: 0000000000000000000000000000000000000000
1993 p1node: 0000000000000000000000000000000000000000
1980 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1994 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1981 p1node--verbose: 0000000000000000000000000000000000000000
1995 p1node--verbose: 0000000000000000000000000000000000000000
1982 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1996 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1983 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1997 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1984 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1998 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1985 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1999 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1986 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2000 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1987 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2001 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1988 p1node--verbose: 0000000000000000000000000000000000000000
2002 p1node--verbose: 0000000000000000000000000000000000000000
1989 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2003 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1990 p1node--debug: 0000000000000000000000000000000000000000
2004 p1node--debug: 0000000000000000000000000000000000000000
1991 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2005 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1992 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2006 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1993 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2007 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1994 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2008 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1995 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2009 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1996 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2010 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1997 p1node--debug: 0000000000000000000000000000000000000000
2011 p1node--debug: 0000000000000000000000000000000000000000
1998 p2node: 0000000000000000000000000000000000000000
2012 p2node: 0000000000000000000000000000000000000000
1999 p2node: 0000000000000000000000000000000000000000
2013 p2node: 0000000000000000000000000000000000000000
2000 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2014 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2001 p2node: 0000000000000000000000000000000000000000
2015 p2node: 0000000000000000000000000000000000000000
2002 p2node: 0000000000000000000000000000000000000000
2016 p2node: 0000000000000000000000000000000000000000
2003 p2node: 0000000000000000000000000000000000000000
2017 p2node: 0000000000000000000000000000000000000000
2004 p2node: 0000000000000000000000000000000000000000
2018 p2node: 0000000000000000000000000000000000000000
2005 p2node: 0000000000000000000000000000000000000000
2019 p2node: 0000000000000000000000000000000000000000
2006 p2node: 0000000000000000000000000000000000000000
2020 p2node: 0000000000000000000000000000000000000000
2007 p2node--verbose: 0000000000000000000000000000000000000000
2021 p2node--verbose: 0000000000000000000000000000000000000000
2008 p2node--verbose: 0000000000000000000000000000000000000000
2022 p2node--verbose: 0000000000000000000000000000000000000000
2009 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2023 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2010 p2node--verbose: 0000000000000000000000000000000000000000
2024 p2node--verbose: 0000000000000000000000000000000000000000
2011 p2node--verbose: 0000000000000000000000000000000000000000
2025 p2node--verbose: 0000000000000000000000000000000000000000
2012 p2node--verbose: 0000000000000000000000000000000000000000
2026 p2node--verbose: 0000000000000000000000000000000000000000
2013 p2node--verbose: 0000000000000000000000000000000000000000
2027 p2node--verbose: 0000000000000000000000000000000000000000
2014 p2node--verbose: 0000000000000000000000000000000000000000
2028 p2node--verbose: 0000000000000000000000000000000000000000
2015 p2node--verbose: 0000000000000000000000000000000000000000
2029 p2node--verbose: 0000000000000000000000000000000000000000
2016 p2node--debug: 0000000000000000000000000000000000000000
2030 p2node--debug: 0000000000000000000000000000000000000000
2017 p2node--debug: 0000000000000000000000000000000000000000
2031 p2node--debug: 0000000000000000000000000000000000000000
2018 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2032 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2019 p2node--debug: 0000000000000000000000000000000000000000
2033 p2node--debug: 0000000000000000000000000000000000000000
2020 p2node--debug: 0000000000000000000000000000000000000000
2034 p2node--debug: 0000000000000000000000000000000000000000
2021 p2node--debug: 0000000000000000000000000000000000000000
2035 p2node--debug: 0000000000000000000000000000000000000000
2022 p2node--debug: 0000000000000000000000000000000000000000
2036 p2node--debug: 0000000000000000000000000000000000000000
2023 p2node--debug: 0000000000000000000000000000000000000000
2037 p2node--debug: 0000000000000000000000000000000000000000
2024 p2node--debug: 0000000000000000000000000000000000000000
2038 p2node--debug: 0000000000000000000000000000000000000000
2025
2039
2026 Filters work:
2040 Filters work:
2027
2041
2028 $ hg log --template '{author|domain}\n'
2042 $ hg log --template '{author|domain}\n'
2029
2043
2030 hostname
2044 hostname
2031
2045
2032
2046
2033
2047
2034
2048
2035 place
2049 place
2036 place
2050 place
2037 hostname
2051 hostname
2038
2052
2039 $ hg log --template '{author|person}\n'
2053 $ hg log --template '{author|person}\n'
2040 test
2054 test
2041 User Name
2055 User Name
2042 person
2056 person
2043 person
2057 person
2044 person
2058 person
2045 person
2059 person
2046 other
2060 other
2047 A. N. Other
2061 A. N. Other
2048 User Name
2062 User Name
2049
2063
2050 $ hg log --template '{author|user}\n'
2064 $ hg log --template '{author|user}\n'
2051 test
2065 test
2052 user
2066 user
2053 person
2067 person
2054 person
2068 person
2055 person
2069 person
2056 person
2070 person
2057 other
2071 other
2058 other
2072 other
2059 user
2073 user
2060
2074
2061 $ hg log --template '{date|date}\n'
2075 $ hg log --template '{date|date}\n'
2062 Wed Jan 01 10:01:00 2020 +0000
2076 Wed Jan 01 10:01:00 2020 +0000
2063 Mon Jan 12 13:46:40 1970 +0000
2077 Mon Jan 12 13:46:40 1970 +0000
2064 Sun Jan 18 08:40:01 1970 +0000
2078 Sun Jan 18 08:40:01 1970 +0000
2065 Sun Jan 18 08:40:00 1970 +0000
2079 Sun Jan 18 08:40:00 1970 +0000
2066 Sat Jan 17 04:53:20 1970 +0000
2080 Sat Jan 17 04:53:20 1970 +0000
2067 Fri Jan 16 01:06:40 1970 +0000
2081 Fri Jan 16 01:06:40 1970 +0000
2068 Wed Jan 14 21:20:00 1970 +0000
2082 Wed Jan 14 21:20:00 1970 +0000
2069 Tue Jan 13 17:33:20 1970 +0000
2083 Tue Jan 13 17:33:20 1970 +0000
2070 Mon Jan 12 13:46:40 1970 +0000
2084 Mon Jan 12 13:46:40 1970 +0000
2071
2085
2072 $ hg log --template '{date|isodate}\n'
2086 $ hg log --template '{date|isodate}\n'
2073 2020-01-01 10:01 +0000
2087 2020-01-01 10:01 +0000
2074 1970-01-12 13:46 +0000
2088 1970-01-12 13:46 +0000
2075 1970-01-18 08:40 +0000
2089 1970-01-18 08:40 +0000
2076 1970-01-18 08:40 +0000
2090 1970-01-18 08:40 +0000
2077 1970-01-17 04:53 +0000
2091 1970-01-17 04:53 +0000
2078 1970-01-16 01:06 +0000
2092 1970-01-16 01:06 +0000
2079 1970-01-14 21:20 +0000
2093 1970-01-14 21:20 +0000
2080 1970-01-13 17:33 +0000
2094 1970-01-13 17:33 +0000
2081 1970-01-12 13:46 +0000
2095 1970-01-12 13:46 +0000
2082
2096
2083 $ hg log --template '{date|isodatesec}\n'
2097 $ hg log --template '{date|isodatesec}\n'
2084 2020-01-01 10:01:00 +0000
2098 2020-01-01 10:01:00 +0000
2085 1970-01-12 13:46:40 +0000
2099 1970-01-12 13:46:40 +0000
2086 1970-01-18 08:40:01 +0000
2100 1970-01-18 08:40:01 +0000
2087 1970-01-18 08:40:00 +0000
2101 1970-01-18 08:40:00 +0000
2088 1970-01-17 04:53:20 +0000
2102 1970-01-17 04:53:20 +0000
2089 1970-01-16 01:06:40 +0000
2103 1970-01-16 01:06:40 +0000
2090 1970-01-14 21:20:00 +0000
2104 1970-01-14 21:20:00 +0000
2091 1970-01-13 17:33:20 +0000
2105 1970-01-13 17:33:20 +0000
2092 1970-01-12 13:46:40 +0000
2106 1970-01-12 13:46:40 +0000
2093
2107
2094 $ hg log --template '{date|rfc822date}\n'
2108 $ hg log --template '{date|rfc822date}\n'
2095 Wed, 01 Jan 2020 10:01:00 +0000
2109 Wed, 01 Jan 2020 10:01:00 +0000
2096 Mon, 12 Jan 1970 13:46:40 +0000
2110 Mon, 12 Jan 1970 13:46:40 +0000
2097 Sun, 18 Jan 1970 08:40:01 +0000
2111 Sun, 18 Jan 1970 08:40:01 +0000
2098 Sun, 18 Jan 1970 08:40:00 +0000
2112 Sun, 18 Jan 1970 08:40:00 +0000
2099 Sat, 17 Jan 1970 04:53:20 +0000
2113 Sat, 17 Jan 1970 04:53:20 +0000
2100 Fri, 16 Jan 1970 01:06:40 +0000
2114 Fri, 16 Jan 1970 01:06:40 +0000
2101 Wed, 14 Jan 1970 21:20:00 +0000
2115 Wed, 14 Jan 1970 21:20:00 +0000
2102 Tue, 13 Jan 1970 17:33:20 +0000
2116 Tue, 13 Jan 1970 17:33:20 +0000
2103 Mon, 12 Jan 1970 13:46:40 +0000
2117 Mon, 12 Jan 1970 13:46:40 +0000
2104
2118
2105 $ hg log --template '{desc|firstline}\n'
2119 $ hg log --template '{desc|firstline}\n'
2106 third
2120 third
2107 second
2121 second
2108 merge
2122 merge
2109 new head
2123 new head
2110 new branch
2124 new branch
2111 no user, no domain
2125 no user, no domain
2112 no person
2126 no person
2113 other 1
2127 other 1
2114 line 1
2128 line 1
2115
2129
2116 $ hg log --template '{node|short}\n'
2130 $ hg log --template '{node|short}\n'
2117 95c24699272e
2131 95c24699272e
2118 29114dbae42b
2132 29114dbae42b
2119 d41e714fe50d
2133 d41e714fe50d
2120 13207e5a10d9
2134 13207e5a10d9
2121 bbe44766e73d
2135 bbe44766e73d
2122 10e46f2dcbf4
2136 10e46f2dcbf4
2123 97054abb4ab8
2137 97054abb4ab8
2124 b608e9d1a3f0
2138 b608e9d1a3f0
2125 1e4e1b8f71e0
2139 1e4e1b8f71e0
2126
2140
2127 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2141 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2128 <changeset author="test"/>
2142 <changeset author="test"/>
2129 <changeset author="User Name &lt;user@hostname&gt;"/>
2143 <changeset author="User Name &lt;user@hostname&gt;"/>
2130 <changeset author="person"/>
2144 <changeset author="person"/>
2131 <changeset author="person"/>
2145 <changeset author="person"/>
2132 <changeset author="person"/>
2146 <changeset author="person"/>
2133 <changeset author="person"/>
2147 <changeset author="person"/>
2134 <changeset author="other@place"/>
2148 <changeset author="other@place"/>
2135 <changeset author="A. N. Other &lt;other@place&gt;"/>
2149 <changeset author="A. N. Other &lt;other@place&gt;"/>
2136 <changeset author="User Name &lt;user@hostname&gt;"/>
2150 <changeset author="User Name &lt;user@hostname&gt;"/>
2137
2151
2138 $ hg log --template '{rev}: {children}\n'
2152 $ hg log --template '{rev}: {children}\n'
2139 8:
2153 8:
2140 7: 8:95c24699272e
2154 7: 8:95c24699272e
2141 6:
2155 6:
2142 5: 6:d41e714fe50d
2156 5: 6:d41e714fe50d
2143 4: 6:d41e714fe50d
2157 4: 6:d41e714fe50d
2144 3: 4:bbe44766e73d 5:13207e5a10d9
2158 3: 4:bbe44766e73d 5:13207e5a10d9
2145 2: 3:10e46f2dcbf4
2159 2: 3:10e46f2dcbf4
2146 1: 2:97054abb4ab8
2160 1: 2:97054abb4ab8
2147 0: 1:b608e9d1a3f0
2161 0: 1:b608e9d1a3f0
2148
2162
2149 Formatnode filter works:
2163 Formatnode filter works:
2150
2164
2151 $ hg -q log -r 0 --template '{node|formatnode}\n'
2165 $ hg -q log -r 0 --template '{node|formatnode}\n'
2152 1e4e1b8f71e0
2166 1e4e1b8f71e0
2153
2167
2154 $ hg log -r 0 --template '{node|formatnode}\n'
2168 $ hg log -r 0 --template '{node|formatnode}\n'
2155 1e4e1b8f71e0
2169 1e4e1b8f71e0
2156
2170
2157 $ hg -v log -r 0 --template '{node|formatnode}\n'
2171 $ hg -v log -r 0 --template '{node|formatnode}\n'
2158 1e4e1b8f71e0
2172 1e4e1b8f71e0
2159
2173
2160 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2174 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2161 1e4e1b8f71e05681d422154f5421e385fec3454f
2175 1e4e1b8f71e05681d422154f5421e385fec3454f
2162
2176
2163 Age filter:
2177 Age filter:
2164
2178
2165 $ hg init unstable-hash
2179 $ hg init unstable-hash
2166 $ cd unstable-hash
2180 $ cd unstable-hash
2167 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2181 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2168
2182
2169 >>> from __future__ import absolute_import
2183 >>> from __future__ import absolute_import
2170 >>> import datetime
2184 >>> import datetime
2171 >>> fp = open('a', 'w')
2185 >>> fp = open('a', 'w')
2172 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2186 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2173 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2187 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2174 >>> fp.close()
2188 >>> fp.close()
2175 $ hg add a
2189 $ hg add a
2176 $ hg commit -m future -d "`cat a`"
2190 $ hg commit -m future -d "`cat a`"
2177
2191
2178 $ hg log -l1 --template '{date|age}\n'
2192 $ hg log -l1 --template '{date|age}\n'
2179 7 years from now
2193 7 years from now
2180
2194
2181 $ cd ..
2195 $ cd ..
2182 $ rm -rf unstable-hash
2196 $ rm -rf unstable-hash
2183
2197
2184 Add a dummy commit to make up for the instability of the above:
2198 Add a dummy commit to make up for the instability of the above:
2185
2199
2186 $ echo a > a
2200 $ echo a > a
2187 $ hg add a
2201 $ hg add a
2188 $ hg ci -m future
2202 $ hg ci -m future
2189
2203
2190 Count filter:
2204 Count filter:
2191
2205
2192 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2206 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2193 40 12
2207 40 12
2194
2208
2195 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2209 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2196 0 1 4
2210 0 1 4
2197
2211
2198 $ hg log -G --template '{rev}: children: {children|count}, \
2212 $ hg log -G --template '{rev}: children: {children|count}, \
2199 > tags: {tags|count}, file_adds: {file_adds|count}, \
2213 > tags: {tags|count}, file_adds: {file_adds|count}, \
2200 > ancestors: {revset("ancestors(%s)", rev)|count}'
2214 > ancestors: {revset("ancestors(%s)", rev)|count}'
2201 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2215 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2202 |
2216 |
2203 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2217 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2204 |
2218 |
2205 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2219 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2206
2220
2207 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2221 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2208 |\
2222 |\
2209 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2223 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2210 | |
2224 | |
2211 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2225 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2212 |/
2226 |/
2213 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2227 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2214 |
2228 |
2215 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2229 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2216 |
2230 |
2217 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2231 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2218 |
2232 |
2219 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2233 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2220
2234
2221
2235
2222 Upper/lower filters:
2236 Upper/lower filters:
2223
2237
2224 $ hg log -r0 --template '{branch|upper}\n'
2238 $ hg log -r0 --template '{branch|upper}\n'
2225 DEFAULT
2239 DEFAULT
2226 $ hg log -r0 --template '{author|lower}\n'
2240 $ hg log -r0 --template '{author|lower}\n'
2227 user name <user@hostname>
2241 user name <user@hostname>
2228 $ hg log -r0 --template '{date|upper}\n'
2242 $ hg log -r0 --template '{date|upper}\n'
2229 abort: template filter 'upper' is not compatible with keyword 'date'
2243 abort: template filter 'upper' is not compatible with keyword 'date'
2230 [255]
2244 [255]
2231
2245
2232 Add a commit that does all possible modifications at once
2246 Add a commit that does all possible modifications at once
2233
2247
2234 $ echo modify >> third
2248 $ echo modify >> third
2235 $ touch b
2249 $ touch b
2236 $ hg add b
2250 $ hg add b
2237 $ hg mv fourth fifth
2251 $ hg mv fourth fifth
2238 $ hg rm a
2252 $ hg rm a
2239 $ hg ci -m "Modify, add, remove, rename"
2253 $ hg ci -m "Modify, add, remove, rename"
2240
2254
2241 Check the status template
2255 Check the status template
2242
2256
2243 $ cat <<EOF >> $HGRCPATH
2257 $ cat <<EOF >> $HGRCPATH
2244 > [extensions]
2258 > [extensions]
2245 > color=
2259 > color=
2246 > EOF
2260 > EOF
2247
2261
2248 $ hg log -T status -r 10
2262 $ hg log -T status -r 10
2249 changeset: 10:0f9759ec227a
2263 changeset: 10:0f9759ec227a
2250 tag: tip
2264 tag: tip
2251 user: test
2265 user: test
2252 date: Thu Jan 01 00:00:00 1970 +0000
2266 date: Thu Jan 01 00:00:00 1970 +0000
2253 summary: Modify, add, remove, rename
2267 summary: Modify, add, remove, rename
2254 files:
2268 files:
2255 M third
2269 M third
2256 A b
2270 A b
2257 A fifth
2271 A fifth
2258 R a
2272 R a
2259 R fourth
2273 R fourth
2260
2274
2261 $ hg log -T status -C -r 10
2275 $ hg log -T status -C -r 10
2262 changeset: 10:0f9759ec227a
2276 changeset: 10:0f9759ec227a
2263 tag: tip
2277 tag: tip
2264 user: test
2278 user: test
2265 date: Thu Jan 01 00:00:00 1970 +0000
2279 date: Thu Jan 01 00:00:00 1970 +0000
2266 summary: Modify, add, remove, rename
2280 summary: Modify, add, remove, rename
2267 files:
2281 files:
2268 M third
2282 M third
2269 A b
2283 A b
2270 A fifth
2284 A fifth
2271 fourth
2285 fourth
2272 R a
2286 R a
2273 R fourth
2287 R fourth
2274
2288
2275 $ hg log -T status -C -r 10 -v
2289 $ hg log -T status -C -r 10 -v
2276 changeset: 10:0f9759ec227a
2290 changeset: 10:0f9759ec227a
2277 tag: tip
2291 tag: tip
2278 user: test
2292 user: test
2279 date: Thu Jan 01 00:00:00 1970 +0000
2293 date: Thu Jan 01 00:00:00 1970 +0000
2280 description:
2294 description:
2281 Modify, add, remove, rename
2295 Modify, add, remove, rename
2282
2296
2283 files:
2297 files:
2284 M third
2298 M third
2285 A b
2299 A b
2286 A fifth
2300 A fifth
2287 fourth
2301 fourth
2288 R a
2302 R a
2289 R fourth
2303 R fourth
2290
2304
2291 $ hg log -T status -C -r 10 --debug
2305 $ hg log -T status -C -r 10 --debug
2292 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2306 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2293 tag: tip
2307 tag: tip
2294 phase: secret
2308 phase: secret
2295 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2309 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2296 parent: -1:0000000000000000000000000000000000000000
2310 parent: -1:0000000000000000000000000000000000000000
2297 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2311 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2298 user: test
2312 user: test
2299 date: Thu Jan 01 00:00:00 1970 +0000
2313 date: Thu Jan 01 00:00:00 1970 +0000
2300 extra: branch=default
2314 extra: branch=default
2301 description:
2315 description:
2302 Modify, add, remove, rename
2316 Modify, add, remove, rename
2303
2317
2304 files:
2318 files:
2305 M third
2319 M third
2306 A b
2320 A b
2307 A fifth
2321 A fifth
2308 fourth
2322 fourth
2309 R a
2323 R a
2310 R fourth
2324 R fourth
2311
2325
2312 $ hg log -T status -C -r 10 --quiet
2326 $ hg log -T status -C -r 10 --quiet
2313 10:0f9759ec227a
2327 10:0f9759ec227a
2314 $ hg --color=debug log -T status -r 10
2328 $ hg --color=debug log -T status -r 10
2315 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2329 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2316 [log.tag|tag: tip]
2330 [log.tag|tag: tip]
2317 [log.user|user: test]
2331 [log.user|user: test]
2318 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2332 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2319 [log.summary|summary: Modify, add, remove, rename]
2333 [log.summary|summary: Modify, add, remove, rename]
2320 [ui.note log.files|files:]
2334 [ui.note log.files|files:]
2321 [status.modified|M third]
2335 [status.modified|M third]
2322 [status.added|A b]
2336 [status.added|A b]
2323 [status.added|A fifth]
2337 [status.added|A fifth]
2324 [status.removed|R a]
2338 [status.removed|R a]
2325 [status.removed|R fourth]
2339 [status.removed|R fourth]
2326
2340
2327 $ hg --color=debug log -T status -C -r 10
2341 $ hg --color=debug log -T status -C -r 10
2328 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2342 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2329 [log.tag|tag: tip]
2343 [log.tag|tag: tip]
2330 [log.user|user: test]
2344 [log.user|user: test]
2331 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2345 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2332 [log.summary|summary: Modify, add, remove, rename]
2346 [log.summary|summary: Modify, add, remove, rename]
2333 [ui.note log.files|files:]
2347 [ui.note log.files|files:]
2334 [status.modified|M third]
2348 [status.modified|M third]
2335 [status.added|A b]
2349 [status.added|A b]
2336 [status.added|A fifth]
2350 [status.added|A fifth]
2337 [status.copied| fourth]
2351 [status.copied| fourth]
2338 [status.removed|R a]
2352 [status.removed|R a]
2339 [status.removed|R fourth]
2353 [status.removed|R fourth]
2340
2354
2341 $ hg --color=debug log -T status -C -r 10 -v
2355 $ hg --color=debug log -T status -C -r 10 -v
2342 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2356 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2343 [log.tag|tag: tip]
2357 [log.tag|tag: tip]
2344 [log.user|user: test]
2358 [log.user|user: test]
2345 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2359 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2346 [ui.note log.description|description:]
2360 [ui.note log.description|description:]
2347 [ui.note log.description|Modify, add, remove, rename]
2361 [ui.note log.description|Modify, add, remove, rename]
2348
2362
2349 [ui.note log.files|files:]
2363 [ui.note log.files|files:]
2350 [status.modified|M third]
2364 [status.modified|M third]
2351 [status.added|A b]
2365 [status.added|A b]
2352 [status.added|A fifth]
2366 [status.added|A fifth]
2353 [status.copied| fourth]
2367 [status.copied| fourth]
2354 [status.removed|R a]
2368 [status.removed|R a]
2355 [status.removed|R fourth]
2369 [status.removed|R fourth]
2356
2370
2357 $ hg --color=debug log -T status -C -r 10 --debug
2371 $ hg --color=debug log -T status -C -r 10 --debug
2358 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2372 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2359 [log.tag|tag: tip]
2373 [log.tag|tag: tip]
2360 [log.phase|phase: secret]
2374 [log.phase|phase: secret]
2361 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2375 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2362 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2376 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2363 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2377 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2364 [log.user|user: test]
2378 [log.user|user: test]
2365 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2379 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2366 [ui.debug log.extra|extra: branch=default]
2380 [ui.debug log.extra|extra: branch=default]
2367 [ui.note log.description|description:]
2381 [ui.note log.description|description:]
2368 [ui.note log.description|Modify, add, remove, rename]
2382 [ui.note log.description|Modify, add, remove, rename]
2369
2383
2370 [ui.note log.files|files:]
2384 [ui.note log.files|files:]
2371 [status.modified|M third]
2385 [status.modified|M third]
2372 [status.added|A b]
2386 [status.added|A b]
2373 [status.added|A fifth]
2387 [status.added|A fifth]
2374 [status.copied| fourth]
2388 [status.copied| fourth]
2375 [status.removed|R a]
2389 [status.removed|R a]
2376 [status.removed|R fourth]
2390 [status.removed|R fourth]
2377
2391
2378 $ hg --color=debug log -T status -C -r 10 --quiet
2392 $ hg --color=debug log -T status -C -r 10 --quiet
2379 [log.node|10:0f9759ec227a]
2393 [log.node|10:0f9759ec227a]
2380
2394
2381 Check the bisect template
2395 Check the bisect template
2382
2396
2383 $ hg bisect -g 1
2397 $ hg bisect -g 1
2384 $ hg bisect -b 3 --noupdate
2398 $ hg bisect -b 3 --noupdate
2385 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2399 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2386 $ hg log -T bisect -r 0:4
2400 $ hg log -T bisect -r 0:4
2387 changeset: 0:1e4e1b8f71e0
2401 changeset: 0:1e4e1b8f71e0
2388 bisect: good (implicit)
2402 bisect: good (implicit)
2389 user: User Name <user@hostname>
2403 user: User Name <user@hostname>
2390 date: Mon Jan 12 13:46:40 1970 +0000
2404 date: Mon Jan 12 13:46:40 1970 +0000
2391 summary: line 1
2405 summary: line 1
2392
2406
2393 changeset: 1:b608e9d1a3f0
2407 changeset: 1:b608e9d1a3f0
2394 bisect: good
2408 bisect: good
2395 user: A. N. Other <other@place>
2409 user: A. N. Other <other@place>
2396 date: Tue Jan 13 17:33:20 1970 +0000
2410 date: Tue Jan 13 17:33:20 1970 +0000
2397 summary: other 1
2411 summary: other 1
2398
2412
2399 changeset: 2:97054abb4ab8
2413 changeset: 2:97054abb4ab8
2400 bisect: untested
2414 bisect: untested
2401 user: other@place
2415 user: other@place
2402 date: Wed Jan 14 21:20:00 1970 +0000
2416 date: Wed Jan 14 21:20:00 1970 +0000
2403 summary: no person
2417 summary: no person
2404
2418
2405 changeset: 3:10e46f2dcbf4
2419 changeset: 3:10e46f2dcbf4
2406 bisect: bad
2420 bisect: bad
2407 user: person
2421 user: person
2408 date: Fri Jan 16 01:06:40 1970 +0000
2422 date: Fri Jan 16 01:06:40 1970 +0000
2409 summary: no user, no domain
2423 summary: no user, no domain
2410
2424
2411 changeset: 4:bbe44766e73d
2425 changeset: 4:bbe44766e73d
2412 bisect: bad (implicit)
2426 bisect: bad (implicit)
2413 branch: foo
2427 branch: foo
2414 user: person
2428 user: person
2415 date: Sat Jan 17 04:53:20 1970 +0000
2429 date: Sat Jan 17 04:53:20 1970 +0000
2416 summary: new branch
2430 summary: new branch
2417
2431
2418 $ hg log --debug -T bisect -r 0:4
2432 $ hg log --debug -T bisect -r 0:4
2419 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2433 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2420 bisect: good (implicit)
2434 bisect: good (implicit)
2421 phase: public
2435 phase: public
2422 parent: -1:0000000000000000000000000000000000000000
2436 parent: -1:0000000000000000000000000000000000000000
2423 parent: -1:0000000000000000000000000000000000000000
2437 parent: -1:0000000000000000000000000000000000000000
2424 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2438 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2425 user: User Name <user@hostname>
2439 user: User Name <user@hostname>
2426 date: Mon Jan 12 13:46:40 1970 +0000
2440 date: Mon Jan 12 13:46:40 1970 +0000
2427 files+: a
2441 files+: a
2428 extra: branch=default
2442 extra: branch=default
2429 description:
2443 description:
2430 line 1
2444 line 1
2431 line 2
2445 line 2
2432
2446
2433
2447
2434 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2448 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2435 bisect: good
2449 bisect: good
2436 phase: public
2450 phase: public
2437 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2451 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2438 parent: -1:0000000000000000000000000000000000000000
2452 parent: -1:0000000000000000000000000000000000000000
2439 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2453 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2440 user: A. N. Other <other@place>
2454 user: A. N. Other <other@place>
2441 date: Tue Jan 13 17:33:20 1970 +0000
2455 date: Tue Jan 13 17:33:20 1970 +0000
2442 files+: b
2456 files+: b
2443 extra: branch=default
2457 extra: branch=default
2444 description:
2458 description:
2445 other 1
2459 other 1
2446 other 2
2460 other 2
2447
2461
2448 other 3
2462 other 3
2449
2463
2450
2464
2451 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2465 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2452 bisect: untested
2466 bisect: untested
2453 phase: public
2467 phase: public
2454 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2468 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2455 parent: -1:0000000000000000000000000000000000000000
2469 parent: -1:0000000000000000000000000000000000000000
2456 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2470 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2457 user: other@place
2471 user: other@place
2458 date: Wed Jan 14 21:20:00 1970 +0000
2472 date: Wed Jan 14 21:20:00 1970 +0000
2459 files+: c
2473 files+: c
2460 extra: branch=default
2474 extra: branch=default
2461 description:
2475 description:
2462 no person
2476 no person
2463
2477
2464
2478
2465 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2479 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2466 bisect: bad
2480 bisect: bad
2467 phase: public
2481 phase: public
2468 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2482 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2469 parent: -1:0000000000000000000000000000000000000000
2483 parent: -1:0000000000000000000000000000000000000000
2470 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2484 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2471 user: person
2485 user: person
2472 date: Fri Jan 16 01:06:40 1970 +0000
2486 date: Fri Jan 16 01:06:40 1970 +0000
2473 files: c
2487 files: c
2474 extra: branch=default
2488 extra: branch=default
2475 description:
2489 description:
2476 no user, no domain
2490 no user, no domain
2477
2491
2478
2492
2479 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2493 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2480 bisect: bad (implicit)
2494 bisect: bad (implicit)
2481 branch: foo
2495 branch: foo
2482 phase: draft
2496 phase: draft
2483 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2497 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2484 parent: -1:0000000000000000000000000000000000000000
2498 parent: -1:0000000000000000000000000000000000000000
2485 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2499 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2486 user: person
2500 user: person
2487 date: Sat Jan 17 04:53:20 1970 +0000
2501 date: Sat Jan 17 04:53:20 1970 +0000
2488 extra: branch=foo
2502 extra: branch=foo
2489 description:
2503 description:
2490 new branch
2504 new branch
2491
2505
2492
2506
2493 $ hg log -v -T bisect -r 0:4
2507 $ hg log -v -T bisect -r 0:4
2494 changeset: 0:1e4e1b8f71e0
2508 changeset: 0:1e4e1b8f71e0
2495 bisect: good (implicit)
2509 bisect: good (implicit)
2496 user: User Name <user@hostname>
2510 user: User Name <user@hostname>
2497 date: Mon Jan 12 13:46:40 1970 +0000
2511 date: Mon Jan 12 13:46:40 1970 +0000
2498 files: a
2512 files: a
2499 description:
2513 description:
2500 line 1
2514 line 1
2501 line 2
2515 line 2
2502
2516
2503
2517
2504 changeset: 1:b608e9d1a3f0
2518 changeset: 1:b608e9d1a3f0
2505 bisect: good
2519 bisect: good
2506 user: A. N. Other <other@place>
2520 user: A. N. Other <other@place>
2507 date: Tue Jan 13 17:33:20 1970 +0000
2521 date: Tue Jan 13 17:33:20 1970 +0000
2508 files: b
2522 files: b
2509 description:
2523 description:
2510 other 1
2524 other 1
2511 other 2
2525 other 2
2512
2526
2513 other 3
2527 other 3
2514
2528
2515
2529
2516 changeset: 2:97054abb4ab8
2530 changeset: 2:97054abb4ab8
2517 bisect: untested
2531 bisect: untested
2518 user: other@place
2532 user: other@place
2519 date: Wed Jan 14 21:20:00 1970 +0000
2533 date: Wed Jan 14 21:20:00 1970 +0000
2520 files: c
2534 files: c
2521 description:
2535 description:
2522 no person
2536 no person
2523
2537
2524
2538
2525 changeset: 3:10e46f2dcbf4
2539 changeset: 3:10e46f2dcbf4
2526 bisect: bad
2540 bisect: bad
2527 user: person
2541 user: person
2528 date: Fri Jan 16 01:06:40 1970 +0000
2542 date: Fri Jan 16 01:06:40 1970 +0000
2529 files: c
2543 files: c
2530 description:
2544 description:
2531 no user, no domain
2545 no user, no domain
2532
2546
2533
2547
2534 changeset: 4:bbe44766e73d
2548 changeset: 4:bbe44766e73d
2535 bisect: bad (implicit)
2549 bisect: bad (implicit)
2536 branch: foo
2550 branch: foo
2537 user: person
2551 user: person
2538 date: Sat Jan 17 04:53:20 1970 +0000
2552 date: Sat Jan 17 04:53:20 1970 +0000
2539 description:
2553 description:
2540 new branch
2554 new branch
2541
2555
2542
2556
2543 $ hg --color=debug log -T bisect -r 0:4
2557 $ hg --color=debug log -T bisect -r 0:4
2544 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2558 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2545 [log.bisect bisect.good|bisect: good (implicit)]
2559 [log.bisect bisect.good|bisect: good (implicit)]
2546 [log.user|user: User Name <user@hostname>]
2560 [log.user|user: User Name <user@hostname>]
2547 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2561 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2548 [log.summary|summary: line 1]
2562 [log.summary|summary: line 1]
2549
2563
2550 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2564 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2551 [log.bisect bisect.good|bisect: good]
2565 [log.bisect bisect.good|bisect: good]
2552 [log.user|user: A. N. Other <other@place>]
2566 [log.user|user: A. N. Other <other@place>]
2553 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2567 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2554 [log.summary|summary: other 1]
2568 [log.summary|summary: other 1]
2555
2569
2556 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2570 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2557 [log.bisect bisect.untested|bisect: untested]
2571 [log.bisect bisect.untested|bisect: untested]
2558 [log.user|user: other@place]
2572 [log.user|user: other@place]
2559 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2573 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2560 [log.summary|summary: no person]
2574 [log.summary|summary: no person]
2561
2575
2562 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2576 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2563 [log.bisect bisect.bad|bisect: bad]
2577 [log.bisect bisect.bad|bisect: bad]
2564 [log.user|user: person]
2578 [log.user|user: person]
2565 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2579 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2566 [log.summary|summary: no user, no domain]
2580 [log.summary|summary: no user, no domain]
2567
2581
2568 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2582 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2569 [log.bisect bisect.bad|bisect: bad (implicit)]
2583 [log.bisect bisect.bad|bisect: bad (implicit)]
2570 [log.branch|branch: foo]
2584 [log.branch|branch: foo]
2571 [log.user|user: person]
2585 [log.user|user: person]
2572 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2586 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2573 [log.summary|summary: new branch]
2587 [log.summary|summary: new branch]
2574
2588
2575 $ hg --color=debug log --debug -T bisect -r 0:4
2589 $ hg --color=debug log --debug -T bisect -r 0:4
2576 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2590 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2577 [log.bisect bisect.good|bisect: good (implicit)]
2591 [log.bisect bisect.good|bisect: good (implicit)]
2578 [log.phase|phase: public]
2592 [log.phase|phase: public]
2579 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2593 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2580 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2594 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2581 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2595 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2582 [log.user|user: User Name <user@hostname>]
2596 [log.user|user: User Name <user@hostname>]
2583 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2597 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2584 [ui.debug log.files|files+: a]
2598 [ui.debug log.files|files+: a]
2585 [ui.debug log.extra|extra: branch=default]
2599 [ui.debug log.extra|extra: branch=default]
2586 [ui.note log.description|description:]
2600 [ui.note log.description|description:]
2587 [ui.note log.description|line 1
2601 [ui.note log.description|line 1
2588 line 2]
2602 line 2]
2589
2603
2590
2604
2591 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2605 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2592 [log.bisect bisect.good|bisect: good]
2606 [log.bisect bisect.good|bisect: good]
2593 [log.phase|phase: public]
2607 [log.phase|phase: public]
2594 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2608 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2595 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2609 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2596 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2610 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2597 [log.user|user: A. N. Other <other@place>]
2611 [log.user|user: A. N. Other <other@place>]
2598 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2612 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2599 [ui.debug log.files|files+: b]
2613 [ui.debug log.files|files+: b]
2600 [ui.debug log.extra|extra: branch=default]
2614 [ui.debug log.extra|extra: branch=default]
2601 [ui.note log.description|description:]
2615 [ui.note log.description|description:]
2602 [ui.note log.description|other 1
2616 [ui.note log.description|other 1
2603 other 2
2617 other 2
2604
2618
2605 other 3]
2619 other 3]
2606
2620
2607
2621
2608 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2622 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2609 [log.bisect bisect.untested|bisect: untested]
2623 [log.bisect bisect.untested|bisect: untested]
2610 [log.phase|phase: public]
2624 [log.phase|phase: public]
2611 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2625 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2612 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2626 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2613 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2627 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2614 [log.user|user: other@place]
2628 [log.user|user: other@place]
2615 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2629 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2616 [ui.debug log.files|files+: c]
2630 [ui.debug log.files|files+: c]
2617 [ui.debug log.extra|extra: branch=default]
2631 [ui.debug log.extra|extra: branch=default]
2618 [ui.note log.description|description:]
2632 [ui.note log.description|description:]
2619 [ui.note log.description|no person]
2633 [ui.note log.description|no person]
2620
2634
2621
2635
2622 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2636 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2623 [log.bisect bisect.bad|bisect: bad]
2637 [log.bisect bisect.bad|bisect: bad]
2624 [log.phase|phase: public]
2638 [log.phase|phase: public]
2625 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2639 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2626 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2640 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2627 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2641 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2628 [log.user|user: person]
2642 [log.user|user: person]
2629 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2643 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2630 [ui.debug log.files|files: c]
2644 [ui.debug log.files|files: c]
2631 [ui.debug log.extra|extra: branch=default]
2645 [ui.debug log.extra|extra: branch=default]
2632 [ui.note log.description|description:]
2646 [ui.note log.description|description:]
2633 [ui.note log.description|no user, no domain]
2647 [ui.note log.description|no user, no domain]
2634
2648
2635
2649
2636 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2650 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2637 [log.bisect bisect.bad|bisect: bad (implicit)]
2651 [log.bisect bisect.bad|bisect: bad (implicit)]
2638 [log.branch|branch: foo]
2652 [log.branch|branch: foo]
2639 [log.phase|phase: draft]
2653 [log.phase|phase: draft]
2640 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2654 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2641 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2655 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2642 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2656 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2643 [log.user|user: person]
2657 [log.user|user: person]
2644 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2658 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2645 [ui.debug log.extra|extra: branch=foo]
2659 [ui.debug log.extra|extra: branch=foo]
2646 [ui.note log.description|description:]
2660 [ui.note log.description|description:]
2647 [ui.note log.description|new branch]
2661 [ui.note log.description|new branch]
2648
2662
2649
2663
2650 $ hg --color=debug log -v -T bisect -r 0:4
2664 $ hg --color=debug log -v -T bisect -r 0:4
2651 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2665 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2652 [log.bisect bisect.good|bisect: good (implicit)]
2666 [log.bisect bisect.good|bisect: good (implicit)]
2653 [log.user|user: User Name <user@hostname>]
2667 [log.user|user: User Name <user@hostname>]
2654 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2668 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2655 [ui.note log.files|files: a]
2669 [ui.note log.files|files: a]
2656 [ui.note log.description|description:]
2670 [ui.note log.description|description:]
2657 [ui.note log.description|line 1
2671 [ui.note log.description|line 1
2658 line 2]
2672 line 2]
2659
2673
2660
2674
2661 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2675 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2662 [log.bisect bisect.good|bisect: good]
2676 [log.bisect bisect.good|bisect: good]
2663 [log.user|user: A. N. Other <other@place>]
2677 [log.user|user: A. N. Other <other@place>]
2664 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2678 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2665 [ui.note log.files|files: b]
2679 [ui.note log.files|files: b]
2666 [ui.note log.description|description:]
2680 [ui.note log.description|description:]
2667 [ui.note log.description|other 1
2681 [ui.note log.description|other 1
2668 other 2
2682 other 2
2669
2683
2670 other 3]
2684 other 3]
2671
2685
2672
2686
2673 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2687 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2674 [log.bisect bisect.untested|bisect: untested]
2688 [log.bisect bisect.untested|bisect: untested]
2675 [log.user|user: other@place]
2689 [log.user|user: other@place]
2676 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2690 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2677 [ui.note log.files|files: c]
2691 [ui.note log.files|files: c]
2678 [ui.note log.description|description:]
2692 [ui.note log.description|description:]
2679 [ui.note log.description|no person]
2693 [ui.note log.description|no person]
2680
2694
2681
2695
2682 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2696 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2683 [log.bisect bisect.bad|bisect: bad]
2697 [log.bisect bisect.bad|bisect: bad]
2684 [log.user|user: person]
2698 [log.user|user: person]
2685 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2699 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2686 [ui.note log.files|files: c]
2700 [ui.note log.files|files: c]
2687 [ui.note log.description|description:]
2701 [ui.note log.description|description:]
2688 [ui.note log.description|no user, no domain]
2702 [ui.note log.description|no user, no domain]
2689
2703
2690
2704
2691 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2705 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2692 [log.bisect bisect.bad|bisect: bad (implicit)]
2706 [log.bisect bisect.bad|bisect: bad (implicit)]
2693 [log.branch|branch: foo]
2707 [log.branch|branch: foo]
2694 [log.user|user: person]
2708 [log.user|user: person]
2695 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2709 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2696 [ui.note log.description|description:]
2710 [ui.note log.description|description:]
2697 [ui.note log.description|new branch]
2711 [ui.note log.description|new branch]
2698
2712
2699
2713
2700 $ hg bisect --reset
2714 $ hg bisect --reset
2701
2715
2702 Error on syntax:
2716 Error on syntax:
2703
2717
2704 $ echo 'x = "f' >> t
2718 $ echo 'x = "f' >> t
2705 $ hg log
2719 $ hg log
2706 hg: parse error at t:3: unmatched quotes
2720 hg: parse error at t:3: unmatched quotes
2707 [255]
2721 [255]
2708
2722
2709 $ hg log -T '{date'
2723 $ hg log -T '{date'
2710 hg: parse error at 1: unterminated template expansion
2724 hg: parse error at 1: unterminated template expansion
2711 [255]
2725 [255]
2712
2726
2713 Behind the scenes, this will throw TypeError
2727 Behind the scenes, this will throw TypeError
2714
2728
2715 $ hg log -l 3 --template '{date|obfuscate}\n'
2729 $ hg log -l 3 --template '{date|obfuscate}\n'
2716 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2730 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2717 [255]
2731 [255]
2718
2732
2719 Behind the scenes, this will throw a ValueError
2733 Behind the scenes, this will throw a ValueError
2720
2734
2721 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2735 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2722 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2736 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2723 [255]
2737 [255]
2724
2738
2725 Behind the scenes, this will throw AttributeError
2739 Behind the scenes, this will throw AttributeError
2726
2740
2727 $ hg log -l 3 --template 'line: {date|escape}\n'
2741 $ hg log -l 3 --template 'line: {date|escape}\n'
2728 abort: template filter 'escape' is not compatible with keyword 'date'
2742 abort: template filter 'escape' is not compatible with keyword 'date'
2729 [255]
2743 [255]
2730
2744
2731 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2745 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2732 hg: parse error: localdate expects a date information
2746 hg: parse error: localdate expects a date information
2733 [255]
2747 [255]
2734
2748
2735 Behind the scenes, this will throw ValueError
2749 Behind the scenes, this will throw ValueError
2736
2750
2737 $ hg tip --template '{author|email|date}\n'
2751 $ hg tip --template '{author|email|date}\n'
2738 hg: parse error: date expects a date information
2752 hg: parse error: date expects a date information
2739 [255]
2753 [255]
2740
2754
2741 $ hg tip -T '{author|email|shortdate}\n'
2755 $ hg tip -T '{author|email|shortdate}\n'
2742 abort: template filter 'shortdate' is not compatible with keyword 'author'
2756 abort: template filter 'shortdate' is not compatible with keyword 'author'
2743 [255]
2757 [255]
2744
2758
2745 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2759 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2746 abort: incompatible use of template filter 'shortdate'
2760 abort: incompatible use of template filter 'shortdate'
2747 [255]
2761 [255]
2748
2762
2749 Error in nested template:
2763 Error in nested template:
2750
2764
2751 $ hg log -T '{"date'
2765 $ hg log -T '{"date'
2752 hg: parse error at 2: unterminated string
2766 hg: parse error at 2: unterminated string
2753 [255]
2767 [255]
2754
2768
2755 $ hg log -T '{"foo{date|?}"}'
2769 $ hg log -T '{"foo{date|?}"}'
2756 hg: parse error at 11: syntax error
2770 hg: parse error at 11: syntax error
2757 [255]
2771 [255]
2758
2772
2759 Thrown an error if a template function doesn't exist
2773 Thrown an error if a template function doesn't exist
2760
2774
2761 $ hg tip --template '{foo()}\n'
2775 $ hg tip --template '{foo()}\n'
2762 hg: parse error: unknown function 'foo'
2776 hg: parse error: unknown function 'foo'
2763 [255]
2777 [255]
2764
2778
2765 Pass generator object created by template function to filter
2779 Pass generator object created by template function to filter
2766
2780
2767 $ hg log -l 1 --template '{if(author, author)|user}\n'
2781 $ hg log -l 1 --template '{if(author, author)|user}\n'
2768 test
2782 test
2769
2783
2770 Test index keyword:
2784 Test index keyword:
2771
2785
2772 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2786 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2773 10 0:a 1:b 2:fifth 3:fourth 4:third
2787 10 0:a 1:b 2:fifth 3:fourth 4:third
2774 11 0:a
2788 11 0:a
2775
2789
2776 $ hg branches -T '{index} {branch}\n'
2790 $ hg branches -T '{index} {branch}\n'
2777 0 default
2791 0 default
2778 1 foo
2792 1 foo
2779
2793
2780 Test diff function:
2794 Test diff function:
2781
2795
2782 $ hg diff -c 8
2796 $ hg diff -c 8
2783 diff -r 29114dbae42b -r 95c24699272e fourth
2797 diff -r 29114dbae42b -r 95c24699272e fourth
2784 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2798 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2785 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2799 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2786 @@ -0,0 +1,1 @@
2800 @@ -0,0 +1,1 @@
2787 +second
2801 +second
2788 diff -r 29114dbae42b -r 95c24699272e second
2802 diff -r 29114dbae42b -r 95c24699272e second
2789 --- a/second Mon Jan 12 13:46:40 1970 +0000
2803 --- a/second Mon Jan 12 13:46:40 1970 +0000
2790 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2804 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2791 @@ -1,1 +0,0 @@
2805 @@ -1,1 +0,0 @@
2792 -second
2806 -second
2793 diff -r 29114dbae42b -r 95c24699272e third
2807 diff -r 29114dbae42b -r 95c24699272e third
2794 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2808 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2795 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2809 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2796 @@ -0,0 +1,1 @@
2810 @@ -0,0 +1,1 @@
2797 +third
2811 +third
2798
2812
2799 $ hg log -r 8 -T "{diff()}"
2813 $ hg log -r 8 -T "{diff()}"
2800 diff -r 29114dbae42b -r 95c24699272e fourth
2814 diff -r 29114dbae42b -r 95c24699272e fourth
2801 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2815 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2802 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2816 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2803 @@ -0,0 +1,1 @@
2817 @@ -0,0 +1,1 @@
2804 +second
2818 +second
2805 diff -r 29114dbae42b -r 95c24699272e second
2819 diff -r 29114dbae42b -r 95c24699272e second
2806 --- a/second Mon Jan 12 13:46:40 1970 +0000
2820 --- a/second Mon Jan 12 13:46:40 1970 +0000
2807 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2821 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2808 @@ -1,1 +0,0 @@
2822 @@ -1,1 +0,0 @@
2809 -second
2823 -second
2810 diff -r 29114dbae42b -r 95c24699272e third
2824 diff -r 29114dbae42b -r 95c24699272e third
2811 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2825 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2812 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2826 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2813 @@ -0,0 +1,1 @@
2827 @@ -0,0 +1,1 @@
2814 +third
2828 +third
2815
2829
2816 $ hg log -r 8 -T "{diff('glob:f*')}"
2830 $ hg log -r 8 -T "{diff('glob:f*')}"
2817 diff -r 29114dbae42b -r 95c24699272e fourth
2831 diff -r 29114dbae42b -r 95c24699272e fourth
2818 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2832 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2819 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2833 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2820 @@ -0,0 +1,1 @@
2834 @@ -0,0 +1,1 @@
2821 +second
2835 +second
2822
2836
2823 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2837 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2824 diff -r 29114dbae42b -r 95c24699272e second
2838 diff -r 29114dbae42b -r 95c24699272e second
2825 --- a/second Mon Jan 12 13:46:40 1970 +0000
2839 --- a/second Mon Jan 12 13:46:40 1970 +0000
2826 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2840 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2827 @@ -1,1 +0,0 @@
2841 @@ -1,1 +0,0 @@
2828 -second
2842 -second
2829 diff -r 29114dbae42b -r 95c24699272e third
2843 diff -r 29114dbae42b -r 95c24699272e third
2830 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2844 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2831 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2845 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2832 @@ -0,0 +1,1 @@
2846 @@ -0,0 +1,1 @@
2833 +third
2847 +third
2834
2848
2835 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2849 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2836 diff -r 29114dbae42b -r 95c24699272e fourth
2850 diff -r 29114dbae42b -r 95c24699272e fourth
2837 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2851 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2838 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2852 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2839 @@ -0,0 +1,1 @@
2853 @@ -0,0 +1,1 @@
2840 +second
2854 +second
2841
2855
2842 $ cd ..
2856 $ cd ..
2843
2857
2844
2858
2845 latesttag:
2859 latesttag:
2846
2860
2847 $ hg init latesttag
2861 $ hg init latesttag
2848 $ cd latesttag
2862 $ cd latesttag
2849
2863
2850 $ echo a > file
2864 $ echo a > file
2851 $ hg ci -Am a -d '0 0'
2865 $ hg ci -Am a -d '0 0'
2852 adding file
2866 adding file
2853
2867
2854 $ echo b >> file
2868 $ echo b >> file
2855 $ hg ci -m b -d '1 0'
2869 $ hg ci -m b -d '1 0'
2856
2870
2857 $ echo c >> head1
2871 $ echo c >> head1
2858 $ hg ci -Am h1c -d '2 0'
2872 $ hg ci -Am h1c -d '2 0'
2859 adding head1
2873 adding head1
2860
2874
2861 $ hg update -q 1
2875 $ hg update -q 1
2862 $ echo d >> head2
2876 $ echo d >> head2
2863 $ hg ci -Am h2d -d '3 0'
2877 $ hg ci -Am h2d -d '3 0'
2864 adding head2
2878 adding head2
2865 created new head
2879 created new head
2866
2880
2867 $ echo e >> head2
2881 $ echo e >> head2
2868 $ hg ci -m h2e -d '4 0'
2882 $ hg ci -m h2e -d '4 0'
2869
2883
2870 $ hg merge -q
2884 $ hg merge -q
2871 $ hg ci -m merge -d '5 -3600'
2885 $ hg ci -m merge -d '5 -3600'
2872
2886
2873 No tag set:
2887 No tag set:
2874
2888
2875 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2889 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2876 @ 5: null+5
2890 @ 5: null+5
2877 |\
2891 |\
2878 | o 4: null+4
2892 | o 4: null+4
2879 | |
2893 | |
2880 | o 3: null+3
2894 | o 3: null+3
2881 | |
2895 | |
2882 o | 2: null+3
2896 o | 2: null+3
2883 |/
2897 |/
2884 o 1: null+2
2898 o 1: null+2
2885 |
2899 |
2886 o 0: null+1
2900 o 0: null+1
2887
2901
2888
2902
2889 One common tag: longest path wins for {latesttagdistance}:
2903 One common tag: longest path wins for {latesttagdistance}:
2890
2904
2891 $ hg tag -r 1 -m t1 -d '6 0' t1
2905 $ hg tag -r 1 -m t1 -d '6 0' t1
2892 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2906 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2893 @ 6: t1+4
2907 @ 6: t1+4
2894 |
2908 |
2895 o 5: t1+3
2909 o 5: t1+3
2896 |\
2910 |\
2897 | o 4: t1+2
2911 | o 4: t1+2
2898 | |
2912 | |
2899 | o 3: t1+1
2913 | o 3: t1+1
2900 | |
2914 | |
2901 o | 2: t1+1
2915 o | 2: t1+1
2902 |/
2916 |/
2903 o 1: t1+0
2917 o 1: t1+0
2904 |
2918 |
2905 o 0: null+1
2919 o 0: null+1
2906
2920
2907
2921
2908 One ancestor tag: closest wins:
2922 One ancestor tag: closest wins:
2909
2923
2910 $ hg tag -r 2 -m t2 -d '7 0' t2
2924 $ hg tag -r 2 -m t2 -d '7 0' t2
2911 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2925 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2912 @ 7: t2+3
2926 @ 7: t2+3
2913 |
2927 |
2914 o 6: t2+2
2928 o 6: t2+2
2915 |
2929 |
2916 o 5: t2+1
2930 o 5: t2+1
2917 |\
2931 |\
2918 | o 4: t1+2
2932 | o 4: t1+2
2919 | |
2933 | |
2920 | o 3: t1+1
2934 | o 3: t1+1
2921 | |
2935 | |
2922 o | 2: t2+0
2936 o | 2: t2+0
2923 |/
2937 |/
2924 o 1: t1+0
2938 o 1: t1+0
2925 |
2939 |
2926 o 0: null+1
2940 o 0: null+1
2927
2941
2928
2942
2929 Two branch tags: more recent wins if same number of changes:
2943 Two branch tags: more recent wins if same number of changes:
2930
2944
2931 $ hg tag -r 3 -m t3 -d '8 0' t3
2945 $ hg tag -r 3 -m t3 -d '8 0' t3
2932 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2946 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2933 @ 8: t3+5
2947 @ 8: t3+5
2934 |
2948 |
2935 o 7: t3+4
2949 o 7: t3+4
2936 |
2950 |
2937 o 6: t3+3
2951 o 6: t3+3
2938 |
2952 |
2939 o 5: t3+2
2953 o 5: t3+2
2940 |\
2954 |\
2941 | o 4: t3+1
2955 | o 4: t3+1
2942 | |
2956 | |
2943 | o 3: t3+0
2957 | o 3: t3+0
2944 | |
2958 | |
2945 o | 2: t2+0
2959 o | 2: t2+0
2946 |/
2960 |/
2947 o 1: t1+0
2961 o 1: t1+0
2948 |
2962 |
2949 o 0: null+1
2963 o 0: null+1
2950
2964
2951
2965
2952 Two branch tags: fewest changes wins:
2966 Two branch tags: fewest changes wins:
2953
2967
2954 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
2968 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
2955 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2969 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2956 @ 9: t4+5,6
2970 @ 9: t4+5,6
2957 |
2971 |
2958 o 8: t4+4,5
2972 o 8: t4+4,5
2959 |
2973 |
2960 o 7: t4+3,4
2974 o 7: t4+3,4
2961 |
2975 |
2962 o 6: t4+2,3
2976 o 6: t4+2,3
2963 |
2977 |
2964 o 5: t4+1,2
2978 o 5: t4+1,2
2965 |\
2979 |\
2966 | o 4: t4+0,0
2980 | o 4: t4+0,0
2967 | |
2981 | |
2968 | o 3: t3+0,0
2982 | o 3: t3+0,0
2969 | |
2983 | |
2970 o | 2: t2+0,0
2984 o | 2: t2+0,0
2971 |/
2985 |/
2972 o 1: t1+0,0
2986 o 1: t1+0,0
2973 |
2987 |
2974 o 0: null+1,1
2988 o 0: null+1,1
2975
2989
2976
2990
2977 Merged tag overrides:
2991 Merged tag overrides:
2978
2992
2979 $ hg tag -r 5 -m t5 -d '9 0' t5
2993 $ hg tag -r 5 -m t5 -d '9 0' t5
2980 $ hg tag -r 3 -m at3 -d '10 0' at3
2994 $ hg tag -r 3 -m at3 -d '10 0' at3
2981 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2995 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2982 @ 11: t5+6
2996 @ 11: t5+6
2983 |
2997 |
2984 o 10: t5+5
2998 o 10: t5+5
2985 |
2999 |
2986 o 9: t5+4
3000 o 9: t5+4
2987 |
3001 |
2988 o 8: t5+3
3002 o 8: t5+3
2989 |
3003 |
2990 o 7: t5+2
3004 o 7: t5+2
2991 |
3005 |
2992 o 6: t5+1
3006 o 6: t5+1
2993 |
3007 |
2994 o 5: t5+0
3008 o 5: t5+0
2995 |\
3009 |\
2996 | o 4: t4+0
3010 | o 4: t4+0
2997 | |
3011 | |
2998 | o 3: at3:t3+0
3012 | o 3: at3:t3+0
2999 | |
3013 | |
3000 o | 2: t2+0
3014 o | 2: t2+0
3001 |/
3015 |/
3002 o 1: t1+0
3016 o 1: t1+0
3003 |
3017 |
3004 o 0: null+1
3018 o 0: null+1
3005
3019
3006
3020
3007 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3021 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3008 @ 11: t5+6,6
3022 @ 11: t5+6,6
3009 |
3023 |
3010 o 10: t5+5,5
3024 o 10: t5+5,5
3011 |
3025 |
3012 o 9: t5+4,4
3026 o 9: t5+4,4
3013 |
3027 |
3014 o 8: t5+3,3
3028 o 8: t5+3,3
3015 |
3029 |
3016 o 7: t5+2,2
3030 o 7: t5+2,2
3017 |
3031 |
3018 o 6: t5+1,1
3032 o 6: t5+1,1
3019 |
3033 |
3020 o 5: t5+0,0
3034 o 5: t5+0,0
3021 |\
3035 |\
3022 | o 4: t4+0,0
3036 | o 4: t4+0,0
3023 | |
3037 | |
3024 | o 3: at3+0,0 t3+0,0
3038 | o 3: at3+0,0 t3+0,0
3025 | |
3039 | |
3026 o | 2: t2+0,0
3040 o | 2: t2+0,0
3027 |/
3041 |/
3028 o 1: t1+0,0
3042 o 1: t1+0,0
3029 |
3043 |
3030 o 0: null+1,1
3044 o 0: null+1,1
3031
3045
3032
3046
3033 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3047 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3034 @ 11: t3, C: 9, D: 8
3048 @ 11: t3, C: 9, D: 8
3035 |
3049 |
3036 o 10: t3, C: 8, D: 7
3050 o 10: t3, C: 8, D: 7
3037 |
3051 |
3038 o 9: t3, C: 7, D: 6
3052 o 9: t3, C: 7, D: 6
3039 |
3053 |
3040 o 8: t3, C: 6, D: 5
3054 o 8: t3, C: 6, D: 5
3041 |
3055 |
3042 o 7: t3, C: 5, D: 4
3056 o 7: t3, C: 5, D: 4
3043 |
3057 |
3044 o 6: t3, C: 4, D: 3
3058 o 6: t3, C: 4, D: 3
3045 |
3059 |
3046 o 5: t3, C: 3, D: 2
3060 o 5: t3, C: 3, D: 2
3047 |\
3061 |\
3048 | o 4: t3, C: 1, D: 1
3062 | o 4: t3, C: 1, D: 1
3049 | |
3063 | |
3050 | o 3: t3, C: 0, D: 0
3064 | o 3: t3, C: 0, D: 0
3051 | |
3065 | |
3052 o | 2: t1, C: 1, D: 1
3066 o | 2: t1, C: 1, D: 1
3053 |/
3067 |/
3054 o 1: t1, C: 0, D: 0
3068 o 1: t1, C: 0, D: 0
3055 |
3069 |
3056 o 0: null, C: 1, D: 1
3070 o 0: null, C: 1, D: 1
3057
3071
3058
3072
3059 $ cd ..
3073 $ cd ..
3060
3074
3061
3075
3062 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3076 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3063 if it is a relative path
3077 if it is a relative path
3064
3078
3065 $ mkdir -p home/styles
3079 $ mkdir -p home/styles
3066
3080
3067 $ cat > home/styles/teststyle <<EOF
3081 $ cat > home/styles/teststyle <<EOF
3068 > changeset = 'test {rev}:{node|short}\n'
3082 > changeset = 'test {rev}:{node|short}\n'
3069 > EOF
3083 > EOF
3070
3084
3071 $ HOME=`pwd`/home; export HOME
3085 $ HOME=`pwd`/home; export HOME
3072
3086
3073 $ cat > latesttag/.hg/hgrc <<EOF
3087 $ cat > latesttag/.hg/hgrc <<EOF
3074 > [ui]
3088 > [ui]
3075 > style = ~/styles/teststyle
3089 > style = ~/styles/teststyle
3076 > EOF
3090 > EOF
3077
3091
3078 $ hg -R latesttag tip
3092 $ hg -R latesttag tip
3079 test 11:97e5943b523a
3093 test 11:97e5943b523a
3080
3094
3081 Test recursive showlist template (issue1989):
3095 Test recursive showlist template (issue1989):
3082
3096
3083 $ cat > style1989 <<EOF
3097 $ cat > style1989 <<EOF
3084 > changeset = '{file_mods}{manifest}{extras}'
3098 > changeset = '{file_mods}{manifest}{extras}'
3085 > file_mod = 'M|{author|person}\n'
3099 > file_mod = 'M|{author|person}\n'
3086 > manifest = '{rev},{author}\n'
3100 > manifest = '{rev},{author}\n'
3087 > extra = '{key}: {author}\n'
3101 > extra = '{key}: {author}\n'
3088 > EOF
3102 > EOF
3089
3103
3090 $ hg -R latesttag log -r tip --style=style1989
3104 $ hg -R latesttag log -r tip --style=style1989
3091 M|test
3105 M|test
3092 11,test
3106 11,test
3093 branch: test
3107 branch: test
3094
3108
3095 Test new-style inline templating:
3109 Test new-style inline templating:
3096
3110
3097 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3111 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3098 modified files: .hgtags
3112 modified files: .hgtags
3099
3113
3100
3114
3101 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3115 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3102 hg: parse error: keyword 'rev' is not iterable
3116 hg: parse error: keyword 'rev' is not iterable
3103 [255]
3117 [255]
3104 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3118 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3105 hg: parse error: None is not iterable
3119 hg: parse error: None is not iterable
3106 [255]
3120 [255]
3107
3121
3108 Test the sub function of templating for expansion:
3122 Test the sub function of templating for expansion:
3109
3123
3110 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3124 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3111 xx
3125 xx
3112
3126
3113 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3127 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3114 hg: parse error: sub got an invalid pattern: [
3128 hg: parse error: sub got an invalid pattern: [
3115 [255]
3129 [255]
3116 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3130 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3117 hg: parse error: sub got an invalid replacement: \1
3131 hg: parse error: sub got an invalid replacement: \1
3118 [255]
3132 [255]
3119
3133
3120 Test the strip function with chars specified:
3134 Test the strip function with chars specified:
3121
3135
3122 $ hg log -R latesttag --template '{desc}\n'
3136 $ hg log -R latesttag --template '{desc}\n'
3123 at3
3137 at3
3124 t5
3138 t5
3125 t4
3139 t4
3126 t3
3140 t3
3127 t2
3141 t2
3128 t1
3142 t1
3129 merge
3143 merge
3130 h2e
3144 h2e
3131 h2d
3145 h2d
3132 h1c
3146 h1c
3133 b
3147 b
3134 a
3148 a
3135
3149
3136 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3150 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3137 at3
3151 at3
3138 5
3152 5
3139 4
3153 4
3140 3
3154 3
3141 2
3155 2
3142 1
3156 1
3143 merg
3157 merg
3144 h2
3158 h2
3145 h2d
3159 h2d
3146 h1c
3160 h1c
3147 b
3161 b
3148 a
3162 a
3149
3163
3150 Test date format:
3164 Test date format:
3151
3165
3152 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3166 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3153 date: 70 01 01 10 +0000
3167 date: 70 01 01 10 +0000
3154 date: 70 01 01 09 +0000
3168 date: 70 01 01 09 +0000
3155 date: 70 01 01 04 +0000
3169 date: 70 01 01 04 +0000
3156 date: 70 01 01 08 +0000
3170 date: 70 01 01 08 +0000
3157 date: 70 01 01 07 +0000
3171 date: 70 01 01 07 +0000
3158 date: 70 01 01 06 +0000
3172 date: 70 01 01 06 +0000
3159 date: 70 01 01 05 +0100
3173 date: 70 01 01 05 +0100
3160 date: 70 01 01 04 +0000
3174 date: 70 01 01 04 +0000
3161 date: 70 01 01 03 +0000
3175 date: 70 01 01 03 +0000
3162 date: 70 01 01 02 +0000
3176 date: 70 01 01 02 +0000
3163 date: 70 01 01 01 +0000
3177 date: 70 01 01 01 +0000
3164 date: 70 01 01 00 +0000
3178 date: 70 01 01 00 +0000
3165
3179
3166 Test invalid date:
3180 Test invalid date:
3167
3181
3168 $ hg log -R latesttag -T '{date(rev)}\n'
3182 $ hg log -R latesttag -T '{date(rev)}\n'
3169 hg: parse error: date expects a date information
3183 hg: parse error: date expects a date information
3170 [255]
3184 [255]
3171
3185
3172 Test integer literal:
3186 Test integer literal:
3173
3187
3174 $ hg debugtemplate -v '{(0)}\n'
3188 $ hg debugtemplate -v '{(0)}\n'
3175 (template
3189 (template
3176 (group
3190 (group
3177 (integer '0'))
3191 (integer '0'))
3178 (string '\n'))
3192 (string '\n'))
3179 0
3193 0
3180 $ hg debugtemplate -v '{(123)}\n'
3194 $ hg debugtemplate -v '{(123)}\n'
3181 (template
3195 (template
3182 (group
3196 (group
3183 (integer '123'))
3197 (integer '123'))
3184 (string '\n'))
3198 (string '\n'))
3185 123
3199 123
3186 $ hg debugtemplate -v '{(-4)}\n'
3200 $ hg debugtemplate -v '{(-4)}\n'
3187 (template
3201 (template
3188 (group
3202 (group
3189 (negate
3203 (negate
3190 (integer '4')))
3204 (integer '4')))
3191 (string '\n'))
3205 (string '\n'))
3192 -4
3206 -4
3193 $ hg debugtemplate '{(-)}\n'
3207 $ hg debugtemplate '{(-)}\n'
3194 hg: parse error at 3: not a prefix: )
3208 hg: parse error at 3: not a prefix: )
3195 [255]
3209 [255]
3196 $ hg debugtemplate '{(-a)}\n'
3210 $ hg debugtemplate '{(-a)}\n'
3197 hg: parse error: negation needs an integer argument
3211 hg: parse error: negation needs an integer argument
3198 [255]
3212 [255]
3199
3213
3200 top-level integer literal is interpreted as symbol (i.e. variable name):
3214 top-level integer literal is interpreted as symbol (i.e. variable name):
3201
3215
3202 $ hg debugtemplate -D 1=one -v '{1}\n'
3216 $ hg debugtemplate -D 1=one -v '{1}\n'
3203 (template
3217 (template
3204 (integer '1')
3218 (integer '1')
3205 (string '\n'))
3219 (string '\n'))
3206 one
3220 one
3207 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3221 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3208 (template
3222 (template
3209 (func
3223 (func
3210 (symbol 'if')
3224 (symbol 'if')
3211 (list
3225 (list
3212 (string 't')
3226 (string 't')
3213 (template
3227 (template
3214 (integer '1'))))
3228 (integer '1'))))
3215 (string '\n'))
3229 (string '\n'))
3216 one
3230 one
3217 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3231 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3218 (template
3232 (template
3219 (|
3233 (|
3220 (integer '1')
3234 (integer '1')
3221 (symbol 'stringify'))
3235 (symbol 'stringify'))
3222 (string '\n'))
3236 (string '\n'))
3223 one
3237 one
3224
3238
3225 unless explicit symbol is expected:
3239 unless explicit symbol is expected:
3226
3240
3227 $ hg log -Ra -r0 -T '{desc|1}\n'
3241 $ hg log -Ra -r0 -T '{desc|1}\n'
3228 hg: parse error: expected a symbol, got 'integer'
3242 hg: parse error: expected a symbol, got 'integer'
3229 [255]
3243 [255]
3230 $ hg log -Ra -r0 -T '{1()}\n'
3244 $ hg log -Ra -r0 -T '{1()}\n'
3231 hg: parse error: expected a symbol, got 'integer'
3245 hg: parse error: expected a symbol, got 'integer'
3232 [255]
3246 [255]
3233
3247
3234 Test string literal:
3248 Test string literal:
3235
3249
3236 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3250 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3237 (template
3251 (template
3238 (string 'string with no template fragment')
3252 (string 'string with no template fragment')
3239 (string '\n'))
3253 (string '\n'))
3240 string with no template fragment
3254 string with no template fragment
3241 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3255 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3242 (template
3256 (template
3243 (template
3257 (template
3244 (string 'template: ')
3258 (string 'template: ')
3245 (symbol 'rev'))
3259 (symbol 'rev'))
3246 (string '\n'))
3260 (string '\n'))
3247 template: 0
3261 template: 0
3248 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3262 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3249 (template
3263 (template
3250 (string 'rawstring: {rev}')
3264 (string 'rawstring: {rev}')
3251 (string '\n'))
3265 (string '\n'))
3252 rawstring: {rev}
3266 rawstring: {rev}
3253 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3267 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3254 (template
3268 (template
3255 (%
3269 (%
3256 (symbol 'files')
3270 (symbol 'files')
3257 (string 'rawstring: {file}'))
3271 (string 'rawstring: {file}'))
3258 (string '\n'))
3272 (string '\n'))
3259 rawstring: {file}
3273 rawstring: {file}
3260
3274
3261 Test string escaping:
3275 Test string escaping:
3262
3276
3263 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3277 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3264 >
3278 >
3265 <>\n<[>
3279 <>\n<[>
3266 <>\n<]>
3280 <>\n<]>
3267 <>\n<
3281 <>\n<
3268
3282
3269 $ hg log -R latesttag -r 0 \
3283 $ hg log -R latesttag -r 0 \
3270 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3284 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3271 >
3285 >
3272 <>\n<[>
3286 <>\n<[>
3273 <>\n<]>
3287 <>\n<]>
3274 <>\n<
3288 <>\n<
3275
3289
3276 $ hg log -R latesttag -r 0 -T esc \
3290 $ hg log -R latesttag -r 0 -T esc \
3277 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3291 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3278 >
3292 >
3279 <>\n<[>
3293 <>\n<[>
3280 <>\n<]>
3294 <>\n<]>
3281 <>\n<
3295 <>\n<
3282
3296
3283 $ cat <<'EOF' > esctmpl
3297 $ cat <<'EOF' > esctmpl
3284 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3298 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3285 > EOF
3299 > EOF
3286 $ hg log -R latesttag -r 0 --style ./esctmpl
3300 $ hg log -R latesttag -r 0 --style ./esctmpl
3287 >
3301 >
3288 <>\n<[>
3302 <>\n<[>
3289 <>\n<]>
3303 <>\n<]>
3290 <>\n<
3304 <>\n<
3291
3305
3292 Test string escaping of quotes:
3306 Test string escaping of quotes:
3293
3307
3294 $ hg log -Ra -r0 -T '{"\""}\n'
3308 $ hg log -Ra -r0 -T '{"\""}\n'
3295 "
3309 "
3296 $ hg log -Ra -r0 -T '{"\\\""}\n'
3310 $ hg log -Ra -r0 -T '{"\\\""}\n'
3297 \"
3311 \"
3298 $ hg log -Ra -r0 -T '{r"\""}\n'
3312 $ hg log -Ra -r0 -T '{r"\""}\n'
3299 \"
3313 \"
3300 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3314 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3301 \\\"
3315 \\\"
3302
3316
3303
3317
3304 $ hg log -Ra -r0 -T '{"\""}\n'
3318 $ hg log -Ra -r0 -T '{"\""}\n'
3305 "
3319 "
3306 $ hg log -Ra -r0 -T '{"\\\""}\n'
3320 $ hg log -Ra -r0 -T '{"\\\""}\n'
3307 \"
3321 \"
3308 $ hg log -Ra -r0 -T '{r"\""}\n'
3322 $ hg log -Ra -r0 -T '{r"\""}\n'
3309 \"
3323 \"
3310 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3324 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3311 \\\"
3325 \\\"
3312
3326
3313 Test exception in quoted template. single backslash before quotation mark is
3327 Test exception in quoted template. single backslash before quotation mark is
3314 stripped before parsing:
3328 stripped before parsing:
3315
3329
3316 $ cat <<'EOF' > escquotetmpl
3330 $ cat <<'EOF' > escquotetmpl
3317 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3331 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3318 > EOF
3332 > EOF
3319 $ cd latesttag
3333 $ cd latesttag
3320 $ hg log -r 2 --style ../escquotetmpl
3334 $ hg log -r 2 --style ../escquotetmpl
3321 " \" \" \\" head1
3335 " \" \" \\" head1
3322
3336
3323 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3337 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3324 valid
3338 valid
3325 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3339 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3326 valid
3340 valid
3327
3341
3328 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3342 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3329 _evalifliteral() templates (issue4733):
3343 _evalifliteral() templates (issue4733):
3330
3344
3331 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3345 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3332 "2
3346 "2
3333 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3347 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3334 "2
3348 "2
3335 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3349 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3336 "2
3350 "2
3337
3351
3338 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3352 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3339 \"
3353 \"
3340 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3354 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3341 \"
3355 \"
3342 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3356 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3343 \"
3357 \"
3344
3358
3345 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3359 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3346 \\\"
3360 \\\"
3347 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3361 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3348 \\\"
3362 \\\"
3349 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3363 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3350 \\\"
3364 \\\"
3351
3365
3352 escaped single quotes and errors:
3366 escaped single quotes and errors:
3353
3367
3354 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3368 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3355 foo
3369 foo
3356 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3370 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3357 foo
3371 foo
3358 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3372 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3359 hg: parse error at 21: unterminated string
3373 hg: parse error at 21: unterminated string
3360 [255]
3374 [255]
3361 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3375 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3362 hg: parse error: trailing \ in string
3376 hg: parse error: trailing \ in string
3363 [255]
3377 [255]
3364 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3378 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3365 hg: parse error: trailing \ in string
3379 hg: parse error: trailing \ in string
3366 [255]
3380 [255]
3367
3381
3368 $ cd ..
3382 $ cd ..
3369
3383
3370 Test leading backslashes:
3384 Test leading backslashes:
3371
3385
3372 $ cd latesttag
3386 $ cd latesttag
3373 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3387 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3374 {rev} {file}
3388 {rev} {file}
3375 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3389 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3376 \2 \head1
3390 \2 \head1
3377 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3391 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3378 \{rev} \{file}
3392 \{rev} \{file}
3379 $ cd ..
3393 $ cd ..
3380
3394
3381 Test leading backslashes in "if" expression (issue4714):
3395 Test leading backslashes in "if" expression (issue4714):
3382
3396
3383 $ cd latesttag
3397 $ cd latesttag
3384 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3398 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3385 {rev} \{rev}
3399 {rev} \{rev}
3386 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3400 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3387 \2 \\{rev}
3401 \2 \\{rev}
3388 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3402 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3389 \{rev} \\\{rev}
3403 \{rev} \\\{rev}
3390 $ cd ..
3404 $ cd ..
3391
3405
3392 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3406 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3393
3407
3394 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3408 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3395 \x6e
3409 \x6e
3396 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3410 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3397 \x5c\x786e
3411 \x5c\x786e
3398 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3412 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3399 \x6e
3413 \x6e
3400 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3414 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3401 \x5c\x786e
3415 \x5c\x786e
3402
3416
3403 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3417 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3404 \x6e
3418 \x6e
3405 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3419 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3406 \x5c\x786e
3420 \x5c\x786e
3407 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3421 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3408 \x6e
3422 \x6e
3409 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3423 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3410 \x5c\x786e
3424 \x5c\x786e
3411
3425
3412 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3426 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3413 fourth
3427 fourth
3414 second
3428 second
3415 third
3429 third
3416 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3430 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3417 fourth\nsecond\nthird
3431 fourth\nsecond\nthird
3418
3432
3419 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3433 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3420 <p>
3434 <p>
3421 1st
3435 1st
3422 </p>
3436 </p>
3423 <p>
3437 <p>
3424 2nd
3438 2nd
3425 </p>
3439 </p>
3426 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3440 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3427 <p>
3441 <p>
3428 1st\n\n2nd
3442 1st\n\n2nd
3429 </p>
3443 </p>
3430 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3444 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3431 1st
3445 1st
3432
3446
3433 2nd
3447 2nd
3434
3448
3435 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3449 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3436 o perso
3450 o perso
3437 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3451 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3438 no person
3452 no person
3439 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3453 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3440 o perso
3454 o perso
3441 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3455 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3442 no perso
3456 no perso
3443
3457
3444 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3458 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3445 -o perso-
3459 -o perso-
3446 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3460 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3447 no person
3461 no person
3448 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3462 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3449 \x2do perso\x2d
3463 \x2do perso\x2d
3450 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3464 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3451 -o perso-
3465 -o perso-
3452 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3466 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3453 \x2do perso\x6e
3467 \x2do perso\x6e
3454
3468
3455 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3469 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3456 fourth
3470 fourth
3457 second
3471 second
3458 third
3472 third
3459
3473
3460 Test string escaping in nested expression:
3474 Test string escaping in nested expression:
3461
3475
3462 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3476 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3463 fourth\x6esecond\x6ethird
3477 fourth\x6esecond\x6ethird
3464 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3478 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3465 fourth\x6esecond\x6ethird
3479 fourth\x6esecond\x6ethird
3466
3480
3467 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3481 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3468 fourth\x6esecond\x6ethird
3482 fourth\x6esecond\x6ethird
3469 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3483 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3470 fourth\x5c\x786esecond\x5c\x786ethird
3484 fourth\x5c\x786esecond\x5c\x786ethird
3471
3485
3472 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3486 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3473 3:\x6eo user, \x6eo domai\x6e
3487 3:\x6eo user, \x6eo domai\x6e
3474 4:\x5c\x786eew bra\x5c\x786ech
3488 4:\x5c\x786eew bra\x5c\x786ech
3475
3489
3476 Test quotes in nested expression are evaluated just like a $(command)
3490 Test quotes in nested expression are evaluated just like a $(command)
3477 substitution in POSIX shells:
3491 substitution in POSIX shells:
3478
3492
3479 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3493 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3480 8:95c24699272e
3494 8:95c24699272e
3481 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3495 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3482 {8} "95c24699272e"
3496 {8} "95c24699272e"
3483
3497
3484 Test recursive evaluation:
3498 Test recursive evaluation:
3485
3499
3486 $ hg init r
3500 $ hg init r
3487 $ cd r
3501 $ cd r
3488 $ echo a > a
3502 $ echo a > a
3489 $ hg ci -Am '{rev}'
3503 $ hg ci -Am '{rev}'
3490 adding a
3504 adding a
3491 $ hg log -r 0 --template '{if(rev, desc)}\n'
3505 $ hg log -r 0 --template '{if(rev, desc)}\n'
3492 {rev}
3506 {rev}
3493 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3507 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3494 test 0
3508 test 0
3495
3509
3496 $ hg branch -q 'text.{rev}'
3510 $ hg branch -q 'text.{rev}'
3497 $ echo aa >> aa
3511 $ echo aa >> aa
3498 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3512 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3499
3513
3500 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3514 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3501 {node|short}desc to
3515 {node|short}desc to
3502 text.{rev}be wrapped
3516 text.{rev}be wrapped
3503 text.{rev}desc to be
3517 text.{rev}desc to be
3504 text.{rev}wrapped (no-eol)
3518 text.{rev}wrapped (no-eol)
3505 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3519 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3506 bcc7ff960b8e:desc to
3520 bcc7ff960b8e:desc to
3507 text.1:be wrapped
3521 text.1:be wrapped
3508 text.1:desc to be
3522 text.1:desc to be
3509 text.1:wrapped (no-eol)
3523 text.1:wrapped (no-eol)
3510 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3524 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3511 hg: parse error: fill expects an integer width
3525 hg: parse error: fill expects an integer width
3512 [255]
3526 [255]
3513
3527
3514 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3528 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3515 bcc7ff960b8e:desc to be
3529 bcc7ff960b8e:desc to be
3516 termwidth.1:wrapped desc
3530 termwidth.1:wrapped desc
3517 termwidth.1:to be wrapped (no-eol)
3531 termwidth.1:to be wrapped (no-eol)
3518
3532
3519 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3533 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3520 {node|short} (no-eol)
3534 {node|short} (no-eol)
3521 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3535 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3522 bcc-ff---b-e (no-eol)
3536 bcc-ff---b-e (no-eol)
3523
3537
3524 $ cat >> .hg/hgrc <<EOF
3538 $ cat >> .hg/hgrc <<EOF
3525 > [extensions]
3539 > [extensions]
3526 > color=
3540 > color=
3527 > [color]
3541 > [color]
3528 > mode=ansi
3542 > mode=ansi
3529 > text.{rev} = red
3543 > text.{rev} = red
3530 > text.1 = green
3544 > text.1 = green
3531 > EOF
3545 > EOF
3532 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3546 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3533 \x1b[0;31mtext\x1b[0m (esc)
3547 \x1b[0;31mtext\x1b[0m (esc)
3534 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3548 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3535 \x1b[0;32mtext\x1b[0m (esc)
3549 \x1b[0;32mtext\x1b[0m (esc)
3536
3550
3537 color effect can be specified without quoting:
3551 color effect can be specified without quoting:
3538
3552
3539 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3553 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3540 \x1b[0;31mtext\x1b[0m (esc)
3554 \x1b[0;31mtext\x1b[0m (esc)
3541
3555
3542 color effects can be nested (issue5413)
3556 color effects can be nested (issue5413)
3543
3557
3544 $ hg debugtemplate --color=always \
3558 $ hg debugtemplate --color=always \
3545 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3559 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3546 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3560 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3547
3561
3548 pad() should interact well with color codes (issue5416)
3562 pad() should interact well with color codes (issue5416)
3549
3563
3550 $ hg debugtemplate --color=always \
3564 $ hg debugtemplate --color=always \
3551 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3565 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3552 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3566 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3553
3567
3554 label should be no-op if color is disabled:
3568 label should be no-op if color is disabled:
3555
3569
3556 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3570 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3557 text
3571 text
3558 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3572 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3559 text
3573 text
3560
3574
3561 Test branches inside if statement:
3575 Test branches inside if statement:
3562
3576
3563 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3577 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3564 no
3578 no
3565
3579
3566 Test dict constructor:
3580 Test dict constructor:
3567
3581
3568 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3582 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3569 y=f7769ec2ab97 x=0
3583 y=f7769ec2ab97 x=0
3570 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3584 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3571 x=0
3585 x=0
3572 y=f7769ec2ab97
3586 y=f7769ec2ab97
3573 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3587 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3574 {"x": 0, "y": "f7769ec2ab97"}
3588 {"x": 0, "y": "f7769ec2ab97"}
3575 $ hg log -r 0 -T '{dict()|json}\n'
3589 $ hg log -r 0 -T '{dict()|json}\n'
3576 {}
3590 {}
3577
3591
3578 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3592 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3579 rev=0 node=f7769ec2ab97
3593 rev=0 node=f7769ec2ab97
3580 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3594 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3581 rev=0 node=f7769ec2ab97
3595 rev=0 node=f7769ec2ab97
3582
3596
3583 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3597 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3584 hg: parse error: duplicated dict key 'rev' inferred
3598 hg: parse error: duplicated dict key 'rev' inferred
3585 [255]
3599 [255]
3586 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3600 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3587 hg: parse error: duplicated dict key 'node' inferred
3601 hg: parse error: duplicated dict key 'node' inferred
3588 [255]
3602 [255]
3589 $ hg log -r 0 -T '{dict(1 + 2)}'
3603 $ hg log -r 0 -T '{dict(1 + 2)}'
3590 hg: parse error: dict key cannot be inferred
3604 hg: parse error: dict key cannot be inferred
3591 [255]
3605 [255]
3592
3606
3593 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3607 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3594 hg: parse error: dict got multiple values for keyword argument 'x'
3608 hg: parse error: dict got multiple values for keyword argument 'x'
3595 [255]
3609 [255]
3596
3610
3597 Test get function:
3611 Test get function:
3598
3612
3599 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3613 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3600 default
3614 default
3601 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3615 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3602 default
3616 default
3603 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3617 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3604 hg: parse error: get() expects a dict as first argument
3618 hg: parse error: get() expects a dict as first argument
3605 [255]
3619 [255]
3606
3620
3607 Test json filter applied to hybrid object:
3621 Test json filter applied to hybrid object:
3608
3622
3609 $ hg log -r0 -T '{files|json}\n'
3623 $ hg log -r0 -T '{files|json}\n'
3610 ["a"]
3624 ["a"]
3611 $ hg log -r0 -T '{extras|json}\n'
3625 $ hg log -r0 -T '{extras|json}\n'
3612 {"branch": "default"}
3626 {"branch": "default"}
3613
3627
3614 Test localdate(date, tz) function:
3628 Test localdate(date, tz) function:
3615
3629
3616 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3630 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3617 1970-01-01 09:00 +0900
3631 1970-01-01 09:00 +0900
3618 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3632 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3619 1970-01-01 00:00 +0000
3633 1970-01-01 00:00 +0000
3620 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3634 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3621 hg: parse error: localdate expects a timezone
3635 hg: parse error: localdate expects a timezone
3622 [255]
3636 [255]
3623 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3637 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3624 1970-01-01 02:00 +0200
3638 1970-01-01 02:00 +0200
3625 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3639 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3626 1970-01-01 00:00 +0000
3640 1970-01-01 00:00 +0000
3627 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3641 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3628 1970-01-01 00:00 +0000
3642 1970-01-01 00:00 +0000
3629 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3643 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3630 hg: parse error: localdate expects a timezone
3644 hg: parse error: localdate expects a timezone
3631 [255]
3645 [255]
3632 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3646 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3633 hg: parse error: localdate expects a timezone
3647 hg: parse error: localdate expects a timezone
3634 [255]
3648 [255]
3635
3649
3636 Test shortest(node) function:
3650 Test shortest(node) function:
3637
3651
3638 $ echo b > b
3652 $ echo b > b
3639 $ hg ci -qAm b
3653 $ hg ci -qAm b
3640 $ hg log --template '{shortest(node)}\n'
3654 $ hg log --template '{shortest(node)}\n'
3641 e777
3655 e777
3642 bcc7
3656 bcc7
3643 f776
3657 f776
3644 $ hg log --template '{shortest(node, 10)}\n'
3658 $ hg log --template '{shortest(node, 10)}\n'
3645 e777603221
3659 e777603221
3646 bcc7ff960b
3660 bcc7ff960b
3647 f7769ec2ab
3661 f7769ec2ab
3648 $ hg log --template '{node|shortest}\n' -l1
3662 $ hg log --template '{node|shortest}\n' -l1
3649 e777
3663 e777
3650
3664
3651 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3665 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3652 f7769ec2ab
3666 f7769ec2ab
3653 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3667 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3654 hg: parse error: shortest() expects an integer minlength
3668 hg: parse error: shortest() expects an integer minlength
3655 [255]
3669 [255]
3656
3670
3657 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3671 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3658 ffff
3672 ffff
3659
3673
3660 $ cd ..
3674 $ cd ..
3661
3675
3662 Test shortest(node) with the repo having short hash collision:
3676 Test shortest(node) with the repo having short hash collision:
3663
3677
3664 $ hg init hashcollision
3678 $ hg init hashcollision
3665 $ cd hashcollision
3679 $ cd hashcollision
3666 $ cat <<EOF >> .hg/hgrc
3680 $ cat <<EOF >> .hg/hgrc
3667 > [experimental]
3681 > [experimental]
3668 > stabilization = createmarkers
3682 > stabilization = createmarkers
3669 > EOF
3683 > EOF
3670 $ echo 0 > a
3684 $ echo 0 > a
3671 $ hg ci -qAm 0
3685 $ hg ci -qAm 0
3672 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3686 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3673 > hg up -q 0
3687 > hg up -q 0
3674 > echo $i > a
3688 > echo $i > a
3675 > hg ci -qm $i
3689 > hg ci -qm $i
3676 > done
3690 > done
3677 $ hg up -q null
3691 $ hg up -q null
3678 $ hg log -r0: -T '{rev}:{node}\n'
3692 $ hg log -r0: -T '{rev}:{node}\n'
3679 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3693 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3680 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3694 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3681 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3695 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3682 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3696 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3683 4:10776689e627b465361ad5c296a20a487e153ca4
3697 4:10776689e627b465361ad5c296a20a487e153ca4
3684 5:a00be79088084cb3aff086ab799f8790e01a976b
3698 5:a00be79088084cb3aff086ab799f8790e01a976b
3685 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3699 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3686 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3700 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3687 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3701 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3688 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3702 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3689 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3703 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3690 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3704 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3691 obsoleted 1 changesets
3705 obsoleted 1 changesets
3692 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3706 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3693 obsoleted 1 changesets
3707 obsoleted 1 changesets
3694 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3708 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3695 obsoleted 1 changesets
3709 obsoleted 1 changesets
3696
3710
3697 nodes starting with '11' (we don't have the revision number '11' though)
3711 nodes starting with '11' (we don't have the revision number '11' though)
3698
3712
3699 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3713 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3700 1:1142
3714 1:1142
3701 2:1140
3715 2:1140
3702 3:11d
3716 3:11d
3703
3717
3704 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3718 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3705
3719
3706 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3720 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3707 6:a0b
3721 6:a0b
3708 7:a04
3722 7:a04
3709
3723
3710 node '10' conflicts with the revision number '10' even if it is hidden
3724 node '10' conflicts with the revision number '10' even if it is hidden
3711 (we could exclude hidden revision numbers, but currently we don't)
3725 (we could exclude hidden revision numbers, but currently we don't)
3712
3726
3713 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3727 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3714 4:107
3728 4:107
3715 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3729 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3716 4:107
3730 4:107
3717
3731
3718 node 'c562' should be unique if the other 'c562' nodes are hidden
3732 node 'c562' should be unique if the other 'c562' nodes are hidden
3719 (but we don't try the slow path to filter out hidden nodes for now)
3733 (but we don't try the slow path to filter out hidden nodes for now)
3720
3734
3721 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3735 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3722 8:c5625
3736 8:c5625
3723 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3737 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3724 8:c5625
3738 8:c5625
3725 9:c5623
3739 9:c5623
3726 10:c562d
3740 10:c562d
3727
3741
3728 $ cd ..
3742 $ cd ..
3729
3743
3730 Test pad function
3744 Test pad function
3731
3745
3732 $ cd r
3746 $ cd r
3733
3747
3734 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3748 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3735 2 test
3749 2 test
3736 1 {node|short}
3750 1 {node|short}
3737 0 test
3751 0 test
3738
3752
3739 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3753 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3740 2 test
3754 2 test
3741 1 {node|short}
3755 1 {node|short}
3742 0 test
3756 0 test
3743
3757
3744 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3758 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3745 2------------------- test
3759 2------------------- test
3746 1------------------- {node|short}
3760 1------------------- {node|short}
3747 0------------------- test
3761 0------------------- test
3748
3762
3749 Test template string in pad function
3763 Test template string in pad function
3750
3764
3751 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3765 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3752 {0} test
3766 {0} test
3753
3767
3754 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3768 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3755 \{rev} test
3769 \{rev} test
3756
3770
3757 Test width argument passed to pad function
3771 Test width argument passed to pad function
3758
3772
3759 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3773 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3760 0 test
3774 0 test
3761 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3775 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3762 hg: parse error: pad() expects an integer width
3776 hg: parse error: pad() expects an integer width
3763 [255]
3777 [255]
3764
3778
3765 Test invalid fillchar passed to pad function
3779 Test invalid fillchar passed to pad function
3766
3780
3767 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3781 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3768 hg: parse error: pad() expects a single fill character
3782 hg: parse error: pad() expects a single fill character
3769 [255]
3783 [255]
3770 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3784 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3771 hg: parse error: pad() expects a single fill character
3785 hg: parse error: pad() expects a single fill character
3772 [255]
3786 [255]
3773
3787
3774 Test boolean argument passed to pad function
3788 Test boolean argument passed to pad function
3775
3789
3776 no crash
3790 no crash
3777
3791
3778 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3792 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3779 ---------0
3793 ---------0
3780
3794
3781 string/literal
3795 string/literal
3782
3796
3783 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3797 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3784 ---------0
3798 ---------0
3785 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3799 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3786 0---------
3800 0---------
3787 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3801 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3788 0---------
3802 0---------
3789
3803
3790 unknown keyword is evaluated to ''
3804 unknown keyword is evaluated to ''
3791
3805
3792 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3806 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3793 0---------
3807 0---------
3794
3808
3795 Test separate function
3809 Test separate function
3796
3810
3797 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3811 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3798 a-b-c
3812 a-b-c
3799 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3813 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3800 0:f7769ec2ab97 test default
3814 0:f7769ec2ab97 test default
3801 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3815 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3802 a \x1b[0;31mb\x1b[0m c d (esc)
3816 a \x1b[0;31mb\x1b[0m c d (esc)
3803
3817
3804 Test boolean expression/literal passed to if function
3818 Test boolean expression/literal passed to if function
3805
3819
3806 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3820 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3807 rev 0 is True
3821 rev 0 is True
3808 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3822 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3809 literal 0 is True as well
3823 literal 0 is True as well
3810 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3824 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3811 empty string is False
3825 empty string is False
3812 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3826 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3813 empty list is False
3827 empty list is False
3814 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3828 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3815 true is True
3829 true is True
3816 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3830 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3817 false is False
3831 false is False
3818 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3832 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3819 non-empty string is True
3833 non-empty string is True
3820
3834
3821 Test ifcontains function
3835 Test ifcontains function
3822
3836
3823 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3837 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3824 2 is in the string
3838 2 is in the string
3825 1 is not
3839 1 is not
3826 0 is in the string
3840 0 is in the string
3827
3841
3828 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3842 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3829 2 is in the string
3843 2 is in the string
3830 1 is not
3844 1 is not
3831 0 is in the string
3845 0 is in the string
3832
3846
3833 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3847 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3834 2 did not add a
3848 2 did not add a
3835 1 did not add a
3849 1 did not add a
3836 0 added a
3850 0 added a
3837
3851
3838 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3852 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3839 2 is parent of 1
3853 2 is parent of 1
3840 1
3854 1
3841 0
3855 0
3842
3856
3843 Test revset function
3857 Test revset function
3844
3858
3845 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3859 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3846 2 current rev
3860 2 current rev
3847 1 not current rev
3861 1 not current rev
3848 0 not current rev
3862 0 not current rev
3849
3863
3850 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3864 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3851 2 match rev
3865 2 match rev
3852 1 match rev
3866 1 match rev
3853 0 not match rev
3867 0 not match rev
3854
3868
3855 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3869 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3856 2 Parents: 1
3870 2 Parents: 1
3857 1 Parents: 0
3871 1 Parents: 0
3858 0 Parents:
3872 0 Parents:
3859
3873
3860 $ cat >> .hg/hgrc <<EOF
3874 $ cat >> .hg/hgrc <<EOF
3861 > [revsetalias]
3875 > [revsetalias]
3862 > myparents(\$1) = parents(\$1)
3876 > myparents(\$1) = parents(\$1)
3863 > EOF
3877 > EOF
3864 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3878 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3865 2 Parents: 1
3879 2 Parents: 1
3866 1 Parents: 0
3880 1 Parents: 0
3867 0 Parents:
3881 0 Parents:
3868
3882
3869 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3883 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3870 Rev: 2
3884 Rev: 2
3871 Ancestor: 0
3885 Ancestor: 0
3872 Ancestor: 1
3886 Ancestor: 1
3873 Ancestor: 2
3887 Ancestor: 2
3874
3888
3875 Rev: 1
3889 Rev: 1
3876 Ancestor: 0
3890 Ancestor: 0
3877 Ancestor: 1
3891 Ancestor: 1
3878
3892
3879 Rev: 0
3893 Rev: 0
3880 Ancestor: 0
3894 Ancestor: 0
3881
3895
3882 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3896 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3883 2
3897 2
3884
3898
3885 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3899 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3886 2
3900 2
3887
3901
3888 a list template is evaluated for each item of revset/parents
3902 a list template is evaluated for each item of revset/parents
3889
3903
3890 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3904 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3891 2 p: 1:bcc7ff960b8e
3905 2 p: 1:bcc7ff960b8e
3892 1 p: 0:f7769ec2ab97
3906 1 p: 0:f7769ec2ab97
3893 0 p:
3907 0 p:
3894
3908
3895 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3909 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3896 2 p: 1:bcc7ff960b8e -1:000000000000
3910 2 p: 1:bcc7ff960b8e -1:000000000000
3897 1 p: 0:f7769ec2ab97 -1:000000000000
3911 1 p: 0:f7769ec2ab97 -1:000000000000
3898 0 p: -1:000000000000 -1:000000000000
3912 0 p: -1:000000000000 -1:000000000000
3899
3913
3900 therefore, 'revcache' should be recreated for each rev
3914 therefore, 'revcache' should be recreated for each rev
3901
3915
3902 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3916 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3903 2 aa b
3917 2 aa b
3904 p
3918 p
3905 1
3919 1
3906 p a
3920 p a
3907 0 a
3921 0 a
3908 p
3922 p
3909
3923
3910 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3924 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3911 2 aa b
3925 2 aa b
3912 p
3926 p
3913 1
3927 1
3914 p a
3928 p a
3915 0 a
3929 0 a
3916 p
3930 p
3917
3931
3918 a revset item must be evaluated as an integer revision, not an offset from tip
3932 a revset item must be evaluated as an integer revision, not an offset from tip
3919
3933
3920 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3934 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3921 -1:000000000000
3935 -1:000000000000
3922 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3936 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3923 -1:000000000000
3937 -1:000000000000
3924
3938
3925 join() should pick '{rev}' from revset items:
3939 join() should pick '{rev}' from revset items:
3926
3940
3927 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
3941 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
3928 4, 5
3942 4, 5
3929
3943
3930 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
3944 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
3931 default. join() should agree with the default formatting:
3945 default. join() should agree with the default formatting:
3932
3946
3933 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
3947 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
3934 5:13207e5a10d9, 4:bbe44766e73d
3948 5:13207e5a10d9, 4:bbe44766e73d
3935
3949
3936 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
3950 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
3937 5:13207e5a10d9fd28ec424934298e176197f2c67f,
3951 5:13207e5a10d9fd28ec424934298e176197f2c67f,
3938 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
3952 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
3939
3953
3940 Test files function
3954 Test files function
3941
3955
3942 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
3956 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
3943 2
3957 2
3944 a
3958 a
3945 aa
3959 aa
3946 b
3960 b
3947 1
3961 1
3948 a
3962 a
3949 0
3963 0
3950 a
3964 a
3951
3965
3952 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
3966 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
3953 2
3967 2
3954 aa
3968 aa
3955 1
3969 1
3956
3970
3957 0
3971 0
3958
3972
3959
3973
3960 Test relpath function
3974 Test relpath function
3961
3975
3962 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
3976 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
3963 a
3977 a
3964 $ cd ..
3978 $ cd ..
3965 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
3979 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
3966 r/a
3980 r/a
3967 $ cd r
3981 $ cd r
3968
3982
3969 Test active bookmark templating
3983 Test active bookmark templating
3970
3984
3971 $ hg book foo
3985 $ hg book foo
3972 $ hg book bar
3986 $ hg book bar
3973 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3987 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3974 2 bar* foo
3988 2 bar* foo
3975 1
3989 1
3976 0
3990 0
3977 $ hg log --template "{rev} {activebookmark}\n"
3991 $ hg log --template "{rev} {activebookmark}\n"
3978 2 bar
3992 2 bar
3979 1
3993 1
3980 0
3994 0
3981 $ hg bookmarks --inactive bar
3995 $ hg bookmarks --inactive bar
3982 $ hg log --template "{rev} {activebookmark}\n"
3996 $ hg log --template "{rev} {activebookmark}\n"
3983 2
3997 2
3984 1
3998 1
3985 0
3999 0
3986 $ hg book -r1 baz
4000 $ hg book -r1 baz
3987 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4001 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3988 2 bar foo
4002 2 bar foo
3989 1 baz
4003 1 baz
3990 0
4004 0
3991 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4005 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3992 2 t
4006 2 t
3993 1 f
4007 1 f
3994 0 f
4008 0 f
3995
4009
3996 Test namespaces dict
4010 Test namespaces dict
3997
4011
3998 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4012 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
3999 2
4013 2
4000 bookmarks color=bookmark builtin=True
4014 bookmarks color=bookmark builtin=True
4001 bar,foo
4015 bar,foo
4002 tags color=tag builtin=True
4016 tags color=tag builtin=True
4003 tip
4017 tip
4004 branches color=branch builtin=True
4018 branches color=branch builtin=True
4005 text.{rev}
4019 text.{rev}
4006 revnames color=revname builtin=False
4020 revnames color=revname builtin=False
4007 r2
4021 r2
4008
4022
4009 1
4023 1
4010 bookmarks color=bookmark builtin=True
4024 bookmarks color=bookmark builtin=True
4011 baz
4025 baz
4012 tags color=tag builtin=True
4026 tags color=tag builtin=True
4013
4027
4014 branches color=branch builtin=True
4028 branches color=branch builtin=True
4015 text.{rev}
4029 text.{rev}
4016 revnames color=revname builtin=False
4030 revnames color=revname builtin=False
4017 r1
4031 r1
4018
4032
4019 0
4033 0
4020 bookmarks color=bookmark builtin=True
4034 bookmarks color=bookmark builtin=True
4021
4035
4022 tags color=tag builtin=True
4036 tags color=tag builtin=True
4023
4037
4024 branches color=branch builtin=True
4038 branches color=branch builtin=True
4025 default
4039 default
4026 revnames color=revname builtin=False
4040 revnames color=revname builtin=False
4027 r0
4041 r0
4028
4042
4029 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4043 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4030 bookmarks: bar foo
4044 bookmarks: bar foo
4031 tags: tip
4045 tags: tip
4032 branches: text.{rev}
4046 branches: text.{rev}
4033 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4047 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4034 bookmarks:
4048 bookmarks:
4035 bar
4049 bar
4036 foo
4050 foo
4037 tags:
4051 tags:
4038 tip
4052 tip
4039 branches:
4053 branches:
4040 text.{rev}
4054 text.{rev}
4041 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4055 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4042 bar
4056 bar
4043 foo
4057 foo
4044
4058
4045 Test stringify on sub expressions
4059 Test stringify on sub expressions
4046
4060
4047 $ cd ..
4061 $ cd ..
4048 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4062 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4049 fourth, second, third
4063 fourth, second, third
4050 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4064 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4051 abc
4065 abc
4052
4066
4053 Test splitlines
4067 Test splitlines
4054
4068
4055 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4069 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4056 @ foo Modify, add, remove, rename
4070 @ foo Modify, add, remove, rename
4057 |
4071 |
4058 o foo future
4072 o foo future
4059 |
4073 |
4060 o foo third
4074 o foo third
4061 |
4075 |
4062 o foo second
4076 o foo second
4063
4077
4064 o foo merge
4078 o foo merge
4065 |\
4079 |\
4066 | o foo new head
4080 | o foo new head
4067 | |
4081 | |
4068 o | foo new branch
4082 o | foo new branch
4069 |/
4083 |/
4070 o foo no user, no domain
4084 o foo no user, no domain
4071 |
4085 |
4072 o foo no person
4086 o foo no person
4073 |
4087 |
4074 o foo other 1
4088 o foo other 1
4075 | foo other 2
4089 | foo other 2
4076 | foo
4090 | foo
4077 | foo other 3
4091 | foo other 3
4078 o foo line 1
4092 o foo line 1
4079 foo line 2
4093 foo line 2
4080
4094
4081 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4095 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4082 line 1 line 2
4096 line 1 line 2
4083 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4097 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4084 line 1|line 2
4098 line 1|line 2
4085
4099
4086 Test startswith
4100 Test startswith
4087 $ hg log -Gv -R a --template "{startswith(desc)}"
4101 $ hg log -Gv -R a --template "{startswith(desc)}"
4088 hg: parse error: startswith expects two arguments
4102 hg: parse error: startswith expects two arguments
4089 [255]
4103 [255]
4090
4104
4091 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4105 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4092 @
4106 @
4093 |
4107 |
4094 o
4108 o
4095 |
4109 |
4096 o
4110 o
4097 |
4111 |
4098 o
4112 o
4099
4113
4100 o
4114 o
4101 |\
4115 |\
4102 | o
4116 | o
4103 | |
4117 | |
4104 o |
4118 o |
4105 |/
4119 |/
4106 o
4120 o
4107 |
4121 |
4108 o
4122 o
4109 |
4123 |
4110 o
4124 o
4111 |
4125 |
4112 o line 1
4126 o line 1
4113 line 2
4127 line 2
4114
4128
4115 Test bad template with better error message
4129 Test bad template with better error message
4116
4130
4117 $ hg log -Gv -R a --template '{desc|user()}'
4131 $ hg log -Gv -R a --template '{desc|user()}'
4118 hg: parse error: expected a symbol, got 'func'
4132 hg: parse error: expected a symbol, got 'func'
4119 [255]
4133 [255]
4120
4134
4121 Test word function (including index out of bounds graceful failure)
4135 Test word function (including index out of bounds graceful failure)
4122
4136
4123 $ hg log -Gv -R a --template "{word('1', desc)}"
4137 $ hg log -Gv -R a --template "{word('1', desc)}"
4124 @ add,
4138 @ add,
4125 |
4139 |
4126 o
4140 o
4127 |
4141 |
4128 o
4142 o
4129 |
4143 |
4130 o
4144 o
4131
4145
4132 o
4146 o
4133 |\
4147 |\
4134 | o head
4148 | o head
4135 | |
4149 | |
4136 o | branch
4150 o | branch
4137 |/
4151 |/
4138 o user,
4152 o user,
4139 |
4153 |
4140 o person
4154 o person
4141 |
4155 |
4142 o 1
4156 o 1
4143 |
4157 |
4144 o 1
4158 o 1
4145
4159
4146
4160
4147 Test word third parameter used as splitter
4161 Test word third parameter used as splitter
4148
4162
4149 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4163 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4150 @ M
4164 @ M
4151 |
4165 |
4152 o future
4166 o future
4153 |
4167 |
4154 o third
4168 o third
4155 |
4169 |
4156 o sec
4170 o sec
4157
4171
4158 o merge
4172 o merge
4159 |\
4173 |\
4160 | o new head
4174 | o new head
4161 | |
4175 | |
4162 o | new branch
4176 o | new branch
4163 |/
4177 |/
4164 o n
4178 o n
4165 |
4179 |
4166 o n
4180 o n
4167 |
4181 |
4168 o
4182 o
4169 |
4183 |
4170 o line 1
4184 o line 1
4171 line 2
4185 line 2
4172
4186
4173 Test word error messages for not enough and too many arguments
4187 Test word error messages for not enough and too many arguments
4174
4188
4175 $ hg log -Gv -R a --template "{word('0')}"
4189 $ hg log -Gv -R a --template "{word('0')}"
4176 hg: parse error: word expects two or three arguments, got 1
4190 hg: parse error: word expects two or three arguments, got 1
4177 [255]
4191 [255]
4178
4192
4179 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4193 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4180 hg: parse error: word expects two or three arguments, got 7
4194 hg: parse error: word expects two or three arguments, got 7
4181 [255]
4195 [255]
4182
4196
4183 Test word for integer literal
4197 Test word for integer literal
4184
4198
4185 $ hg log -R a --template "{word(2, desc)}\n" -r0
4199 $ hg log -R a --template "{word(2, desc)}\n" -r0
4186 line
4200 line
4187
4201
4188 Test word for invalid numbers
4202 Test word for invalid numbers
4189
4203
4190 $ hg log -Gv -R a --template "{word('a', desc)}"
4204 $ hg log -Gv -R a --template "{word('a', desc)}"
4191 hg: parse error: word expects an integer index
4205 hg: parse error: word expects an integer index
4192 [255]
4206 [255]
4193
4207
4194 Test word for out of range
4208 Test word for out of range
4195
4209
4196 $ hg log -R a --template "{word(10000, desc)}"
4210 $ hg log -R a --template "{word(10000, desc)}"
4197 $ hg log -R a --template "{word(-10000, desc)}"
4211 $ hg log -R a --template "{word(-10000, desc)}"
4198
4212
4199 Test indent and not adding to empty lines
4213 Test indent and not adding to empty lines
4200
4214
4201 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4215 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4202 -----
4216 -----
4203 > line 1
4217 > line 1
4204 >> line 2
4218 >> line 2
4205 -----
4219 -----
4206 > other 1
4220 > other 1
4207 >> other 2
4221 >> other 2
4208
4222
4209 >> other 3
4223 >> other 3
4210
4224
4211 Test with non-strings like dates
4225 Test with non-strings like dates
4212
4226
4213 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4227 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4214 1200000.00
4228 1200000.00
4215 1300000.00
4229 1300000.00
4216
4230
4217 Test broken string escapes:
4231 Test broken string escapes:
4218
4232
4219 $ hg log -T "bogus\\" -R a
4233 $ hg log -T "bogus\\" -R a
4220 hg: parse error: trailing \ in string
4234 hg: parse error: trailing \ in string
4221 [255]
4235 [255]
4222 $ hg log -T "\\xy" -R a
4236 $ hg log -T "\\xy" -R a
4223 hg: parse error: invalid \x escape
4237 hg: parse error: invalid \x escape
4224 [255]
4238 [255]
4225
4239
4226 json filter should escape HTML tags so that the output can be embedded in hgweb:
4240 json filter should escape HTML tags so that the output can be embedded in hgweb:
4227
4241
4228 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4242 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4229 "\u003cfoo@example.org\u003e"
4243 "\u003cfoo@example.org\u003e"
4230
4244
4231 Templater supports aliases of symbol and func() styles:
4245 Templater supports aliases of symbol and func() styles:
4232
4246
4233 $ hg clone -q a aliases
4247 $ hg clone -q a aliases
4234 $ cd aliases
4248 $ cd aliases
4235 $ cat <<EOF >> .hg/hgrc
4249 $ cat <<EOF >> .hg/hgrc
4236 > [templatealias]
4250 > [templatealias]
4237 > r = rev
4251 > r = rev
4238 > rn = "{r}:{node|short}"
4252 > rn = "{r}:{node|short}"
4239 > status(c, files) = files % "{c} {file}\n"
4253 > status(c, files) = files % "{c} {file}\n"
4240 > utcdate(d) = localdate(d, "UTC")
4254 > utcdate(d) = localdate(d, "UTC")
4241 > EOF
4255 > EOF
4242
4256
4243 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4257 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4244 (template
4258 (template
4245 (symbol 'rn')
4259 (symbol 'rn')
4246 (string ' ')
4260 (string ' ')
4247 (|
4261 (|
4248 (func
4262 (func
4249 (symbol 'utcdate')
4263 (symbol 'utcdate')
4250 (symbol 'date'))
4264 (symbol 'date'))
4251 (symbol 'isodate'))
4265 (symbol 'isodate'))
4252 (string '\n'))
4266 (string '\n'))
4253 * expanded:
4267 * expanded:
4254 (template
4268 (template
4255 (template
4269 (template
4256 (symbol 'rev')
4270 (symbol 'rev')
4257 (string ':')
4271 (string ':')
4258 (|
4272 (|
4259 (symbol 'node')
4273 (symbol 'node')
4260 (symbol 'short')))
4274 (symbol 'short')))
4261 (string ' ')
4275 (string ' ')
4262 (|
4276 (|
4263 (func
4277 (func
4264 (symbol 'localdate')
4278 (symbol 'localdate')
4265 (list
4279 (list
4266 (symbol 'date')
4280 (symbol 'date')
4267 (string 'UTC')))
4281 (string 'UTC')))
4268 (symbol 'isodate'))
4282 (symbol 'isodate'))
4269 (string '\n'))
4283 (string '\n'))
4270 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4284 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4271
4285
4272 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4286 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4273 (template
4287 (template
4274 (func
4288 (func
4275 (symbol 'status')
4289 (symbol 'status')
4276 (list
4290 (list
4277 (string 'A')
4291 (string 'A')
4278 (symbol 'file_adds'))))
4292 (symbol 'file_adds'))))
4279 * expanded:
4293 * expanded:
4280 (template
4294 (template
4281 (%
4295 (%
4282 (symbol 'file_adds')
4296 (symbol 'file_adds')
4283 (template
4297 (template
4284 (string 'A')
4298 (string 'A')
4285 (string ' ')
4299 (string ' ')
4286 (symbol 'file')
4300 (symbol 'file')
4287 (string '\n'))))
4301 (string '\n'))))
4288 A a
4302 A a
4289
4303
4290 A unary function alias can be called as a filter:
4304 A unary function alias can be called as a filter:
4291
4305
4292 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4306 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4293 (template
4307 (template
4294 (|
4308 (|
4295 (|
4309 (|
4296 (symbol 'date')
4310 (symbol 'date')
4297 (symbol 'utcdate'))
4311 (symbol 'utcdate'))
4298 (symbol 'isodate'))
4312 (symbol 'isodate'))
4299 (string '\n'))
4313 (string '\n'))
4300 * expanded:
4314 * expanded:
4301 (template
4315 (template
4302 (|
4316 (|
4303 (func
4317 (func
4304 (symbol 'localdate')
4318 (symbol 'localdate')
4305 (list
4319 (list
4306 (symbol 'date')
4320 (symbol 'date')
4307 (string 'UTC')))
4321 (string 'UTC')))
4308 (symbol 'isodate'))
4322 (symbol 'isodate'))
4309 (string '\n'))
4323 (string '\n'))
4310 1970-01-12 13:46 +0000
4324 1970-01-12 13:46 +0000
4311
4325
4312 Aliases should be applied only to command arguments and templates in hgrc.
4326 Aliases should be applied only to command arguments and templates in hgrc.
4313 Otherwise, our stock styles and web templates could be corrupted:
4327 Otherwise, our stock styles and web templates could be corrupted:
4314
4328
4315 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4329 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4316 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4330 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4317
4331
4318 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4332 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4319 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4333 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4320
4334
4321 $ cat <<EOF > tmpl
4335 $ cat <<EOF > tmpl
4322 > changeset = 'nothing expanded:{rn}\n'
4336 > changeset = 'nothing expanded:{rn}\n'
4323 > EOF
4337 > EOF
4324 $ hg log -r0 --style ./tmpl
4338 $ hg log -r0 --style ./tmpl
4325 nothing expanded:
4339 nothing expanded:
4326
4340
4327 Aliases in formatter:
4341 Aliases in formatter:
4328
4342
4329 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4343 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4330 default 6:d41e714fe50d
4344 default 6:d41e714fe50d
4331 foo 4:bbe44766e73d
4345 foo 4:bbe44766e73d
4332
4346
4333 Aliases should honor HGPLAIN:
4347 Aliases should honor HGPLAIN:
4334
4348
4335 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4349 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4336 nothing expanded:
4350 nothing expanded:
4337 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4351 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4338 0:1e4e1b8f71e0
4352 0:1e4e1b8f71e0
4339
4353
4340 Unparsable alias:
4354 Unparsable alias:
4341
4355
4342 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4356 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4343 (template
4357 (template
4344 (symbol 'bad'))
4358 (symbol 'bad'))
4345 abort: bad definition of template alias "bad": at 2: not a prefix: end
4359 abort: bad definition of template alias "bad": at 2: not a prefix: end
4346 [255]
4360 [255]
4347 $ hg log --config templatealias.bad='x(' -T '{bad}'
4361 $ hg log --config templatealias.bad='x(' -T '{bad}'
4348 abort: bad definition of template alias "bad": at 2: not a prefix: end
4362 abort: bad definition of template alias "bad": at 2: not a prefix: end
4349 [255]
4363 [255]
4350
4364
4351 $ cd ..
4365 $ cd ..
4352
4366
4353 Set up repository for non-ascii encoding tests:
4367 Set up repository for non-ascii encoding tests:
4354
4368
4355 $ hg init nonascii
4369 $ hg init nonascii
4356 $ cd nonascii
4370 $ cd nonascii
4357 $ $PYTHON <<EOF
4371 $ $PYTHON <<EOF
4358 > open('latin1', 'w').write('\xe9')
4372 > open('latin1', 'w').write('\xe9')
4359 > open('utf-8', 'w').write('\xc3\xa9')
4373 > open('utf-8', 'w').write('\xc3\xa9')
4360 > EOF
4374 > EOF
4361 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4375 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4362 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4376 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4363
4377
4364 json filter should try round-trip conversion to utf-8:
4378 json filter should try round-trip conversion to utf-8:
4365
4379
4366 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4380 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4367 "\u00e9"
4381 "\u00e9"
4368 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4382 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4369 "non-ascii branch: \u00e9"
4383 "non-ascii branch: \u00e9"
4370
4384
4371 json filter takes input as utf-8b:
4385 json filter takes input as utf-8b:
4372
4386
4373 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4387 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4374 "\u00e9"
4388 "\u00e9"
4375 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4389 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4376 "\udce9"
4390 "\udce9"
4377
4391
4378 utf8 filter:
4392 utf8 filter:
4379
4393
4380 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4394 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4381 round-trip: c3a9
4395 round-trip: c3a9
4382 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4396 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4383 decoded: c3a9
4397 decoded: c3a9
4384 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4398 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4385 abort: decoding near * (glob)
4399 abort: decoding near * (glob)
4386 [255]
4400 [255]
4387 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4401 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4388 abort: template filter 'utf8' is not compatible with keyword 'rev'
4402 abort: template filter 'utf8' is not compatible with keyword 'rev'
4389 [255]
4403 [255]
4390
4404
4391 pad width:
4405 pad width:
4392
4406
4393 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4407 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4394 \xc3\xa9- (esc)
4408 \xc3\xa9- (esc)
4395
4409
4396 $ cd ..
4410 $ cd ..
4397
4411
4398 Test that template function in extension is registered as expected
4412 Test that template function in extension is registered as expected
4399
4413
4400 $ cd a
4414 $ cd a
4401
4415
4402 $ cat <<EOF > $TESTTMP/customfunc.py
4416 $ cat <<EOF > $TESTTMP/customfunc.py
4403 > from mercurial import registrar
4417 > from mercurial import registrar
4404 >
4418 >
4405 > templatefunc = registrar.templatefunc()
4419 > templatefunc = registrar.templatefunc()
4406 >
4420 >
4407 > @templatefunc('custom()')
4421 > @templatefunc('custom()')
4408 > def custom(context, mapping, args):
4422 > def custom(context, mapping, args):
4409 > return 'custom'
4423 > return 'custom'
4410 > EOF
4424 > EOF
4411 $ cat <<EOF > .hg/hgrc
4425 $ cat <<EOF > .hg/hgrc
4412 > [extensions]
4426 > [extensions]
4413 > customfunc = $TESTTMP/customfunc.py
4427 > customfunc = $TESTTMP/customfunc.py
4414 > EOF
4428 > EOF
4415
4429
4416 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4430 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4417 custom
4431 custom
4418
4432
4419 $ cd ..
4433 $ cd ..
4420
4434
4421 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4435 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4422 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4436 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4423 columns. We don't care about other aspects of the graph rendering here.
4437 columns. We don't care about other aspects of the graph rendering here.
4424
4438
4425 $ hg init graphwidth
4439 $ hg init graphwidth
4426 $ cd graphwidth
4440 $ cd graphwidth
4427
4441
4428 $ wrappabletext="a a a a a a a a a a a a"
4442 $ wrappabletext="a a a a a a a a a a a a"
4429
4443
4430 $ printf "first\n" > file
4444 $ printf "first\n" > file
4431 $ hg add file
4445 $ hg add file
4432 $ hg commit -m "$wrappabletext"
4446 $ hg commit -m "$wrappabletext"
4433
4447
4434 $ printf "first\nsecond\n" > file
4448 $ printf "first\nsecond\n" > file
4435 $ hg commit -m "$wrappabletext"
4449 $ hg commit -m "$wrappabletext"
4436
4450
4437 $ hg checkout 0
4451 $ hg checkout 0
4438 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4439 $ printf "third\nfirst\n" > file
4453 $ printf "third\nfirst\n" > file
4440 $ hg commit -m "$wrappabletext"
4454 $ hg commit -m "$wrappabletext"
4441 created new head
4455 created new head
4442
4456
4443 $ hg merge
4457 $ hg merge
4444 merging file
4458 merging file
4445 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4459 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4446 (branch merge, don't forget to commit)
4460 (branch merge, don't forget to commit)
4447
4461
4448 $ hg log --graph -T "{graphwidth}"
4462 $ hg log --graph -T "{graphwidth}"
4449 @ 3
4463 @ 3
4450 |
4464 |
4451 | @ 5
4465 | @ 5
4452 |/
4466 |/
4453 o 3
4467 o 3
4454
4468
4455 $ hg commit -m "$wrappabletext"
4469 $ hg commit -m "$wrappabletext"
4456
4470
4457 $ hg log --graph -T "{graphwidth}"
4471 $ hg log --graph -T "{graphwidth}"
4458 @ 5
4472 @ 5
4459 |\
4473 |\
4460 | o 5
4474 | o 5
4461 | |
4475 | |
4462 o | 5
4476 o | 5
4463 |/
4477 |/
4464 o 3
4478 o 3
4465
4479
4466
4480
4467 $ hg checkout 0
4481 $ hg checkout 0
4468 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4469 $ printf "third\nfirst\nsecond\n" > file
4483 $ printf "third\nfirst\nsecond\n" > file
4470 $ hg commit -m "$wrappabletext"
4484 $ hg commit -m "$wrappabletext"
4471 created new head
4485 created new head
4472
4486
4473 $ hg log --graph -T "{graphwidth}"
4487 $ hg log --graph -T "{graphwidth}"
4474 @ 3
4488 @ 3
4475 |
4489 |
4476 | o 7
4490 | o 7
4477 | |\
4491 | |\
4478 +---o 7
4492 +---o 7
4479 | |
4493 | |
4480 | o 5
4494 | o 5
4481 |/
4495 |/
4482 o 3
4496 o 3
4483
4497
4484
4498
4485 $ hg log --graph -T "{graphwidth}" -r 3
4499 $ hg log --graph -T "{graphwidth}" -r 3
4486 o 5
4500 o 5
4487 |\
4501 |\
4488 ~ ~
4502 ~ ~
4489
4503
4490 $ hg log --graph -T "{graphwidth}" -r 1
4504 $ hg log --graph -T "{graphwidth}" -r 1
4491 o 3
4505 o 3
4492 |
4506 |
4493 ~
4507 ~
4494
4508
4495 $ hg merge
4509 $ hg merge
4496 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4510 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4497 (branch merge, don't forget to commit)
4511 (branch merge, don't forget to commit)
4498 $ hg commit -m "$wrappabletext"
4512 $ hg commit -m "$wrappabletext"
4499
4513
4500 $ printf "seventh\n" >> file
4514 $ printf "seventh\n" >> file
4501 $ hg commit -m "$wrappabletext"
4515 $ hg commit -m "$wrappabletext"
4502
4516
4503 $ hg log --graph -T "{graphwidth}"
4517 $ hg log --graph -T "{graphwidth}"
4504 @ 3
4518 @ 3
4505 |
4519 |
4506 o 5
4520 o 5
4507 |\
4521 |\
4508 | o 5
4522 | o 5
4509 | |
4523 | |
4510 o | 7
4524 o | 7
4511 |\ \
4525 |\ \
4512 | o | 7
4526 | o | 7
4513 | |/
4527 | |/
4514 o / 5
4528 o / 5
4515 |/
4529 |/
4516 o 3
4530 o 3
4517
4531
4518
4532
4519 The point of graphwidth is to allow wrapping that accounts for the space taken
4533 The point of graphwidth is to allow wrapping that accounts for the space taken
4520 by the graph.
4534 by the graph.
4521
4535
4522 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4536 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4523 @ a a a a
4537 @ a a a a
4524 | a a a a
4538 | a a a a
4525 | a a a a
4539 | a a a a
4526 o a a a
4540 o a a a
4527 |\ a a a
4541 |\ a a a
4528 | | a a a
4542 | | a a a
4529 | | a a a
4543 | | a a a
4530 | o a a a
4544 | o a a a
4531 | | a a a
4545 | | a a a
4532 | | a a a
4546 | | a a a
4533 | | a a a
4547 | | a a a
4534 o | a a
4548 o | a a
4535 |\ \ a a
4549 |\ \ a a
4536 | | | a a
4550 | | | a a
4537 | | | a a
4551 | | | a a
4538 | | | a a
4552 | | | a a
4539 | | | a a
4553 | | | a a
4540 | o | a a
4554 | o | a a
4541 | |/ a a
4555 | |/ a a
4542 | | a a
4556 | | a a
4543 | | a a
4557 | | a a
4544 | | a a
4558 | | a a
4545 | | a a
4559 | | a a
4546 o | a a a
4560 o | a a a
4547 |/ a a a
4561 |/ a a a
4548 | a a a
4562 | a a a
4549 | a a a
4563 | a a a
4550 o a a a a
4564 o a a a a
4551 a a a a
4565 a a a a
4552 a a a a
4566 a a a a
4553
4567
4554 Something tricky happens when there are elided nodes; the next drawn row of
4568 Something tricky happens when there are elided nodes; the next drawn row of
4555 edges can be more than one column wider, but the graph width only increases by
4569 edges can be more than one column wider, but the graph width only increases by
4556 one column. The remaining columns are added in between the nodes.
4570 one column. The remaining columns are added in between the nodes.
4557
4571
4558 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4572 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4559 o 5
4573 o 5
4560 |\
4574 |\
4561 | \
4575 | \
4562 | :\
4576 | :\
4563 o : : 7
4577 o : : 7
4564 :/ /
4578 :/ /
4565 : o 5
4579 : o 5
4566 :/
4580 :/
4567 o 3
4581 o 3
4568
4582
4569
4583
4570 $ cd ..
4584 $ cd ..
4571
4585
General Comments 0
You need to be logged in to leave comments. Login now