##// END OF EJS Templates
templater: wrap result of '%' operation so it never looks like a thunk...
Yuya Nishihara -
r37517:75c13343 default
parent child Browse files
Show More
@@ -1,911 +1,915
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 """Slightly complicated template engine for commands and hgweb
8 """Slightly complicated template engine for commands and hgweb
9
9
10 This module provides low-level interface to the template engine. See the
10 This module provides low-level interface to the template engine. See the
11 formatter and cmdutil modules if you are looking for high-level functions
11 formatter and cmdutil modules if you are looking for high-level functions
12 such as ``cmdutil.rendertemplate(ctx, tmpl)``.
12 such as ``cmdutil.rendertemplate(ctx, tmpl)``.
13
13
14 Internal Data Types
14 Internal Data Types
15 -------------------
15 -------------------
16
16
17 Template keywords and functions take a dictionary of current symbols and
17 Template keywords and functions take a dictionary of current symbols and
18 resources (a "mapping") and return result. Inputs and outputs must be one
18 resources (a "mapping") and return result. Inputs and outputs must be one
19 of the following data types:
19 of the following data types:
20
20
21 bytes
21 bytes
22 a byte string, which is generally a human-readable text in local encoding.
22 a byte string, which is generally a human-readable text in local encoding.
23
23
24 generator
24 generator
25 a lazily-evaluated byte string, which is a possibly nested generator of
25 a lazily-evaluated byte string, which is a possibly nested generator of
26 values of any printable types, and will be folded by ``stringify()``
26 values of any printable types, and will be folded by ``stringify()``
27 or ``flatten()``.
27 or ``flatten()``.
28
28
29 BUG: hgweb overloads this type for mappings (i.e. some hgweb keywords
29 BUG: hgweb overloads this type for mappings (i.e. some hgweb keywords
30 returns a generator of dicts.)
30 returns a generator of dicts.)
31
31
32 None
32 None
33 sometimes represents an empty value, which can be stringified to ''.
33 sometimes represents an empty value, which can be stringified to ''.
34
34
35 True, False, int, float
35 True, False, int, float
36 can be stringified as such.
36 can be stringified as such.
37
37
38 date tuple
38 date tuple
39 a (unixtime, offset) tuple, which produces no meaningful output by itself.
39 a (unixtime, offset) tuple, which produces no meaningful output by itself.
40
40
41 hybrid
41 hybrid
42 represents a list/dict of printable values, which can also be converted
42 represents a list/dict of printable values, which can also be converted
43 to mappings by % operator.
43 to mappings by % operator.
44
44
45 mappable
45 mappable
46 represents a scalar printable value, also supports % operator.
46 represents a scalar printable value, also supports % operator.
47
47
48 mappinggenerator, mappinglist
48 mappinggenerator, mappinglist
49 represents mappings (i.e. a list of dicts), which may have default
49 represents mappings (i.e. a list of dicts), which may have default
50 output format.
50 output format.
51
52 mappedgenerator
53 a lazily-evaluated list of byte strings, which is e.g. a result of %
54 operation.
51 """
55 """
52
56
53 from __future__ import absolute_import, print_function
57 from __future__ import absolute_import, print_function
54
58
55 import abc
59 import abc
56 import os
60 import os
57
61
58 from .i18n import _
62 from .i18n import _
59 from . import (
63 from . import (
60 config,
64 config,
61 encoding,
65 encoding,
62 error,
66 error,
63 parser,
67 parser,
64 pycompat,
68 pycompat,
65 templatefilters,
69 templatefilters,
66 templatefuncs,
70 templatefuncs,
67 templateutil,
71 templateutil,
68 util,
72 util,
69 )
73 )
70 from .utils import (
74 from .utils import (
71 stringutil,
75 stringutil,
72 )
76 )
73
77
74 # template parsing
78 # template parsing
75
79
76 elements = {
80 elements = {
77 # token-type: binding-strength, primary, prefix, infix, suffix
81 # token-type: binding-strength, primary, prefix, infix, suffix
78 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
82 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
79 ".": (18, None, None, (".", 18), None),
83 ".": (18, None, None, (".", 18), None),
80 "%": (15, None, None, ("%", 15), None),
84 "%": (15, None, None, ("%", 15), None),
81 "|": (15, None, None, ("|", 15), None),
85 "|": (15, None, None, ("|", 15), None),
82 "*": (5, None, None, ("*", 5), None),
86 "*": (5, None, None, ("*", 5), None),
83 "/": (5, None, None, ("/", 5), None),
87 "/": (5, None, None, ("/", 5), None),
84 "+": (4, None, None, ("+", 4), None),
88 "+": (4, None, None, ("+", 4), None),
85 "-": (4, None, ("negate", 19), ("-", 4), None),
89 "-": (4, None, ("negate", 19), ("-", 4), None),
86 "=": (3, None, None, ("keyvalue", 3), None),
90 "=": (3, None, None, ("keyvalue", 3), None),
87 ",": (2, None, None, ("list", 2), None),
91 ",": (2, None, None, ("list", 2), None),
88 ")": (0, None, None, None, None),
92 ")": (0, None, None, None, None),
89 "integer": (0, "integer", None, None, None),
93 "integer": (0, "integer", None, None, None),
90 "symbol": (0, "symbol", None, None, None),
94 "symbol": (0, "symbol", None, None, None),
91 "string": (0, "string", None, None, None),
95 "string": (0, "string", None, None, None),
92 "template": (0, "template", None, None, None),
96 "template": (0, "template", None, None, None),
93 "end": (0, None, None, None, None),
97 "end": (0, None, None, None, None),
94 }
98 }
95
99
96 def tokenize(program, start, end, term=None):
100 def tokenize(program, start, end, term=None):
97 """Parse a template expression into a stream of tokens, which must end
101 """Parse a template expression into a stream of tokens, which must end
98 with term if specified"""
102 with term if specified"""
99 pos = start
103 pos = start
100 program = pycompat.bytestr(program)
104 program = pycompat.bytestr(program)
101 while pos < end:
105 while pos < end:
102 c = program[pos]
106 c = program[pos]
103 if c.isspace(): # skip inter-token whitespace
107 if c.isspace(): # skip inter-token whitespace
104 pass
108 pass
105 elif c in "(=,).%|+-*/": # handle simple operators
109 elif c in "(=,).%|+-*/": # handle simple operators
106 yield (c, None, pos)
110 yield (c, None, pos)
107 elif c in '"\'': # handle quoted templates
111 elif c in '"\'': # handle quoted templates
108 s = pos + 1
112 s = pos + 1
109 data, pos = _parsetemplate(program, s, end, c)
113 data, pos = _parsetemplate(program, s, end, c)
110 yield ('template', data, s)
114 yield ('template', data, s)
111 pos -= 1
115 pos -= 1
112 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
116 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
113 # handle quoted strings
117 # handle quoted strings
114 c = program[pos + 1]
118 c = program[pos + 1]
115 s = pos = pos + 2
119 s = pos = pos + 2
116 while pos < end: # find closing quote
120 while pos < end: # find closing quote
117 d = program[pos]
121 d = program[pos]
118 if d == '\\': # skip over escaped characters
122 if d == '\\': # skip over escaped characters
119 pos += 2
123 pos += 2
120 continue
124 continue
121 if d == c:
125 if d == c:
122 yield ('string', program[s:pos], s)
126 yield ('string', program[s:pos], s)
123 break
127 break
124 pos += 1
128 pos += 1
125 else:
129 else:
126 raise error.ParseError(_("unterminated string"), s)
130 raise error.ParseError(_("unterminated string"), s)
127 elif c.isdigit():
131 elif c.isdigit():
128 s = pos
132 s = pos
129 while pos < end:
133 while pos < end:
130 d = program[pos]
134 d = program[pos]
131 if not d.isdigit():
135 if not d.isdigit():
132 break
136 break
133 pos += 1
137 pos += 1
134 yield ('integer', program[s:pos], s)
138 yield ('integer', program[s:pos], s)
135 pos -= 1
139 pos -= 1
136 elif (c == '\\' and program[pos:pos + 2] in (br"\'", br'\"')
140 elif (c == '\\' and program[pos:pos + 2] in (br"\'", br'\"')
137 or c == 'r' and program[pos:pos + 3] in (br"r\'", br'r\"')):
141 or c == 'r' and program[pos:pos + 3] in (br"r\'", br'r\"')):
138 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
142 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
139 # where some of nested templates were preprocessed as strings and
143 # where some of nested templates were preprocessed as strings and
140 # then compiled. therefore, \"...\" was allowed. (issue4733)
144 # then compiled. therefore, \"...\" was allowed. (issue4733)
141 #
145 #
142 # processing flow of _evalifliteral() at 5ab28a2e9962:
146 # processing flow of _evalifliteral() at 5ab28a2e9962:
143 # outer template string -> stringify() -> compiletemplate()
147 # outer template string -> stringify() -> compiletemplate()
144 # ------------------------ ------------ ------------------
148 # ------------------------ ------------ ------------------
145 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
149 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
146 # ~~~~~~~~
150 # ~~~~~~~~
147 # escaped quoted string
151 # escaped quoted string
148 if c == 'r':
152 if c == 'r':
149 pos += 1
153 pos += 1
150 token = 'string'
154 token = 'string'
151 else:
155 else:
152 token = 'template'
156 token = 'template'
153 quote = program[pos:pos + 2]
157 quote = program[pos:pos + 2]
154 s = pos = pos + 2
158 s = pos = pos + 2
155 while pos < end: # find closing escaped quote
159 while pos < end: # find closing escaped quote
156 if program.startswith('\\\\\\', pos, end):
160 if program.startswith('\\\\\\', pos, end):
157 pos += 4 # skip over double escaped characters
161 pos += 4 # skip over double escaped characters
158 continue
162 continue
159 if program.startswith(quote, pos, end):
163 if program.startswith(quote, pos, end):
160 # interpret as if it were a part of an outer string
164 # interpret as if it were a part of an outer string
161 data = parser.unescapestr(program[s:pos])
165 data = parser.unescapestr(program[s:pos])
162 if token == 'template':
166 if token == 'template':
163 data = _parsetemplate(data, 0, len(data))[0]
167 data = _parsetemplate(data, 0, len(data))[0]
164 yield (token, data, s)
168 yield (token, data, s)
165 pos += 1
169 pos += 1
166 break
170 break
167 pos += 1
171 pos += 1
168 else:
172 else:
169 raise error.ParseError(_("unterminated string"), s)
173 raise error.ParseError(_("unterminated string"), s)
170 elif c.isalnum() or c in '_':
174 elif c.isalnum() or c in '_':
171 s = pos
175 s = pos
172 pos += 1
176 pos += 1
173 while pos < end: # find end of symbol
177 while pos < end: # find end of symbol
174 d = program[pos]
178 d = program[pos]
175 if not (d.isalnum() or d == "_"):
179 if not (d.isalnum() or d == "_"):
176 break
180 break
177 pos += 1
181 pos += 1
178 sym = program[s:pos]
182 sym = program[s:pos]
179 yield ('symbol', sym, s)
183 yield ('symbol', sym, s)
180 pos -= 1
184 pos -= 1
181 elif c == term:
185 elif c == term:
182 yield ('end', None, pos)
186 yield ('end', None, pos)
183 return
187 return
184 else:
188 else:
185 raise error.ParseError(_("syntax error"), pos)
189 raise error.ParseError(_("syntax error"), pos)
186 pos += 1
190 pos += 1
187 if term:
191 if term:
188 raise error.ParseError(_("unterminated template expansion"), start)
192 raise error.ParseError(_("unterminated template expansion"), start)
189 yield ('end', None, pos)
193 yield ('end', None, pos)
190
194
191 def _parsetemplate(tmpl, start, stop, quote=''):
195 def _parsetemplate(tmpl, start, stop, quote=''):
192 r"""
196 r"""
193 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
197 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
194 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
198 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
195 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
199 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
196 ([('string', 'foo'), ('symbol', 'bar')], 9)
200 ([('string', 'foo'), ('symbol', 'bar')], 9)
197 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
201 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
198 ([('string', 'foo')], 4)
202 ([('string', 'foo')], 4)
199 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
203 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
200 ([('string', 'foo"'), ('string', 'bar')], 9)
204 ([('string', 'foo"'), ('string', 'bar')], 9)
201 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
205 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
202 ([('string', 'foo\\')], 6)
206 ([('string', 'foo\\')], 6)
203 """
207 """
204 parsed = []
208 parsed = []
205 for typ, val, pos in _scantemplate(tmpl, start, stop, quote):
209 for typ, val, pos in _scantemplate(tmpl, start, stop, quote):
206 if typ == 'string':
210 if typ == 'string':
207 parsed.append((typ, val))
211 parsed.append((typ, val))
208 elif typ == 'template':
212 elif typ == 'template':
209 parsed.append(val)
213 parsed.append(val)
210 elif typ == 'end':
214 elif typ == 'end':
211 return parsed, pos
215 return parsed, pos
212 else:
216 else:
213 raise error.ProgrammingError('unexpected type: %s' % typ)
217 raise error.ProgrammingError('unexpected type: %s' % typ)
214 raise error.ProgrammingError('unterminated scanning of template')
218 raise error.ProgrammingError('unterminated scanning of template')
215
219
216 def scantemplate(tmpl, raw=False):
220 def scantemplate(tmpl, raw=False):
217 r"""Scan (type, start, end) positions of outermost elements in template
221 r"""Scan (type, start, end) positions of outermost elements in template
218
222
219 If raw=True, a backslash is not taken as an escape character just like
223 If raw=True, a backslash is not taken as an escape character just like
220 r'' string in Python. Note that this is different from r'' literal in
224 r'' string in Python. Note that this is different from r'' literal in
221 template in that no template fragment can appear in r'', e.g. r'{foo}'
225 template in that no template fragment can appear in r'', e.g. r'{foo}'
222 is a literal '{foo}', but ('{foo}', raw=True) is a template expression
226 is a literal '{foo}', but ('{foo}', raw=True) is a template expression
223 'foo'.
227 'foo'.
224
228
225 >>> list(scantemplate(b'foo{bar}"baz'))
229 >>> list(scantemplate(b'foo{bar}"baz'))
226 [('string', 0, 3), ('template', 3, 8), ('string', 8, 12)]
230 [('string', 0, 3), ('template', 3, 8), ('string', 8, 12)]
227 >>> list(scantemplate(b'outer{"inner"}outer'))
231 >>> list(scantemplate(b'outer{"inner"}outer'))
228 [('string', 0, 5), ('template', 5, 14), ('string', 14, 19)]
232 [('string', 0, 5), ('template', 5, 14), ('string', 14, 19)]
229 >>> list(scantemplate(b'foo\\{escaped}'))
233 >>> list(scantemplate(b'foo\\{escaped}'))
230 [('string', 0, 5), ('string', 5, 13)]
234 [('string', 0, 5), ('string', 5, 13)]
231 >>> list(scantemplate(b'foo\\{escaped}', raw=True))
235 >>> list(scantemplate(b'foo\\{escaped}', raw=True))
232 [('string', 0, 4), ('template', 4, 13)]
236 [('string', 0, 4), ('template', 4, 13)]
233 """
237 """
234 last = None
238 last = None
235 for typ, val, pos in _scantemplate(tmpl, 0, len(tmpl), raw=raw):
239 for typ, val, pos in _scantemplate(tmpl, 0, len(tmpl), raw=raw):
236 if last:
240 if last:
237 yield last + (pos,)
241 yield last + (pos,)
238 if typ == 'end':
242 if typ == 'end':
239 return
243 return
240 else:
244 else:
241 last = (typ, pos)
245 last = (typ, pos)
242 raise error.ProgrammingError('unterminated scanning of template')
246 raise error.ProgrammingError('unterminated scanning of template')
243
247
244 def _scantemplate(tmpl, start, stop, quote='', raw=False):
248 def _scantemplate(tmpl, start, stop, quote='', raw=False):
245 """Parse template string into chunks of strings and template expressions"""
249 """Parse template string into chunks of strings and template expressions"""
246 sepchars = '{' + quote
250 sepchars = '{' + quote
247 unescape = [parser.unescapestr, pycompat.identity][raw]
251 unescape = [parser.unescapestr, pycompat.identity][raw]
248 pos = start
252 pos = start
249 p = parser.parser(elements)
253 p = parser.parser(elements)
250 try:
254 try:
251 while pos < stop:
255 while pos < stop:
252 n = min((tmpl.find(c, pos, stop) for c in sepchars),
256 n = min((tmpl.find(c, pos, stop) for c in sepchars),
253 key=lambda n: (n < 0, n))
257 key=lambda n: (n < 0, n))
254 if n < 0:
258 if n < 0:
255 yield ('string', unescape(tmpl[pos:stop]), pos)
259 yield ('string', unescape(tmpl[pos:stop]), pos)
256 pos = stop
260 pos = stop
257 break
261 break
258 c = tmpl[n:n + 1]
262 c = tmpl[n:n + 1]
259 bs = 0 # count leading backslashes
263 bs = 0 # count leading backslashes
260 if not raw:
264 if not raw:
261 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
265 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
262 if bs % 2 == 1:
266 if bs % 2 == 1:
263 # escaped (e.g. '\{', '\\\{', but not '\\{')
267 # escaped (e.g. '\{', '\\\{', but not '\\{')
264 yield ('string', unescape(tmpl[pos:n - 1]) + c, pos)
268 yield ('string', unescape(tmpl[pos:n - 1]) + c, pos)
265 pos = n + 1
269 pos = n + 1
266 continue
270 continue
267 if n > pos:
271 if n > pos:
268 yield ('string', unescape(tmpl[pos:n]), pos)
272 yield ('string', unescape(tmpl[pos:n]), pos)
269 if c == quote:
273 if c == quote:
270 yield ('end', None, n + 1)
274 yield ('end', None, n + 1)
271 return
275 return
272
276
273 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
277 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
274 if not tmpl.startswith('}', pos):
278 if not tmpl.startswith('}', pos):
275 raise error.ParseError(_("invalid token"), pos)
279 raise error.ParseError(_("invalid token"), pos)
276 yield ('template', parseres, n)
280 yield ('template', parseres, n)
277 pos += 1
281 pos += 1
278
282
279 if quote:
283 if quote:
280 raise error.ParseError(_("unterminated string"), start)
284 raise error.ParseError(_("unterminated string"), start)
281 except error.ParseError as inst:
285 except error.ParseError as inst:
282 if len(inst.args) > 1: # has location
286 if len(inst.args) > 1: # has location
283 loc = inst.args[1]
287 loc = inst.args[1]
284 # Offset the caret location by the number of newlines before the
288 # Offset the caret location by the number of newlines before the
285 # location of the error, since we will replace one-char newlines
289 # location of the error, since we will replace one-char newlines
286 # with the two-char literal r'\n'.
290 # with the two-char literal r'\n'.
287 offset = tmpl[:loc].count('\n')
291 offset = tmpl[:loc].count('\n')
288 tmpl = tmpl.replace('\n', br'\n')
292 tmpl = tmpl.replace('\n', br'\n')
289 # We want the caret to point to the place in the template that
293 # We want the caret to point to the place in the template that
290 # failed to parse, but in a hint we get a open paren at the
294 # failed to parse, but in a hint we get a open paren at the
291 # start. Therefore, we print "loc + 1" spaces (instead of "loc")
295 # start. Therefore, we print "loc + 1" spaces (instead of "loc")
292 # to line up the caret with the location of the error.
296 # to line up the caret with the location of the error.
293 inst.hint = (tmpl + '\n'
297 inst.hint = (tmpl + '\n'
294 + ' ' * (loc + 1 + offset) + '^ ' + _('here'))
298 + ' ' * (loc + 1 + offset) + '^ ' + _('here'))
295 raise
299 raise
296 yield ('end', None, pos)
300 yield ('end', None, pos)
297
301
298 def _unnesttemplatelist(tree):
302 def _unnesttemplatelist(tree):
299 """Expand list of templates to node tuple
303 """Expand list of templates to node tuple
300
304
301 >>> def f(tree):
305 >>> def f(tree):
302 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
306 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
303 >>> f((b'template', []))
307 >>> f((b'template', []))
304 (string '')
308 (string '')
305 >>> f((b'template', [(b'string', b'foo')]))
309 >>> f((b'template', [(b'string', b'foo')]))
306 (string 'foo')
310 (string 'foo')
307 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
311 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
308 (template
312 (template
309 (string 'foo')
313 (string 'foo')
310 (symbol 'rev'))
314 (symbol 'rev'))
311 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
315 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
312 (template
316 (template
313 (symbol 'rev'))
317 (symbol 'rev'))
314 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
318 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
315 (string 'foo')
319 (string 'foo')
316 """
320 """
317 if not isinstance(tree, tuple):
321 if not isinstance(tree, tuple):
318 return tree
322 return tree
319 op = tree[0]
323 op = tree[0]
320 if op != 'template':
324 if op != 'template':
321 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
325 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
322
326
323 assert len(tree) == 2
327 assert len(tree) == 2
324 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
328 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
325 if not xs:
329 if not xs:
326 return ('string', '') # empty template ""
330 return ('string', '') # empty template ""
327 elif len(xs) == 1 and xs[0][0] == 'string':
331 elif len(xs) == 1 and xs[0][0] == 'string':
328 return xs[0] # fast path for string with no template fragment "x"
332 return xs[0] # fast path for string with no template fragment "x"
329 else:
333 else:
330 return (op,) + xs
334 return (op,) + xs
331
335
332 def parse(tmpl):
336 def parse(tmpl):
333 """Parse template string into tree"""
337 """Parse template string into tree"""
334 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
338 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
335 assert pos == len(tmpl), 'unquoted template should be consumed'
339 assert pos == len(tmpl), 'unquoted template should be consumed'
336 return _unnesttemplatelist(('template', parsed))
340 return _unnesttemplatelist(('template', parsed))
337
341
338 def _parseexpr(expr):
342 def _parseexpr(expr):
339 """Parse a template expression into tree
343 """Parse a template expression into tree
340
344
341 >>> _parseexpr(b'"foo"')
345 >>> _parseexpr(b'"foo"')
342 ('string', 'foo')
346 ('string', 'foo')
343 >>> _parseexpr(b'foo(bar)')
347 >>> _parseexpr(b'foo(bar)')
344 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
348 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
345 >>> _parseexpr(b'foo(')
349 >>> _parseexpr(b'foo(')
346 Traceback (most recent call last):
350 Traceback (most recent call last):
347 ...
351 ...
348 ParseError: ('not a prefix: end', 4)
352 ParseError: ('not a prefix: end', 4)
349 >>> _parseexpr(b'"foo" "bar"')
353 >>> _parseexpr(b'"foo" "bar"')
350 Traceback (most recent call last):
354 Traceback (most recent call last):
351 ...
355 ...
352 ParseError: ('invalid token', 7)
356 ParseError: ('invalid token', 7)
353 """
357 """
354 p = parser.parser(elements)
358 p = parser.parser(elements)
355 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
359 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
356 if pos != len(expr):
360 if pos != len(expr):
357 raise error.ParseError(_('invalid token'), pos)
361 raise error.ParseError(_('invalid token'), pos)
358 return _unnesttemplatelist(tree)
362 return _unnesttemplatelist(tree)
359
363
360 def prettyformat(tree):
364 def prettyformat(tree):
361 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
365 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
362
366
363 def compileexp(exp, context, curmethods):
367 def compileexp(exp, context, curmethods):
364 """Compile parsed template tree to (func, data) pair"""
368 """Compile parsed template tree to (func, data) pair"""
365 if not exp:
369 if not exp:
366 raise error.ParseError(_("missing argument"))
370 raise error.ParseError(_("missing argument"))
367 t = exp[0]
371 t = exp[0]
368 if t in curmethods:
372 if t in curmethods:
369 return curmethods[t](exp, context)
373 return curmethods[t](exp, context)
370 raise error.ParseError(_("unknown method '%s'") % t)
374 raise error.ParseError(_("unknown method '%s'") % t)
371
375
372 # template evaluation
376 # template evaluation
373
377
374 def getsymbol(exp):
378 def getsymbol(exp):
375 if exp[0] == 'symbol':
379 if exp[0] == 'symbol':
376 return exp[1]
380 return exp[1]
377 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
381 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
378
382
379 def getlist(x):
383 def getlist(x):
380 if not x:
384 if not x:
381 return []
385 return []
382 if x[0] == 'list':
386 if x[0] == 'list':
383 return getlist(x[1]) + [x[2]]
387 return getlist(x[1]) + [x[2]]
384 return [x]
388 return [x]
385
389
386 def gettemplate(exp, context):
390 def gettemplate(exp, context):
387 """Compile given template tree or load named template from map file;
391 """Compile given template tree or load named template from map file;
388 returns (func, data) pair"""
392 returns (func, data) pair"""
389 if exp[0] in ('template', 'string'):
393 if exp[0] in ('template', 'string'):
390 return compileexp(exp, context, methods)
394 return compileexp(exp, context, methods)
391 if exp[0] == 'symbol':
395 if exp[0] == 'symbol':
392 # unlike runsymbol(), here 'symbol' is always taken as template name
396 # unlike runsymbol(), here 'symbol' is always taken as template name
393 # even if it exists in mapping. this allows us to override mapping
397 # even if it exists in mapping. this allows us to override mapping
394 # by web templates, e.g. 'changelogtag' is redefined in map file.
398 # by web templates, e.g. 'changelogtag' is redefined in map file.
395 return context._load(exp[1])
399 return context._load(exp[1])
396 raise error.ParseError(_("expected template specifier"))
400 raise error.ParseError(_("expected template specifier"))
397
401
398 def _runrecursivesymbol(context, mapping, key):
402 def _runrecursivesymbol(context, mapping, key):
399 raise error.Abort(_("recursive reference '%s' in template") % key)
403 raise error.Abort(_("recursive reference '%s' in template") % key)
400
404
401 def buildtemplate(exp, context):
405 def buildtemplate(exp, context):
402 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
406 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
403 return (templateutil.runtemplate, ctmpl)
407 return (templateutil.runtemplate, ctmpl)
404
408
405 def buildfilter(exp, context):
409 def buildfilter(exp, context):
406 n = getsymbol(exp[2])
410 n = getsymbol(exp[2])
407 if n in context._filters:
411 if n in context._filters:
408 filt = context._filters[n]
412 filt = context._filters[n]
409 arg = compileexp(exp[1], context, methods)
413 arg = compileexp(exp[1], context, methods)
410 return (templateutil.runfilter, (arg, filt))
414 return (templateutil.runfilter, (arg, filt))
411 if n in context._funcs:
415 if n in context._funcs:
412 f = context._funcs[n]
416 f = context._funcs[n]
413 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
417 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
414 return (f, args)
418 return (f, args)
415 raise error.ParseError(_("unknown function '%s'") % n)
419 raise error.ParseError(_("unknown function '%s'") % n)
416
420
417 def buildmap(exp, context):
421 def buildmap(exp, context):
418 darg = compileexp(exp[1], context, methods)
422 darg = compileexp(exp[1], context, methods)
419 targ = gettemplate(exp[2], context)
423 targ = gettemplate(exp[2], context)
420 return (templateutil.runmap, (darg, targ))
424 return (templateutil.runmap, (darg, targ))
421
425
422 def buildmember(exp, context):
426 def buildmember(exp, context):
423 darg = compileexp(exp[1], context, methods)
427 darg = compileexp(exp[1], context, methods)
424 memb = getsymbol(exp[2])
428 memb = getsymbol(exp[2])
425 return (templateutil.runmember, (darg, memb))
429 return (templateutil.runmember, (darg, memb))
426
430
427 def buildnegate(exp, context):
431 def buildnegate(exp, context):
428 arg = compileexp(exp[1], context, exprmethods)
432 arg = compileexp(exp[1], context, exprmethods)
429 return (templateutil.runnegate, arg)
433 return (templateutil.runnegate, arg)
430
434
431 def buildarithmetic(exp, context, func):
435 def buildarithmetic(exp, context, func):
432 left = compileexp(exp[1], context, exprmethods)
436 left = compileexp(exp[1], context, exprmethods)
433 right = compileexp(exp[2], context, exprmethods)
437 right = compileexp(exp[2], context, exprmethods)
434 return (templateutil.runarithmetic, (func, left, right))
438 return (templateutil.runarithmetic, (func, left, right))
435
439
436 def buildfunc(exp, context):
440 def buildfunc(exp, context):
437 n = getsymbol(exp[1])
441 n = getsymbol(exp[1])
438 if n in context._funcs:
442 if n in context._funcs:
439 f = context._funcs[n]
443 f = context._funcs[n]
440 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
444 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
441 return (f, args)
445 return (f, args)
442 if n in context._filters:
446 if n in context._filters:
443 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
447 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
444 if len(args) != 1:
448 if len(args) != 1:
445 raise error.ParseError(_("filter %s expects one argument") % n)
449 raise error.ParseError(_("filter %s expects one argument") % n)
446 f = context._filters[n]
450 f = context._filters[n]
447 return (templateutil.runfilter, (args[0], f))
451 return (templateutil.runfilter, (args[0], f))
448 raise error.ParseError(_("unknown function '%s'") % n)
452 raise error.ParseError(_("unknown function '%s'") % n)
449
453
450 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
454 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
451 """Compile parsed tree of function arguments into list or dict of
455 """Compile parsed tree of function arguments into list or dict of
452 (func, data) pairs
456 (func, data) pairs
453
457
454 >>> context = engine(lambda t: (templateutil.runsymbol, t))
458 >>> context = engine(lambda t: (templateutil.runsymbol, t))
455 >>> def fargs(expr, argspec):
459 >>> def fargs(expr, argspec):
456 ... x = _parseexpr(expr)
460 ... x = _parseexpr(expr)
457 ... n = getsymbol(x[1])
461 ... n = getsymbol(x[1])
458 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
462 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
459 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
463 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
460 ['l', 'k']
464 ['l', 'k']
461 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
465 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
462 >>> list(args.keys()), list(args[b'opts'].keys())
466 >>> list(args.keys()), list(args[b'opts'].keys())
463 (['opts'], ['opts', 'k'])
467 (['opts'], ['opts', 'k'])
464 """
468 """
465 def compiledict(xs):
469 def compiledict(xs):
466 return util.sortdict((k, compileexp(x, context, curmethods))
470 return util.sortdict((k, compileexp(x, context, curmethods))
467 for k, x in xs.iteritems())
471 for k, x in xs.iteritems())
468 def compilelist(xs):
472 def compilelist(xs):
469 return [compileexp(x, context, curmethods) for x in xs]
473 return [compileexp(x, context, curmethods) for x in xs]
470
474
471 if not argspec:
475 if not argspec:
472 # filter or function with no argspec: return list of positional args
476 # filter or function with no argspec: return list of positional args
473 return compilelist(getlist(exp))
477 return compilelist(getlist(exp))
474
478
475 # function with argspec: return dict of named args
479 # function with argspec: return dict of named args
476 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
480 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
477 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
481 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
478 keyvaluenode='keyvalue', keynode='symbol')
482 keyvaluenode='keyvalue', keynode='symbol')
479 compargs = util.sortdict()
483 compargs = util.sortdict()
480 if varkey:
484 if varkey:
481 compargs[varkey] = compilelist(treeargs.pop(varkey))
485 compargs[varkey] = compilelist(treeargs.pop(varkey))
482 if optkey:
486 if optkey:
483 compargs[optkey] = compiledict(treeargs.pop(optkey))
487 compargs[optkey] = compiledict(treeargs.pop(optkey))
484 compargs.update(compiledict(treeargs))
488 compargs.update(compiledict(treeargs))
485 return compargs
489 return compargs
486
490
487 def buildkeyvaluepair(exp, content):
491 def buildkeyvaluepair(exp, content):
488 raise error.ParseError(_("can't use a key-value pair in this context"))
492 raise error.ParseError(_("can't use a key-value pair in this context"))
489
493
490 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
494 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
491 exprmethods = {
495 exprmethods = {
492 "integer": lambda e, c: (templateutil.runinteger, e[1]),
496 "integer": lambda e, c: (templateutil.runinteger, e[1]),
493 "string": lambda e, c: (templateutil.runstring, e[1]),
497 "string": lambda e, c: (templateutil.runstring, e[1]),
494 "symbol": lambda e, c: (templateutil.runsymbol, e[1]),
498 "symbol": lambda e, c: (templateutil.runsymbol, e[1]),
495 "template": buildtemplate,
499 "template": buildtemplate,
496 "group": lambda e, c: compileexp(e[1], c, exprmethods),
500 "group": lambda e, c: compileexp(e[1], c, exprmethods),
497 ".": buildmember,
501 ".": buildmember,
498 "|": buildfilter,
502 "|": buildfilter,
499 "%": buildmap,
503 "%": buildmap,
500 "func": buildfunc,
504 "func": buildfunc,
501 "keyvalue": buildkeyvaluepair,
505 "keyvalue": buildkeyvaluepair,
502 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
506 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
503 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
507 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
504 "negate": buildnegate,
508 "negate": buildnegate,
505 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
509 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
506 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
510 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
507 }
511 }
508
512
509 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
513 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
510 methods = exprmethods.copy()
514 methods = exprmethods.copy()
511 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
515 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
512
516
513 class _aliasrules(parser.basealiasrules):
517 class _aliasrules(parser.basealiasrules):
514 """Parsing and expansion rule set of template aliases"""
518 """Parsing and expansion rule set of template aliases"""
515 _section = _('template alias')
519 _section = _('template alias')
516 _parse = staticmethod(_parseexpr)
520 _parse = staticmethod(_parseexpr)
517
521
518 @staticmethod
522 @staticmethod
519 def _trygetfunc(tree):
523 def _trygetfunc(tree):
520 """Return (name, args) if tree is func(...) or ...|filter; otherwise
524 """Return (name, args) if tree is func(...) or ...|filter; otherwise
521 None"""
525 None"""
522 if tree[0] == 'func' and tree[1][0] == 'symbol':
526 if tree[0] == 'func' and tree[1][0] == 'symbol':
523 return tree[1][1], getlist(tree[2])
527 return tree[1][1], getlist(tree[2])
524 if tree[0] == '|' and tree[2][0] == 'symbol':
528 if tree[0] == '|' and tree[2][0] == 'symbol':
525 return tree[2][1], [tree[1]]
529 return tree[2][1], [tree[1]]
526
530
527 def expandaliases(tree, aliases):
531 def expandaliases(tree, aliases):
528 """Return new tree of aliases are expanded"""
532 """Return new tree of aliases are expanded"""
529 aliasmap = _aliasrules.buildmap(aliases)
533 aliasmap = _aliasrules.buildmap(aliases)
530 return _aliasrules.expand(aliasmap, tree)
534 return _aliasrules.expand(aliasmap, tree)
531
535
532 # template engine
536 # template engine
533
537
534 def unquotestring(s):
538 def unquotestring(s):
535 '''unwrap quotes if any; otherwise returns unmodified string'''
539 '''unwrap quotes if any; otherwise returns unmodified string'''
536 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
540 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
537 return s
541 return s
538 return s[1:-1]
542 return s[1:-1]
539
543
540 class resourcemapper(object):
544 class resourcemapper(object):
541 """Mapper of internal template resources"""
545 """Mapper of internal template resources"""
542
546
543 __metaclass__ = abc.ABCMeta
547 __metaclass__ = abc.ABCMeta
544
548
545 @abc.abstractmethod
549 @abc.abstractmethod
546 def availablekeys(self, context, mapping):
550 def availablekeys(self, context, mapping):
547 """Return a set of available resource keys based on the given mapping"""
551 """Return a set of available resource keys based on the given mapping"""
548
552
549 @abc.abstractmethod
553 @abc.abstractmethod
550 def knownkeys(self):
554 def knownkeys(self):
551 """Return a set of supported resource keys"""
555 """Return a set of supported resource keys"""
552
556
553 @abc.abstractmethod
557 @abc.abstractmethod
554 def lookup(self, context, mapping, key):
558 def lookup(self, context, mapping, key):
555 """Return a resource for the key if available; otherwise None"""
559 """Return a resource for the key if available; otherwise None"""
556
560
557 @abc.abstractmethod
561 @abc.abstractmethod
558 def populatemap(self, context, origmapping, newmapping):
562 def populatemap(self, context, origmapping, newmapping):
559 """Return a dict of additional mapping items which should be paired
563 """Return a dict of additional mapping items which should be paired
560 with the given new mapping"""
564 with the given new mapping"""
561
565
562 class nullresourcemapper(resourcemapper):
566 class nullresourcemapper(resourcemapper):
563 def availablekeys(self, context, mapping):
567 def availablekeys(self, context, mapping):
564 return set()
568 return set()
565
569
566 def knownkeys(self):
570 def knownkeys(self):
567 return set()
571 return set()
568
572
569 def lookup(self, context, mapping, key):
573 def lookup(self, context, mapping, key):
570 return None
574 return None
571
575
572 def populatemap(self, context, origmapping, newmapping):
576 def populatemap(self, context, origmapping, newmapping):
573 return {}
577 return {}
574
578
575 class engine(object):
579 class engine(object):
576 '''template expansion engine.
580 '''template expansion engine.
577
581
578 template expansion works like this. a map file contains key=value
582 template expansion works like this. a map file contains key=value
579 pairs. if value is quoted, it is treated as string. otherwise, it
583 pairs. if value is quoted, it is treated as string. otherwise, it
580 is treated as name of template file.
584 is treated as name of template file.
581
585
582 templater is asked to expand a key in map. it looks up key, and
586 templater is asked to expand a key in map. it looks up key, and
583 looks for strings like this: {foo}. it expands {foo} by looking up
587 looks for strings like this: {foo}. it expands {foo} by looking up
584 foo in map, and substituting it. expansion is recursive: it stops
588 foo in map, and substituting it. expansion is recursive: it stops
585 when there is no more {foo} to replace.
589 when there is no more {foo} to replace.
586
590
587 expansion also allows formatting and filtering.
591 expansion also allows formatting and filtering.
588
592
589 format uses key to expand each item in list. syntax is
593 format uses key to expand each item in list. syntax is
590 {key%format}.
594 {key%format}.
591
595
592 filter uses function to transform value. syntax is
596 filter uses function to transform value. syntax is
593 {key|filter1|filter2|...}.'''
597 {key|filter1|filter2|...}.'''
594
598
595 def __init__(self, loader, filters=None, defaults=None, resources=None,
599 def __init__(self, loader, filters=None, defaults=None, resources=None,
596 aliases=()):
600 aliases=()):
597 self._loader = loader
601 self._loader = loader
598 if filters is None:
602 if filters is None:
599 filters = {}
603 filters = {}
600 self._filters = filters
604 self._filters = filters
601 self._funcs = templatefuncs.funcs # make this a parameter if needed
605 self._funcs = templatefuncs.funcs # make this a parameter if needed
602 if defaults is None:
606 if defaults is None:
603 defaults = {}
607 defaults = {}
604 if resources is None:
608 if resources is None:
605 resources = nullresourcemapper()
609 resources = nullresourcemapper()
606 self._defaults = defaults
610 self._defaults = defaults
607 self._resources = resources
611 self._resources = resources
608 self._aliasmap = _aliasrules.buildmap(aliases)
612 self._aliasmap = _aliasrules.buildmap(aliases)
609 self._cache = {} # key: (func, data)
613 self._cache = {} # key: (func, data)
610 self._tmplcache = {} # literal template: (func, data)
614 self._tmplcache = {} # literal template: (func, data)
611
615
612 def overlaymap(self, origmapping, newmapping):
616 def overlaymap(self, origmapping, newmapping):
613 """Create combined mapping from the original mapping and partial
617 """Create combined mapping from the original mapping and partial
614 mapping to override the original"""
618 mapping to override the original"""
615 # do not copy symbols which overrides the defaults depending on
619 # do not copy symbols which overrides the defaults depending on
616 # new resources, so the defaults will be re-evaluated (issue5612)
620 # new resources, so the defaults will be re-evaluated (issue5612)
617 knownres = self._resources.knownkeys()
621 knownres = self._resources.knownkeys()
618 newres = self._resources.availablekeys(self, newmapping)
622 newres = self._resources.availablekeys(self, newmapping)
619 mapping = {k: v for k, v in origmapping.iteritems()
623 mapping = {k: v for k, v in origmapping.iteritems()
620 if (k in knownres # not a symbol per self.symbol()
624 if (k in knownres # not a symbol per self.symbol()
621 or newres.isdisjoint(self._defaultrequires(k)))}
625 or newres.isdisjoint(self._defaultrequires(k)))}
622 mapping.update(newmapping)
626 mapping.update(newmapping)
623 mapping.update(
627 mapping.update(
624 self._resources.populatemap(self, origmapping, newmapping))
628 self._resources.populatemap(self, origmapping, newmapping))
625 return mapping
629 return mapping
626
630
627 def _defaultrequires(self, key):
631 def _defaultrequires(self, key):
628 """Resource keys required by the specified default symbol function"""
632 """Resource keys required by the specified default symbol function"""
629 v = self._defaults.get(key)
633 v = self._defaults.get(key)
630 if v is None or not callable(v):
634 if v is None or not callable(v):
631 return ()
635 return ()
632 return getattr(v, '_requires', ())
636 return getattr(v, '_requires', ())
633
637
634 def symbol(self, mapping, key):
638 def symbol(self, mapping, key):
635 """Resolve symbol to value or function; None if nothing found"""
639 """Resolve symbol to value or function; None if nothing found"""
636 v = None
640 v = None
637 if key not in self._resources.knownkeys():
641 if key not in self._resources.knownkeys():
638 v = mapping.get(key)
642 v = mapping.get(key)
639 if v is None:
643 if v is None:
640 v = self._defaults.get(key)
644 v = self._defaults.get(key)
641 return v
645 return v
642
646
643 def resource(self, mapping, key):
647 def resource(self, mapping, key):
644 """Return internal data (e.g. cache) used for keyword/function
648 """Return internal data (e.g. cache) used for keyword/function
645 evaluation"""
649 evaluation"""
646 v = self._resources.lookup(self, mapping, key)
650 v = self._resources.lookup(self, mapping, key)
647 if v is None:
651 if v is None:
648 raise templateutil.ResourceUnavailable(
652 raise templateutil.ResourceUnavailable(
649 _('template resource not available: %s') % key)
653 _('template resource not available: %s') % key)
650 return v
654 return v
651
655
652 def _load(self, t):
656 def _load(self, t):
653 '''load, parse, and cache a template'''
657 '''load, parse, and cache a template'''
654 if t not in self._cache:
658 if t not in self._cache:
655 # put poison to cut recursion while compiling 't'
659 # put poison to cut recursion while compiling 't'
656 self._cache[t] = (_runrecursivesymbol, t)
660 self._cache[t] = (_runrecursivesymbol, t)
657 try:
661 try:
658 x = parse(self._loader(t))
662 x = parse(self._loader(t))
659 if self._aliasmap:
663 if self._aliasmap:
660 x = _aliasrules.expand(self._aliasmap, x)
664 x = _aliasrules.expand(self._aliasmap, x)
661 self._cache[t] = compileexp(x, self, methods)
665 self._cache[t] = compileexp(x, self, methods)
662 except: # re-raises
666 except: # re-raises
663 del self._cache[t]
667 del self._cache[t]
664 raise
668 raise
665 return self._cache[t]
669 return self._cache[t]
666
670
667 def _parse(self, tmpl):
671 def _parse(self, tmpl):
668 """Parse and cache a literal template"""
672 """Parse and cache a literal template"""
669 if tmpl not in self._tmplcache:
673 if tmpl not in self._tmplcache:
670 x = parse(tmpl)
674 x = parse(tmpl)
671 self._tmplcache[tmpl] = compileexp(x, self, methods)
675 self._tmplcache[tmpl] = compileexp(x, self, methods)
672 return self._tmplcache[tmpl]
676 return self._tmplcache[tmpl]
673
677
674 def preload(self, t):
678 def preload(self, t):
675 """Load, parse, and cache the specified template if available"""
679 """Load, parse, and cache the specified template if available"""
676 try:
680 try:
677 self._load(t)
681 self._load(t)
678 return True
682 return True
679 except templateutil.TemplateNotFound:
683 except templateutil.TemplateNotFound:
680 return False
684 return False
681
685
682 def process(self, t, mapping):
686 def process(self, t, mapping):
683 '''Perform expansion. t is name of map element to expand.
687 '''Perform expansion. t is name of map element to expand.
684 mapping contains added elements for use during expansion. Is a
688 mapping contains added elements for use during expansion. Is a
685 generator.'''
689 generator.'''
686 func, data = self._load(t)
690 func, data = self._load(t)
687 return self._expand(func, data, mapping)
691 return self._expand(func, data, mapping)
688
692
689 def expand(self, tmpl, mapping):
693 def expand(self, tmpl, mapping):
690 """Perform expansion over a literal template
694 """Perform expansion over a literal template
691
695
692 No user aliases will be expanded since this is supposed to be called
696 No user aliases will be expanded since this is supposed to be called
693 with an internal template string.
697 with an internal template string.
694 """
698 """
695 func, data = self._parse(tmpl)
699 func, data = self._parse(tmpl)
696 return self._expand(func, data, mapping)
700 return self._expand(func, data, mapping)
697
701
698 def _expand(self, func, data, mapping):
702 def _expand(self, func, data, mapping):
699 # populate additional items only if they don't exist in the given
703 # populate additional items only if they don't exist in the given
700 # mapping. this is slightly different from overlaymap() because the
704 # mapping. this is slightly different from overlaymap() because the
701 # initial 'revcache' may contain pre-computed items.
705 # initial 'revcache' may contain pre-computed items.
702 extramapping = self._resources.populatemap(self, {}, mapping)
706 extramapping = self._resources.populatemap(self, {}, mapping)
703 if extramapping:
707 if extramapping:
704 extramapping.update(mapping)
708 extramapping.update(mapping)
705 mapping = extramapping
709 mapping = extramapping
706 return templateutil.flatten(self, mapping, func(self, mapping, data))
710 return templateutil.flatten(self, mapping, func(self, mapping, data))
707
711
708 engines = {'default': engine}
712 engines = {'default': engine}
709
713
710 def stylelist():
714 def stylelist():
711 paths = templatepaths()
715 paths = templatepaths()
712 if not paths:
716 if not paths:
713 return _('no templates found, try `hg debuginstall` for more info')
717 return _('no templates found, try `hg debuginstall` for more info')
714 dirlist = os.listdir(paths[0])
718 dirlist = os.listdir(paths[0])
715 stylelist = []
719 stylelist = []
716 for file in dirlist:
720 for file in dirlist:
717 split = file.split(".")
721 split = file.split(".")
718 if split[-1] in ('orig', 'rej'):
722 if split[-1] in ('orig', 'rej'):
719 continue
723 continue
720 if split[0] == "map-cmdline":
724 if split[0] == "map-cmdline":
721 stylelist.append(split[1])
725 stylelist.append(split[1])
722 return ", ".join(sorted(stylelist))
726 return ", ".join(sorted(stylelist))
723
727
724 def _readmapfile(mapfile):
728 def _readmapfile(mapfile):
725 """Load template elements from the given map file"""
729 """Load template elements from the given map file"""
726 if not os.path.exists(mapfile):
730 if not os.path.exists(mapfile):
727 raise error.Abort(_("style '%s' not found") % mapfile,
731 raise error.Abort(_("style '%s' not found") % mapfile,
728 hint=_("available styles: %s") % stylelist())
732 hint=_("available styles: %s") % stylelist())
729
733
730 base = os.path.dirname(mapfile)
734 base = os.path.dirname(mapfile)
731 conf = config.config(includepaths=templatepaths())
735 conf = config.config(includepaths=templatepaths())
732 conf.read(mapfile, remap={'': 'templates'})
736 conf.read(mapfile, remap={'': 'templates'})
733
737
734 cache = {}
738 cache = {}
735 tmap = {}
739 tmap = {}
736 aliases = []
740 aliases = []
737
741
738 val = conf.get('templates', '__base__')
742 val = conf.get('templates', '__base__')
739 if val and val[0] not in "'\"":
743 if val and val[0] not in "'\"":
740 # treat as a pointer to a base class for this style
744 # treat as a pointer to a base class for this style
741 path = util.normpath(os.path.join(base, val))
745 path = util.normpath(os.path.join(base, val))
742
746
743 # fallback check in template paths
747 # fallback check in template paths
744 if not os.path.exists(path):
748 if not os.path.exists(path):
745 for p in templatepaths():
749 for p in templatepaths():
746 p2 = util.normpath(os.path.join(p, val))
750 p2 = util.normpath(os.path.join(p, val))
747 if os.path.isfile(p2):
751 if os.path.isfile(p2):
748 path = p2
752 path = p2
749 break
753 break
750 p3 = util.normpath(os.path.join(p2, "map"))
754 p3 = util.normpath(os.path.join(p2, "map"))
751 if os.path.isfile(p3):
755 if os.path.isfile(p3):
752 path = p3
756 path = p3
753 break
757 break
754
758
755 cache, tmap, aliases = _readmapfile(path)
759 cache, tmap, aliases = _readmapfile(path)
756
760
757 for key, val in conf['templates'].items():
761 for key, val in conf['templates'].items():
758 if not val:
762 if not val:
759 raise error.ParseError(_('missing value'),
763 raise error.ParseError(_('missing value'),
760 conf.source('templates', key))
764 conf.source('templates', key))
761 if val[0] in "'\"":
765 if val[0] in "'\"":
762 if val[0] != val[-1]:
766 if val[0] != val[-1]:
763 raise error.ParseError(_('unmatched quotes'),
767 raise error.ParseError(_('unmatched quotes'),
764 conf.source('templates', key))
768 conf.source('templates', key))
765 cache[key] = unquotestring(val)
769 cache[key] = unquotestring(val)
766 elif key != '__base__':
770 elif key != '__base__':
767 val = 'default', val
771 val = 'default', val
768 if ':' in val[1]:
772 if ':' in val[1]:
769 val = val[1].split(':', 1)
773 val = val[1].split(':', 1)
770 tmap[key] = val[0], os.path.join(base, val[1])
774 tmap[key] = val[0], os.path.join(base, val[1])
771 aliases.extend(conf['templatealias'].items())
775 aliases.extend(conf['templatealias'].items())
772 return cache, tmap, aliases
776 return cache, tmap, aliases
773
777
774 class templater(object):
778 class templater(object):
775
779
776 def __init__(self, filters=None, defaults=None, resources=None,
780 def __init__(self, filters=None, defaults=None, resources=None,
777 cache=None, aliases=(), minchunk=1024, maxchunk=65536):
781 cache=None, aliases=(), minchunk=1024, maxchunk=65536):
778 """Create template engine optionally with preloaded template fragments
782 """Create template engine optionally with preloaded template fragments
779
783
780 - ``filters``: a dict of functions to transform a value into another.
784 - ``filters``: a dict of functions to transform a value into another.
781 - ``defaults``: a dict of symbol values/functions; may be overridden
785 - ``defaults``: a dict of symbol values/functions; may be overridden
782 by a ``mapping`` dict.
786 by a ``mapping`` dict.
783 - ``resources``: a resourcemapper object to look up internal data
787 - ``resources``: a resourcemapper object to look up internal data
784 (e.g. cache), inaccessible from user template.
788 (e.g. cache), inaccessible from user template.
785 - ``cache``: a dict of preloaded template fragments.
789 - ``cache``: a dict of preloaded template fragments.
786 - ``aliases``: a list of alias (name, replacement) pairs.
790 - ``aliases``: a list of alias (name, replacement) pairs.
787
791
788 self.cache may be updated later to register additional template
792 self.cache may be updated later to register additional template
789 fragments.
793 fragments.
790 """
794 """
791 if filters is None:
795 if filters is None:
792 filters = {}
796 filters = {}
793 if defaults is None:
797 if defaults is None:
794 defaults = {}
798 defaults = {}
795 if cache is None:
799 if cache is None:
796 cache = {}
800 cache = {}
797 self.cache = cache.copy()
801 self.cache = cache.copy()
798 self.map = {}
802 self.map = {}
799 self.filters = templatefilters.filters.copy()
803 self.filters = templatefilters.filters.copy()
800 self.filters.update(filters)
804 self.filters.update(filters)
801 self.defaults = defaults
805 self.defaults = defaults
802 self._resources = resources
806 self._resources = resources
803 self._aliases = aliases
807 self._aliases = aliases
804 self.minchunk, self.maxchunk = minchunk, maxchunk
808 self.minchunk, self.maxchunk = minchunk, maxchunk
805 self.ecache = {}
809 self.ecache = {}
806
810
807 @classmethod
811 @classmethod
808 def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
812 def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
809 cache=None, minchunk=1024, maxchunk=65536):
813 cache=None, minchunk=1024, maxchunk=65536):
810 """Create templater from the specified map file"""
814 """Create templater from the specified map file"""
811 t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk)
815 t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk)
812 cache, tmap, aliases = _readmapfile(mapfile)
816 cache, tmap, aliases = _readmapfile(mapfile)
813 t.cache.update(cache)
817 t.cache.update(cache)
814 t.map = tmap
818 t.map = tmap
815 t._aliases = aliases
819 t._aliases = aliases
816 return t
820 return t
817
821
818 def __contains__(self, key):
822 def __contains__(self, key):
819 return key in self.cache or key in self.map
823 return key in self.cache or key in self.map
820
824
821 def load(self, t):
825 def load(self, t):
822 '''Get the template for the given template name. Use a local cache.'''
826 '''Get the template for the given template name. Use a local cache.'''
823 if t not in self.cache:
827 if t not in self.cache:
824 try:
828 try:
825 self.cache[t] = util.readfile(self.map[t][1])
829 self.cache[t] = util.readfile(self.map[t][1])
826 except KeyError as inst:
830 except KeyError as inst:
827 raise templateutil.TemplateNotFound(
831 raise templateutil.TemplateNotFound(
828 _('"%s" not in template map') % inst.args[0])
832 _('"%s" not in template map') % inst.args[0])
829 except IOError as inst:
833 except IOError as inst:
830 reason = (_('template file %s: %s')
834 reason = (_('template file %s: %s')
831 % (self.map[t][1],
835 % (self.map[t][1],
832 stringutil.forcebytestr(inst.args[1])))
836 stringutil.forcebytestr(inst.args[1])))
833 raise IOError(inst.args[0], encoding.strfromlocal(reason))
837 raise IOError(inst.args[0], encoding.strfromlocal(reason))
834 return self.cache[t]
838 return self.cache[t]
835
839
836 def renderdefault(self, mapping):
840 def renderdefault(self, mapping):
837 """Render the default unnamed template and return result as string"""
841 """Render the default unnamed template and return result as string"""
838 return self.render('', mapping)
842 return self.render('', mapping)
839
843
840 def render(self, t, mapping):
844 def render(self, t, mapping):
841 """Render the specified named template and return result as string"""
845 """Render the specified named template and return result as string"""
842 return b''.join(self.generate(t, mapping))
846 return b''.join(self.generate(t, mapping))
843
847
844 def generate(self, t, mapping):
848 def generate(self, t, mapping):
845 """Return a generator that renders the specified named template and
849 """Return a generator that renders the specified named template and
846 yields chunks"""
850 yields chunks"""
847 ttype = t in self.map and self.map[t][0] or 'default'
851 ttype = t in self.map and self.map[t][0] or 'default'
848 if ttype not in self.ecache:
852 if ttype not in self.ecache:
849 try:
853 try:
850 ecls = engines[ttype]
854 ecls = engines[ttype]
851 except KeyError:
855 except KeyError:
852 raise error.Abort(_('invalid template engine: %s') % ttype)
856 raise error.Abort(_('invalid template engine: %s') % ttype)
853 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
857 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
854 self._resources, self._aliases)
858 self._resources, self._aliases)
855 proc = self.ecache[ttype]
859 proc = self.ecache[ttype]
856
860
857 stream = proc.process(t, mapping)
861 stream = proc.process(t, mapping)
858 if self.minchunk:
862 if self.minchunk:
859 stream = util.increasingchunks(stream, min=self.minchunk,
863 stream = util.increasingchunks(stream, min=self.minchunk,
860 max=self.maxchunk)
864 max=self.maxchunk)
861 return stream
865 return stream
862
866
863 def templatepaths():
867 def templatepaths():
864 '''return locations used for template files.'''
868 '''return locations used for template files.'''
865 pathsrel = ['templates']
869 pathsrel = ['templates']
866 paths = [os.path.normpath(os.path.join(util.datapath, f))
870 paths = [os.path.normpath(os.path.join(util.datapath, f))
867 for f in pathsrel]
871 for f in pathsrel]
868 return [p for p in paths if os.path.isdir(p)]
872 return [p for p in paths if os.path.isdir(p)]
869
873
870 def templatepath(name):
874 def templatepath(name):
871 '''return location of template file. returns None if not found.'''
875 '''return location of template file. returns None if not found.'''
872 for p in templatepaths():
876 for p in templatepaths():
873 f = os.path.join(p, name)
877 f = os.path.join(p, name)
874 if os.path.exists(f):
878 if os.path.exists(f):
875 return f
879 return f
876 return None
880 return None
877
881
878 def stylemap(styles, paths=None):
882 def stylemap(styles, paths=None):
879 """Return path to mapfile for a given style.
883 """Return path to mapfile for a given style.
880
884
881 Searches mapfile in the following locations:
885 Searches mapfile in the following locations:
882 1. templatepath/style/map
886 1. templatepath/style/map
883 2. templatepath/map-style
887 2. templatepath/map-style
884 3. templatepath/map
888 3. templatepath/map
885 """
889 """
886
890
887 if paths is None:
891 if paths is None:
888 paths = templatepaths()
892 paths = templatepaths()
889 elif isinstance(paths, bytes):
893 elif isinstance(paths, bytes):
890 paths = [paths]
894 paths = [paths]
891
895
892 if isinstance(styles, bytes):
896 if isinstance(styles, bytes):
893 styles = [styles]
897 styles = [styles]
894
898
895 for style in styles:
899 for style in styles:
896 # only plain name is allowed to honor template paths
900 # only plain name is allowed to honor template paths
897 if (not style
901 if (not style
898 or style in (pycompat.oscurdir, pycompat.ospardir)
902 or style in (pycompat.oscurdir, pycompat.ospardir)
899 or pycompat.ossep in style
903 or pycompat.ossep in style
900 or pycompat.osaltsep and pycompat.osaltsep in style):
904 or pycompat.osaltsep and pycompat.osaltsep in style):
901 continue
905 continue
902 locations = [os.path.join(style, 'map'), 'map-' + style]
906 locations = [os.path.join(style, 'map'), 'map-' + style]
903 locations.append('map')
907 locations.append('map')
904
908
905 for path in paths:
909 for path in paths:
906 for location in locations:
910 for location in locations:
907 mapfile = os.path.join(path, location)
911 mapfile = os.path.join(path, location)
908 if os.path.isfile(mapfile):
912 if os.path.isfile(mapfile):
909 return style, mapfile
913 return style, mapfile
910
914
911 raise RuntimeError("No hgweb templates found in %r" % paths)
915 raise RuntimeError("No hgweb templates found in %r" % paths)
@@ -1,650 +1,682
1 # templateutil.py - utility for template evaluation
1 # templateutil.py - utility for template evaluation
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import abc
10 import abc
11 import types
11 import types
12
12
13 from .i18n import _
13 from .i18n import _
14 from . import (
14 from . import (
15 error,
15 error,
16 pycompat,
16 pycompat,
17 util,
17 util,
18 )
18 )
19 from .utils import (
19 from .utils import (
20 dateutil,
20 dateutil,
21 stringutil,
21 stringutil,
22 )
22 )
23
23
24 class ResourceUnavailable(error.Abort):
24 class ResourceUnavailable(error.Abort):
25 pass
25 pass
26
26
27 class TemplateNotFound(error.Abort):
27 class TemplateNotFound(error.Abort):
28 pass
28 pass
29
29
30 class wrapped(object):
30 class wrapped(object):
31 """Object requiring extra conversion prior to displaying or processing
31 """Object requiring extra conversion prior to displaying or processing
32 as value
32 as value
33
33
34 Use unwrapvalue(), unwrapastype(), or unwraphybrid() to obtain the inner
34 Use unwrapvalue(), unwrapastype(), or unwraphybrid() to obtain the inner
35 object.
35 object.
36 """
36 """
37
37
38 __metaclass__ = abc.ABCMeta
38 __metaclass__ = abc.ABCMeta
39
39
40 @abc.abstractmethod
40 @abc.abstractmethod
41 def itermaps(self, context):
41 def itermaps(self, context):
42 """Yield each template mapping"""
42 """Yield each template mapping"""
43
43
44 @abc.abstractmethod
44 @abc.abstractmethod
45 def join(self, context, mapping, sep):
45 def join(self, context, mapping, sep):
46 """Join items with the separator; Returns a bytes or (possibly nested)
46 """Join items with the separator; Returns a bytes or (possibly nested)
47 generator of bytes
47 generator of bytes
48
48
49 A pre-configured template may be rendered per item if this container
49 A pre-configured template may be rendered per item if this container
50 holds unprintable items.
50 holds unprintable items.
51 """
51 """
52
52
53 @abc.abstractmethod
53 @abc.abstractmethod
54 def show(self, context, mapping):
54 def show(self, context, mapping):
55 """Return a bytes or (possibly nested) generator of bytes representing
55 """Return a bytes or (possibly nested) generator of bytes representing
56 the underlying object
56 the underlying object
57
57
58 A pre-configured template may be rendered if the underlying object is
58 A pre-configured template may be rendered if the underlying object is
59 not printable.
59 not printable.
60 """
60 """
61
61
62 @abc.abstractmethod
62 @abc.abstractmethod
63 def tovalue(self, context, mapping):
63 def tovalue(self, context, mapping):
64 """Move the inner value object out or create a value representation
64 """Move the inner value object out or create a value representation
65
65
66 A returned value must be serializable by templaterfilters.json().
66 A returned value must be serializable by templaterfilters.json().
67 """
67 """
68
68
69 # stub for representing a date type; may be a real date type that can
69 # stub for representing a date type; may be a real date type that can
70 # provide a readable string value
70 # provide a readable string value
71 class date(object):
71 class date(object):
72 pass
72 pass
73
73
74 class hybrid(wrapped):
74 class hybrid(wrapped):
75 """Wrapper for list or dict to support legacy template
75 """Wrapper for list or dict to support legacy template
76
76
77 This class allows us to handle both:
77 This class allows us to handle both:
78 - "{files}" (legacy command-line-specific list hack) and
78 - "{files}" (legacy command-line-specific list hack) and
79 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
79 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
80 and to access raw values:
80 and to access raw values:
81 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
81 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
82 - "{get(extras, key)}"
82 - "{get(extras, key)}"
83 - "{files|json}"
83 - "{files|json}"
84 """
84 """
85
85
86 def __init__(self, gen, values, makemap, joinfmt, keytype=None):
86 def __init__(self, gen, values, makemap, joinfmt, keytype=None):
87 self._gen = gen # generator or function returning generator
87 self._gen = gen # generator or function returning generator
88 self._values = values
88 self._values = values
89 self._makemap = makemap
89 self._makemap = makemap
90 self._joinfmt = joinfmt
90 self._joinfmt = joinfmt
91 self.keytype = keytype # hint for 'x in y' where type(x) is unresolved
91 self.keytype = keytype # hint for 'x in y' where type(x) is unresolved
92
92
93 def itermaps(self, context):
93 def itermaps(self, context):
94 makemap = self._makemap
94 makemap = self._makemap
95 for x in self._values:
95 for x in self._values:
96 yield makemap(x)
96 yield makemap(x)
97
97
98 def join(self, context, mapping, sep):
98 def join(self, context, mapping, sep):
99 # TODO: switch gen to (context, mapping) API?
99 # TODO: switch gen to (context, mapping) API?
100 return joinitems((self._joinfmt(x) for x in self._values), sep)
100 return joinitems((self._joinfmt(x) for x in self._values), sep)
101
101
102 def show(self, context, mapping):
102 def show(self, context, mapping):
103 # TODO: switch gen to (context, mapping) API?
103 # TODO: switch gen to (context, mapping) API?
104 gen = self._gen
104 gen = self._gen
105 if gen is None:
105 if gen is None:
106 return self.join(context, mapping, ' ')
106 return self.join(context, mapping, ' ')
107 if callable(gen):
107 if callable(gen):
108 return gen()
108 return gen()
109 return gen
109 return gen
110
110
111 def tovalue(self, context, mapping):
111 def tovalue(self, context, mapping):
112 # TODO: return self._values and get rid of proxy methods
112 # TODO: return self._values and get rid of proxy methods
113 return self
113 return self
114
114
115 def __contains__(self, x):
115 def __contains__(self, x):
116 return x in self._values
116 return x in self._values
117 def __getitem__(self, key):
117 def __getitem__(self, key):
118 return self._values[key]
118 return self._values[key]
119 def __len__(self):
119 def __len__(self):
120 return len(self._values)
120 return len(self._values)
121 def __iter__(self):
121 def __iter__(self):
122 return iter(self._values)
122 return iter(self._values)
123 def __getattr__(self, name):
123 def __getattr__(self, name):
124 if name not in (r'get', r'items', r'iteritems', r'iterkeys',
124 if name not in (r'get', r'items', r'iteritems', r'iterkeys',
125 r'itervalues', r'keys', r'values'):
125 r'itervalues', r'keys', r'values'):
126 raise AttributeError(name)
126 raise AttributeError(name)
127 return getattr(self._values, name)
127 return getattr(self._values, name)
128
128
129 class mappable(wrapped):
129 class mappable(wrapped):
130 """Wrapper for non-list/dict object to support map operation
130 """Wrapper for non-list/dict object to support map operation
131
131
132 This class allows us to handle both:
132 This class allows us to handle both:
133 - "{manifest}"
133 - "{manifest}"
134 - "{manifest % '{rev}:{node}'}"
134 - "{manifest % '{rev}:{node}'}"
135 - "{manifest.rev}"
135 - "{manifest.rev}"
136
136
137 Unlike a hybrid, this does not simulate the behavior of the underling
137 Unlike a hybrid, this does not simulate the behavior of the underling
138 value.
138 value.
139 """
139 """
140
140
141 def __init__(self, gen, key, value, makemap):
141 def __init__(self, gen, key, value, makemap):
142 self._gen = gen # generator or function returning generator
142 self._gen = gen # generator or function returning generator
143 self._key = key
143 self._key = key
144 self._value = value # may be generator of strings
144 self._value = value # may be generator of strings
145 self._makemap = makemap
145 self._makemap = makemap
146
146
147 def tomap(self):
147 def tomap(self):
148 return self._makemap(self._key)
148 return self._makemap(self._key)
149
149
150 def itermaps(self, context):
150 def itermaps(self, context):
151 yield self.tomap()
151 yield self.tomap()
152
152
153 def join(self, context, mapping, sep):
153 def join(self, context, mapping, sep):
154 # TODO: just copies the old behavior where a value was a generator
154 # TODO: just copies the old behavior where a value was a generator
155 # yielding one item, but reconsider about it. join() over a string
155 # yielding one item, but reconsider about it. join() over a string
156 # has no consistent result because a string may be a bytes, or a
156 # has no consistent result because a string may be a bytes, or a
157 # generator yielding an item, or a generator yielding multiple items.
157 # generator yielding an item, or a generator yielding multiple items.
158 # Preserving all of the current behaviors wouldn't make any sense.
158 # Preserving all of the current behaviors wouldn't make any sense.
159 return self.show(context, mapping)
159 return self.show(context, mapping)
160
160
161 def show(self, context, mapping):
161 def show(self, context, mapping):
162 # TODO: switch gen to (context, mapping) API?
162 # TODO: switch gen to (context, mapping) API?
163 gen = self._gen
163 gen = self._gen
164 if gen is None:
164 if gen is None:
165 return pycompat.bytestr(self._value)
165 return pycompat.bytestr(self._value)
166 if callable(gen):
166 if callable(gen):
167 return gen()
167 return gen()
168 return gen
168 return gen
169
169
170 def tovalue(self, context, mapping):
170 def tovalue(self, context, mapping):
171 return _unthunk(context, mapping, self._value)
171 return _unthunk(context, mapping, self._value)
172
172
173 class _mappingsequence(wrapped):
173 class _mappingsequence(wrapped):
174 """Wrapper for sequence of template mappings
174 """Wrapper for sequence of template mappings
175
175
176 This represents an inner template structure (i.e. a list of dicts),
176 This represents an inner template structure (i.e. a list of dicts),
177 which can also be rendered by the specified named/literal template.
177 which can also be rendered by the specified named/literal template.
178
178
179 Template mappings may be nested.
179 Template mappings may be nested.
180 """
180 """
181
181
182 def __init__(self, name=None, tmpl=None, sep=''):
182 def __init__(self, name=None, tmpl=None, sep=''):
183 if name is not None and tmpl is not None:
183 if name is not None and tmpl is not None:
184 raise error.ProgrammingError('name and tmpl are mutually exclusive')
184 raise error.ProgrammingError('name and tmpl are mutually exclusive')
185 self._name = name
185 self._name = name
186 self._tmpl = tmpl
186 self._tmpl = tmpl
187 self._defaultsep = sep
187 self._defaultsep = sep
188
188
189 def join(self, context, mapping, sep):
189 def join(self, context, mapping, sep):
190 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
190 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
191 if self._name:
191 if self._name:
192 itemiter = (context.process(self._name, m) for m in mapsiter)
192 itemiter = (context.process(self._name, m) for m in mapsiter)
193 elif self._tmpl:
193 elif self._tmpl:
194 itemiter = (context.expand(self._tmpl, m) for m in mapsiter)
194 itemiter = (context.expand(self._tmpl, m) for m in mapsiter)
195 else:
195 else:
196 raise error.ParseError(_('not displayable without template'))
196 raise error.ParseError(_('not displayable without template'))
197 return joinitems(itemiter, sep)
197 return joinitems(itemiter, sep)
198
198
199 def show(self, context, mapping):
199 def show(self, context, mapping):
200 return self.join(context, mapping, self._defaultsep)
200 return self.join(context, mapping, self._defaultsep)
201
201
202 def tovalue(self, context, mapping):
202 def tovalue(self, context, mapping):
203 return list(self.itermaps(context))
203 return list(self.itermaps(context))
204
204
205 class mappinggenerator(_mappingsequence):
205 class mappinggenerator(_mappingsequence):
206 """Wrapper for generator of template mappings
206 """Wrapper for generator of template mappings
207
207
208 The function ``make(context, *args)`` should return a generator of
208 The function ``make(context, *args)`` should return a generator of
209 mapping dicts.
209 mapping dicts.
210 """
210 """
211
211
212 def __init__(self, make, args=(), name=None, tmpl=None, sep=''):
212 def __init__(self, make, args=(), name=None, tmpl=None, sep=''):
213 super(mappinggenerator, self).__init__(name, tmpl, sep)
213 super(mappinggenerator, self).__init__(name, tmpl, sep)
214 self._make = make
214 self._make = make
215 self._args = args
215 self._args = args
216
216
217 def itermaps(self, context):
217 def itermaps(self, context):
218 return self._make(context, *self._args)
218 return self._make(context, *self._args)
219
219
220 class mappinglist(_mappingsequence):
220 class mappinglist(_mappingsequence):
221 """Wrapper for list of template mappings"""
221 """Wrapper for list of template mappings"""
222
222
223 def __init__(self, mappings, name=None, tmpl=None, sep=''):
223 def __init__(self, mappings, name=None, tmpl=None, sep=''):
224 super(mappinglist, self).__init__(name, tmpl, sep)
224 super(mappinglist, self).__init__(name, tmpl, sep)
225 self._mappings = mappings
225 self._mappings = mappings
226
226
227 def itermaps(self, context):
227 def itermaps(self, context):
228 return iter(self._mappings)
228 return iter(self._mappings)
229
229
230 class mappedgenerator(wrapped):
231 """Wrapper for generator of strings which acts as a list
232
233 The function ``make(context, *args)`` should return a generator of
234 byte strings, or a generator of (possibly nested) generators of byte
235 strings (i.e. a generator for a list of byte strings.)
236 """
237
238 def __init__(self, make, args=()):
239 self._make = make
240 self._args = args
241
242 def _gen(self, context):
243 return self._make(context, *self._args)
244
245 def itermaps(self, context):
246 raise error.ParseError(_('list of strings is not mappable'))
247
248 def join(self, context, mapping, sep):
249 return joinitems(self._gen(context), sep)
250
251 def show(self, context, mapping):
252 return self.join(context, mapping, '')
253
254 def tovalue(self, context, mapping):
255 return [stringify(context, mapping, x) for x in self._gen(context)]
256
230 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
257 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
231 """Wrap data to support both dict-like and string-like operations"""
258 """Wrap data to support both dict-like and string-like operations"""
232 prefmt = pycompat.identity
259 prefmt = pycompat.identity
233 if fmt is None:
260 if fmt is None:
234 fmt = '%s=%s'
261 fmt = '%s=%s'
235 prefmt = pycompat.bytestr
262 prefmt = pycompat.bytestr
236 return hybrid(gen, data, lambda k: {key: k, value: data[k]},
263 return hybrid(gen, data, lambda k: {key: k, value: data[k]},
237 lambda k: fmt % (prefmt(k), prefmt(data[k])))
264 lambda k: fmt % (prefmt(k), prefmt(data[k])))
238
265
239 def hybridlist(data, name, fmt=None, gen=None):
266 def hybridlist(data, name, fmt=None, gen=None):
240 """Wrap data to support both list-like and string-like operations"""
267 """Wrap data to support both list-like and string-like operations"""
241 prefmt = pycompat.identity
268 prefmt = pycompat.identity
242 if fmt is None:
269 if fmt is None:
243 fmt = '%s'
270 fmt = '%s'
244 prefmt = pycompat.bytestr
271 prefmt = pycompat.bytestr
245 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
272 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
246
273
247 def unwraphybrid(context, mapping, thing):
274 def unwraphybrid(context, mapping, thing):
248 """Return an object which can be stringified possibly by using a legacy
275 """Return an object which can be stringified possibly by using a legacy
249 template"""
276 template"""
250 if not isinstance(thing, wrapped):
277 if not isinstance(thing, wrapped):
251 return thing
278 return thing
252 return thing.show(context, mapping)
279 return thing.show(context, mapping)
253
280
254 def unwrapvalue(context, mapping, thing):
281 def unwrapvalue(context, mapping, thing):
255 """Move the inner value object out of the wrapper"""
282 """Move the inner value object out of the wrapper"""
256 if not isinstance(thing, wrapped):
283 if not isinstance(thing, wrapped):
257 return thing
284 return thing
258 return thing.tovalue(context, mapping)
285 return thing.tovalue(context, mapping)
259
286
260 def wraphybridvalue(container, key, value):
287 def wraphybridvalue(container, key, value):
261 """Wrap an element of hybrid container to be mappable
288 """Wrap an element of hybrid container to be mappable
262
289
263 The key is passed to the makemap function of the given container, which
290 The key is passed to the makemap function of the given container, which
264 should be an item generated by iter(container).
291 should be an item generated by iter(container).
265 """
292 """
266 makemap = getattr(container, '_makemap', None)
293 makemap = getattr(container, '_makemap', None)
267 if makemap is None:
294 if makemap is None:
268 return value
295 return value
269 if util.safehasattr(value, '_makemap'):
296 if util.safehasattr(value, '_makemap'):
270 # a nested hybrid list/dict, which has its own way of map operation
297 # a nested hybrid list/dict, which has its own way of map operation
271 return value
298 return value
272 return mappable(None, key, value, makemap)
299 return mappable(None, key, value, makemap)
273
300
274 def compatdict(context, mapping, name, data, key='key', value='value',
301 def compatdict(context, mapping, name, data, key='key', value='value',
275 fmt=None, plural=None, separator=' '):
302 fmt=None, plural=None, separator=' '):
276 """Wrap data like hybriddict(), but also supports old-style list template
303 """Wrap data like hybriddict(), but also supports old-style list template
277
304
278 This exists for backward compatibility with the old-style template. Use
305 This exists for backward compatibility with the old-style template. Use
279 hybriddict() for new template keywords.
306 hybriddict() for new template keywords.
280 """
307 """
281 c = [{key: k, value: v} for k, v in data.iteritems()]
308 c = [{key: k, value: v} for k, v in data.iteritems()]
282 f = _showcompatlist(context, mapping, name, c, plural, separator)
309 f = _showcompatlist(context, mapping, name, c, plural, separator)
283 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
310 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
284
311
285 def compatlist(context, mapping, name, data, element=None, fmt=None,
312 def compatlist(context, mapping, name, data, element=None, fmt=None,
286 plural=None, separator=' '):
313 plural=None, separator=' '):
287 """Wrap data like hybridlist(), but also supports old-style list template
314 """Wrap data like hybridlist(), but also supports old-style list template
288
315
289 This exists for backward compatibility with the old-style template. Use
316 This exists for backward compatibility with the old-style template. Use
290 hybridlist() for new template keywords.
317 hybridlist() for new template keywords.
291 """
318 """
292 f = _showcompatlist(context, mapping, name, data, plural, separator)
319 f = _showcompatlist(context, mapping, name, data, plural, separator)
293 return hybridlist(data, name=element or name, fmt=fmt, gen=f)
320 return hybridlist(data, name=element or name, fmt=fmt, gen=f)
294
321
295 def _showcompatlist(context, mapping, name, values, plural=None, separator=' '):
322 def _showcompatlist(context, mapping, name, values, plural=None, separator=' '):
296 """Return a generator that renders old-style list template
323 """Return a generator that renders old-style list template
297
324
298 name is name of key in template map.
325 name is name of key in template map.
299 values is list of strings or dicts.
326 values is list of strings or dicts.
300 plural is plural of name, if not simply name + 's'.
327 plural is plural of name, if not simply name + 's'.
301 separator is used to join values as a string
328 separator is used to join values as a string
302
329
303 expansion works like this, given name 'foo'.
330 expansion works like this, given name 'foo'.
304
331
305 if values is empty, expand 'no_foos'.
332 if values is empty, expand 'no_foos'.
306
333
307 if 'foo' not in template map, return values as a string,
334 if 'foo' not in template map, return values as a string,
308 joined by 'separator'.
335 joined by 'separator'.
309
336
310 expand 'start_foos'.
337 expand 'start_foos'.
311
338
312 for each value, expand 'foo'. if 'last_foo' in template
339 for each value, expand 'foo'. if 'last_foo' in template
313 map, expand it instead of 'foo' for last key.
340 map, expand it instead of 'foo' for last key.
314
341
315 expand 'end_foos'.
342 expand 'end_foos'.
316 """
343 """
317 if not plural:
344 if not plural:
318 plural = name + 's'
345 plural = name + 's'
319 if not values:
346 if not values:
320 noname = 'no_' + plural
347 noname = 'no_' + plural
321 if context.preload(noname):
348 if context.preload(noname):
322 yield context.process(noname, mapping)
349 yield context.process(noname, mapping)
323 return
350 return
324 if not context.preload(name):
351 if not context.preload(name):
325 if isinstance(values[0], bytes):
352 if isinstance(values[0], bytes):
326 yield separator.join(values)
353 yield separator.join(values)
327 else:
354 else:
328 for v in values:
355 for v in values:
329 r = dict(v)
356 r = dict(v)
330 r.update(mapping)
357 r.update(mapping)
331 yield r
358 yield r
332 return
359 return
333 startname = 'start_' + plural
360 startname = 'start_' + plural
334 if context.preload(startname):
361 if context.preload(startname):
335 yield context.process(startname, mapping)
362 yield context.process(startname, mapping)
336 def one(v, tag=name):
363 def one(v, tag=name):
337 vmapping = {}
364 vmapping = {}
338 try:
365 try:
339 vmapping.update(v)
366 vmapping.update(v)
340 # Python 2 raises ValueError if the type of v is wrong. Python
367 # Python 2 raises ValueError if the type of v is wrong. Python
341 # 3 raises TypeError.
368 # 3 raises TypeError.
342 except (AttributeError, TypeError, ValueError):
369 except (AttributeError, TypeError, ValueError):
343 try:
370 try:
344 # Python 2 raises ValueError trying to destructure an e.g.
371 # Python 2 raises ValueError trying to destructure an e.g.
345 # bytes. Python 3 raises TypeError.
372 # bytes. Python 3 raises TypeError.
346 for a, b in v:
373 for a, b in v:
347 vmapping[a] = b
374 vmapping[a] = b
348 except (TypeError, ValueError):
375 except (TypeError, ValueError):
349 vmapping[name] = v
376 vmapping[name] = v
350 vmapping = context.overlaymap(mapping, vmapping)
377 vmapping = context.overlaymap(mapping, vmapping)
351 return context.process(tag, vmapping)
378 return context.process(tag, vmapping)
352 lastname = 'last_' + name
379 lastname = 'last_' + name
353 if context.preload(lastname):
380 if context.preload(lastname):
354 last = values.pop()
381 last = values.pop()
355 else:
382 else:
356 last = None
383 last = None
357 for v in values:
384 for v in values:
358 yield one(v)
385 yield one(v)
359 if last is not None:
386 if last is not None:
360 yield one(last, tag=lastname)
387 yield one(last, tag=lastname)
361 endname = 'end_' + plural
388 endname = 'end_' + plural
362 if context.preload(endname):
389 if context.preload(endname):
363 yield context.process(endname, mapping)
390 yield context.process(endname, mapping)
364
391
365 def flatten(context, mapping, thing):
392 def flatten(context, mapping, thing):
366 """Yield a single stream from a possibly nested set of iterators"""
393 """Yield a single stream from a possibly nested set of iterators"""
367 thing = unwraphybrid(context, mapping, thing)
394 thing = unwraphybrid(context, mapping, thing)
368 if isinstance(thing, bytes):
395 if isinstance(thing, bytes):
369 yield thing
396 yield thing
370 elif isinstance(thing, str):
397 elif isinstance(thing, str):
371 # We can only hit this on Python 3, and it's here to guard
398 # We can only hit this on Python 3, and it's here to guard
372 # against infinite recursion.
399 # against infinite recursion.
373 raise error.ProgrammingError('Mercurial IO including templates is done'
400 raise error.ProgrammingError('Mercurial IO including templates is done'
374 ' with bytes, not strings, got %r' % thing)
401 ' with bytes, not strings, got %r' % thing)
375 elif thing is None:
402 elif thing is None:
376 pass
403 pass
377 elif not util.safehasattr(thing, '__iter__'):
404 elif not util.safehasattr(thing, '__iter__'):
378 yield pycompat.bytestr(thing)
405 yield pycompat.bytestr(thing)
379 else:
406 else:
380 for i in thing:
407 for i in thing:
381 i = unwraphybrid(context, mapping, i)
408 i = unwraphybrid(context, mapping, i)
382 if isinstance(i, bytes):
409 if isinstance(i, bytes):
383 yield i
410 yield i
384 elif i is None:
411 elif i is None:
385 pass
412 pass
386 elif not util.safehasattr(i, '__iter__'):
413 elif not util.safehasattr(i, '__iter__'):
387 yield pycompat.bytestr(i)
414 yield pycompat.bytestr(i)
388 else:
415 else:
389 for j in flatten(context, mapping, i):
416 for j in flatten(context, mapping, i):
390 yield j
417 yield j
391
418
392 def stringify(context, mapping, thing):
419 def stringify(context, mapping, thing):
393 """Turn values into bytes by converting into text and concatenating them"""
420 """Turn values into bytes by converting into text and concatenating them"""
394 if isinstance(thing, bytes):
421 if isinstance(thing, bytes):
395 return thing # retain localstr to be round-tripped
422 return thing # retain localstr to be round-tripped
396 return b''.join(flatten(context, mapping, thing))
423 return b''.join(flatten(context, mapping, thing))
397
424
398 def findsymbolicname(arg):
425 def findsymbolicname(arg):
399 """Find symbolic name for the given compiled expression; returns None
426 """Find symbolic name for the given compiled expression; returns None
400 if nothing found reliably"""
427 if nothing found reliably"""
401 while True:
428 while True:
402 func, data = arg
429 func, data = arg
403 if func is runsymbol:
430 if func is runsymbol:
404 return data
431 return data
405 elif func is runfilter:
432 elif func is runfilter:
406 arg = data[0]
433 arg = data[0]
407 else:
434 else:
408 return None
435 return None
409
436
410 def _unthunk(context, mapping, thing):
437 def _unthunk(context, mapping, thing):
411 """Evaluate a lazy byte string into value"""
438 """Evaluate a lazy byte string into value"""
412 if not isinstance(thing, types.GeneratorType):
439 if not isinstance(thing, types.GeneratorType):
413 return thing
440 return thing
414 return stringify(context, mapping, thing)
441 return stringify(context, mapping, thing)
415
442
416 def evalrawexp(context, mapping, arg):
443 def evalrawexp(context, mapping, arg):
417 """Evaluate given argument as a bare template object which may require
444 """Evaluate given argument as a bare template object which may require
418 further processing (such as folding generator of strings)"""
445 further processing (such as folding generator of strings)"""
419 func, data = arg
446 func, data = arg
420 return func(context, mapping, data)
447 return func(context, mapping, data)
421
448
422 def evalfuncarg(context, mapping, arg):
449 def evalfuncarg(context, mapping, arg):
423 """Evaluate given argument as value type"""
450 """Evaluate given argument as value type"""
424 return _unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))
451 return _unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))
425
452
426 # TODO: unify this with unwrapvalue() once the bug of templatefunc.join()
453 # TODO: unify this with unwrapvalue() once the bug of templatefunc.join()
427 # is fixed. we can't do that right now because join() has to take a generator
454 # is fixed. we can't do that right now because join() has to take a generator
428 # of byte strings as it is, not a lazy byte string.
455 # of byte strings as it is, not a lazy byte string.
429 def _unwrapvalue(context, mapping, thing):
456 def _unwrapvalue(context, mapping, thing):
430 thing = unwrapvalue(context, mapping, thing)
457 thing = unwrapvalue(context, mapping, thing)
431 # evalrawexp() may return string, generator of strings or arbitrary object
458 # evalrawexp() may return string, generator of strings or arbitrary object
432 # such as date tuple, but filter does not want generator.
459 # such as date tuple, but filter does not want generator.
433 return _unthunk(context, mapping, thing)
460 return _unthunk(context, mapping, thing)
434
461
435 def evalboolean(context, mapping, arg):
462 def evalboolean(context, mapping, arg):
436 """Evaluate given argument as boolean, but also takes boolean literals"""
463 """Evaluate given argument as boolean, but also takes boolean literals"""
437 func, data = arg
464 func, data = arg
438 if func is runsymbol:
465 if func is runsymbol:
439 thing = func(context, mapping, data, default=None)
466 thing = func(context, mapping, data, default=None)
440 if thing is None:
467 if thing is None:
441 # not a template keyword, takes as a boolean literal
468 # not a template keyword, takes as a boolean literal
442 thing = stringutil.parsebool(data)
469 thing = stringutil.parsebool(data)
443 else:
470 else:
444 thing = func(context, mapping, data)
471 thing = func(context, mapping, data)
445 thing = unwrapvalue(context, mapping, thing)
472 thing = unwrapvalue(context, mapping, thing)
446 if isinstance(thing, bool):
473 if isinstance(thing, bool):
447 return thing
474 return thing
448 # other objects are evaluated as strings, which means 0 is True, but
475 # other objects are evaluated as strings, which means 0 is True, but
449 # empty dict/list should be False as they are expected to be ''
476 # empty dict/list should be False as they are expected to be ''
450 return bool(stringify(context, mapping, thing))
477 return bool(stringify(context, mapping, thing))
451
478
452 def evaldate(context, mapping, arg, err=None):
479 def evaldate(context, mapping, arg, err=None):
453 """Evaluate given argument as a date tuple or a date string; returns
480 """Evaluate given argument as a date tuple or a date string; returns
454 a (unixtime, offset) tuple"""
481 a (unixtime, offset) tuple"""
455 thing = evalrawexp(context, mapping, arg)
482 thing = evalrawexp(context, mapping, arg)
456 return unwrapdate(context, mapping, thing, err)
483 return unwrapdate(context, mapping, thing, err)
457
484
458 def unwrapdate(context, mapping, thing, err=None):
485 def unwrapdate(context, mapping, thing, err=None):
459 thing = _unwrapvalue(context, mapping, thing)
486 thing = _unwrapvalue(context, mapping, thing)
460 try:
487 try:
461 return dateutil.parsedate(thing)
488 return dateutil.parsedate(thing)
462 except AttributeError:
489 except AttributeError:
463 raise error.ParseError(err or _('not a date tuple nor a string'))
490 raise error.ParseError(err or _('not a date tuple nor a string'))
464 except error.ParseError:
491 except error.ParseError:
465 if not err:
492 if not err:
466 raise
493 raise
467 raise error.ParseError(err)
494 raise error.ParseError(err)
468
495
469 def evalinteger(context, mapping, arg, err=None):
496 def evalinteger(context, mapping, arg, err=None):
470 thing = evalrawexp(context, mapping, arg)
497 thing = evalrawexp(context, mapping, arg)
471 return unwrapinteger(context, mapping, thing, err)
498 return unwrapinteger(context, mapping, thing, err)
472
499
473 def unwrapinteger(context, mapping, thing, err=None):
500 def unwrapinteger(context, mapping, thing, err=None):
474 thing = _unwrapvalue(context, mapping, thing)
501 thing = _unwrapvalue(context, mapping, thing)
475 try:
502 try:
476 return int(thing)
503 return int(thing)
477 except (TypeError, ValueError):
504 except (TypeError, ValueError):
478 raise error.ParseError(err or _('not an integer'))
505 raise error.ParseError(err or _('not an integer'))
479
506
480 def evalstring(context, mapping, arg):
507 def evalstring(context, mapping, arg):
481 return stringify(context, mapping, evalrawexp(context, mapping, arg))
508 return stringify(context, mapping, evalrawexp(context, mapping, arg))
482
509
483 def evalstringliteral(context, mapping, arg):
510 def evalstringliteral(context, mapping, arg):
484 """Evaluate given argument as string template, but returns symbol name
511 """Evaluate given argument as string template, but returns symbol name
485 if it is unknown"""
512 if it is unknown"""
486 func, data = arg
513 func, data = arg
487 if func is runsymbol:
514 if func is runsymbol:
488 thing = func(context, mapping, data, default=data)
515 thing = func(context, mapping, data, default=data)
489 else:
516 else:
490 thing = func(context, mapping, data)
517 thing = func(context, mapping, data)
491 return stringify(context, mapping, thing)
518 return stringify(context, mapping, thing)
492
519
493 _unwrapfuncbytype = {
520 _unwrapfuncbytype = {
494 None: _unwrapvalue,
521 None: _unwrapvalue,
495 bytes: stringify,
522 bytes: stringify,
496 date: unwrapdate,
523 date: unwrapdate,
497 int: unwrapinteger,
524 int: unwrapinteger,
498 }
525 }
499
526
500 def unwrapastype(context, mapping, thing, typ):
527 def unwrapastype(context, mapping, thing, typ):
501 """Move the inner value object out of the wrapper and coerce its type"""
528 """Move the inner value object out of the wrapper and coerce its type"""
502 try:
529 try:
503 f = _unwrapfuncbytype[typ]
530 f = _unwrapfuncbytype[typ]
504 except KeyError:
531 except KeyError:
505 raise error.ProgrammingError('invalid type specified: %r' % typ)
532 raise error.ProgrammingError('invalid type specified: %r' % typ)
506 return f(context, mapping, thing)
533 return f(context, mapping, thing)
507
534
508 def runinteger(context, mapping, data):
535 def runinteger(context, mapping, data):
509 return int(data)
536 return int(data)
510
537
511 def runstring(context, mapping, data):
538 def runstring(context, mapping, data):
512 return data
539 return data
513
540
514 def _recursivesymbolblocker(key):
541 def _recursivesymbolblocker(key):
515 def showrecursion(**args):
542 def showrecursion(**args):
516 raise error.Abort(_("recursive reference '%s' in template") % key)
543 raise error.Abort(_("recursive reference '%s' in template") % key)
517 return showrecursion
544 return showrecursion
518
545
519 def runsymbol(context, mapping, key, default=''):
546 def runsymbol(context, mapping, key, default=''):
520 v = context.symbol(mapping, key)
547 v = context.symbol(mapping, key)
521 if v is None:
548 if v is None:
522 # put poison to cut recursion. we can't move this to parsing phase
549 # put poison to cut recursion. we can't move this to parsing phase
523 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
550 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
524 safemapping = mapping.copy()
551 safemapping = mapping.copy()
525 safemapping[key] = _recursivesymbolblocker(key)
552 safemapping[key] = _recursivesymbolblocker(key)
526 try:
553 try:
527 v = context.process(key, safemapping)
554 v = context.process(key, safemapping)
528 except TemplateNotFound:
555 except TemplateNotFound:
529 v = default
556 v = default
530 if callable(v) and getattr(v, '_requires', None) is None:
557 if callable(v) and getattr(v, '_requires', None) is None:
531 # old templatekw: expand all keywords and resources
558 # old templatekw: expand all keywords and resources
532 # (TODO: deprecate this after porting web template keywords to new API)
559 # (TODO: deprecate this after porting web template keywords to new API)
533 props = {k: context._resources.lookup(context, mapping, k)
560 props = {k: context._resources.lookup(context, mapping, k)
534 for k in context._resources.knownkeys()}
561 for k in context._resources.knownkeys()}
535 # pass context to _showcompatlist() through templatekw._showlist()
562 # pass context to _showcompatlist() through templatekw._showlist()
536 props['templ'] = context
563 props['templ'] = context
537 props.update(mapping)
564 props.update(mapping)
538 return v(**pycompat.strkwargs(props))
565 return v(**pycompat.strkwargs(props))
539 if callable(v):
566 if callable(v):
540 # new templatekw
567 # new templatekw
541 try:
568 try:
542 return v(context, mapping)
569 return v(context, mapping)
543 except ResourceUnavailable:
570 except ResourceUnavailable:
544 # unsupported keyword is mapped to empty just like unknown keyword
571 # unsupported keyword is mapped to empty just like unknown keyword
545 return None
572 return None
546 return v
573 return v
547
574
548 def runtemplate(context, mapping, template):
575 def runtemplate(context, mapping, template):
549 for arg in template:
576 for arg in template:
550 yield evalrawexp(context, mapping, arg)
577 yield evalrawexp(context, mapping, arg)
551
578
552 def runfilter(context, mapping, data):
579 def runfilter(context, mapping, data):
553 arg, filt = data
580 arg, filt = data
554 thing = evalrawexp(context, mapping, arg)
581 thing = evalrawexp(context, mapping, arg)
555 intype = getattr(filt, '_intype', None)
582 intype = getattr(filt, '_intype', None)
556 try:
583 try:
557 thing = unwrapastype(context, mapping, thing, intype)
584 thing = unwrapastype(context, mapping, thing, intype)
558 return filt(thing)
585 return filt(thing)
559 except error.ParseError as e:
586 except error.ParseError as e:
560 raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
587 raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
561
588
562 def _formatfiltererror(arg, filt):
589 def _formatfiltererror(arg, filt):
563 fn = pycompat.sysbytes(filt.__name__)
590 fn = pycompat.sysbytes(filt.__name__)
564 sym = findsymbolicname(arg)
591 sym = findsymbolicname(arg)
565 if not sym:
592 if not sym:
566 return _("incompatible use of template filter '%s'") % fn
593 return _("incompatible use of template filter '%s'") % fn
567 return (_("template filter '%s' is not compatible with keyword '%s'")
594 return (_("template filter '%s' is not compatible with keyword '%s'")
568 % (fn, sym))
595 % (fn, sym))
569
596
570 def _checkeditermaps(darg, d):
597 def _checkeditermaps(darg, d):
571 try:
598 try:
572 for v in d:
599 for v in d:
573 if not isinstance(v, dict):
600 if not isinstance(v, dict):
574 raise TypeError
601 raise TypeError
575 yield v
602 yield v
576 except TypeError:
603 except TypeError:
577 sym = findsymbolicname(darg)
604 sym = findsymbolicname(darg)
578 if sym:
605 if sym:
579 raise error.ParseError(_("keyword '%s' is not iterable of mappings")
606 raise error.ParseError(_("keyword '%s' is not iterable of mappings")
580 % sym)
607 % sym)
581 else:
608 else:
582 raise error.ParseError(_("%r is not iterable of mappings") % d)
609 raise error.ParseError(_("%r is not iterable of mappings") % d)
583
610
584 def _iteroverlaymaps(context, origmapping, newmappings):
611 def _iteroverlaymaps(context, origmapping, newmappings):
585 """Generate combined mappings from the original mapping and an iterable
612 """Generate combined mappings from the original mapping and an iterable
586 of partial mappings to override the original"""
613 of partial mappings to override the original"""
587 for i, nm in enumerate(newmappings):
614 for i, nm in enumerate(newmappings):
588 lm = context.overlaymap(origmapping, nm)
615 lm = context.overlaymap(origmapping, nm)
589 lm['index'] = i
616 lm['index'] = i
590 yield lm
617 yield lm
591
618
619 def _applymap(context, mapping, diter, targ):
620 for lm in _iteroverlaymaps(context, mapping, diter):
621 yield evalrawexp(context, lm, targ)
622
592 def runmap(context, mapping, data):
623 def runmap(context, mapping, data):
593 darg, targ = data
624 darg, targ = data
594 d = evalrawexp(context, mapping, darg)
625 d = evalrawexp(context, mapping, darg)
595 # TODO: a generator should be rejected because it is a thunk of lazy
626 # TODO: a generator should be rejected because it is a thunk of lazy
596 # string, but we can't because hgweb abuses generator as a keyword
627 # string, but we can't because hgweb abuses generator as a keyword
597 # that returns a list of dicts.
628 # that returns a list of dicts.
629 # TODO: drop _checkeditermaps() and pass 'd' to mappedgenerator so it
630 # can be restarted.
598 if isinstance(d, wrapped):
631 if isinstance(d, wrapped):
599 diter = d.itermaps(context)
632 diter = d.itermaps(context)
600 else:
633 else:
601 diter = _checkeditermaps(darg, d)
634 diter = _checkeditermaps(darg, d)
602 for lm in _iteroverlaymaps(context, mapping, diter):
635 return mappedgenerator(_applymap, args=(mapping, diter, targ))
603 yield evalrawexp(context, lm, targ)
604
636
605 def runmember(context, mapping, data):
637 def runmember(context, mapping, data):
606 darg, memb = data
638 darg, memb = data
607 d = evalrawexp(context, mapping, darg)
639 d = evalrawexp(context, mapping, darg)
608 if util.safehasattr(d, 'tomap'):
640 if util.safehasattr(d, 'tomap'):
609 lm = context.overlaymap(mapping, d.tomap())
641 lm = context.overlaymap(mapping, d.tomap())
610 return runsymbol(context, lm, memb)
642 return runsymbol(context, lm, memb)
611 if util.safehasattr(d, 'get'):
643 if util.safehasattr(d, 'get'):
612 return getdictitem(d, memb)
644 return getdictitem(d, memb)
613
645
614 sym = findsymbolicname(darg)
646 sym = findsymbolicname(darg)
615 if sym:
647 if sym:
616 raise error.ParseError(_("keyword '%s' has no member") % sym)
648 raise error.ParseError(_("keyword '%s' has no member") % sym)
617 else:
649 else:
618 raise error.ParseError(_("%r has no member") % pycompat.bytestr(d))
650 raise error.ParseError(_("%r has no member") % pycompat.bytestr(d))
619
651
620 def runnegate(context, mapping, data):
652 def runnegate(context, mapping, data):
621 data = evalinteger(context, mapping, data,
653 data = evalinteger(context, mapping, data,
622 _('negation needs an integer argument'))
654 _('negation needs an integer argument'))
623 return -data
655 return -data
624
656
625 def runarithmetic(context, mapping, data):
657 def runarithmetic(context, mapping, data):
626 func, left, right = data
658 func, left, right = data
627 left = evalinteger(context, mapping, left,
659 left = evalinteger(context, mapping, left,
628 _('arithmetic only defined on integers'))
660 _('arithmetic only defined on integers'))
629 right = evalinteger(context, mapping, right,
661 right = evalinteger(context, mapping, right,
630 _('arithmetic only defined on integers'))
662 _('arithmetic only defined on integers'))
631 try:
663 try:
632 return func(left, right)
664 return func(left, right)
633 except ZeroDivisionError:
665 except ZeroDivisionError:
634 raise error.Abort(_('division by zero is not defined'))
666 raise error.Abort(_('division by zero is not defined'))
635
667
636 def getdictitem(dictarg, key):
668 def getdictitem(dictarg, key):
637 val = dictarg.get(key)
669 val = dictarg.get(key)
638 if val is None:
670 if val is None:
639 return
671 return
640 return wraphybridvalue(dictarg, key, val)
672 return wraphybridvalue(dictarg, key, val)
641
673
642 def joinitems(itemiter, sep):
674 def joinitems(itemiter, sep):
643 """Join items with the separator; Returns generator of bytes"""
675 """Join items with the separator; Returns generator of bytes"""
644 first = True
676 first = True
645 for x in itemiter:
677 for x in itemiter:
646 if first:
678 if first:
647 first = False
679 first = False
648 elif sep:
680 elif sep:
649 yield sep
681 yield sep
650 yield x
682 yield x
@@ -1,4856 +1,4868
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Test arithmetic operators have the right precedence:
32 Test arithmetic operators have the right precedence:
33
33
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
35 2020 1964
35 2020 1964
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
37 9860 5908
37 9860 5908
38
38
39 Test division:
39 Test division:
40
40
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
42 (template
42 (template
43 (/
43 (/
44 (integer '5')
44 (integer '5')
45 (integer '2'))
45 (integer '2'))
46 (string ' ')
46 (string ' ')
47 (func
47 (func
48 (symbol 'mod')
48 (symbol 'mod')
49 (list
49 (list
50 (integer '5')
50 (integer '5')
51 (integer '2')))
51 (integer '2')))
52 (string '\n'))
52 (string '\n'))
53 2 1
53 2 1
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
55 (template
55 (template
56 (/
56 (/
57 (integer '5')
57 (integer '5')
58 (negate
58 (negate
59 (integer '2')))
59 (integer '2')))
60 (string ' ')
60 (string ' ')
61 (func
61 (func
62 (symbol 'mod')
62 (symbol 'mod')
63 (list
63 (list
64 (integer '5')
64 (integer '5')
65 (negate
65 (negate
66 (integer '2'))))
66 (integer '2'))))
67 (string '\n'))
67 (string '\n'))
68 -3 -1
68 -3 -1
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
70 (template
70 (template
71 (/
71 (/
72 (negate
72 (negate
73 (integer '5'))
73 (integer '5'))
74 (integer '2'))
74 (integer '2'))
75 (string ' ')
75 (string ' ')
76 (func
76 (func
77 (symbol 'mod')
77 (symbol 'mod')
78 (list
78 (list
79 (negate
79 (negate
80 (integer '5'))
80 (integer '5'))
81 (integer '2')))
81 (integer '2')))
82 (string '\n'))
82 (string '\n'))
83 -3 1
83 -3 1
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
85 (template
85 (template
86 (/
86 (/
87 (negate
87 (negate
88 (integer '5'))
88 (integer '5'))
89 (negate
89 (negate
90 (integer '2')))
90 (integer '2')))
91 (string ' ')
91 (string ' ')
92 (func
92 (func
93 (symbol 'mod')
93 (symbol 'mod')
94 (list
94 (list
95 (negate
95 (negate
96 (integer '5'))
96 (integer '5'))
97 (negate
97 (negate
98 (integer '2'))))
98 (integer '2'))))
99 (string '\n'))
99 (string '\n'))
100 2 -1
100 2 -1
101
101
102 Filters bind closer than arithmetic:
102 Filters bind closer than arithmetic:
103
103
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
105 (template
105 (template
106 (-
106 (-
107 (|
107 (|
108 (func
108 (func
109 (symbol 'revset')
109 (symbol 'revset')
110 (string '.'))
110 (string '.'))
111 (symbol 'count'))
111 (symbol 'count'))
112 (integer '1'))
112 (integer '1'))
113 (string '\n'))
113 (string '\n'))
114 0
114 0
115
115
116 But negate binds closer still:
116 But negate binds closer still:
117
117
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
119 (template
119 (template
120 (-
120 (-
121 (integer '1')
121 (integer '1')
122 (|
122 (|
123 (integer '3')
123 (integer '3')
124 (symbol 'stringify')))
124 (symbol 'stringify')))
125 (string '\n'))
125 (string '\n'))
126 hg: parse error: arithmetic only defined on integers
126 hg: parse error: arithmetic only defined on integers
127 [255]
127 [255]
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
129 (template
129 (template
130 (|
130 (|
131 (negate
131 (negate
132 (integer '3'))
132 (integer '3'))
133 (symbol 'stringify'))
133 (symbol 'stringify'))
134 (string '\n'))
134 (string '\n'))
135 -3
135 -3
136
136
137 Filters bind as close as map operator:
137 Filters bind as close as map operator:
138
138
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
140 (template
140 (template
141 (%
141 (%
142 (|
142 (|
143 (symbol 'desc')
143 (symbol 'desc')
144 (symbol 'splitlines'))
144 (symbol 'splitlines'))
145 (template
145 (template
146 (symbol 'line')
146 (symbol 'line')
147 (string '\n'))))
147 (string '\n'))))
148 line 1
148 line 1
149 line 2
149 line 2
150
150
151 Keyword arguments:
151 Keyword arguments:
152
152
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
154 (template
154 (template
155 (keyvalue
155 (keyvalue
156 (symbol 'foo')
156 (symbol 'foo')
157 (|
157 (|
158 (symbol 'bar')
158 (symbol 'bar')
159 (symbol 'baz'))))
159 (symbol 'baz'))))
160 hg: parse error: can't use a key-value pair in this context
160 hg: parse error: can't use a key-value pair in this context
161 [255]
161 [255]
162
162
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
164 foo
164 foo
165
165
166 Call function which takes named arguments by filter syntax:
166 Call function which takes named arguments by filter syntax:
167
167
168 $ hg debugtemplate '{" "|separate}'
168 $ hg debugtemplate '{" "|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
170 hg: parse error: unknown method 'list'
170 hg: parse error: unknown method 'list'
171 [255]
171 [255]
172
172
173 Second branch starting at nullrev:
173 Second branch starting at nullrev:
174
174
175 $ hg update null
175 $ hg update null
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
177 $ echo second > second
177 $ echo second > second
178 $ hg add second
178 $ hg add second
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
180 created new head
180 created new head
181
181
182 $ echo third > third
182 $ echo third > third
183 $ hg add third
183 $ hg add third
184 $ hg mv second fourth
184 $ hg mv second fourth
185 $ hg commit -m third -d "2020-01-01 10:01"
185 $ hg commit -m third -d "2020-01-01 10:01"
186
186
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
188 fourth (second)
188 fourth (second)
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
190 second -> fourth
190 second -> fourth
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
192 8 t
192 8 t
193 7 f
193 7 f
194
194
195 Working-directory revision has special identifiers, though they are still
195 Working-directory revision has special identifiers, though they are still
196 experimental:
196 experimental:
197
197
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
200
200
201 Some keywords are invalid for working-directory revision, but they should
201 Some keywords are invalid for working-directory revision, but they should
202 never cause crash:
202 never cause crash:
203
203
204 $ hg log -r 'wdir()' -T '{manifest}\n'
204 $ hg log -r 'wdir()' -T '{manifest}\n'
205
205
206
206
207 Internal resources shouldn't be exposed (issue5699):
207 Internal resources shouldn't be exposed (issue5699):
208
208
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
210
210
211 Never crash on internal resource not available:
211 Never crash on internal resource not available:
212
212
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
214 abort: template resource not available: ctx
214 abort: template resource not available: ctx
215 [255]
215 [255]
216
216
217 $ hg config -T '{author}'
217 $ hg config -T '{author}'
218
218
219 Quoting for ui.logtemplate
219 Quoting for ui.logtemplate
220
220
221 $ hg tip --config "ui.logtemplate={rev}\n"
221 $ hg tip --config "ui.logtemplate={rev}\n"
222 8
222 8
223 $ hg tip --config "ui.logtemplate='{rev}\n'"
223 $ hg tip --config "ui.logtemplate='{rev}\n'"
224 8
224 8
225 $ hg tip --config 'ui.logtemplate="{rev}\n"'
225 $ hg tip --config 'ui.logtemplate="{rev}\n"'
226 8
226 8
227 $ hg tip --config 'ui.logtemplate=n{rev}\n'
227 $ hg tip --config 'ui.logtemplate=n{rev}\n'
228 n8
228 n8
229
229
230 Make sure user/global hgrc does not affect tests
230 Make sure user/global hgrc does not affect tests
231
231
232 $ echo '[ui]' > .hg/hgrc
232 $ echo '[ui]' > .hg/hgrc
233 $ echo 'logtemplate =' >> .hg/hgrc
233 $ echo 'logtemplate =' >> .hg/hgrc
234 $ echo 'style =' >> .hg/hgrc
234 $ echo 'style =' >> .hg/hgrc
235
235
236 Add some simple styles to settings
236 Add some simple styles to settings
237
237
238 $ cat <<'EOF' >> .hg/hgrc
238 $ cat <<'EOF' >> .hg/hgrc
239 > [templates]
239 > [templates]
240 > simple = "{rev}\n"
240 > simple = "{rev}\n"
241 > simple2 = {rev}\n
241 > simple2 = {rev}\n
242 > rev = "should not precede {rev} keyword\n"
242 > rev = "should not precede {rev} keyword\n"
243 > EOF
243 > EOF
244
244
245 $ hg log -l1 -Tsimple
245 $ hg log -l1 -Tsimple
246 8
246 8
247 $ hg log -l1 -Tsimple2
247 $ hg log -l1 -Tsimple2
248 8
248 8
249 $ hg log -l1 -Trev
249 $ hg log -l1 -Trev
250 should not precede 8 keyword
250 should not precede 8 keyword
251 $ hg log -l1 -T '{simple}'
251 $ hg log -l1 -T '{simple}'
252 8
252 8
253
253
254 Map file shouldn't see user templates:
254 Map file shouldn't see user templates:
255
255
256 $ cat <<EOF > tmpl
256 $ cat <<EOF > tmpl
257 > changeset = 'nothing expanded:{simple}\n'
257 > changeset = 'nothing expanded:{simple}\n'
258 > EOF
258 > EOF
259 $ hg log -l1 --style ./tmpl
259 $ hg log -l1 --style ./tmpl
260 nothing expanded:
260 nothing expanded:
261
261
262 Test templates and style maps in files:
262 Test templates and style maps in files:
263
263
264 $ echo "{rev}" > tmpl
264 $ echo "{rev}" > tmpl
265 $ hg log -l1 -T./tmpl
265 $ hg log -l1 -T./tmpl
266 8
266 8
267 $ hg log -l1 -Tblah/blah
267 $ hg log -l1 -Tblah/blah
268 blah/blah (no-eol)
268 blah/blah (no-eol)
269
269
270 $ printf 'changeset = "{rev}\\n"\n' > map-simple
270 $ printf 'changeset = "{rev}\\n"\n' > map-simple
271 $ hg log -l1 -T./map-simple
271 $ hg log -l1 -T./map-simple
272 8
272 8
273
273
274 a map file may have [templates] and [templatealias] sections:
274 a map file may have [templates] and [templatealias] sections:
275
275
276 $ cat <<'EOF' > map-simple
276 $ cat <<'EOF' > map-simple
277 > [templates]
277 > [templates]
278 > changeset = "{a}\n"
278 > changeset = "{a}\n"
279 > [templatealias]
279 > [templatealias]
280 > a = rev
280 > a = rev
281 > EOF
281 > EOF
282 $ hg log -l1 -T./map-simple
282 $ hg log -l1 -T./map-simple
283 8
283 8
284
284
285 so it can be included in hgrc
285 so it can be included in hgrc
286
286
287 $ cat <<EOF > myhgrc
287 $ cat <<EOF > myhgrc
288 > %include $HGRCPATH
288 > %include $HGRCPATH
289 > %include map-simple
289 > %include map-simple
290 > [templates]
290 > [templates]
291 > foo = "{changeset}"
291 > foo = "{changeset}"
292 > EOF
292 > EOF
293 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
293 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
294 8
294 8
295 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
295 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
296 8
296 8
297
297
298 Test template map inheritance
298 Test template map inheritance
299
299
300 $ echo "__base__ = map-cmdline.default" > map-simple
300 $ echo "__base__ = map-cmdline.default" > map-simple
301 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
301 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
302 $ hg log -l1 -T./map-simple
302 $ hg log -l1 -T./map-simple
303 changeset: ***8***
303 changeset: ***8***
304 tag: tip
304 tag: tip
305 user: test
305 user: test
306 date: Wed Jan 01 10:01:00 2020 +0000
306 date: Wed Jan 01 10:01:00 2020 +0000
307 summary: third
307 summary: third
308
308
309
309
310 Test docheader, docfooter and separator in template map
310 Test docheader, docfooter and separator in template map
311
311
312 $ cat <<'EOF' > map-myjson
312 $ cat <<'EOF' > map-myjson
313 > docheader = '\{\n'
313 > docheader = '\{\n'
314 > docfooter = '\n}\n'
314 > docfooter = '\n}\n'
315 > separator = ',\n'
315 > separator = ',\n'
316 > changeset = ' {dict(rev, node|short)|json}'
316 > changeset = ' {dict(rev, node|short)|json}'
317 > EOF
317 > EOF
318 $ hg log -l2 -T./map-myjson
318 $ hg log -l2 -T./map-myjson
319 {
319 {
320 {"node": "95c24699272e", "rev": 8},
320 {"node": "95c24699272e", "rev": 8},
321 {"node": "29114dbae42b", "rev": 7}
321 {"node": "29114dbae42b", "rev": 7}
322 }
322 }
323
323
324 Test docheader, docfooter and separator in [templates] section
324 Test docheader, docfooter and separator in [templates] section
325
325
326 $ cat <<'EOF' >> .hg/hgrc
326 $ cat <<'EOF' >> .hg/hgrc
327 > [templates]
327 > [templates]
328 > myjson = ' {dict(rev, node|short)|json}'
328 > myjson = ' {dict(rev, node|short)|json}'
329 > myjson:docheader = '\{\n'
329 > myjson:docheader = '\{\n'
330 > myjson:docfooter = '\n}\n'
330 > myjson:docfooter = '\n}\n'
331 > myjson:separator = ',\n'
331 > myjson:separator = ',\n'
332 > :docheader = 'should not be selected as a docheader for literal templates\n'
332 > :docheader = 'should not be selected as a docheader for literal templates\n'
333 > EOF
333 > EOF
334 $ hg log -l2 -Tmyjson
334 $ hg log -l2 -Tmyjson
335 {
335 {
336 {"node": "95c24699272e", "rev": 8},
336 {"node": "95c24699272e", "rev": 8},
337 {"node": "29114dbae42b", "rev": 7}
337 {"node": "29114dbae42b", "rev": 7}
338 }
338 }
339 $ hg log -l1 -T'{rev}\n'
339 $ hg log -l1 -T'{rev}\n'
340 8
340 8
341
341
342 Template should precede style option
342 Template should precede style option
343
343
344 $ hg log -l1 --style default -T '{rev}\n'
344 $ hg log -l1 --style default -T '{rev}\n'
345 8
345 8
346
346
347 Add a commit with empty description, to ensure that the templates
347 Add a commit with empty description, to ensure that the templates
348 below will omit the description line.
348 below will omit the description line.
349
349
350 $ echo c >> c
350 $ echo c >> c
351 $ hg add c
351 $ hg add c
352 $ hg commit -qm ' '
352 $ hg commit -qm ' '
353
353
354 Default style is like normal output. Phases style should be the same
354 Default style is like normal output. Phases style should be the same
355 as default style, except for extra phase lines.
355 as default style, except for extra phase lines.
356
356
357 $ hg log > log.out
357 $ hg log > log.out
358 $ hg log --style default > style.out
358 $ hg log --style default > style.out
359 $ cmp log.out style.out || diff -u log.out style.out
359 $ cmp log.out style.out || diff -u log.out style.out
360 $ hg log -T phases > phases.out
360 $ hg log -T phases > phases.out
361 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
361 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
362 +phase: draft
362 +phase: draft
363 +phase: draft
363 +phase: draft
364 +phase: draft
364 +phase: draft
365 +phase: draft
365 +phase: draft
366 +phase: draft
366 +phase: draft
367 +phase: draft
367 +phase: draft
368 +phase: draft
368 +phase: draft
369 +phase: draft
369 +phase: draft
370 +phase: draft
370 +phase: draft
371 +phase: draft
371 +phase: draft
372
372
373 $ hg log -v > log.out
373 $ hg log -v > log.out
374 $ hg log -v --style default > style.out
374 $ hg log -v --style default > style.out
375 $ cmp log.out style.out || diff -u log.out style.out
375 $ cmp log.out style.out || diff -u log.out style.out
376 $ hg log -v -T phases > phases.out
376 $ hg log -v -T phases > phases.out
377 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
377 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
378 +phase: draft
378 +phase: draft
379 +phase: draft
379 +phase: draft
380 +phase: draft
380 +phase: draft
381 +phase: draft
381 +phase: draft
382 +phase: draft
382 +phase: draft
383 +phase: draft
383 +phase: draft
384 +phase: draft
384 +phase: draft
385 +phase: draft
385 +phase: draft
386 +phase: draft
386 +phase: draft
387 +phase: draft
387 +phase: draft
388
388
389 $ hg log -q > log.out
389 $ hg log -q > log.out
390 $ hg log -q --style default > style.out
390 $ hg log -q --style default > style.out
391 $ cmp log.out style.out || diff -u log.out style.out
391 $ cmp log.out style.out || diff -u log.out style.out
392 $ hg log -q -T phases > phases.out
392 $ hg log -q -T phases > phases.out
393 $ cmp log.out phases.out || diff -u log.out phases.out
393 $ cmp log.out phases.out || diff -u log.out phases.out
394
394
395 $ hg log --debug > log.out
395 $ hg log --debug > log.out
396 $ hg log --debug --style default > style.out
396 $ hg log --debug --style default > style.out
397 $ cmp log.out style.out || diff -u log.out style.out
397 $ cmp log.out style.out || diff -u log.out style.out
398 $ hg log --debug -T phases > phases.out
398 $ hg log --debug -T phases > phases.out
399 $ cmp log.out phases.out || diff -u log.out phases.out
399 $ cmp log.out phases.out || diff -u log.out phases.out
400
400
401 Default style of working-directory revision should also be the same (but
401 Default style of working-directory revision should also be the same (but
402 date may change while running tests):
402 date may change while running tests):
403
403
404 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
404 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
405 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
405 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
406 $ cmp log.out style.out || diff -u log.out style.out
406 $ cmp log.out style.out || diff -u log.out style.out
407
407
408 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
408 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
409 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
409 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
410 $ cmp log.out style.out || diff -u log.out style.out
410 $ cmp log.out style.out || diff -u log.out style.out
411
411
412 $ hg log -r 'wdir()' -q > log.out
412 $ hg log -r 'wdir()' -q > log.out
413 $ hg log -r 'wdir()' -q --style default > style.out
413 $ hg log -r 'wdir()' -q --style default > style.out
414 $ cmp log.out style.out || diff -u log.out style.out
414 $ cmp log.out style.out || diff -u log.out style.out
415
415
416 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
416 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
417 $ hg log -r 'wdir()' --debug --style default \
417 $ hg log -r 'wdir()' --debug --style default \
418 > | sed 's|^date:.*|date:|' > style.out
418 > | sed 's|^date:.*|date:|' > style.out
419 $ cmp log.out style.out || diff -u log.out style.out
419 $ cmp log.out style.out || diff -u log.out style.out
420
420
421 Default style should also preserve color information (issue2866):
421 Default style should also preserve color information (issue2866):
422
422
423 $ cp $HGRCPATH $HGRCPATH-bak
423 $ cp $HGRCPATH $HGRCPATH-bak
424 $ cat <<EOF >> $HGRCPATH
424 $ cat <<EOF >> $HGRCPATH
425 > [extensions]
425 > [extensions]
426 > color=
426 > color=
427 > EOF
427 > EOF
428
428
429 $ hg --color=debug log > log.out
429 $ hg --color=debug log > log.out
430 $ hg --color=debug log --style default > style.out
430 $ hg --color=debug log --style default > style.out
431 $ cmp log.out style.out || diff -u log.out style.out
431 $ cmp log.out style.out || diff -u log.out style.out
432 $ hg --color=debug log -T phases > phases.out
432 $ hg --color=debug log -T phases > phases.out
433 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
433 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
434 +[log.phase|phase: draft]
434 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
441 +[log.phase|phase: draft]
441 +[log.phase|phase: draft]
442 +[log.phase|phase: draft]
442 +[log.phase|phase: draft]
443 +[log.phase|phase: draft]
443 +[log.phase|phase: draft]
444
444
445 $ hg --color=debug -v log > log.out
445 $ hg --color=debug -v log > log.out
446 $ hg --color=debug -v log --style default > style.out
446 $ hg --color=debug -v log --style default > style.out
447 $ cmp log.out style.out || diff -u log.out style.out
447 $ cmp log.out style.out || diff -u log.out style.out
448 $ hg --color=debug -v log -T phases > phases.out
448 $ hg --color=debug -v log -T phases > phases.out
449 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
449 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
450 +[log.phase|phase: draft]
450 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
457 +[log.phase|phase: draft]
457 +[log.phase|phase: draft]
458 +[log.phase|phase: draft]
458 +[log.phase|phase: draft]
459 +[log.phase|phase: draft]
459 +[log.phase|phase: draft]
460
460
461 $ hg --color=debug -q log > log.out
461 $ hg --color=debug -q log > log.out
462 $ hg --color=debug -q log --style default > style.out
462 $ hg --color=debug -q log --style default > style.out
463 $ cmp log.out style.out || diff -u log.out style.out
463 $ cmp log.out style.out || diff -u log.out style.out
464 $ hg --color=debug -q log -T phases > phases.out
464 $ hg --color=debug -q log -T phases > phases.out
465 $ cmp log.out phases.out || diff -u log.out phases.out
465 $ cmp log.out phases.out || diff -u log.out phases.out
466
466
467 $ hg --color=debug --debug log > log.out
467 $ hg --color=debug --debug log > log.out
468 $ hg --color=debug --debug log --style default > style.out
468 $ hg --color=debug --debug log --style default > style.out
469 $ cmp log.out style.out || diff -u log.out style.out
469 $ cmp log.out style.out || diff -u log.out style.out
470 $ hg --color=debug --debug log -T phases > phases.out
470 $ hg --color=debug --debug log -T phases > phases.out
471 $ cmp log.out phases.out || diff -u log.out phases.out
471 $ cmp log.out phases.out || diff -u log.out phases.out
472
472
473 $ mv $HGRCPATH-bak $HGRCPATH
473 $ mv $HGRCPATH-bak $HGRCPATH
474
474
475 Remove commit with empty commit message, so as to not pollute further
475 Remove commit with empty commit message, so as to not pollute further
476 tests.
476 tests.
477
477
478 $ hg --config extensions.strip= strip -q .
478 $ hg --config extensions.strip= strip -q .
479
479
480 Revision with no copies (used to print a traceback):
480 Revision with no copies (used to print a traceback):
481
481
482 $ hg tip -v --template '\n'
482 $ hg tip -v --template '\n'
483
483
484
484
485 Compact style works:
485 Compact style works:
486
486
487 $ hg log -Tcompact
487 $ hg log -Tcompact
488 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
488 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
489 third
489 third
490
490
491 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
491 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
492 second
492 second
493
493
494 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
494 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
495 merge
495 merge
496
496
497 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
497 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
498 new head
498 new head
499
499
500 4 bbe44766e73d 1970-01-17 04:53 +0000 person
500 4 bbe44766e73d 1970-01-17 04:53 +0000 person
501 new branch
501 new branch
502
502
503 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
503 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
504 no user, no domain
504 no user, no domain
505
505
506 2 97054abb4ab8 1970-01-14 21:20 +0000 other
506 2 97054abb4ab8 1970-01-14 21:20 +0000 other
507 no person
507 no person
508
508
509 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
509 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
510 other 1
510 other 1
511
511
512 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
512 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
513 line 1
513 line 1
514
514
515
515
516 $ hg log -v --style compact
516 $ hg log -v --style compact
517 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
517 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
518 third
518 third
519
519
520 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
520 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
521 second
521 second
522
522
523 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
523 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
524 merge
524 merge
525
525
526 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
526 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
527 new head
527 new head
528
528
529 4 bbe44766e73d 1970-01-17 04:53 +0000 person
529 4 bbe44766e73d 1970-01-17 04:53 +0000 person
530 new branch
530 new branch
531
531
532 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
532 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
533 no user, no domain
533 no user, no domain
534
534
535 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
535 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
536 no person
536 no person
537
537
538 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
538 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
539 other 1
539 other 1
540 other 2
540 other 2
541
541
542 other 3
542 other 3
543
543
544 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
544 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
545 line 1
545 line 1
546 line 2
546 line 2
547
547
548
548
549 $ hg log --debug --style compact
549 $ hg log --debug --style compact
550 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
550 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
551 third
551 third
552
552
553 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
553 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
554 second
554 second
555
555
556 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
556 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
557 merge
557 merge
558
558
559 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
559 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
560 new head
560 new head
561
561
562 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
562 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
563 new branch
563 new branch
564
564
565 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
565 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
566 no user, no domain
566 no user, no domain
567
567
568 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
568 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
569 no person
569 no person
570
570
571 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
571 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
572 other 1
572 other 1
573 other 2
573 other 2
574
574
575 other 3
575 other 3
576
576
577 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
577 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
578 line 1
578 line 1
579 line 2
579 line 2
580
580
581
581
582 Test xml styles:
582 Test xml styles:
583
583
584 $ hg log --style xml -r 'not all()'
584 $ hg log --style xml -r 'not all()'
585 <?xml version="1.0"?>
585 <?xml version="1.0"?>
586 <log>
586 <log>
587 </log>
587 </log>
588
588
589 $ hg log --style xml
589 $ hg log --style xml
590 <?xml version="1.0"?>
590 <?xml version="1.0"?>
591 <log>
591 <log>
592 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
592 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
593 <tag>tip</tag>
593 <tag>tip</tag>
594 <author email="test">test</author>
594 <author email="test">test</author>
595 <date>2020-01-01T10:01:00+00:00</date>
595 <date>2020-01-01T10:01:00+00:00</date>
596 <msg xml:space="preserve">third</msg>
596 <msg xml:space="preserve">third</msg>
597 </logentry>
597 </logentry>
598 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
598 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
599 <parent revision="-1" node="0000000000000000000000000000000000000000" />
599 <parent revision="-1" node="0000000000000000000000000000000000000000" />
600 <author email="user@hostname">User Name</author>
600 <author email="user@hostname">User Name</author>
601 <date>1970-01-12T13:46:40+00:00</date>
601 <date>1970-01-12T13:46:40+00:00</date>
602 <msg xml:space="preserve">second</msg>
602 <msg xml:space="preserve">second</msg>
603 </logentry>
603 </logentry>
604 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
604 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
605 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
605 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
606 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
606 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
607 <author email="person">person</author>
607 <author email="person">person</author>
608 <date>1970-01-18T08:40:01+00:00</date>
608 <date>1970-01-18T08:40:01+00:00</date>
609 <msg xml:space="preserve">merge</msg>
609 <msg xml:space="preserve">merge</msg>
610 </logentry>
610 </logentry>
611 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
611 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
613 <author email="person">person</author>
613 <author email="person">person</author>
614 <date>1970-01-18T08:40:00+00:00</date>
614 <date>1970-01-18T08:40:00+00:00</date>
615 <msg xml:space="preserve">new head</msg>
615 <msg xml:space="preserve">new head</msg>
616 </logentry>
616 </logentry>
617 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
617 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
618 <branch>foo</branch>
618 <branch>foo</branch>
619 <author email="person">person</author>
619 <author email="person">person</author>
620 <date>1970-01-17T04:53:20+00:00</date>
620 <date>1970-01-17T04:53:20+00:00</date>
621 <msg xml:space="preserve">new branch</msg>
621 <msg xml:space="preserve">new branch</msg>
622 </logentry>
622 </logentry>
623 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
623 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
624 <author email="person">person</author>
624 <author email="person">person</author>
625 <date>1970-01-16T01:06:40+00:00</date>
625 <date>1970-01-16T01:06:40+00:00</date>
626 <msg xml:space="preserve">no user, no domain</msg>
626 <msg xml:space="preserve">no user, no domain</msg>
627 </logentry>
627 </logentry>
628 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
628 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
629 <author email="other@place">other</author>
629 <author email="other@place">other</author>
630 <date>1970-01-14T21:20:00+00:00</date>
630 <date>1970-01-14T21:20:00+00:00</date>
631 <msg xml:space="preserve">no person</msg>
631 <msg xml:space="preserve">no person</msg>
632 </logentry>
632 </logentry>
633 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
633 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
634 <author email="other@place">A. N. Other</author>
634 <author email="other@place">A. N. Other</author>
635 <date>1970-01-13T17:33:20+00:00</date>
635 <date>1970-01-13T17:33:20+00:00</date>
636 <msg xml:space="preserve">other 1
636 <msg xml:space="preserve">other 1
637 other 2
637 other 2
638
638
639 other 3</msg>
639 other 3</msg>
640 </logentry>
640 </logentry>
641 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
641 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
642 <author email="user@hostname">User Name</author>
642 <author email="user@hostname">User Name</author>
643 <date>1970-01-12T13:46:40+00:00</date>
643 <date>1970-01-12T13:46:40+00:00</date>
644 <msg xml:space="preserve">line 1
644 <msg xml:space="preserve">line 1
645 line 2</msg>
645 line 2</msg>
646 </logentry>
646 </logentry>
647 </log>
647 </log>
648
648
649 $ hg log -v --style xml
649 $ hg log -v --style xml
650 <?xml version="1.0"?>
650 <?xml version="1.0"?>
651 <log>
651 <log>
652 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
652 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
653 <tag>tip</tag>
653 <tag>tip</tag>
654 <author email="test">test</author>
654 <author email="test">test</author>
655 <date>2020-01-01T10:01:00+00:00</date>
655 <date>2020-01-01T10:01:00+00:00</date>
656 <msg xml:space="preserve">third</msg>
656 <msg xml:space="preserve">third</msg>
657 <paths>
657 <paths>
658 <path action="A">fourth</path>
658 <path action="A">fourth</path>
659 <path action="A">third</path>
659 <path action="A">third</path>
660 <path action="R">second</path>
660 <path action="R">second</path>
661 </paths>
661 </paths>
662 <copies>
662 <copies>
663 <copy source="second">fourth</copy>
663 <copy source="second">fourth</copy>
664 </copies>
664 </copies>
665 </logentry>
665 </logentry>
666 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
666 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
667 <parent revision="-1" node="0000000000000000000000000000000000000000" />
667 <parent revision="-1" node="0000000000000000000000000000000000000000" />
668 <author email="user@hostname">User Name</author>
668 <author email="user@hostname">User Name</author>
669 <date>1970-01-12T13:46:40+00:00</date>
669 <date>1970-01-12T13:46:40+00:00</date>
670 <msg xml:space="preserve">second</msg>
670 <msg xml:space="preserve">second</msg>
671 <paths>
671 <paths>
672 <path action="A">second</path>
672 <path action="A">second</path>
673 </paths>
673 </paths>
674 </logentry>
674 </logentry>
675 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
675 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
676 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
676 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
677 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
677 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
678 <author email="person">person</author>
678 <author email="person">person</author>
679 <date>1970-01-18T08:40:01+00:00</date>
679 <date>1970-01-18T08:40:01+00:00</date>
680 <msg xml:space="preserve">merge</msg>
680 <msg xml:space="preserve">merge</msg>
681 <paths>
681 <paths>
682 </paths>
682 </paths>
683 </logentry>
683 </logentry>
684 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
684 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
685 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
685 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
686 <author email="person">person</author>
686 <author email="person">person</author>
687 <date>1970-01-18T08:40:00+00:00</date>
687 <date>1970-01-18T08:40:00+00:00</date>
688 <msg xml:space="preserve">new head</msg>
688 <msg xml:space="preserve">new head</msg>
689 <paths>
689 <paths>
690 <path action="A">d</path>
690 <path action="A">d</path>
691 </paths>
691 </paths>
692 </logentry>
692 </logentry>
693 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
693 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
694 <branch>foo</branch>
694 <branch>foo</branch>
695 <author email="person">person</author>
695 <author email="person">person</author>
696 <date>1970-01-17T04:53:20+00:00</date>
696 <date>1970-01-17T04:53:20+00:00</date>
697 <msg xml:space="preserve">new branch</msg>
697 <msg xml:space="preserve">new branch</msg>
698 <paths>
698 <paths>
699 </paths>
699 </paths>
700 </logentry>
700 </logentry>
701 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
701 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
702 <author email="person">person</author>
702 <author email="person">person</author>
703 <date>1970-01-16T01:06:40+00:00</date>
703 <date>1970-01-16T01:06:40+00:00</date>
704 <msg xml:space="preserve">no user, no domain</msg>
704 <msg xml:space="preserve">no user, no domain</msg>
705 <paths>
705 <paths>
706 <path action="M">c</path>
706 <path action="M">c</path>
707 </paths>
707 </paths>
708 </logentry>
708 </logentry>
709 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
709 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
710 <author email="other@place">other</author>
710 <author email="other@place">other</author>
711 <date>1970-01-14T21:20:00+00:00</date>
711 <date>1970-01-14T21:20:00+00:00</date>
712 <msg xml:space="preserve">no person</msg>
712 <msg xml:space="preserve">no person</msg>
713 <paths>
713 <paths>
714 <path action="A">c</path>
714 <path action="A">c</path>
715 </paths>
715 </paths>
716 </logentry>
716 </logentry>
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
718 <author email="other@place">A. N. Other</author>
718 <author email="other@place">A. N. Other</author>
719 <date>1970-01-13T17:33:20+00:00</date>
719 <date>1970-01-13T17:33:20+00:00</date>
720 <msg xml:space="preserve">other 1
720 <msg xml:space="preserve">other 1
721 other 2
721 other 2
722
722
723 other 3</msg>
723 other 3</msg>
724 <paths>
724 <paths>
725 <path action="A">b</path>
725 <path action="A">b</path>
726 </paths>
726 </paths>
727 </logentry>
727 </logentry>
728 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
728 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
729 <author email="user@hostname">User Name</author>
729 <author email="user@hostname">User Name</author>
730 <date>1970-01-12T13:46:40+00:00</date>
730 <date>1970-01-12T13:46:40+00:00</date>
731 <msg xml:space="preserve">line 1
731 <msg xml:space="preserve">line 1
732 line 2</msg>
732 line 2</msg>
733 <paths>
733 <paths>
734 <path action="A">a</path>
734 <path action="A">a</path>
735 </paths>
735 </paths>
736 </logentry>
736 </logentry>
737 </log>
737 </log>
738
738
739 $ hg log --debug --style xml
739 $ hg log --debug --style xml
740 <?xml version="1.0"?>
740 <?xml version="1.0"?>
741 <log>
741 <log>
742 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
742 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
743 <tag>tip</tag>
743 <tag>tip</tag>
744 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
744 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
745 <parent revision="-1" node="0000000000000000000000000000000000000000" />
745 <parent revision="-1" node="0000000000000000000000000000000000000000" />
746 <author email="test">test</author>
746 <author email="test">test</author>
747 <date>2020-01-01T10:01:00+00:00</date>
747 <date>2020-01-01T10:01:00+00:00</date>
748 <msg xml:space="preserve">third</msg>
748 <msg xml:space="preserve">third</msg>
749 <paths>
749 <paths>
750 <path action="A">fourth</path>
750 <path action="A">fourth</path>
751 <path action="A">third</path>
751 <path action="A">third</path>
752 <path action="R">second</path>
752 <path action="R">second</path>
753 </paths>
753 </paths>
754 <copies>
754 <copies>
755 <copy source="second">fourth</copy>
755 <copy source="second">fourth</copy>
756 </copies>
756 </copies>
757 <extra key="branch">default</extra>
757 <extra key="branch">default</extra>
758 </logentry>
758 </logentry>
759 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
759 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
760 <parent revision="-1" node="0000000000000000000000000000000000000000" />
760 <parent revision="-1" node="0000000000000000000000000000000000000000" />
761 <parent revision="-1" node="0000000000000000000000000000000000000000" />
761 <parent revision="-1" node="0000000000000000000000000000000000000000" />
762 <author email="user@hostname">User Name</author>
762 <author email="user@hostname">User Name</author>
763 <date>1970-01-12T13:46:40+00:00</date>
763 <date>1970-01-12T13:46:40+00:00</date>
764 <msg xml:space="preserve">second</msg>
764 <msg xml:space="preserve">second</msg>
765 <paths>
765 <paths>
766 <path action="A">second</path>
766 <path action="A">second</path>
767 </paths>
767 </paths>
768 <extra key="branch">default</extra>
768 <extra key="branch">default</extra>
769 </logentry>
769 </logentry>
770 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
770 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
771 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
771 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
772 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
772 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
773 <author email="person">person</author>
773 <author email="person">person</author>
774 <date>1970-01-18T08:40:01+00:00</date>
774 <date>1970-01-18T08:40:01+00:00</date>
775 <msg xml:space="preserve">merge</msg>
775 <msg xml:space="preserve">merge</msg>
776 <paths>
776 <paths>
777 </paths>
777 </paths>
778 <extra key="branch">default</extra>
778 <extra key="branch">default</extra>
779 </logentry>
779 </logentry>
780 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
780 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
781 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
781 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
782 <parent revision="-1" node="0000000000000000000000000000000000000000" />
782 <parent revision="-1" node="0000000000000000000000000000000000000000" />
783 <author email="person">person</author>
783 <author email="person">person</author>
784 <date>1970-01-18T08:40:00+00:00</date>
784 <date>1970-01-18T08:40:00+00:00</date>
785 <msg xml:space="preserve">new head</msg>
785 <msg xml:space="preserve">new head</msg>
786 <paths>
786 <paths>
787 <path action="A">d</path>
787 <path action="A">d</path>
788 </paths>
788 </paths>
789 <extra key="branch">default</extra>
789 <extra key="branch">default</extra>
790 </logentry>
790 </logentry>
791 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
791 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
792 <branch>foo</branch>
792 <branch>foo</branch>
793 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
793 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
794 <parent revision="-1" node="0000000000000000000000000000000000000000" />
794 <parent revision="-1" node="0000000000000000000000000000000000000000" />
795 <author email="person">person</author>
795 <author email="person">person</author>
796 <date>1970-01-17T04:53:20+00:00</date>
796 <date>1970-01-17T04:53:20+00:00</date>
797 <msg xml:space="preserve">new branch</msg>
797 <msg xml:space="preserve">new branch</msg>
798 <paths>
798 <paths>
799 </paths>
799 </paths>
800 <extra key="branch">foo</extra>
800 <extra key="branch">foo</extra>
801 </logentry>
801 </logentry>
802 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
802 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
803 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
803 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
805 <author email="person">person</author>
805 <author email="person">person</author>
806 <date>1970-01-16T01:06:40+00:00</date>
806 <date>1970-01-16T01:06:40+00:00</date>
807 <msg xml:space="preserve">no user, no domain</msg>
807 <msg xml:space="preserve">no user, no domain</msg>
808 <paths>
808 <paths>
809 <path action="M">c</path>
809 <path action="M">c</path>
810 </paths>
810 </paths>
811 <extra key="branch">default</extra>
811 <extra key="branch">default</extra>
812 </logentry>
812 </logentry>
813 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
813 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
814 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
814 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
815 <parent revision="-1" node="0000000000000000000000000000000000000000" />
815 <parent revision="-1" node="0000000000000000000000000000000000000000" />
816 <author email="other@place">other</author>
816 <author email="other@place">other</author>
817 <date>1970-01-14T21:20:00+00:00</date>
817 <date>1970-01-14T21:20:00+00:00</date>
818 <msg xml:space="preserve">no person</msg>
818 <msg xml:space="preserve">no person</msg>
819 <paths>
819 <paths>
820 <path action="A">c</path>
820 <path action="A">c</path>
821 </paths>
821 </paths>
822 <extra key="branch">default</extra>
822 <extra key="branch">default</extra>
823 </logentry>
823 </logentry>
824 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
824 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
825 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
825 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
826 <parent revision="-1" node="0000000000000000000000000000000000000000" />
826 <parent revision="-1" node="0000000000000000000000000000000000000000" />
827 <author email="other@place">A. N. Other</author>
827 <author email="other@place">A. N. Other</author>
828 <date>1970-01-13T17:33:20+00:00</date>
828 <date>1970-01-13T17:33:20+00:00</date>
829 <msg xml:space="preserve">other 1
829 <msg xml:space="preserve">other 1
830 other 2
830 other 2
831
831
832 other 3</msg>
832 other 3</msg>
833 <paths>
833 <paths>
834 <path action="A">b</path>
834 <path action="A">b</path>
835 </paths>
835 </paths>
836 <extra key="branch">default</extra>
836 <extra key="branch">default</extra>
837 </logentry>
837 </logentry>
838 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
838 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
839 <parent revision="-1" node="0000000000000000000000000000000000000000" />
839 <parent revision="-1" node="0000000000000000000000000000000000000000" />
840 <parent revision="-1" node="0000000000000000000000000000000000000000" />
840 <parent revision="-1" node="0000000000000000000000000000000000000000" />
841 <author email="user@hostname">User Name</author>
841 <author email="user@hostname">User Name</author>
842 <date>1970-01-12T13:46:40+00:00</date>
842 <date>1970-01-12T13:46:40+00:00</date>
843 <msg xml:space="preserve">line 1
843 <msg xml:space="preserve">line 1
844 line 2</msg>
844 line 2</msg>
845 <paths>
845 <paths>
846 <path action="A">a</path>
846 <path action="A">a</path>
847 </paths>
847 </paths>
848 <extra key="branch">default</extra>
848 <extra key="branch">default</extra>
849 </logentry>
849 </logentry>
850 </log>
850 </log>
851
851
852
852
853 Test JSON style:
853 Test JSON style:
854
854
855 $ hg log -k nosuch -Tjson
855 $ hg log -k nosuch -Tjson
856 []
856 []
857
857
858 $ hg log -qr . -Tjson
858 $ hg log -qr . -Tjson
859 [
859 [
860 {
860 {
861 "rev": 8,
861 "rev": 8,
862 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
862 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
863 }
863 }
864 ]
864 ]
865
865
866 $ hg log -vpr . -Tjson --stat
866 $ hg log -vpr . -Tjson --stat
867 [
867 [
868 {
868 {
869 "rev": 8,
869 "rev": 8,
870 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
870 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
871 "branch": "default",
871 "branch": "default",
872 "phase": "draft",
872 "phase": "draft",
873 "user": "test",
873 "user": "test",
874 "date": [1577872860, 0],
874 "date": [1577872860, 0],
875 "desc": "third",
875 "desc": "third",
876 "bookmarks": [],
876 "bookmarks": [],
877 "tags": ["tip"],
877 "tags": ["tip"],
878 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
878 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
879 "files": ["fourth", "second", "third"],
879 "files": ["fourth", "second", "third"],
880 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
880 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
881 "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"
881 "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"
882 }
882 }
883 ]
883 ]
884
884
885 honor --git but not format-breaking diffopts
885 honor --git but not format-breaking diffopts
886 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
886 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
887 [
887 [
888 {
888 {
889 "rev": 8,
889 "rev": 8,
890 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
890 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
891 "branch": "default",
891 "branch": "default",
892 "phase": "draft",
892 "phase": "draft",
893 "user": "test",
893 "user": "test",
894 "date": [1577872860, 0],
894 "date": [1577872860, 0],
895 "desc": "third",
895 "desc": "third",
896 "bookmarks": [],
896 "bookmarks": [],
897 "tags": ["tip"],
897 "tags": ["tip"],
898 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
898 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
899 "files": ["fourth", "second", "third"],
899 "files": ["fourth", "second", "third"],
900 "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"
900 "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"
901 }
901 }
902 ]
902 ]
903
903
904 $ hg log -T json
904 $ hg log -T json
905 [
905 [
906 {
906 {
907 "rev": 8,
907 "rev": 8,
908 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
908 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
909 "branch": "default",
909 "branch": "default",
910 "phase": "draft",
910 "phase": "draft",
911 "user": "test",
911 "user": "test",
912 "date": [1577872860, 0],
912 "date": [1577872860, 0],
913 "desc": "third",
913 "desc": "third",
914 "bookmarks": [],
914 "bookmarks": [],
915 "tags": ["tip"],
915 "tags": ["tip"],
916 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
916 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
917 },
917 },
918 {
918 {
919 "rev": 7,
919 "rev": 7,
920 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
920 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
921 "branch": "default",
921 "branch": "default",
922 "phase": "draft",
922 "phase": "draft",
923 "user": "User Name <user@hostname>",
923 "user": "User Name <user@hostname>",
924 "date": [1000000, 0],
924 "date": [1000000, 0],
925 "desc": "second",
925 "desc": "second",
926 "bookmarks": [],
926 "bookmarks": [],
927 "tags": [],
927 "tags": [],
928 "parents": ["0000000000000000000000000000000000000000"]
928 "parents": ["0000000000000000000000000000000000000000"]
929 },
929 },
930 {
930 {
931 "rev": 6,
931 "rev": 6,
932 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
932 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
933 "branch": "default",
933 "branch": "default",
934 "phase": "draft",
934 "phase": "draft",
935 "user": "person",
935 "user": "person",
936 "date": [1500001, 0],
936 "date": [1500001, 0],
937 "desc": "merge",
937 "desc": "merge",
938 "bookmarks": [],
938 "bookmarks": [],
939 "tags": [],
939 "tags": [],
940 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
940 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
941 },
941 },
942 {
942 {
943 "rev": 5,
943 "rev": 5,
944 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
944 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
945 "branch": "default",
945 "branch": "default",
946 "phase": "draft",
946 "phase": "draft",
947 "user": "person",
947 "user": "person",
948 "date": [1500000, 0],
948 "date": [1500000, 0],
949 "desc": "new head",
949 "desc": "new head",
950 "bookmarks": [],
950 "bookmarks": [],
951 "tags": [],
951 "tags": [],
952 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
952 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
953 },
953 },
954 {
954 {
955 "rev": 4,
955 "rev": 4,
956 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
956 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
957 "branch": "foo",
957 "branch": "foo",
958 "phase": "draft",
958 "phase": "draft",
959 "user": "person",
959 "user": "person",
960 "date": [1400000, 0],
960 "date": [1400000, 0],
961 "desc": "new branch",
961 "desc": "new branch",
962 "bookmarks": [],
962 "bookmarks": [],
963 "tags": [],
963 "tags": [],
964 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
964 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
965 },
965 },
966 {
966 {
967 "rev": 3,
967 "rev": 3,
968 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
968 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
969 "branch": "default",
969 "branch": "default",
970 "phase": "draft",
970 "phase": "draft",
971 "user": "person",
971 "user": "person",
972 "date": [1300000, 0],
972 "date": [1300000, 0],
973 "desc": "no user, no domain",
973 "desc": "no user, no domain",
974 "bookmarks": [],
974 "bookmarks": [],
975 "tags": [],
975 "tags": [],
976 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
976 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
977 },
977 },
978 {
978 {
979 "rev": 2,
979 "rev": 2,
980 "node": "97054abb4ab824450e9164180baf491ae0078465",
980 "node": "97054abb4ab824450e9164180baf491ae0078465",
981 "branch": "default",
981 "branch": "default",
982 "phase": "draft",
982 "phase": "draft",
983 "user": "other@place",
983 "user": "other@place",
984 "date": [1200000, 0],
984 "date": [1200000, 0],
985 "desc": "no person",
985 "desc": "no person",
986 "bookmarks": [],
986 "bookmarks": [],
987 "tags": [],
987 "tags": [],
988 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
988 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
989 },
989 },
990 {
990 {
991 "rev": 1,
991 "rev": 1,
992 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
992 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
993 "branch": "default",
993 "branch": "default",
994 "phase": "draft",
994 "phase": "draft",
995 "user": "A. N. Other <other@place>",
995 "user": "A. N. Other <other@place>",
996 "date": [1100000, 0],
996 "date": [1100000, 0],
997 "desc": "other 1\nother 2\n\nother 3",
997 "desc": "other 1\nother 2\n\nother 3",
998 "bookmarks": [],
998 "bookmarks": [],
999 "tags": [],
999 "tags": [],
1000 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
1000 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
1001 },
1001 },
1002 {
1002 {
1003 "rev": 0,
1003 "rev": 0,
1004 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1004 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1005 "branch": "default",
1005 "branch": "default",
1006 "phase": "draft",
1006 "phase": "draft",
1007 "user": "User Name <user@hostname>",
1007 "user": "User Name <user@hostname>",
1008 "date": [1000000, 0],
1008 "date": [1000000, 0],
1009 "desc": "line 1\nline 2",
1009 "desc": "line 1\nline 2",
1010 "bookmarks": [],
1010 "bookmarks": [],
1011 "tags": [],
1011 "tags": [],
1012 "parents": ["0000000000000000000000000000000000000000"]
1012 "parents": ["0000000000000000000000000000000000000000"]
1013 }
1013 }
1014 ]
1014 ]
1015
1015
1016 $ hg heads -v -Tjson
1016 $ hg heads -v -Tjson
1017 [
1017 [
1018 {
1018 {
1019 "rev": 8,
1019 "rev": 8,
1020 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1020 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1021 "branch": "default",
1021 "branch": "default",
1022 "phase": "draft",
1022 "phase": "draft",
1023 "user": "test",
1023 "user": "test",
1024 "date": [1577872860, 0],
1024 "date": [1577872860, 0],
1025 "desc": "third",
1025 "desc": "third",
1026 "bookmarks": [],
1026 "bookmarks": [],
1027 "tags": ["tip"],
1027 "tags": ["tip"],
1028 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1028 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1029 "files": ["fourth", "second", "third"]
1029 "files": ["fourth", "second", "third"]
1030 },
1030 },
1031 {
1031 {
1032 "rev": 6,
1032 "rev": 6,
1033 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1033 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1034 "branch": "default",
1034 "branch": "default",
1035 "phase": "draft",
1035 "phase": "draft",
1036 "user": "person",
1036 "user": "person",
1037 "date": [1500001, 0],
1037 "date": [1500001, 0],
1038 "desc": "merge",
1038 "desc": "merge",
1039 "bookmarks": [],
1039 "bookmarks": [],
1040 "tags": [],
1040 "tags": [],
1041 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1041 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1042 "files": []
1042 "files": []
1043 },
1043 },
1044 {
1044 {
1045 "rev": 4,
1045 "rev": 4,
1046 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1046 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1047 "branch": "foo",
1047 "branch": "foo",
1048 "phase": "draft",
1048 "phase": "draft",
1049 "user": "person",
1049 "user": "person",
1050 "date": [1400000, 0],
1050 "date": [1400000, 0],
1051 "desc": "new branch",
1051 "desc": "new branch",
1052 "bookmarks": [],
1052 "bookmarks": [],
1053 "tags": [],
1053 "tags": [],
1054 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1054 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1055 "files": []
1055 "files": []
1056 }
1056 }
1057 ]
1057 ]
1058
1058
1059 $ hg log --debug -Tjson
1059 $ hg log --debug -Tjson
1060 [
1060 [
1061 {
1061 {
1062 "rev": 8,
1062 "rev": 8,
1063 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1063 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1064 "branch": "default",
1064 "branch": "default",
1065 "phase": "draft",
1065 "phase": "draft",
1066 "user": "test",
1066 "user": "test",
1067 "date": [1577872860, 0],
1067 "date": [1577872860, 0],
1068 "desc": "third",
1068 "desc": "third",
1069 "bookmarks": [],
1069 "bookmarks": [],
1070 "tags": ["tip"],
1070 "tags": ["tip"],
1071 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1071 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1072 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1072 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1073 "extra": {"branch": "default"},
1073 "extra": {"branch": "default"},
1074 "modified": [],
1074 "modified": [],
1075 "added": ["fourth", "third"],
1075 "added": ["fourth", "third"],
1076 "removed": ["second"]
1076 "removed": ["second"]
1077 },
1077 },
1078 {
1078 {
1079 "rev": 7,
1079 "rev": 7,
1080 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1080 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1081 "branch": "default",
1081 "branch": "default",
1082 "phase": "draft",
1082 "phase": "draft",
1083 "user": "User Name <user@hostname>",
1083 "user": "User Name <user@hostname>",
1084 "date": [1000000, 0],
1084 "date": [1000000, 0],
1085 "desc": "second",
1085 "desc": "second",
1086 "bookmarks": [],
1086 "bookmarks": [],
1087 "tags": [],
1087 "tags": [],
1088 "parents": ["0000000000000000000000000000000000000000"],
1088 "parents": ["0000000000000000000000000000000000000000"],
1089 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1089 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1090 "extra": {"branch": "default"},
1090 "extra": {"branch": "default"},
1091 "modified": [],
1091 "modified": [],
1092 "added": ["second"],
1092 "added": ["second"],
1093 "removed": []
1093 "removed": []
1094 },
1094 },
1095 {
1095 {
1096 "rev": 6,
1096 "rev": 6,
1097 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1097 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1098 "branch": "default",
1098 "branch": "default",
1099 "phase": "draft",
1099 "phase": "draft",
1100 "user": "person",
1100 "user": "person",
1101 "date": [1500001, 0],
1101 "date": [1500001, 0],
1102 "desc": "merge",
1102 "desc": "merge",
1103 "bookmarks": [],
1103 "bookmarks": [],
1104 "tags": [],
1104 "tags": [],
1105 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1105 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1106 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1106 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1107 "extra": {"branch": "default"},
1107 "extra": {"branch": "default"},
1108 "modified": [],
1108 "modified": [],
1109 "added": [],
1109 "added": [],
1110 "removed": []
1110 "removed": []
1111 },
1111 },
1112 {
1112 {
1113 "rev": 5,
1113 "rev": 5,
1114 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1114 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1115 "branch": "default",
1115 "branch": "default",
1116 "phase": "draft",
1116 "phase": "draft",
1117 "user": "person",
1117 "user": "person",
1118 "date": [1500000, 0],
1118 "date": [1500000, 0],
1119 "desc": "new head",
1119 "desc": "new head",
1120 "bookmarks": [],
1120 "bookmarks": [],
1121 "tags": [],
1121 "tags": [],
1122 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1122 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1123 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1123 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1124 "extra": {"branch": "default"},
1124 "extra": {"branch": "default"},
1125 "modified": [],
1125 "modified": [],
1126 "added": ["d"],
1126 "added": ["d"],
1127 "removed": []
1127 "removed": []
1128 },
1128 },
1129 {
1129 {
1130 "rev": 4,
1130 "rev": 4,
1131 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1131 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1132 "branch": "foo",
1132 "branch": "foo",
1133 "phase": "draft",
1133 "phase": "draft",
1134 "user": "person",
1134 "user": "person",
1135 "date": [1400000, 0],
1135 "date": [1400000, 0],
1136 "desc": "new branch",
1136 "desc": "new branch",
1137 "bookmarks": [],
1137 "bookmarks": [],
1138 "tags": [],
1138 "tags": [],
1139 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1139 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1140 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1140 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1141 "extra": {"branch": "foo"},
1141 "extra": {"branch": "foo"},
1142 "modified": [],
1142 "modified": [],
1143 "added": [],
1143 "added": [],
1144 "removed": []
1144 "removed": []
1145 },
1145 },
1146 {
1146 {
1147 "rev": 3,
1147 "rev": 3,
1148 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1148 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1149 "branch": "default",
1149 "branch": "default",
1150 "phase": "draft",
1150 "phase": "draft",
1151 "user": "person",
1151 "user": "person",
1152 "date": [1300000, 0],
1152 "date": [1300000, 0],
1153 "desc": "no user, no domain",
1153 "desc": "no user, no domain",
1154 "bookmarks": [],
1154 "bookmarks": [],
1155 "tags": [],
1155 "tags": [],
1156 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1156 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1157 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1157 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1158 "extra": {"branch": "default"},
1158 "extra": {"branch": "default"},
1159 "modified": ["c"],
1159 "modified": ["c"],
1160 "added": [],
1160 "added": [],
1161 "removed": []
1161 "removed": []
1162 },
1162 },
1163 {
1163 {
1164 "rev": 2,
1164 "rev": 2,
1165 "node": "97054abb4ab824450e9164180baf491ae0078465",
1165 "node": "97054abb4ab824450e9164180baf491ae0078465",
1166 "branch": "default",
1166 "branch": "default",
1167 "phase": "draft",
1167 "phase": "draft",
1168 "user": "other@place",
1168 "user": "other@place",
1169 "date": [1200000, 0],
1169 "date": [1200000, 0],
1170 "desc": "no person",
1170 "desc": "no person",
1171 "bookmarks": [],
1171 "bookmarks": [],
1172 "tags": [],
1172 "tags": [],
1173 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1173 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1174 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1174 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1175 "extra": {"branch": "default"},
1175 "extra": {"branch": "default"},
1176 "modified": [],
1176 "modified": [],
1177 "added": ["c"],
1177 "added": ["c"],
1178 "removed": []
1178 "removed": []
1179 },
1179 },
1180 {
1180 {
1181 "rev": 1,
1181 "rev": 1,
1182 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1182 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1183 "branch": "default",
1183 "branch": "default",
1184 "phase": "draft",
1184 "phase": "draft",
1185 "user": "A. N. Other <other@place>",
1185 "user": "A. N. Other <other@place>",
1186 "date": [1100000, 0],
1186 "date": [1100000, 0],
1187 "desc": "other 1\nother 2\n\nother 3",
1187 "desc": "other 1\nother 2\n\nother 3",
1188 "bookmarks": [],
1188 "bookmarks": [],
1189 "tags": [],
1189 "tags": [],
1190 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1190 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1191 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1191 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1192 "extra": {"branch": "default"},
1192 "extra": {"branch": "default"},
1193 "modified": [],
1193 "modified": [],
1194 "added": ["b"],
1194 "added": ["b"],
1195 "removed": []
1195 "removed": []
1196 },
1196 },
1197 {
1197 {
1198 "rev": 0,
1198 "rev": 0,
1199 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1199 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1200 "branch": "default",
1200 "branch": "default",
1201 "phase": "draft",
1201 "phase": "draft",
1202 "user": "User Name <user@hostname>",
1202 "user": "User Name <user@hostname>",
1203 "date": [1000000, 0],
1203 "date": [1000000, 0],
1204 "desc": "line 1\nline 2",
1204 "desc": "line 1\nline 2",
1205 "bookmarks": [],
1205 "bookmarks": [],
1206 "tags": [],
1206 "tags": [],
1207 "parents": ["0000000000000000000000000000000000000000"],
1207 "parents": ["0000000000000000000000000000000000000000"],
1208 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1208 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1209 "extra": {"branch": "default"},
1209 "extra": {"branch": "default"},
1210 "modified": [],
1210 "modified": [],
1211 "added": ["a"],
1211 "added": ["a"],
1212 "removed": []
1212 "removed": []
1213 }
1213 }
1214 ]
1214 ]
1215
1215
1216 Error if style not readable:
1216 Error if style not readable:
1217
1217
1218 #if unix-permissions no-root
1218 #if unix-permissions no-root
1219 $ touch q
1219 $ touch q
1220 $ chmod 0 q
1220 $ chmod 0 q
1221 $ hg log --style ./q
1221 $ hg log --style ./q
1222 abort: Permission denied: ./q
1222 abort: Permission denied: ./q
1223 [255]
1223 [255]
1224 #endif
1224 #endif
1225
1225
1226 Error if no style:
1226 Error if no style:
1227
1227
1228 $ hg log --style notexist
1228 $ hg log --style notexist
1229 abort: style 'notexist' not found
1229 abort: style 'notexist' not found
1230 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1230 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1231 [255]
1231 [255]
1232
1232
1233 $ hg log -T list
1233 $ hg log -T list
1234 available styles: bisect, changelog, compact, default, phases, show, status, xml
1234 available styles: bisect, changelog, compact, default, phases, show, status, xml
1235 abort: specify a template
1235 abort: specify a template
1236 [255]
1236 [255]
1237
1237
1238 Error if style missing key:
1238 Error if style missing key:
1239
1239
1240 $ echo 'q = q' > t
1240 $ echo 'q = q' > t
1241 $ hg log --style ./t
1241 $ hg log --style ./t
1242 abort: "changeset" not in template map
1242 abort: "changeset" not in template map
1243 [255]
1243 [255]
1244
1244
1245 Error if style missing value:
1245 Error if style missing value:
1246
1246
1247 $ echo 'changeset =' > t
1247 $ echo 'changeset =' > t
1248 $ hg log --style t
1248 $ hg log --style t
1249 hg: parse error at t:1: missing value
1249 hg: parse error at t:1: missing value
1250 [255]
1250 [255]
1251
1251
1252 Error if include fails:
1252 Error if include fails:
1253
1253
1254 $ echo 'changeset = q' >> t
1254 $ echo 'changeset = q' >> t
1255 #if unix-permissions no-root
1255 #if unix-permissions no-root
1256 $ hg log --style ./t
1256 $ hg log --style ./t
1257 abort: template file ./q: Permission denied
1257 abort: template file ./q: Permission denied
1258 [255]
1258 [255]
1259 $ rm -f q
1259 $ rm -f q
1260 #endif
1260 #endif
1261
1261
1262 Include works:
1262 Include works:
1263
1263
1264 $ echo '{rev}' > q
1264 $ echo '{rev}' > q
1265 $ hg log --style ./t
1265 $ hg log --style ./t
1266 8
1266 8
1267 7
1267 7
1268 6
1268 6
1269 5
1269 5
1270 4
1270 4
1271 3
1271 3
1272 2
1272 2
1273 1
1273 1
1274 0
1274 0
1275
1275
1276 Check that recursive reference does not fall into RuntimeError (issue4758):
1276 Check that recursive reference does not fall into RuntimeError (issue4758):
1277
1277
1278 common mistake:
1278 common mistake:
1279
1279
1280 $ cat << EOF > issue4758
1280 $ cat << EOF > issue4758
1281 > changeset = '{changeset}\n'
1281 > changeset = '{changeset}\n'
1282 > EOF
1282 > EOF
1283 $ hg log --style ./issue4758
1283 $ hg log --style ./issue4758
1284 abort: recursive reference 'changeset' in template
1284 abort: recursive reference 'changeset' in template
1285 [255]
1285 [255]
1286
1286
1287 circular reference:
1287 circular reference:
1288
1288
1289 $ cat << EOF > issue4758
1289 $ cat << EOF > issue4758
1290 > changeset = '{foo}'
1290 > changeset = '{foo}'
1291 > foo = '{changeset}'
1291 > foo = '{changeset}'
1292 > EOF
1292 > EOF
1293 $ hg log --style ./issue4758
1293 $ hg log --style ./issue4758
1294 abort: recursive reference 'foo' in template
1294 abort: recursive reference 'foo' in template
1295 [255]
1295 [255]
1296
1296
1297 buildmap() -> gettemplate(), where no thunk was made:
1297 buildmap() -> gettemplate(), where no thunk was made:
1298
1298
1299 $ cat << EOF > issue4758
1299 $ cat << EOF > issue4758
1300 > changeset = '{files % changeset}\n'
1300 > changeset = '{files % changeset}\n'
1301 > EOF
1301 > EOF
1302 $ hg log --style ./issue4758
1302 $ hg log --style ./issue4758
1303 abort: recursive reference 'changeset' in template
1303 abort: recursive reference 'changeset' in template
1304 [255]
1304 [255]
1305
1305
1306 not a recursion if a keyword of the same name exists:
1306 not a recursion if a keyword of the same name exists:
1307
1307
1308 $ cat << EOF > issue4758
1308 $ cat << EOF > issue4758
1309 > changeset = '{tags % rev}'
1309 > changeset = '{tags % rev}'
1310 > rev = '{rev} {tag}\n'
1310 > rev = '{rev} {tag}\n'
1311 > EOF
1311 > EOF
1312 $ hg log --style ./issue4758 -r tip
1312 $ hg log --style ./issue4758 -r tip
1313 8 tip
1313 8 tip
1314
1314
1315 Check that {phase} works correctly on parents:
1315 Check that {phase} works correctly on parents:
1316
1316
1317 $ cat << EOF > parentphase
1317 $ cat << EOF > parentphase
1318 > changeset_debug = '{rev} ({phase}):{parents}\n'
1318 > changeset_debug = '{rev} ({phase}):{parents}\n'
1319 > parent = ' {rev} ({phase})'
1319 > parent = ' {rev} ({phase})'
1320 > EOF
1320 > EOF
1321 $ hg phase -r 5 --public
1321 $ hg phase -r 5 --public
1322 $ hg phase -r 7 --secret --force
1322 $ hg phase -r 7 --secret --force
1323 $ hg log --debug -G --style ./parentphase
1323 $ hg log --debug -G --style ./parentphase
1324 @ 8 (secret): 7 (secret) -1 (public)
1324 @ 8 (secret): 7 (secret) -1 (public)
1325 |
1325 |
1326 o 7 (secret): -1 (public) -1 (public)
1326 o 7 (secret): -1 (public) -1 (public)
1327
1327
1328 o 6 (draft): 5 (public) 4 (draft)
1328 o 6 (draft): 5 (public) 4 (draft)
1329 |\
1329 |\
1330 | o 5 (public): 3 (public) -1 (public)
1330 | o 5 (public): 3 (public) -1 (public)
1331 | |
1331 | |
1332 o | 4 (draft): 3 (public) -1 (public)
1332 o | 4 (draft): 3 (public) -1 (public)
1333 |/
1333 |/
1334 o 3 (public): 2 (public) -1 (public)
1334 o 3 (public): 2 (public) -1 (public)
1335 |
1335 |
1336 o 2 (public): 1 (public) -1 (public)
1336 o 2 (public): 1 (public) -1 (public)
1337 |
1337 |
1338 o 1 (public): 0 (public) -1 (public)
1338 o 1 (public): 0 (public) -1 (public)
1339 |
1339 |
1340 o 0 (public): -1 (public) -1 (public)
1340 o 0 (public): -1 (public) -1 (public)
1341
1341
1342
1342
1343 Missing non-standard names give no error (backward compatibility):
1343 Missing non-standard names give no error (backward compatibility):
1344
1344
1345 $ echo "changeset = '{c}'" > t
1345 $ echo "changeset = '{c}'" > t
1346 $ hg log --style ./t
1346 $ hg log --style ./t
1347
1347
1348 Defining non-standard name works:
1348 Defining non-standard name works:
1349
1349
1350 $ cat <<EOF > t
1350 $ cat <<EOF > t
1351 > changeset = '{c}'
1351 > changeset = '{c}'
1352 > c = q
1352 > c = q
1353 > EOF
1353 > EOF
1354 $ hg log --style ./t
1354 $ hg log --style ./t
1355 8
1355 8
1356 7
1356 7
1357 6
1357 6
1358 5
1358 5
1359 4
1359 4
1360 3
1360 3
1361 2
1361 2
1362 1
1362 1
1363 0
1363 0
1364
1364
1365 ui.style works:
1365 ui.style works:
1366
1366
1367 $ echo '[ui]' > .hg/hgrc
1367 $ echo '[ui]' > .hg/hgrc
1368 $ echo 'style = t' >> .hg/hgrc
1368 $ echo 'style = t' >> .hg/hgrc
1369 $ hg log
1369 $ hg log
1370 8
1370 8
1371 7
1371 7
1372 6
1372 6
1373 5
1373 5
1374 4
1374 4
1375 3
1375 3
1376 2
1376 2
1377 1
1377 1
1378 0
1378 0
1379
1379
1380
1380
1381 Issue338:
1381 Issue338:
1382
1382
1383 $ hg log --style=changelog > changelog
1383 $ hg log --style=changelog > changelog
1384
1384
1385 $ cat changelog
1385 $ cat changelog
1386 2020-01-01 test <test>
1386 2020-01-01 test <test>
1387
1387
1388 * fourth, second, third:
1388 * fourth, second, third:
1389 third
1389 third
1390 [95c24699272e] [tip]
1390 [95c24699272e] [tip]
1391
1391
1392 1970-01-12 User Name <user@hostname>
1392 1970-01-12 User Name <user@hostname>
1393
1393
1394 * second:
1394 * second:
1395 second
1395 second
1396 [29114dbae42b]
1396 [29114dbae42b]
1397
1397
1398 1970-01-18 person <person>
1398 1970-01-18 person <person>
1399
1399
1400 * merge
1400 * merge
1401 [d41e714fe50d]
1401 [d41e714fe50d]
1402
1402
1403 * d:
1403 * d:
1404 new head
1404 new head
1405 [13207e5a10d9]
1405 [13207e5a10d9]
1406
1406
1407 1970-01-17 person <person>
1407 1970-01-17 person <person>
1408
1408
1409 * new branch
1409 * new branch
1410 [bbe44766e73d] <foo>
1410 [bbe44766e73d] <foo>
1411
1411
1412 1970-01-16 person <person>
1412 1970-01-16 person <person>
1413
1413
1414 * c:
1414 * c:
1415 no user, no domain
1415 no user, no domain
1416 [10e46f2dcbf4]
1416 [10e46f2dcbf4]
1417
1417
1418 1970-01-14 other <other@place>
1418 1970-01-14 other <other@place>
1419
1419
1420 * c:
1420 * c:
1421 no person
1421 no person
1422 [97054abb4ab8]
1422 [97054abb4ab8]
1423
1423
1424 1970-01-13 A. N. Other <other@place>
1424 1970-01-13 A. N. Other <other@place>
1425
1425
1426 * b:
1426 * b:
1427 other 1 other 2
1427 other 1 other 2
1428
1428
1429 other 3
1429 other 3
1430 [b608e9d1a3f0]
1430 [b608e9d1a3f0]
1431
1431
1432 1970-01-12 User Name <user@hostname>
1432 1970-01-12 User Name <user@hostname>
1433
1433
1434 * a:
1434 * a:
1435 line 1 line 2
1435 line 1 line 2
1436 [1e4e1b8f71e0]
1436 [1e4e1b8f71e0]
1437
1437
1438
1438
1439 Issue2130: xml output for 'hg heads' is malformed
1439 Issue2130: xml output for 'hg heads' is malformed
1440
1440
1441 $ hg heads --style changelog
1441 $ hg heads --style changelog
1442 2020-01-01 test <test>
1442 2020-01-01 test <test>
1443
1443
1444 * fourth, second, third:
1444 * fourth, second, third:
1445 third
1445 third
1446 [95c24699272e] [tip]
1446 [95c24699272e] [tip]
1447
1447
1448 1970-01-18 person <person>
1448 1970-01-18 person <person>
1449
1449
1450 * merge
1450 * merge
1451 [d41e714fe50d]
1451 [d41e714fe50d]
1452
1452
1453 1970-01-17 person <person>
1453 1970-01-17 person <person>
1454
1454
1455 * new branch
1455 * new branch
1456 [bbe44766e73d] <foo>
1456 [bbe44766e73d] <foo>
1457
1457
1458
1458
1459 Keys work:
1459 Keys work:
1460
1460
1461 $ for key in author branch branches date desc file_adds file_dels file_mods \
1461 $ for key in author branch branches date desc file_adds file_dels file_mods \
1462 > file_copies file_copies_switch files \
1462 > file_copies file_copies_switch files \
1463 > manifest node parents rev tags diffstat extras \
1463 > manifest node parents rev tags diffstat extras \
1464 > p1rev p2rev p1node p2node; do
1464 > p1rev p2rev p1node p2node; do
1465 > for mode in '' --verbose --debug; do
1465 > for mode in '' --verbose --debug; do
1466 > hg log $mode --template "$key$mode: {$key}\n"
1466 > hg log $mode --template "$key$mode: {$key}\n"
1467 > done
1467 > done
1468 > done
1468 > done
1469 author: test
1469 author: test
1470 author: User Name <user@hostname>
1470 author: User Name <user@hostname>
1471 author: person
1471 author: person
1472 author: person
1472 author: person
1473 author: person
1473 author: person
1474 author: person
1474 author: person
1475 author: other@place
1475 author: other@place
1476 author: A. N. Other <other@place>
1476 author: A. N. Other <other@place>
1477 author: User Name <user@hostname>
1477 author: User Name <user@hostname>
1478 author--verbose: test
1478 author--verbose: test
1479 author--verbose: User Name <user@hostname>
1479 author--verbose: User Name <user@hostname>
1480 author--verbose: person
1480 author--verbose: person
1481 author--verbose: person
1481 author--verbose: person
1482 author--verbose: person
1482 author--verbose: person
1483 author--verbose: person
1483 author--verbose: person
1484 author--verbose: other@place
1484 author--verbose: other@place
1485 author--verbose: A. N. Other <other@place>
1485 author--verbose: A. N. Other <other@place>
1486 author--verbose: User Name <user@hostname>
1486 author--verbose: User Name <user@hostname>
1487 author--debug: test
1487 author--debug: test
1488 author--debug: User Name <user@hostname>
1488 author--debug: User Name <user@hostname>
1489 author--debug: person
1489 author--debug: person
1490 author--debug: person
1490 author--debug: person
1491 author--debug: person
1491 author--debug: person
1492 author--debug: person
1492 author--debug: person
1493 author--debug: other@place
1493 author--debug: other@place
1494 author--debug: A. N. Other <other@place>
1494 author--debug: A. N. Other <other@place>
1495 author--debug: User Name <user@hostname>
1495 author--debug: User Name <user@hostname>
1496 branch: default
1496 branch: default
1497 branch: default
1497 branch: default
1498 branch: default
1498 branch: default
1499 branch: default
1499 branch: default
1500 branch: foo
1500 branch: foo
1501 branch: default
1501 branch: default
1502 branch: default
1502 branch: default
1503 branch: default
1503 branch: default
1504 branch: default
1504 branch: default
1505 branch--verbose: default
1505 branch--verbose: default
1506 branch--verbose: default
1506 branch--verbose: default
1507 branch--verbose: default
1507 branch--verbose: default
1508 branch--verbose: default
1508 branch--verbose: default
1509 branch--verbose: foo
1509 branch--verbose: foo
1510 branch--verbose: default
1510 branch--verbose: default
1511 branch--verbose: default
1511 branch--verbose: default
1512 branch--verbose: default
1512 branch--verbose: default
1513 branch--verbose: default
1513 branch--verbose: default
1514 branch--debug: default
1514 branch--debug: default
1515 branch--debug: default
1515 branch--debug: default
1516 branch--debug: default
1516 branch--debug: default
1517 branch--debug: default
1517 branch--debug: default
1518 branch--debug: foo
1518 branch--debug: foo
1519 branch--debug: default
1519 branch--debug: default
1520 branch--debug: default
1520 branch--debug: default
1521 branch--debug: default
1521 branch--debug: default
1522 branch--debug: default
1522 branch--debug: default
1523 branches:
1523 branches:
1524 branches:
1524 branches:
1525 branches:
1525 branches:
1526 branches:
1526 branches:
1527 branches: foo
1527 branches: foo
1528 branches:
1528 branches:
1529 branches:
1529 branches:
1530 branches:
1530 branches:
1531 branches:
1531 branches:
1532 branches--verbose:
1532 branches--verbose:
1533 branches--verbose:
1533 branches--verbose:
1534 branches--verbose:
1534 branches--verbose:
1535 branches--verbose:
1535 branches--verbose:
1536 branches--verbose: foo
1536 branches--verbose: foo
1537 branches--verbose:
1537 branches--verbose:
1538 branches--verbose:
1538 branches--verbose:
1539 branches--verbose:
1539 branches--verbose:
1540 branches--verbose:
1540 branches--verbose:
1541 branches--debug:
1541 branches--debug:
1542 branches--debug:
1542 branches--debug:
1543 branches--debug:
1543 branches--debug:
1544 branches--debug:
1544 branches--debug:
1545 branches--debug: foo
1545 branches--debug: foo
1546 branches--debug:
1546 branches--debug:
1547 branches--debug:
1547 branches--debug:
1548 branches--debug:
1548 branches--debug:
1549 branches--debug:
1549 branches--debug:
1550 date: 1577872860.00
1550 date: 1577872860.00
1551 date: 1000000.00
1551 date: 1000000.00
1552 date: 1500001.00
1552 date: 1500001.00
1553 date: 1500000.00
1553 date: 1500000.00
1554 date: 1400000.00
1554 date: 1400000.00
1555 date: 1300000.00
1555 date: 1300000.00
1556 date: 1200000.00
1556 date: 1200000.00
1557 date: 1100000.00
1557 date: 1100000.00
1558 date: 1000000.00
1558 date: 1000000.00
1559 date--verbose: 1577872860.00
1559 date--verbose: 1577872860.00
1560 date--verbose: 1000000.00
1560 date--verbose: 1000000.00
1561 date--verbose: 1500001.00
1561 date--verbose: 1500001.00
1562 date--verbose: 1500000.00
1562 date--verbose: 1500000.00
1563 date--verbose: 1400000.00
1563 date--verbose: 1400000.00
1564 date--verbose: 1300000.00
1564 date--verbose: 1300000.00
1565 date--verbose: 1200000.00
1565 date--verbose: 1200000.00
1566 date--verbose: 1100000.00
1566 date--verbose: 1100000.00
1567 date--verbose: 1000000.00
1567 date--verbose: 1000000.00
1568 date--debug: 1577872860.00
1568 date--debug: 1577872860.00
1569 date--debug: 1000000.00
1569 date--debug: 1000000.00
1570 date--debug: 1500001.00
1570 date--debug: 1500001.00
1571 date--debug: 1500000.00
1571 date--debug: 1500000.00
1572 date--debug: 1400000.00
1572 date--debug: 1400000.00
1573 date--debug: 1300000.00
1573 date--debug: 1300000.00
1574 date--debug: 1200000.00
1574 date--debug: 1200000.00
1575 date--debug: 1100000.00
1575 date--debug: 1100000.00
1576 date--debug: 1000000.00
1576 date--debug: 1000000.00
1577 desc: third
1577 desc: third
1578 desc: second
1578 desc: second
1579 desc: merge
1579 desc: merge
1580 desc: new head
1580 desc: new head
1581 desc: new branch
1581 desc: new branch
1582 desc: no user, no domain
1582 desc: no user, no domain
1583 desc: no person
1583 desc: no person
1584 desc: other 1
1584 desc: other 1
1585 other 2
1585 other 2
1586
1586
1587 other 3
1587 other 3
1588 desc: line 1
1588 desc: line 1
1589 line 2
1589 line 2
1590 desc--verbose: third
1590 desc--verbose: third
1591 desc--verbose: second
1591 desc--verbose: second
1592 desc--verbose: merge
1592 desc--verbose: merge
1593 desc--verbose: new head
1593 desc--verbose: new head
1594 desc--verbose: new branch
1594 desc--verbose: new branch
1595 desc--verbose: no user, no domain
1595 desc--verbose: no user, no domain
1596 desc--verbose: no person
1596 desc--verbose: no person
1597 desc--verbose: other 1
1597 desc--verbose: other 1
1598 other 2
1598 other 2
1599
1599
1600 other 3
1600 other 3
1601 desc--verbose: line 1
1601 desc--verbose: line 1
1602 line 2
1602 line 2
1603 desc--debug: third
1603 desc--debug: third
1604 desc--debug: second
1604 desc--debug: second
1605 desc--debug: merge
1605 desc--debug: merge
1606 desc--debug: new head
1606 desc--debug: new head
1607 desc--debug: new branch
1607 desc--debug: new branch
1608 desc--debug: no user, no domain
1608 desc--debug: no user, no domain
1609 desc--debug: no person
1609 desc--debug: no person
1610 desc--debug: other 1
1610 desc--debug: other 1
1611 other 2
1611 other 2
1612
1612
1613 other 3
1613 other 3
1614 desc--debug: line 1
1614 desc--debug: line 1
1615 line 2
1615 line 2
1616 file_adds: fourth third
1616 file_adds: fourth third
1617 file_adds: second
1617 file_adds: second
1618 file_adds:
1618 file_adds:
1619 file_adds: d
1619 file_adds: d
1620 file_adds:
1620 file_adds:
1621 file_adds:
1621 file_adds:
1622 file_adds: c
1622 file_adds: c
1623 file_adds: b
1623 file_adds: b
1624 file_adds: a
1624 file_adds: a
1625 file_adds--verbose: fourth third
1625 file_adds--verbose: fourth third
1626 file_adds--verbose: second
1626 file_adds--verbose: second
1627 file_adds--verbose:
1627 file_adds--verbose:
1628 file_adds--verbose: d
1628 file_adds--verbose: d
1629 file_adds--verbose:
1629 file_adds--verbose:
1630 file_adds--verbose:
1630 file_adds--verbose:
1631 file_adds--verbose: c
1631 file_adds--verbose: c
1632 file_adds--verbose: b
1632 file_adds--verbose: b
1633 file_adds--verbose: a
1633 file_adds--verbose: a
1634 file_adds--debug: fourth third
1634 file_adds--debug: fourth third
1635 file_adds--debug: second
1635 file_adds--debug: second
1636 file_adds--debug:
1636 file_adds--debug:
1637 file_adds--debug: d
1637 file_adds--debug: d
1638 file_adds--debug:
1638 file_adds--debug:
1639 file_adds--debug:
1639 file_adds--debug:
1640 file_adds--debug: c
1640 file_adds--debug: c
1641 file_adds--debug: b
1641 file_adds--debug: b
1642 file_adds--debug: a
1642 file_adds--debug: a
1643 file_dels: second
1643 file_dels: second
1644 file_dels:
1644 file_dels:
1645 file_dels:
1645 file_dels:
1646 file_dels:
1646 file_dels:
1647 file_dels:
1647 file_dels:
1648 file_dels:
1648 file_dels:
1649 file_dels:
1649 file_dels:
1650 file_dels:
1650 file_dels:
1651 file_dels:
1651 file_dels:
1652 file_dels--verbose: second
1652 file_dels--verbose: second
1653 file_dels--verbose:
1653 file_dels--verbose:
1654 file_dels--verbose:
1654 file_dels--verbose:
1655 file_dels--verbose:
1655 file_dels--verbose:
1656 file_dels--verbose:
1656 file_dels--verbose:
1657 file_dels--verbose:
1657 file_dels--verbose:
1658 file_dels--verbose:
1658 file_dels--verbose:
1659 file_dels--verbose:
1659 file_dels--verbose:
1660 file_dels--verbose:
1660 file_dels--verbose:
1661 file_dels--debug: second
1661 file_dels--debug: second
1662 file_dels--debug:
1662 file_dels--debug:
1663 file_dels--debug:
1663 file_dels--debug:
1664 file_dels--debug:
1664 file_dels--debug:
1665 file_dels--debug:
1665 file_dels--debug:
1666 file_dels--debug:
1666 file_dels--debug:
1667 file_dels--debug:
1667 file_dels--debug:
1668 file_dels--debug:
1668 file_dels--debug:
1669 file_dels--debug:
1669 file_dels--debug:
1670 file_mods:
1670 file_mods:
1671 file_mods:
1671 file_mods:
1672 file_mods:
1672 file_mods:
1673 file_mods:
1673 file_mods:
1674 file_mods:
1674 file_mods:
1675 file_mods: c
1675 file_mods: c
1676 file_mods:
1676 file_mods:
1677 file_mods:
1677 file_mods:
1678 file_mods:
1678 file_mods:
1679 file_mods--verbose:
1679 file_mods--verbose:
1680 file_mods--verbose:
1680 file_mods--verbose:
1681 file_mods--verbose:
1681 file_mods--verbose:
1682 file_mods--verbose:
1682 file_mods--verbose:
1683 file_mods--verbose:
1683 file_mods--verbose:
1684 file_mods--verbose: c
1684 file_mods--verbose: c
1685 file_mods--verbose:
1685 file_mods--verbose:
1686 file_mods--verbose:
1686 file_mods--verbose:
1687 file_mods--verbose:
1687 file_mods--verbose:
1688 file_mods--debug:
1688 file_mods--debug:
1689 file_mods--debug:
1689 file_mods--debug:
1690 file_mods--debug:
1690 file_mods--debug:
1691 file_mods--debug:
1691 file_mods--debug:
1692 file_mods--debug:
1692 file_mods--debug:
1693 file_mods--debug: c
1693 file_mods--debug: c
1694 file_mods--debug:
1694 file_mods--debug:
1695 file_mods--debug:
1695 file_mods--debug:
1696 file_mods--debug:
1696 file_mods--debug:
1697 file_copies: fourth (second)
1697 file_copies: fourth (second)
1698 file_copies:
1698 file_copies:
1699 file_copies:
1699 file_copies:
1700 file_copies:
1700 file_copies:
1701 file_copies:
1701 file_copies:
1702 file_copies:
1702 file_copies:
1703 file_copies:
1703 file_copies:
1704 file_copies:
1704 file_copies:
1705 file_copies:
1705 file_copies:
1706 file_copies--verbose: fourth (second)
1706 file_copies--verbose: fourth (second)
1707 file_copies--verbose:
1707 file_copies--verbose:
1708 file_copies--verbose:
1708 file_copies--verbose:
1709 file_copies--verbose:
1709 file_copies--verbose:
1710 file_copies--verbose:
1710 file_copies--verbose:
1711 file_copies--verbose:
1711 file_copies--verbose:
1712 file_copies--verbose:
1712 file_copies--verbose:
1713 file_copies--verbose:
1713 file_copies--verbose:
1714 file_copies--verbose:
1714 file_copies--verbose:
1715 file_copies--debug: fourth (second)
1715 file_copies--debug: fourth (second)
1716 file_copies--debug:
1716 file_copies--debug:
1717 file_copies--debug:
1717 file_copies--debug:
1718 file_copies--debug:
1718 file_copies--debug:
1719 file_copies--debug:
1719 file_copies--debug:
1720 file_copies--debug:
1720 file_copies--debug:
1721 file_copies--debug:
1721 file_copies--debug:
1722 file_copies--debug:
1722 file_copies--debug:
1723 file_copies--debug:
1723 file_copies--debug:
1724 file_copies_switch:
1724 file_copies_switch:
1725 file_copies_switch:
1725 file_copies_switch:
1726 file_copies_switch:
1726 file_copies_switch:
1727 file_copies_switch:
1727 file_copies_switch:
1728 file_copies_switch:
1728 file_copies_switch:
1729 file_copies_switch:
1729 file_copies_switch:
1730 file_copies_switch:
1730 file_copies_switch:
1731 file_copies_switch:
1731 file_copies_switch:
1732 file_copies_switch:
1732 file_copies_switch:
1733 file_copies_switch--verbose:
1733 file_copies_switch--verbose:
1734 file_copies_switch--verbose:
1734 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1739 file_copies_switch--verbose:
1739 file_copies_switch--verbose:
1740 file_copies_switch--verbose:
1740 file_copies_switch--verbose:
1741 file_copies_switch--verbose:
1741 file_copies_switch--verbose:
1742 file_copies_switch--debug:
1742 file_copies_switch--debug:
1743 file_copies_switch--debug:
1743 file_copies_switch--debug:
1744 file_copies_switch--debug:
1744 file_copies_switch--debug:
1745 file_copies_switch--debug:
1745 file_copies_switch--debug:
1746 file_copies_switch--debug:
1746 file_copies_switch--debug:
1747 file_copies_switch--debug:
1747 file_copies_switch--debug:
1748 file_copies_switch--debug:
1748 file_copies_switch--debug:
1749 file_copies_switch--debug:
1749 file_copies_switch--debug:
1750 file_copies_switch--debug:
1750 file_copies_switch--debug:
1751 files: fourth second third
1751 files: fourth second third
1752 files: second
1752 files: second
1753 files:
1753 files:
1754 files: d
1754 files: d
1755 files:
1755 files:
1756 files: c
1756 files: c
1757 files: c
1757 files: c
1758 files: b
1758 files: b
1759 files: a
1759 files: a
1760 files--verbose: fourth second third
1760 files--verbose: fourth second third
1761 files--verbose: second
1761 files--verbose: second
1762 files--verbose:
1762 files--verbose:
1763 files--verbose: d
1763 files--verbose: d
1764 files--verbose:
1764 files--verbose:
1765 files--verbose: c
1765 files--verbose: c
1766 files--verbose: c
1766 files--verbose: c
1767 files--verbose: b
1767 files--verbose: b
1768 files--verbose: a
1768 files--verbose: a
1769 files--debug: fourth second third
1769 files--debug: fourth second third
1770 files--debug: second
1770 files--debug: second
1771 files--debug:
1771 files--debug:
1772 files--debug: d
1772 files--debug: d
1773 files--debug:
1773 files--debug:
1774 files--debug: c
1774 files--debug: c
1775 files--debug: c
1775 files--debug: c
1776 files--debug: b
1776 files--debug: b
1777 files--debug: a
1777 files--debug: a
1778 manifest: 6:94961b75a2da
1778 manifest: 6:94961b75a2da
1779 manifest: 5:f2dbc354b94e
1779 manifest: 5:f2dbc354b94e
1780 manifest: 4:4dc3def4f9b4
1780 manifest: 4:4dc3def4f9b4
1781 manifest: 4:4dc3def4f9b4
1781 manifest: 4:4dc3def4f9b4
1782 manifest: 3:cb5a1327723b
1782 manifest: 3:cb5a1327723b
1783 manifest: 3:cb5a1327723b
1783 manifest: 3:cb5a1327723b
1784 manifest: 2:6e0e82995c35
1784 manifest: 2:6e0e82995c35
1785 manifest: 1:4e8d705b1e53
1785 manifest: 1:4e8d705b1e53
1786 manifest: 0:a0c8bcbbb45c
1786 manifest: 0:a0c8bcbbb45c
1787 manifest--verbose: 6:94961b75a2da
1787 manifest--verbose: 6:94961b75a2da
1788 manifest--verbose: 5:f2dbc354b94e
1788 manifest--verbose: 5:f2dbc354b94e
1789 manifest--verbose: 4:4dc3def4f9b4
1789 manifest--verbose: 4:4dc3def4f9b4
1790 manifest--verbose: 4:4dc3def4f9b4
1790 manifest--verbose: 4:4dc3def4f9b4
1791 manifest--verbose: 3:cb5a1327723b
1791 manifest--verbose: 3:cb5a1327723b
1792 manifest--verbose: 3:cb5a1327723b
1792 manifest--verbose: 3:cb5a1327723b
1793 manifest--verbose: 2:6e0e82995c35
1793 manifest--verbose: 2:6e0e82995c35
1794 manifest--verbose: 1:4e8d705b1e53
1794 manifest--verbose: 1:4e8d705b1e53
1795 manifest--verbose: 0:a0c8bcbbb45c
1795 manifest--verbose: 0:a0c8bcbbb45c
1796 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1796 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1797 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1797 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1798 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1798 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1799 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1799 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1800 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1800 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1801 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1801 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1802 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1802 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1803 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1803 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1804 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1804 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1805 node: 95c24699272ef57d062b8bccc32c878bf841784a
1805 node: 95c24699272ef57d062b8bccc32c878bf841784a
1806 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1806 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1807 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1807 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1808 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1808 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1809 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1809 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1810 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1810 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1811 node: 97054abb4ab824450e9164180baf491ae0078465
1811 node: 97054abb4ab824450e9164180baf491ae0078465
1812 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1812 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1813 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1813 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1814 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1814 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1815 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1815 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1816 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1816 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1817 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1817 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1818 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1818 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1819 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1819 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1820 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1820 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1821 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1821 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1822 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1822 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1823 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1823 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1824 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1824 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1825 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1825 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1826 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1826 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1827 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1827 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1828 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1828 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1829 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1829 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1830 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1830 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1831 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1831 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1832 parents:
1832 parents:
1833 parents: -1:000000000000
1833 parents: -1:000000000000
1834 parents: 5:13207e5a10d9 4:bbe44766e73d
1834 parents: 5:13207e5a10d9 4:bbe44766e73d
1835 parents: 3:10e46f2dcbf4
1835 parents: 3:10e46f2dcbf4
1836 parents:
1836 parents:
1837 parents:
1837 parents:
1838 parents:
1838 parents:
1839 parents:
1839 parents:
1840 parents:
1840 parents:
1841 parents--verbose:
1841 parents--verbose:
1842 parents--verbose: -1:000000000000
1842 parents--verbose: -1:000000000000
1843 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1843 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1844 parents--verbose: 3:10e46f2dcbf4
1844 parents--verbose: 3:10e46f2dcbf4
1845 parents--verbose:
1845 parents--verbose:
1846 parents--verbose:
1846 parents--verbose:
1847 parents--verbose:
1847 parents--verbose:
1848 parents--verbose:
1848 parents--verbose:
1849 parents--verbose:
1849 parents--verbose:
1850 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1850 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1851 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1851 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1852 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1852 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1853 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1853 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1854 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1854 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1855 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1855 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1856 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1856 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1857 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1857 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1858 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1858 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1859 rev: 8
1859 rev: 8
1860 rev: 7
1860 rev: 7
1861 rev: 6
1861 rev: 6
1862 rev: 5
1862 rev: 5
1863 rev: 4
1863 rev: 4
1864 rev: 3
1864 rev: 3
1865 rev: 2
1865 rev: 2
1866 rev: 1
1866 rev: 1
1867 rev: 0
1867 rev: 0
1868 rev--verbose: 8
1868 rev--verbose: 8
1869 rev--verbose: 7
1869 rev--verbose: 7
1870 rev--verbose: 6
1870 rev--verbose: 6
1871 rev--verbose: 5
1871 rev--verbose: 5
1872 rev--verbose: 4
1872 rev--verbose: 4
1873 rev--verbose: 3
1873 rev--verbose: 3
1874 rev--verbose: 2
1874 rev--verbose: 2
1875 rev--verbose: 1
1875 rev--verbose: 1
1876 rev--verbose: 0
1876 rev--verbose: 0
1877 rev--debug: 8
1877 rev--debug: 8
1878 rev--debug: 7
1878 rev--debug: 7
1879 rev--debug: 6
1879 rev--debug: 6
1880 rev--debug: 5
1880 rev--debug: 5
1881 rev--debug: 4
1881 rev--debug: 4
1882 rev--debug: 3
1882 rev--debug: 3
1883 rev--debug: 2
1883 rev--debug: 2
1884 rev--debug: 1
1884 rev--debug: 1
1885 rev--debug: 0
1885 rev--debug: 0
1886 tags: tip
1886 tags: tip
1887 tags:
1887 tags:
1888 tags:
1888 tags:
1889 tags:
1889 tags:
1890 tags:
1890 tags:
1891 tags:
1891 tags:
1892 tags:
1892 tags:
1893 tags:
1893 tags:
1894 tags:
1894 tags:
1895 tags--verbose: tip
1895 tags--verbose: tip
1896 tags--verbose:
1896 tags--verbose:
1897 tags--verbose:
1897 tags--verbose:
1898 tags--verbose:
1898 tags--verbose:
1899 tags--verbose:
1899 tags--verbose:
1900 tags--verbose:
1900 tags--verbose:
1901 tags--verbose:
1901 tags--verbose:
1902 tags--verbose:
1902 tags--verbose:
1903 tags--verbose:
1903 tags--verbose:
1904 tags--debug: tip
1904 tags--debug: tip
1905 tags--debug:
1905 tags--debug:
1906 tags--debug:
1906 tags--debug:
1907 tags--debug:
1907 tags--debug:
1908 tags--debug:
1908 tags--debug:
1909 tags--debug:
1909 tags--debug:
1910 tags--debug:
1910 tags--debug:
1911 tags--debug:
1911 tags--debug:
1912 tags--debug:
1912 tags--debug:
1913 diffstat: 3: +2/-1
1913 diffstat: 3: +2/-1
1914 diffstat: 1: +1/-0
1914 diffstat: 1: +1/-0
1915 diffstat: 0: +0/-0
1915 diffstat: 0: +0/-0
1916 diffstat: 1: +1/-0
1916 diffstat: 1: +1/-0
1917 diffstat: 0: +0/-0
1917 diffstat: 0: +0/-0
1918 diffstat: 1: +1/-0
1918 diffstat: 1: +1/-0
1919 diffstat: 1: +4/-0
1919 diffstat: 1: +4/-0
1920 diffstat: 1: +2/-0
1920 diffstat: 1: +2/-0
1921 diffstat: 1: +1/-0
1921 diffstat: 1: +1/-0
1922 diffstat--verbose: 3: +2/-1
1922 diffstat--verbose: 3: +2/-1
1923 diffstat--verbose: 1: +1/-0
1923 diffstat--verbose: 1: +1/-0
1924 diffstat--verbose: 0: +0/-0
1924 diffstat--verbose: 0: +0/-0
1925 diffstat--verbose: 1: +1/-0
1925 diffstat--verbose: 1: +1/-0
1926 diffstat--verbose: 0: +0/-0
1926 diffstat--verbose: 0: +0/-0
1927 diffstat--verbose: 1: +1/-0
1927 diffstat--verbose: 1: +1/-0
1928 diffstat--verbose: 1: +4/-0
1928 diffstat--verbose: 1: +4/-0
1929 diffstat--verbose: 1: +2/-0
1929 diffstat--verbose: 1: +2/-0
1930 diffstat--verbose: 1: +1/-0
1930 diffstat--verbose: 1: +1/-0
1931 diffstat--debug: 3: +2/-1
1931 diffstat--debug: 3: +2/-1
1932 diffstat--debug: 1: +1/-0
1932 diffstat--debug: 1: +1/-0
1933 diffstat--debug: 0: +0/-0
1933 diffstat--debug: 0: +0/-0
1934 diffstat--debug: 1: +1/-0
1934 diffstat--debug: 1: +1/-0
1935 diffstat--debug: 0: +0/-0
1935 diffstat--debug: 0: +0/-0
1936 diffstat--debug: 1: +1/-0
1936 diffstat--debug: 1: +1/-0
1937 diffstat--debug: 1: +4/-0
1937 diffstat--debug: 1: +4/-0
1938 diffstat--debug: 1: +2/-0
1938 diffstat--debug: 1: +2/-0
1939 diffstat--debug: 1: +1/-0
1939 diffstat--debug: 1: +1/-0
1940 extras: branch=default
1940 extras: branch=default
1941 extras: branch=default
1941 extras: branch=default
1942 extras: branch=default
1942 extras: branch=default
1943 extras: branch=default
1943 extras: branch=default
1944 extras: branch=foo
1944 extras: branch=foo
1945 extras: branch=default
1945 extras: branch=default
1946 extras: branch=default
1946 extras: branch=default
1947 extras: branch=default
1947 extras: branch=default
1948 extras: branch=default
1948 extras: branch=default
1949 extras--verbose: branch=default
1949 extras--verbose: branch=default
1950 extras--verbose: branch=default
1950 extras--verbose: branch=default
1951 extras--verbose: branch=default
1951 extras--verbose: branch=default
1952 extras--verbose: branch=default
1952 extras--verbose: branch=default
1953 extras--verbose: branch=foo
1953 extras--verbose: branch=foo
1954 extras--verbose: branch=default
1954 extras--verbose: branch=default
1955 extras--verbose: branch=default
1955 extras--verbose: branch=default
1956 extras--verbose: branch=default
1956 extras--verbose: branch=default
1957 extras--verbose: branch=default
1957 extras--verbose: branch=default
1958 extras--debug: branch=default
1958 extras--debug: branch=default
1959 extras--debug: branch=default
1959 extras--debug: branch=default
1960 extras--debug: branch=default
1960 extras--debug: branch=default
1961 extras--debug: branch=default
1961 extras--debug: branch=default
1962 extras--debug: branch=foo
1962 extras--debug: branch=foo
1963 extras--debug: branch=default
1963 extras--debug: branch=default
1964 extras--debug: branch=default
1964 extras--debug: branch=default
1965 extras--debug: branch=default
1965 extras--debug: branch=default
1966 extras--debug: branch=default
1966 extras--debug: branch=default
1967 p1rev: 7
1967 p1rev: 7
1968 p1rev: -1
1968 p1rev: -1
1969 p1rev: 5
1969 p1rev: 5
1970 p1rev: 3
1970 p1rev: 3
1971 p1rev: 3
1971 p1rev: 3
1972 p1rev: 2
1972 p1rev: 2
1973 p1rev: 1
1973 p1rev: 1
1974 p1rev: 0
1974 p1rev: 0
1975 p1rev: -1
1975 p1rev: -1
1976 p1rev--verbose: 7
1976 p1rev--verbose: 7
1977 p1rev--verbose: -1
1977 p1rev--verbose: -1
1978 p1rev--verbose: 5
1978 p1rev--verbose: 5
1979 p1rev--verbose: 3
1979 p1rev--verbose: 3
1980 p1rev--verbose: 3
1980 p1rev--verbose: 3
1981 p1rev--verbose: 2
1981 p1rev--verbose: 2
1982 p1rev--verbose: 1
1982 p1rev--verbose: 1
1983 p1rev--verbose: 0
1983 p1rev--verbose: 0
1984 p1rev--verbose: -1
1984 p1rev--verbose: -1
1985 p1rev--debug: 7
1985 p1rev--debug: 7
1986 p1rev--debug: -1
1986 p1rev--debug: -1
1987 p1rev--debug: 5
1987 p1rev--debug: 5
1988 p1rev--debug: 3
1988 p1rev--debug: 3
1989 p1rev--debug: 3
1989 p1rev--debug: 3
1990 p1rev--debug: 2
1990 p1rev--debug: 2
1991 p1rev--debug: 1
1991 p1rev--debug: 1
1992 p1rev--debug: 0
1992 p1rev--debug: 0
1993 p1rev--debug: -1
1993 p1rev--debug: -1
1994 p2rev: -1
1994 p2rev: -1
1995 p2rev: -1
1995 p2rev: -1
1996 p2rev: 4
1996 p2rev: 4
1997 p2rev: -1
1997 p2rev: -1
1998 p2rev: -1
1998 p2rev: -1
1999 p2rev: -1
1999 p2rev: -1
2000 p2rev: -1
2000 p2rev: -1
2001 p2rev: -1
2001 p2rev: -1
2002 p2rev: -1
2002 p2rev: -1
2003 p2rev--verbose: -1
2003 p2rev--verbose: -1
2004 p2rev--verbose: -1
2004 p2rev--verbose: -1
2005 p2rev--verbose: 4
2005 p2rev--verbose: 4
2006 p2rev--verbose: -1
2006 p2rev--verbose: -1
2007 p2rev--verbose: -1
2007 p2rev--verbose: -1
2008 p2rev--verbose: -1
2008 p2rev--verbose: -1
2009 p2rev--verbose: -1
2009 p2rev--verbose: -1
2010 p2rev--verbose: -1
2010 p2rev--verbose: -1
2011 p2rev--verbose: -1
2011 p2rev--verbose: -1
2012 p2rev--debug: -1
2012 p2rev--debug: -1
2013 p2rev--debug: -1
2013 p2rev--debug: -1
2014 p2rev--debug: 4
2014 p2rev--debug: 4
2015 p2rev--debug: -1
2015 p2rev--debug: -1
2016 p2rev--debug: -1
2016 p2rev--debug: -1
2017 p2rev--debug: -1
2017 p2rev--debug: -1
2018 p2rev--debug: -1
2018 p2rev--debug: -1
2019 p2rev--debug: -1
2019 p2rev--debug: -1
2020 p2rev--debug: -1
2020 p2rev--debug: -1
2021 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2021 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2022 p1node: 0000000000000000000000000000000000000000
2022 p1node: 0000000000000000000000000000000000000000
2023 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2023 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2024 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2024 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2025 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2025 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2026 p1node: 97054abb4ab824450e9164180baf491ae0078465
2026 p1node: 97054abb4ab824450e9164180baf491ae0078465
2027 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2027 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2028 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2028 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2029 p1node: 0000000000000000000000000000000000000000
2029 p1node: 0000000000000000000000000000000000000000
2030 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2030 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2031 p1node--verbose: 0000000000000000000000000000000000000000
2031 p1node--verbose: 0000000000000000000000000000000000000000
2032 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2032 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2033 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2033 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2034 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2034 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2035 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2035 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2036 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2036 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2037 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2037 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2038 p1node--verbose: 0000000000000000000000000000000000000000
2038 p1node--verbose: 0000000000000000000000000000000000000000
2039 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2039 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2040 p1node--debug: 0000000000000000000000000000000000000000
2040 p1node--debug: 0000000000000000000000000000000000000000
2041 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2041 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2042 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2042 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2043 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2043 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2044 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2044 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2045 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2045 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2046 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2046 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2047 p1node--debug: 0000000000000000000000000000000000000000
2047 p1node--debug: 0000000000000000000000000000000000000000
2048 p2node: 0000000000000000000000000000000000000000
2048 p2node: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2050 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2050 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2051 p2node: 0000000000000000000000000000000000000000
2051 p2node: 0000000000000000000000000000000000000000
2052 p2node: 0000000000000000000000000000000000000000
2052 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2054 p2node: 0000000000000000000000000000000000000000
2054 p2node: 0000000000000000000000000000000000000000
2055 p2node: 0000000000000000000000000000000000000000
2055 p2node: 0000000000000000000000000000000000000000
2056 p2node: 0000000000000000000000000000000000000000
2056 p2node: 0000000000000000000000000000000000000000
2057 p2node--verbose: 0000000000000000000000000000000000000000
2057 p2node--verbose: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2059 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2060 p2node--verbose: 0000000000000000000000000000000000000000
2060 p2node--verbose: 0000000000000000000000000000000000000000
2061 p2node--verbose: 0000000000000000000000000000000000000000
2061 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--verbose: 0000000000000000000000000000000000000000
2064 p2node--verbose: 0000000000000000000000000000000000000000
2064 p2node--verbose: 0000000000000000000000000000000000000000
2065 p2node--verbose: 0000000000000000000000000000000000000000
2065 p2node--verbose: 0000000000000000000000000000000000000000
2066 p2node--debug: 0000000000000000000000000000000000000000
2066 p2node--debug: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2068 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2069 p2node--debug: 0000000000000000000000000000000000000000
2069 p2node--debug: 0000000000000000000000000000000000000000
2070 p2node--debug: 0000000000000000000000000000000000000000
2070 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2072 p2node--debug: 0000000000000000000000000000000000000000
2072 p2node--debug: 0000000000000000000000000000000000000000
2073 p2node--debug: 0000000000000000000000000000000000000000
2073 p2node--debug: 0000000000000000000000000000000000000000
2074 p2node--debug: 0000000000000000000000000000000000000000
2074 p2node--debug: 0000000000000000000000000000000000000000
2075
2075
2076 Filters work:
2076 Filters work:
2077
2077
2078 $ hg log --template '{author|domain}\n'
2078 $ hg log --template '{author|domain}\n'
2079
2079
2080 hostname
2080 hostname
2081
2081
2082
2082
2083
2083
2084
2084
2085 place
2085 place
2086 place
2086 place
2087 hostname
2087 hostname
2088
2088
2089 $ hg log --template '{author|person}\n'
2089 $ hg log --template '{author|person}\n'
2090 test
2090 test
2091 User Name
2091 User Name
2092 person
2092 person
2093 person
2093 person
2094 person
2094 person
2095 person
2095 person
2096 other
2096 other
2097 A. N. Other
2097 A. N. Other
2098 User Name
2098 User Name
2099
2099
2100 $ hg log --template '{author|user}\n'
2100 $ hg log --template '{author|user}\n'
2101 test
2101 test
2102 user
2102 user
2103 person
2103 person
2104 person
2104 person
2105 person
2105 person
2106 person
2106 person
2107 other
2107 other
2108 other
2108 other
2109 user
2109 user
2110
2110
2111 $ hg log --template '{date|date}\n'
2111 $ hg log --template '{date|date}\n'
2112 Wed Jan 01 10:01:00 2020 +0000
2112 Wed Jan 01 10:01:00 2020 +0000
2113 Mon Jan 12 13:46:40 1970 +0000
2113 Mon Jan 12 13:46:40 1970 +0000
2114 Sun Jan 18 08:40:01 1970 +0000
2114 Sun Jan 18 08:40:01 1970 +0000
2115 Sun Jan 18 08:40:00 1970 +0000
2115 Sun Jan 18 08:40:00 1970 +0000
2116 Sat Jan 17 04:53:20 1970 +0000
2116 Sat Jan 17 04:53:20 1970 +0000
2117 Fri Jan 16 01:06:40 1970 +0000
2117 Fri Jan 16 01:06:40 1970 +0000
2118 Wed Jan 14 21:20:00 1970 +0000
2118 Wed Jan 14 21:20:00 1970 +0000
2119 Tue Jan 13 17:33:20 1970 +0000
2119 Tue Jan 13 17:33:20 1970 +0000
2120 Mon Jan 12 13:46:40 1970 +0000
2120 Mon Jan 12 13:46:40 1970 +0000
2121
2121
2122 $ hg log --template '{date|isodate}\n'
2122 $ hg log --template '{date|isodate}\n'
2123 2020-01-01 10:01 +0000
2123 2020-01-01 10:01 +0000
2124 1970-01-12 13:46 +0000
2124 1970-01-12 13:46 +0000
2125 1970-01-18 08:40 +0000
2125 1970-01-18 08:40 +0000
2126 1970-01-18 08:40 +0000
2126 1970-01-18 08:40 +0000
2127 1970-01-17 04:53 +0000
2127 1970-01-17 04:53 +0000
2128 1970-01-16 01:06 +0000
2128 1970-01-16 01:06 +0000
2129 1970-01-14 21:20 +0000
2129 1970-01-14 21:20 +0000
2130 1970-01-13 17:33 +0000
2130 1970-01-13 17:33 +0000
2131 1970-01-12 13:46 +0000
2131 1970-01-12 13:46 +0000
2132
2132
2133 $ hg log --template '{date|isodatesec}\n'
2133 $ hg log --template '{date|isodatesec}\n'
2134 2020-01-01 10:01:00 +0000
2134 2020-01-01 10:01:00 +0000
2135 1970-01-12 13:46:40 +0000
2135 1970-01-12 13:46:40 +0000
2136 1970-01-18 08:40:01 +0000
2136 1970-01-18 08:40:01 +0000
2137 1970-01-18 08:40:00 +0000
2137 1970-01-18 08:40:00 +0000
2138 1970-01-17 04:53:20 +0000
2138 1970-01-17 04:53:20 +0000
2139 1970-01-16 01:06:40 +0000
2139 1970-01-16 01:06:40 +0000
2140 1970-01-14 21:20:00 +0000
2140 1970-01-14 21:20:00 +0000
2141 1970-01-13 17:33:20 +0000
2141 1970-01-13 17:33:20 +0000
2142 1970-01-12 13:46:40 +0000
2142 1970-01-12 13:46:40 +0000
2143
2143
2144 $ hg log --template '{date|rfc822date}\n'
2144 $ hg log --template '{date|rfc822date}\n'
2145 Wed, 01 Jan 2020 10:01:00 +0000
2145 Wed, 01 Jan 2020 10:01:00 +0000
2146 Mon, 12 Jan 1970 13:46:40 +0000
2146 Mon, 12 Jan 1970 13:46:40 +0000
2147 Sun, 18 Jan 1970 08:40:01 +0000
2147 Sun, 18 Jan 1970 08:40:01 +0000
2148 Sun, 18 Jan 1970 08:40:00 +0000
2148 Sun, 18 Jan 1970 08:40:00 +0000
2149 Sat, 17 Jan 1970 04:53:20 +0000
2149 Sat, 17 Jan 1970 04:53:20 +0000
2150 Fri, 16 Jan 1970 01:06:40 +0000
2150 Fri, 16 Jan 1970 01:06:40 +0000
2151 Wed, 14 Jan 1970 21:20:00 +0000
2151 Wed, 14 Jan 1970 21:20:00 +0000
2152 Tue, 13 Jan 1970 17:33:20 +0000
2152 Tue, 13 Jan 1970 17:33:20 +0000
2153 Mon, 12 Jan 1970 13:46:40 +0000
2153 Mon, 12 Jan 1970 13:46:40 +0000
2154
2154
2155 $ hg log --template '{desc|firstline}\n'
2155 $ hg log --template '{desc|firstline}\n'
2156 third
2156 third
2157 second
2157 second
2158 merge
2158 merge
2159 new head
2159 new head
2160 new branch
2160 new branch
2161 no user, no domain
2161 no user, no domain
2162 no person
2162 no person
2163 other 1
2163 other 1
2164 line 1
2164 line 1
2165
2165
2166 $ hg log --template '{node|short}\n'
2166 $ hg log --template '{node|short}\n'
2167 95c24699272e
2167 95c24699272e
2168 29114dbae42b
2168 29114dbae42b
2169 d41e714fe50d
2169 d41e714fe50d
2170 13207e5a10d9
2170 13207e5a10d9
2171 bbe44766e73d
2171 bbe44766e73d
2172 10e46f2dcbf4
2172 10e46f2dcbf4
2173 97054abb4ab8
2173 97054abb4ab8
2174 b608e9d1a3f0
2174 b608e9d1a3f0
2175 1e4e1b8f71e0
2175 1e4e1b8f71e0
2176
2176
2177 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2177 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2178 <changeset author="test"/>
2178 <changeset author="test"/>
2179 <changeset author="User Name &lt;user@hostname&gt;"/>
2179 <changeset author="User Name &lt;user@hostname&gt;"/>
2180 <changeset author="person"/>
2180 <changeset author="person"/>
2181 <changeset author="person"/>
2181 <changeset author="person"/>
2182 <changeset author="person"/>
2182 <changeset author="person"/>
2183 <changeset author="person"/>
2183 <changeset author="person"/>
2184 <changeset author="other@place"/>
2184 <changeset author="other@place"/>
2185 <changeset author="A. N. Other &lt;other@place&gt;"/>
2185 <changeset author="A. N. Other &lt;other@place&gt;"/>
2186 <changeset author="User Name &lt;user@hostname&gt;"/>
2186 <changeset author="User Name &lt;user@hostname&gt;"/>
2187
2187
2188 $ hg log --template '{rev}: {children}\n'
2188 $ hg log --template '{rev}: {children}\n'
2189 8:
2189 8:
2190 7: 8:95c24699272e
2190 7: 8:95c24699272e
2191 6:
2191 6:
2192 5: 6:d41e714fe50d
2192 5: 6:d41e714fe50d
2193 4: 6:d41e714fe50d
2193 4: 6:d41e714fe50d
2194 3: 4:bbe44766e73d 5:13207e5a10d9
2194 3: 4:bbe44766e73d 5:13207e5a10d9
2195 2: 3:10e46f2dcbf4
2195 2: 3:10e46f2dcbf4
2196 1: 2:97054abb4ab8
2196 1: 2:97054abb4ab8
2197 0: 1:b608e9d1a3f0
2197 0: 1:b608e9d1a3f0
2198
2198
2199 Formatnode filter works:
2199 Formatnode filter works:
2200
2200
2201 $ hg -q log -r 0 --template '{node|formatnode}\n'
2201 $ hg -q log -r 0 --template '{node|formatnode}\n'
2202 1e4e1b8f71e0
2202 1e4e1b8f71e0
2203
2203
2204 $ hg log -r 0 --template '{node|formatnode}\n'
2204 $ hg log -r 0 --template '{node|formatnode}\n'
2205 1e4e1b8f71e0
2205 1e4e1b8f71e0
2206
2206
2207 $ hg -v log -r 0 --template '{node|formatnode}\n'
2207 $ hg -v log -r 0 --template '{node|formatnode}\n'
2208 1e4e1b8f71e0
2208 1e4e1b8f71e0
2209
2209
2210 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2210 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2211 1e4e1b8f71e05681d422154f5421e385fec3454f
2211 1e4e1b8f71e05681d422154f5421e385fec3454f
2212
2212
2213 Age filter:
2213 Age filter:
2214
2214
2215 $ hg init unstable-hash
2215 $ hg init unstable-hash
2216 $ cd unstable-hash
2216 $ cd unstable-hash
2217 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2217 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2218
2218
2219 >>> from __future__ import absolute_import
2219 >>> from __future__ import absolute_import
2220 >>> import datetime
2220 >>> import datetime
2221 >>> fp = open('a', 'wb')
2221 >>> fp = open('a', 'wb')
2222 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2222 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2223 >>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None
2223 >>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None
2224 >>> fp.close()
2224 >>> fp.close()
2225 $ hg add a
2225 $ hg add a
2226 $ hg commit -m future -d "`cat a`"
2226 $ hg commit -m future -d "`cat a`"
2227
2227
2228 $ hg log -l1 --template '{date|age}\n'
2228 $ hg log -l1 --template '{date|age}\n'
2229 7 years from now
2229 7 years from now
2230
2230
2231 $ cd ..
2231 $ cd ..
2232 $ rm -rf unstable-hash
2232 $ rm -rf unstable-hash
2233
2233
2234 Filename filters:
2234 Filename filters:
2235
2235
2236 $ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n'
2236 $ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n'
2237 bar||foo|
2237 bar||foo|
2238 $ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n'
2238 $ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n'
2239 foo|foo||
2239 foo|foo||
2240 $ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n'
2240 $ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n'
2241 foo|foo|foo|
2241 foo|foo|foo|
2242
2242
2243 Add a dummy commit to make up for the instability of the above:
2243 Add a dummy commit to make up for the instability of the above:
2244
2244
2245 $ echo a > a
2245 $ echo a > a
2246 $ hg add a
2246 $ hg add a
2247 $ hg ci -m future
2247 $ hg ci -m future
2248
2248
2249 Count filter:
2249 Count filter:
2250
2250
2251 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2251 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2252 40 12
2252 40 12
2253
2253
2254 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2254 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2255 0 1 4
2255 0 1 4
2256
2256
2257 $ hg log -G --template '{rev}: children: {children|count}, \
2257 $ hg log -G --template '{rev}: children: {children|count}, \
2258 > tags: {tags|count}, file_adds: {file_adds|count}, \
2258 > tags: {tags|count}, file_adds: {file_adds|count}, \
2259 > ancestors: {revset("ancestors(%s)", rev)|count}'
2259 > ancestors: {revset("ancestors(%s)", rev)|count}'
2260 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2260 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2261 |
2261 |
2262 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2262 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2263 |
2263 |
2264 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2264 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2265
2265
2266 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2266 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2267 |\
2267 |\
2268 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2268 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2269 | |
2269 | |
2270 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2270 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2271 |/
2271 |/
2272 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2272 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2273 |
2273 |
2274 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2274 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2275 |
2275 |
2276 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2276 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2277 |
2277 |
2278 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2278 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2279
2279
2280
2280
2281 $ hg log -l1 -T '{termwidth|count}\n'
2281 $ hg log -l1 -T '{termwidth|count}\n'
2282 hg: parse error: not countable
2282 hg: parse error: not countable
2283 (template filter 'count' is not compatible with keyword 'termwidth')
2283 (template filter 'count' is not compatible with keyword 'termwidth')
2284 [255]
2284 [255]
2285
2285
2286 Upper/lower filters:
2286 Upper/lower filters:
2287
2287
2288 $ hg log -r0 --template '{branch|upper}\n'
2288 $ hg log -r0 --template '{branch|upper}\n'
2289 DEFAULT
2289 DEFAULT
2290 $ hg log -r0 --template '{author|lower}\n'
2290 $ hg log -r0 --template '{author|lower}\n'
2291 user name <user@hostname>
2291 user name <user@hostname>
2292 $ hg log -r0 --template '{date|upper}\n'
2292 $ hg log -r0 --template '{date|upper}\n'
2293 1000000.00
2293 1000000.00
2294
2294
2295 Add a commit that does all possible modifications at once
2295 Add a commit that does all possible modifications at once
2296
2296
2297 $ echo modify >> third
2297 $ echo modify >> third
2298 $ touch b
2298 $ touch b
2299 $ hg add b
2299 $ hg add b
2300 $ hg mv fourth fifth
2300 $ hg mv fourth fifth
2301 $ hg rm a
2301 $ hg rm a
2302 $ hg ci -m "Modify, add, remove, rename"
2302 $ hg ci -m "Modify, add, remove, rename"
2303
2303
2304 Check the status template
2304 Check the status template
2305
2305
2306 $ cat <<EOF >> $HGRCPATH
2306 $ cat <<EOF >> $HGRCPATH
2307 > [extensions]
2307 > [extensions]
2308 > color=
2308 > color=
2309 > EOF
2309 > EOF
2310
2310
2311 $ hg log -T status -r 10
2311 $ hg log -T status -r 10
2312 changeset: 10:0f9759ec227a
2312 changeset: 10:0f9759ec227a
2313 tag: tip
2313 tag: tip
2314 user: test
2314 user: test
2315 date: Thu Jan 01 00:00:00 1970 +0000
2315 date: Thu Jan 01 00:00:00 1970 +0000
2316 summary: Modify, add, remove, rename
2316 summary: Modify, add, remove, rename
2317 files:
2317 files:
2318 M third
2318 M third
2319 A b
2319 A b
2320 A fifth
2320 A fifth
2321 R a
2321 R a
2322 R fourth
2322 R fourth
2323
2323
2324 $ hg log -T status -C -r 10
2324 $ hg log -T status -C -r 10
2325 changeset: 10:0f9759ec227a
2325 changeset: 10:0f9759ec227a
2326 tag: tip
2326 tag: tip
2327 user: test
2327 user: test
2328 date: Thu Jan 01 00:00:00 1970 +0000
2328 date: Thu Jan 01 00:00:00 1970 +0000
2329 summary: Modify, add, remove, rename
2329 summary: Modify, add, remove, rename
2330 files:
2330 files:
2331 M third
2331 M third
2332 A b
2332 A b
2333 A fifth
2333 A fifth
2334 fourth
2334 fourth
2335 R a
2335 R a
2336 R fourth
2336 R fourth
2337
2337
2338 $ hg log -T status -C -r 10 -v
2338 $ hg log -T status -C -r 10 -v
2339 changeset: 10:0f9759ec227a
2339 changeset: 10:0f9759ec227a
2340 tag: tip
2340 tag: tip
2341 user: test
2341 user: test
2342 date: Thu Jan 01 00:00:00 1970 +0000
2342 date: Thu Jan 01 00:00:00 1970 +0000
2343 description:
2343 description:
2344 Modify, add, remove, rename
2344 Modify, add, remove, rename
2345
2345
2346 files:
2346 files:
2347 M third
2347 M third
2348 A b
2348 A b
2349 A fifth
2349 A fifth
2350 fourth
2350 fourth
2351 R a
2351 R a
2352 R fourth
2352 R fourth
2353
2353
2354 $ hg log -T status -C -r 10 --debug
2354 $ hg log -T status -C -r 10 --debug
2355 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2355 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2356 tag: tip
2356 tag: tip
2357 phase: secret
2357 phase: secret
2358 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2358 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2359 parent: -1:0000000000000000000000000000000000000000
2359 parent: -1:0000000000000000000000000000000000000000
2360 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2360 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2361 user: test
2361 user: test
2362 date: Thu Jan 01 00:00:00 1970 +0000
2362 date: Thu Jan 01 00:00:00 1970 +0000
2363 extra: branch=default
2363 extra: branch=default
2364 description:
2364 description:
2365 Modify, add, remove, rename
2365 Modify, add, remove, rename
2366
2366
2367 files:
2367 files:
2368 M third
2368 M third
2369 A b
2369 A b
2370 A fifth
2370 A fifth
2371 fourth
2371 fourth
2372 R a
2372 R a
2373 R fourth
2373 R fourth
2374
2374
2375 $ hg log -T status -C -r 10 --quiet
2375 $ hg log -T status -C -r 10 --quiet
2376 10:0f9759ec227a
2376 10:0f9759ec227a
2377 $ hg --color=debug log -T status -r 10
2377 $ hg --color=debug log -T status -r 10
2378 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2378 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2379 [log.tag|tag: tip]
2379 [log.tag|tag: tip]
2380 [log.user|user: test]
2380 [log.user|user: test]
2381 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2381 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2382 [log.summary|summary: Modify, add, remove, rename]
2382 [log.summary|summary: Modify, add, remove, rename]
2383 [ui.note log.files|files:]
2383 [ui.note log.files|files:]
2384 [status.modified|M third]
2384 [status.modified|M third]
2385 [status.added|A b]
2385 [status.added|A b]
2386 [status.added|A fifth]
2386 [status.added|A fifth]
2387 [status.removed|R a]
2387 [status.removed|R a]
2388 [status.removed|R fourth]
2388 [status.removed|R fourth]
2389
2389
2390 $ hg --color=debug log -T status -C -r 10
2390 $ hg --color=debug log -T status -C -r 10
2391 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2391 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2392 [log.tag|tag: tip]
2392 [log.tag|tag: tip]
2393 [log.user|user: test]
2393 [log.user|user: test]
2394 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2394 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2395 [log.summary|summary: Modify, add, remove, rename]
2395 [log.summary|summary: Modify, add, remove, rename]
2396 [ui.note log.files|files:]
2396 [ui.note log.files|files:]
2397 [status.modified|M third]
2397 [status.modified|M third]
2398 [status.added|A b]
2398 [status.added|A b]
2399 [status.added|A fifth]
2399 [status.added|A fifth]
2400 [status.copied| fourth]
2400 [status.copied| fourth]
2401 [status.removed|R a]
2401 [status.removed|R a]
2402 [status.removed|R fourth]
2402 [status.removed|R fourth]
2403
2403
2404 $ hg --color=debug log -T status -C -r 10 -v
2404 $ hg --color=debug log -T status -C -r 10 -v
2405 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2405 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2406 [log.tag|tag: tip]
2406 [log.tag|tag: tip]
2407 [log.user|user: test]
2407 [log.user|user: test]
2408 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2408 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2409 [ui.note log.description|description:]
2409 [ui.note log.description|description:]
2410 [ui.note log.description|Modify, add, remove, rename]
2410 [ui.note log.description|Modify, add, remove, rename]
2411
2411
2412 [ui.note log.files|files:]
2412 [ui.note log.files|files:]
2413 [status.modified|M third]
2413 [status.modified|M third]
2414 [status.added|A b]
2414 [status.added|A b]
2415 [status.added|A fifth]
2415 [status.added|A fifth]
2416 [status.copied| fourth]
2416 [status.copied| fourth]
2417 [status.removed|R a]
2417 [status.removed|R a]
2418 [status.removed|R fourth]
2418 [status.removed|R fourth]
2419
2419
2420 $ hg --color=debug log -T status -C -r 10 --debug
2420 $ hg --color=debug log -T status -C -r 10 --debug
2421 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2421 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2422 [log.tag|tag: tip]
2422 [log.tag|tag: tip]
2423 [log.phase|phase: secret]
2423 [log.phase|phase: secret]
2424 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2424 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2425 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2425 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2426 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2426 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2427 [log.user|user: test]
2427 [log.user|user: test]
2428 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2428 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2429 [ui.debug log.extra|extra: branch=default]
2429 [ui.debug log.extra|extra: branch=default]
2430 [ui.note log.description|description:]
2430 [ui.note log.description|description:]
2431 [ui.note log.description|Modify, add, remove, rename]
2431 [ui.note log.description|Modify, add, remove, rename]
2432
2432
2433 [ui.note log.files|files:]
2433 [ui.note log.files|files:]
2434 [status.modified|M third]
2434 [status.modified|M third]
2435 [status.added|A b]
2435 [status.added|A b]
2436 [status.added|A fifth]
2436 [status.added|A fifth]
2437 [status.copied| fourth]
2437 [status.copied| fourth]
2438 [status.removed|R a]
2438 [status.removed|R a]
2439 [status.removed|R fourth]
2439 [status.removed|R fourth]
2440
2440
2441 $ hg --color=debug log -T status -C -r 10 --quiet
2441 $ hg --color=debug log -T status -C -r 10 --quiet
2442 [log.node|10:0f9759ec227a]
2442 [log.node|10:0f9759ec227a]
2443
2443
2444 Check the bisect template
2444 Check the bisect template
2445
2445
2446 $ hg bisect -g 1
2446 $ hg bisect -g 1
2447 $ hg bisect -b 3 --noupdate
2447 $ hg bisect -b 3 --noupdate
2448 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2448 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2449 $ hg log -T bisect -r 0:4
2449 $ hg log -T bisect -r 0:4
2450 changeset: 0:1e4e1b8f71e0
2450 changeset: 0:1e4e1b8f71e0
2451 bisect: good (implicit)
2451 bisect: good (implicit)
2452 user: User Name <user@hostname>
2452 user: User Name <user@hostname>
2453 date: Mon Jan 12 13:46:40 1970 +0000
2453 date: Mon Jan 12 13:46:40 1970 +0000
2454 summary: line 1
2454 summary: line 1
2455
2455
2456 changeset: 1:b608e9d1a3f0
2456 changeset: 1:b608e9d1a3f0
2457 bisect: good
2457 bisect: good
2458 user: A. N. Other <other@place>
2458 user: A. N. Other <other@place>
2459 date: Tue Jan 13 17:33:20 1970 +0000
2459 date: Tue Jan 13 17:33:20 1970 +0000
2460 summary: other 1
2460 summary: other 1
2461
2461
2462 changeset: 2:97054abb4ab8
2462 changeset: 2:97054abb4ab8
2463 bisect: untested
2463 bisect: untested
2464 user: other@place
2464 user: other@place
2465 date: Wed Jan 14 21:20:00 1970 +0000
2465 date: Wed Jan 14 21:20:00 1970 +0000
2466 summary: no person
2466 summary: no person
2467
2467
2468 changeset: 3:10e46f2dcbf4
2468 changeset: 3:10e46f2dcbf4
2469 bisect: bad
2469 bisect: bad
2470 user: person
2470 user: person
2471 date: Fri Jan 16 01:06:40 1970 +0000
2471 date: Fri Jan 16 01:06:40 1970 +0000
2472 summary: no user, no domain
2472 summary: no user, no domain
2473
2473
2474 changeset: 4:bbe44766e73d
2474 changeset: 4:bbe44766e73d
2475 bisect: bad (implicit)
2475 bisect: bad (implicit)
2476 branch: foo
2476 branch: foo
2477 user: person
2477 user: person
2478 date: Sat Jan 17 04:53:20 1970 +0000
2478 date: Sat Jan 17 04:53:20 1970 +0000
2479 summary: new branch
2479 summary: new branch
2480
2480
2481 $ hg log --debug -T bisect -r 0:4
2481 $ hg log --debug -T bisect -r 0:4
2482 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2482 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2483 bisect: good (implicit)
2483 bisect: good (implicit)
2484 phase: public
2484 phase: public
2485 parent: -1:0000000000000000000000000000000000000000
2485 parent: -1:0000000000000000000000000000000000000000
2486 parent: -1:0000000000000000000000000000000000000000
2486 parent: -1:0000000000000000000000000000000000000000
2487 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2487 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2488 user: User Name <user@hostname>
2488 user: User Name <user@hostname>
2489 date: Mon Jan 12 13:46:40 1970 +0000
2489 date: Mon Jan 12 13:46:40 1970 +0000
2490 files+: a
2490 files+: a
2491 extra: branch=default
2491 extra: branch=default
2492 description:
2492 description:
2493 line 1
2493 line 1
2494 line 2
2494 line 2
2495
2495
2496
2496
2497 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2497 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2498 bisect: good
2498 bisect: good
2499 phase: public
2499 phase: public
2500 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2500 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2501 parent: -1:0000000000000000000000000000000000000000
2501 parent: -1:0000000000000000000000000000000000000000
2502 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2502 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2503 user: A. N. Other <other@place>
2503 user: A. N. Other <other@place>
2504 date: Tue Jan 13 17:33:20 1970 +0000
2504 date: Tue Jan 13 17:33:20 1970 +0000
2505 files+: b
2505 files+: b
2506 extra: branch=default
2506 extra: branch=default
2507 description:
2507 description:
2508 other 1
2508 other 1
2509 other 2
2509 other 2
2510
2510
2511 other 3
2511 other 3
2512
2512
2513
2513
2514 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2514 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2515 bisect: untested
2515 bisect: untested
2516 phase: public
2516 phase: public
2517 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2517 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2518 parent: -1:0000000000000000000000000000000000000000
2518 parent: -1:0000000000000000000000000000000000000000
2519 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2519 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2520 user: other@place
2520 user: other@place
2521 date: Wed Jan 14 21:20:00 1970 +0000
2521 date: Wed Jan 14 21:20:00 1970 +0000
2522 files+: c
2522 files+: c
2523 extra: branch=default
2523 extra: branch=default
2524 description:
2524 description:
2525 no person
2525 no person
2526
2526
2527
2527
2528 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2528 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2529 bisect: bad
2529 bisect: bad
2530 phase: public
2530 phase: public
2531 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2531 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2532 parent: -1:0000000000000000000000000000000000000000
2532 parent: -1:0000000000000000000000000000000000000000
2533 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2533 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2534 user: person
2534 user: person
2535 date: Fri Jan 16 01:06:40 1970 +0000
2535 date: Fri Jan 16 01:06:40 1970 +0000
2536 files: c
2536 files: c
2537 extra: branch=default
2537 extra: branch=default
2538 description:
2538 description:
2539 no user, no domain
2539 no user, no domain
2540
2540
2541
2541
2542 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2542 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2543 bisect: bad (implicit)
2543 bisect: bad (implicit)
2544 branch: foo
2544 branch: foo
2545 phase: draft
2545 phase: draft
2546 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2546 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2547 parent: -1:0000000000000000000000000000000000000000
2547 parent: -1:0000000000000000000000000000000000000000
2548 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2548 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2549 user: person
2549 user: person
2550 date: Sat Jan 17 04:53:20 1970 +0000
2550 date: Sat Jan 17 04:53:20 1970 +0000
2551 extra: branch=foo
2551 extra: branch=foo
2552 description:
2552 description:
2553 new branch
2553 new branch
2554
2554
2555
2555
2556 $ hg log -v -T bisect -r 0:4
2556 $ hg log -v -T bisect -r 0:4
2557 changeset: 0:1e4e1b8f71e0
2557 changeset: 0:1e4e1b8f71e0
2558 bisect: good (implicit)
2558 bisect: good (implicit)
2559 user: User Name <user@hostname>
2559 user: User Name <user@hostname>
2560 date: Mon Jan 12 13:46:40 1970 +0000
2560 date: Mon Jan 12 13:46:40 1970 +0000
2561 files: a
2561 files: a
2562 description:
2562 description:
2563 line 1
2563 line 1
2564 line 2
2564 line 2
2565
2565
2566
2566
2567 changeset: 1:b608e9d1a3f0
2567 changeset: 1:b608e9d1a3f0
2568 bisect: good
2568 bisect: good
2569 user: A. N. Other <other@place>
2569 user: A. N. Other <other@place>
2570 date: Tue Jan 13 17:33:20 1970 +0000
2570 date: Tue Jan 13 17:33:20 1970 +0000
2571 files: b
2571 files: b
2572 description:
2572 description:
2573 other 1
2573 other 1
2574 other 2
2574 other 2
2575
2575
2576 other 3
2576 other 3
2577
2577
2578
2578
2579 changeset: 2:97054abb4ab8
2579 changeset: 2:97054abb4ab8
2580 bisect: untested
2580 bisect: untested
2581 user: other@place
2581 user: other@place
2582 date: Wed Jan 14 21:20:00 1970 +0000
2582 date: Wed Jan 14 21:20:00 1970 +0000
2583 files: c
2583 files: c
2584 description:
2584 description:
2585 no person
2585 no person
2586
2586
2587
2587
2588 changeset: 3:10e46f2dcbf4
2588 changeset: 3:10e46f2dcbf4
2589 bisect: bad
2589 bisect: bad
2590 user: person
2590 user: person
2591 date: Fri Jan 16 01:06:40 1970 +0000
2591 date: Fri Jan 16 01:06:40 1970 +0000
2592 files: c
2592 files: c
2593 description:
2593 description:
2594 no user, no domain
2594 no user, no domain
2595
2595
2596
2596
2597 changeset: 4:bbe44766e73d
2597 changeset: 4:bbe44766e73d
2598 bisect: bad (implicit)
2598 bisect: bad (implicit)
2599 branch: foo
2599 branch: foo
2600 user: person
2600 user: person
2601 date: Sat Jan 17 04:53:20 1970 +0000
2601 date: Sat Jan 17 04:53:20 1970 +0000
2602 description:
2602 description:
2603 new branch
2603 new branch
2604
2604
2605
2605
2606 $ hg --color=debug log -T bisect -r 0:4
2606 $ hg --color=debug log -T bisect -r 0:4
2607 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2607 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2608 [log.bisect bisect.good|bisect: good (implicit)]
2608 [log.bisect bisect.good|bisect: good (implicit)]
2609 [log.user|user: User Name <user@hostname>]
2609 [log.user|user: User Name <user@hostname>]
2610 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2610 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2611 [log.summary|summary: line 1]
2611 [log.summary|summary: line 1]
2612
2612
2613 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2613 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2614 [log.bisect bisect.good|bisect: good]
2614 [log.bisect bisect.good|bisect: good]
2615 [log.user|user: A. N. Other <other@place>]
2615 [log.user|user: A. N. Other <other@place>]
2616 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2616 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2617 [log.summary|summary: other 1]
2617 [log.summary|summary: other 1]
2618
2618
2619 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2619 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2620 [log.bisect bisect.untested|bisect: untested]
2620 [log.bisect bisect.untested|bisect: untested]
2621 [log.user|user: other@place]
2621 [log.user|user: other@place]
2622 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2622 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2623 [log.summary|summary: no person]
2623 [log.summary|summary: no person]
2624
2624
2625 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2625 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2626 [log.bisect bisect.bad|bisect: bad]
2626 [log.bisect bisect.bad|bisect: bad]
2627 [log.user|user: person]
2627 [log.user|user: person]
2628 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2628 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2629 [log.summary|summary: no user, no domain]
2629 [log.summary|summary: no user, no domain]
2630
2630
2631 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2631 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2632 [log.bisect bisect.bad|bisect: bad (implicit)]
2632 [log.bisect bisect.bad|bisect: bad (implicit)]
2633 [log.branch|branch: foo]
2633 [log.branch|branch: foo]
2634 [log.user|user: person]
2634 [log.user|user: person]
2635 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2635 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2636 [log.summary|summary: new branch]
2636 [log.summary|summary: new branch]
2637
2637
2638 $ hg --color=debug log --debug -T bisect -r 0:4
2638 $ hg --color=debug log --debug -T bisect -r 0:4
2639 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2639 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2640 [log.bisect bisect.good|bisect: good (implicit)]
2640 [log.bisect bisect.good|bisect: good (implicit)]
2641 [log.phase|phase: public]
2641 [log.phase|phase: public]
2642 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2642 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2643 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2643 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2644 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2644 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2645 [log.user|user: User Name <user@hostname>]
2645 [log.user|user: User Name <user@hostname>]
2646 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2646 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2647 [ui.debug log.files|files+: a]
2647 [ui.debug log.files|files+: a]
2648 [ui.debug log.extra|extra: branch=default]
2648 [ui.debug log.extra|extra: branch=default]
2649 [ui.note log.description|description:]
2649 [ui.note log.description|description:]
2650 [ui.note log.description|line 1
2650 [ui.note log.description|line 1
2651 line 2]
2651 line 2]
2652
2652
2653
2653
2654 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2654 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2655 [log.bisect bisect.good|bisect: good]
2655 [log.bisect bisect.good|bisect: good]
2656 [log.phase|phase: public]
2656 [log.phase|phase: public]
2657 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2657 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2658 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2658 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2659 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2659 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2660 [log.user|user: A. N. Other <other@place>]
2660 [log.user|user: A. N. Other <other@place>]
2661 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2661 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2662 [ui.debug log.files|files+: b]
2662 [ui.debug log.files|files+: b]
2663 [ui.debug log.extra|extra: branch=default]
2663 [ui.debug log.extra|extra: branch=default]
2664 [ui.note log.description|description:]
2664 [ui.note log.description|description:]
2665 [ui.note log.description|other 1
2665 [ui.note log.description|other 1
2666 other 2
2666 other 2
2667
2667
2668 other 3]
2668 other 3]
2669
2669
2670
2670
2671 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2671 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2672 [log.bisect bisect.untested|bisect: untested]
2672 [log.bisect bisect.untested|bisect: untested]
2673 [log.phase|phase: public]
2673 [log.phase|phase: public]
2674 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2674 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2675 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2675 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2676 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2676 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2677 [log.user|user: other@place]
2677 [log.user|user: other@place]
2678 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2678 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2679 [ui.debug log.files|files+: c]
2679 [ui.debug log.files|files+: c]
2680 [ui.debug log.extra|extra: branch=default]
2680 [ui.debug log.extra|extra: branch=default]
2681 [ui.note log.description|description:]
2681 [ui.note log.description|description:]
2682 [ui.note log.description|no person]
2682 [ui.note log.description|no person]
2683
2683
2684
2684
2685 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2685 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2686 [log.bisect bisect.bad|bisect: bad]
2686 [log.bisect bisect.bad|bisect: bad]
2687 [log.phase|phase: public]
2687 [log.phase|phase: public]
2688 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2688 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2689 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2689 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2690 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2690 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2691 [log.user|user: person]
2691 [log.user|user: person]
2692 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2692 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2693 [ui.debug log.files|files: c]
2693 [ui.debug log.files|files: c]
2694 [ui.debug log.extra|extra: branch=default]
2694 [ui.debug log.extra|extra: branch=default]
2695 [ui.note log.description|description:]
2695 [ui.note log.description|description:]
2696 [ui.note log.description|no user, no domain]
2696 [ui.note log.description|no user, no domain]
2697
2697
2698
2698
2699 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2699 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2700 [log.bisect bisect.bad|bisect: bad (implicit)]
2700 [log.bisect bisect.bad|bisect: bad (implicit)]
2701 [log.branch|branch: foo]
2701 [log.branch|branch: foo]
2702 [log.phase|phase: draft]
2702 [log.phase|phase: draft]
2703 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2703 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2704 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2704 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2705 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2705 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2706 [log.user|user: person]
2706 [log.user|user: person]
2707 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2707 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2708 [ui.debug log.extra|extra: branch=foo]
2708 [ui.debug log.extra|extra: branch=foo]
2709 [ui.note log.description|description:]
2709 [ui.note log.description|description:]
2710 [ui.note log.description|new branch]
2710 [ui.note log.description|new branch]
2711
2711
2712
2712
2713 $ hg --color=debug log -v -T bisect -r 0:4
2713 $ hg --color=debug log -v -T bisect -r 0:4
2714 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2714 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2715 [log.bisect bisect.good|bisect: good (implicit)]
2715 [log.bisect bisect.good|bisect: good (implicit)]
2716 [log.user|user: User Name <user@hostname>]
2716 [log.user|user: User Name <user@hostname>]
2717 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2717 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2718 [ui.note log.files|files: a]
2718 [ui.note log.files|files: a]
2719 [ui.note log.description|description:]
2719 [ui.note log.description|description:]
2720 [ui.note log.description|line 1
2720 [ui.note log.description|line 1
2721 line 2]
2721 line 2]
2722
2722
2723
2723
2724 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2724 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2725 [log.bisect bisect.good|bisect: good]
2725 [log.bisect bisect.good|bisect: good]
2726 [log.user|user: A. N. Other <other@place>]
2726 [log.user|user: A. N. Other <other@place>]
2727 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2727 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2728 [ui.note log.files|files: b]
2728 [ui.note log.files|files: b]
2729 [ui.note log.description|description:]
2729 [ui.note log.description|description:]
2730 [ui.note log.description|other 1
2730 [ui.note log.description|other 1
2731 other 2
2731 other 2
2732
2732
2733 other 3]
2733 other 3]
2734
2734
2735
2735
2736 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2736 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2737 [log.bisect bisect.untested|bisect: untested]
2737 [log.bisect bisect.untested|bisect: untested]
2738 [log.user|user: other@place]
2738 [log.user|user: other@place]
2739 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2739 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2740 [ui.note log.files|files: c]
2740 [ui.note log.files|files: c]
2741 [ui.note log.description|description:]
2741 [ui.note log.description|description:]
2742 [ui.note log.description|no person]
2742 [ui.note log.description|no person]
2743
2743
2744
2744
2745 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2745 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2746 [log.bisect bisect.bad|bisect: bad]
2746 [log.bisect bisect.bad|bisect: bad]
2747 [log.user|user: person]
2747 [log.user|user: person]
2748 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2748 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2749 [ui.note log.files|files: c]
2749 [ui.note log.files|files: c]
2750 [ui.note log.description|description:]
2750 [ui.note log.description|description:]
2751 [ui.note log.description|no user, no domain]
2751 [ui.note log.description|no user, no domain]
2752
2752
2753
2753
2754 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2754 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2755 [log.bisect bisect.bad|bisect: bad (implicit)]
2755 [log.bisect bisect.bad|bisect: bad (implicit)]
2756 [log.branch|branch: foo]
2756 [log.branch|branch: foo]
2757 [log.user|user: person]
2757 [log.user|user: person]
2758 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2758 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2759 [ui.note log.description|description:]
2759 [ui.note log.description|description:]
2760 [ui.note log.description|new branch]
2760 [ui.note log.description|new branch]
2761
2761
2762
2762
2763 $ hg bisect --reset
2763 $ hg bisect --reset
2764
2764
2765 Error on syntax:
2765 Error on syntax:
2766
2766
2767 $ echo 'x = "f' >> t
2767 $ echo 'x = "f' >> t
2768 $ hg log
2768 $ hg log
2769 hg: parse error at t:3: unmatched quotes
2769 hg: parse error at t:3: unmatched quotes
2770 [255]
2770 [255]
2771
2771
2772 $ hg log -T '{date'
2772 $ hg log -T '{date'
2773 hg: parse error at 1: unterminated template expansion
2773 hg: parse error at 1: unterminated template expansion
2774 ({date
2774 ({date
2775 ^ here)
2775 ^ here)
2776 [255]
2776 [255]
2777 $ hg log -T '{date(}'
2777 $ hg log -T '{date(}'
2778 hg: parse error at 6: not a prefix: end
2778 hg: parse error at 6: not a prefix: end
2779 ({date(}
2779 ({date(}
2780 ^ here)
2780 ^ here)
2781 [255]
2781 [255]
2782 $ hg log -T '{date)}'
2782 $ hg log -T '{date)}'
2783 hg: parse error at 5: invalid token
2783 hg: parse error at 5: invalid token
2784 ({date)}
2784 ({date)}
2785 ^ here)
2785 ^ here)
2786 [255]
2786 [255]
2787 $ hg log -T '{date date}'
2787 $ hg log -T '{date date}'
2788 hg: parse error at 6: invalid token
2788 hg: parse error at 6: invalid token
2789 ({date date}
2789 ({date date}
2790 ^ here)
2790 ^ here)
2791 [255]
2791 [255]
2792
2792
2793 $ hg log -T '{}'
2793 $ hg log -T '{}'
2794 hg: parse error at 1: not a prefix: end
2794 hg: parse error at 1: not a prefix: end
2795 ({}
2795 ({}
2796 ^ here)
2796 ^ here)
2797 [255]
2797 [255]
2798 $ hg debugtemplate -v '{()}'
2798 $ hg debugtemplate -v '{()}'
2799 (template
2799 (template
2800 (group
2800 (group
2801 None))
2801 None))
2802 hg: parse error: missing argument
2802 hg: parse error: missing argument
2803 [255]
2803 [255]
2804
2804
2805 Behind the scenes, this would throw TypeError without intype=bytes
2805 Behind the scenes, this would throw TypeError without intype=bytes
2806
2806
2807 $ hg log -l 3 --template '{date|obfuscate}\n'
2807 $ hg log -l 3 --template '{date|obfuscate}\n'
2808 &#48;&#46;&#48;&#48;
2808 &#48;&#46;&#48;&#48;
2809 &#48;&#46;&#48;&#48;
2809 &#48;&#46;&#48;&#48;
2810 &#49;&#53;&#55;&#55;&#56;&#55;&#50;&#56;&#54;&#48;&#46;&#48;&#48;
2810 &#49;&#53;&#55;&#55;&#56;&#55;&#50;&#56;&#54;&#48;&#46;&#48;&#48;
2811
2811
2812 Behind the scenes, this will throw a ValueError
2812 Behind the scenes, this will throw a ValueError
2813
2813
2814 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2814 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2815 hg: parse error: invalid date: 'Modify, add, remove, rename'
2815 hg: parse error: invalid date: 'Modify, add, remove, rename'
2816 (template filter 'shortdate' is not compatible with keyword 'desc')
2816 (template filter 'shortdate' is not compatible with keyword 'desc')
2817 [255]
2817 [255]
2818
2818
2819 Behind the scenes, this would throw AttributeError without intype=bytes
2819 Behind the scenes, this would throw AttributeError without intype=bytes
2820
2820
2821 $ hg log -l 3 --template 'line: {date|escape}\n'
2821 $ hg log -l 3 --template 'line: {date|escape}\n'
2822 line: 0.00
2822 line: 0.00
2823 line: 0.00
2823 line: 0.00
2824 line: 1577872860.00
2824 line: 1577872860.00
2825
2825
2826 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2826 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2827 hg: parse error: localdate expects a date information
2827 hg: parse error: localdate expects a date information
2828 [255]
2828 [255]
2829
2829
2830 Behind the scenes, this will throw ValueError
2830 Behind the scenes, this will throw ValueError
2831
2831
2832 $ hg tip --template '{author|email|date}\n'
2832 $ hg tip --template '{author|email|date}\n'
2833 hg: parse error: date expects a date information
2833 hg: parse error: date expects a date information
2834 [255]
2834 [255]
2835
2835
2836 $ hg tip -T '{author|email|shortdate}\n'
2836 $ hg tip -T '{author|email|shortdate}\n'
2837 hg: parse error: invalid date: 'test'
2837 hg: parse error: invalid date: 'test'
2838 (template filter 'shortdate' is not compatible with keyword 'author')
2838 (template filter 'shortdate' is not compatible with keyword 'author')
2839 [255]
2839 [255]
2840
2840
2841 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2841 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2842 hg: parse error: invalid date: 'default'
2842 hg: parse error: invalid date: 'default'
2843 (incompatible use of template filter 'shortdate')
2843 (incompatible use of template filter 'shortdate')
2844 [255]
2844 [255]
2845
2845
2846 Error in nested template:
2846 Error in nested template:
2847
2847
2848 $ hg log -T '{"date'
2848 $ hg log -T '{"date'
2849 hg: parse error at 2: unterminated string
2849 hg: parse error at 2: unterminated string
2850 ({"date
2850 ({"date
2851 ^ here)
2851 ^ here)
2852 [255]
2852 [255]
2853
2853
2854 $ hg log -T '{"foo{date|?}"}'
2854 $ hg log -T '{"foo{date|?}"}'
2855 hg: parse error at 11: syntax error
2855 hg: parse error at 11: syntax error
2856 ({"foo{date|?}"}
2856 ({"foo{date|?}"}
2857 ^ here)
2857 ^ here)
2858 [255]
2858 [255]
2859
2859
2860 Thrown an error if a template function doesn't exist
2860 Thrown an error if a template function doesn't exist
2861
2861
2862 $ hg tip --template '{foo()}\n'
2862 $ hg tip --template '{foo()}\n'
2863 hg: parse error: unknown function 'foo'
2863 hg: parse error: unknown function 'foo'
2864 [255]
2864 [255]
2865
2865
2866 Pass generator object created by template function to filter
2866 Pass generator object created by template function to filter
2867
2867
2868 $ hg log -l 1 --template '{if(author, author)|user}\n'
2868 $ hg log -l 1 --template '{if(author, author)|user}\n'
2869 test
2869 test
2870
2870
2871 Test index keyword:
2871 Test index keyword:
2872
2872
2873 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2873 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2874 10 0:a 1:b 2:fifth 3:fourth 4:third
2874 10 0:a 1:b 2:fifth 3:fourth 4:third
2875 11 0:a
2875 11 0:a
2876
2876
2877 $ hg branches -T '{index} {branch}\n'
2877 $ hg branches -T '{index} {branch}\n'
2878 0 default
2878 0 default
2879 1 foo
2879 1 foo
2880
2880
2881 Test diff function:
2881 Test diff function:
2882
2882
2883 $ hg diff -c 8
2883 $ hg diff -c 8
2884 diff -r 29114dbae42b -r 95c24699272e fourth
2884 diff -r 29114dbae42b -r 95c24699272e fourth
2885 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2885 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2886 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2886 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2887 @@ -0,0 +1,1 @@
2887 @@ -0,0 +1,1 @@
2888 +second
2888 +second
2889 diff -r 29114dbae42b -r 95c24699272e second
2889 diff -r 29114dbae42b -r 95c24699272e second
2890 --- a/second Mon Jan 12 13:46:40 1970 +0000
2890 --- a/second Mon Jan 12 13:46:40 1970 +0000
2891 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2891 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2892 @@ -1,1 +0,0 @@
2892 @@ -1,1 +0,0 @@
2893 -second
2893 -second
2894 diff -r 29114dbae42b -r 95c24699272e third
2894 diff -r 29114dbae42b -r 95c24699272e third
2895 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2895 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2896 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2896 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2897 @@ -0,0 +1,1 @@
2897 @@ -0,0 +1,1 @@
2898 +third
2898 +third
2899
2899
2900 $ hg log -r 8 -T "{diff()}"
2900 $ hg log -r 8 -T "{diff()}"
2901 diff -r 29114dbae42b -r 95c24699272e fourth
2901 diff -r 29114dbae42b -r 95c24699272e fourth
2902 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2902 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2903 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2903 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2904 @@ -0,0 +1,1 @@
2904 @@ -0,0 +1,1 @@
2905 +second
2905 +second
2906 diff -r 29114dbae42b -r 95c24699272e second
2906 diff -r 29114dbae42b -r 95c24699272e second
2907 --- a/second Mon Jan 12 13:46:40 1970 +0000
2907 --- a/second Mon Jan 12 13:46:40 1970 +0000
2908 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2908 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2909 @@ -1,1 +0,0 @@
2909 @@ -1,1 +0,0 @@
2910 -second
2910 -second
2911 diff -r 29114dbae42b -r 95c24699272e third
2911 diff -r 29114dbae42b -r 95c24699272e third
2912 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2912 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2913 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2913 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2914 @@ -0,0 +1,1 @@
2914 @@ -0,0 +1,1 @@
2915 +third
2915 +third
2916
2916
2917 $ hg log -r 8 -T "{diff('glob:f*')}"
2917 $ hg log -r 8 -T "{diff('glob:f*')}"
2918 diff -r 29114dbae42b -r 95c24699272e fourth
2918 diff -r 29114dbae42b -r 95c24699272e fourth
2919 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2919 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2920 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2920 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2921 @@ -0,0 +1,1 @@
2921 @@ -0,0 +1,1 @@
2922 +second
2922 +second
2923
2923
2924 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2924 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2925 diff -r 29114dbae42b -r 95c24699272e second
2925 diff -r 29114dbae42b -r 95c24699272e second
2926 --- a/second Mon Jan 12 13:46:40 1970 +0000
2926 --- a/second Mon Jan 12 13:46:40 1970 +0000
2927 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2927 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2928 @@ -1,1 +0,0 @@
2928 @@ -1,1 +0,0 @@
2929 -second
2929 -second
2930 diff -r 29114dbae42b -r 95c24699272e third
2930 diff -r 29114dbae42b -r 95c24699272e third
2931 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2931 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2932 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2932 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2933 @@ -0,0 +1,1 @@
2933 @@ -0,0 +1,1 @@
2934 +third
2934 +third
2935
2935
2936 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2936 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2937 diff -r 29114dbae42b -r 95c24699272e fourth
2937 diff -r 29114dbae42b -r 95c24699272e fourth
2938 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2938 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2939 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2939 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2940 @@ -0,0 +1,1 @@
2940 @@ -0,0 +1,1 @@
2941 +second
2941 +second
2942
2942
2943 ui verbosity:
2943 ui verbosity:
2944
2944
2945 $ hg log -l1 -T '{verbosity}\n'
2945 $ hg log -l1 -T '{verbosity}\n'
2946
2946
2947 $ hg log -l1 -T '{verbosity}\n' --debug
2947 $ hg log -l1 -T '{verbosity}\n' --debug
2948 debug
2948 debug
2949 $ hg log -l1 -T '{verbosity}\n' --quiet
2949 $ hg log -l1 -T '{verbosity}\n' --quiet
2950 quiet
2950 quiet
2951 $ hg log -l1 -T '{verbosity}\n' --verbose
2951 $ hg log -l1 -T '{verbosity}\n' --verbose
2952 verbose
2952 verbose
2953
2953
2954 $ cd ..
2954 $ cd ..
2955
2955
2956
2956
2957 latesttag:
2957 latesttag:
2958
2958
2959 $ hg init latesttag
2959 $ hg init latesttag
2960 $ cd latesttag
2960 $ cd latesttag
2961
2961
2962 $ echo a > file
2962 $ echo a > file
2963 $ hg ci -Am a -d '0 0'
2963 $ hg ci -Am a -d '0 0'
2964 adding file
2964 adding file
2965
2965
2966 $ echo b >> file
2966 $ echo b >> file
2967 $ hg ci -m b -d '1 0'
2967 $ hg ci -m b -d '1 0'
2968
2968
2969 $ echo c >> head1
2969 $ echo c >> head1
2970 $ hg ci -Am h1c -d '2 0'
2970 $ hg ci -Am h1c -d '2 0'
2971 adding head1
2971 adding head1
2972
2972
2973 $ hg update -q 1
2973 $ hg update -q 1
2974 $ echo d >> head2
2974 $ echo d >> head2
2975 $ hg ci -Am h2d -d '3 0'
2975 $ hg ci -Am h2d -d '3 0'
2976 adding head2
2976 adding head2
2977 created new head
2977 created new head
2978
2978
2979 $ echo e >> head2
2979 $ echo e >> head2
2980 $ hg ci -m h2e -d '4 0'
2980 $ hg ci -m h2e -d '4 0'
2981
2981
2982 $ hg merge -q
2982 $ hg merge -q
2983 $ hg ci -m merge -d '5 -3600'
2983 $ hg ci -m merge -d '5 -3600'
2984
2984
2985 No tag set:
2985 No tag set:
2986
2986
2987 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2987 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2988 @ 5: null+5
2988 @ 5: null+5
2989 |\
2989 |\
2990 | o 4: null+4
2990 | o 4: null+4
2991 | |
2991 | |
2992 | o 3: null+3
2992 | o 3: null+3
2993 | |
2993 | |
2994 o | 2: null+3
2994 o | 2: null+3
2995 |/
2995 |/
2996 o 1: null+2
2996 o 1: null+2
2997 |
2997 |
2998 o 0: null+1
2998 o 0: null+1
2999
2999
3000
3000
3001 One common tag: longest path wins for {latesttagdistance}:
3001 One common tag: longest path wins for {latesttagdistance}:
3002
3002
3003 $ hg tag -r 1 -m t1 -d '6 0' t1
3003 $ hg tag -r 1 -m t1 -d '6 0' t1
3004 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3004 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3005 @ 6: t1+4
3005 @ 6: t1+4
3006 |
3006 |
3007 o 5: t1+3
3007 o 5: t1+3
3008 |\
3008 |\
3009 | o 4: t1+2
3009 | o 4: t1+2
3010 | |
3010 | |
3011 | o 3: t1+1
3011 | o 3: t1+1
3012 | |
3012 | |
3013 o | 2: t1+1
3013 o | 2: t1+1
3014 |/
3014 |/
3015 o 1: t1+0
3015 o 1: t1+0
3016 |
3016 |
3017 o 0: null+1
3017 o 0: null+1
3018
3018
3019
3019
3020 One ancestor tag: closest wins:
3020 One ancestor tag: closest wins:
3021
3021
3022 $ hg tag -r 2 -m t2 -d '7 0' t2
3022 $ hg tag -r 2 -m t2 -d '7 0' t2
3023 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3023 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3024 @ 7: t2+3
3024 @ 7: t2+3
3025 |
3025 |
3026 o 6: t2+2
3026 o 6: t2+2
3027 |
3027 |
3028 o 5: t2+1
3028 o 5: t2+1
3029 |\
3029 |\
3030 | o 4: t1+2
3030 | o 4: t1+2
3031 | |
3031 | |
3032 | o 3: t1+1
3032 | o 3: t1+1
3033 | |
3033 | |
3034 o | 2: t2+0
3034 o | 2: t2+0
3035 |/
3035 |/
3036 o 1: t1+0
3036 o 1: t1+0
3037 |
3037 |
3038 o 0: null+1
3038 o 0: null+1
3039
3039
3040
3040
3041 Two branch tags: more recent wins if same number of changes:
3041 Two branch tags: more recent wins if same number of changes:
3042
3042
3043 $ hg tag -r 3 -m t3 -d '8 0' t3
3043 $ hg tag -r 3 -m t3 -d '8 0' t3
3044 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3044 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3045 @ 8: t3+5
3045 @ 8: t3+5
3046 |
3046 |
3047 o 7: t3+4
3047 o 7: t3+4
3048 |
3048 |
3049 o 6: t3+3
3049 o 6: t3+3
3050 |
3050 |
3051 o 5: t3+2
3051 o 5: t3+2
3052 |\
3052 |\
3053 | o 4: t3+1
3053 | o 4: t3+1
3054 | |
3054 | |
3055 | o 3: t3+0
3055 | o 3: t3+0
3056 | |
3056 | |
3057 o | 2: t2+0
3057 o | 2: t2+0
3058 |/
3058 |/
3059 o 1: t1+0
3059 o 1: t1+0
3060 |
3060 |
3061 o 0: null+1
3061 o 0: null+1
3062
3062
3063
3063
3064 Two branch tags: fewest changes wins:
3064 Two branch tags: fewest changes wins:
3065
3065
3066 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3066 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3067 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3067 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3068 @ 9: t4+5,6
3068 @ 9: t4+5,6
3069 |
3069 |
3070 o 8: t4+4,5
3070 o 8: t4+4,5
3071 |
3071 |
3072 o 7: t4+3,4
3072 o 7: t4+3,4
3073 |
3073 |
3074 o 6: t4+2,3
3074 o 6: t4+2,3
3075 |
3075 |
3076 o 5: t4+1,2
3076 o 5: t4+1,2
3077 |\
3077 |\
3078 | o 4: t4+0,0
3078 | o 4: t4+0,0
3079 | |
3079 | |
3080 | o 3: t3+0,0
3080 | o 3: t3+0,0
3081 | |
3081 | |
3082 o | 2: t2+0,0
3082 o | 2: t2+0,0
3083 |/
3083 |/
3084 o 1: t1+0,0
3084 o 1: t1+0,0
3085 |
3085 |
3086 o 0: null+1,1
3086 o 0: null+1,1
3087
3087
3088
3088
3089 Merged tag overrides:
3089 Merged tag overrides:
3090
3090
3091 $ hg tag -r 5 -m t5 -d '9 0' t5
3091 $ hg tag -r 5 -m t5 -d '9 0' t5
3092 $ hg tag -r 3 -m at3 -d '10 0' at3
3092 $ hg tag -r 3 -m at3 -d '10 0' at3
3093 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3093 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3094 @ 11: t5+6
3094 @ 11: t5+6
3095 |
3095 |
3096 o 10: t5+5
3096 o 10: t5+5
3097 |
3097 |
3098 o 9: t5+4
3098 o 9: t5+4
3099 |
3099 |
3100 o 8: t5+3
3100 o 8: t5+3
3101 |
3101 |
3102 o 7: t5+2
3102 o 7: t5+2
3103 |
3103 |
3104 o 6: t5+1
3104 o 6: t5+1
3105 |
3105 |
3106 o 5: t5+0
3106 o 5: t5+0
3107 |\
3107 |\
3108 | o 4: t4+0
3108 | o 4: t4+0
3109 | |
3109 | |
3110 | o 3: at3:t3+0
3110 | o 3: at3:t3+0
3111 | |
3111 | |
3112 o | 2: t2+0
3112 o | 2: t2+0
3113 |/
3113 |/
3114 o 1: t1+0
3114 o 1: t1+0
3115 |
3115 |
3116 o 0: null+1
3116 o 0: null+1
3117
3117
3118
3118
3119 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3119 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3120 @ 11: t5+6,6
3120 @ 11: t5+6,6
3121 |
3121 |
3122 o 10: t5+5,5
3122 o 10: t5+5,5
3123 |
3123 |
3124 o 9: t5+4,4
3124 o 9: t5+4,4
3125 |
3125 |
3126 o 8: t5+3,3
3126 o 8: t5+3,3
3127 |
3127 |
3128 o 7: t5+2,2
3128 o 7: t5+2,2
3129 |
3129 |
3130 o 6: t5+1,1
3130 o 6: t5+1,1
3131 |
3131 |
3132 o 5: t5+0,0
3132 o 5: t5+0,0
3133 |\
3133 |\
3134 | o 4: t4+0,0
3134 | o 4: t4+0,0
3135 | |
3135 | |
3136 | o 3: at3+0,0 t3+0,0
3136 | o 3: at3+0,0 t3+0,0
3137 | |
3137 | |
3138 o | 2: t2+0,0
3138 o | 2: t2+0,0
3139 |/
3139 |/
3140 o 1: t1+0,0
3140 o 1: t1+0,0
3141 |
3141 |
3142 o 0: null+1,1
3142 o 0: null+1,1
3143
3143
3144
3144
3145 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3145 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3146 @ 11: t3, C: 9, D: 8
3146 @ 11: t3, C: 9, D: 8
3147 |
3147 |
3148 o 10: t3, C: 8, D: 7
3148 o 10: t3, C: 8, D: 7
3149 |
3149 |
3150 o 9: t3, C: 7, D: 6
3150 o 9: t3, C: 7, D: 6
3151 |
3151 |
3152 o 8: t3, C: 6, D: 5
3152 o 8: t3, C: 6, D: 5
3153 |
3153 |
3154 o 7: t3, C: 5, D: 4
3154 o 7: t3, C: 5, D: 4
3155 |
3155 |
3156 o 6: t3, C: 4, D: 3
3156 o 6: t3, C: 4, D: 3
3157 |
3157 |
3158 o 5: t3, C: 3, D: 2
3158 o 5: t3, C: 3, D: 2
3159 |\
3159 |\
3160 | o 4: t3, C: 1, D: 1
3160 | o 4: t3, C: 1, D: 1
3161 | |
3161 | |
3162 | o 3: t3, C: 0, D: 0
3162 | o 3: t3, C: 0, D: 0
3163 | |
3163 | |
3164 o | 2: t1, C: 1, D: 1
3164 o | 2: t1, C: 1, D: 1
3165 |/
3165 |/
3166 o 1: t1, C: 0, D: 0
3166 o 1: t1, C: 0, D: 0
3167 |
3167 |
3168 o 0: null, C: 1, D: 1
3168 o 0: null, C: 1, D: 1
3169
3169
3170
3170
3171 $ cd ..
3171 $ cd ..
3172
3172
3173
3173
3174 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3174 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3175 if it is a relative path
3175 if it is a relative path
3176
3176
3177 $ mkdir -p home/styles
3177 $ mkdir -p home/styles
3178
3178
3179 $ cat > home/styles/teststyle <<EOF
3179 $ cat > home/styles/teststyle <<EOF
3180 > changeset = 'test {rev}:{node|short}\n'
3180 > changeset = 'test {rev}:{node|short}\n'
3181 > EOF
3181 > EOF
3182
3182
3183 $ HOME=`pwd`/home; export HOME
3183 $ HOME=`pwd`/home; export HOME
3184
3184
3185 $ cat > latesttag/.hg/hgrc <<EOF
3185 $ cat > latesttag/.hg/hgrc <<EOF
3186 > [ui]
3186 > [ui]
3187 > style = ~/styles/teststyle
3187 > style = ~/styles/teststyle
3188 > EOF
3188 > EOF
3189
3189
3190 $ hg -R latesttag tip
3190 $ hg -R latesttag tip
3191 test 11:97e5943b523a
3191 test 11:97e5943b523a
3192
3192
3193 Test recursive showlist template (issue1989):
3193 Test recursive showlist template (issue1989):
3194
3194
3195 $ cat > style1989 <<EOF
3195 $ cat > style1989 <<EOF
3196 > changeset = '{file_mods}{manifest}{extras}'
3196 > changeset = '{file_mods}{manifest}{extras}'
3197 > file_mod = 'M|{author|person}\n'
3197 > file_mod = 'M|{author|person}\n'
3198 > manifest = '{rev},{author}\n'
3198 > manifest = '{rev},{author}\n'
3199 > extra = '{key}: {author}\n'
3199 > extra = '{key}: {author}\n'
3200 > EOF
3200 > EOF
3201
3201
3202 $ hg -R latesttag log -r tip --style=style1989
3202 $ hg -R latesttag log -r tip --style=style1989
3203 M|test
3203 M|test
3204 11,test
3204 11,test
3205 branch: test
3205 branch: test
3206
3206
3207 Test new-style inline templating:
3207 Test new-style inline templating:
3208
3208
3209 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3209 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3210 modified files: .hgtags
3210 modified files: .hgtags
3211
3211
3212
3212
3213 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3213 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3214 hg: parse error: keyword 'rev' is not iterable of mappings
3214 hg: parse error: keyword 'rev' is not iterable of mappings
3215 [255]
3215 [255]
3216 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3216 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3217 hg: parse error: None is not iterable of mappings
3217 hg: parse error: None is not iterable of mappings
3218 [255]
3218 [255]
3219 $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
3219 $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
3220 hg: parse error: <generator *> is not iterable of mappings (glob)
3220 hg: parse error: list of strings is not mappable
3221 [255]
3221 [255]
3222
3222
3223 Test new-style inline templating of non-list/dict type:
3223 Test new-style inline templating of non-list/dict type:
3224
3224
3225 $ hg log -R latesttag -r tip -T '{manifest}\n'
3225 $ hg log -R latesttag -r tip -T '{manifest}\n'
3226 11:2bc6e9006ce2
3226 11:2bc6e9006ce2
3227 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3227 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3228 string length: 15
3228 string length: 15
3229 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3229 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3230 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3230 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3231
3231
3232 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3232 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3233 branch: default
3233 branch: default
3234 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3234 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3235 hg: parse error: None is not iterable of mappings
3235 hg: parse error: None is not iterable of mappings
3236 [255]
3236 [255]
3237 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3237 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3238 branch: default
3238 branch: default
3239 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3239 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3240 0:ce3cec86e6c2
3240 0:ce3cec86e6c2
3241 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3241 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3242 9:fbc7cd862e9c
3242 9:fbc7cd862e9c
3243
3243
3244 Test manifest/get() can be join()-ed as before, though it's silly:
3244 Test manifest/get() can be join()-ed as before, though it's silly:
3245
3245
3246 $ hg log -R latesttag -r tip -T '{join(manifest, "")}\n'
3246 $ hg log -R latesttag -r tip -T '{join(manifest, "")}\n'
3247 11:2bc6e9006ce2
3247 11:2bc6e9006ce2
3248 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3248 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3249 default
3249 default
3250
3250
3251 Test min/max of integers
3251 Test min/max of integers
3252
3252
3253 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3253 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3254 9
3254 9
3255 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3255 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3256 10
3256 10
3257
3257
3258 Test min/max over map operation:
3259
3260 $ hg log -R latesttag -r3 -T '{min(tags % "{tag}")}\n'
3261 at3
3262 $ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n'
3263 t3
3264
3258 Test min/max of if() result
3265 Test min/max of if() result
3259
3266
3260 $ cd latesttag
3267 $ cd latesttag
3261 $ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n'
3268 $ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n'
3262 9
3269 9
3263 $ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n'
3270 $ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n'
3264 10
3271 10
3265 $ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n'
3272 $ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n'
3266 9
3273 9
3267 $ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n'
3274 $ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n'
3268 10
3275 10
3269 $ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n'
3276 $ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n'
3270 9
3277 9
3271 $ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n'
3278 $ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n'
3272 10
3279 10
3273 $ cd ..
3280 $ cd ..
3274
3281
3275 Test laziness of if() then/else clause
3282 Test laziness of if() then/else clause
3276
3283
3277 $ hg debugtemplate '{count(0)}'
3284 $ hg debugtemplate '{count(0)}'
3278 hg: parse error: not countable
3285 hg: parse error: not countable
3279 (incompatible use of template filter 'count')
3286 (incompatible use of template filter 'count')
3280 [255]
3287 [255]
3281 $ hg debugtemplate '{if(true, "", count(0))}'
3288 $ hg debugtemplate '{if(true, "", count(0))}'
3282 $ hg debugtemplate '{if(false, count(0), "")}'
3289 $ hg debugtemplate '{if(false, count(0), "")}'
3283 $ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}'
3290 $ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}'
3284 $ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}'
3291 $ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}'
3285 $ hg debugtemplate '{ifeq(0, 0, "", count(0))}'
3292 $ hg debugtemplate '{ifeq(0, 0, "", count(0))}'
3286 $ hg debugtemplate '{ifeq(0, 1, count(0), "")}'
3293 $ hg debugtemplate '{ifeq(0, 1, count(0), "")}'
3287
3294
3288 Test dot operator precedence:
3295 Test dot operator precedence:
3289
3296
3290 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3297 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3291 (template
3298 (template
3292 (|
3299 (|
3293 (.
3300 (.
3294 (symbol 'manifest')
3301 (symbol 'manifest')
3295 (symbol 'node'))
3302 (symbol 'node'))
3296 (symbol 'short'))
3303 (symbol 'short'))
3297 (string '\n'))
3304 (string '\n'))
3298 89f4071fec70
3305 89f4071fec70
3299
3306
3300 (the following examples are invalid, but seem natural in parsing POV)
3307 (the following examples are invalid, but seem natural in parsing POV)
3301
3308
3302 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3309 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3303 (template
3310 (template
3304 (|
3311 (|
3305 (symbol 'foo')
3312 (symbol 'foo')
3306 (.
3313 (.
3307 (symbol 'bar')
3314 (symbol 'bar')
3308 (symbol 'baz')))
3315 (symbol 'baz')))
3309 (string '\n'))
3316 (string '\n'))
3310 [255]
3317 [255]
3311 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3318 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3312 (template
3319 (template
3313 (.
3320 (.
3314 (symbol 'foo')
3321 (symbol 'foo')
3315 (func
3322 (func
3316 (symbol 'bar')
3323 (symbol 'bar')
3317 None))
3324 None))
3318 (string '\n'))
3325 (string '\n'))
3319 [255]
3326 [255]
3320
3327
3321 Test evaluation of dot operator:
3328 Test evaluation of dot operator:
3322
3329
3323 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3330 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3324 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3331 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3325 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3332 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3326 default
3333 default
3327
3334
3328 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3335 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3329 hg: parse error: keyword 'author' has no member
3336 hg: parse error: keyword 'author' has no member
3330 [255]
3337 [255]
3331 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3338 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3332 hg: parse error: 'a' has no member
3339 hg: parse error: 'a' has no member
3333 [255]
3340 [255]
3334
3341
3335 Test the sub function of templating for expansion:
3342 Test the sub function of templating for expansion:
3336
3343
3337 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3344 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3338 xx
3345 xx
3339
3346
3340 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3347 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3341 hg: parse error: sub got an invalid pattern: [
3348 hg: parse error: sub got an invalid pattern: [
3342 [255]
3349 [255]
3343 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3350 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3344 hg: parse error: sub got an invalid replacement: \1
3351 hg: parse error: sub got an invalid replacement: \1
3345 [255]
3352 [255]
3346
3353
3347 Test the strip function with chars specified:
3354 Test the strip function with chars specified:
3348
3355
3349 $ hg log -R latesttag --template '{desc}\n'
3356 $ hg log -R latesttag --template '{desc}\n'
3350 at3
3357 at3
3351 t5
3358 t5
3352 t4
3359 t4
3353 t3
3360 t3
3354 t2
3361 t2
3355 t1
3362 t1
3356 merge
3363 merge
3357 h2e
3364 h2e
3358 h2d
3365 h2d
3359 h1c
3366 h1c
3360 b
3367 b
3361 a
3368 a
3362
3369
3363 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3370 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3364 at3
3371 at3
3365 5
3372 5
3366 4
3373 4
3367 3
3374 3
3368 2
3375 2
3369 1
3376 1
3370 merg
3377 merg
3371 h2
3378 h2
3372 h2d
3379 h2d
3373 h1c
3380 h1c
3374 b
3381 b
3375 a
3382 a
3376
3383
3377 Test date format:
3384 Test date format:
3378
3385
3379 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3386 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3380 date: 70 01 01 10 +0000
3387 date: 70 01 01 10 +0000
3381 date: 70 01 01 09 +0000
3388 date: 70 01 01 09 +0000
3382 date: 70 01 01 04 +0000
3389 date: 70 01 01 04 +0000
3383 date: 70 01 01 08 +0000
3390 date: 70 01 01 08 +0000
3384 date: 70 01 01 07 +0000
3391 date: 70 01 01 07 +0000
3385 date: 70 01 01 06 +0000
3392 date: 70 01 01 06 +0000
3386 date: 70 01 01 05 +0100
3393 date: 70 01 01 05 +0100
3387 date: 70 01 01 04 +0000
3394 date: 70 01 01 04 +0000
3388 date: 70 01 01 03 +0000
3395 date: 70 01 01 03 +0000
3389 date: 70 01 01 02 +0000
3396 date: 70 01 01 02 +0000
3390 date: 70 01 01 01 +0000
3397 date: 70 01 01 01 +0000
3391 date: 70 01 01 00 +0000
3398 date: 70 01 01 00 +0000
3392
3399
3393 Test invalid date:
3400 Test invalid date:
3394
3401
3395 $ hg log -R latesttag -T '{date(rev)}\n'
3402 $ hg log -R latesttag -T '{date(rev)}\n'
3396 hg: parse error: date expects a date information
3403 hg: parse error: date expects a date information
3397 [255]
3404 [255]
3398
3405
3399 Test integer literal:
3406 Test integer literal:
3400
3407
3401 $ hg debugtemplate -v '{(0)}\n'
3408 $ hg debugtemplate -v '{(0)}\n'
3402 (template
3409 (template
3403 (group
3410 (group
3404 (integer '0'))
3411 (integer '0'))
3405 (string '\n'))
3412 (string '\n'))
3406 0
3413 0
3407 $ hg debugtemplate -v '{(123)}\n'
3414 $ hg debugtemplate -v '{(123)}\n'
3408 (template
3415 (template
3409 (group
3416 (group
3410 (integer '123'))
3417 (integer '123'))
3411 (string '\n'))
3418 (string '\n'))
3412 123
3419 123
3413 $ hg debugtemplate -v '{(-4)}\n'
3420 $ hg debugtemplate -v '{(-4)}\n'
3414 (template
3421 (template
3415 (group
3422 (group
3416 (negate
3423 (negate
3417 (integer '4')))
3424 (integer '4')))
3418 (string '\n'))
3425 (string '\n'))
3419 -4
3426 -4
3420 $ hg debugtemplate '{(-)}\n'
3427 $ hg debugtemplate '{(-)}\n'
3421 hg: parse error at 3: not a prefix: )
3428 hg: parse error at 3: not a prefix: )
3422 ({(-)}\n
3429 ({(-)}\n
3423 ^ here)
3430 ^ here)
3424 [255]
3431 [255]
3425 $ hg debugtemplate '{(-a)}\n'
3432 $ hg debugtemplate '{(-a)}\n'
3426 hg: parse error: negation needs an integer argument
3433 hg: parse error: negation needs an integer argument
3427 [255]
3434 [255]
3428
3435
3429 top-level integer literal is interpreted as symbol (i.e. variable name):
3436 top-level integer literal is interpreted as symbol (i.e. variable name):
3430
3437
3431 $ hg debugtemplate -D 1=one -v '{1}\n'
3438 $ hg debugtemplate -D 1=one -v '{1}\n'
3432 (template
3439 (template
3433 (integer '1')
3440 (integer '1')
3434 (string '\n'))
3441 (string '\n'))
3435 one
3442 one
3436 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3443 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3437 (template
3444 (template
3438 (func
3445 (func
3439 (symbol 'if')
3446 (symbol 'if')
3440 (list
3447 (list
3441 (string 't')
3448 (string 't')
3442 (template
3449 (template
3443 (integer '1'))))
3450 (integer '1'))))
3444 (string '\n'))
3451 (string '\n'))
3445 one
3452 one
3446 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3453 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3447 (template
3454 (template
3448 (|
3455 (|
3449 (integer '1')
3456 (integer '1')
3450 (symbol 'stringify'))
3457 (symbol 'stringify'))
3451 (string '\n'))
3458 (string '\n'))
3452 one
3459 one
3453
3460
3454 unless explicit symbol is expected:
3461 unless explicit symbol is expected:
3455
3462
3456 $ hg log -Ra -r0 -T '{desc|1}\n'
3463 $ hg log -Ra -r0 -T '{desc|1}\n'
3457 hg: parse error: expected a symbol, got 'integer'
3464 hg: parse error: expected a symbol, got 'integer'
3458 [255]
3465 [255]
3459 $ hg log -Ra -r0 -T '{1()}\n'
3466 $ hg log -Ra -r0 -T '{1()}\n'
3460 hg: parse error: expected a symbol, got 'integer'
3467 hg: parse error: expected a symbol, got 'integer'
3461 [255]
3468 [255]
3462
3469
3463 Test string literal:
3470 Test string literal:
3464
3471
3465 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3472 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3466 (template
3473 (template
3467 (string 'string with no template fragment')
3474 (string 'string with no template fragment')
3468 (string '\n'))
3475 (string '\n'))
3469 string with no template fragment
3476 string with no template fragment
3470 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3477 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3471 (template
3478 (template
3472 (template
3479 (template
3473 (string 'template: ')
3480 (string 'template: ')
3474 (symbol 'rev'))
3481 (symbol 'rev'))
3475 (string '\n'))
3482 (string '\n'))
3476 template: 0
3483 template: 0
3477 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3484 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3478 (template
3485 (template
3479 (string 'rawstring: {rev}')
3486 (string 'rawstring: {rev}')
3480 (string '\n'))
3487 (string '\n'))
3481 rawstring: {rev}
3488 rawstring: {rev}
3482 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3489 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3483 (template
3490 (template
3484 (%
3491 (%
3485 (symbol 'files')
3492 (symbol 'files')
3486 (string 'rawstring: {file}'))
3493 (string 'rawstring: {file}'))
3487 (string '\n'))
3494 (string '\n'))
3488 rawstring: {file}
3495 rawstring: {file}
3489
3496
3490 Test string escaping:
3497 Test string escaping:
3491
3498
3492 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3499 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3493 >
3500 >
3494 <>\n<[>
3501 <>\n<[>
3495 <>\n<]>
3502 <>\n<]>
3496 <>\n<
3503 <>\n<
3497
3504
3498 $ hg log -R latesttag -r 0 \
3505 $ hg log -R latesttag -r 0 \
3499 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3506 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3500 >
3507 >
3501 <>\n<[>
3508 <>\n<[>
3502 <>\n<]>
3509 <>\n<]>
3503 <>\n<
3510 <>\n<
3504
3511
3505 $ hg log -R latesttag -r 0 -T esc \
3512 $ hg log -R latesttag -r 0 -T esc \
3506 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3513 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3507 >
3514 >
3508 <>\n<[>
3515 <>\n<[>
3509 <>\n<]>
3516 <>\n<]>
3510 <>\n<
3517 <>\n<
3511
3518
3512 $ cat <<'EOF' > esctmpl
3519 $ cat <<'EOF' > esctmpl
3513 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3520 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3514 > EOF
3521 > EOF
3515 $ hg log -R latesttag -r 0 --style ./esctmpl
3522 $ hg log -R latesttag -r 0 --style ./esctmpl
3516 >
3523 >
3517 <>\n<[>
3524 <>\n<[>
3518 <>\n<]>
3525 <>\n<]>
3519 <>\n<
3526 <>\n<
3520
3527
3521 Test string escaping of quotes:
3528 Test string escaping of quotes:
3522
3529
3523 $ hg log -Ra -r0 -T '{"\""}\n'
3530 $ hg log -Ra -r0 -T '{"\""}\n'
3524 "
3531 "
3525 $ hg log -Ra -r0 -T '{"\\\""}\n'
3532 $ hg log -Ra -r0 -T '{"\\\""}\n'
3526 \"
3533 \"
3527 $ hg log -Ra -r0 -T '{r"\""}\n'
3534 $ hg log -Ra -r0 -T '{r"\""}\n'
3528 \"
3535 \"
3529 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3536 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3530 \\\"
3537 \\\"
3531
3538
3532
3539
3533 $ hg log -Ra -r0 -T '{"\""}\n'
3540 $ hg log -Ra -r0 -T '{"\""}\n'
3534 "
3541 "
3535 $ hg log -Ra -r0 -T '{"\\\""}\n'
3542 $ hg log -Ra -r0 -T '{"\\\""}\n'
3536 \"
3543 \"
3537 $ hg log -Ra -r0 -T '{r"\""}\n'
3544 $ hg log -Ra -r0 -T '{r"\""}\n'
3538 \"
3545 \"
3539 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3546 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3540 \\\"
3547 \\\"
3541
3548
3542 Test exception in quoted template. single backslash before quotation mark is
3549 Test exception in quoted template. single backslash before quotation mark is
3543 stripped before parsing:
3550 stripped before parsing:
3544
3551
3545 $ cat <<'EOF' > escquotetmpl
3552 $ cat <<'EOF' > escquotetmpl
3546 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3553 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3547 > EOF
3554 > EOF
3548 $ cd latesttag
3555 $ cd latesttag
3549 $ hg log -r 2 --style ../escquotetmpl
3556 $ hg log -r 2 --style ../escquotetmpl
3550 " \" \" \\" head1
3557 " \" \" \\" head1
3551
3558
3552 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3559 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3553 valid
3560 valid
3554 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3561 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3555 valid
3562 valid
3556
3563
3557 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3564 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3558 _evalifliteral() templates (issue4733):
3565 _evalifliteral() templates (issue4733):
3559
3566
3560 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3567 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3561 "2
3568 "2
3562 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3569 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3563 "2
3570 "2
3564 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3571 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3565 "2
3572 "2
3566
3573
3567 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3574 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3568 \"
3575 \"
3569 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3576 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3570 \"
3577 \"
3571 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3578 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3572 \"
3579 \"
3573
3580
3574 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3581 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3575 \\\"
3582 \\\"
3576 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3583 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3577 \\\"
3584 \\\"
3578 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3585 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3579 \\\"
3586 \\\"
3580
3587
3581 escaped single quotes and errors:
3588 escaped single quotes and errors:
3582
3589
3583 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3590 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3584 foo
3591 foo
3585 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3592 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3586 foo
3593 foo
3587 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3594 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3588 hg: parse error at 21: unterminated string
3595 hg: parse error at 21: unterminated string
3589 ({if(rev, "{if(rev, \")}")}\n
3596 ({if(rev, "{if(rev, \")}")}\n
3590 ^ here)
3597 ^ here)
3591 [255]
3598 [255]
3592 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3599 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3593 hg: parse error: trailing \ in string
3600 hg: parse error: trailing \ in string
3594 [255]
3601 [255]
3595 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3602 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3596 hg: parse error: trailing \ in string
3603 hg: parse error: trailing \ in string
3597 [255]
3604 [255]
3598
3605
3599 $ cd ..
3606 $ cd ..
3600
3607
3601 Test leading backslashes:
3608 Test leading backslashes:
3602
3609
3603 $ cd latesttag
3610 $ cd latesttag
3604 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3611 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3605 {rev} {file}
3612 {rev} {file}
3606 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3613 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3607 \2 \head1
3614 \2 \head1
3608 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3615 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3609 \{rev} \{file}
3616 \{rev} \{file}
3610 $ cd ..
3617 $ cd ..
3611
3618
3612 Test leading backslashes in "if" expression (issue4714):
3619 Test leading backslashes in "if" expression (issue4714):
3613
3620
3614 $ cd latesttag
3621 $ cd latesttag
3615 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3622 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3616 {rev} \{rev}
3623 {rev} \{rev}
3617 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3624 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3618 \2 \\{rev}
3625 \2 \\{rev}
3619 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3626 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3620 \{rev} \\\{rev}
3627 \{rev} \\\{rev}
3621 $ cd ..
3628 $ cd ..
3622
3629
3623 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3630 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3624
3631
3625 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3632 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3626 \x6e
3633 \x6e
3627 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3634 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3628 \x5c\x786e
3635 \x5c\x786e
3629 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3636 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3630 \x6e
3637 \x6e
3631 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3638 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3632 \x5c\x786e
3639 \x5c\x786e
3633
3640
3634 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3641 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3635 \x6e
3642 \x6e
3636 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3643 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3637 \x5c\x786e
3644 \x5c\x786e
3638 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3645 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3639 \x6e
3646 \x6e
3640 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3647 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3641 \x5c\x786e
3648 \x5c\x786e
3642
3649
3643 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3650 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3644 fourth
3651 fourth
3645 second
3652 second
3646 third
3653 third
3647 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3654 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3648 fourth\nsecond\nthird
3655 fourth\nsecond\nthird
3649
3656
3650 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3657 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3651 <p>
3658 <p>
3652 1st
3659 1st
3653 </p>
3660 </p>
3654 <p>
3661 <p>
3655 2nd
3662 2nd
3656 </p>
3663 </p>
3657 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3664 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3658 <p>
3665 <p>
3659 1st\n\n2nd
3666 1st\n\n2nd
3660 </p>
3667 </p>
3661 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3668 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3662 1st
3669 1st
3663
3670
3664 2nd
3671 2nd
3665
3672
3666 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3673 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3667 o perso
3674 o perso
3668 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3675 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3669 no person
3676 no person
3670 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3677 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3671 o perso
3678 o perso
3672 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3679 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3673 no perso
3680 no perso
3674
3681
3675 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3682 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3676 -o perso-
3683 -o perso-
3677 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3684 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3678 no person
3685 no person
3679 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3686 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3680 \x2do perso\x2d
3687 \x2do perso\x2d
3681 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3688 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3682 -o perso-
3689 -o perso-
3683 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3690 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3684 \x2do perso\x6e
3691 \x2do perso\x6e
3685
3692
3686 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3693 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3687 fourth
3694 fourth
3688 second
3695 second
3689 third
3696 third
3690
3697
3691 Test string escaping in nested expression:
3698 Test string escaping in nested expression:
3692
3699
3693 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3700 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3694 fourth\x6esecond\x6ethird
3701 fourth\x6esecond\x6ethird
3695 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3702 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3696 fourth\x6esecond\x6ethird
3703 fourth\x6esecond\x6ethird
3697
3704
3698 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3705 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3699 fourth\x6esecond\x6ethird
3706 fourth\x6esecond\x6ethird
3700 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3707 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3701 fourth\x5c\x786esecond\x5c\x786ethird
3708 fourth\x5c\x786esecond\x5c\x786ethird
3702
3709
3703 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3710 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3704 3:\x6eo user, \x6eo domai\x6e
3711 3:\x6eo user, \x6eo domai\x6e
3705 4:\x5c\x786eew bra\x5c\x786ech
3712 4:\x5c\x786eew bra\x5c\x786ech
3706
3713
3707 Test quotes in nested expression are evaluated just like a $(command)
3714 Test quotes in nested expression are evaluated just like a $(command)
3708 substitution in POSIX shells:
3715 substitution in POSIX shells:
3709
3716
3710 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3717 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3711 8:95c24699272e
3718 8:95c24699272e
3712 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3719 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3713 {8} "95c24699272e"
3720 {8} "95c24699272e"
3714
3721
3715 Test recursive evaluation:
3722 Test recursive evaluation:
3716
3723
3717 $ hg init r
3724 $ hg init r
3718 $ cd r
3725 $ cd r
3719 $ echo a > a
3726 $ echo a > a
3720 $ hg ci -Am '{rev}'
3727 $ hg ci -Am '{rev}'
3721 adding a
3728 adding a
3722 $ hg log -r 0 --template '{if(rev, desc)}\n'
3729 $ hg log -r 0 --template '{if(rev, desc)}\n'
3723 {rev}
3730 {rev}
3724 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3731 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3725 test 0
3732 test 0
3726
3733
3727 $ hg branch -q 'text.{rev}'
3734 $ hg branch -q 'text.{rev}'
3728 $ echo aa >> aa
3735 $ echo aa >> aa
3729 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3736 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3730
3737
3731 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3738 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3732 {node|short}desc to
3739 {node|short}desc to
3733 text.{rev}be wrapped
3740 text.{rev}be wrapped
3734 text.{rev}desc to be
3741 text.{rev}desc to be
3735 text.{rev}wrapped (no-eol)
3742 text.{rev}wrapped (no-eol)
3736 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3743 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3737 bcc7ff960b8e:desc to
3744 bcc7ff960b8e:desc to
3738 text.1:be wrapped
3745 text.1:be wrapped
3739 text.1:desc to be
3746 text.1:desc to be
3740 text.1:wrapped (no-eol)
3747 text.1:wrapped (no-eol)
3741 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3748 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3742 hg: parse error: fill expects an integer width
3749 hg: parse error: fill expects an integer width
3743 [255]
3750 [255]
3744
3751
3745 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3752 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3746 bcc7ff960b8e:desc to be
3753 bcc7ff960b8e:desc to be
3747 termwidth.1:wrapped desc
3754 termwidth.1:wrapped desc
3748 termwidth.1:to be wrapped (no-eol)
3755 termwidth.1:to be wrapped (no-eol)
3749
3756
3750 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3757 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3751 {node|short} (no-eol)
3758 {node|short} (no-eol)
3752 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3759 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3753 bcc-ff---b-e (no-eol)
3760 bcc-ff---b-e (no-eol)
3754
3761
3755 $ cat >> .hg/hgrc <<EOF
3762 $ cat >> .hg/hgrc <<EOF
3756 > [extensions]
3763 > [extensions]
3757 > color=
3764 > color=
3758 > [color]
3765 > [color]
3759 > mode=ansi
3766 > mode=ansi
3760 > text.{rev} = red
3767 > text.{rev} = red
3761 > text.1 = green
3768 > text.1 = green
3762 > EOF
3769 > EOF
3763 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3770 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3764 \x1b[0;31mtext\x1b[0m (esc)
3771 \x1b[0;31mtext\x1b[0m (esc)
3765 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3772 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3766 \x1b[0;32mtext\x1b[0m (esc)
3773 \x1b[0;32mtext\x1b[0m (esc)
3767
3774
3768 color effect can be specified without quoting:
3775 color effect can be specified without quoting:
3769
3776
3770 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3777 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3771 \x1b[0;31mtext\x1b[0m (esc)
3778 \x1b[0;31mtext\x1b[0m (esc)
3772
3779
3773 color effects can be nested (issue5413)
3780 color effects can be nested (issue5413)
3774
3781
3775 $ hg debugtemplate --color=always \
3782 $ hg debugtemplate --color=always \
3776 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3783 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3777 \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)
3784 \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)
3778
3785
3779 pad() should interact well with color codes (issue5416)
3786 pad() should interact well with color codes (issue5416)
3780
3787
3781 $ hg debugtemplate --color=always \
3788 $ hg debugtemplate --color=always \
3782 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3789 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3783 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3790 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3784
3791
3785 label should be no-op if color is disabled:
3792 label should be no-op if color is disabled:
3786
3793
3787 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3794 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3788 text
3795 text
3789 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3796 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3790 text
3797 text
3791
3798
3792 Test branches inside if statement:
3799 Test branches inside if statement:
3793
3800
3794 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3801 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3795 no
3802 no
3796
3803
3797 Test dict constructor:
3804 Test dict constructor:
3798
3805
3799 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3806 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3800 y=f7769ec2ab97 x=0
3807 y=f7769ec2ab97 x=0
3801 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3808 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3802 x=0
3809 x=0
3803 y=f7769ec2ab97
3810 y=f7769ec2ab97
3804 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3811 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3805 {"x": 0, "y": "f7769ec2ab97"}
3812 {"x": 0, "y": "f7769ec2ab97"}
3806 $ hg log -r 0 -T '{dict()|json}\n'
3813 $ hg log -r 0 -T '{dict()|json}\n'
3807 {}
3814 {}
3808
3815
3809 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3816 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3810 rev=0 node=f7769ec2ab97
3817 rev=0 node=f7769ec2ab97
3811 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3818 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3812 rev=0 node=f7769ec2ab97
3819 rev=0 node=f7769ec2ab97
3813
3820
3814 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3821 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3815 hg: parse error: duplicated dict key 'rev' inferred
3822 hg: parse error: duplicated dict key 'rev' inferred
3816 [255]
3823 [255]
3817 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3824 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3818 hg: parse error: duplicated dict key 'node' inferred
3825 hg: parse error: duplicated dict key 'node' inferred
3819 [255]
3826 [255]
3820 $ hg log -r 0 -T '{dict(1 + 2)}'
3827 $ hg log -r 0 -T '{dict(1 + 2)}'
3821 hg: parse error: dict key cannot be inferred
3828 hg: parse error: dict key cannot be inferred
3822 [255]
3829 [255]
3823
3830
3824 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3831 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3825 hg: parse error: dict got multiple values for keyword argument 'x'
3832 hg: parse error: dict got multiple values for keyword argument 'x'
3826 [255]
3833 [255]
3827
3834
3828 Test get function:
3835 Test get function:
3829
3836
3830 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3837 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3831 default
3838 default
3832 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3839 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3833 default
3840 default
3834 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3841 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3835 hg: parse error: get() expects a dict as first argument
3842 hg: parse error: get() expects a dict as first argument
3836 [255]
3843 [255]
3837
3844
3838 Test json filter applied to hybrid object:
3845 Test json filter applied to hybrid object:
3839
3846
3840 $ hg log -r0 -T '{files|json}\n'
3847 $ hg log -r0 -T '{files|json}\n'
3841 ["a"]
3848 ["a"]
3842 $ hg log -r0 -T '{extras|json}\n'
3849 $ hg log -r0 -T '{extras|json}\n'
3843 {"branch": "default"}
3850 {"branch": "default"}
3844
3851
3852 Test json filter applied to map result:
3853
3854 $ hg log -r0 -T '{json(extras % "{key}")}\n'
3855 ["branch"]
3856
3845 Test localdate(date, tz) function:
3857 Test localdate(date, tz) function:
3846
3858
3847 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3859 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3848 1970-01-01 09:00 +0900
3860 1970-01-01 09:00 +0900
3849 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3861 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3850 1970-01-01 00:00 +0000
3862 1970-01-01 00:00 +0000
3851 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3863 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3852 hg: parse error: localdate expects a timezone
3864 hg: parse error: localdate expects a timezone
3853 [255]
3865 [255]
3854 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3866 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3855 1970-01-01 02:00 +0200
3867 1970-01-01 02:00 +0200
3856 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3868 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3857 1970-01-01 00:00 +0000
3869 1970-01-01 00:00 +0000
3858 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3870 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3859 1970-01-01 00:00 +0000
3871 1970-01-01 00:00 +0000
3860 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3872 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3861 hg: parse error: localdate expects a timezone
3873 hg: parse error: localdate expects a timezone
3862 [255]
3874 [255]
3863 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3875 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3864 hg: parse error: localdate expects a timezone
3876 hg: parse error: localdate expects a timezone
3865 [255]
3877 [255]
3866
3878
3867 Test shortest(node) function:
3879 Test shortest(node) function:
3868
3880
3869 $ echo b > b
3881 $ echo b > b
3870 $ hg ci -qAm b
3882 $ hg ci -qAm b
3871 $ hg log --template '{shortest(node)}\n'
3883 $ hg log --template '{shortest(node)}\n'
3872 e777
3884 e777
3873 bcc7
3885 bcc7
3874 f776
3886 f776
3875 $ hg log --template '{shortest(node, 10)}\n'
3887 $ hg log --template '{shortest(node, 10)}\n'
3876 e777603221
3888 e777603221
3877 bcc7ff960b
3889 bcc7ff960b
3878 f7769ec2ab
3890 f7769ec2ab
3879 $ hg log --template '{node|shortest}\n' -l1
3891 $ hg log --template '{node|shortest}\n' -l1
3880 e777
3892 e777
3881
3893
3882 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3894 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3883 f7769ec2ab
3895 f7769ec2ab
3884 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3896 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3885 hg: parse error: shortest() expects an integer minlength
3897 hg: parse error: shortest() expects an integer minlength
3886 [255]
3898 [255]
3887
3899
3888 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3900 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3889 ffff
3901 ffff
3890
3902
3891 $ cd ..
3903 $ cd ..
3892
3904
3893 Test shortest(node) with the repo having short hash collision:
3905 Test shortest(node) with the repo having short hash collision:
3894
3906
3895 $ hg init hashcollision
3907 $ hg init hashcollision
3896 $ cd hashcollision
3908 $ cd hashcollision
3897 $ cat <<EOF >> .hg/hgrc
3909 $ cat <<EOF >> .hg/hgrc
3898 > [experimental]
3910 > [experimental]
3899 > evolution.createmarkers=True
3911 > evolution.createmarkers=True
3900 > EOF
3912 > EOF
3901 $ echo 0 > a
3913 $ echo 0 > a
3902 $ hg ci -qAm 0
3914 $ hg ci -qAm 0
3903 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3915 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3904 > hg up -q 0
3916 > hg up -q 0
3905 > echo $i > a
3917 > echo $i > a
3906 > hg ci -qm $i
3918 > hg ci -qm $i
3907 > done
3919 > done
3908 $ hg up -q null
3920 $ hg up -q null
3909 $ hg log -r0: -T '{rev}:{node}\n'
3921 $ hg log -r0: -T '{rev}:{node}\n'
3910 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3922 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3911 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3923 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3912 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3924 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3913 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3925 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3914 4:10776689e627b465361ad5c296a20a487e153ca4
3926 4:10776689e627b465361ad5c296a20a487e153ca4
3915 5:a00be79088084cb3aff086ab799f8790e01a976b
3927 5:a00be79088084cb3aff086ab799f8790e01a976b
3916 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3928 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3917 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3929 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3918 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3930 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3919 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3931 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3920 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3932 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3921 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3933 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3922 obsoleted 1 changesets
3934 obsoleted 1 changesets
3923 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3935 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3924 obsoleted 1 changesets
3936 obsoleted 1 changesets
3925 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3937 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3926 obsoleted 1 changesets
3938 obsoleted 1 changesets
3927
3939
3928 nodes starting with '11' (we don't have the revision number '11' though)
3940 nodes starting with '11' (we don't have the revision number '11' though)
3929
3941
3930 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3942 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3931 1:1142
3943 1:1142
3932 2:1140
3944 2:1140
3933 3:11d
3945 3:11d
3934
3946
3935 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3947 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3936
3948
3937 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3949 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3938 6:a0b
3950 6:a0b
3939 7:a04
3951 7:a04
3940
3952
3941 node '10' conflicts with the revision number '10' even if it is hidden
3953 node '10' conflicts with the revision number '10' even if it is hidden
3942 (we could exclude hidden revision numbers, but currently we don't)
3954 (we could exclude hidden revision numbers, but currently we don't)
3943
3955
3944 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3956 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3945 4:107
3957 4:107
3946 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3958 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3947 4:107
3959 4:107
3948
3960
3949 node 'c562' should be unique if the other 'c562' nodes are hidden
3961 node 'c562' should be unique if the other 'c562' nodes are hidden
3950 (but we don't try the slow path to filter out hidden nodes for now)
3962 (but we don't try the slow path to filter out hidden nodes for now)
3951
3963
3952 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3964 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3953 8:c5625
3965 8:c5625
3954 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3966 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3955 8:c5625
3967 8:c5625
3956 9:c5623
3968 9:c5623
3957 10:c562d
3969 10:c562d
3958
3970
3959 $ cd ..
3971 $ cd ..
3960
3972
3961 Test pad function
3973 Test pad function
3962
3974
3963 $ cd r
3975 $ cd r
3964
3976
3965 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3977 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3966 2 test
3978 2 test
3967 1 {node|short}
3979 1 {node|short}
3968 0 test
3980 0 test
3969
3981
3970 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3982 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3971 2 test
3983 2 test
3972 1 {node|short}
3984 1 {node|short}
3973 0 test
3985 0 test
3974
3986
3975 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3987 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3976 2------------------- test
3988 2------------------- test
3977 1------------------- {node|short}
3989 1------------------- {node|short}
3978 0------------------- test
3990 0------------------- test
3979
3991
3980 Test template string in pad function
3992 Test template string in pad function
3981
3993
3982 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3994 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3983 {0} test
3995 {0} test
3984
3996
3985 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3997 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3986 \{rev} test
3998 \{rev} test
3987
3999
3988 Test width argument passed to pad function
4000 Test width argument passed to pad function
3989
4001
3990 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
4002 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3991 0 test
4003 0 test
3992 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
4004 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3993 hg: parse error: pad() expects an integer width
4005 hg: parse error: pad() expects an integer width
3994 [255]
4006 [255]
3995
4007
3996 Test invalid fillchar passed to pad function
4008 Test invalid fillchar passed to pad function
3997
4009
3998 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
4010 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3999 hg: parse error: pad() expects a single fill character
4011 hg: parse error: pad() expects a single fill character
4000 [255]
4012 [255]
4001 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
4013 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
4002 hg: parse error: pad() expects a single fill character
4014 hg: parse error: pad() expects a single fill character
4003 [255]
4015 [255]
4004
4016
4005 Test boolean argument passed to pad function
4017 Test boolean argument passed to pad function
4006
4018
4007 no crash
4019 no crash
4008
4020
4009 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
4021 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
4010 ---------0
4022 ---------0
4011
4023
4012 string/literal
4024 string/literal
4013
4025
4014 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
4026 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
4015 ---------0
4027 ---------0
4016 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
4028 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
4017 0---------
4029 0---------
4018 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
4030 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
4019 0---------
4031 0---------
4020
4032
4021 unknown keyword is evaluated to ''
4033 unknown keyword is evaluated to ''
4022
4034
4023 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
4035 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
4024 0---------
4036 0---------
4025
4037
4026 Test separate function
4038 Test separate function
4027
4039
4028 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
4040 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
4029 a-b-c
4041 a-b-c
4030 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
4042 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
4031 0:f7769ec2ab97 test default
4043 0:f7769ec2ab97 test default
4032 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
4044 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
4033 a \x1b[0;31mb\x1b[0m c d (esc)
4045 a \x1b[0;31mb\x1b[0m c d (esc)
4034
4046
4035 Test boolean expression/literal passed to if function
4047 Test boolean expression/literal passed to if function
4036
4048
4037 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
4049 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
4038 rev 0 is True
4050 rev 0 is True
4039 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
4051 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
4040 literal 0 is True as well
4052 literal 0 is True as well
4041 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
4053 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
4042 empty string is False
4054 empty string is False
4043 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
4055 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
4044 empty list is False
4056 empty list is False
4045 $ hg log -r 0 -T '{if(true, "true is True")}\n'
4057 $ hg log -r 0 -T '{if(true, "true is True")}\n'
4046 true is True
4058 true is True
4047 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
4059 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
4048 false is False
4060 false is False
4049 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
4061 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
4050 non-empty string is True
4062 non-empty string is True
4051
4063
4052 Test ifcontains function
4064 Test ifcontains function
4053
4065
4054 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
4066 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
4055 2 is in the string
4067 2 is in the string
4056 1 is not
4068 1 is not
4057 0 is in the string
4069 0 is in the string
4058
4070
4059 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
4071 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
4060 2 is in the string
4072 2 is in the string
4061 1 is not
4073 1 is not
4062 0 is in the string
4074 0 is in the string
4063
4075
4064 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
4076 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
4065 2 did not add a
4077 2 did not add a
4066 1 did not add a
4078 1 did not add a
4067 0 added a
4079 0 added a
4068
4080
4069 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
4081 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
4070 2 is parent of 1
4082 2 is parent of 1
4071 1
4083 1
4072 0
4084 0
4073
4085
4074 Test revset function
4086 Test revset function
4075
4087
4076 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4088 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4077 2 current rev
4089 2 current rev
4078 1 not current rev
4090 1 not current rev
4079 0 not current rev
4091 0 not current rev
4080
4092
4081 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4093 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4082 2 match rev
4094 2 match rev
4083 1 match rev
4095 1 match rev
4084 0 not match rev
4096 0 not match rev
4085
4097
4086 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4098 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4087 type not match
4099 type not match
4088
4100
4089 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4101 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4090 2 Parents: 1
4102 2 Parents: 1
4091 1 Parents: 0
4103 1 Parents: 0
4092 0 Parents:
4104 0 Parents:
4093
4105
4094 $ cat >> .hg/hgrc <<EOF
4106 $ cat >> .hg/hgrc <<EOF
4095 > [revsetalias]
4107 > [revsetalias]
4096 > myparents(\$1) = parents(\$1)
4108 > myparents(\$1) = parents(\$1)
4097 > EOF
4109 > EOF
4098 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4110 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4099 2 Parents: 1
4111 2 Parents: 1
4100 1 Parents: 0
4112 1 Parents: 0
4101 0 Parents:
4113 0 Parents:
4102
4114
4103 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4115 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4104 Rev: 2
4116 Rev: 2
4105 Ancestor: 0
4117 Ancestor: 0
4106 Ancestor: 1
4118 Ancestor: 1
4107 Ancestor: 2
4119 Ancestor: 2
4108
4120
4109 Rev: 1
4121 Rev: 1
4110 Ancestor: 0
4122 Ancestor: 0
4111 Ancestor: 1
4123 Ancestor: 1
4112
4124
4113 Rev: 0
4125 Rev: 0
4114 Ancestor: 0
4126 Ancestor: 0
4115
4127
4116 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4128 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4117 2
4129 2
4118
4130
4119 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4131 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4120 2
4132 2
4121
4133
4122 a list template is evaluated for each item of revset/parents
4134 a list template is evaluated for each item of revset/parents
4123
4135
4124 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4136 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4125 2 p: 1:bcc7ff960b8e
4137 2 p: 1:bcc7ff960b8e
4126 1 p: 0:f7769ec2ab97
4138 1 p: 0:f7769ec2ab97
4127 0 p:
4139 0 p:
4128
4140
4129 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4141 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4130 2 p: 1:bcc7ff960b8e -1:000000000000
4142 2 p: 1:bcc7ff960b8e -1:000000000000
4131 1 p: 0:f7769ec2ab97 -1:000000000000
4143 1 p: 0:f7769ec2ab97 -1:000000000000
4132 0 p: -1:000000000000 -1:000000000000
4144 0 p: -1:000000000000 -1:000000000000
4133
4145
4134 therefore, 'revcache' should be recreated for each rev
4146 therefore, 'revcache' should be recreated for each rev
4135
4147
4136 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4148 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4137 2 aa b
4149 2 aa b
4138 p
4150 p
4139 1
4151 1
4140 p a
4152 p a
4141 0 a
4153 0 a
4142 p
4154 p
4143
4155
4144 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4156 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4145 2 aa b
4157 2 aa b
4146 p
4158 p
4147 1
4159 1
4148 p a
4160 p a
4149 0 a
4161 0 a
4150 p
4162 p
4151
4163
4152 a revset item must be evaluated as an integer revision, not an offset from tip
4164 a revset item must be evaluated as an integer revision, not an offset from tip
4153
4165
4154 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4166 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4155 -1:000000000000
4167 -1:000000000000
4156 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4168 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4157 -1:000000000000
4169 -1:000000000000
4158
4170
4159 join() should pick '{rev}' from revset items:
4171 join() should pick '{rev}' from revset items:
4160
4172
4161 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4173 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4162 4, 5
4174 4, 5
4163
4175
4164 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4176 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4165 default. join() should agree with the default formatting:
4177 default. join() should agree with the default formatting:
4166
4178
4167 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4179 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4168 5:13207e5a10d9, 4:bbe44766e73d
4180 5:13207e5a10d9, 4:bbe44766e73d
4169
4181
4170 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4182 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4171 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4183 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4172 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4184 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4173
4185
4174 Invalid arguments passed to revset()
4186 Invalid arguments passed to revset()
4175
4187
4176 $ hg log -T '{revset("%whatever", 0)}\n'
4188 $ hg log -T '{revset("%whatever", 0)}\n'
4177 hg: parse error: unexpected revspec format character w
4189 hg: parse error: unexpected revspec format character w
4178 [255]
4190 [255]
4179 $ hg log -T '{revset("%lwhatever", files)}\n'
4191 $ hg log -T '{revset("%lwhatever", files)}\n'
4180 hg: parse error: unexpected revspec format character w
4192 hg: parse error: unexpected revspec format character w
4181 [255]
4193 [255]
4182 $ hg log -T '{revset("%s %s", 0)}\n'
4194 $ hg log -T '{revset("%s %s", 0)}\n'
4183 hg: parse error: missing argument for revspec
4195 hg: parse error: missing argument for revspec
4184 [255]
4196 [255]
4185 $ hg log -T '{revset("", 0)}\n'
4197 $ hg log -T '{revset("", 0)}\n'
4186 hg: parse error: too many revspec arguments specified
4198 hg: parse error: too many revspec arguments specified
4187 [255]
4199 [255]
4188 $ hg log -T '{revset("%s", 0, 1)}\n'
4200 $ hg log -T '{revset("%s", 0, 1)}\n'
4189 hg: parse error: too many revspec arguments specified
4201 hg: parse error: too many revspec arguments specified
4190 [255]
4202 [255]
4191 $ hg log -T '{revset("%", 0)}\n'
4203 $ hg log -T '{revset("%", 0)}\n'
4192 hg: parse error: incomplete revspec format character
4204 hg: parse error: incomplete revspec format character
4193 [255]
4205 [255]
4194 $ hg log -T '{revset("%l", 0)}\n'
4206 $ hg log -T '{revset("%l", 0)}\n'
4195 hg: parse error: incomplete revspec format character
4207 hg: parse error: incomplete revspec format character
4196 [255]
4208 [255]
4197 $ hg log -T '{revset("%d", 'foo')}\n'
4209 $ hg log -T '{revset("%d", 'foo')}\n'
4198 hg: parse error: invalid argument for revspec
4210 hg: parse error: invalid argument for revspec
4199 [255]
4211 [255]
4200 $ hg log -T '{revset("%ld", files)}\n'
4212 $ hg log -T '{revset("%ld", files)}\n'
4201 hg: parse error: invalid argument for revspec
4213 hg: parse error: invalid argument for revspec
4202 [255]
4214 [255]
4203 $ hg log -T '{revset("%ls", 0)}\n'
4215 $ hg log -T '{revset("%ls", 0)}\n'
4204 hg: parse error: invalid argument for revspec
4216 hg: parse error: invalid argument for revspec
4205 [255]
4217 [255]
4206 $ hg log -T '{revset("%b", 'foo')}\n'
4218 $ hg log -T '{revset("%b", 'foo')}\n'
4207 hg: parse error: invalid argument for revspec
4219 hg: parse error: invalid argument for revspec
4208 [255]
4220 [255]
4209 $ hg log -T '{revset("%lb", files)}\n'
4221 $ hg log -T '{revset("%lb", files)}\n'
4210 hg: parse error: invalid argument for revspec
4222 hg: parse error: invalid argument for revspec
4211 [255]
4223 [255]
4212 $ hg log -T '{revset("%r", 0)}\n'
4224 $ hg log -T '{revset("%r", 0)}\n'
4213 hg: parse error: invalid argument for revspec
4225 hg: parse error: invalid argument for revspec
4214 [255]
4226 [255]
4215
4227
4216 Test 'originalnode'
4228 Test 'originalnode'
4217
4229
4218 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
4230 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
4219 000000000000 bcc7ff960b8e
4231 000000000000 bcc7ff960b8e
4220 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
4232 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
4221 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
4233 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
4222
4234
4223 Test files function
4235 Test files function
4224
4236
4225 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4237 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4226 2
4238 2
4227 a
4239 a
4228 aa
4240 aa
4229 b
4241 b
4230 1
4242 1
4231 a
4243 a
4232 0
4244 0
4233 a
4245 a
4234
4246
4235 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4247 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4236 2
4248 2
4237 aa
4249 aa
4238 1
4250 1
4239
4251
4240 0
4252 0
4241
4253
4242
4254
4243 Test relpath function
4255 Test relpath function
4244
4256
4245 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4257 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4246 a
4258 a
4247 $ cd ..
4259 $ cd ..
4248 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4260 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4249 r/a
4261 r/a
4250 $ cd r
4262 $ cd r
4251
4263
4252 Test active bookmark templating
4264 Test active bookmark templating
4253
4265
4254 $ hg book foo
4266 $ hg book foo
4255 $ hg book bar
4267 $ hg book bar
4256 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4268 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4257 2 bar* foo
4269 2 bar* foo
4258 1
4270 1
4259 0
4271 0
4260 $ hg log --template "{rev} {activebookmark}\n"
4272 $ hg log --template "{rev} {activebookmark}\n"
4261 2 bar
4273 2 bar
4262 1
4274 1
4263 0
4275 0
4264 $ hg bookmarks --inactive bar
4276 $ hg bookmarks --inactive bar
4265 $ hg log --template "{rev} {activebookmark}\n"
4277 $ hg log --template "{rev} {activebookmark}\n"
4266 2
4278 2
4267 1
4279 1
4268 0
4280 0
4269 $ hg book -r1 baz
4281 $ hg book -r1 baz
4270 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4282 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4271 2 bar foo
4283 2 bar foo
4272 1 baz
4284 1 baz
4273 0
4285 0
4274 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4286 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4275 2 t
4287 2 t
4276 1 f
4288 1 f
4277 0 f
4289 0 f
4278
4290
4279 Test namespaces dict
4291 Test namespaces dict
4280
4292
4281 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4293 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4282 2
4294 2
4283 bookmarks color=bookmark builtin=True
4295 bookmarks color=bookmark builtin=True
4284 bar,foo
4296 bar,foo
4285 tags color=tag builtin=True
4297 tags color=tag builtin=True
4286 tip
4298 tip
4287 branches color=branch builtin=True
4299 branches color=branch builtin=True
4288 text.{rev}
4300 text.{rev}
4289 revnames color=revname builtin=False
4301 revnames color=revname builtin=False
4290 r2
4302 r2
4291
4303
4292 1
4304 1
4293 bookmarks color=bookmark builtin=True
4305 bookmarks color=bookmark builtin=True
4294 baz
4306 baz
4295 tags color=tag builtin=True
4307 tags color=tag builtin=True
4296
4308
4297 branches color=branch builtin=True
4309 branches color=branch builtin=True
4298 text.{rev}
4310 text.{rev}
4299 revnames color=revname builtin=False
4311 revnames color=revname builtin=False
4300 r1
4312 r1
4301
4313
4302 0
4314 0
4303 bookmarks color=bookmark builtin=True
4315 bookmarks color=bookmark builtin=True
4304
4316
4305 tags color=tag builtin=True
4317 tags color=tag builtin=True
4306
4318
4307 branches color=branch builtin=True
4319 branches color=branch builtin=True
4308 default
4320 default
4309 revnames color=revname builtin=False
4321 revnames color=revname builtin=False
4310 r0
4322 r0
4311
4323
4312 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4324 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4313 bookmarks: bar foo
4325 bookmarks: bar foo
4314 tags: tip
4326 tags: tip
4315 branches: text.{rev}
4327 branches: text.{rev}
4316 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4328 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4317 bookmarks:
4329 bookmarks:
4318 bar
4330 bar
4319 foo
4331 foo
4320 tags:
4332 tags:
4321 tip
4333 tip
4322 branches:
4334 branches:
4323 text.{rev}
4335 text.{rev}
4324 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4336 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4325 bar
4337 bar
4326 foo
4338 foo
4327 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4339 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4328 bar
4340 bar
4329 foo
4341 foo
4330
4342
4331 Test stringify on sub expressions
4343 Test stringify on sub expressions
4332
4344
4333 $ cd ..
4345 $ cd ..
4334 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4346 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4335 fourth, second, third
4347 fourth, second, third
4336 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4348 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4337 abc
4349 abc
4338
4350
4339 Test splitlines
4351 Test splitlines
4340
4352
4341 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4353 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4342 @ foo Modify, add, remove, rename
4354 @ foo Modify, add, remove, rename
4343 |
4355 |
4344 o foo future
4356 o foo future
4345 |
4357 |
4346 o foo third
4358 o foo third
4347 |
4359 |
4348 o foo second
4360 o foo second
4349
4361
4350 o foo merge
4362 o foo merge
4351 |\
4363 |\
4352 | o foo new head
4364 | o foo new head
4353 | |
4365 | |
4354 o | foo new branch
4366 o | foo new branch
4355 |/
4367 |/
4356 o foo no user, no domain
4368 o foo no user, no domain
4357 |
4369 |
4358 o foo no person
4370 o foo no person
4359 |
4371 |
4360 o foo other 1
4372 o foo other 1
4361 | foo other 2
4373 | foo other 2
4362 | foo
4374 | foo
4363 | foo other 3
4375 | foo other 3
4364 o foo line 1
4376 o foo line 1
4365 foo line 2
4377 foo line 2
4366
4378
4367 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4379 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4368 line 1 line 2
4380 line 1 line 2
4369 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4381 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4370 line 1|line 2
4382 line 1|line 2
4371
4383
4372 Test startswith
4384 Test startswith
4373 $ hg log -Gv -R a --template "{startswith(desc)}"
4385 $ hg log -Gv -R a --template "{startswith(desc)}"
4374 hg: parse error: startswith expects two arguments
4386 hg: parse error: startswith expects two arguments
4375 [255]
4387 [255]
4376
4388
4377 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4389 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4378 @
4390 @
4379 |
4391 |
4380 o
4392 o
4381 |
4393 |
4382 o
4394 o
4383 |
4395 |
4384 o
4396 o
4385
4397
4386 o
4398 o
4387 |\
4399 |\
4388 | o
4400 | o
4389 | |
4401 | |
4390 o |
4402 o |
4391 |/
4403 |/
4392 o
4404 o
4393 |
4405 |
4394 o
4406 o
4395 |
4407 |
4396 o
4408 o
4397 |
4409 |
4398 o line 1
4410 o line 1
4399 line 2
4411 line 2
4400
4412
4401 Test bad template with better error message
4413 Test bad template with better error message
4402
4414
4403 $ hg log -Gv -R a --template '{desc|user()}'
4415 $ hg log -Gv -R a --template '{desc|user()}'
4404 hg: parse error: expected a symbol, got 'func'
4416 hg: parse error: expected a symbol, got 'func'
4405 [255]
4417 [255]
4406
4418
4407 Test word function (including index out of bounds graceful failure)
4419 Test word function (including index out of bounds graceful failure)
4408
4420
4409 $ hg log -Gv -R a --template "{word('1', desc)}"
4421 $ hg log -Gv -R a --template "{word('1', desc)}"
4410 @ add,
4422 @ add,
4411 |
4423 |
4412 o
4424 o
4413 |
4425 |
4414 o
4426 o
4415 |
4427 |
4416 o
4428 o
4417
4429
4418 o
4430 o
4419 |\
4431 |\
4420 | o head
4432 | o head
4421 | |
4433 | |
4422 o | branch
4434 o | branch
4423 |/
4435 |/
4424 o user,
4436 o user,
4425 |
4437 |
4426 o person
4438 o person
4427 |
4439 |
4428 o 1
4440 o 1
4429 |
4441 |
4430 o 1
4442 o 1
4431
4443
4432
4444
4433 Test word third parameter used as splitter
4445 Test word third parameter used as splitter
4434
4446
4435 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4447 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4436 @ M
4448 @ M
4437 |
4449 |
4438 o future
4450 o future
4439 |
4451 |
4440 o third
4452 o third
4441 |
4453 |
4442 o sec
4454 o sec
4443
4455
4444 o merge
4456 o merge
4445 |\
4457 |\
4446 | o new head
4458 | o new head
4447 | |
4459 | |
4448 o | new branch
4460 o | new branch
4449 |/
4461 |/
4450 o n
4462 o n
4451 |
4463 |
4452 o n
4464 o n
4453 |
4465 |
4454 o
4466 o
4455 |
4467 |
4456 o line 1
4468 o line 1
4457 line 2
4469 line 2
4458
4470
4459 Test word error messages for not enough and too many arguments
4471 Test word error messages for not enough and too many arguments
4460
4472
4461 $ hg log -Gv -R a --template "{word('0')}"
4473 $ hg log -Gv -R a --template "{word('0')}"
4462 hg: parse error: word expects two or three arguments, got 1
4474 hg: parse error: word expects two or three arguments, got 1
4463 [255]
4475 [255]
4464
4476
4465 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4477 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4466 hg: parse error: word expects two or three arguments, got 7
4478 hg: parse error: word expects two or three arguments, got 7
4467 [255]
4479 [255]
4468
4480
4469 Test word for integer literal
4481 Test word for integer literal
4470
4482
4471 $ hg log -R a --template "{word(2, desc)}\n" -r0
4483 $ hg log -R a --template "{word(2, desc)}\n" -r0
4472 line
4484 line
4473
4485
4474 Test word for invalid numbers
4486 Test word for invalid numbers
4475
4487
4476 $ hg log -Gv -R a --template "{word('a', desc)}"
4488 $ hg log -Gv -R a --template "{word('a', desc)}"
4477 hg: parse error: word expects an integer index
4489 hg: parse error: word expects an integer index
4478 [255]
4490 [255]
4479
4491
4480 Test word for out of range
4492 Test word for out of range
4481
4493
4482 $ hg log -R a --template "{word(10000, desc)}"
4494 $ hg log -R a --template "{word(10000, desc)}"
4483 $ hg log -R a --template "{word(-10000, desc)}"
4495 $ hg log -R a --template "{word(-10000, desc)}"
4484
4496
4485 Test indent and not adding to empty lines
4497 Test indent and not adding to empty lines
4486
4498
4487 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4499 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4488 -----
4500 -----
4489 > line 1
4501 > line 1
4490 >> line 2
4502 >> line 2
4491 -----
4503 -----
4492 > other 1
4504 > other 1
4493 >> other 2
4505 >> other 2
4494
4506
4495 >> other 3
4507 >> other 3
4496
4508
4497 Test with non-strings like dates
4509 Test with non-strings like dates
4498
4510
4499 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4511 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4500 1200000.00
4512 1200000.00
4501 1300000.00
4513 1300000.00
4502
4514
4503 Test broken string escapes:
4515 Test broken string escapes:
4504
4516
4505 $ hg log -T "bogus\\" -R a
4517 $ hg log -T "bogus\\" -R a
4506 hg: parse error: trailing \ in string
4518 hg: parse error: trailing \ in string
4507 [255]
4519 [255]
4508 $ hg log -T "\\xy" -R a
4520 $ hg log -T "\\xy" -R a
4509 hg: parse error: invalid \x escape* (glob)
4521 hg: parse error: invalid \x escape* (glob)
4510 [255]
4522 [255]
4511
4523
4512 json filter should escape HTML tags so that the output can be embedded in hgweb:
4524 json filter should escape HTML tags so that the output can be embedded in hgweb:
4513
4525
4514 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4526 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4515 "\u003cfoo@example.org\u003e"
4527 "\u003cfoo@example.org\u003e"
4516
4528
4517 Templater supports aliases of symbol and func() styles:
4529 Templater supports aliases of symbol and func() styles:
4518
4530
4519 $ hg clone -q a aliases
4531 $ hg clone -q a aliases
4520 $ cd aliases
4532 $ cd aliases
4521 $ cat <<EOF >> .hg/hgrc
4533 $ cat <<EOF >> .hg/hgrc
4522 > [templatealias]
4534 > [templatealias]
4523 > r = rev
4535 > r = rev
4524 > rn = "{r}:{node|short}"
4536 > rn = "{r}:{node|short}"
4525 > status(c, files) = files % "{c} {file}\n"
4537 > status(c, files) = files % "{c} {file}\n"
4526 > utcdate(d) = localdate(d, "UTC")
4538 > utcdate(d) = localdate(d, "UTC")
4527 > EOF
4539 > EOF
4528
4540
4529 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4541 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4530 (template
4542 (template
4531 (symbol 'rn')
4543 (symbol 'rn')
4532 (string ' ')
4544 (string ' ')
4533 (|
4545 (|
4534 (func
4546 (func
4535 (symbol 'utcdate')
4547 (symbol 'utcdate')
4536 (symbol 'date'))
4548 (symbol 'date'))
4537 (symbol 'isodate'))
4549 (symbol 'isodate'))
4538 (string '\n'))
4550 (string '\n'))
4539 * expanded:
4551 * expanded:
4540 (template
4552 (template
4541 (template
4553 (template
4542 (symbol 'rev')
4554 (symbol 'rev')
4543 (string ':')
4555 (string ':')
4544 (|
4556 (|
4545 (symbol 'node')
4557 (symbol 'node')
4546 (symbol 'short')))
4558 (symbol 'short')))
4547 (string ' ')
4559 (string ' ')
4548 (|
4560 (|
4549 (func
4561 (func
4550 (symbol 'localdate')
4562 (symbol 'localdate')
4551 (list
4563 (list
4552 (symbol 'date')
4564 (symbol 'date')
4553 (string 'UTC')))
4565 (string 'UTC')))
4554 (symbol 'isodate'))
4566 (symbol 'isodate'))
4555 (string '\n'))
4567 (string '\n'))
4556 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4568 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4557
4569
4558 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4570 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4559 (template
4571 (template
4560 (func
4572 (func
4561 (symbol 'status')
4573 (symbol 'status')
4562 (list
4574 (list
4563 (string 'A')
4575 (string 'A')
4564 (symbol 'file_adds'))))
4576 (symbol 'file_adds'))))
4565 * expanded:
4577 * expanded:
4566 (template
4578 (template
4567 (%
4579 (%
4568 (symbol 'file_adds')
4580 (symbol 'file_adds')
4569 (template
4581 (template
4570 (string 'A')
4582 (string 'A')
4571 (string ' ')
4583 (string ' ')
4572 (symbol 'file')
4584 (symbol 'file')
4573 (string '\n'))))
4585 (string '\n'))))
4574 A a
4586 A a
4575
4587
4576 A unary function alias can be called as a filter:
4588 A unary function alias can be called as a filter:
4577
4589
4578 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4590 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4579 (template
4591 (template
4580 (|
4592 (|
4581 (|
4593 (|
4582 (symbol 'date')
4594 (symbol 'date')
4583 (symbol 'utcdate'))
4595 (symbol 'utcdate'))
4584 (symbol 'isodate'))
4596 (symbol 'isodate'))
4585 (string '\n'))
4597 (string '\n'))
4586 * expanded:
4598 * expanded:
4587 (template
4599 (template
4588 (|
4600 (|
4589 (func
4601 (func
4590 (symbol 'localdate')
4602 (symbol 'localdate')
4591 (list
4603 (list
4592 (symbol 'date')
4604 (symbol 'date')
4593 (string 'UTC')))
4605 (string 'UTC')))
4594 (symbol 'isodate'))
4606 (symbol 'isodate'))
4595 (string '\n'))
4607 (string '\n'))
4596 1970-01-12 13:46 +0000
4608 1970-01-12 13:46 +0000
4597
4609
4598 Aliases should be applied only to command arguments and templates in hgrc.
4610 Aliases should be applied only to command arguments and templates in hgrc.
4599 Otherwise, our stock styles and web templates could be corrupted:
4611 Otherwise, our stock styles and web templates could be corrupted:
4600
4612
4601 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4613 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4602 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4614 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4603
4615
4604 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4616 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4605 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4617 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4606
4618
4607 $ cat <<EOF > tmpl
4619 $ cat <<EOF > tmpl
4608 > changeset = 'nothing expanded:{rn}\n'
4620 > changeset = 'nothing expanded:{rn}\n'
4609 > EOF
4621 > EOF
4610 $ hg log -r0 --style ./tmpl
4622 $ hg log -r0 --style ./tmpl
4611 nothing expanded:
4623 nothing expanded:
4612
4624
4613 Aliases in formatter:
4625 Aliases in formatter:
4614
4626
4615 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4627 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4616 default 6:d41e714fe50d
4628 default 6:d41e714fe50d
4617 foo 4:bbe44766e73d
4629 foo 4:bbe44766e73d
4618
4630
4619 Aliases should honor HGPLAIN:
4631 Aliases should honor HGPLAIN:
4620
4632
4621 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4633 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4622 nothing expanded:
4634 nothing expanded:
4623 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4635 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4624 0:1e4e1b8f71e0
4636 0:1e4e1b8f71e0
4625
4637
4626 Unparsable alias:
4638 Unparsable alias:
4627
4639
4628 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4640 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4629 (template
4641 (template
4630 (symbol 'bad'))
4642 (symbol 'bad'))
4631 abort: bad definition of template alias "bad": at 2: not a prefix: end
4643 abort: bad definition of template alias "bad": at 2: not a prefix: end
4632 [255]
4644 [255]
4633 $ hg log --config templatealias.bad='x(' -T '{bad}'
4645 $ hg log --config templatealias.bad='x(' -T '{bad}'
4634 abort: bad definition of template alias "bad": at 2: not a prefix: end
4646 abort: bad definition of template alias "bad": at 2: not a prefix: end
4635 [255]
4647 [255]
4636
4648
4637 $ cd ..
4649 $ cd ..
4638
4650
4639 Set up repository for non-ascii encoding tests:
4651 Set up repository for non-ascii encoding tests:
4640
4652
4641 $ hg init nonascii
4653 $ hg init nonascii
4642 $ cd nonascii
4654 $ cd nonascii
4643 $ $PYTHON <<EOF
4655 $ $PYTHON <<EOF
4644 > open('latin1', 'wb').write(b'\xe9')
4656 > open('latin1', 'wb').write(b'\xe9')
4645 > open('utf-8', 'wb').write(b'\xc3\xa9')
4657 > open('utf-8', 'wb').write(b'\xc3\xa9')
4646 > EOF
4658 > EOF
4647 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4659 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4648 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4660 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4649
4661
4650 json filter should try round-trip conversion to utf-8:
4662 json filter should try round-trip conversion to utf-8:
4651
4663
4652 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4664 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4653 "\u00e9"
4665 "\u00e9"
4654 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4666 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4655 "non-ascii branch: \u00e9"
4667 "non-ascii branch: \u00e9"
4656
4668
4657 json filter takes input as utf-8b:
4669 json filter takes input as utf-8b:
4658
4670
4659 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4671 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4660 "\u00e9"
4672 "\u00e9"
4661 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4673 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4662 "\udce9"
4674 "\udce9"
4663
4675
4664 utf8 filter:
4676 utf8 filter:
4665
4677
4666 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4678 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4667 round-trip: c3a9
4679 round-trip: c3a9
4668 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4680 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4669 decoded: c3a9
4681 decoded: c3a9
4670 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4682 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4671 abort: decoding near * (glob)
4683 abort: decoding near * (glob)
4672 [255]
4684 [255]
4673 $ hg log -T "coerced to string: {rev|utf8}\n" -r0
4685 $ hg log -T "coerced to string: {rev|utf8}\n" -r0
4674 coerced to string: 0
4686 coerced to string: 0
4675
4687
4676 pad width:
4688 pad width:
4677
4689
4678 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4690 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4679 \xc3\xa9- (esc)
4691 \xc3\xa9- (esc)
4680
4692
4681 $ cd ..
4693 $ cd ..
4682
4694
4683 Test that template function in extension is registered as expected
4695 Test that template function in extension is registered as expected
4684
4696
4685 $ cd a
4697 $ cd a
4686
4698
4687 $ cat <<EOF > $TESTTMP/customfunc.py
4699 $ cat <<EOF > $TESTTMP/customfunc.py
4688 > from mercurial import registrar
4700 > from mercurial import registrar
4689 >
4701 >
4690 > templatefunc = registrar.templatefunc()
4702 > templatefunc = registrar.templatefunc()
4691 >
4703 >
4692 > @templatefunc(b'custom()')
4704 > @templatefunc(b'custom()')
4693 > def custom(context, mapping, args):
4705 > def custom(context, mapping, args):
4694 > return b'custom'
4706 > return b'custom'
4695 > EOF
4707 > EOF
4696 $ cat <<EOF > .hg/hgrc
4708 $ cat <<EOF > .hg/hgrc
4697 > [extensions]
4709 > [extensions]
4698 > customfunc = $TESTTMP/customfunc.py
4710 > customfunc = $TESTTMP/customfunc.py
4699 > EOF
4711 > EOF
4700
4712
4701 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4713 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4702 custom
4714 custom
4703
4715
4704 $ cd ..
4716 $ cd ..
4705
4717
4706 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4718 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4707 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4719 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4708 columns. We don't care about other aspects of the graph rendering here.
4720 columns. We don't care about other aspects of the graph rendering here.
4709
4721
4710 $ hg init graphwidth
4722 $ hg init graphwidth
4711 $ cd graphwidth
4723 $ cd graphwidth
4712
4724
4713 $ wrappabletext="a a a a a a a a a a a a"
4725 $ wrappabletext="a a a a a a a a a a a a"
4714
4726
4715 $ printf "first\n" > file
4727 $ printf "first\n" > file
4716 $ hg add file
4728 $ hg add file
4717 $ hg commit -m "$wrappabletext"
4729 $ hg commit -m "$wrappabletext"
4718
4730
4719 $ printf "first\nsecond\n" > file
4731 $ printf "first\nsecond\n" > file
4720 $ hg commit -m "$wrappabletext"
4732 $ hg commit -m "$wrappabletext"
4721
4733
4722 $ hg checkout 0
4734 $ hg checkout 0
4723 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4735 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4724 $ printf "third\nfirst\n" > file
4736 $ printf "third\nfirst\n" > file
4725 $ hg commit -m "$wrappabletext"
4737 $ hg commit -m "$wrappabletext"
4726 created new head
4738 created new head
4727
4739
4728 $ hg merge
4740 $ hg merge
4729 merging file
4741 merging file
4730 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4742 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4731 (branch merge, don't forget to commit)
4743 (branch merge, don't forget to commit)
4732
4744
4733 $ hg log --graph -T "{graphwidth}"
4745 $ hg log --graph -T "{graphwidth}"
4734 @ 3
4746 @ 3
4735 |
4747 |
4736 | @ 5
4748 | @ 5
4737 |/
4749 |/
4738 o 3
4750 o 3
4739
4751
4740 $ hg commit -m "$wrappabletext"
4752 $ hg commit -m "$wrappabletext"
4741
4753
4742 $ hg log --graph -T "{graphwidth}"
4754 $ hg log --graph -T "{graphwidth}"
4743 @ 5
4755 @ 5
4744 |\
4756 |\
4745 | o 5
4757 | o 5
4746 | |
4758 | |
4747 o | 5
4759 o | 5
4748 |/
4760 |/
4749 o 3
4761 o 3
4750
4762
4751
4763
4752 $ hg checkout 0
4764 $ hg checkout 0
4753 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4765 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4754 $ printf "third\nfirst\nsecond\n" > file
4766 $ printf "third\nfirst\nsecond\n" > file
4755 $ hg commit -m "$wrappabletext"
4767 $ hg commit -m "$wrappabletext"
4756 created new head
4768 created new head
4757
4769
4758 $ hg log --graph -T "{graphwidth}"
4770 $ hg log --graph -T "{graphwidth}"
4759 @ 3
4771 @ 3
4760 |
4772 |
4761 | o 7
4773 | o 7
4762 | |\
4774 | |\
4763 +---o 7
4775 +---o 7
4764 | |
4776 | |
4765 | o 5
4777 | o 5
4766 |/
4778 |/
4767 o 3
4779 o 3
4768
4780
4769
4781
4770 $ hg log --graph -T "{graphwidth}" -r 3
4782 $ hg log --graph -T "{graphwidth}" -r 3
4771 o 5
4783 o 5
4772 |\
4784 |\
4773 ~ ~
4785 ~ ~
4774
4786
4775 $ hg log --graph -T "{graphwidth}" -r 1
4787 $ hg log --graph -T "{graphwidth}" -r 1
4776 o 3
4788 o 3
4777 |
4789 |
4778 ~
4790 ~
4779
4791
4780 $ hg merge
4792 $ hg merge
4781 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4793 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4782 (branch merge, don't forget to commit)
4794 (branch merge, don't forget to commit)
4783 $ hg commit -m "$wrappabletext"
4795 $ hg commit -m "$wrappabletext"
4784
4796
4785 $ printf "seventh\n" >> file
4797 $ printf "seventh\n" >> file
4786 $ hg commit -m "$wrappabletext"
4798 $ hg commit -m "$wrappabletext"
4787
4799
4788 $ hg log --graph -T "{graphwidth}"
4800 $ hg log --graph -T "{graphwidth}"
4789 @ 3
4801 @ 3
4790 |
4802 |
4791 o 5
4803 o 5
4792 |\
4804 |\
4793 | o 5
4805 | o 5
4794 | |
4806 | |
4795 o | 7
4807 o | 7
4796 |\ \
4808 |\ \
4797 | o | 7
4809 | o | 7
4798 | |/
4810 | |/
4799 o / 5
4811 o / 5
4800 |/
4812 |/
4801 o 3
4813 o 3
4802
4814
4803
4815
4804 The point of graphwidth is to allow wrapping that accounts for the space taken
4816 The point of graphwidth is to allow wrapping that accounts for the space taken
4805 by the graph.
4817 by the graph.
4806
4818
4807 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4819 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4808 @ a a a a
4820 @ a a a a
4809 | a a a a
4821 | a a a a
4810 | a a a a
4822 | a a a a
4811 o a a a
4823 o a a a
4812 |\ a a a
4824 |\ a a a
4813 | | a a a
4825 | | a a a
4814 | | a a a
4826 | | a a a
4815 | o a a a
4827 | o a a a
4816 | | a a a
4828 | | a a a
4817 | | a a a
4829 | | a a a
4818 | | a a a
4830 | | a a a
4819 o | a a
4831 o | a a
4820 |\ \ a a
4832 |\ \ a a
4821 | | | a a
4833 | | | a a
4822 | | | a a
4834 | | | a a
4823 | | | a a
4835 | | | a a
4824 | | | a a
4836 | | | a a
4825 | o | a a
4837 | o | a a
4826 | |/ a a
4838 | |/ a a
4827 | | a a
4839 | | a a
4828 | | a a
4840 | | a a
4829 | | a a
4841 | | a a
4830 | | a a
4842 | | a a
4831 o | a a a
4843 o | a a a
4832 |/ a a a
4844 |/ a a a
4833 | a a a
4845 | a a a
4834 | a a a
4846 | a a a
4835 o a a a a
4847 o a a a a
4836 a a a a
4848 a a a a
4837 a a a a
4849 a a a a
4838
4850
4839 Something tricky happens when there are elided nodes; the next drawn row of
4851 Something tricky happens when there are elided nodes; the next drawn row of
4840 edges can be more than one column wider, but the graph width only increases by
4852 edges can be more than one column wider, but the graph width only increases by
4841 one column. The remaining columns are added in between the nodes.
4853 one column. The remaining columns are added in between the nodes.
4842
4854
4843 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4855 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4844 o 5
4856 o 5
4845 |\
4857 |\
4846 | \
4858 | \
4847 | :\
4859 | :\
4848 o : : 7
4860 o : : 7
4849 :/ /
4861 :/ /
4850 : o 5
4862 : o 5
4851 :/
4863 :/
4852 o 3
4864 o 3
4853
4865
4854
4866
4855 $ cd ..
4867 $ cd ..
4856
4868
General Comments 0
You need to be logged in to leave comments. Login now