##// END OF EJS Templates
templater: add support for keyword arguments...
Yuya Nishihara -
r31886:bdda942f default
parent child Browse files
Show More
@@ -1,254 +1,261 b''
1 # registrar.py - utilities to register function for specific purpose
1 # registrar.py - utilities to register function for specific purpose
2 #
2 #
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
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 from . import (
10 from . import (
11 error,
11 error,
12 pycompat,
12 pycompat,
13 util,
13 util,
14 )
14 )
15
15
16 class _funcregistrarbase(object):
16 class _funcregistrarbase(object):
17 """Base of decorator to register a function for specific purpose
17 """Base of decorator to register a function for specific purpose
18
18
19 This decorator stores decorated functions into own dict 'table'.
19 This decorator stores decorated functions into own dict 'table'.
20
20
21 The least derived class can be defined by overriding 'formatdoc',
21 The least derived class can be defined by overriding 'formatdoc',
22 for example::
22 for example::
23
23
24 class keyword(_funcregistrarbase):
24 class keyword(_funcregistrarbase):
25 _docformat = ":%s: %s"
25 _docformat = ":%s: %s"
26
26
27 This should be used as below:
27 This should be used as below:
28
28
29 keyword = registrar.keyword()
29 keyword = registrar.keyword()
30
30
31 @keyword('bar')
31 @keyword('bar')
32 def barfunc(*args, **kwargs):
32 def barfunc(*args, **kwargs):
33 '''Explanation of bar keyword ....
33 '''Explanation of bar keyword ....
34 '''
34 '''
35 pass
35 pass
36
36
37 In this case:
37 In this case:
38
38
39 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
39 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
40 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
40 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
41 """
41 """
42 def __init__(self, table=None):
42 def __init__(self, table=None):
43 if table is None:
43 if table is None:
44 self._table = {}
44 self._table = {}
45 else:
45 else:
46 self._table = table
46 self._table = table
47
47
48 def __call__(self, decl, *args, **kwargs):
48 def __call__(self, decl, *args, **kwargs):
49 return lambda func: self._doregister(func, decl, *args, **kwargs)
49 return lambda func: self._doregister(func, decl, *args, **kwargs)
50
50
51 def _doregister(self, func, decl, *args, **kwargs):
51 def _doregister(self, func, decl, *args, **kwargs):
52 name = self._getname(decl)
52 name = self._getname(decl)
53
53
54 if name in self._table:
54 if name in self._table:
55 msg = 'duplicate registration for name: "%s"' % name
55 msg = 'duplicate registration for name: "%s"' % name
56 raise error.ProgrammingError(msg)
56 raise error.ProgrammingError(msg)
57
57
58 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
58 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
59 doc = pycompat.sysbytes(func.__doc__).strip()
59 doc = pycompat.sysbytes(func.__doc__).strip()
60 func._origdoc = doc
60 func._origdoc = doc
61 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
61 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
62
62
63 self._table[name] = func
63 self._table[name] = func
64 self._extrasetup(name, func, *args, **kwargs)
64 self._extrasetup(name, func, *args, **kwargs)
65
65
66 return func
66 return func
67
67
68 def _parsefuncdecl(self, decl):
68 def _parsefuncdecl(self, decl):
69 """Parse function declaration and return the name of function in it
69 """Parse function declaration and return the name of function in it
70 """
70 """
71 i = decl.find('(')
71 i = decl.find('(')
72 if i >= 0:
72 if i >= 0:
73 return decl[:i]
73 return decl[:i]
74 else:
74 else:
75 return decl
75 return decl
76
76
77 def _getname(self, decl):
77 def _getname(self, decl):
78 """Return the name of the registered function from decl
78 """Return the name of the registered function from decl
79
79
80 Derived class should override this, if it allows more
80 Derived class should override this, if it allows more
81 descriptive 'decl' string than just a name.
81 descriptive 'decl' string than just a name.
82 """
82 """
83 return decl
83 return decl
84
84
85 _docformat = None
85 _docformat = None
86
86
87 def _formatdoc(self, decl, doc):
87 def _formatdoc(self, decl, doc):
88 """Return formatted document of the registered function for help
88 """Return formatted document of the registered function for help
89
89
90 'doc' is '__doc__.strip()' of the registered function.
90 'doc' is '__doc__.strip()' of the registered function.
91 """
91 """
92 return self._docformat % (decl, doc)
92 return self._docformat % (decl, doc)
93
93
94 def _extrasetup(self, name, func):
94 def _extrasetup(self, name, func):
95 """Execute exra setup for registered function, if needed
95 """Execute exra setup for registered function, if needed
96 """
96 """
97 pass
97 pass
98
98
99 class revsetpredicate(_funcregistrarbase):
99 class revsetpredicate(_funcregistrarbase):
100 """Decorator to register revset predicate
100 """Decorator to register revset predicate
101
101
102 Usage::
102 Usage::
103
103
104 revsetpredicate = registrar.revsetpredicate()
104 revsetpredicate = registrar.revsetpredicate()
105
105
106 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
106 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
107 def mypredicatefunc(repo, subset, x):
107 def mypredicatefunc(repo, subset, x):
108 '''Explanation of this revset predicate ....
108 '''Explanation of this revset predicate ....
109 '''
109 '''
110 pass
110 pass
111
111
112 The first string argument is used also in online help.
112 The first string argument is used also in online help.
113
113
114 Optional argument 'safe' indicates whether a predicate is safe for
114 Optional argument 'safe' indicates whether a predicate is safe for
115 DoS attack (False by default).
115 DoS attack (False by default).
116
116
117 Optional argument 'takeorder' indicates whether a predicate function
117 Optional argument 'takeorder' indicates whether a predicate function
118 takes ordering policy as the last argument.
118 takes ordering policy as the last argument.
119
119
120 'revsetpredicate' instance in example above can be used to
120 'revsetpredicate' instance in example above can be used to
121 decorate multiple functions.
121 decorate multiple functions.
122
122
123 Decorated functions are registered automatically at loading
123 Decorated functions are registered automatically at loading
124 extension, if an instance named as 'revsetpredicate' is used for
124 extension, if an instance named as 'revsetpredicate' is used for
125 decorating in extension.
125 decorating in extension.
126
126
127 Otherwise, explicit 'revset.loadpredicate()' is needed.
127 Otherwise, explicit 'revset.loadpredicate()' is needed.
128 """
128 """
129 _getname = _funcregistrarbase._parsefuncdecl
129 _getname = _funcregistrarbase._parsefuncdecl
130 _docformat = "``%s``\n %s"
130 _docformat = "``%s``\n %s"
131
131
132 def _extrasetup(self, name, func, safe=False, takeorder=False):
132 def _extrasetup(self, name, func, safe=False, takeorder=False):
133 func._safe = safe
133 func._safe = safe
134 func._takeorder = takeorder
134 func._takeorder = takeorder
135
135
136 class filesetpredicate(_funcregistrarbase):
136 class filesetpredicate(_funcregistrarbase):
137 """Decorator to register fileset predicate
137 """Decorator to register fileset predicate
138
138
139 Usage::
139 Usage::
140
140
141 filesetpredicate = registrar.filesetpredicate()
141 filesetpredicate = registrar.filesetpredicate()
142
142
143 @filesetpredicate('mypredicate()')
143 @filesetpredicate('mypredicate()')
144 def mypredicatefunc(mctx, x):
144 def mypredicatefunc(mctx, x):
145 '''Explanation of this fileset predicate ....
145 '''Explanation of this fileset predicate ....
146 '''
146 '''
147 pass
147 pass
148
148
149 The first string argument is used also in online help.
149 The first string argument is used also in online help.
150
150
151 Optional argument 'callstatus' indicates whether a predicate
151 Optional argument 'callstatus' indicates whether a predicate
152 implies 'matchctx.status()' at runtime or not (False, by
152 implies 'matchctx.status()' at runtime or not (False, by
153 default).
153 default).
154
154
155 Optional argument 'callexisting' indicates whether a predicate
155 Optional argument 'callexisting' indicates whether a predicate
156 implies 'matchctx.existing()' at runtime or not (False, by
156 implies 'matchctx.existing()' at runtime or not (False, by
157 default).
157 default).
158
158
159 'filesetpredicate' instance in example above can be used to
159 'filesetpredicate' instance in example above can be used to
160 decorate multiple functions.
160 decorate multiple functions.
161
161
162 Decorated functions are registered automatically at loading
162 Decorated functions are registered automatically at loading
163 extension, if an instance named as 'filesetpredicate' is used for
163 extension, if an instance named as 'filesetpredicate' is used for
164 decorating in extension.
164 decorating in extension.
165
165
166 Otherwise, explicit 'fileset.loadpredicate()' is needed.
166 Otherwise, explicit 'fileset.loadpredicate()' is needed.
167 """
167 """
168 _getname = _funcregistrarbase._parsefuncdecl
168 _getname = _funcregistrarbase._parsefuncdecl
169 _docformat = "``%s``\n %s"
169 _docformat = "``%s``\n %s"
170
170
171 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
171 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
172 func._callstatus = callstatus
172 func._callstatus = callstatus
173 func._callexisting = callexisting
173 func._callexisting = callexisting
174
174
175 class _templateregistrarbase(_funcregistrarbase):
175 class _templateregistrarbase(_funcregistrarbase):
176 """Base of decorator to register functions as template specific one
176 """Base of decorator to register functions as template specific one
177 """
177 """
178 _docformat = ":%s: %s"
178 _docformat = ":%s: %s"
179
179
180 class templatekeyword(_templateregistrarbase):
180 class templatekeyword(_templateregistrarbase):
181 """Decorator to register template keyword
181 """Decorator to register template keyword
182
182
183 Usage::
183 Usage::
184
184
185 templatekeyword = registrar.templatekeyword()
185 templatekeyword = registrar.templatekeyword()
186
186
187 @templatekeyword('mykeyword')
187 @templatekeyword('mykeyword')
188 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
188 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
189 '''Explanation of this template keyword ....
189 '''Explanation of this template keyword ....
190 '''
190 '''
191 pass
191 pass
192
192
193 The first string argument is used also in online help.
193 The first string argument is used also in online help.
194
194
195 'templatekeyword' instance in example above can be used to
195 'templatekeyword' instance in example above can be used to
196 decorate multiple functions.
196 decorate multiple functions.
197
197
198 Decorated functions are registered automatically at loading
198 Decorated functions are registered automatically at loading
199 extension, if an instance named as 'templatekeyword' is used for
199 extension, if an instance named as 'templatekeyword' is used for
200 decorating in extension.
200 decorating in extension.
201
201
202 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
202 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
203 """
203 """
204
204
205 class templatefilter(_templateregistrarbase):
205 class templatefilter(_templateregistrarbase):
206 """Decorator to register template filer
206 """Decorator to register template filer
207
207
208 Usage::
208 Usage::
209
209
210 templatefilter = registrar.templatefilter()
210 templatefilter = registrar.templatefilter()
211
211
212 @templatefilter('myfilter')
212 @templatefilter('myfilter')
213 def myfilterfunc(text):
213 def myfilterfunc(text):
214 '''Explanation of this template filter ....
214 '''Explanation of this template filter ....
215 '''
215 '''
216 pass
216 pass
217
217
218 The first string argument is used also in online help.
218 The first string argument is used also in online help.
219
219
220 'templatefilter' instance in example above can be used to
220 'templatefilter' instance in example above can be used to
221 decorate multiple functions.
221 decorate multiple functions.
222
222
223 Decorated functions are registered automatically at loading
223 Decorated functions are registered automatically at loading
224 extension, if an instance named as 'templatefilter' is used for
224 extension, if an instance named as 'templatefilter' is used for
225 decorating in extension.
225 decorating in extension.
226
226
227 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
227 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
228 """
228 """
229
229
230 class templatefunc(_templateregistrarbase):
230 class templatefunc(_templateregistrarbase):
231 """Decorator to register template function
231 """Decorator to register template function
232
232
233 Usage::
233 Usage::
234
234
235 templatefunc = registrar.templatefunc()
235 templatefunc = registrar.templatefunc()
236
236
237 @templatefunc('myfunc(arg1, arg2[, arg3])')
237 @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3')
238 def myfuncfunc(context, mapping, args):
238 def myfuncfunc(context, mapping, args):
239 '''Explanation of this template function ....
239 '''Explanation of this template function ....
240 '''
240 '''
241 pass
241 pass
242
242
243 The first string argument is used also in online help.
243 The first string argument is used also in online help.
244
244
245 If optional 'argspec' is defined, the function will receive 'args' as
246 a dict of named arguments. Otherwise 'args' is a list of positional
247 arguments.
248
245 'templatefunc' instance in example above can be used to
249 'templatefunc' instance in example above can be used to
246 decorate multiple functions.
250 decorate multiple functions.
247
251
248 Decorated functions are registered automatically at loading
252 Decorated functions are registered automatically at loading
249 extension, if an instance named as 'templatefunc' is used for
253 extension, if an instance named as 'templatefunc' is used for
250 decorating in extension.
254 decorating in extension.
251
255
252 Otherwise, explicit 'templater.loadfunction()' is needed.
256 Otherwise, explicit 'templater.loadfunction()' is needed.
253 """
257 """
254 _getname = _funcregistrarbase._parsefuncdecl
258 _getname = _funcregistrarbase._parsefuncdecl
259
260 def _extrasetup(self, name, func, argspec=None):
261 func._argspec = argspec
@@ -1,1300 +1,1325 b''
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import re
11 import re
12 import types
12 import types
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 color,
16 color,
17 config,
17 config,
18 encoding,
18 encoding,
19 error,
19 error,
20 minirst,
20 minirst,
21 parser,
21 parser,
22 pycompat,
22 pycompat,
23 registrar,
23 registrar,
24 revset as revsetmod,
24 revset as revsetmod,
25 revsetlang,
25 revsetlang,
26 templatefilters,
26 templatefilters,
27 templatekw,
27 templatekw,
28 util,
28 util,
29 )
29 )
30
30
31 # template parsing
31 # template parsing
32
32
33 elements = {
33 elements = {
34 # token-type: binding-strength, primary, prefix, infix, suffix
34 # token-type: binding-strength, primary, prefix, infix, suffix
35 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
35 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
36 "%": (16, None, None, ("%", 16), None),
36 "%": (16, None, None, ("%", 16), None),
37 "|": (15, None, None, ("|", 15), None),
37 "|": (15, None, None, ("|", 15), None),
38 "*": (5, None, None, ("*", 5), None),
38 "*": (5, None, None, ("*", 5), None),
39 "/": (5, None, None, ("/", 5), None),
39 "/": (5, None, None, ("/", 5), None),
40 "+": (4, None, None, ("+", 4), None),
40 "+": (4, None, None, ("+", 4), None),
41 "-": (4, None, ("negate", 19), ("-", 4), None),
41 "-": (4, None, ("negate", 19), ("-", 4), None),
42 "=": (3, None, None, ("keyvalue", 3), None),
42 "=": (3, None, None, ("keyvalue", 3), None),
43 ",": (2, None, None, ("list", 2), None),
43 ",": (2, None, None, ("list", 2), None),
44 ")": (0, None, None, None, None),
44 ")": (0, None, None, None, None),
45 "integer": (0, "integer", None, None, None),
45 "integer": (0, "integer", None, None, None),
46 "symbol": (0, "symbol", None, None, None),
46 "symbol": (0, "symbol", None, None, None),
47 "string": (0, "string", None, None, None),
47 "string": (0, "string", None, None, None),
48 "template": (0, "template", None, None, None),
48 "template": (0, "template", None, None, None),
49 "end": (0, None, None, None, None),
49 "end": (0, None, None, None, None),
50 }
50 }
51
51
52 def tokenize(program, start, end, term=None):
52 def tokenize(program, start, end, term=None):
53 """Parse a template expression into a stream of tokens, which must end
53 """Parse a template expression into a stream of tokens, which must end
54 with term if specified"""
54 with term if specified"""
55 pos = start
55 pos = start
56 while pos < end:
56 while pos < end:
57 c = program[pos]
57 c = program[pos]
58 if c.isspace(): # skip inter-token whitespace
58 if c.isspace(): # skip inter-token whitespace
59 pass
59 pass
60 elif c in "(=,)%|+-*/": # handle simple operators
60 elif c in "(=,)%|+-*/": # handle simple operators
61 yield (c, None, pos)
61 yield (c, None, pos)
62 elif c in '"\'': # handle quoted templates
62 elif c in '"\'': # handle quoted templates
63 s = pos + 1
63 s = pos + 1
64 data, pos = _parsetemplate(program, s, end, c)
64 data, pos = _parsetemplate(program, s, end, c)
65 yield ('template', data, s)
65 yield ('template', data, s)
66 pos -= 1
66 pos -= 1
67 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
67 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
68 # handle quoted strings
68 # handle quoted strings
69 c = program[pos + 1]
69 c = program[pos + 1]
70 s = pos = pos + 2
70 s = pos = pos + 2
71 while pos < end: # find closing quote
71 while pos < end: # find closing quote
72 d = program[pos]
72 d = program[pos]
73 if d == '\\': # skip over escaped characters
73 if d == '\\': # skip over escaped characters
74 pos += 2
74 pos += 2
75 continue
75 continue
76 if d == c:
76 if d == c:
77 yield ('string', program[s:pos], s)
77 yield ('string', program[s:pos], s)
78 break
78 break
79 pos += 1
79 pos += 1
80 else:
80 else:
81 raise error.ParseError(_("unterminated string"), s)
81 raise error.ParseError(_("unterminated string"), s)
82 elif c.isdigit():
82 elif c.isdigit():
83 s = pos
83 s = pos
84 while pos < end:
84 while pos < end:
85 d = program[pos]
85 d = program[pos]
86 if not d.isdigit():
86 if not d.isdigit():
87 break
87 break
88 pos += 1
88 pos += 1
89 yield ('integer', program[s:pos], s)
89 yield ('integer', program[s:pos], s)
90 pos -= 1
90 pos -= 1
91 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
91 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
92 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
92 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
93 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
93 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
94 # where some of nested templates were preprocessed as strings and
94 # where some of nested templates were preprocessed as strings and
95 # then compiled. therefore, \"...\" was allowed. (issue4733)
95 # then compiled. therefore, \"...\" was allowed. (issue4733)
96 #
96 #
97 # processing flow of _evalifliteral() at 5ab28a2e9962:
97 # processing flow of _evalifliteral() at 5ab28a2e9962:
98 # outer template string -> stringify() -> compiletemplate()
98 # outer template string -> stringify() -> compiletemplate()
99 # ------------------------ ------------ ------------------
99 # ------------------------ ------------ ------------------
100 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
100 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
101 # ~~~~~~~~
101 # ~~~~~~~~
102 # escaped quoted string
102 # escaped quoted string
103 if c == 'r':
103 if c == 'r':
104 pos += 1
104 pos += 1
105 token = 'string'
105 token = 'string'
106 else:
106 else:
107 token = 'template'
107 token = 'template'
108 quote = program[pos:pos + 2]
108 quote = program[pos:pos + 2]
109 s = pos = pos + 2
109 s = pos = pos + 2
110 while pos < end: # find closing escaped quote
110 while pos < end: # find closing escaped quote
111 if program.startswith('\\\\\\', pos, end):
111 if program.startswith('\\\\\\', pos, end):
112 pos += 4 # skip over double escaped characters
112 pos += 4 # skip over double escaped characters
113 continue
113 continue
114 if program.startswith(quote, pos, end):
114 if program.startswith(quote, pos, end):
115 # interpret as if it were a part of an outer string
115 # interpret as if it were a part of an outer string
116 data = parser.unescapestr(program[s:pos])
116 data = parser.unescapestr(program[s:pos])
117 if token == 'template':
117 if token == 'template':
118 data = _parsetemplate(data, 0, len(data))[0]
118 data = _parsetemplate(data, 0, len(data))[0]
119 yield (token, data, s)
119 yield (token, data, s)
120 pos += 1
120 pos += 1
121 break
121 break
122 pos += 1
122 pos += 1
123 else:
123 else:
124 raise error.ParseError(_("unterminated string"), s)
124 raise error.ParseError(_("unterminated string"), s)
125 elif c.isalnum() or c in '_':
125 elif c.isalnum() or c in '_':
126 s = pos
126 s = pos
127 pos += 1
127 pos += 1
128 while pos < end: # find end of symbol
128 while pos < end: # find end of symbol
129 d = program[pos]
129 d = program[pos]
130 if not (d.isalnum() or d == "_"):
130 if not (d.isalnum() or d == "_"):
131 break
131 break
132 pos += 1
132 pos += 1
133 sym = program[s:pos]
133 sym = program[s:pos]
134 yield ('symbol', sym, s)
134 yield ('symbol', sym, s)
135 pos -= 1
135 pos -= 1
136 elif c == term:
136 elif c == term:
137 yield ('end', None, pos + 1)
137 yield ('end', None, pos + 1)
138 return
138 return
139 else:
139 else:
140 raise error.ParseError(_("syntax error"), pos)
140 raise error.ParseError(_("syntax error"), pos)
141 pos += 1
141 pos += 1
142 if term:
142 if term:
143 raise error.ParseError(_("unterminated template expansion"), start)
143 raise error.ParseError(_("unterminated template expansion"), start)
144 yield ('end', None, pos)
144 yield ('end', None, pos)
145
145
146 def _parsetemplate(tmpl, start, stop, quote=''):
146 def _parsetemplate(tmpl, start, stop, quote=''):
147 r"""
147 r"""
148 >>> _parsetemplate('foo{bar}"baz', 0, 12)
148 >>> _parsetemplate('foo{bar}"baz', 0, 12)
149 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
149 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
150 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
150 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
151 ([('string', 'foo'), ('symbol', 'bar')], 9)
151 ([('string', 'foo'), ('symbol', 'bar')], 9)
152 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
152 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
153 ([('string', 'foo')], 4)
153 ([('string', 'foo')], 4)
154 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
154 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
155 ([('string', 'foo"'), ('string', 'bar')], 9)
155 ([('string', 'foo"'), ('string', 'bar')], 9)
156 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
156 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
157 ([('string', 'foo\\')], 6)
157 ([('string', 'foo\\')], 6)
158 """
158 """
159 parsed = []
159 parsed = []
160 sepchars = '{' + quote
160 sepchars = '{' + quote
161 pos = start
161 pos = start
162 p = parser.parser(elements)
162 p = parser.parser(elements)
163 while pos < stop:
163 while pos < stop:
164 n = min((tmpl.find(c, pos, stop) for c in sepchars),
164 n = min((tmpl.find(c, pos, stop) for c in sepchars),
165 key=lambda n: (n < 0, n))
165 key=lambda n: (n < 0, n))
166 if n < 0:
166 if n < 0:
167 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
167 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
168 pos = stop
168 pos = stop
169 break
169 break
170 c = tmpl[n]
170 c = tmpl[n]
171 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
171 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
172 if bs % 2 == 1:
172 if bs % 2 == 1:
173 # escaped (e.g. '\{', '\\\{', but not '\\{')
173 # escaped (e.g. '\{', '\\\{', but not '\\{')
174 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
174 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
175 pos = n + 1
175 pos = n + 1
176 continue
176 continue
177 if n > pos:
177 if n > pos:
178 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
178 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
179 if c == quote:
179 if c == quote:
180 return parsed, n + 1
180 return parsed, n + 1
181
181
182 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
182 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
183 parsed.append(parseres)
183 parsed.append(parseres)
184
184
185 if quote:
185 if quote:
186 raise error.ParseError(_("unterminated string"), start)
186 raise error.ParseError(_("unterminated string"), start)
187 return parsed, pos
187 return parsed, pos
188
188
189 def _unnesttemplatelist(tree):
189 def _unnesttemplatelist(tree):
190 """Expand list of templates to node tuple
190 """Expand list of templates to node tuple
191
191
192 >>> def f(tree):
192 >>> def f(tree):
193 ... print prettyformat(_unnesttemplatelist(tree))
193 ... print prettyformat(_unnesttemplatelist(tree))
194 >>> f(('template', []))
194 >>> f(('template', []))
195 ('string', '')
195 ('string', '')
196 >>> f(('template', [('string', 'foo')]))
196 >>> f(('template', [('string', 'foo')]))
197 ('string', 'foo')
197 ('string', 'foo')
198 >>> f(('template', [('string', 'foo'), ('symbol', 'rev')]))
198 >>> f(('template', [('string', 'foo'), ('symbol', 'rev')]))
199 (template
199 (template
200 ('string', 'foo')
200 ('string', 'foo')
201 ('symbol', 'rev'))
201 ('symbol', 'rev'))
202 >>> f(('template', [('symbol', 'rev')])) # template(rev) -> str
202 >>> f(('template', [('symbol', 'rev')])) # template(rev) -> str
203 (template
203 (template
204 ('symbol', 'rev'))
204 ('symbol', 'rev'))
205 >>> f(('template', [('template', [('string', 'foo')])]))
205 >>> f(('template', [('template', [('string', 'foo')])]))
206 ('string', 'foo')
206 ('string', 'foo')
207 """
207 """
208 if not isinstance(tree, tuple):
208 if not isinstance(tree, tuple):
209 return tree
209 return tree
210 op = tree[0]
210 op = tree[0]
211 if op != 'template':
211 if op != 'template':
212 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
212 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
213
213
214 assert len(tree) == 2
214 assert len(tree) == 2
215 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
215 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
216 if not xs:
216 if not xs:
217 return ('string', '') # empty template ""
217 return ('string', '') # empty template ""
218 elif len(xs) == 1 and xs[0][0] == 'string':
218 elif len(xs) == 1 and xs[0][0] == 'string':
219 return xs[0] # fast path for string with no template fragment "x"
219 return xs[0] # fast path for string with no template fragment "x"
220 else:
220 else:
221 return (op,) + xs
221 return (op,) + xs
222
222
223 def parse(tmpl):
223 def parse(tmpl):
224 """Parse template string into tree"""
224 """Parse template string into tree"""
225 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
225 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
226 assert pos == len(tmpl), 'unquoted template should be consumed'
226 assert pos == len(tmpl), 'unquoted template should be consumed'
227 return _unnesttemplatelist(('template', parsed))
227 return _unnesttemplatelist(('template', parsed))
228
228
229 def _parseexpr(expr):
229 def _parseexpr(expr):
230 """Parse a template expression into tree
230 """Parse a template expression into tree
231
231
232 >>> _parseexpr('"foo"')
232 >>> _parseexpr('"foo"')
233 ('string', 'foo')
233 ('string', 'foo')
234 >>> _parseexpr('foo(bar)')
234 >>> _parseexpr('foo(bar)')
235 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
235 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
236 >>> _parseexpr('foo(')
236 >>> _parseexpr('foo(')
237 Traceback (most recent call last):
237 Traceback (most recent call last):
238 ...
238 ...
239 ParseError: ('not a prefix: end', 4)
239 ParseError: ('not a prefix: end', 4)
240 >>> _parseexpr('"foo" "bar"')
240 >>> _parseexpr('"foo" "bar"')
241 Traceback (most recent call last):
241 Traceback (most recent call last):
242 ...
242 ...
243 ParseError: ('invalid token', 7)
243 ParseError: ('invalid token', 7)
244 """
244 """
245 p = parser.parser(elements)
245 p = parser.parser(elements)
246 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
246 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
247 if pos != len(expr):
247 if pos != len(expr):
248 raise error.ParseError(_('invalid token'), pos)
248 raise error.ParseError(_('invalid token'), pos)
249 return _unnesttemplatelist(tree)
249 return _unnesttemplatelist(tree)
250
250
251 def prettyformat(tree):
251 def prettyformat(tree):
252 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
252 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
253
253
254 def compileexp(exp, context, curmethods):
254 def compileexp(exp, context, curmethods):
255 """Compile parsed template tree to (func, data) pair"""
255 """Compile parsed template tree to (func, data) pair"""
256 t = exp[0]
256 t = exp[0]
257 if t in curmethods:
257 if t in curmethods:
258 return curmethods[t](exp, context)
258 return curmethods[t](exp, context)
259 raise error.ParseError(_("unknown method '%s'") % t)
259 raise error.ParseError(_("unknown method '%s'") % t)
260
260
261 # template evaluation
261 # template evaluation
262
262
263 def getsymbol(exp):
263 def getsymbol(exp):
264 if exp[0] == 'symbol':
264 if exp[0] == 'symbol':
265 return exp[1]
265 return exp[1]
266 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
266 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
267
267
268 def getlist(x):
268 def getlist(x):
269 if not x:
269 if not x:
270 return []
270 return []
271 if x[0] == 'list':
271 if x[0] == 'list':
272 return getlist(x[1]) + [x[2]]
272 return getlist(x[1]) + [x[2]]
273 return [x]
273 return [x]
274
274
275 def gettemplate(exp, context):
275 def gettemplate(exp, context):
276 """Compile given template tree or load named template from map file;
276 """Compile given template tree or load named template from map file;
277 returns (func, data) pair"""
277 returns (func, data) pair"""
278 if exp[0] in ('template', 'string'):
278 if exp[0] in ('template', 'string'):
279 return compileexp(exp, context, methods)
279 return compileexp(exp, context, methods)
280 if exp[0] == 'symbol':
280 if exp[0] == 'symbol':
281 # unlike runsymbol(), here 'symbol' is always taken as template name
281 # unlike runsymbol(), here 'symbol' is always taken as template name
282 # even if it exists in mapping. this allows us to override mapping
282 # even if it exists in mapping. this allows us to override mapping
283 # by web templates, e.g. 'changelogtag' is redefined in map file.
283 # by web templates, e.g. 'changelogtag' is redefined in map file.
284 return context._load(exp[1])
284 return context._load(exp[1])
285 raise error.ParseError(_("expected template specifier"))
285 raise error.ParseError(_("expected template specifier"))
286
286
287 def evalfuncarg(context, mapping, arg):
287 def evalfuncarg(context, mapping, arg):
288 func, data = arg
288 func, data = arg
289 # func() may return string, generator of strings or arbitrary object such
289 # func() may return string, generator of strings or arbitrary object such
290 # as date tuple, but filter does not want generator.
290 # as date tuple, but filter does not want generator.
291 thing = func(context, mapping, data)
291 thing = func(context, mapping, data)
292 if isinstance(thing, types.GeneratorType):
292 if isinstance(thing, types.GeneratorType):
293 thing = stringify(thing)
293 thing = stringify(thing)
294 return thing
294 return thing
295
295
296 def evalboolean(context, mapping, arg):
296 def evalboolean(context, mapping, arg):
297 """Evaluate given argument as boolean, but also takes boolean literals"""
297 """Evaluate given argument as boolean, but also takes boolean literals"""
298 func, data = arg
298 func, data = arg
299 if func is runsymbol:
299 if func is runsymbol:
300 thing = func(context, mapping, data, default=None)
300 thing = func(context, mapping, data, default=None)
301 if thing is None:
301 if thing is None:
302 # not a template keyword, takes as a boolean literal
302 # not a template keyword, takes as a boolean literal
303 thing = util.parsebool(data)
303 thing = util.parsebool(data)
304 else:
304 else:
305 thing = func(context, mapping, data)
305 thing = func(context, mapping, data)
306 if isinstance(thing, bool):
306 if isinstance(thing, bool):
307 return thing
307 return thing
308 # other objects are evaluated as strings, which means 0 is True, but
308 # other objects are evaluated as strings, which means 0 is True, but
309 # empty dict/list should be False as they are expected to be ''
309 # empty dict/list should be False as they are expected to be ''
310 return bool(stringify(thing))
310 return bool(stringify(thing))
311
311
312 def evalinteger(context, mapping, arg, err):
312 def evalinteger(context, mapping, arg, err):
313 v = evalfuncarg(context, mapping, arg)
313 v = evalfuncarg(context, mapping, arg)
314 try:
314 try:
315 return int(v)
315 return int(v)
316 except (TypeError, ValueError):
316 except (TypeError, ValueError):
317 raise error.ParseError(err)
317 raise error.ParseError(err)
318
318
319 def evalstring(context, mapping, arg):
319 def evalstring(context, mapping, arg):
320 func, data = arg
320 func, data = arg
321 return stringify(func(context, mapping, data))
321 return stringify(func(context, mapping, data))
322
322
323 def evalstringliteral(context, mapping, arg):
323 def evalstringliteral(context, mapping, arg):
324 """Evaluate given argument as string template, but returns symbol name
324 """Evaluate given argument as string template, but returns symbol name
325 if it is unknown"""
325 if it is unknown"""
326 func, data = arg
326 func, data = arg
327 if func is runsymbol:
327 if func is runsymbol:
328 thing = func(context, mapping, data, default=data)
328 thing = func(context, mapping, data, default=data)
329 else:
329 else:
330 thing = func(context, mapping, data)
330 thing = func(context, mapping, data)
331 return stringify(thing)
331 return stringify(thing)
332
332
333 def runinteger(context, mapping, data):
333 def runinteger(context, mapping, data):
334 return int(data)
334 return int(data)
335
335
336 def runstring(context, mapping, data):
336 def runstring(context, mapping, data):
337 return data
337 return data
338
338
339 def _recursivesymbolblocker(key):
339 def _recursivesymbolblocker(key):
340 def showrecursion(**args):
340 def showrecursion(**args):
341 raise error.Abort(_("recursive reference '%s' in template") % key)
341 raise error.Abort(_("recursive reference '%s' in template") % key)
342 return showrecursion
342 return showrecursion
343
343
344 def _runrecursivesymbol(context, mapping, key):
344 def _runrecursivesymbol(context, mapping, key):
345 raise error.Abort(_("recursive reference '%s' in template") % key)
345 raise error.Abort(_("recursive reference '%s' in template") % key)
346
346
347 def runsymbol(context, mapping, key, default=''):
347 def runsymbol(context, mapping, key, default=''):
348 v = mapping.get(key)
348 v = mapping.get(key)
349 if v is None:
349 if v is None:
350 v = context._defaults.get(key)
350 v = context._defaults.get(key)
351 if v is None:
351 if v is None:
352 # put poison to cut recursion. we can't move this to parsing phase
352 # put poison to cut recursion. we can't move this to parsing phase
353 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
353 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
354 safemapping = mapping.copy()
354 safemapping = mapping.copy()
355 safemapping[key] = _recursivesymbolblocker(key)
355 safemapping[key] = _recursivesymbolblocker(key)
356 try:
356 try:
357 v = context.process(key, safemapping)
357 v = context.process(key, safemapping)
358 except TemplateNotFound:
358 except TemplateNotFound:
359 v = default
359 v = default
360 if callable(v):
360 if callable(v):
361 return v(**mapping)
361 return v(**mapping)
362 return v
362 return v
363
363
364 def buildtemplate(exp, context):
364 def buildtemplate(exp, context):
365 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
365 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
366 return (runtemplate, ctmpl)
366 return (runtemplate, ctmpl)
367
367
368 def runtemplate(context, mapping, template):
368 def runtemplate(context, mapping, template):
369 for func, data in template:
369 for func, data in template:
370 yield func(context, mapping, data)
370 yield func(context, mapping, data)
371
371
372 def buildfilter(exp, context):
372 def buildfilter(exp, context):
373 arg = compileexp(exp[1], context, methods)
374 n = getsymbol(exp[2])
373 n = getsymbol(exp[2])
375 if n in context._filters:
374 if n in context._filters:
376 filt = context._filters[n]
375 filt = context._filters[n]
376 arg = compileexp(exp[1], context, methods)
377 return (runfilter, (arg, filt))
377 return (runfilter, (arg, filt))
378 if n in funcs:
378 if n in funcs:
379 f = funcs[n]
379 f = funcs[n]
380 return (f, [arg])
380 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
381 return (f, args)
381 raise error.ParseError(_("unknown function '%s'") % n)
382 raise error.ParseError(_("unknown function '%s'") % n)
382
383
383 def runfilter(context, mapping, data):
384 def runfilter(context, mapping, data):
384 arg, filt = data
385 arg, filt = data
385 thing = evalfuncarg(context, mapping, arg)
386 thing = evalfuncarg(context, mapping, arg)
386 try:
387 try:
387 return filt(thing)
388 return filt(thing)
388 except (ValueError, AttributeError, TypeError):
389 except (ValueError, AttributeError, TypeError):
389 if isinstance(arg[1], tuple):
390 if isinstance(arg[1], tuple):
390 dt = arg[1][1]
391 dt = arg[1][1]
391 else:
392 else:
392 dt = arg[1]
393 dt = arg[1]
393 raise error.Abort(_("template filter '%s' is not compatible with "
394 raise error.Abort(_("template filter '%s' is not compatible with "
394 "keyword '%s'") % (filt.func_name, dt))
395 "keyword '%s'") % (filt.func_name, dt))
395
396
396 def buildmap(exp, context):
397 def buildmap(exp, context):
397 func, data = compileexp(exp[1], context, methods)
398 func, data = compileexp(exp[1], context, methods)
398 tfunc, tdata = gettemplate(exp[2], context)
399 tfunc, tdata = gettemplate(exp[2], context)
399 return (runmap, (func, data, tfunc, tdata))
400 return (runmap, (func, data, tfunc, tdata))
400
401
401 def runmap(context, mapping, data):
402 def runmap(context, mapping, data):
402 func, data, tfunc, tdata = data
403 func, data, tfunc, tdata = data
403 d = func(context, mapping, data)
404 d = func(context, mapping, data)
404 if util.safehasattr(d, 'itermaps'):
405 if util.safehasattr(d, 'itermaps'):
405 diter = d.itermaps()
406 diter = d.itermaps()
406 else:
407 else:
407 try:
408 try:
408 diter = iter(d)
409 diter = iter(d)
409 except TypeError:
410 except TypeError:
410 if func is runsymbol:
411 if func is runsymbol:
411 raise error.ParseError(_("keyword '%s' is not iterable") % data)
412 raise error.ParseError(_("keyword '%s' is not iterable") % data)
412 else:
413 else:
413 raise error.ParseError(_("%r is not iterable") % d)
414 raise error.ParseError(_("%r is not iterable") % d)
414
415
415 for i, v in enumerate(diter):
416 for i, v in enumerate(diter):
416 lm = mapping.copy()
417 lm = mapping.copy()
417 lm['index'] = i
418 lm['index'] = i
418 if isinstance(v, dict):
419 if isinstance(v, dict):
419 lm.update(v)
420 lm.update(v)
420 lm['originalnode'] = mapping.get('node')
421 lm['originalnode'] = mapping.get('node')
421 yield tfunc(context, lm, tdata)
422 yield tfunc(context, lm, tdata)
422 else:
423 else:
423 # v is not an iterable of dicts, this happen when 'key'
424 # v is not an iterable of dicts, this happen when 'key'
424 # has been fully expanded already and format is useless.
425 # has been fully expanded already and format is useless.
425 # If so, return the expanded value.
426 # If so, return the expanded value.
426 yield v
427 yield v
427
428
428 def buildnegate(exp, context):
429 def buildnegate(exp, context):
429 arg = compileexp(exp[1], context, exprmethods)
430 arg = compileexp(exp[1], context, exprmethods)
430 return (runnegate, arg)
431 return (runnegate, arg)
431
432
432 def runnegate(context, mapping, data):
433 def runnegate(context, mapping, data):
433 data = evalinteger(context, mapping, data,
434 data = evalinteger(context, mapping, data,
434 _('negation needs an integer argument'))
435 _('negation needs an integer argument'))
435 return -data
436 return -data
436
437
437 def buildarithmetic(exp, context, func):
438 def buildarithmetic(exp, context, func):
438 left = compileexp(exp[1], context, exprmethods)
439 left = compileexp(exp[1], context, exprmethods)
439 right = compileexp(exp[2], context, exprmethods)
440 right = compileexp(exp[2], context, exprmethods)
440 return (runarithmetic, (func, left, right))
441 return (runarithmetic, (func, left, right))
441
442
442 def runarithmetic(context, mapping, data):
443 def runarithmetic(context, mapping, data):
443 func, left, right = data
444 func, left, right = data
444 left = evalinteger(context, mapping, left,
445 left = evalinteger(context, mapping, left,
445 _('arithmetic only defined on integers'))
446 _('arithmetic only defined on integers'))
446 right = evalinteger(context, mapping, right,
447 right = evalinteger(context, mapping, right,
447 _('arithmetic only defined on integers'))
448 _('arithmetic only defined on integers'))
448 try:
449 try:
449 return func(left, right)
450 return func(left, right)
450 except ZeroDivisionError:
451 except ZeroDivisionError:
451 raise error.Abort(_('division by zero is not defined'))
452 raise error.Abort(_('division by zero is not defined'))
452
453
453 def buildfunc(exp, context):
454 def buildfunc(exp, context):
454 n = getsymbol(exp[1])
455 n = getsymbol(exp[1])
455 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
456 if n in funcs:
456 if n in funcs:
457 f = funcs[n]
457 f = funcs[n]
458 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
458 return (f, args)
459 return (f, args)
459 if n in context._filters:
460 if n in context._filters:
461 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
460 if len(args) != 1:
462 if len(args) != 1:
461 raise error.ParseError(_("filter %s expects one argument") % n)
463 raise error.ParseError(_("filter %s expects one argument") % n)
462 f = context._filters[n]
464 f = context._filters[n]
463 return (runfilter, (args[0], f))
465 return (runfilter, (args[0], f))
464 raise error.ParseError(_("unknown function '%s'") % n)
466 raise error.ParseError(_("unknown function '%s'") % n)
465
467
468 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
469 """Compile parsed tree of function arguments into list or dict of
470 (func, data) pairs"""
471 def compiledict(xs):
472 return dict((k, compileexp(x, context, curmethods))
473 for k, x in xs.iteritems())
474 def compilelist(xs):
475 return [compileexp(x, context, curmethods) for x in xs]
476
477 if not argspec:
478 # filter or function with no argspec: return list of positional args
479 return compilelist(getlist(exp))
480
481 # function with argspec: return dict of named args
482 _poskeys, varkey, _keys = argspec = parser.splitargspec(argspec)
483 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
484 keyvaluenode='keyvalue', keynode='symbol')
485 compargs = {}
486 if varkey:
487 compargs[varkey] = compilelist(treeargs.pop(varkey))
488 compargs.update(compiledict(treeargs))
489 return compargs
490
466 def buildkeyvaluepair(exp, content):
491 def buildkeyvaluepair(exp, content):
467 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"))
468
493
469 # dict of template built-in functions
494 # dict of template built-in functions
470 funcs = {}
495 funcs = {}
471
496
472 templatefunc = registrar.templatefunc(funcs)
497 templatefunc = registrar.templatefunc(funcs)
473
498
474 @templatefunc('date(date[, fmt])')
499 @templatefunc('date(date[, fmt])')
475 def date(context, mapping, args):
500 def date(context, mapping, args):
476 """Format a date. See :hg:`help dates` for formatting
501 """Format a date. See :hg:`help dates` for formatting
477 strings. The default is a Unix date format, including the timezone:
502 strings. The default is a Unix date format, including the timezone:
478 "Mon Sep 04 15:13:13 2006 0700"."""
503 "Mon Sep 04 15:13:13 2006 0700"."""
479 if not (1 <= len(args) <= 2):
504 if not (1 <= len(args) <= 2):
480 # i18n: "date" is a keyword
505 # i18n: "date" is a keyword
481 raise error.ParseError(_("date expects one or two arguments"))
506 raise error.ParseError(_("date expects one or two arguments"))
482
507
483 date = evalfuncarg(context, mapping, args[0])
508 date = evalfuncarg(context, mapping, args[0])
484 fmt = None
509 fmt = None
485 if len(args) == 2:
510 if len(args) == 2:
486 fmt = evalstring(context, mapping, args[1])
511 fmt = evalstring(context, mapping, args[1])
487 try:
512 try:
488 if fmt is None:
513 if fmt is None:
489 return util.datestr(date)
514 return util.datestr(date)
490 else:
515 else:
491 return util.datestr(date, fmt)
516 return util.datestr(date, fmt)
492 except (TypeError, ValueError):
517 except (TypeError, ValueError):
493 # i18n: "date" is a keyword
518 # i18n: "date" is a keyword
494 raise error.ParseError(_("date expects a date information"))
519 raise error.ParseError(_("date expects a date information"))
495
520
496 @templatefunc('diff([includepattern [, excludepattern]])')
521 @templatefunc('diff([includepattern [, excludepattern]])')
497 def diff(context, mapping, args):
522 def diff(context, mapping, args):
498 """Show a diff, optionally
523 """Show a diff, optionally
499 specifying files to include or exclude."""
524 specifying files to include or exclude."""
500 if len(args) > 2:
525 if len(args) > 2:
501 # i18n: "diff" is a keyword
526 # i18n: "diff" is a keyword
502 raise error.ParseError(_("diff expects zero, one, or two arguments"))
527 raise error.ParseError(_("diff expects zero, one, or two arguments"))
503
528
504 def getpatterns(i):
529 def getpatterns(i):
505 if i < len(args):
530 if i < len(args):
506 s = evalstring(context, mapping, args[i]).strip()
531 s = evalstring(context, mapping, args[i]).strip()
507 if s:
532 if s:
508 return [s]
533 return [s]
509 return []
534 return []
510
535
511 ctx = mapping['ctx']
536 ctx = mapping['ctx']
512 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
537 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
513
538
514 return ''.join(chunks)
539 return ''.join(chunks)
515
540
516 @templatefunc('files(pattern)')
541 @templatefunc('files(pattern)')
517 def files(context, mapping, args):
542 def files(context, mapping, args):
518 """All files of the current changeset matching the pattern. See
543 """All files of the current changeset matching the pattern. See
519 :hg:`help patterns`."""
544 :hg:`help patterns`."""
520 if not len(args) == 1:
545 if not len(args) == 1:
521 # i18n: "files" is a keyword
546 # i18n: "files" is a keyword
522 raise error.ParseError(_("files expects one argument"))
547 raise error.ParseError(_("files expects one argument"))
523
548
524 raw = evalstring(context, mapping, args[0])
549 raw = evalstring(context, mapping, args[0])
525 ctx = mapping['ctx']
550 ctx = mapping['ctx']
526 m = ctx.match([raw])
551 m = ctx.match([raw])
527 files = list(ctx.matches(m))
552 files = list(ctx.matches(m))
528 return templatekw.showlist("file", files, **mapping)
553 return templatekw.showlist("file", files, **mapping)
529
554
530 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
555 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
531 def fill(context, mapping, args):
556 def fill(context, mapping, args):
532 """Fill many
557 """Fill many
533 paragraphs with optional indentation. See the "fill" filter."""
558 paragraphs with optional indentation. See the "fill" filter."""
534 if not (1 <= len(args) <= 4):
559 if not (1 <= len(args) <= 4):
535 # i18n: "fill" is a keyword
560 # i18n: "fill" is a keyword
536 raise error.ParseError(_("fill expects one to four arguments"))
561 raise error.ParseError(_("fill expects one to four arguments"))
537
562
538 text = evalstring(context, mapping, args[0])
563 text = evalstring(context, mapping, args[0])
539 width = 76
564 width = 76
540 initindent = ''
565 initindent = ''
541 hangindent = ''
566 hangindent = ''
542 if 2 <= len(args) <= 4:
567 if 2 <= len(args) <= 4:
543 width = evalinteger(context, mapping, args[1],
568 width = evalinteger(context, mapping, args[1],
544 # i18n: "fill" is a keyword
569 # i18n: "fill" is a keyword
545 _("fill expects an integer width"))
570 _("fill expects an integer width"))
546 try:
571 try:
547 initindent = evalstring(context, mapping, args[2])
572 initindent = evalstring(context, mapping, args[2])
548 hangindent = evalstring(context, mapping, args[3])
573 hangindent = evalstring(context, mapping, args[3])
549 except IndexError:
574 except IndexError:
550 pass
575 pass
551
576
552 return templatefilters.fill(text, width, initindent, hangindent)
577 return templatefilters.fill(text, width, initindent, hangindent)
553
578
554 @templatefunc('formatnode(node)')
579 @templatefunc('formatnode(node)')
555 def formatnode(context, mapping, args):
580 def formatnode(context, mapping, args):
556 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
581 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
557 if len(args) != 1:
582 if len(args) != 1:
558 # i18n: "formatnode" is a keyword
583 # i18n: "formatnode" is a keyword
559 raise error.ParseError(_("formatnode expects one argument"))
584 raise error.ParseError(_("formatnode expects one argument"))
560
585
561 ui = mapping['ui']
586 ui = mapping['ui']
562 node = evalstring(context, mapping, args[0])
587 node = evalstring(context, mapping, args[0])
563 if ui.debugflag:
588 if ui.debugflag:
564 return node
589 return node
565 return templatefilters.short(node)
590 return templatefilters.short(node)
566
591
567 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])')
592 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])')
568 def pad(context, mapping, args):
593 def pad(context, mapping, args):
569 """Pad text with a
594 """Pad text with a
570 fill character."""
595 fill character."""
571 if not (2 <= len(args) <= 4):
596 if not (2 <= len(args) <= 4):
572 # i18n: "pad" is a keyword
597 # i18n: "pad" is a keyword
573 raise error.ParseError(_("pad() expects two to four arguments"))
598 raise error.ParseError(_("pad() expects two to four arguments"))
574
599
575 width = evalinteger(context, mapping, args[1],
600 width = evalinteger(context, mapping, args[1],
576 # i18n: "pad" is a keyword
601 # i18n: "pad" is a keyword
577 _("pad() expects an integer width"))
602 _("pad() expects an integer width"))
578
603
579 text = evalstring(context, mapping, args[0])
604 text = evalstring(context, mapping, args[0])
580
605
581 left = False
606 left = False
582 fillchar = ' '
607 fillchar = ' '
583 if len(args) > 2:
608 if len(args) > 2:
584 fillchar = evalstring(context, mapping, args[2])
609 fillchar = evalstring(context, mapping, args[2])
585 if len(color.stripeffects(fillchar)) != 1:
610 if len(color.stripeffects(fillchar)) != 1:
586 # i18n: "pad" is a keyword
611 # i18n: "pad" is a keyword
587 raise error.ParseError(_("pad() expects a single fill character"))
612 raise error.ParseError(_("pad() expects a single fill character"))
588 if len(args) > 3:
613 if len(args) > 3:
589 left = evalboolean(context, mapping, args[3])
614 left = evalboolean(context, mapping, args[3])
590
615
591 fillwidth = width - encoding.colwidth(color.stripeffects(text))
616 fillwidth = width - encoding.colwidth(color.stripeffects(text))
592 if fillwidth <= 0:
617 if fillwidth <= 0:
593 return text
618 return text
594 if left:
619 if left:
595 return fillchar * fillwidth + text
620 return fillchar * fillwidth + text
596 else:
621 else:
597 return text + fillchar * fillwidth
622 return text + fillchar * fillwidth
598
623
599 @templatefunc('indent(text, indentchars[, firstline])')
624 @templatefunc('indent(text, indentchars[, firstline])')
600 def indent(context, mapping, args):
625 def indent(context, mapping, args):
601 """Indents all non-empty lines
626 """Indents all non-empty lines
602 with the characters given in the indentchars string. An optional
627 with the characters given in the indentchars string. An optional
603 third parameter will override the indent for the first line only
628 third parameter will override the indent for the first line only
604 if present."""
629 if present."""
605 if not (2 <= len(args) <= 3):
630 if not (2 <= len(args) <= 3):
606 # i18n: "indent" is a keyword
631 # i18n: "indent" is a keyword
607 raise error.ParseError(_("indent() expects two or three arguments"))
632 raise error.ParseError(_("indent() expects two or three arguments"))
608
633
609 text = evalstring(context, mapping, args[0])
634 text = evalstring(context, mapping, args[0])
610 indent = evalstring(context, mapping, args[1])
635 indent = evalstring(context, mapping, args[1])
611
636
612 if len(args) == 3:
637 if len(args) == 3:
613 firstline = evalstring(context, mapping, args[2])
638 firstline = evalstring(context, mapping, args[2])
614 else:
639 else:
615 firstline = indent
640 firstline = indent
616
641
617 # the indent function doesn't indent the first line, so we do it here
642 # the indent function doesn't indent the first line, so we do it here
618 return templatefilters.indent(firstline + text, indent)
643 return templatefilters.indent(firstline + text, indent)
619
644
620 @templatefunc('get(dict, key)')
645 @templatefunc('get(dict, key)')
621 def get(context, mapping, args):
646 def get(context, mapping, args):
622 """Get an attribute/key from an object. Some keywords
647 """Get an attribute/key from an object. Some keywords
623 are complex types. This function allows you to obtain the value of an
648 are complex types. This function allows you to obtain the value of an
624 attribute on these types."""
649 attribute on these types."""
625 if len(args) != 2:
650 if len(args) != 2:
626 # i18n: "get" is a keyword
651 # i18n: "get" is a keyword
627 raise error.ParseError(_("get() expects two arguments"))
652 raise error.ParseError(_("get() expects two arguments"))
628
653
629 dictarg = evalfuncarg(context, mapping, args[0])
654 dictarg = evalfuncarg(context, mapping, args[0])
630 if not util.safehasattr(dictarg, 'get'):
655 if not util.safehasattr(dictarg, 'get'):
631 # i18n: "get" is a keyword
656 # i18n: "get" is a keyword
632 raise error.ParseError(_("get() expects a dict as first argument"))
657 raise error.ParseError(_("get() expects a dict as first argument"))
633
658
634 key = evalfuncarg(context, mapping, args[1])
659 key = evalfuncarg(context, mapping, args[1])
635 return dictarg.get(key)
660 return dictarg.get(key)
636
661
637 @templatefunc('if(expr, then[, else])')
662 @templatefunc('if(expr, then[, else])')
638 def if_(context, mapping, args):
663 def if_(context, mapping, args):
639 """Conditionally execute based on the result of
664 """Conditionally execute based on the result of
640 an expression."""
665 an expression."""
641 if not (2 <= len(args) <= 3):
666 if not (2 <= len(args) <= 3):
642 # i18n: "if" is a keyword
667 # i18n: "if" is a keyword
643 raise error.ParseError(_("if expects two or three arguments"))
668 raise error.ParseError(_("if expects two or three arguments"))
644
669
645 test = evalboolean(context, mapping, args[0])
670 test = evalboolean(context, mapping, args[0])
646 if test:
671 if test:
647 yield args[1][0](context, mapping, args[1][1])
672 yield args[1][0](context, mapping, args[1][1])
648 elif len(args) == 3:
673 elif len(args) == 3:
649 yield args[2][0](context, mapping, args[2][1])
674 yield args[2][0](context, mapping, args[2][1])
650
675
651 @templatefunc('ifcontains(needle, haystack, then[, else])')
676 @templatefunc('ifcontains(needle, haystack, then[, else])')
652 def ifcontains(context, mapping, args):
677 def ifcontains(context, mapping, args):
653 """Conditionally execute based
678 """Conditionally execute based
654 on whether the item "needle" is in "haystack"."""
679 on whether the item "needle" is in "haystack"."""
655 if not (3 <= len(args) <= 4):
680 if not (3 <= len(args) <= 4):
656 # i18n: "ifcontains" is a keyword
681 # i18n: "ifcontains" is a keyword
657 raise error.ParseError(_("ifcontains expects three or four arguments"))
682 raise error.ParseError(_("ifcontains expects three or four arguments"))
658
683
659 needle = evalstring(context, mapping, args[0])
684 needle = evalstring(context, mapping, args[0])
660 haystack = evalfuncarg(context, mapping, args[1])
685 haystack = evalfuncarg(context, mapping, args[1])
661
686
662 if needle in haystack:
687 if needle in haystack:
663 yield args[2][0](context, mapping, args[2][1])
688 yield args[2][0](context, mapping, args[2][1])
664 elif len(args) == 4:
689 elif len(args) == 4:
665 yield args[3][0](context, mapping, args[3][1])
690 yield args[3][0](context, mapping, args[3][1])
666
691
667 @templatefunc('ifeq(expr1, expr2, then[, else])')
692 @templatefunc('ifeq(expr1, expr2, then[, else])')
668 def ifeq(context, mapping, args):
693 def ifeq(context, mapping, args):
669 """Conditionally execute based on
694 """Conditionally execute based on
670 whether 2 items are equivalent."""
695 whether 2 items are equivalent."""
671 if not (3 <= len(args) <= 4):
696 if not (3 <= len(args) <= 4):
672 # i18n: "ifeq" is a keyword
697 # i18n: "ifeq" is a keyword
673 raise error.ParseError(_("ifeq expects three or four arguments"))
698 raise error.ParseError(_("ifeq expects three or four arguments"))
674
699
675 test = evalstring(context, mapping, args[0])
700 test = evalstring(context, mapping, args[0])
676 match = evalstring(context, mapping, args[1])
701 match = evalstring(context, mapping, args[1])
677 if test == match:
702 if test == match:
678 yield args[2][0](context, mapping, args[2][1])
703 yield args[2][0](context, mapping, args[2][1])
679 elif len(args) == 4:
704 elif len(args) == 4:
680 yield args[3][0](context, mapping, args[3][1])
705 yield args[3][0](context, mapping, args[3][1])
681
706
682 @templatefunc('join(list, sep)')
707 @templatefunc('join(list, sep)')
683 def join(context, mapping, args):
708 def join(context, mapping, args):
684 """Join items in a list with a delimiter."""
709 """Join items in a list with a delimiter."""
685 if not (1 <= len(args) <= 2):
710 if not (1 <= len(args) <= 2):
686 # i18n: "join" is a keyword
711 # i18n: "join" is a keyword
687 raise error.ParseError(_("join expects one or two arguments"))
712 raise error.ParseError(_("join expects one or two arguments"))
688
713
689 joinset = args[0][0](context, mapping, args[0][1])
714 joinset = args[0][0](context, mapping, args[0][1])
690 if util.safehasattr(joinset, 'itermaps'):
715 if util.safehasattr(joinset, 'itermaps'):
691 jf = joinset.joinfmt
716 jf = joinset.joinfmt
692 joinset = [jf(x) for x in joinset.itermaps()]
717 joinset = [jf(x) for x in joinset.itermaps()]
693
718
694 joiner = " "
719 joiner = " "
695 if len(args) > 1:
720 if len(args) > 1:
696 joiner = evalstring(context, mapping, args[1])
721 joiner = evalstring(context, mapping, args[1])
697
722
698 first = True
723 first = True
699 for x in joinset:
724 for x in joinset:
700 if first:
725 if first:
701 first = False
726 first = False
702 else:
727 else:
703 yield joiner
728 yield joiner
704 yield x
729 yield x
705
730
706 @templatefunc('label(label, expr)')
731 @templatefunc('label(label, expr)')
707 def label(context, mapping, args):
732 def label(context, mapping, args):
708 """Apply a label to generated content. Content with
733 """Apply a label to generated content. Content with
709 a label applied can result in additional post-processing, such as
734 a label applied can result in additional post-processing, such as
710 automatic colorization."""
735 automatic colorization."""
711 if len(args) != 2:
736 if len(args) != 2:
712 # i18n: "label" is a keyword
737 # i18n: "label" is a keyword
713 raise error.ParseError(_("label expects two arguments"))
738 raise error.ParseError(_("label expects two arguments"))
714
739
715 ui = mapping['ui']
740 ui = mapping['ui']
716 thing = evalstring(context, mapping, args[1])
741 thing = evalstring(context, mapping, args[1])
717 # preserve unknown symbol as literal so effects like 'red', 'bold',
742 # preserve unknown symbol as literal so effects like 'red', 'bold',
718 # etc. don't need to be quoted
743 # etc. don't need to be quoted
719 label = evalstringliteral(context, mapping, args[0])
744 label = evalstringliteral(context, mapping, args[0])
720
745
721 return ui.label(thing, label)
746 return ui.label(thing, label)
722
747
723 @templatefunc('latesttag([pattern])')
748 @templatefunc('latesttag([pattern])')
724 def latesttag(context, mapping, args):
749 def latesttag(context, mapping, args):
725 """The global tags matching the given pattern on the
750 """The global tags matching the given pattern on the
726 most recent globally tagged ancestor of this changeset.
751 most recent globally tagged ancestor of this changeset.
727 If no such tags exist, the "{tag}" template resolves to
752 If no such tags exist, the "{tag}" template resolves to
728 the string "null"."""
753 the string "null"."""
729 if len(args) > 1:
754 if len(args) > 1:
730 # i18n: "latesttag" is a keyword
755 # i18n: "latesttag" is a keyword
731 raise error.ParseError(_("latesttag expects at most one argument"))
756 raise error.ParseError(_("latesttag expects at most one argument"))
732
757
733 pattern = None
758 pattern = None
734 if len(args) == 1:
759 if len(args) == 1:
735 pattern = evalstring(context, mapping, args[0])
760 pattern = evalstring(context, mapping, args[0])
736
761
737 return templatekw.showlatesttags(pattern, **mapping)
762 return templatekw.showlatesttags(pattern, **mapping)
738
763
739 @templatefunc('localdate(date[, tz])')
764 @templatefunc('localdate(date[, tz])')
740 def localdate(context, mapping, args):
765 def localdate(context, mapping, args):
741 """Converts a date to the specified timezone.
766 """Converts a date to the specified timezone.
742 The default is local date."""
767 The default is local date."""
743 if not (1 <= len(args) <= 2):
768 if not (1 <= len(args) <= 2):
744 # i18n: "localdate" is a keyword
769 # i18n: "localdate" is a keyword
745 raise error.ParseError(_("localdate expects one or two arguments"))
770 raise error.ParseError(_("localdate expects one or two arguments"))
746
771
747 date = evalfuncarg(context, mapping, args[0])
772 date = evalfuncarg(context, mapping, args[0])
748 try:
773 try:
749 date = util.parsedate(date)
774 date = util.parsedate(date)
750 except AttributeError: # not str nor date tuple
775 except AttributeError: # not str nor date tuple
751 # i18n: "localdate" is a keyword
776 # i18n: "localdate" is a keyword
752 raise error.ParseError(_("localdate expects a date information"))
777 raise error.ParseError(_("localdate expects a date information"))
753 if len(args) >= 2:
778 if len(args) >= 2:
754 tzoffset = None
779 tzoffset = None
755 tz = evalfuncarg(context, mapping, args[1])
780 tz = evalfuncarg(context, mapping, args[1])
756 if isinstance(tz, str):
781 if isinstance(tz, str):
757 tzoffset, remainder = util.parsetimezone(tz)
782 tzoffset, remainder = util.parsetimezone(tz)
758 if remainder:
783 if remainder:
759 tzoffset = None
784 tzoffset = None
760 if tzoffset is None:
785 if tzoffset is None:
761 try:
786 try:
762 tzoffset = int(tz)
787 tzoffset = int(tz)
763 except (TypeError, ValueError):
788 except (TypeError, ValueError):
764 # i18n: "localdate" is a keyword
789 # i18n: "localdate" is a keyword
765 raise error.ParseError(_("localdate expects a timezone"))
790 raise error.ParseError(_("localdate expects a timezone"))
766 else:
791 else:
767 tzoffset = util.makedate()[1]
792 tzoffset = util.makedate()[1]
768 return (date[0], tzoffset)
793 return (date[0], tzoffset)
769
794
770 @templatefunc('mod(a, b)')
795 @templatefunc('mod(a, b)')
771 def mod(context, mapping, args):
796 def mod(context, mapping, args):
772 """Calculate a mod b such that a / b + a mod b == a"""
797 """Calculate a mod b such that a / b + a mod b == a"""
773 if not len(args) == 2:
798 if not len(args) == 2:
774 # i18n: "mod" is a keyword
799 # i18n: "mod" is a keyword
775 raise error.ParseError(_("mod expects two arguments"))
800 raise error.ParseError(_("mod expects two arguments"))
776
801
777 func = lambda a, b: a % b
802 func = lambda a, b: a % b
778 return runarithmetic(context, mapping, (func, args[0], args[1]))
803 return runarithmetic(context, mapping, (func, args[0], args[1]))
779
804
780 @templatefunc('relpath(path)')
805 @templatefunc('relpath(path)')
781 def relpath(context, mapping, args):
806 def relpath(context, mapping, args):
782 """Convert a repository-absolute path into a filesystem path relative to
807 """Convert a repository-absolute path into a filesystem path relative to
783 the current working directory."""
808 the current working directory."""
784 if len(args) != 1:
809 if len(args) != 1:
785 # i18n: "relpath" is a keyword
810 # i18n: "relpath" is a keyword
786 raise error.ParseError(_("relpath expects one argument"))
811 raise error.ParseError(_("relpath expects one argument"))
787
812
788 repo = mapping['ctx'].repo()
813 repo = mapping['ctx'].repo()
789 path = evalstring(context, mapping, args[0])
814 path = evalstring(context, mapping, args[0])
790 return repo.pathto(path)
815 return repo.pathto(path)
791
816
792 @templatefunc('revset(query[, formatargs...])')
817 @templatefunc('revset(query[, formatargs...])')
793 def revset(context, mapping, args):
818 def revset(context, mapping, args):
794 """Execute a revision set query. See
819 """Execute a revision set query. See
795 :hg:`help revset`."""
820 :hg:`help revset`."""
796 if not len(args) > 0:
821 if not len(args) > 0:
797 # i18n: "revset" is a keyword
822 # i18n: "revset" is a keyword
798 raise error.ParseError(_("revset expects one or more arguments"))
823 raise error.ParseError(_("revset expects one or more arguments"))
799
824
800 raw = evalstring(context, mapping, args[0])
825 raw = evalstring(context, mapping, args[0])
801 ctx = mapping['ctx']
826 ctx = mapping['ctx']
802 repo = ctx.repo()
827 repo = ctx.repo()
803
828
804 def query(expr):
829 def query(expr):
805 m = revsetmod.match(repo.ui, expr)
830 m = revsetmod.match(repo.ui, expr)
806 return m(repo)
831 return m(repo)
807
832
808 if len(args) > 1:
833 if len(args) > 1:
809 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
834 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
810 revs = query(revsetlang.formatspec(raw, *formatargs))
835 revs = query(revsetlang.formatspec(raw, *formatargs))
811 revs = list(revs)
836 revs = list(revs)
812 else:
837 else:
813 revsetcache = mapping['cache'].setdefault("revsetcache", {})
838 revsetcache = mapping['cache'].setdefault("revsetcache", {})
814 if raw in revsetcache:
839 if raw in revsetcache:
815 revs = revsetcache[raw]
840 revs = revsetcache[raw]
816 else:
841 else:
817 revs = query(raw)
842 revs = query(raw)
818 revs = list(revs)
843 revs = list(revs)
819 revsetcache[raw] = revs
844 revsetcache[raw] = revs
820
845
821 return templatekw.showrevslist("revision", revs, **mapping)
846 return templatekw.showrevslist("revision", revs, **mapping)
822
847
823 @templatefunc('rstdoc(text, style)')
848 @templatefunc('rstdoc(text, style)')
824 def rstdoc(context, mapping, args):
849 def rstdoc(context, mapping, args):
825 """Format reStructuredText."""
850 """Format reStructuredText."""
826 if len(args) != 2:
851 if len(args) != 2:
827 # i18n: "rstdoc" is a keyword
852 # i18n: "rstdoc" is a keyword
828 raise error.ParseError(_("rstdoc expects two arguments"))
853 raise error.ParseError(_("rstdoc expects two arguments"))
829
854
830 text = evalstring(context, mapping, args[0])
855 text = evalstring(context, mapping, args[0])
831 style = evalstring(context, mapping, args[1])
856 style = evalstring(context, mapping, args[1])
832
857
833 return minirst.format(text, style=style, keep=['verbose'])
858 return minirst.format(text, style=style, keep=['verbose'])
834
859
835 @templatefunc('separate(sep, args)')
860 @templatefunc('separate(sep, args)', argspec='sep *args')
836 def separate(context, mapping, args):
861 def separate(context, mapping, args):
837 """Add a separator between non-empty arguments."""
862 """Add a separator between non-empty arguments."""
838 if not args:
863 if 'sep' not in args:
839 # i18n: "separate" is a keyword
864 # i18n: "separate" is a keyword
840 raise error.ParseError(_("separate expects at least one argument"))
865 raise error.ParseError(_("separate expects at least one argument"))
841
866
842 sep = evalstring(context, mapping, args[0])
867 sep = evalstring(context, mapping, args['sep'])
843 first = True
868 first = True
844 for arg in args[1:]:
869 for arg in args['args']:
845 argstr = evalstring(context, mapping, arg)
870 argstr = evalstring(context, mapping, arg)
846 if not argstr:
871 if not argstr:
847 continue
872 continue
848 if first:
873 if first:
849 first = False
874 first = False
850 else:
875 else:
851 yield sep
876 yield sep
852 yield argstr
877 yield argstr
853
878
854 @templatefunc('shortest(node, minlength=4)')
879 @templatefunc('shortest(node, minlength=4)')
855 def shortest(context, mapping, args):
880 def shortest(context, mapping, args):
856 """Obtain the shortest representation of
881 """Obtain the shortest representation of
857 a node."""
882 a node."""
858 if not (1 <= len(args) <= 2):
883 if not (1 <= len(args) <= 2):
859 # i18n: "shortest" is a keyword
884 # i18n: "shortest" is a keyword
860 raise error.ParseError(_("shortest() expects one or two arguments"))
885 raise error.ParseError(_("shortest() expects one or two arguments"))
861
886
862 node = evalstring(context, mapping, args[0])
887 node = evalstring(context, mapping, args[0])
863
888
864 minlength = 4
889 minlength = 4
865 if len(args) > 1:
890 if len(args) > 1:
866 minlength = evalinteger(context, mapping, args[1],
891 minlength = evalinteger(context, mapping, args[1],
867 # i18n: "shortest" is a keyword
892 # i18n: "shortest" is a keyword
868 _("shortest() expects an integer minlength"))
893 _("shortest() expects an integer minlength"))
869
894
870 # _partialmatch() of filtered changelog could take O(len(repo)) time,
895 # _partialmatch() of filtered changelog could take O(len(repo)) time,
871 # which would be unacceptably slow. so we look for hash collision in
896 # which would be unacceptably slow. so we look for hash collision in
872 # unfiltered space, which means some hashes may be slightly longer.
897 # unfiltered space, which means some hashes may be slightly longer.
873 cl = mapping['ctx']._repo.unfiltered().changelog
898 cl = mapping['ctx']._repo.unfiltered().changelog
874 def isvalid(test):
899 def isvalid(test):
875 try:
900 try:
876 if cl._partialmatch(test) is None:
901 if cl._partialmatch(test) is None:
877 return False
902 return False
878
903
879 try:
904 try:
880 i = int(test)
905 i = int(test)
881 # if we are a pure int, then starting with zero will not be
906 # if we are a pure int, then starting with zero will not be
882 # confused as a rev; or, obviously, if the int is larger than
907 # confused as a rev; or, obviously, if the int is larger than
883 # the value of the tip rev
908 # the value of the tip rev
884 if test[0] == '0' or i > len(cl):
909 if test[0] == '0' or i > len(cl):
885 return True
910 return True
886 return False
911 return False
887 except ValueError:
912 except ValueError:
888 return True
913 return True
889 except error.RevlogError:
914 except error.RevlogError:
890 return False
915 return False
891
916
892 shortest = node
917 shortest = node
893 startlength = max(6, minlength)
918 startlength = max(6, minlength)
894 length = startlength
919 length = startlength
895 while True:
920 while True:
896 test = node[:length]
921 test = node[:length]
897 if isvalid(test):
922 if isvalid(test):
898 shortest = test
923 shortest = test
899 if length == minlength or length > startlength:
924 if length == minlength or length > startlength:
900 return shortest
925 return shortest
901 length -= 1
926 length -= 1
902 else:
927 else:
903 length += 1
928 length += 1
904 if len(shortest) <= length:
929 if len(shortest) <= length:
905 return shortest
930 return shortest
906
931
907 @templatefunc('strip(text[, chars])')
932 @templatefunc('strip(text[, chars])')
908 def strip(context, mapping, args):
933 def strip(context, mapping, args):
909 """Strip characters from a string. By default,
934 """Strip characters from a string. By default,
910 strips all leading and trailing whitespace."""
935 strips all leading and trailing whitespace."""
911 if not (1 <= len(args) <= 2):
936 if not (1 <= len(args) <= 2):
912 # i18n: "strip" is a keyword
937 # i18n: "strip" is a keyword
913 raise error.ParseError(_("strip expects one or two arguments"))
938 raise error.ParseError(_("strip expects one or two arguments"))
914
939
915 text = evalstring(context, mapping, args[0])
940 text = evalstring(context, mapping, args[0])
916 if len(args) == 2:
941 if len(args) == 2:
917 chars = evalstring(context, mapping, args[1])
942 chars = evalstring(context, mapping, args[1])
918 return text.strip(chars)
943 return text.strip(chars)
919 return text.strip()
944 return text.strip()
920
945
921 @templatefunc('sub(pattern, replacement, expression)')
946 @templatefunc('sub(pattern, replacement, expression)')
922 def sub(context, mapping, args):
947 def sub(context, mapping, args):
923 """Perform text substitution
948 """Perform text substitution
924 using regular expressions."""
949 using regular expressions."""
925 if len(args) != 3:
950 if len(args) != 3:
926 # i18n: "sub" is a keyword
951 # i18n: "sub" is a keyword
927 raise error.ParseError(_("sub expects three arguments"))
952 raise error.ParseError(_("sub expects three arguments"))
928
953
929 pat = evalstring(context, mapping, args[0])
954 pat = evalstring(context, mapping, args[0])
930 rpl = evalstring(context, mapping, args[1])
955 rpl = evalstring(context, mapping, args[1])
931 src = evalstring(context, mapping, args[2])
956 src = evalstring(context, mapping, args[2])
932 try:
957 try:
933 patre = re.compile(pat)
958 patre = re.compile(pat)
934 except re.error:
959 except re.error:
935 # i18n: "sub" is a keyword
960 # i18n: "sub" is a keyword
936 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
961 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
937 try:
962 try:
938 yield patre.sub(rpl, src)
963 yield patre.sub(rpl, src)
939 except re.error:
964 except re.error:
940 # i18n: "sub" is a keyword
965 # i18n: "sub" is a keyword
941 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
966 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
942
967
943 @templatefunc('startswith(pattern, text)')
968 @templatefunc('startswith(pattern, text)')
944 def startswith(context, mapping, args):
969 def startswith(context, mapping, args):
945 """Returns the value from the "text" argument
970 """Returns the value from the "text" argument
946 if it begins with the content from the "pattern" argument."""
971 if it begins with the content from the "pattern" argument."""
947 if len(args) != 2:
972 if len(args) != 2:
948 # i18n: "startswith" is a keyword
973 # i18n: "startswith" is a keyword
949 raise error.ParseError(_("startswith expects two arguments"))
974 raise error.ParseError(_("startswith expects two arguments"))
950
975
951 patn = evalstring(context, mapping, args[0])
976 patn = evalstring(context, mapping, args[0])
952 text = evalstring(context, mapping, args[1])
977 text = evalstring(context, mapping, args[1])
953 if text.startswith(patn):
978 if text.startswith(patn):
954 return text
979 return text
955 return ''
980 return ''
956
981
957 @templatefunc('word(number, text[, separator])')
982 @templatefunc('word(number, text[, separator])')
958 def word(context, mapping, args):
983 def word(context, mapping, args):
959 """Return the nth word from a string."""
984 """Return the nth word from a string."""
960 if not (2 <= len(args) <= 3):
985 if not (2 <= len(args) <= 3):
961 # i18n: "word" is a keyword
986 # i18n: "word" is a keyword
962 raise error.ParseError(_("word expects two or three arguments, got %d")
987 raise error.ParseError(_("word expects two or three arguments, got %d")
963 % len(args))
988 % len(args))
964
989
965 num = evalinteger(context, mapping, args[0],
990 num = evalinteger(context, mapping, args[0],
966 # i18n: "word" is a keyword
991 # i18n: "word" is a keyword
967 _("word expects an integer index"))
992 _("word expects an integer index"))
968 text = evalstring(context, mapping, args[1])
993 text = evalstring(context, mapping, args[1])
969 if len(args) == 3:
994 if len(args) == 3:
970 splitter = evalstring(context, mapping, args[2])
995 splitter = evalstring(context, mapping, args[2])
971 else:
996 else:
972 splitter = None
997 splitter = None
973
998
974 tokens = text.split(splitter)
999 tokens = text.split(splitter)
975 if num >= len(tokens) or num < -len(tokens):
1000 if num >= len(tokens) or num < -len(tokens):
976 return ''
1001 return ''
977 else:
1002 else:
978 return tokens[num]
1003 return tokens[num]
979
1004
980 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1005 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
981 exprmethods = {
1006 exprmethods = {
982 "integer": lambda e, c: (runinteger, e[1]),
1007 "integer": lambda e, c: (runinteger, e[1]),
983 "string": lambda e, c: (runstring, e[1]),
1008 "string": lambda e, c: (runstring, e[1]),
984 "symbol": lambda e, c: (runsymbol, e[1]),
1009 "symbol": lambda e, c: (runsymbol, e[1]),
985 "template": buildtemplate,
1010 "template": buildtemplate,
986 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1011 "group": lambda e, c: compileexp(e[1], c, exprmethods),
987 # ".": buildmember,
1012 # ".": buildmember,
988 "|": buildfilter,
1013 "|": buildfilter,
989 "%": buildmap,
1014 "%": buildmap,
990 "func": buildfunc,
1015 "func": buildfunc,
991 "keyvalue": buildkeyvaluepair,
1016 "keyvalue": buildkeyvaluepair,
992 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1017 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
993 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1018 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
994 "negate": buildnegate,
1019 "negate": buildnegate,
995 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1020 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
996 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1021 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
997 }
1022 }
998
1023
999 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1024 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1000 methods = exprmethods.copy()
1025 methods = exprmethods.copy()
1001 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1026 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1002
1027
1003 class _aliasrules(parser.basealiasrules):
1028 class _aliasrules(parser.basealiasrules):
1004 """Parsing and expansion rule set of template aliases"""
1029 """Parsing and expansion rule set of template aliases"""
1005 _section = _('template alias')
1030 _section = _('template alias')
1006 _parse = staticmethod(_parseexpr)
1031 _parse = staticmethod(_parseexpr)
1007
1032
1008 @staticmethod
1033 @staticmethod
1009 def _trygetfunc(tree):
1034 def _trygetfunc(tree):
1010 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1035 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1011 None"""
1036 None"""
1012 if tree[0] == 'func' and tree[1][0] == 'symbol':
1037 if tree[0] == 'func' and tree[1][0] == 'symbol':
1013 return tree[1][1], getlist(tree[2])
1038 return tree[1][1], getlist(tree[2])
1014 if tree[0] == '|' and tree[2][0] == 'symbol':
1039 if tree[0] == '|' and tree[2][0] == 'symbol':
1015 return tree[2][1], [tree[1]]
1040 return tree[2][1], [tree[1]]
1016
1041
1017 def expandaliases(tree, aliases):
1042 def expandaliases(tree, aliases):
1018 """Return new tree of aliases are expanded"""
1043 """Return new tree of aliases are expanded"""
1019 aliasmap = _aliasrules.buildmap(aliases)
1044 aliasmap = _aliasrules.buildmap(aliases)
1020 return _aliasrules.expand(aliasmap, tree)
1045 return _aliasrules.expand(aliasmap, tree)
1021
1046
1022 # template engine
1047 # template engine
1023
1048
1024 stringify = templatefilters.stringify
1049 stringify = templatefilters.stringify
1025
1050
1026 def _flatten(thing):
1051 def _flatten(thing):
1027 '''yield a single stream from a possibly nested set of iterators'''
1052 '''yield a single stream from a possibly nested set of iterators'''
1028 thing = templatekw.unwraphybrid(thing)
1053 thing = templatekw.unwraphybrid(thing)
1029 if isinstance(thing, str):
1054 if isinstance(thing, str):
1030 yield thing
1055 yield thing
1031 elif thing is None:
1056 elif thing is None:
1032 pass
1057 pass
1033 elif not util.safehasattr(thing, '__iter__'):
1058 elif not util.safehasattr(thing, '__iter__'):
1034 yield str(thing)
1059 yield str(thing)
1035 else:
1060 else:
1036 for i in thing:
1061 for i in thing:
1037 i = templatekw.unwraphybrid(i)
1062 i = templatekw.unwraphybrid(i)
1038 if isinstance(i, str):
1063 if isinstance(i, str):
1039 yield i
1064 yield i
1040 elif i is None:
1065 elif i is None:
1041 pass
1066 pass
1042 elif not util.safehasattr(i, '__iter__'):
1067 elif not util.safehasattr(i, '__iter__'):
1043 yield str(i)
1068 yield str(i)
1044 else:
1069 else:
1045 for j in _flatten(i):
1070 for j in _flatten(i):
1046 yield j
1071 yield j
1047
1072
1048 def unquotestring(s):
1073 def unquotestring(s):
1049 '''unwrap quotes if any; otherwise returns unmodified string'''
1074 '''unwrap quotes if any; otherwise returns unmodified string'''
1050 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1075 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1051 return s
1076 return s
1052 return s[1:-1]
1077 return s[1:-1]
1053
1078
1054 class engine(object):
1079 class engine(object):
1055 '''template expansion engine.
1080 '''template expansion engine.
1056
1081
1057 template expansion works like this. a map file contains key=value
1082 template expansion works like this. a map file contains key=value
1058 pairs. if value is quoted, it is treated as string. otherwise, it
1083 pairs. if value is quoted, it is treated as string. otherwise, it
1059 is treated as name of template file.
1084 is treated as name of template file.
1060
1085
1061 templater is asked to expand a key in map. it looks up key, and
1086 templater is asked to expand a key in map. it looks up key, and
1062 looks for strings like this: {foo}. it expands {foo} by looking up
1087 looks for strings like this: {foo}. it expands {foo} by looking up
1063 foo in map, and substituting it. expansion is recursive: it stops
1088 foo in map, and substituting it. expansion is recursive: it stops
1064 when there is no more {foo} to replace.
1089 when there is no more {foo} to replace.
1065
1090
1066 expansion also allows formatting and filtering.
1091 expansion also allows formatting and filtering.
1067
1092
1068 format uses key to expand each item in list. syntax is
1093 format uses key to expand each item in list. syntax is
1069 {key%format}.
1094 {key%format}.
1070
1095
1071 filter uses function to transform value. syntax is
1096 filter uses function to transform value. syntax is
1072 {key|filter1|filter2|...}.'''
1097 {key|filter1|filter2|...}.'''
1073
1098
1074 def __init__(self, loader, filters=None, defaults=None, aliases=()):
1099 def __init__(self, loader, filters=None, defaults=None, aliases=()):
1075 self._loader = loader
1100 self._loader = loader
1076 if filters is None:
1101 if filters is None:
1077 filters = {}
1102 filters = {}
1078 self._filters = filters
1103 self._filters = filters
1079 if defaults is None:
1104 if defaults is None:
1080 defaults = {}
1105 defaults = {}
1081 self._defaults = defaults
1106 self._defaults = defaults
1082 self._aliasmap = _aliasrules.buildmap(aliases)
1107 self._aliasmap = _aliasrules.buildmap(aliases)
1083 self._cache = {} # key: (func, data)
1108 self._cache = {} # key: (func, data)
1084
1109
1085 def _load(self, t):
1110 def _load(self, t):
1086 '''load, parse, and cache a template'''
1111 '''load, parse, and cache a template'''
1087 if t not in self._cache:
1112 if t not in self._cache:
1088 # put poison to cut recursion while compiling 't'
1113 # put poison to cut recursion while compiling 't'
1089 self._cache[t] = (_runrecursivesymbol, t)
1114 self._cache[t] = (_runrecursivesymbol, t)
1090 try:
1115 try:
1091 x = parse(self._loader(t))
1116 x = parse(self._loader(t))
1092 if self._aliasmap:
1117 if self._aliasmap:
1093 x = _aliasrules.expand(self._aliasmap, x)
1118 x = _aliasrules.expand(self._aliasmap, x)
1094 self._cache[t] = compileexp(x, self, methods)
1119 self._cache[t] = compileexp(x, self, methods)
1095 except: # re-raises
1120 except: # re-raises
1096 del self._cache[t]
1121 del self._cache[t]
1097 raise
1122 raise
1098 return self._cache[t]
1123 return self._cache[t]
1099
1124
1100 def process(self, t, mapping):
1125 def process(self, t, mapping):
1101 '''Perform expansion. t is name of map element to expand.
1126 '''Perform expansion. t is name of map element to expand.
1102 mapping contains added elements for use during expansion. Is a
1127 mapping contains added elements for use during expansion. Is a
1103 generator.'''
1128 generator.'''
1104 func, data = self._load(t)
1129 func, data = self._load(t)
1105 return _flatten(func(self, mapping, data))
1130 return _flatten(func(self, mapping, data))
1106
1131
1107 engines = {'default': engine}
1132 engines = {'default': engine}
1108
1133
1109 def stylelist():
1134 def stylelist():
1110 paths = templatepaths()
1135 paths = templatepaths()
1111 if not paths:
1136 if not paths:
1112 return _('no templates found, try `hg debuginstall` for more info')
1137 return _('no templates found, try `hg debuginstall` for more info')
1113 dirlist = os.listdir(paths[0])
1138 dirlist = os.listdir(paths[0])
1114 stylelist = []
1139 stylelist = []
1115 for file in dirlist:
1140 for file in dirlist:
1116 split = file.split(".")
1141 split = file.split(".")
1117 if split[-1] in ('orig', 'rej'):
1142 if split[-1] in ('orig', 'rej'):
1118 continue
1143 continue
1119 if split[0] == "map-cmdline":
1144 if split[0] == "map-cmdline":
1120 stylelist.append(split[1])
1145 stylelist.append(split[1])
1121 return ", ".join(sorted(stylelist))
1146 return ", ".join(sorted(stylelist))
1122
1147
1123 def _readmapfile(mapfile):
1148 def _readmapfile(mapfile):
1124 """Load template elements from the given map file"""
1149 """Load template elements from the given map file"""
1125 if not os.path.exists(mapfile):
1150 if not os.path.exists(mapfile):
1126 raise error.Abort(_("style '%s' not found") % mapfile,
1151 raise error.Abort(_("style '%s' not found") % mapfile,
1127 hint=_("available styles: %s") % stylelist())
1152 hint=_("available styles: %s") % stylelist())
1128
1153
1129 base = os.path.dirname(mapfile)
1154 base = os.path.dirname(mapfile)
1130 conf = config.config(includepaths=templatepaths())
1155 conf = config.config(includepaths=templatepaths())
1131 conf.read(mapfile)
1156 conf.read(mapfile)
1132
1157
1133 cache = {}
1158 cache = {}
1134 tmap = {}
1159 tmap = {}
1135 for key, val in conf[''].items():
1160 for key, val in conf[''].items():
1136 if not val:
1161 if not val:
1137 raise error.ParseError(_('missing value'), conf.source('', key))
1162 raise error.ParseError(_('missing value'), conf.source('', key))
1138 if val[0] in "'\"":
1163 if val[0] in "'\"":
1139 if val[0] != val[-1]:
1164 if val[0] != val[-1]:
1140 raise error.ParseError(_('unmatched quotes'),
1165 raise error.ParseError(_('unmatched quotes'),
1141 conf.source('', key))
1166 conf.source('', key))
1142 cache[key] = unquotestring(val)
1167 cache[key] = unquotestring(val)
1143 elif key == "__base__":
1168 elif key == "__base__":
1144 # treat as a pointer to a base class for this style
1169 # treat as a pointer to a base class for this style
1145 path = util.normpath(os.path.join(base, val))
1170 path = util.normpath(os.path.join(base, val))
1146
1171
1147 # fallback check in template paths
1172 # fallback check in template paths
1148 if not os.path.exists(path):
1173 if not os.path.exists(path):
1149 for p in templatepaths():
1174 for p in templatepaths():
1150 p2 = util.normpath(os.path.join(p, val))
1175 p2 = util.normpath(os.path.join(p, val))
1151 if os.path.isfile(p2):
1176 if os.path.isfile(p2):
1152 path = p2
1177 path = p2
1153 break
1178 break
1154 p3 = util.normpath(os.path.join(p2, "map"))
1179 p3 = util.normpath(os.path.join(p2, "map"))
1155 if os.path.isfile(p3):
1180 if os.path.isfile(p3):
1156 path = p3
1181 path = p3
1157 break
1182 break
1158
1183
1159 bcache, btmap = _readmapfile(path)
1184 bcache, btmap = _readmapfile(path)
1160 for k in bcache:
1185 for k in bcache:
1161 if k not in cache:
1186 if k not in cache:
1162 cache[k] = bcache[k]
1187 cache[k] = bcache[k]
1163 for k in btmap:
1188 for k in btmap:
1164 if k not in tmap:
1189 if k not in tmap:
1165 tmap[k] = btmap[k]
1190 tmap[k] = btmap[k]
1166 else:
1191 else:
1167 val = 'default', val
1192 val = 'default', val
1168 if ':' in val[1]:
1193 if ':' in val[1]:
1169 val = val[1].split(':', 1)
1194 val = val[1].split(':', 1)
1170 tmap[key] = val[0], os.path.join(base, val[1])
1195 tmap[key] = val[0], os.path.join(base, val[1])
1171 return cache, tmap
1196 return cache, tmap
1172
1197
1173 class TemplateNotFound(error.Abort):
1198 class TemplateNotFound(error.Abort):
1174 pass
1199 pass
1175
1200
1176 class templater(object):
1201 class templater(object):
1177
1202
1178 def __init__(self, filters=None, defaults=None, cache=None, aliases=(),
1203 def __init__(self, filters=None, defaults=None, cache=None, aliases=(),
1179 minchunk=1024, maxchunk=65536):
1204 minchunk=1024, maxchunk=65536):
1180 '''set up template engine.
1205 '''set up template engine.
1181 filters is dict of functions. each transforms a value into another.
1206 filters is dict of functions. each transforms a value into another.
1182 defaults is dict of default map definitions.
1207 defaults is dict of default map definitions.
1183 aliases is list of alias (name, replacement) pairs.
1208 aliases is list of alias (name, replacement) pairs.
1184 '''
1209 '''
1185 if filters is None:
1210 if filters is None:
1186 filters = {}
1211 filters = {}
1187 if defaults is None:
1212 if defaults is None:
1188 defaults = {}
1213 defaults = {}
1189 if cache is None:
1214 if cache is None:
1190 cache = {}
1215 cache = {}
1191 self.cache = cache.copy()
1216 self.cache = cache.copy()
1192 self.map = {}
1217 self.map = {}
1193 self.filters = templatefilters.filters.copy()
1218 self.filters = templatefilters.filters.copy()
1194 self.filters.update(filters)
1219 self.filters.update(filters)
1195 self.defaults = defaults
1220 self.defaults = defaults
1196 self._aliases = aliases
1221 self._aliases = aliases
1197 self.minchunk, self.maxchunk = minchunk, maxchunk
1222 self.minchunk, self.maxchunk = minchunk, maxchunk
1198 self.ecache = {}
1223 self.ecache = {}
1199
1224
1200 @classmethod
1225 @classmethod
1201 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None,
1226 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None,
1202 minchunk=1024, maxchunk=65536):
1227 minchunk=1024, maxchunk=65536):
1203 """Create templater from the specified map file"""
1228 """Create templater from the specified map file"""
1204 t = cls(filters, defaults, cache, [], minchunk, maxchunk)
1229 t = cls(filters, defaults, cache, [], minchunk, maxchunk)
1205 cache, tmap = _readmapfile(mapfile)
1230 cache, tmap = _readmapfile(mapfile)
1206 t.cache.update(cache)
1231 t.cache.update(cache)
1207 t.map = tmap
1232 t.map = tmap
1208 return t
1233 return t
1209
1234
1210 def __contains__(self, key):
1235 def __contains__(self, key):
1211 return key in self.cache or key in self.map
1236 return key in self.cache or key in self.map
1212
1237
1213 def load(self, t):
1238 def load(self, t):
1214 '''Get the template for the given template name. Use a local cache.'''
1239 '''Get the template for the given template name. Use a local cache.'''
1215 if t not in self.cache:
1240 if t not in self.cache:
1216 try:
1241 try:
1217 self.cache[t] = util.readfile(self.map[t][1])
1242 self.cache[t] = util.readfile(self.map[t][1])
1218 except KeyError as inst:
1243 except KeyError as inst:
1219 raise TemplateNotFound(_('"%s" not in template map') %
1244 raise TemplateNotFound(_('"%s" not in template map') %
1220 inst.args[0])
1245 inst.args[0])
1221 except IOError as inst:
1246 except IOError as inst:
1222 raise IOError(inst.args[0], _('template file %s: %s') %
1247 raise IOError(inst.args[0], _('template file %s: %s') %
1223 (self.map[t][1], inst.args[1]))
1248 (self.map[t][1], inst.args[1]))
1224 return self.cache[t]
1249 return self.cache[t]
1225
1250
1226 def __call__(self, t, **mapping):
1251 def __call__(self, t, **mapping):
1227 ttype = t in self.map and self.map[t][0] or 'default'
1252 ttype = t in self.map and self.map[t][0] or 'default'
1228 if ttype not in self.ecache:
1253 if ttype not in self.ecache:
1229 try:
1254 try:
1230 ecls = engines[ttype]
1255 ecls = engines[ttype]
1231 except KeyError:
1256 except KeyError:
1232 raise error.Abort(_('invalid template engine: %s') % ttype)
1257 raise error.Abort(_('invalid template engine: %s') % ttype)
1233 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1258 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1234 self._aliases)
1259 self._aliases)
1235 proc = self.ecache[ttype]
1260 proc = self.ecache[ttype]
1236
1261
1237 stream = proc.process(t, mapping)
1262 stream = proc.process(t, mapping)
1238 if self.minchunk:
1263 if self.minchunk:
1239 stream = util.increasingchunks(stream, min=self.minchunk,
1264 stream = util.increasingchunks(stream, min=self.minchunk,
1240 max=self.maxchunk)
1265 max=self.maxchunk)
1241 return stream
1266 return stream
1242
1267
1243 def templatepaths():
1268 def templatepaths():
1244 '''return locations used for template files.'''
1269 '''return locations used for template files.'''
1245 pathsrel = ['templates']
1270 pathsrel = ['templates']
1246 paths = [os.path.normpath(os.path.join(util.datapath, f))
1271 paths = [os.path.normpath(os.path.join(util.datapath, f))
1247 for f in pathsrel]
1272 for f in pathsrel]
1248 return [p for p in paths if os.path.isdir(p)]
1273 return [p for p in paths if os.path.isdir(p)]
1249
1274
1250 def templatepath(name):
1275 def templatepath(name):
1251 '''return location of template file. returns None if not found.'''
1276 '''return location of template file. returns None if not found.'''
1252 for p in templatepaths():
1277 for p in templatepaths():
1253 f = os.path.join(p, name)
1278 f = os.path.join(p, name)
1254 if os.path.exists(f):
1279 if os.path.exists(f):
1255 return f
1280 return f
1256 return None
1281 return None
1257
1282
1258 def stylemap(styles, paths=None):
1283 def stylemap(styles, paths=None):
1259 """Return path to mapfile for a given style.
1284 """Return path to mapfile for a given style.
1260
1285
1261 Searches mapfile in the following locations:
1286 Searches mapfile in the following locations:
1262 1. templatepath/style/map
1287 1. templatepath/style/map
1263 2. templatepath/map-style
1288 2. templatepath/map-style
1264 3. templatepath/map
1289 3. templatepath/map
1265 """
1290 """
1266
1291
1267 if paths is None:
1292 if paths is None:
1268 paths = templatepaths()
1293 paths = templatepaths()
1269 elif isinstance(paths, str):
1294 elif isinstance(paths, str):
1270 paths = [paths]
1295 paths = [paths]
1271
1296
1272 if isinstance(styles, str):
1297 if isinstance(styles, str):
1273 styles = [styles]
1298 styles = [styles]
1274
1299
1275 for style in styles:
1300 for style in styles:
1276 # only plain name is allowed to honor template paths
1301 # only plain name is allowed to honor template paths
1277 if (not style
1302 if (not style
1278 or style in (os.curdir, os.pardir)
1303 or style in (os.curdir, os.pardir)
1279 or pycompat.ossep in style
1304 or pycompat.ossep in style
1280 or pycompat.osaltsep and pycompat.osaltsep in style):
1305 or pycompat.osaltsep and pycompat.osaltsep in style):
1281 continue
1306 continue
1282 locations = [os.path.join(style, 'map'), 'map-' + style]
1307 locations = [os.path.join(style, 'map'), 'map-' + style]
1283 locations.append('map')
1308 locations.append('map')
1284
1309
1285 for path in paths:
1310 for path in paths:
1286 for location in locations:
1311 for location in locations:
1287 mapfile = os.path.join(path, location)
1312 mapfile = os.path.join(path, location)
1288 if os.path.isfile(mapfile):
1313 if os.path.isfile(mapfile):
1289 return style, mapfile
1314 return style, mapfile
1290
1315
1291 raise RuntimeError("No hgweb templates found in %r" % paths)
1316 raise RuntimeError("No hgweb templates found in %r" % paths)
1292
1317
1293 def loadfunction(ui, extname, registrarobj):
1318 def loadfunction(ui, extname, registrarobj):
1294 """Load template function from specified registrarobj
1319 """Load template function from specified registrarobj
1295 """
1320 """
1296 for name, func in registrarobj._table.iteritems():
1321 for name, func in registrarobj._table.iteritems():
1297 funcs[name] = func
1322 funcs[name] = func
1298
1323
1299 # tell hggettext to extract docstrings from these functions:
1324 # tell hggettext to extract docstrings from these functions:
1300 i18nfunctions = funcs.values()
1325 i18nfunctions = funcs.values()
@@ -1,4181 +1,4188 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Test arithmetic operators have the right precedence:
32 Test arithmetic operators have the right precedence:
33
33
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
35 2020 1964
35 2020 1964
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
37 9860 5908
37 9860 5908
38
38
39 Test division:
39 Test division:
40
40
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
42 (template
42 (template
43 (/
43 (/
44 ('integer', '5')
44 ('integer', '5')
45 ('integer', '2'))
45 ('integer', '2'))
46 ('string', ' ')
46 ('string', ' ')
47 (func
47 (func
48 ('symbol', 'mod')
48 ('symbol', 'mod')
49 (list
49 (list
50 ('integer', '5')
50 ('integer', '5')
51 ('integer', '2')))
51 ('integer', '2')))
52 ('string', '\n'))
52 ('string', '\n'))
53 2 1
53 2 1
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
55 (template
55 (template
56 (/
56 (/
57 ('integer', '5')
57 ('integer', '5')
58 (negate
58 (negate
59 ('integer', '2')))
59 ('integer', '2')))
60 ('string', ' ')
60 ('string', ' ')
61 (func
61 (func
62 ('symbol', 'mod')
62 ('symbol', 'mod')
63 (list
63 (list
64 ('integer', '5')
64 ('integer', '5')
65 (negate
65 (negate
66 ('integer', '2'))))
66 ('integer', '2'))))
67 ('string', '\n'))
67 ('string', '\n'))
68 -3 -1
68 -3 -1
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
70 (template
70 (template
71 (/
71 (/
72 (negate
72 (negate
73 ('integer', '5'))
73 ('integer', '5'))
74 ('integer', '2'))
74 ('integer', '2'))
75 ('string', ' ')
75 ('string', ' ')
76 (func
76 (func
77 ('symbol', 'mod')
77 ('symbol', 'mod')
78 (list
78 (list
79 (negate
79 (negate
80 ('integer', '5'))
80 ('integer', '5'))
81 ('integer', '2')))
81 ('integer', '2')))
82 ('string', '\n'))
82 ('string', '\n'))
83 -3 1
83 -3 1
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
85 (template
85 (template
86 (/
86 (/
87 (negate
87 (negate
88 ('integer', '5'))
88 ('integer', '5'))
89 (negate
89 (negate
90 ('integer', '2')))
90 ('integer', '2')))
91 ('string', ' ')
91 ('string', ' ')
92 (func
92 (func
93 ('symbol', 'mod')
93 ('symbol', 'mod')
94 (list
94 (list
95 (negate
95 (negate
96 ('integer', '5'))
96 ('integer', '5'))
97 (negate
97 (negate
98 ('integer', '2'))))
98 ('integer', '2'))))
99 ('string', '\n'))
99 ('string', '\n'))
100 2 -1
100 2 -1
101
101
102 Filters bind closer than arithmetic:
102 Filters bind closer than arithmetic:
103
103
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
105 (template
105 (template
106 (-
106 (-
107 (|
107 (|
108 (func
108 (func
109 ('symbol', 'revset')
109 ('symbol', 'revset')
110 ('string', '.'))
110 ('string', '.'))
111 ('symbol', 'count'))
111 ('symbol', 'count'))
112 ('integer', '1'))
112 ('integer', '1'))
113 ('string', '\n'))
113 ('string', '\n'))
114 0
114 0
115
115
116 But negate binds closer still:
116 But negate binds closer still:
117
117
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
119 (template
119 (template
120 (-
120 (-
121 ('integer', '1')
121 ('integer', '1')
122 (|
122 (|
123 ('integer', '3')
123 ('integer', '3')
124 ('symbol', 'stringify')))
124 ('symbol', 'stringify')))
125 ('string', '\n'))
125 ('string', '\n'))
126 hg: parse error: arithmetic only defined on integers
126 hg: parse error: arithmetic only defined on integers
127 [255]
127 [255]
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
129 (template
129 (template
130 (|
130 (|
131 (negate
131 (negate
132 ('integer', '3'))
132 ('integer', '3'))
133 ('symbol', 'stringify'))
133 ('symbol', 'stringify'))
134 ('string', '\n'))
134 ('string', '\n'))
135 -3
135 -3
136
136
137 Keyword arguments:
137 Keyword arguments:
138
138
139 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
139 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
140 (template
140 (template
141 (keyvalue
141 (keyvalue
142 ('symbol', 'foo')
142 ('symbol', 'foo')
143 (|
143 (|
144 ('symbol', 'bar')
144 ('symbol', 'bar')
145 ('symbol', 'baz'))))
145 ('symbol', 'baz'))))
146 hg: parse error: can't use a key-value pair in this context
146 hg: parse error: can't use a key-value pair in this context
147 [255]
147 [255]
148
148
149 Call function which takes named arguments by filter syntax:
150
151 $ hg debugtemplate '{" "|separate}'
152 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
153 hg: parse error: unknown method 'list'
154 [255]
155
149 Second branch starting at nullrev:
156 Second branch starting at nullrev:
150
157
151 $ hg update null
158 $ hg update null
152 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
159 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
153 $ echo second > second
160 $ echo second > second
154 $ hg add second
161 $ hg add second
155 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
162 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
156 created new head
163 created new head
157
164
158 $ echo third > third
165 $ echo third > third
159 $ hg add third
166 $ hg add third
160 $ hg mv second fourth
167 $ hg mv second fourth
161 $ hg commit -m third -d "2020-01-01 10:01"
168 $ hg commit -m third -d "2020-01-01 10:01"
162
169
163 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
170 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
164 fourth (second)
171 fourth (second)
165 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
172 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
166 second -> fourth
173 second -> fourth
167 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
174 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
168 8 t
175 8 t
169 7 f
176 7 f
170
177
171 Working-directory revision has special identifiers, though they are still
178 Working-directory revision has special identifiers, though they are still
172 experimental:
179 experimental:
173
180
174 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
181 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
175 2147483647:ffffffffffffffffffffffffffffffffffffffff
182 2147483647:ffffffffffffffffffffffffffffffffffffffff
176
183
177 Some keywords are invalid for working-directory revision, but they should
184 Some keywords are invalid for working-directory revision, but they should
178 never cause crash:
185 never cause crash:
179
186
180 $ hg log -r 'wdir()' -T '{manifest}\n'
187 $ hg log -r 'wdir()' -T '{manifest}\n'
181
188
182
189
183 Quoting for ui.logtemplate
190 Quoting for ui.logtemplate
184
191
185 $ hg tip --config "ui.logtemplate={rev}\n"
192 $ hg tip --config "ui.logtemplate={rev}\n"
186 8
193 8
187 $ hg tip --config "ui.logtemplate='{rev}\n'"
194 $ hg tip --config "ui.logtemplate='{rev}\n'"
188 8
195 8
189 $ hg tip --config 'ui.logtemplate="{rev}\n"'
196 $ hg tip --config 'ui.logtemplate="{rev}\n"'
190 8
197 8
191 $ hg tip --config 'ui.logtemplate=n{rev}\n'
198 $ hg tip --config 'ui.logtemplate=n{rev}\n'
192 n8
199 n8
193
200
194 Make sure user/global hgrc does not affect tests
201 Make sure user/global hgrc does not affect tests
195
202
196 $ echo '[ui]' > .hg/hgrc
203 $ echo '[ui]' > .hg/hgrc
197 $ echo 'logtemplate =' >> .hg/hgrc
204 $ echo 'logtemplate =' >> .hg/hgrc
198 $ echo 'style =' >> .hg/hgrc
205 $ echo 'style =' >> .hg/hgrc
199
206
200 Add some simple styles to settings
207 Add some simple styles to settings
201
208
202 $ echo '[templates]' >> .hg/hgrc
209 $ echo '[templates]' >> .hg/hgrc
203 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
210 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
204 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
211 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
205
212
206 $ hg log -l1 -Tsimple
213 $ hg log -l1 -Tsimple
207 8
214 8
208 $ hg log -l1 -Tsimple2
215 $ hg log -l1 -Tsimple2
209 8
216 8
210
217
211 Test templates and style maps in files:
218 Test templates and style maps in files:
212
219
213 $ echo "{rev}" > tmpl
220 $ echo "{rev}" > tmpl
214 $ hg log -l1 -T./tmpl
221 $ hg log -l1 -T./tmpl
215 8
222 8
216 $ hg log -l1 -Tblah/blah
223 $ hg log -l1 -Tblah/blah
217 blah/blah (no-eol)
224 blah/blah (no-eol)
218
225
219 $ printf 'changeset = "{rev}\\n"\n' > map-simple
226 $ printf 'changeset = "{rev}\\n"\n' > map-simple
220 $ hg log -l1 -T./map-simple
227 $ hg log -l1 -T./map-simple
221 8
228 8
222
229
223 Test template map inheritance
230 Test template map inheritance
224
231
225 $ echo "__base__ = map-cmdline.default" > map-simple
232 $ echo "__base__ = map-cmdline.default" > map-simple
226 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
233 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
227 $ hg log -l1 -T./map-simple
234 $ hg log -l1 -T./map-simple
228 changeset: ***8***
235 changeset: ***8***
229 tag: tip
236 tag: tip
230 user: test
237 user: test
231 date: Wed Jan 01 10:01:00 2020 +0000
238 date: Wed Jan 01 10:01:00 2020 +0000
232 summary: third
239 summary: third
233
240
234
241
235 Template should precede style option
242 Template should precede style option
236
243
237 $ hg log -l1 --style default -T '{rev}\n'
244 $ hg log -l1 --style default -T '{rev}\n'
238 8
245 8
239
246
240 Add a commit with empty description, to ensure that the templates
247 Add a commit with empty description, to ensure that the templates
241 below will omit the description line.
248 below will omit the description line.
242
249
243 $ echo c >> c
250 $ echo c >> c
244 $ hg add c
251 $ hg add c
245 $ hg commit -qm ' '
252 $ hg commit -qm ' '
246
253
247 Default style is like normal output. Phases style should be the same
254 Default style is like normal output. Phases style should be the same
248 as default style, except for extra phase lines.
255 as default style, except for extra phase lines.
249
256
250 $ hg log > log.out
257 $ hg log > log.out
251 $ hg log --style default > style.out
258 $ hg log --style default > style.out
252 $ cmp log.out style.out || diff -u log.out style.out
259 $ cmp log.out style.out || diff -u log.out style.out
253 $ hg log -T phases > phases.out
260 $ hg log -T phases > phases.out
254 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
261 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
255 +phase: draft
262 +phase: draft
256 +phase: draft
263 +phase: draft
257 +phase: draft
264 +phase: draft
258 +phase: draft
265 +phase: draft
259 +phase: draft
266 +phase: draft
260 +phase: draft
267 +phase: draft
261 +phase: draft
268 +phase: draft
262 +phase: draft
269 +phase: draft
263 +phase: draft
270 +phase: draft
264 +phase: draft
271 +phase: draft
265
272
266 $ hg log -v > log.out
273 $ hg log -v > log.out
267 $ hg log -v --style default > style.out
274 $ hg log -v --style default > style.out
268 $ cmp log.out style.out || diff -u log.out style.out
275 $ cmp log.out style.out || diff -u log.out style.out
269 $ hg log -v -T phases > phases.out
276 $ hg log -v -T phases > phases.out
270 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
277 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
271 +phase: draft
278 +phase: draft
272 +phase: draft
279 +phase: draft
273 +phase: draft
280 +phase: draft
274 +phase: draft
281 +phase: draft
275 +phase: draft
282 +phase: draft
276 +phase: draft
283 +phase: draft
277 +phase: draft
284 +phase: draft
278 +phase: draft
285 +phase: draft
279 +phase: draft
286 +phase: draft
280 +phase: draft
287 +phase: draft
281
288
282 $ hg log -q > log.out
289 $ hg log -q > log.out
283 $ hg log -q --style default > style.out
290 $ hg log -q --style default > style.out
284 $ cmp log.out style.out || diff -u log.out style.out
291 $ cmp log.out style.out || diff -u log.out style.out
285 $ hg log -q -T phases > phases.out
292 $ hg log -q -T phases > phases.out
286 $ cmp log.out phases.out || diff -u log.out phases.out
293 $ cmp log.out phases.out || diff -u log.out phases.out
287
294
288 $ hg log --debug > log.out
295 $ hg log --debug > log.out
289 $ hg log --debug --style default > style.out
296 $ hg log --debug --style default > style.out
290 $ cmp log.out style.out || diff -u log.out style.out
297 $ cmp log.out style.out || diff -u log.out style.out
291 $ hg log --debug -T phases > phases.out
298 $ hg log --debug -T phases > phases.out
292 $ cmp log.out phases.out || diff -u log.out phases.out
299 $ cmp log.out phases.out || diff -u log.out phases.out
293
300
294 Default style of working-directory revision should also be the same (but
301 Default style of working-directory revision should also be the same (but
295 date may change while running tests):
302 date may change while running tests):
296
303
297 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
304 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
298 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
305 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
299 $ cmp log.out style.out || diff -u log.out style.out
306 $ cmp log.out style.out || diff -u log.out style.out
300
307
301 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
308 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
302 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
309 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
303 $ cmp log.out style.out || diff -u log.out style.out
310 $ cmp log.out style.out || diff -u log.out style.out
304
311
305 $ hg log -r 'wdir()' -q > log.out
312 $ hg log -r 'wdir()' -q > log.out
306 $ hg log -r 'wdir()' -q --style default > style.out
313 $ hg log -r 'wdir()' -q --style default > style.out
307 $ cmp log.out style.out || diff -u log.out style.out
314 $ cmp log.out style.out || diff -u log.out style.out
308
315
309 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
316 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
310 $ hg log -r 'wdir()' --debug --style default \
317 $ hg log -r 'wdir()' --debug --style default \
311 > | sed 's|^date:.*|date:|' > style.out
318 > | sed 's|^date:.*|date:|' > style.out
312 $ cmp log.out style.out || diff -u log.out style.out
319 $ cmp log.out style.out || diff -u log.out style.out
313
320
314 Default style should also preserve color information (issue2866):
321 Default style should also preserve color information (issue2866):
315
322
316 $ cp $HGRCPATH $HGRCPATH-bak
323 $ cp $HGRCPATH $HGRCPATH-bak
317 $ cat <<EOF >> $HGRCPATH
324 $ cat <<EOF >> $HGRCPATH
318 > [extensions]
325 > [extensions]
319 > color=
326 > color=
320 > EOF
327 > EOF
321
328
322 $ hg --color=debug log > log.out
329 $ hg --color=debug log > log.out
323 $ hg --color=debug log --style default > style.out
330 $ hg --color=debug log --style default > style.out
324 $ cmp log.out style.out || diff -u log.out style.out
331 $ cmp log.out style.out || diff -u log.out style.out
325 $ hg --color=debug log -T phases > phases.out
332 $ hg --color=debug log -T phases > phases.out
326 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
333 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
327 +[log.phase|phase: draft]
334 +[log.phase|phase: draft]
328 +[log.phase|phase: draft]
335 +[log.phase|phase: draft]
329 +[log.phase|phase: draft]
336 +[log.phase|phase: draft]
330 +[log.phase|phase: draft]
337 +[log.phase|phase: draft]
331 +[log.phase|phase: draft]
338 +[log.phase|phase: draft]
332 +[log.phase|phase: draft]
339 +[log.phase|phase: draft]
333 +[log.phase|phase: draft]
340 +[log.phase|phase: draft]
334 +[log.phase|phase: draft]
341 +[log.phase|phase: draft]
335 +[log.phase|phase: draft]
342 +[log.phase|phase: draft]
336 +[log.phase|phase: draft]
343 +[log.phase|phase: draft]
337
344
338 $ hg --color=debug -v log > log.out
345 $ hg --color=debug -v log > log.out
339 $ hg --color=debug -v log --style default > style.out
346 $ hg --color=debug -v log --style default > style.out
340 $ cmp log.out style.out || diff -u log.out style.out
347 $ cmp log.out style.out || diff -u log.out style.out
341 $ hg --color=debug -v log -T phases > phases.out
348 $ hg --color=debug -v log -T phases > phases.out
342 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
349 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
343 +[log.phase|phase: draft]
350 +[log.phase|phase: draft]
344 +[log.phase|phase: draft]
351 +[log.phase|phase: draft]
345 +[log.phase|phase: draft]
352 +[log.phase|phase: draft]
346 +[log.phase|phase: draft]
353 +[log.phase|phase: draft]
347 +[log.phase|phase: draft]
354 +[log.phase|phase: draft]
348 +[log.phase|phase: draft]
355 +[log.phase|phase: draft]
349 +[log.phase|phase: draft]
356 +[log.phase|phase: draft]
350 +[log.phase|phase: draft]
357 +[log.phase|phase: draft]
351 +[log.phase|phase: draft]
358 +[log.phase|phase: draft]
352 +[log.phase|phase: draft]
359 +[log.phase|phase: draft]
353
360
354 $ hg --color=debug -q log > log.out
361 $ hg --color=debug -q log > log.out
355 $ hg --color=debug -q log --style default > style.out
362 $ hg --color=debug -q log --style default > style.out
356 $ cmp log.out style.out || diff -u log.out style.out
363 $ cmp log.out style.out || diff -u log.out style.out
357 $ hg --color=debug -q log -T phases > phases.out
364 $ hg --color=debug -q log -T phases > phases.out
358 $ cmp log.out phases.out || diff -u log.out phases.out
365 $ cmp log.out phases.out || diff -u log.out phases.out
359
366
360 $ hg --color=debug --debug log > log.out
367 $ hg --color=debug --debug log > log.out
361 $ hg --color=debug --debug log --style default > style.out
368 $ hg --color=debug --debug log --style default > style.out
362 $ cmp log.out style.out || diff -u log.out style.out
369 $ cmp log.out style.out || diff -u log.out style.out
363 $ hg --color=debug --debug log -T phases > phases.out
370 $ hg --color=debug --debug log -T phases > phases.out
364 $ cmp log.out phases.out || diff -u log.out phases.out
371 $ cmp log.out phases.out || diff -u log.out phases.out
365
372
366 $ mv $HGRCPATH-bak $HGRCPATH
373 $ mv $HGRCPATH-bak $HGRCPATH
367
374
368 Remove commit with empty commit message, so as to not pollute further
375 Remove commit with empty commit message, so as to not pollute further
369 tests.
376 tests.
370
377
371 $ hg --config extensions.strip= strip -q .
378 $ hg --config extensions.strip= strip -q .
372
379
373 Revision with no copies (used to print a traceback):
380 Revision with no copies (used to print a traceback):
374
381
375 $ hg tip -v --template '\n'
382 $ hg tip -v --template '\n'
376
383
377
384
378 Compact style works:
385 Compact style works:
379
386
380 $ hg log -Tcompact
387 $ hg log -Tcompact
381 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
388 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
382 third
389 third
383
390
384 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
391 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
385 second
392 second
386
393
387 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
394 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
388 merge
395 merge
389
396
390 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
397 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
391 new head
398 new head
392
399
393 4 bbe44766e73d 1970-01-17 04:53 +0000 person
400 4 bbe44766e73d 1970-01-17 04:53 +0000 person
394 new branch
401 new branch
395
402
396 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
403 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
397 no user, no domain
404 no user, no domain
398
405
399 2 97054abb4ab8 1970-01-14 21:20 +0000 other
406 2 97054abb4ab8 1970-01-14 21:20 +0000 other
400 no person
407 no person
401
408
402 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
409 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
403 other 1
410 other 1
404
411
405 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
412 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
406 line 1
413 line 1
407
414
408
415
409 $ hg log -v --style compact
416 $ hg log -v --style compact
410 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
417 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
411 third
418 third
412
419
413 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
420 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
414 second
421 second
415
422
416 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
423 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
417 merge
424 merge
418
425
419 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
426 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
420 new head
427 new head
421
428
422 4 bbe44766e73d 1970-01-17 04:53 +0000 person
429 4 bbe44766e73d 1970-01-17 04:53 +0000 person
423 new branch
430 new branch
424
431
425 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
432 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
426 no user, no domain
433 no user, no domain
427
434
428 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
435 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
429 no person
436 no person
430
437
431 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
438 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
432 other 1
439 other 1
433 other 2
440 other 2
434
441
435 other 3
442 other 3
436
443
437 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
444 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
438 line 1
445 line 1
439 line 2
446 line 2
440
447
441
448
442 $ hg log --debug --style compact
449 $ hg log --debug --style compact
443 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
450 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
444 third
451 third
445
452
446 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
453 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
447 second
454 second
448
455
449 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
456 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
450 merge
457 merge
451
458
452 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
459 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
453 new head
460 new head
454
461
455 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
462 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
456 new branch
463 new branch
457
464
458 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
465 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
459 no user, no domain
466 no user, no domain
460
467
461 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
468 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
462 no person
469 no person
463
470
464 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
471 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
465 other 1
472 other 1
466 other 2
473 other 2
467
474
468 other 3
475 other 3
469
476
470 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
477 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
471 line 1
478 line 1
472 line 2
479 line 2
473
480
474
481
475 Test xml styles:
482 Test xml styles:
476
483
477 $ hg log --style xml -r 'not all()'
484 $ hg log --style xml -r 'not all()'
478 <?xml version="1.0"?>
485 <?xml version="1.0"?>
479 <log>
486 <log>
480 </log>
487 </log>
481
488
482 $ hg log --style xml
489 $ hg log --style xml
483 <?xml version="1.0"?>
490 <?xml version="1.0"?>
484 <log>
491 <log>
485 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
492 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
486 <tag>tip</tag>
493 <tag>tip</tag>
487 <author email="test">test</author>
494 <author email="test">test</author>
488 <date>2020-01-01T10:01:00+00:00</date>
495 <date>2020-01-01T10:01:00+00:00</date>
489 <msg xml:space="preserve">third</msg>
496 <msg xml:space="preserve">third</msg>
490 </logentry>
497 </logentry>
491 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
498 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
492 <parent revision="-1" node="0000000000000000000000000000000000000000" />
499 <parent revision="-1" node="0000000000000000000000000000000000000000" />
493 <author email="user@hostname">User Name</author>
500 <author email="user@hostname">User Name</author>
494 <date>1970-01-12T13:46:40+00:00</date>
501 <date>1970-01-12T13:46:40+00:00</date>
495 <msg xml:space="preserve">second</msg>
502 <msg xml:space="preserve">second</msg>
496 </logentry>
503 </logentry>
497 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
504 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
498 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
505 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
499 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
506 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
500 <author email="person">person</author>
507 <author email="person">person</author>
501 <date>1970-01-18T08:40:01+00:00</date>
508 <date>1970-01-18T08:40:01+00:00</date>
502 <msg xml:space="preserve">merge</msg>
509 <msg xml:space="preserve">merge</msg>
503 </logentry>
510 </logentry>
504 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
511 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
505 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
512 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
506 <author email="person">person</author>
513 <author email="person">person</author>
507 <date>1970-01-18T08:40:00+00:00</date>
514 <date>1970-01-18T08:40:00+00:00</date>
508 <msg xml:space="preserve">new head</msg>
515 <msg xml:space="preserve">new head</msg>
509 </logentry>
516 </logentry>
510 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
517 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
511 <branch>foo</branch>
518 <branch>foo</branch>
512 <author email="person">person</author>
519 <author email="person">person</author>
513 <date>1970-01-17T04:53:20+00:00</date>
520 <date>1970-01-17T04:53:20+00:00</date>
514 <msg xml:space="preserve">new branch</msg>
521 <msg xml:space="preserve">new branch</msg>
515 </logentry>
522 </logentry>
516 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
523 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
517 <author email="person">person</author>
524 <author email="person">person</author>
518 <date>1970-01-16T01:06:40+00:00</date>
525 <date>1970-01-16T01:06:40+00:00</date>
519 <msg xml:space="preserve">no user, no domain</msg>
526 <msg xml:space="preserve">no user, no domain</msg>
520 </logentry>
527 </logentry>
521 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
528 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
522 <author email="other@place">other</author>
529 <author email="other@place">other</author>
523 <date>1970-01-14T21:20:00+00:00</date>
530 <date>1970-01-14T21:20:00+00:00</date>
524 <msg xml:space="preserve">no person</msg>
531 <msg xml:space="preserve">no person</msg>
525 </logentry>
532 </logentry>
526 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
533 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
527 <author email="other@place">A. N. Other</author>
534 <author email="other@place">A. N. Other</author>
528 <date>1970-01-13T17:33:20+00:00</date>
535 <date>1970-01-13T17:33:20+00:00</date>
529 <msg xml:space="preserve">other 1
536 <msg xml:space="preserve">other 1
530 other 2
537 other 2
531
538
532 other 3</msg>
539 other 3</msg>
533 </logentry>
540 </logentry>
534 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
541 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
535 <author email="user@hostname">User Name</author>
542 <author email="user@hostname">User Name</author>
536 <date>1970-01-12T13:46:40+00:00</date>
543 <date>1970-01-12T13:46:40+00:00</date>
537 <msg xml:space="preserve">line 1
544 <msg xml:space="preserve">line 1
538 line 2</msg>
545 line 2</msg>
539 </logentry>
546 </logentry>
540 </log>
547 </log>
541
548
542 $ hg log -v --style xml
549 $ hg log -v --style xml
543 <?xml version="1.0"?>
550 <?xml version="1.0"?>
544 <log>
551 <log>
545 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
552 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
546 <tag>tip</tag>
553 <tag>tip</tag>
547 <author email="test">test</author>
554 <author email="test">test</author>
548 <date>2020-01-01T10:01:00+00:00</date>
555 <date>2020-01-01T10:01:00+00:00</date>
549 <msg xml:space="preserve">third</msg>
556 <msg xml:space="preserve">third</msg>
550 <paths>
557 <paths>
551 <path action="A">fourth</path>
558 <path action="A">fourth</path>
552 <path action="A">third</path>
559 <path action="A">third</path>
553 <path action="R">second</path>
560 <path action="R">second</path>
554 </paths>
561 </paths>
555 <copies>
562 <copies>
556 <copy source="second">fourth</copy>
563 <copy source="second">fourth</copy>
557 </copies>
564 </copies>
558 </logentry>
565 </logentry>
559 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
566 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
560 <parent revision="-1" node="0000000000000000000000000000000000000000" />
567 <parent revision="-1" node="0000000000000000000000000000000000000000" />
561 <author email="user@hostname">User Name</author>
568 <author email="user@hostname">User Name</author>
562 <date>1970-01-12T13:46:40+00:00</date>
569 <date>1970-01-12T13:46:40+00:00</date>
563 <msg xml:space="preserve">second</msg>
570 <msg xml:space="preserve">second</msg>
564 <paths>
571 <paths>
565 <path action="A">second</path>
572 <path action="A">second</path>
566 </paths>
573 </paths>
567 </logentry>
574 </logentry>
568 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
575 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
569 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
576 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
570 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
577 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
571 <author email="person">person</author>
578 <author email="person">person</author>
572 <date>1970-01-18T08:40:01+00:00</date>
579 <date>1970-01-18T08:40:01+00:00</date>
573 <msg xml:space="preserve">merge</msg>
580 <msg xml:space="preserve">merge</msg>
574 <paths>
581 <paths>
575 </paths>
582 </paths>
576 </logentry>
583 </logentry>
577 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
584 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
578 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
585 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
579 <author email="person">person</author>
586 <author email="person">person</author>
580 <date>1970-01-18T08:40:00+00:00</date>
587 <date>1970-01-18T08:40:00+00:00</date>
581 <msg xml:space="preserve">new head</msg>
588 <msg xml:space="preserve">new head</msg>
582 <paths>
589 <paths>
583 <path action="A">d</path>
590 <path action="A">d</path>
584 </paths>
591 </paths>
585 </logentry>
592 </logentry>
586 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
593 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
587 <branch>foo</branch>
594 <branch>foo</branch>
588 <author email="person">person</author>
595 <author email="person">person</author>
589 <date>1970-01-17T04:53:20+00:00</date>
596 <date>1970-01-17T04:53:20+00:00</date>
590 <msg xml:space="preserve">new branch</msg>
597 <msg xml:space="preserve">new branch</msg>
591 <paths>
598 <paths>
592 </paths>
599 </paths>
593 </logentry>
600 </logentry>
594 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
601 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
595 <author email="person">person</author>
602 <author email="person">person</author>
596 <date>1970-01-16T01:06:40+00:00</date>
603 <date>1970-01-16T01:06:40+00:00</date>
597 <msg xml:space="preserve">no user, no domain</msg>
604 <msg xml:space="preserve">no user, no domain</msg>
598 <paths>
605 <paths>
599 <path action="M">c</path>
606 <path action="M">c</path>
600 </paths>
607 </paths>
601 </logentry>
608 </logentry>
602 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
609 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
603 <author email="other@place">other</author>
610 <author email="other@place">other</author>
604 <date>1970-01-14T21:20:00+00:00</date>
611 <date>1970-01-14T21:20:00+00:00</date>
605 <msg xml:space="preserve">no person</msg>
612 <msg xml:space="preserve">no person</msg>
606 <paths>
613 <paths>
607 <path action="A">c</path>
614 <path action="A">c</path>
608 </paths>
615 </paths>
609 </logentry>
616 </logentry>
610 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
617 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
611 <author email="other@place">A. N. Other</author>
618 <author email="other@place">A. N. Other</author>
612 <date>1970-01-13T17:33:20+00:00</date>
619 <date>1970-01-13T17:33:20+00:00</date>
613 <msg xml:space="preserve">other 1
620 <msg xml:space="preserve">other 1
614 other 2
621 other 2
615
622
616 other 3</msg>
623 other 3</msg>
617 <paths>
624 <paths>
618 <path action="A">b</path>
625 <path action="A">b</path>
619 </paths>
626 </paths>
620 </logentry>
627 </logentry>
621 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
628 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
622 <author email="user@hostname">User Name</author>
629 <author email="user@hostname">User Name</author>
623 <date>1970-01-12T13:46:40+00:00</date>
630 <date>1970-01-12T13:46:40+00:00</date>
624 <msg xml:space="preserve">line 1
631 <msg xml:space="preserve">line 1
625 line 2</msg>
632 line 2</msg>
626 <paths>
633 <paths>
627 <path action="A">a</path>
634 <path action="A">a</path>
628 </paths>
635 </paths>
629 </logentry>
636 </logentry>
630 </log>
637 </log>
631
638
632 $ hg log --debug --style xml
639 $ hg log --debug --style xml
633 <?xml version="1.0"?>
640 <?xml version="1.0"?>
634 <log>
641 <log>
635 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
642 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
636 <tag>tip</tag>
643 <tag>tip</tag>
637 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
644 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
638 <parent revision="-1" node="0000000000000000000000000000000000000000" />
645 <parent revision="-1" node="0000000000000000000000000000000000000000" />
639 <author email="test">test</author>
646 <author email="test">test</author>
640 <date>2020-01-01T10:01:00+00:00</date>
647 <date>2020-01-01T10:01:00+00:00</date>
641 <msg xml:space="preserve">third</msg>
648 <msg xml:space="preserve">third</msg>
642 <paths>
649 <paths>
643 <path action="A">fourth</path>
650 <path action="A">fourth</path>
644 <path action="A">third</path>
651 <path action="A">third</path>
645 <path action="R">second</path>
652 <path action="R">second</path>
646 </paths>
653 </paths>
647 <copies>
654 <copies>
648 <copy source="second">fourth</copy>
655 <copy source="second">fourth</copy>
649 </copies>
656 </copies>
650 <extra key="branch">default</extra>
657 <extra key="branch">default</extra>
651 </logentry>
658 </logentry>
652 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
659 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
653 <parent revision="-1" node="0000000000000000000000000000000000000000" />
660 <parent revision="-1" node="0000000000000000000000000000000000000000" />
654 <parent revision="-1" node="0000000000000000000000000000000000000000" />
661 <parent revision="-1" node="0000000000000000000000000000000000000000" />
655 <author email="user@hostname">User Name</author>
662 <author email="user@hostname">User Name</author>
656 <date>1970-01-12T13:46:40+00:00</date>
663 <date>1970-01-12T13:46:40+00:00</date>
657 <msg xml:space="preserve">second</msg>
664 <msg xml:space="preserve">second</msg>
658 <paths>
665 <paths>
659 <path action="A">second</path>
666 <path action="A">second</path>
660 </paths>
667 </paths>
661 <extra key="branch">default</extra>
668 <extra key="branch">default</extra>
662 </logentry>
669 </logentry>
663 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
670 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
664 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
671 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
665 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
672 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
666 <author email="person">person</author>
673 <author email="person">person</author>
667 <date>1970-01-18T08:40:01+00:00</date>
674 <date>1970-01-18T08:40:01+00:00</date>
668 <msg xml:space="preserve">merge</msg>
675 <msg xml:space="preserve">merge</msg>
669 <paths>
676 <paths>
670 </paths>
677 </paths>
671 <extra key="branch">default</extra>
678 <extra key="branch">default</extra>
672 </logentry>
679 </logentry>
673 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
680 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
674 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
681 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
675 <parent revision="-1" node="0000000000000000000000000000000000000000" />
682 <parent revision="-1" node="0000000000000000000000000000000000000000" />
676 <author email="person">person</author>
683 <author email="person">person</author>
677 <date>1970-01-18T08:40:00+00:00</date>
684 <date>1970-01-18T08:40:00+00:00</date>
678 <msg xml:space="preserve">new head</msg>
685 <msg xml:space="preserve">new head</msg>
679 <paths>
686 <paths>
680 <path action="A">d</path>
687 <path action="A">d</path>
681 </paths>
688 </paths>
682 <extra key="branch">default</extra>
689 <extra key="branch">default</extra>
683 </logentry>
690 </logentry>
684 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
691 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
685 <branch>foo</branch>
692 <branch>foo</branch>
686 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
693 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
687 <parent revision="-1" node="0000000000000000000000000000000000000000" />
694 <parent revision="-1" node="0000000000000000000000000000000000000000" />
688 <author email="person">person</author>
695 <author email="person">person</author>
689 <date>1970-01-17T04:53:20+00:00</date>
696 <date>1970-01-17T04:53:20+00:00</date>
690 <msg xml:space="preserve">new branch</msg>
697 <msg xml:space="preserve">new branch</msg>
691 <paths>
698 <paths>
692 </paths>
699 </paths>
693 <extra key="branch">foo</extra>
700 <extra key="branch">foo</extra>
694 </logentry>
701 </logentry>
695 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
702 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
696 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
703 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
697 <parent revision="-1" node="0000000000000000000000000000000000000000" />
704 <parent revision="-1" node="0000000000000000000000000000000000000000" />
698 <author email="person">person</author>
705 <author email="person">person</author>
699 <date>1970-01-16T01:06:40+00:00</date>
706 <date>1970-01-16T01:06:40+00:00</date>
700 <msg xml:space="preserve">no user, no domain</msg>
707 <msg xml:space="preserve">no user, no domain</msg>
701 <paths>
708 <paths>
702 <path action="M">c</path>
709 <path action="M">c</path>
703 </paths>
710 </paths>
704 <extra key="branch">default</extra>
711 <extra key="branch">default</extra>
705 </logentry>
712 </logentry>
706 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
713 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
707 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
714 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
708 <parent revision="-1" node="0000000000000000000000000000000000000000" />
715 <parent revision="-1" node="0000000000000000000000000000000000000000" />
709 <author email="other@place">other</author>
716 <author email="other@place">other</author>
710 <date>1970-01-14T21:20:00+00:00</date>
717 <date>1970-01-14T21:20:00+00:00</date>
711 <msg xml:space="preserve">no person</msg>
718 <msg xml:space="preserve">no person</msg>
712 <paths>
719 <paths>
713 <path action="A">c</path>
720 <path action="A">c</path>
714 </paths>
721 </paths>
715 <extra key="branch">default</extra>
722 <extra key="branch">default</extra>
716 </logentry>
723 </logentry>
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
724 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
718 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
725 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
719 <parent revision="-1" node="0000000000000000000000000000000000000000" />
726 <parent revision="-1" node="0000000000000000000000000000000000000000" />
720 <author email="other@place">A. N. Other</author>
727 <author email="other@place">A. N. Other</author>
721 <date>1970-01-13T17:33:20+00:00</date>
728 <date>1970-01-13T17:33:20+00:00</date>
722 <msg xml:space="preserve">other 1
729 <msg xml:space="preserve">other 1
723 other 2
730 other 2
724
731
725 other 3</msg>
732 other 3</msg>
726 <paths>
733 <paths>
727 <path action="A">b</path>
734 <path action="A">b</path>
728 </paths>
735 </paths>
729 <extra key="branch">default</extra>
736 <extra key="branch">default</extra>
730 </logentry>
737 </logentry>
731 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
738 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
732 <parent revision="-1" node="0000000000000000000000000000000000000000" />
739 <parent revision="-1" node="0000000000000000000000000000000000000000" />
733 <parent revision="-1" node="0000000000000000000000000000000000000000" />
740 <parent revision="-1" node="0000000000000000000000000000000000000000" />
734 <author email="user@hostname">User Name</author>
741 <author email="user@hostname">User Name</author>
735 <date>1970-01-12T13:46:40+00:00</date>
742 <date>1970-01-12T13:46:40+00:00</date>
736 <msg xml:space="preserve">line 1
743 <msg xml:space="preserve">line 1
737 line 2</msg>
744 line 2</msg>
738 <paths>
745 <paths>
739 <path action="A">a</path>
746 <path action="A">a</path>
740 </paths>
747 </paths>
741 <extra key="branch">default</extra>
748 <extra key="branch">default</extra>
742 </logentry>
749 </logentry>
743 </log>
750 </log>
744
751
745
752
746 Test JSON style:
753 Test JSON style:
747
754
748 $ hg log -k nosuch -Tjson
755 $ hg log -k nosuch -Tjson
749 []
756 []
750
757
751 $ hg log -qr . -Tjson
758 $ hg log -qr . -Tjson
752 [
759 [
753 {
760 {
754 "rev": 8,
761 "rev": 8,
755 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
762 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
756 }
763 }
757 ]
764 ]
758
765
759 $ hg log -vpr . -Tjson --stat
766 $ hg log -vpr . -Tjson --stat
760 [
767 [
761 {
768 {
762 "rev": 8,
769 "rev": 8,
763 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
770 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
764 "branch": "default",
771 "branch": "default",
765 "phase": "draft",
772 "phase": "draft",
766 "user": "test",
773 "user": "test",
767 "date": [1577872860, 0],
774 "date": [1577872860, 0],
768 "desc": "third",
775 "desc": "third",
769 "bookmarks": [],
776 "bookmarks": [],
770 "tags": ["tip"],
777 "tags": ["tip"],
771 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
778 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
772 "files": ["fourth", "second", "third"],
779 "files": ["fourth", "second", "third"],
773 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
780 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
774 "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"
781 "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"
775 }
782 }
776 ]
783 ]
777
784
778 honor --git but not format-breaking diffopts
785 honor --git but not format-breaking diffopts
779 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
786 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
780 [
787 [
781 {
788 {
782 "rev": 8,
789 "rev": 8,
783 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
790 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
784 "branch": "default",
791 "branch": "default",
785 "phase": "draft",
792 "phase": "draft",
786 "user": "test",
793 "user": "test",
787 "date": [1577872860, 0],
794 "date": [1577872860, 0],
788 "desc": "third",
795 "desc": "third",
789 "bookmarks": [],
796 "bookmarks": [],
790 "tags": ["tip"],
797 "tags": ["tip"],
791 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
798 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
792 "files": ["fourth", "second", "third"],
799 "files": ["fourth", "second", "third"],
793 "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"
800 "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"
794 }
801 }
795 ]
802 ]
796
803
797 $ hg log -T json
804 $ hg log -T json
798 [
805 [
799 {
806 {
800 "rev": 8,
807 "rev": 8,
801 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
808 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
802 "branch": "default",
809 "branch": "default",
803 "phase": "draft",
810 "phase": "draft",
804 "user": "test",
811 "user": "test",
805 "date": [1577872860, 0],
812 "date": [1577872860, 0],
806 "desc": "third",
813 "desc": "third",
807 "bookmarks": [],
814 "bookmarks": [],
808 "tags": ["tip"],
815 "tags": ["tip"],
809 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
816 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
810 },
817 },
811 {
818 {
812 "rev": 7,
819 "rev": 7,
813 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
820 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
814 "branch": "default",
821 "branch": "default",
815 "phase": "draft",
822 "phase": "draft",
816 "user": "User Name <user@hostname>",
823 "user": "User Name <user@hostname>",
817 "date": [1000000, 0],
824 "date": [1000000, 0],
818 "desc": "second",
825 "desc": "second",
819 "bookmarks": [],
826 "bookmarks": [],
820 "tags": [],
827 "tags": [],
821 "parents": ["0000000000000000000000000000000000000000"]
828 "parents": ["0000000000000000000000000000000000000000"]
822 },
829 },
823 {
830 {
824 "rev": 6,
831 "rev": 6,
825 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
832 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
826 "branch": "default",
833 "branch": "default",
827 "phase": "draft",
834 "phase": "draft",
828 "user": "person",
835 "user": "person",
829 "date": [1500001, 0],
836 "date": [1500001, 0],
830 "desc": "merge",
837 "desc": "merge",
831 "bookmarks": [],
838 "bookmarks": [],
832 "tags": [],
839 "tags": [],
833 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
840 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
834 },
841 },
835 {
842 {
836 "rev": 5,
843 "rev": 5,
837 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
844 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
838 "branch": "default",
845 "branch": "default",
839 "phase": "draft",
846 "phase": "draft",
840 "user": "person",
847 "user": "person",
841 "date": [1500000, 0],
848 "date": [1500000, 0],
842 "desc": "new head",
849 "desc": "new head",
843 "bookmarks": [],
850 "bookmarks": [],
844 "tags": [],
851 "tags": [],
845 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
852 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
846 },
853 },
847 {
854 {
848 "rev": 4,
855 "rev": 4,
849 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
856 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
850 "branch": "foo",
857 "branch": "foo",
851 "phase": "draft",
858 "phase": "draft",
852 "user": "person",
859 "user": "person",
853 "date": [1400000, 0],
860 "date": [1400000, 0],
854 "desc": "new branch",
861 "desc": "new branch",
855 "bookmarks": [],
862 "bookmarks": [],
856 "tags": [],
863 "tags": [],
857 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
864 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
858 },
865 },
859 {
866 {
860 "rev": 3,
867 "rev": 3,
861 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
868 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
862 "branch": "default",
869 "branch": "default",
863 "phase": "draft",
870 "phase": "draft",
864 "user": "person",
871 "user": "person",
865 "date": [1300000, 0],
872 "date": [1300000, 0],
866 "desc": "no user, no domain",
873 "desc": "no user, no domain",
867 "bookmarks": [],
874 "bookmarks": [],
868 "tags": [],
875 "tags": [],
869 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
876 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
870 },
877 },
871 {
878 {
872 "rev": 2,
879 "rev": 2,
873 "node": "97054abb4ab824450e9164180baf491ae0078465",
880 "node": "97054abb4ab824450e9164180baf491ae0078465",
874 "branch": "default",
881 "branch": "default",
875 "phase": "draft",
882 "phase": "draft",
876 "user": "other@place",
883 "user": "other@place",
877 "date": [1200000, 0],
884 "date": [1200000, 0],
878 "desc": "no person",
885 "desc": "no person",
879 "bookmarks": [],
886 "bookmarks": [],
880 "tags": [],
887 "tags": [],
881 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
888 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
882 },
889 },
883 {
890 {
884 "rev": 1,
891 "rev": 1,
885 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
892 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
886 "branch": "default",
893 "branch": "default",
887 "phase": "draft",
894 "phase": "draft",
888 "user": "A. N. Other <other@place>",
895 "user": "A. N. Other <other@place>",
889 "date": [1100000, 0],
896 "date": [1100000, 0],
890 "desc": "other 1\nother 2\n\nother 3",
897 "desc": "other 1\nother 2\n\nother 3",
891 "bookmarks": [],
898 "bookmarks": [],
892 "tags": [],
899 "tags": [],
893 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
900 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
894 },
901 },
895 {
902 {
896 "rev": 0,
903 "rev": 0,
897 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
904 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
898 "branch": "default",
905 "branch": "default",
899 "phase": "draft",
906 "phase": "draft",
900 "user": "User Name <user@hostname>",
907 "user": "User Name <user@hostname>",
901 "date": [1000000, 0],
908 "date": [1000000, 0],
902 "desc": "line 1\nline 2",
909 "desc": "line 1\nline 2",
903 "bookmarks": [],
910 "bookmarks": [],
904 "tags": [],
911 "tags": [],
905 "parents": ["0000000000000000000000000000000000000000"]
912 "parents": ["0000000000000000000000000000000000000000"]
906 }
913 }
907 ]
914 ]
908
915
909 $ hg heads -v -Tjson
916 $ hg heads -v -Tjson
910 [
917 [
911 {
918 {
912 "rev": 8,
919 "rev": 8,
913 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
920 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
914 "branch": "default",
921 "branch": "default",
915 "phase": "draft",
922 "phase": "draft",
916 "user": "test",
923 "user": "test",
917 "date": [1577872860, 0],
924 "date": [1577872860, 0],
918 "desc": "third",
925 "desc": "third",
919 "bookmarks": [],
926 "bookmarks": [],
920 "tags": ["tip"],
927 "tags": ["tip"],
921 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
928 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
922 "files": ["fourth", "second", "third"]
929 "files": ["fourth", "second", "third"]
923 },
930 },
924 {
931 {
925 "rev": 6,
932 "rev": 6,
926 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
933 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
927 "branch": "default",
934 "branch": "default",
928 "phase": "draft",
935 "phase": "draft",
929 "user": "person",
936 "user": "person",
930 "date": [1500001, 0],
937 "date": [1500001, 0],
931 "desc": "merge",
938 "desc": "merge",
932 "bookmarks": [],
939 "bookmarks": [],
933 "tags": [],
940 "tags": [],
934 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
941 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
935 "files": []
942 "files": []
936 },
943 },
937 {
944 {
938 "rev": 4,
945 "rev": 4,
939 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
946 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
940 "branch": "foo",
947 "branch": "foo",
941 "phase": "draft",
948 "phase": "draft",
942 "user": "person",
949 "user": "person",
943 "date": [1400000, 0],
950 "date": [1400000, 0],
944 "desc": "new branch",
951 "desc": "new branch",
945 "bookmarks": [],
952 "bookmarks": [],
946 "tags": [],
953 "tags": [],
947 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
954 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
948 "files": []
955 "files": []
949 }
956 }
950 ]
957 ]
951
958
952 $ hg log --debug -Tjson
959 $ hg log --debug -Tjson
953 [
960 [
954 {
961 {
955 "rev": 8,
962 "rev": 8,
956 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
963 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
957 "branch": "default",
964 "branch": "default",
958 "phase": "draft",
965 "phase": "draft",
959 "user": "test",
966 "user": "test",
960 "date": [1577872860, 0],
967 "date": [1577872860, 0],
961 "desc": "third",
968 "desc": "third",
962 "bookmarks": [],
969 "bookmarks": [],
963 "tags": ["tip"],
970 "tags": ["tip"],
964 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
971 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
965 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
972 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
966 "extra": {"branch": "default"},
973 "extra": {"branch": "default"},
967 "modified": [],
974 "modified": [],
968 "added": ["fourth", "third"],
975 "added": ["fourth", "third"],
969 "removed": ["second"]
976 "removed": ["second"]
970 },
977 },
971 {
978 {
972 "rev": 7,
979 "rev": 7,
973 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
980 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
974 "branch": "default",
981 "branch": "default",
975 "phase": "draft",
982 "phase": "draft",
976 "user": "User Name <user@hostname>",
983 "user": "User Name <user@hostname>",
977 "date": [1000000, 0],
984 "date": [1000000, 0],
978 "desc": "second",
985 "desc": "second",
979 "bookmarks": [],
986 "bookmarks": [],
980 "tags": [],
987 "tags": [],
981 "parents": ["0000000000000000000000000000000000000000"],
988 "parents": ["0000000000000000000000000000000000000000"],
982 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
989 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
983 "extra": {"branch": "default"},
990 "extra": {"branch": "default"},
984 "modified": [],
991 "modified": [],
985 "added": ["second"],
992 "added": ["second"],
986 "removed": []
993 "removed": []
987 },
994 },
988 {
995 {
989 "rev": 6,
996 "rev": 6,
990 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
997 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
991 "branch": "default",
998 "branch": "default",
992 "phase": "draft",
999 "phase": "draft",
993 "user": "person",
1000 "user": "person",
994 "date": [1500001, 0],
1001 "date": [1500001, 0],
995 "desc": "merge",
1002 "desc": "merge",
996 "bookmarks": [],
1003 "bookmarks": [],
997 "tags": [],
1004 "tags": [],
998 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1005 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
999 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1006 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1000 "extra": {"branch": "default"},
1007 "extra": {"branch": "default"},
1001 "modified": [],
1008 "modified": [],
1002 "added": [],
1009 "added": [],
1003 "removed": []
1010 "removed": []
1004 },
1011 },
1005 {
1012 {
1006 "rev": 5,
1013 "rev": 5,
1007 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1014 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1008 "branch": "default",
1015 "branch": "default",
1009 "phase": "draft",
1016 "phase": "draft",
1010 "user": "person",
1017 "user": "person",
1011 "date": [1500000, 0],
1018 "date": [1500000, 0],
1012 "desc": "new head",
1019 "desc": "new head",
1013 "bookmarks": [],
1020 "bookmarks": [],
1014 "tags": [],
1021 "tags": [],
1015 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1022 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1016 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1023 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1017 "extra": {"branch": "default"},
1024 "extra": {"branch": "default"},
1018 "modified": [],
1025 "modified": [],
1019 "added": ["d"],
1026 "added": ["d"],
1020 "removed": []
1027 "removed": []
1021 },
1028 },
1022 {
1029 {
1023 "rev": 4,
1030 "rev": 4,
1024 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1031 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1025 "branch": "foo",
1032 "branch": "foo",
1026 "phase": "draft",
1033 "phase": "draft",
1027 "user": "person",
1034 "user": "person",
1028 "date": [1400000, 0],
1035 "date": [1400000, 0],
1029 "desc": "new branch",
1036 "desc": "new branch",
1030 "bookmarks": [],
1037 "bookmarks": [],
1031 "tags": [],
1038 "tags": [],
1032 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1039 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1033 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1040 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1034 "extra": {"branch": "foo"},
1041 "extra": {"branch": "foo"},
1035 "modified": [],
1042 "modified": [],
1036 "added": [],
1043 "added": [],
1037 "removed": []
1044 "removed": []
1038 },
1045 },
1039 {
1046 {
1040 "rev": 3,
1047 "rev": 3,
1041 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1048 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1042 "branch": "default",
1049 "branch": "default",
1043 "phase": "draft",
1050 "phase": "draft",
1044 "user": "person",
1051 "user": "person",
1045 "date": [1300000, 0],
1052 "date": [1300000, 0],
1046 "desc": "no user, no domain",
1053 "desc": "no user, no domain",
1047 "bookmarks": [],
1054 "bookmarks": [],
1048 "tags": [],
1055 "tags": [],
1049 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1056 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1050 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1057 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1051 "extra": {"branch": "default"},
1058 "extra": {"branch": "default"},
1052 "modified": ["c"],
1059 "modified": ["c"],
1053 "added": [],
1060 "added": [],
1054 "removed": []
1061 "removed": []
1055 },
1062 },
1056 {
1063 {
1057 "rev": 2,
1064 "rev": 2,
1058 "node": "97054abb4ab824450e9164180baf491ae0078465",
1065 "node": "97054abb4ab824450e9164180baf491ae0078465",
1059 "branch": "default",
1066 "branch": "default",
1060 "phase": "draft",
1067 "phase": "draft",
1061 "user": "other@place",
1068 "user": "other@place",
1062 "date": [1200000, 0],
1069 "date": [1200000, 0],
1063 "desc": "no person",
1070 "desc": "no person",
1064 "bookmarks": [],
1071 "bookmarks": [],
1065 "tags": [],
1072 "tags": [],
1066 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1073 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1067 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1074 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1068 "extra": {"branch": "default"},
1075 "extra": {"branch": "default"},
1069 "modified": [],
1076 "modified": [],
1070 "added": ["c"],
1077 "added": ["c"],
1071 "removed": []
1078 "removed": []
1072 },
1079 },
1073 {
1080 {
1074 "rev": 1,
1081 "rev": 1,
1075 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1082 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1076 "branch": "default",
1083 "branch": "default",
1077 "phase": "draft",
1084 "phase": "draft",
1078 "user": "A. N. Other <other@place>",
1085 "user": "A. N. Other <other@place>",
1079 "date": [1100000, 0],
1086 "date": [1100000, 0],
1080 "desc": "other 1\nother 2\n\nother 3",
1087 "desc": "other 1\nother 2\n\nother 3",
1081 "bookmarks": [],
1088 "bookmarks": [],
1082 "tags": [],
1089 "tags": [],
1083 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1090 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1084 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1091 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1085 "extra": {"branch": "default"},
1092 "extra": {"branch": "default"},
1086 "modified": [],
1093 "modified": [],
1087 "added": ["b"],
1094 "added": ["b"],
1088 "removed": []
1095 "removed": []
1089 },
1096 },
1090 {
1097 {
1091 "rev": 0,
1098 "rev": 0,
1092 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1099 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1093 "branch": "default",
1100 "branch": "default",
1094 "phase": "draft",
1101 "phase": "draft",
1095 "user": "User Name <user@hostname>",
1102 "user": "User Name <user@hostname>",
1096 "date": [1000000, 0],
1103 "date": [1000000, 0],
1097 "desc": "line 1\nline 2",
1104 "desc": "line 1\nline 2",
1098 "bookmarks": [],
1105 "bookmarks": [],
1099 "tags": [],
1106 "tags": [],
1100 "parents": ["0000000000000000000000000000000000000000"],
1107 "parents": ["0000000000000000000000000000000000000000"],
1101 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1108 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1102 "extra": {"branch": "default"},
1109 "extra": {"branch": "default"},
1103 "modified": [],
1110 "modified": [],
1104 "added": ["a"],
1111 "added": ["a"],
1105 "removed": []
1112 "removed": []
1106 }
1113 }
1107 ]
1114 ]
1108
1115
1109 Error if style not readable:
1116 Error if style not readable:
1110
1117
1111 #if unix-permissions no-root
1118 #if unix-permissions no-root
1112 $ touch q
1119 $ touch q
1113 $ chmod 0 q
1120 $ chmod 0 q
1114 $ hg log --style ./q
1121 $ hg log --style ./q
1115 abort: Permission denied: ./q
1122 abort: Permission denied: ./q
1116 [255]
1123 [255]
1117 #endif
1124 #endif
1118
1125
1119 Error if no style:
1126 Error if no style:
1120
1127
1121 $ hg log --style notexist
1128 $ hg log --style notexist
1122 abort: style 'notexist' not found
1129 abort: style 'notexist' not found
1123 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1130 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1124 [255]
1131 [255]
1125
1132
1126 $ hg log -T list
1133 $ hg log -T list
1127 available styles: bisect, changelog, compact, default, phases, show, status, xml
1134 available styles: bisect, changelog, compact, default, phases, show, status, xml
1128 abort: specify a template
1135 abort: specify a template
1129 [255]
1136 [255]
1130
1137
1131 Error if style missing key:
1138 Error if style missing key:
1132
1139
1133 $ echo 'q = q' > t
1140 $ echo 'q = q' > t
1134 $ hg log --style ./t
1141 $ hg log --style ./t
1135 abort: "changeset" not in template map
1142 abort: "changeset" not in template map
1136 [255]
1143 [255]
1137
1144
1138 Error if style missing value:
1145 Error if style missing value:
1139
1146
1140 $ echo 'changeset =' > t
1147 $ echo 'changeset =' > t
1141 $ hg log --style t
1148 $ hg log --style t
1142 hg: parse error at t:1: missing value
1149 hg: parse error at t:1: missing value
1143 [255]
1150 [255]
1144
1151
1145 Error if include fails:
1152 Error if include fails:
1146
1153
1147 $ echo 'changeset = q' >> t
1154 $ echo 'changeset = q' >> t
1148 #if unix-permissions no-root
1155 #if unix-permissions no-root
1149 $ hg log --style ./t
1156 $ hg log --style ./t
1150 abort: template file ./q: Permission denied
1157 abort: template file ./q: Permission denied
1151 [255]
1158 [255]
1152 $ rm -f q
1159 $ rm -f q
1153 #endif
1160 #endif
1154
1161
1155 Include works:
1162 Include works:
1156
1163
1157 $ echo '{rev}' > q
1164 $ echo '{rev}' > q
1158 $ hg log --style ./t
1165 $ hg log --style ./t
1159 8
1166 8
1160 7
1167 7
1161 6
1168 6
1162 5
1169 5
1163 4
1170 4
1164 3
1171 3
1165 2
1172 2
1166 1
1173 1
1167 0
1174 0
1168
1175
1169 Check that recursive reference does not fall into RuntimeError (issue4758):
1176 Check that recursive reference does not fall into RuntimeError (issue4758):
1170
1177
1171 common mistake:
1178 common mistake:
1172
1179
1173 $ hg log -T '{changeset}\n'
1180 $ hg log -T '{changeset}\n'
1174 abort: recursive reference 'changeset' in template
1181 abort: recursive reference 'changeset' in template
1175 [255]
1182 [255]
1176
1183
1177 circular reference:
1184 circular reference:
1178
1185
1179 $ cat << EOF > issue4758
1186 $ cat << EOF > issue4758
1180 > changeset = '{foo}'
1187 > changeset = '{foo}'
1181 > foo = '{changeset}'
1188 > foo = '{changeset}'
1182 > EOF
1189 > EOF
1183 $ hg log --style ./issue4758
1190 $ hg log --style ./issue4758
1184 abort: recursive reference 'foo' in template
1191 abort: recursive reference 'foo' in template
1185 [255]
1192 [255]
1186
1193
1187 buildmap() -> gettemplate(), where no thunk was made:
1194 buildmap() -> gettemplate(), where no thunk was made:
1188
1195
1189 $ hg log -T '{files % changeset}\n'
1196 $ hg log -T '{files % changeset}\n'
1190 abort: recursive reference 'changeset' in template
1197 abort: recursive reference 'changeset' in template
1191 [255]
1198 [255]
1192
1199
1193 not a recursion if a keyword of the same name exists:
1200 not a recursion if a keyword of the same name exists:
1194
1201
1195 $ cat << EOF > issue4758
1202 $ cat << EOF > issue4758
1196 > changeset = '{tags % rev}'
1203 > changeset = '{tags % rev}'
1197 > rev = '{rev} {tag}\n'
1204 > rev = '{rev} {tag}\n'
1198 > EOF
1205 > EOF
1199 $ hg log --style ./issue4758 -r tip
1206 $ hg log --style ./issue4758 -r tip
1200 8 tip
1207 8 tip
1201
1208
1202 Check that {phase} works correctly on parents:
1209 Check that {phase} works correctly on parents:
1203
1210
1204 $ cat << EOF > parentphase
1211 $ cat << EOF > parentphase
1205 > changeset_debug = '{rev} ({phase}):{parents}\n'
1212 > changeset_debug = '{rev} ({phase}):{parents}\n'
1206 > parent = ' {rev} ({phase})'
1213 > parent = ' {rev} ({phase})'
1207 > EOF
1214 > EOF
1208 $ hg phase -r 5 --public
1215 $ hg phase -r 5 --public
1209 $ hg phase -r 7 --secret --force
1216 $ hg phase -r 7 --secret --force
1210 $ hg log --debug -G --style ./parentphase
1217 $ hg log --debug -G --style ./parentphase
1211 @ 8 (secret): 7 (secret) -1 (public)
1218 @ 8 (secret): 7 (secret) -1 (public)
1212 |
1219 |
1213 o 7 (secret): -1 (public) -1 (public)
1220 o 7 (secret): -1 (public) -1 (public)
1214
1221
1215 o 6 (draft): 5 (public) 4 (draft)
1222 o 6 (draft): 5 (public) 4 (draft)
1216 |\
1223 |\
1217 | o 5 (public): 3 (public) -1 (public)
1224 | o 5 (public): 3 (public) -1 (public)
1218 | |
1225 | |
1219 o | 4 (draft): 3 (public) -1 (public)
1226 o | 4 (draft): 3 (public) -1 (public)
1220 |/
1227 |/
1221 o 3 (public): 2 (public) -1 (public)
1228 o 3 (public): 2 (public) -1 (public)
1222 |
1229 |
1223 o 2 (public): 1 (public) -1 (public)
1230 o 2 (public): 1 (public) -1 (public)
1224 |
1231 |
1225 o 1 (public): 0 (public) -1 (public)
1232 o 1 (public): 0 (public) -1 (public)
1226 |
1233 |
1227 o 0 (public): -1 (public) -1 (public)
1234 o 0 (public): -1 (public) -1 (public)
1228
1235
1229
1236
1230 Missing non-standard names give no error (backward compatibility):
1237 Missing non-standard names give no error (backward compatibility):
1231
1238
1232 $ echo "changeset = '{c}'" > t
1239 $ echo "changeset = '{c}'" > t
1233 $ hg log --style ./t
1240 $ hg log --style ./t
1234
1241
1235 Defining non-standard name works:
1242 Defining non-standard name works:
1236
1243
1237 $ cat <<EOF > t
1244 $ cat <<EOF > t
1238 > changeset = '{c}'
1245 > changeset = '{c}'
1239 > c = q
1246 > c = q
1240 > EOF
1247 > EOF
1241 $ hg log --style ./t
1248 $ hg log --style ./t
1242 8
1249 8
1243 7
1250 7
1244 6
1251 6
1245 5
1252 5
1246 4
1253 4
1247 3
1254 3
1248 2
1255 2
1249 1
1256 1
1250 0
1257 0
1251
1258
1252 ui.style works:
1259 ui.style works:
1253
1260
1254 $ echo '[ui]' > .hg/hgrc
1261 $ echo '[ui]' > .hg/hgrc
1255 $ echo 'style = t' >> .hg/hgrc
1262 $ echo 'style = t' >> .hg/hgrc
1256 $ hg log
1263 $ hg log
1257 8
1264 8
1258 7
1265 7
1259 6
1266 6
1260 5
1267 5
1261 4
1268 4
1262 3
1269 3
1263 2
1270 2
1264 1
1271 1
1265 0
1272 0
1266
1273
1267
1274
1268 Issue338:
1275 Issue338:
1269
1276
1270 $ hg log --style=changelog > changelog
1277 $ hg log --style=changelog > changelog
1271
1278
1272 $ cat changelog
1279 $ cat changelog
1273 2020-01-01 test <test>
1280 2020-01-01 test <test>
1274
1281
1275 * fourth, second, third:
1282 * fourth, second, third:
1276 third
1283 third
1277 [95c24699272e] [tip]
1284 [95c24699272e] [tip]
1278
1285
1279 1970-01-12 User Name <user@hostname>
1286 1970-01-12 User Name <user@hostname>
1280
1287
1281 * second:
1288 * second:
1282 second
1289 second
1283 [29114dbae42b]
1290 [29114dbae42b]
1284
1291
1285 1970-01-18 person <person>
1292 1970-01-18 person <person>
1286
1293
1287 * merge
1294 * merge
1288 [d41e714fe50d]
1295 [d41e714fe50d]
1289
1296
1290 * d:
1297 * d:
1291 new head
1298 new head
1292 [13207e5a10d9]
1299 [13207e5a10d9]
1293
1300
1294 1970-01-17 person <person>
1301 1970-01-17 person <person>
1295
1302
1296 * new branch
1303 * new branch
1297 [bbe44766e73d] <foo>
1304 [bbe44766e73d] <foo>
1298
1305
1299 1970-01-16 person <person>
1306 1970-01-16 person <person>
1300
1307
1301 * c:
1308 * c:
1302 no user, no domain
1309 no user, no domain
1303 [10e46f2dcbf4]
1310 [10e46f2dcbf4]
1304
1311
1305 1970-01-14 other <other@place>
1312 1970-01-14 other <other@place>
1306
1313
1307 * c:
1314 * c:
1308 no person
1315 no person
1309 [97054abb4ab8]
1316 [97054abb4ab8]
1310
1317
1311 1970-01-13 A. N. Other <other@place>
1318 1970-01-13 A. N. Other <other@place>
1312
1319
1313 * b:
1320 * b:
1314 other 1 other 2
1321 other 1 other 2
1315
1322
1316 other 3
1323 other 3
1317 [b608e9d1a3f0]
1324 [b608e9d1a3f0]
1318
1325
1319 1970-01-12 User Name <user@hostname>
1326 1970-01-12 User Name <user@hostname>
1320
1327
1321 * a:
1328 * a:
1322 line 1 line 2
1329 line 1 line 2
1323 [1e4e1b8f71e0]
1330 [1e4e1b8f71e0]
1324
1331
1325
1332
1326 Issue2130: xml output for 'hg heads' is malformed
1333 Issue2130: xml output for 'hg heads' is malformed
1327
1334
1328 $ hg heads --style changelog
1335 $ hg heads --style changelog
1329 2020-01-01 test <test>
1336 2020-01-01 test <test>
1330
1337
1331 * fourth, second, third:
1338 * fourth, second, third:
1332 third
1339 third
1333 [95c24699272e] [tip]
1340 [95c24699272e] [tip]
1334
1341
1335 1970-01-18 person <person>
1342 1970-01-18 person <person>
1336
1343
1337 * merge
1344 * merge
1338 [d41e714fe50d]
1345 [d41e714fe50d]
1339
1346
1340 1970-01-17 person <person>
1347 1970-01-17 person <person>
1341
1348
1342 * new branch
1349 * new branch
1343 [bbe44766e73d] <foo>
1350 [bbe44766e73d] <foo>
1344
1351
1345
1352
1346 Keys work:
1353 Keys work:
1347
1354
1348 $ for key in author branch branches date desc file_adds file_dels file_mods \
1355 $ for key in author branch branches date desc file_adds file_dels file_mods \
1349 > file_copies file_copies_switch files \
1356 > file_copies file_copies_switch files \
1350 > manifest node parents rev tags diffstat extras \
1357 > manifest node parents rev tags diffstat extras \
1351 > p1rev p2rev p1node p2node; do
1358 > p1rev p2rev p1node p2node; do
1352 > for mode in '' --verbose --debug; do
1359 > for mode in '' --verbose --debug; do
1353 > hg log $mode --template "$key$mode: {$key}\n"
1360 > hg log $mode --template "$key$mode: {$key}\n"
1354 > done
1361 > done
1355 > done
1362 > done
1356 author: test
1363 author: test
1357 author: User Name <user@hostname>
1364 author: User Name <user@hostname>
1358 author: person
1365 author: person
1359 author: person
1366 author: person
1360 author: person
1367 author: person
1361 author: person
1368 author: person
1362 author: other@place
1369 author: other@place
1363 author: A. N. Other <other@place>
1370 author: A. N. Other <other@place>
1364 author: User Name <user@hostname>
1371 author: User Name <user@hostname>
1365 author--verbose: test
1372 author--verbose: test
1366 author--verbose: User Name <user@hostname>
1373 author--verbose: User Name <user@hostname>
1367 author--verbose: person
1374 author--verbose: person
1368 author--verbose: person
1375 author--verbose: person
1369 author--verbose: person
1376 author--verbose: person
1370 author--verbose: person
1377 author--verbose: person
1371 author--verbose: other@place
1378 author--verbose: other@place
1372 author--verbose: A. N. Other <other@place>
1379 author--verbose: A. N. Other <other@place>
1373 author--verbose: User Name <user@hostname>
1380 author--verbose: User Name <user@hostname>
1374 author--debug: test
1381 author--debug: test
1375 author--debug: User Name <user@hostname>
1382 author--debug: User Name <user@hostname>
1376 author--debug: person
1383 author--debug: person
1377 author--debug: person
1384 author--debug: person
1378 author--debug: person
1385 author--debug: person
1379 author--debug: person
1386 author--debug: person
1380 author--debug: other@place
1387 author--debug: other@place
1381 author--debug: A. N. Other <other@place>
1388 author--debug: A. N. Other <other@place>
1382 author--debug: User Name <user@hostname>
1389 author--debug: User Name <user@hostname>
1383 branch: default
1390 branch: default
1384 branch: default
1391 branch: default
1385 branch: default
1392 branch: default
1386 branch: default
1393 branch: default
1387 branch: foo
1394 branch: foo
1388 branch: default
1395 branch: default
1389 branch: default
1396 branch: default
1390 branch: default
1397 branch: default
1391 branch: default
1398 branch: default
1392 branch--verbose: default
1399 branch--verbose: default
1393 branch--verbose: default
1400 branch--verbose: default
1394 branch--verbose: default
1401 branch--verbose: default
1395 branch--verbose: default
1402 branch--verbose: default
1396 branch--verbose: foo
1403 branch--verbose: foo
1397 branch--verbose: default
1404 branch--verbose: default
1398 branch--verbose: default
1405 branch--verbose: default
1399 branch--verbose: default
1406 branch--verbose: default
1400 branch--verbose: default
1407 branch--verbose: default
1401 branch--debug: default
1408 branch--debug: default
1402 branch--debug: default
1409 branch--debug: default
1403 branch--debug: default
1410 branch--debug: default
1404 branch--debug: default
1411 branch--debug: default
1405 branch--debug: foo
1412 branch--debug: foo
1406 branch--debug: default
1413 branch--debug: default
1407 branch--debug: default
1414 branch--debug: default
1408 branch--debug: default
1415 branch--debug: default
1409 branch--debug: default
1416 branch--debug: default
1410 branches:
1417 branches:
1411 branches:
1418 branches:
1412 branches:
1419 branches:
1413 branches:
1420 branches:
1414 branches: foo
1421 branches: foo
1415 branches:
1422 branches:
1416 branches:
1423 branches:
1417 branches:
1424 branches:
1418 branches:
1425 branches:
1419 branches--verbose:
1426 branches--verbose:
1420 branches--verbose:
1427 branches--verbose:
1421 branches--verbose:
1428 branches--verbose:
1422 branches--verbose:
1429 branches--verbose:
1423 branches--verbose: foo
1430 branches--verbose: foo
1424 branches--verbose:
1431 branches--verbose:
1425 branches--verbose:
1432 branches--verbose:
1426 branches--verbose:
1433 branches--verbose:
1427 branches--verbose:
1434 branches--verbose:
1428 branches--debug:
1435 branches--debug:
1429 branches--debug:
1436 branches--debug:
1430 branches--debug:
1437 branches--debug:
1431 branches--debug:
1438 branches--debug:
1432 branches--debug: foo
1439 branches--debug: foo
1433 branches--debug:
1440 branches--debug:
1434 branches--debug:
1441 branches--debug:
1435 branches--debug:
1442 branches--debug:
1436 branches--debug:
1443 branches--debug:
1437 date: 1577872860.00
1444 date: 1577872860.00
1438 date: 1000000.00
1445 date: 1000000.00
1439 date: 1500001.00
1446 date: 1500001.00
1440 date: 1500000.00
1447 date: 1500000.00
1441 date: 1400000.00
1448 date: 1400000.00
1442 date: 1300000.00
1449 date: 1300000.00
1443 date: 1200000.00
1450 date: 1200000.00
1444 date: 1100000.00
1451 date: 1100000.00
1445 date: 1000000.00
1452 date: 1000000.00
1446 date--verbose: 1577872860.00
1453 date--verbose: 1577872860.00
1447 date--verbose: 1000000.00
1454 date--verbose: 1000000.00
1448 date--verbose: 1500001.00
1455 date--verbose: 1500001.00
1449 date--verbose: 1500000.00
1456 date--verbose: 1500000.00
1450 date--verbose: 1400000.00
1457 date--verbose: 1400000.00
1451 date--verbose: 1300000.00
1458 date--verbose: 1300000.00
1452 date--verbose: 1200000.00
1459 date--verbose: 1200000.00
1453 date--verbose: 1100000.00
1460 date--verbose: 1100000.00
1454 date--verbose: 1000000.00
1461 date--verbose: 1000000.00
1455 date--debug: 1577872860.00
1462 date--debug: 1577872860.00
1456 date--debug: 1000000.00
1463 date--debug: 1000000.00
1457 date--debug: 1500001.00
1464 date--debug: 1500001.00
1458 date--debug: 1500000.00
1465 date--debug: 1500000.00
1459 date--debug: 1400000.00
1466 date--debug: 1400000.00
1460 date--debug: 1300000.00
1467 date--debug: 1300000.00
1461 date--debug: 1200000.00
1468 date--debug: 1200000.00
1462 date--debug: 1100000.00
1469 date--debug: 1100000.00
1463 date--debug: 1000000.00
1470 date--debug: 1000000.00
1464 desc: third
1471 desc: third
1465 desc: second
1472 desc: second
1466 desc: merge
1473 desc: merge
1467 desc: new head
1474 desc: new head
1468 desc: new branch
1475 desc: new branch
1469 desc: no user, no domain
1476 desc: no user, no domain
1470 desc: no person
1477 desc: no person
1471 desc: other 1
1478 desc: other 1
1472 other 2
1479 other 2
1473
1480
1474 other 3
1481 other 3
1475 desc: line 1
1482 desc: line 1
1476 line 2
1483 line 2
1477 desc--verbose: third
1484 desc--verbose: third
1478 desc--verbose: second
1485 desc--verbose: second
1479 desc--verbose: merge
1486 desc--verbose: merge
1480 desc--verbose: new head
1487 desc--verbose: new head
1481 desc--verbose: new branch
1488 desc--verbose: new branch
1482 desc--verbose: no user, no domain
1489 desc--verbose: no user, no domain
1483 desc--verbose: no person
1490 desc--verbose: no person
1484 desc--verbose: other 1
1491 desc--verbose: other 1
1485 other 2
1492 other 2
1486
1493
1487 other 3
1494 other 3
1488 desc--verbose: line 1
1495 desc--verbose: line 1
1489 line 2
1496 line 2
1490 desc--debug: third
1497 desc--debug: third
1491 desc--debug: second
1498 desc--debug: second
1492 desc--debug: merge
1499 desc--debug: merge
1493 desc--debug: new head
1500 desc--debug: new head
1494 desc--debug: new branch
1501 desc--debug: new branch
1495 desc--debug: no user, no domain
1502 desc--debug: no user, no domain
1496 desc--debug: no person
1503 desc--debug: no person
1497 desc--debug: other 1
1504 desc--debug: other 1
1498 other 2
1505 other 2
1499
1506
1500 other 3
1507 other 3
1501 desc--debug: line 1
1508 desc--debug: line 1
1502 line 2
1509 line 2
1503 file_adds: fourth third
1510 file_adds: fourth third
1504 file_adds: second
1511 file_adds: second
1505 file_adds:
1512 file_adds:
1506 file_adds: d
1513 file_adds: d
1507 file_adds:
1514 file_adds:
1508 file_adds:
1515 file_adds:
1509 file_adds: c
1516 file_adds: c
1510 file_adds: b
1517 file_adds: b
1511 file_adds: a
1518 file_adds: a
1512 file_adds--verbose: fourth third
1519 file_adds--verbose: fourth third
1513 file_adds--verbose: second
1520 file_adds--verbose: second
1514 file_adds--verbose:
1521 file_adds--verbose:
1515 file_adds--verbose: d
1522 file_adds--verbose: d
1516 file_adds--verbose:
1523 file_adds--verbose:
1517 file_adds--verbose:
1524 file_adds--verbose:
1518 file_adds--verbose: c
1525 file_adds--verbose: c
1519 file_adds--verbose: b
1526 file_adds--verbose: b
1520 file_adds--verbose: a
1527 file_adds--verbose: a
1521 file_adds--debug: fourth third
1528 file_adds--debug: fourth third
1522 file_adds--debug: second
1529 file_adds--debug: second
1523 file_adds--debug:
1530 file_adds--debug:
1524 file_adds--debug: d
1531 file_adds--debug: d
1525 file_adds--debug:
1532 file_adds--debug:
1526 file_adds--debug:
1533 file_adds--debug:
1527 file_adds--debug: c
1534 file_adds--debug: c
1528 file_adds--debug: b
1535 file_adds--debug: b
1529 file_adds--debug: a
1536 file_adds--debug: a
1530 file_dels: second
1537 file_dels: second
1531 file_dels:
1538 file_dels:
1532 file_dels:
1539 file_dels:
1533 file_dels:
1540 file_dels:
1534 file_dels:
1541 file_dels:
1535 file_dels:
1542 file_dels:
1536 file_dels:
1543 file_dels:
1537 file_dels:
1544 file_dels:
1538 file_dels:
1545 file_dels:
1539 file_dels--verbose: second
1546 file_dels--verbose: second
1540 file_dels--verbose:
1547 file_dels--verbose:
1541 file_dels--verbose:
1548 file_dels--verbose:
1542 file_dels--verbose:
1549 file_dels--verbose:
1543 file_dels--verbose:
1550 file_dels--verbose:
1544 file_dels--verbose:
1551 file_dels--verbose:
1545 file_dels--verbose:
1552 file_dels--verbose:
1546 file_dels--verbose:
1553 file_dels--verbose:
1547 file_dels--verbose:
1554 file_dels--verbose:
1548 file_dels--debug: second
1555 file_dels--debug: second
1549 file_dels--debug:
1556 file_dels--debug:
1550 file_dels--debug:
1557 file_dels--debug:
1551 file_dels--debug:
1558 file_dels--debug:
1552 file_dels--debug:
1559 file_dels--debug:
1553 file_dels--debug:
1560 file_dels--debug:
1554 file_dels--debug:
1561 file_dels--debug:
1555 file_dels--debug:
1562 file_dels--debug:
1556 file_dels--debug:
1563 file_dels--debug:
1557 file_mods:
1564 file_mods:
1558 file_mods:
1565 file_mods:
1559 file_mods:
1566 file_mods:
1560 file_mods:
1567 file_mods:
1561 file_mods:
1568 file_mods:
1562 file_mods: c
1569 file_mods: c
1563 file_mods:
1570 file_mods:
1564 file_mods:
1571 file_mods:
1565 file_mods:
1572 file_mods:
1566 file_mods--verbose:
1573 file_mods--verbose:
1567 file_mods--verbose:
1574 file_mods--verbose:
1568 file_mods--verbose:
1575 file_mods--verbose:
1569 file_mods--verbose:
1576 file_mods--verbose:
1570 file_mods--verbose:
1577 file_mods--verbose:
1571 file_mods--verbose: c
1578 file_mods--verbose: c
1572 file_mods--verbose:
1579 file_mods--verbose:
1573 file_mods--verbose:
1580 file_mods--verbose:
1574 file_mods--verbose:
1581 file_mods--verbose:
1575 file_mods--debug:
1582 file_mods--debug:
1576 file_mods--debug:
1583 file_mods--debug:
1577 file_mods--debug:
1584 file_mods--debug:
1578 file_mods--debug:
1585 file_mods--debug:
1579 file_mods--debug:
1586 file_mods--debug:
1580 file_mods--debug: c
1587 file_mods--debug: c
1581 file_mods--debug:
1588 file_mods--debug:
1582 file_mods--debug:
1589 file_mods--debug:
1583 file_mods--debug:
1590 file_mods--debug:
1584 file_copies: fourth (second)
1591 file_copies: fourth (second)
1585 file_copies:
1592 file_copies:
1586 file_copies:
1593 file_copies:
1587 file_copies:
1594 file_copies:
1588 file_copies:
1595 file_copies:
1589 file_copies:
1596 file_copies:
1590 file_copies:
1597 file_copies:
1591 file_copies:
1598 file_copies:
1592 file_copies:
1599 file_copies:
1593 file_copies--verbose: fourth (second)
1600 file_copies--verbose: fourth (second)
1594 file_copies--verbose:
1601 file_copies--verbose:
1595 file_copies--verbose:
1602 file_copies--verbose:
1596 file_copies--verbose:
1603 file_copies--verbose:
1597 file_copies--verbose:
1604 file_copies--verbose:
1598 file_copies--verbose:
1605 file_copies--verbose:
1599 file_copies--verbose:
1606 file_copies--verbose:
1600 file_copies--verbose:
1607 file_copies--verbose:
1601 file_copies--verbose:
1608 file_copies--verbose:
1602 file_copies--debug: fourth (second)
1609 file_copies--debug: fourth (second)
1603 file_copies--debug:
1610 file_copies--debug:
1604 file_copies--debug:
1611 file_copies--debug:
1605 file_copies--debug:
1612 file_copies--debug:
1606 file_copies--debug:
1613 file_copies--debug:
1607 file_copies--debug:
1614 file_copies--debug:
1608 file_copies--debug:
1615 file_copies--debug:
1609 file_copies--debug:
1616 file_copies--debug:
1610 file_copies--debug:
1617 file_copies--debug:
1611 file_copies_switch:
1618 file_copies_switch:
1612 file_copies_switch:
1619 file_copies_switch:
1613 file_copies_switch:
1620 file_copies_switch:
1614 file_copies_switch:
1621 file_copies_switch:
1615 file_copies_switch:
1622 file_copies_switch:
1616 file_copies_switch:
1623 file_copies_switch:
1617 file_copies_switch:
1624 file_copies_switch:
1618 file_copies_switch:
1625 file_copies_switch:
1619 file_copies_switch:
1626 file_copies_switch:
1620 file_copies_switch--verbose:
1627 file_copies_switch--verbose:
1621 file_copies_switch--verbose:
1628 file_copies_switch--verbose:
1622 file_copies_switch--verbose:
1629 file_copies_switch--verbose:
1623 file_copies_switch--verbose:
1630 file_copies_switch--verbose:
1624 file_copies_switch--verbose:
1631 file_copies_switch--verbose:
1625 file_copies_switch--verbose:
1632 file_copies_switch--verbose:
1626 file_copies_switch--verbose:
1633 file_copies_switch--verbose:
1627 file_copies_switch--verbose:
1634 file_copies_switch--verbose:
1628 file_copies_switch--verbose:
1635 file_copies_switch--verbose:
1629 file_copies_switch--debug:
1636 file_copies_switch--debug:
1630 file_copies_switch--debug:
1637 file_copies_switch--debug:
1631 file_copies_switch--debug:
1638 file_copies_switch--debug:
1632 file_copies_switch--debug:
1639 file_copies_switch--debug:
1633 file_copies_switch--debug:
1640 file_copies_switch--debug:
1634 file_copies_switch--debug:
1641 file_copies_switch--debug:
1635 file_copies_switch--debug:
1642 file_copies_switch--debug:
1636 file_copies_switch--debug:
1643 file_copies_switch--debug:
1637 file_copies_switch--debug:
1644 file_copies_switch--debug:
1638 files: fourth second third
1645 files: fourth second third
1639 files: second
1646 files: second
1640 files:
1647 files:
1641 files: d
1648 files: d
1642 files:
1649 files:
1643 files: c
1650 files: c
1644 files: c
1651 files: c
1645 files: b
1652 files: b
1646 files: a
1653 files: a
1647 files--verbose: fourth second third
1654 files--verbose: fourth second third
1648 files--verbose: second
1655 files--verbose: second
1649 files--verbose:
1656 files--verbose:
1650 files--verbose: d
1657 files--verbose: d
1651 files--verbose:
1658 files--verbose:
1652 files--verbose: c
1659 files--verbose: c
1653 files--verbose: c
1660 files--verbose: c
1654 files--verbose: b
1661 files--verbose: b
1655 files--verbose: a
1662 files--verbose: a
1656 files--debug: fourth second third
1663 files--debug: fourth second third
1657 files--debug: second
1664 files--debug: second
1658 files--debug:
1665 files--debug:
1659 files--debug: d
1666 files--debug: d
1660 files--debug:
1667 files--debug:
1661 files--debug: c
1668 files--debug: c
1662 files--debug: c
1669 files--debug: c
1663 files--debug: b
1670 files--debug: b
1664 files--debug: a
1671 files--debug: a
1665 manifest: 6:94961b75a2da
1672 manifest: 6:94961b75a2da
1666 manifest: 5:f2dbc354b94e
1673 manifest: 5:f2dbc354b94e
1667 manifest: 4:4dc3def4f9b4
1674 manifest: 4:4dc3def4f9b4
1668 manifest: 4:4dc3def4f9b4
1675 manifest: 4:4dc3def4f9b4
1669 manifest: 3:cb5a1327723b
1676 manifest: 3:cb5a1327723b
1670 manifest: 3:cb5a1327723b
1677 manifest: 3:cb5a1327723b
1671 manifest: 2:6e0e82995c35
1678 manifest: 2:6e0e82995c35
1672 manifest: 1:4e8d705b1e53
1679 manifest: 1:4e8d705b1e53
1673 manifest: 0:a0c8bcbbb45c
1680 manifest: 0:a0c8bcbbb45c
1674 manifest--verbose: 6:94961b75a2da
1681 manifest--verbose: 6:94961b75a2da
1675 manifest--verbose: 5:f2dbc354b94e
1682 manifest--verbose: 5:f2dbc354b94e
1676 manifest--verbose: 4:4dc3def4f9b4
1683 manifest--verbose: 4:4dc3def4f9b4
1677 manifest--verbose: 4:4dc3def4f9b4
1684 manifest--verbose: 4:4dc3def4f9b4
1678 manifest--verbose: 3:cb5a1327723b
1685 manifest--verbose: 3:cb5a1327723b
1679 manifest--verbose: 3:cb5a1327723b
1686 manifest--verbose: 3:cb5a1327723b
1680 manifest--verbose: 2:6e0e82995c35
1687 manifest--verbose: 2:6e0e82995c35
1681 manifest--verbose: 1:4e8d705b1e53
1688 manifest--verbose: 1:4e8d705b1e53
1682 manifest--verbose: 0:a0c8bcbbb45c
1689 manifest--verbose: 0:a0c8bcbbb45c
1683 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1690 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1684 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1691 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1685 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1692 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1686 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1693 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1687 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1694 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1688 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1695 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1689 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1696 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1690 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1697 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1691 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1698 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1692 node: 95c24699272ef57d062b8bccc32c878bf841784a
1699 node: 95c24699272ef57d062b8bccc32c878bf841784a
1693 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1700 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1694 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1701 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1695 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1702 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1696 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1703 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1697 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1704 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1698 node: 97054abb4ab824450e9164180baf491ae0078465
1705 node: 97054abb4ab824450e9164180baf491ae0078465
1699 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1706 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1700 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1707 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1701 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1708 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1702 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1709 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1703 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1710 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1704 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1711 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1705 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1712 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1706 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1713 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1707 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1714 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1708 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1715 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1709 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1716 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1710 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1717 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1711 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1718 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1712 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1719 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1713 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1720 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1714 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1721 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1715 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1722 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1716 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1723 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1717 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1724 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1718 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1725 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1719 parents:
1726 parents:
1720 parents: -1:000000000000
1727 parents: -1:000000000000
1721 parents: 5:13207e5a10d9 4:bbe44766e73d
1728 parents: 5:13207e5a10d9 4:bbe44766e73d
1722 parents: 3:10e46f2dcbf4
1729 parents: 3:10e46f2dcbf4
1723 parents:
1730 parents:
1724 parents:
1731 parents:
1725 parents:
1732 parents:
1726 parents:
1733 parents:
1727 parents:
1734 parents:
1728 parents--verbose:
1735 parents--verbose:
1729 parents--verbose: -1:000000000000
1736 parents--verbose: -1:000000000000
1730 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1737 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1731 parents--verbose: 3:10e46f2dcbf4
1738 parents--verbose: 3:10e46f2dcbf4
1732 parents--verbose:
1739 parents--verbose:
1733 parents--verbose:
1740 parents--verbose:
1734 parents--verbose:
1741 parents--verbose:
1735 parents--verbose:
1742 parents--verbose:
1736 parents--verbose:
1743 parents--verbose:
1737 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1744 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1738 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1745 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1739 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1746 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1740 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1747 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1741 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1748 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1742 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1749 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1743 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1750 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1744 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1751 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1745 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1752 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1746 rev: 8
1753 rev: 8
1747 rev: 7
1754 rev: 7
1748 rev: 6
1755 rev: 6
1749 rev: 5
1756 rev: 5
1750 rev: 4
1757 rev: 4
1751 rev: 3
1758 rev: 3
1752 rev: 2
1759 rev: 2
1753 rev: 1
1760 rev: 1
1754 rev: 0
1761 rev: 0
1755 rev--verbose: 8
1762 rev--verbose: 8
1756 rev--verbose: 7
1763 rev--verbose: 7
1757 rev--verbose: 6
1764 rev--verbose: 6
1758 rev--verbose: 5
1765 rev--verbose: 5
1759 rev--verbose: 4
1766 rev--verbose: 4
1760 rev--verbose: 3
1767 rev--verbose: 3
1761 rev--verbose: 2
1768 rev--verbose: 2
1762 rev--verbose: 1
1769 rev--verbose: 1
1763 rev--verbose: 0
1770 rev--verbose: 0
1764 rev--debug: 8
1771 rev--debug: 8
1765 rev--debug: 7
1772 rev--debug: 7
1766 rev--debug: 6
1773 rev--debug: 6
1767 rev--debug: 5
1774 rev--debug: 5
1768 rev--debug: 4
1775 rev--debug: 4
1769 rev--debug: 3
1776 rev--debug: 3
1770 rev--debug: 2
1777 rev--debug: 2
1771 rev--debug: 1
1778 rev--debug: 1
1772 rev--debug: 0
1779 rev--debug: 0
1773 tags: tip
1780 tags: tip
1774 tags:
1781 tags:
1775 tags:
1782 tags:
1776 tags:
1783 tags:
1777 tags:
1784 tags:
1778 tags:
1785 tags:
1779 tags:
1786 tags:
1780 tags:
1787 tags:
1781 tags:
1788 tags:
1782 tags--verbose: tip
1789 tags--verbose: tip
1783 tags--verbose:
1790 tags--verbose:
1784 tags--verbose:
1791 tags--verbose:
1785 tags--verbose:
1792 tags--verbose:
1786 tags--verbose:
1793 tags--verbose:
1787 tags--verbose:
1794 tags--verbose:
1788 tags--verbose:
1795 tags--verbose:
1789 tags--verbose:
1796 tags--verbose:
1790 tags--verbose:
1797 tags--verbose:
1791 tags--debug: tip
1798 tags--debug: tip
1792 tags--debug:
1799 tags--debug:
1793 tags--debug:
1800 tags--debug:
1794 tags--debug:
1801 tags--debug:
1795 tags--debug:
1802 tags--debug:
1796 tags--debug:
1803 tags--debug:
1797 tags--debug:
1804 tags--debug:
1798 tags--debug:
1805 tags--debug:
1799 tags--debug:
1806 tags--debug:
1800 diffstat: 3: +2/-1
1807 diffstat: 3: +2/-1
1801 diffstat: 1: +1/-0
1808 diffstat: 1: +1/-0
1802 diffstat: 0: +0/-0
1809 diffstat: 0: +0/-0
1803 diffstat: 1: +1/-0
1810 diffstat: 1: +1/-0
1804 diffstat: 0: +0/-0
1811 diffstat: 0: +0/-0
1805 diffstat: 1: +1/-0
1812 diffstat: 1: +1/-0
1806 diffstat: 1: +4/-0
1813 diffstat: 1: +4/-0
1807 diffstat: 1: +2/-0
1814 diffstat: 1: +2/-0
1808 diffstat: 1: +1/-0
1815 diffstat: 1: +1/-0
1809 diffstat--verbose: 3: +2/-1
1816 diffstat--verbose: 3: +2/-1
1810 diffstat--verbose: 1: +1/-0
1817 diffstat--verbose: 1: +1/-0
1811 diffstat--verbose: 0: +0/-0
1818 diffstat--verbose: 0: +0/-0
1812 diffstat--verbose: 1: +1/-0
1819 diffstat--verbose: 1: +1/-0
1813 diffstat--verbose: 0: +0/-0
1820 diffstat--verbose: 0: +0/-0
1814 diffstat--verbose: 1: +1/-0
1821 diffstat--verbose: 1: +1/-0
1815 diffstat--verbose: 1: +4/-0
1822 diffstat--verbose: 1: +4/-0
1816 diffstat--verbose: 1: +2/-0
1823 diffstat--verbose: 1: +2/-0
1817 diffstat--verbose: 1: +1/-0
1824 diffstat--verbose: 1: +1/-0
1818 diffstat--debug: 3: +2/-1
1825 diffstat--debug: 3: +2/-1
1819 diffstat--debug: 1: +1/-0
1826 diffstat--debug: 1: +1/-0
1820 diffstat--debug: 0: +0/-0
1827 diffstat--debug: 0: +0/-0
1821 diffstat--debug: 1: +1/-0
1828 diffstat--debug: 1: +1/-0
1822 diffstat--debug: 0: +0/-0
1829 diffstat--debug: 0: +0/-0
1823 diffstat--debug: 1: +1/-0
1830 diffstat--debug: 1: +1/-0
1824 diffstat--debug: 1: +4/-0
1831 diffstat--debug: 1: +4/-0
1825 diffstat--debug: 1: +2/-0
1832 diffstat--debug: 1: +2/-0
1826 diffstat--debug: 1: +1/-0
1833 diffstat--debug: 1: +1/-0
1827 extras: branch=default
1834 extras: branch=default
1828 extras: branch=default
1835 extras: branch=default
1829 extras: branch=default
1836 extras: branch=default
1830 extras: branch=default
1837 extras: branch=default
1831 extras: branch=foo
1838 extras: branch=foo
1832 extras: branch=default
1839 extras: branch=default
1833 extras: branch=default
1840 extras: branch=default
1834 extras: branch=default
1841 extras: branch=default
1835 extras: branch=default
1842 extras: branch=default
1836 extras--verbose: branch=default
1843 extras--verbose: branch=default
1837 extras--verbose: branch=default
1844 extras--verbose: branch=default
1838 extras--verbose: branch=default
1845 extras--verbose: branch=default
1839 extras--verbose: branch=default
1846 extras--verbose: branch=default
1840 extras--verbose: branch=foo
1847 extras--verbose: branch=foo
1841 extras--verbose: branch=default
1848 extras--verbose: branch=default
1842 extras--verbose: branch=default
1849 extras--verbose: branch=default
1843 extras--verbose: branch=default
1850 extras--verbose: branch=default
1844 extras--verbose: branch=default
1851 extras--verbose: branch=default
1845 extras--debug: branch=default
1852 extras--debug: branch=default
1846 extras--debug: branch=default
1853 extras--debug: branch=default
1847 extras--debug: branch=default
1854 extras--debug: branch=default
1848 extras--debug: branch=default
1855 extras--debug: branch=default
1849 extras--debug: branch=foo
1856 extras--debug: branch=foo
1850 extras--debug: branch=default
1857 extras--debug: branch=default
1851 extras--debug: branch=default
1858 extras--debug: branch=default
1852 extras--debug: branch=default
1859 extras--debug: branch=default
1853 extras--debug: branch=default
1860 extras--debug: branch=default
1854 p1rev: 7
1861 p1rev: 7
1855 p1rev: -1
1862 p1rev: -1
1856 p1rev: 5
1863 p1rev: 5
1857 p1rev: 3
1864 p1rev: 3
1858 p1rev: 3
1865 p1rev: 3
1859 p1rev: 2
1866 p1rev: 2
1860 p1rev: 1
1867 p1rev: 1
1861 p1rev: 0
1868 p1rev: 0
1862 p1rev: -1
1869 p1rev: -1
1863 p1rev--verbose: 7
1870 p1rev--verbose: 7
1864 p1rev--verbose: -1
1871 p1rev--verbose: -1
1865 p1rev--verbose: 5
1872 p1rev--verbose: 5
1866 p1rev--verbose: 3
1873 p1rev--verbose: 3
1867 p1rev--verbose: 3
1874 p1rev--verbose: 3
1868 p1rev--verbose: 2
1875 p1rev--verbose: 2
1869 p1rev--verbose: 1
1876 p1rev--verbose: 1
1870 p1rev--verbose: 0
1877 p1rev--verbose: 0
1871 p1rev--verbose: -1
1878 p1rev--verbose: -1
1872 p1rev--debug: 7
1879 p1rev--debug: 7
1873 p1rev--debug: -1
1880 p1rev--debug: -1
1874 p1rev--debug: 5
1881 p1rev--debug: 5
1875 p1rev--debug: 3
1882 p1rev--debug: 3
1876 p1rev--debug: 3
1883 p1rev--debug: 3
1877 p1rev--debug: 2
1884 p1rev--debug: 2
1878 p1rev--debug: 1
1885 p1rev--debug: 1
1879 p1rev--debug: 0
1886 p1rev--debug: 0
1880 p1rev--debug: -1
1887 p1rev--debug: -1
1881 p2rev: -1
1888 p2rev: -1
1882 p2rev: -1
1889 p2rev: -1
1883 p2rev: 4
1890 p2rev: 4
1884 p2rev: -1
1891 p2rev: -1
1885 p2rev: -1
1892 p2rev: -1
1886 p2rev: -1
1893 p2rev: -1
1887 p2rev: -1
1894 p2rev: -1
1888 p2rev: -1
1895 p2rev: -1
1889 p2rev: -1
1896 p2rev: -1
1890 p2rev--verbose: -1
1897 p2rev--verbose: -1
1891 p2rev--verbose: -1
1898 p2rev--verbose: -1
1892 p2rev--verbose: 4
1899 p2rev--verbose: 4
1893 p2rev--verbose: -1
1900 p2rev--verbose: -1
1894 p2rev--verbose: -1
1901 p2rev--verbose: -1
1895 p2rev--verbose: -1
1902 p2rev--verbose: -1
1896 p2rev--verbose: -1
1903 p2rev--verbose: -1
1897 p2rev--verbose: -1
1904 p2rev--verbose: -1
1898 p2rev--verbose: -1
1905 p2rev--verbose: -1
1899 p2rev--debug: -1
1906 p2rev--debug: -1
1900 p2rev--debug: -1
1907 p2rev--debug: -1
1901 p2rev--debug: 4
1908 p2rev--debug: 4
1902 p2rev--debug: -1
1909 p2rev--debug: -1
1903 p2rev--debug: -1
1910 p2rev--debug: -1
1904 p2rev--debug: -1
1911 p2rev--debug: -1
1905 p2rev--debug: -1
1912 p2rev--debug: -1
1906 p2rev--debug: -1
1913 p2rev--debug: -1
1907 p2rev--debug: -1
1914 p2rev--debug: -1
1908 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1915 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1909 p1node: 0000000000000000000000000000000000000000
1916 p1node: 0000000000000000000000000000000000000000
1910 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1917 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1911 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1918 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1912 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1919 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1913 p1node: 97054abb4ab824450e9164180baf491ae0078465
1920 p1node: 97054abb4ab824450e9164180baf491ae0078465
1914 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1921 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1915 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1922 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1916 p1node: 0000000000000000000000000000000000000000
1923 p1node: 0000000000000000000000000000000000000000
1917 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1924 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1918 p1node--verbose: 0000000000000000000000000000000000000000
1925 p1node--verbose: 0000000000000000000000000000000000000000
1919 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1926 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1920 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1927 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1921 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1928 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1922 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1929 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1923 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1930 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1924 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1931 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1925 p1node--verbose: 0000000000000000000000000000000000000000
1932 p1node--verbose: 0000000000000000000000000000000000000000
1926 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1933 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1927 p1node--debug: 0000000000000000000000000000000000000000
1934 p1node--debug: 0000000000000000000000000000000000000000
1928 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1935 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1929 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1936 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1930 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1937 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1931 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1938 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1932 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1939 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1933 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1940 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1934 p1node--debug: 0000000000000000000000000000000000000000
1941 p1node--debug: 0000000000000000000000000000000000000000
1935 p2node: 0000000000000000000000000000000000000000
1942 p2node: 0000000000000000000000000000000000000000
1936 p2node: 0000000000000000000000000000000000000000
1943 p2node: 0000000000000000000000000000000000000000
1937 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1944 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1938 p2node: 0000000000000000000000000000000000000000
1945 p2node: 0000000000000000000000000000000000000000
1939 p2node: 0000000000000000000000000000000000000000
1946 p2node: 0000000000000000000000000000000000000000
1940 p2node: 0000000000000000000000000000000000000000
1947 p2node: 0000000000000000000000000000000000000000
1941 p2node: 0000000000000000000000000000000000000000
1948 p2node: 0000000000000000000000000000000000000000
1942 p2node: 0000000000000000000000000000000000000000
1949 p2node: 0000000000000000000000000000000000000000
1943 p2node: 0000000000000000000000000000000000000000
1950 p2node: 0000000000000000000000000000000000000000
1944 p2node--verbose: 0000000000000000000000000000000000000000
1951 p2node--verbose: 0000000000000000000000000000000000000000
1945 p2node--verbose: 0000000000000000000000000000000000000000
1952 p2node--verbose: 0000000000000000000000000000000000000000
1946 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1953 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1947 p2node--verbose: 0000000000000000000000000000000000000000
1954 p2node--verbose: 0000000000000000000000000000000000000000
1948 p2node--verbose: 0000000000000000000000000000000000000000
1955 p2node--verbose: 0000000000000000000000000000000000000000
1949 p2node--verbose: 0000000000000000000000000000000000000000
1956 p2node--verbose: 0000000000000000000000000000000000000000
1950 p2node--verbose: 0000000000000000000000000000000000000000
1957 p2node--verbose: 0000000000000000000000000000000000000000
1951 p2node--verbose: 0000000000000000000000000000000000000000
1958 p2node--verbose: 0000000000000000000000000000000000000000
1952 p2node--verbose: 0000000000000000000000000000000000000000
1959 p2node--verbose: 0000000000000000000000000000000000000000
1953 p2node--debug: 0000000000000000000000000000000000000000
1960 p2node--debug: 0000000000000000000000000000000000000000
1954 p2node--debug: 0000000000000000000000000000000000000000
1961 p2node--debug: 0000000000000000000000000000000000000000
1955 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1962 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1956 p2node--debug: 0000000000000000000000000000000000000000
1963 p2node--debug: 0000000000000000000000000000000000000000
1957 p2node--debug: 0000000000000000000000000000000000000000
1964 p2node--debug: 0000000000000000000000000000000000000000
1958 p2node--debug: 0000000000000000000000000000000000000000
1965 p2node--debug: 0000000000000000000000000000000000000000
1959 p2node--debug: 0000000000000000000000000000000000000000
1966 p2node--debug: 0000000000000000000000000000000000000000
1960 p2node--debug: 0000000000000000000000000000000000000000
1967 p2node--debug: 0000000000000000000000000000000000000000
1961 p2node--debug: 0000000000000000000000000000000000000000
1968 p2node--debug: 0000000000000000000000000000000000000000
1962
1969
1963 Filters work:
1970 Filters work:
1964
1971
1965 $ hg log --template '{author|domain}\n'
1972 $ hg log --template '{author|domain}\n'
1966
1973
1967 hostname
1974 hostname
1968
1975
1969
1976
1970
1977
1971
1978
1972 place
1979 place
1973 place
1980 place
1974 hostname
1981 hostname
1975
1982
1976 $ hg log --template '{author|person}\n'
1983 $ hg log --template '{author|person}\n'
1977 test
1984 test
1978 User Name
1985 User Name
1979 person
1986 person
1980 person
1987 person
1981 person
1988 person
1982 person
1989 person
1983 other
1990 other
1984 A. N. Other
1991 A. N. Other
1985 User Name
1992 User Name
1986
1993
1987 $ hg log --template '{author|user}\n'
1994 $ hg log --template '{author|user}\n'
1988 test
1995 test
1989 user
1996 user
1990 person
1997 person
1991 person
1998 person
1992 person
1999 person
1993 person
2000 person
1994 other
2001 other
1995 other
2002 other
1996 user
2003 user
1997
2004
1998 $ hg log --template '{date|date}\n'
2005 $ hg log --template '{date|date}\n'
1999 Wed Jan 01 10:01:00 2020 +0000
2006 Wed Jan 01 10:01:00 2020 +0000
2000 Mon Jan 12 13:46:40 1970 +0000
2007 Mon Jan 12 13:46:40 1970 +0000
2001 Sun Jan 18 08:40:01 1970 +0000
2008 Sun Jan 18 08:40:01 1970 +0000
2002 Sun Jan 18 08:40:00 1970 +0000
2009 Sun Jan 18 08:40:00 1970 +0000
2003 Sat Jan 17 04:53:20 1970 +0000
2010 Sat Jan 17 04:53:20 1970 +0000
2004 Fri Jan 16 01:06:40 1970 +0000
2011 Fri Jan 16 01:06:40 1970 +0000
2005 Wed Jan 14 21:20:00 1970 +0000
2012 Wed Jan 14 21:20:00 1970 +0000
2006 Tue Jan 13 17:33:20 1970 +0000
2013 Tue Jan 13 17:33:20 1970 +0000
2007 Mon Jan 12 13:46:40 1970 +0000
2014 Mon Jan 12 13:46:40 1970 +0000
2008
2015
2009 $ hg log --template '{date|isodate}\n'
2016 $ hg log --template '{date|isodate}\n'
2010 2020-01-01 10:01 +0000
2017 2020-01-01 10:01 +0000
2011 1970-01-12 13:46 +0000
2018 1970-01-12 13:46 +0000
2012 1970-01-18 08:40 +0000
2019 1970-01-18 08:40 +0000
2013 1970-01-18 08:40 +0000
2020 1970-01-18 08:40 +0000
2014 1970-01-17 04:53 +0000
2021 1970-01-17 04:53 +0000
2015 1970-01-16 01:06 +0000
2022 1970-01-16 01:06 +0000
2016 1970-01-14 21:20 +0000
2023 1970-01-14 21:20 +0000
2017 1970-01-13 17:33 +0000
2024 1970-01-13 17:33 +0000
2018 1970-01-12 13:46 +0000
2025 1970-01-12 13:46 +0000
2019
2026
2020 $ hg log --template '{date|isodatesec}\n'
2027 $ hg log --template '{date|isodatesec}\n'
2021 2020-01-01 10:01:00 +0000
2028 2020-01-01 10:01:00 +0000
2022 1970-01-12 13:46:40 +0000
2029 1970-01-12 13:46:40 +0000
2023 1970-01-18 08:40:01 +0000
2030 1970-01-18 08:40:01 +0000
2024 1970-01-18 08:40:00 +0000
2031 1970-01-18 08:40:00 +0000
2025 1970-01-17 04:53:20 +0000
2032 1970-01-17 04:53:20 +0000
2026 1970-01-16 01:06:40 +0000
2033 1970-01-16 01:06:40 +0000
2027 1970-01-14 21:20:00 +0000
2034 1970-01-14 21:20:00 +0000
2028 1970-01-13 17:33:20 +0000
2035 1970-01-13 17:33:20 +0000
2029 1970-01-12 13:46:40 +0000
2036 1970-01-12 13:46:40 +0000
2030
2037
2031 $ hg log --template '{date|rfc822date}\n'
2038 $ hg log --template '{date|rfc822date}\n'
2032 Wed, 01 Jan 2020 10:01:00 +0000
2039 Wed, 01 Jan 2020 10:01:00 +0000
2033 Mon, 12 Jan 1970 13:46:40 +0000
2040 Mon, 12 Jan 1970 13:46:40 +0000
2034 Sun, 18 Jan 1970 08:40:01 +0000
2041 Sun, 18 Jan 1970 08:40:01 +0000
2035 Sun, 18 Jan 1970 08:40:00 +0000
2042 Sun, 18 Jan 1970 08:40:00 +0000
2036 Sat, 17 Jan 1970 04:53:20 +0000
2043 Sat, 17 Jan 1970 04:53:20 +0000
2037 Fri, 16 Jan 1970 01:06:40 +0000
2044 Fri, 16 Jan 1970 01:06:40 +0000
2038 Wed, 14 Jan 1970 21:20:00 +0000
2045 Wed, 14 Jan 1970 21:20:00 +0000
2039 Tue, 13 Jan 1970 17:33:20 +0000
2046 Tue, 13 Jan 1970 17:33:20 +0000
2040 Mon, 12 Jan 1970 13:46:40 +0000
2047 Mon, 12 Jan 1970 13:46:40 +0000
2041
2048
2042 $ hg log --template '{desc|firstline}\n'
2049 $ hg log --template '{desc|firstline}\n'
2043 third
2050 third
2044 second
2051 second
2045 merge
2052 merge
2046 new head
2053 new head
2047 new branch
2054 new branch
2048 no user, no domain
2055 no user, no domain
2049 no person
2056 no person
2050 other 1
2057 other 1
2051 line 1
2058 line 1
2052
2059
2053 $ hg log --template '{node|short}\n'
2060 $ hg log --template '{node|short}\n'
2054 95c24699272e
2061 95c24699272e
2055 29114dbae42b
2062 29114dbae42b
2056 d41e714fe50d
2063 d41e714fe50d
2057 13207e5a10d9
2064 13207e5a10d9
2058 bbe44766e73d
2065 bbe44766e73d
2059 10e46f2dcbf4
2066 10e46f2dcbf4
2060 97054abb4ab8
2067 97054abb4ab8
2061 b608e9d1a3f0
2068 b608e9d1a3f0
2062 1e4e1b8f71e0
2069 1e4e1b8f71e0
2063
2070
2064 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2071 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2065 <changeset author="test"/>
2072 <changeset author="test"/>
2066 <changeset author="User Name &lt;user@hostname&gt;"/>
2073 <changeset author="User Name &lt;user@hostname&gt;"/>
2067 <changeset author="person"/>
2074 <changeset author="person"/>
2068 <changeset author="person"/>
2075 <changeset author="person"/>
2069 <changeset author="person"/>
2076 <changeset author="person"/>
2070 <changeset author="person"/>
2077 <changeset author="person"/>
2071 <changeset author="other@place"/>
2078 <changeset author="other@place"/>
2072 <changeset author="A. N. Other &lt;other@place&gt;"/>
2079 <changeset author="A. N. Other &lt;other@place&gt;"/>
2073 <changeset author="User Name &lt;user@hostname&gt;"/>
2080 <changeset author="User Name &lt;user@hostname&gt;"/>
2074
2081
2075 $ hg log --template '{rev}: {children}\n'
2082 $ hg log --template '{rev}: {children}\n'
2076 8:
2083 8:
2077 7: 8:95c24699272e
2084 7: 8:95c24699272e
2078 6:
2085 6:
2079 5: 6:d41e714fe50d
2086 5: 6:d41e714fe50d
2080 4: 6:d41e714fe50d
2087 4: 6:d41e714fe50d
2081 3: 4:bbe44766e73d 5:13207e5a10d9
2088 3: 4:bbe44766e73d 5:13207e5a10d9
2082 2: 3:10e46f2dcbf4
2089 2: 3:10e46f2dcbf4
2083 1: 2:97054abb4ab8
2090 1: 2:97054abb4ab8
2084 0: 1:b608e9d1a3f0
2091 0: 1:b608e9d1a3f0
2085
2092
2086 Formatnode filter works:
2093 Formatnode filter works:
2087
2094
2088 $ hg -q log -r 0 --template '{node|formatnode}\n'
2095 $ hg -q log -r 0 --template '{node|formatnode}\n'
2089 1e4e1b8f71e0
2096 1e4e1b8f71e0
2090
2097
2091 $ hg log -r 0 --template '{node|formatnode}\n'
2098 $ hg log -r 0 --template '{node|formatnode}\n'
2092 1e4e1b8f71e0
2099 1e4e1b8f71e0
2093
2100
2094 $ hg -v log -r 0 --template '{node|formatnode}\n'
2101 $ hg -v log -r 0 --template '{node|formatnode}\n'
2095 1e4e1b8f71e0
2102 1e4e1b8f71e0
2096
2103
2097 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2104 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2098 1e4e1b8f71e05681d422154f5421e385fec3454f
2105 1e4e1b8f71e05681d422154f5421e385fec3454f
2099
2106
2100 Age filter:
2107 Age filter:
2101
2108
2102 $ hg init unstable-hash
2109 $ hg init unstable-hash
2103 $ cd unstable-hash
2110 $ cd unstable-hash
2104 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2111 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2105
2112
2106 >>> from datetime import datetime, timedelta
2113 >>> from datetime import datetime, timedelta
2107 >>> fp = open('a', 'w')
2114 >>> fp = open('a', 'w')
2108 >>> n = datetime.now() + timedelta(366 * 7)
2115 >>> n = datetime.now() + timedelta(366 * 7)
2109 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2116 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
2110 >>> fp.close()
2117 >>> fp.close()
2111 $ hg add a
2118 $ hg add a
2112 $ hg commit -m future -d "`cat a`"
2119 $ hg commit -m future -d "`cat a`"
2113
2120
2114 $ hg log -l1 --template '{date|age}\n'
2121 $ hg log -l1 --template '{date|age}\n'
2115 7 years from now
2122 7 years from now
2116
2123
2117 $ cd ..
2124 $ cd ..
2118 $ rm -rf unstable-hash
2125 $ rm -rf unstable-hash
2119
2126
2120 Add a dummy commit to make up for the instability of the above:
2127 Add a dummy commit to make up for the instability of the above:
2121
2128
2122 $ echo a > a
2129 $ echo a > a
2123 $ hg add a
2130 $ hg add a
2124 $ hg ci -m future
2131 $ hg ci -m future
2125
2132
2126 Count filter:
2133 Count filter:
2127
2134
2128 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2135 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2129 40 12
2136 40 12
2130
2137
2131 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2138 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2132 0 1 4
2139 0 1 4
2133
2140
2134 $ hg log -G --template '{rev}: children: {children|count}, \
2141 $ hg log -G --template '{rev}: children: {children|count}, \
2135 > tags: {tags|count}, file_adds: {file_adds|count}, \
2142 > tags: {tags|count}, file_adds: {file_adds|count}, \
2136 > ancestors: {revset("ancestors(%s)", rev)|count}'
2143 > ancestors: {revset("ancestors(%s)", rev)|count}'
2137 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2144 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2138 |
2145 |
2139 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2146 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2140 |
2147 |
2141 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2148 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2142
2149
2143 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2150 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2144 |\
2151 |\
2145 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2152 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2146 | |
2153 | |
2147 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2154 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2148 |/
2155 |/
2149 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2156 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2150 |
2157 |
2151 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2158 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2152 |
2159 |
2153 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2160 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2154 |
2161 |
2155 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2162 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2156
2163
2157
2164
2158 Upper/lower filters:
2165 Upper/lower filters:
2159
2166
2160 $ hg log -r0 --template '{branch|upper}\n'
2167 $ hg log -r0 --template '{branch|upper}\n'
2161 DEFAULT
2168 DEFAULT
2162 $ hg log -r0 --template '{author|lower}\n'
2169 $ hg log -r0 --template '{author|lower}\n'
2163 user name <user@hostname>
2170 user name <user@hostname>
2164 $ hg log -r0 --template '{date|upper}\n'
2171 $ hg log -r0 --template '{date|upper}\n'
2165 abort: template filter 'upper' is not compatible with keyword 'date'
2172 abort: template filter 'upper' is not compatible with keyword 'date'
2166 [255]
2173 [255]
2167
2174
2168 Add a commit that does all possible modifications at once
2175 Add a commit that does all possible modifications at once
2169
2176
2170 $ echo modify >> third
2177 $ echo modify >> third
2171 $ touch b
2178 $ touch b
2172 $ hg add b
2179 $ hg add b
2173 $ hg mv fourth fifth
2180 $ hg mv fourth fifth
2174 $ hg rm a
2181 $ hg rm a
2175 $ hg ci -m "Modify, add, remove, rename"
2182 $ hg ci -m "Modify, add, remove, rename"
2176
2183
2177 Check the status template
2184 Check the status template
2178
2185
2179 $ cat <<EOF >> $HGRCPATH
2186 $ cat <<EOF >> $HGRCPATH
2180 > [extensions]
2187 > [extensions]
2181 > color=
2188 > color=
2182 > EOF
2189 > EOF
2183
2190
2184 $ hg log -T status -r 10
2191 $ hg log -T status -r 10
2185 changeset: 10:0f9759ec227a
2192 changeset: 10:0f9759ec227a
2186 tag: tip
2193 tag: tip
2187 user: test
2194 user: test
2188 date: Thu Jan 01 00:00:00 1970 +0000
2195 date: Thu Jan 01 00:00:00 1970 +0000
2189 summary: Modify, add, remove, rename
2196 summary: Modify, add, remove, rename
2190 files:
2197 files:
2191 M third
2198 M third
2192 A b
2199 A b
2193 A fifth
2200 A fifth
2194 R a
2201 R a
2195 R fourth
2202 R fourth
2196
2203
2197 $ hg log -T status -C -r 10
2204 $ hg log -T status -C -r 10
2198 changeset: 10:0f9759ec227a
2205 changeset: 10:0f9759ec227a
2199 tag: tip
2206 tag: tip
2200 user: test
2207 user: test
2201 date: Thu Jan 01 00:00:00 1970 +0000
2208 date: Thu Jan 01 00:00:00 1970 +0000
2202 summary: Modify, add, remove, rename
2209 summary: Modify, add, remove, rename
2203 files:
2210 files:
2204 M third
2211 M third
2205 A b
2212 A b
2206 A fifth
2213 A fifth
2207 fourth
2214 fourth
2208 R a
2215 R a
2209 R fourth
2216 R fourth
2210
2217
2211 $ hg log -T status -C -r 10 -v
2218 $ hg log -T status -C -r 10 -v
2212 changeset: 10:0f9759ec227a
2219 changeset: 10:0f9759ec227a
2213 tag: tip
2220 tag: tip
2214 user: test
2221 user: test
2215 date: Thu Jan 01 00:00:00 1970 +0000
2222 date: Thu Jan 01 00:00:00 1970 +0000
2216 description:
2223 description:
2217 Modify, add, remove, rename
2224 Modify, add, remove, rename
2218
2225
2219 files:
2226 files:
2220 M third
2227 M third
2221 A b
2228 A b
2222 A fifth
2229 A fifth
2223 fourth
2230 fourth
2224 R a
2231 R a
2225 R fourth
2232 R fourth
2226
2233
2227 $ hg log -T status -C -r 10 --debug
2234 $ hg log -T status -C -r 10 --debug
2228 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2235 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2229 tag: tip
2236 tag: tip
2230 phase: secret
2237 phase: secret
2231 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2238 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2232 parent: -1:0000000000000000000000000000000000000000
2239 parent: -1:0000000000000000000000000000000000000000
2233 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2240 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2234 user: test
2241 user: test
2235 date: Thu Jan 01 00:00:00 1970 +0000
2242 date: Thu Jan 01 00:00:00 1970 +0000
2236 extra: branch=default
2243 extra: branch=default
2237 description:
2244 description:
2238 Modify, add, remove, rename
2245 Modify, add, remove, rename
2239
2246
2240 files:
2247 files:
2241 M third
2248 M third
2242 A b
2249 A b
2243 A fifth
2250 A fifth
2244 fourth
2251 fourth
2245 R a
2252 R a
2246 R fourth
2253 R fourth
2247
2254
2248 $ hg log -T status -C -r 10 --quiet
2255 $ hg log -T status -C -r 10 --quiet
2249 10:0f9759ec227a
2256 10:0f9759ec227a
2250 $ hg --color=debug log -T status -r 10
2257 $ hg --color=debug log -T status -r 10
2251 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2258 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2252 [log.tag|tag: tip]
2259 [log.tag|tag: tip]
2253 [log.user|user: test]
2260 [log.user|user: test]
2254 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2261 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2255 [log.summary|summary: Modify, add, remove, rename]
2262 [log.summary|summary: Modify, add, remove, rename]
2256 [ui.note log.files|files:]
2263 [ui.note log.files|files:]
2257 [status.modified|M third]
2264 [status.modified|M third]
2258 [status.added|A b]
2265 [status.added|A b]
2259 [status.added|A fifth]
2266 [status.added|A fifth]
2260 [status.removed|R a]
2267 [status.removed|R a]
2261 [status.removed|R fourth]
2268 [status.removed|R fourth]
2262
2269
2263 $ hg --color=debug log -T status -C -r 10
2270 $ hg --color=debug log -T status -C -r 10
2264 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2271 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2265 [log.tag|tag: tip]
2272 [log.tag|tag: tip]
2266 [log.user|user: test]
2273 [log.user|user: test]
2267 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2274 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2268 [log.summary|summary: Modify, add, remove, rename]
2275 [log.summary|summary: Modify, add, remove, rename]
2269 [ui.note log.files|files:]
2276 [ui.note log.files|files:]
2270 [status.modified|M third]
2277 [status.modified|M third]
2271 [status.added|A b]
2278 [status.added|A b]
2272 [status.added|A fifth]
2279 [status.added|A fifth]
2273 [status.copied| fourth]
2280 [status.copied| fourth]
2274 [status.removed|R a]
2281 [status.removed|R a]
2275 [status.removed|R fourth]
2282 [status.removed|R fourth]
2276
2283
2277 $ hg --color=debug log -T status -C -r 10 -v
2284 $ hg --color=debug log -T status -C -r 10 -v
2278 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2285 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2279 [log.tag|tag: tip]
2286 [log.tag|tag: tip]
2280 [log.user|user: test]
2287 [log.user|user: test]
2281 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2288 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2282 [ui.note log.description|description:]
2289 [ui.note log.description|description:]
2283 [ui.note log.description|Modify, add, remove, rename]
2290 [ui.note log.description|Modify, add, remove, rename]
2284
2291
2285 [ui.note log.files|files:]
2292 [ui.note log.files|files:]
2286 [status.modified|M third]
2293 [status.modified|M third]
2287 [status.added|A b]
2294 [status.added|A b]
2288 [status.added|A fifth]
2295 [status.added|A fifth]
2289 [status.copied| fourth]
2296 [status.copied| fourth]
2290 [status.removed|R a]
2297 [status.removed|R a]
2291 [status.removed|R fourth]
2298 [status.removed|R fourth]
2292
2299
2293 $ hg --color=debug log -T status -C -r 10 --debug
2300 $ hg --color=debug log -T status -C -r 10 --debug
2294 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2301 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2295 [log.tag|tag: tip]
2302 [log.tag|tag: tip]
2296 [log.phase|phase: secret]
2303 [log.phase|phase: secret]
2297 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2304 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2298 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2305 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2299 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2306 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2300 [log.user|user: test]
2307 [log.user|user: test]
2301 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2308 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2302 [ui.debug log.extra|extra: branch=default]
2309 [ui.debug log.extra|extra: branch=default]
2303 [ui.note log.description|description:]
2310 [ui.note log.description|description:]
2304 [ui.note log.description|Modify, add, remove, rename]
2311 [ui.note log.description|Modify, add, remove, rename]
2305
2312
2306 [ui.note log.files|files:]
2313 [ui.note log.files|files:]
2307 [status.modified|M third]
2314 [status.modified|M third]
2308 [status.added|A b]
2315 [status.added|A b]
2309 [status.added|A fifth]
2316 [status.added|A fifth]
2310 [status.copied| fourth]
2317 [status.copied| fourth]
2311 [status.removed|R a]
2318 [status.removed|R a]
2312 [status.removed|R fourth]
2319 [status.removed|R fourth]
2313
2320
2314 $ hg --color=debug log -T status -C -r 10 --quiet
2321 $ hg --color=debug log -T status -C -r 10 --quiet
2315 [log.node|10:0f9759ec227a]
2322 [log.node|10:0f9759ec227a]
2316
2323
2317 Check the bisect template
2324 Check the bisect template
2318
2325
2319 $ hg bisect -g 1
2326 $ hg bisect -g 1
2320 $ hg bisect -b 3 --noupdate
2327 $ hg bisect -b 3 --noupdate
2321 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2328 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2322 $ hg log -T bisect -r 0:4
2329 $ hg log -T bisect -r 0:4
2323 changeset: 0:1e4e1b8f71e0
2330 changeset: 0:1e4e1b8f71e0
2324 bisect: good (implicit)
2331 bisect: good (implicit)
2325 user: User Name <user@hostname>
2332 user: User Name <user@hostname>
2326 date: Mon Jan 12 13:46:40 1970 +0000
2333 date: Mon Jan 12 13:46:40 1970 +0000
2327 summary: line 1
2334 summary: line 1
2328
2335
2329 changeset: 1:b608e9d1a3f0
2336 changeset: 1:b608e9d1a3f0
2330 bisect: good
2337 bisect: good
2331 user: A. N. Other <other@place>
2338 user: A. N. Other <other@place>
2332 date: Tue Jan 13 17:33:20 1970 +0000
2339 date: Tue Jan 13 17:33:20 1970 +0000
2333 summary: other 1
2340 summary: other 1
2334
2341
2335 changeset: 2:97054abb4ab8
2342 changeset: 2:97054abb4ab8
2336 bisect: untested
2343 bisect: untested
2337 user: other@place
2344 user: other@place
2338 date: Wed Jan 14 21:20:00 1970 +0000
2345 date: Wed Jan 14 21:20:00 1970 +0000
2339 summary: no person
2346 summary: no person
2340
2347
2341 changeset: 3:10e46f2dcbf4
2348 changeset: 3:10e46f2dcbf4
2342 bisect: bad
2349 bisect: bad
2343 user: person
2350 user: person
2344 date: Fri Jan 16 01:06:40 1970 +0000
2351 date: Fri Jan 16 01:06:40 1970 +0000
2345 summary: no user, no domain
2352 summary: no user, no domain
2346
2353
2347 changeset: 4:bbe44766e73d
2354 changeset: 4:bbe44766e73d
2348 bisect: bad (implicit)
2355 bisect: bad (implicit)
2349 branch: foo
2356 branch: foo
2350 user: person
2357 user: person
2351 date: Sat Jan 17 04:53:20 1970 +0000
2358 date: Sat Jan 17 04:53:20 1970 +0000
2352 summary: new branch
2359 summary: new branch
2353
2360
2354 $ hg log --debug -T bisect -r 0:4
2361 $ hg log --debug -T bisect -r 0:4
2355 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2362 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2356 bisect: good (implicit)
2363 bisect: good (implicit)
2357 phase: public
2364 phase: public
2358 parent: -1:0000000000000000000000000000000000000000
2365 parent: -1:0000000000000000000000000000000000000000
2359 parent: -1:0000000000000000000000000000000000000000
2366 parent: -1:0000000000000000000000000000000000000000
2360 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2367 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2361 user: User Name <user@hostname>
2368 user: User Name <user@hostname>
2362 date: Mon Jan 12 13:46:40 1970 +0000
2369 date: Mon Jan 12 13:46:40 1970 +0000
2363 files+: a
2370 files+: a
2364 extra: branch=default
2371 extra: branch=default
2365 description:
2372 description:
2366 line 1
2373 line 1
2367 line 2
2374 line 2
2368
2375
2369
2376
2370 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2377 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2371 bisect: good
2378 bisect: good
2372 phase: public
2379 phase: public
2373 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2380 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2374 parent: -1:0000000000000000000000000000000000000000
2381 parent: -1:0000000000000000000000000000000000000000
2375 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2382 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2376 user: A. N. Other <other@place>
2383 user: A. N. Other <other@place>
2377 date: Tue Jan 13 17:33:20 1970 +0000
2384 date: Tue Jan 13 17:33:20 1970 +0000
2378 files+: b
2385 files+: b
2379 extra: branch=default
2386 extra: branch=default
2380 description:
2387 description:
2381 other 1
2388 other 1
2382 other 2
2389 other 2
2383
2390
2384 other 3
2391 other 3
2385
2392
2386
2393
2387 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2394 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2388 bisect: untested
2395 bisect: untested
2389 phase: public
2396 phase: public
2390 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2397 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2391 parent: -1:0000000000000000000000000000000000000000
2398 parent: -1:0000000000000000000000000000000000000000
2392 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2399 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2393 user: other@place
2400 user: other@place
2394 date: Wed Jan 14 21:20:00 1970 +0000
2401 date: Wed Jan 14 21:20:00 1970 +0000
2395 files+: c
2402 files+: c
2396 extra: branch=default
2403 extra: branch=default
2397 description:
2404 description:
2398 no person
2405 no person
2399
2406
2400
2407
2401 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2408 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2402 bisect: bad
2409 bisect: bad
2403 phase: public
2410 phase: public
2404 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2411 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2405 parent: -1:0000000000000000000000000000000000000000
2412 parent: -1:0000000000000000000000000000000000000000
2406 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2413 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2407 user: person
2414 user: person
2408 date: Fri Jan 16 01:06:40 1970 +0000
2415 date: Fri Jan 16 01:06:40 1970 +0000
2409 files: c
2416 files: c
2410 extra: branch=default
2417 extra: branch=default
2411 description:
2418 description:
2412 no user, no domain
2419 no user, no domain
2413
2420
2414
2421
2415 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2422 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2416 bisect: bad (implicit)
2423 bisect: bad (implicit)
2417 branch: foo
2424 branch: foo
2418 phase: draft
2425 phase: draft
2419 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2426 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2420 parent: -1:0000000000000000000000000000000000000000
2427 parent: -1:0000000000000000000000000000000000000000
2421 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2428 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2422 user: person
2429 user: person
2423 date: Sat Jan 17 04:53:20 1970 +0000
2430 date: Sat Jan 17 04:53:20 1970 +0000
2424 extra: branch=foo
2431 extra: branch=foo
2425 description:
2432 description:
2426 new branch
2433 new branch
2427
2434
2428
2435
2429 $ hg log -v -T bisect -r 0:4
2436 $ hg log -v -T bisect -r 0:4
2430 changeset: 0:1e4e1b8f71e0
2437 changeset: 0:1e4e1b8f71e0
2431 bisect: good (implicit)
2438 bisect: good (implicit)
2432 user: User Name <user@hostname>
2439 user: User Name <user@hostname>
2433 date: Mon Jan 12 13:46:40 1970 +0000
2440 date: Mon Jan 12 13:46:40 1970 +0000
2434 files: a
2441 files: a
2435 description:
2442 description:
2436 line 1
2443 line 1
2437 line 2
2444 line 2
2438
2445
2439
2446
2440 changeset: 1:b608e9d1a3f0
2447 changeset: 1:b608e9d1a3f0
2441 bisect: good
2448 bisect: good
2442 user: A. N. Other <other@place>
2449 user: A. N. Other <other@place>
2443 date: Tue Jan 13 17:33:20 1970 +0000
2450 date: Tue Jan 13 17:33:20 1970 +0000
2444 files: b
2451 files: b
2445 description:
2452 description:
2446 other 1
2453 other 1
2447 other 2
2454 other 2
2448
2455
2449 other 3
2456 other 3
2450
2457
2451
2458
2452 changeset: 2:97054abb4ab8
2459 changeset: 2:97054abb4ab8
2453 bisect: untested
2460 bisect: untested
2454 user: other@place
2461 user: other@place
2455 date: Wed Jan 14 21:20:00 1970 +0000
2462 date: Wed Jan 14 21:20:00 1970 +0000
2456 files: c
2463 files: c
2457 description:
2464 description:
2458 no person
2465 no person
2459
2466
2460
2467
2461 changeset: 3:10e46f2dcbf4
2468 changeset: 3:10e46f2dcbf4
2462 bisect: bad
2469 bisect: bad
2463 user: person
2470 user: person
2464 date: Fri Jan 16 01:06:40 1970 +0000
2471 date: Fri Jan 16 01:06:40 1970 +0000
2465 files: c
2472 files: c
2466 description:
2473 description:
2467 no user, no domain
2474 no user, no domain
2468
2475
2469
2476
2470 changeset: 4:bbe44766e73d
2477 changeset: 4:bbe44766e73d
2471 bisect: bad (implicit)
2478 bisect: bad (implicit)
2472 branch: foo
2479 branch: foo
2473 user: person
2480 user: person
2474 date: Sat Jan 17 04:53:20 1970 +0000
2481 date: Sat Jan 17 04:53:20 1970 +0000
2475 description:
2482 description:
2476 new branch
2483 new branch
2477
2484
2478
2485
2479 $ hg --color=debug log -T bisect -r 0:4
2486 $ hg --color=debug log -T bisect -r 0:4
2480 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2487 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2481 [log.bisect bisect.good|bisect: good (implicit)]
2488 [log.bisect bisect.good|bisect: good (implicit)]
2482 [log.user|user: User Name <user@hostname>]
2489 [log.user|user: User Name <user@hostname>]
2483 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2490 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2484 [log.summary|summary: line 1]
2491 [log.summary|summary: line 1]
2485
2492
2486 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2493 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2487 [log.bisect bisect.good|bisect: good]
2494 [log.bisect bisect.good|bisect: good]
2488 [log.user|user: A. N. Other <other@place>]
2495 [log.user|user: A. N. Other <other@place>]
2489 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2496 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2490 [log.summary|summary: other 1]
2497 [log.summary|summary: other 1]
2491
2498
2492 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2499 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2493 [log.bisect bisect.untested|bisect: untested]
2500 [log.bisect bisect.untested|bisect: untested]
2494 [log.user|user: other@place]
2501 [log.user|user: other@place]
2495 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2502 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2496 [log.summary|summary: no person]
2503 [log.summary|summary: no person]
2497
2504
2498 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2505 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2499 [log.bisect bisect.bad|bisect: bad]
2506 [log.bisect bisect.bad|bisect: bad]
2500 [log.user|user: person]
2507 [log.user|user: person]
2501 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2508 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2502 [log.summary|summary: no user, no domain]
2509 [log.summary|summary: no user, no domain]
2503
2510
2504 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2511 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2505 [log.bisect bisect.bad|bisect: bad (implicit)]
2512 [log.bisect bisect.bad|bisect: bad (implicit)]
2506 [log.branch|branch: foo]
2513 [log.branch|branch: foo]
2507 [log.user|user: person]
2514 [log.user|user: person]
2508 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2515 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2509 [log.summary|summary: new branch]
2516 [log.summary|summary: new branch]
2510
2517
2511 $ hg --color=debug log --debug -T bisect -r 0:4
2518 $ hg --color=debug log --debug -T bisect -r 0:4
2512 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2519 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2513 [log.bisect bisect.good|bisect: good (implicit)]
2520 [log.bisect bisect.good|bisect: good (implicit)]
2514 [log.phase|phase: public]
2521 [log.phase|phase: public]
2515 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2522 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2516 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2523 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2517 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2524 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2518 [log.user|user: User Name <user@hostname>]
2525 [log.user|user: User Name <user@hostname>]
2519 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2526 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2520 [ui.debug log.files|files+: a]
2527 [ui.debug log.files|files+: a]
2521 [ui.debug log.extra|extra: branch=default]
2528 [ui.debug log.extra|extra: branch=default]
2522 [ui.note log.description|description:]
2529 [ui.note log.description|description:]
2523 [ui.note log.description|line 1
2530 [ui.note log.description|line 1
2524 line 2]
2531 line 2]
2525
2532
2526
2533
2527 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2534 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2528 [log.bisect bisect.good|bisect: good]
2535 [log.bisect bisect.good|bisect: good]
2529 [log.phase|phase: public]
2536 [log.phase|phase: public]
2530 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2537 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2531 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2538 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2532 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2539 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2533 [log.user|user: A. N. Other <other@place>]
2540 [log.user|user: A. N. Other <other@place>]
2534 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2541 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2535 [ui.debug log.files|files+: b]
2542 [ui.debug log.files|files+: b]
2536 [ui.debug log.extra|extra: branch=default]
2543 [ui.debug log.extra|extra: branch=default]
2537 [ui.note log.description|description:]
2544 [ui.note log.description|description:]
2538 [ui.note log.description|other 1
2545 [ui.note log.description|other 1
2539 other 2
2546 other 2
2540
2547
2541 other 3]
2548 other 3]
2542
2549
2543
2550
2544 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2551 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2545 [log.bisect bisect.untested|bisect: untested]
2552 [log.bisect bisect.untested|bisect: untested]
2546 [log.phase|phase: public]
2553 [log.phase|phase: public]
2547 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2554 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2548 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2555 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2549 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2556 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2550 [log.user|user: other@place]
2557 [log.user|user: other@place]
2551 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2558 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2552 [ui.debug log.files|files+: c]
2559 [ui.debug log.files|files+: c]
2553 [ui.debug log.extra|extra: branch=default]
2560 [ui.debug log.extra|extra: branch=default]
2554 [ui.note log.description|description:]
2561 [ui.note log.description|description:]
2555 [ui.note log.description|no person]
2562 [ui.note log.description|no person]
2556
2563
2557
2564
2558 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2565 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2559 [log.bisect bisect.bad|bisect: bad]
2566 [log.bisect bisect.bad|bisect: bad]
2560 [log.phase|phase: public]
2567 [log.phase|phase: public]
2561 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2568 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2562 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2569 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2563 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2570 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2564 [log.user|user: person]
2571 [log.user|user: person]
2565 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2572 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2566 [ui.debug log.files|files: c]
2573 [ui.debug log.files|files: c]
2567 [ui.debug log.extra|extra: branch=default]
2574 [ui.debug log.extra|extra: branch=default]
2568 [ui.note log.description|description:]
2575 [ui.note log.description|description:]
2569 [ui.note log.description|no user, no domain]
2576 [ui.note log.description|no user, no domain]
2570
2577
2571
2578
2572 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2579 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2573 [log.bisect bisect.bad|bisect: bad (implicit)]
2580 [log.bisect bisect.bad|bisect: bad (implicit)]
2574 [log.branch|branch: foo]
2581 [log.branch|branch: foo]
2575 [log.phase|phase: draft]
2582 [log.phase|phase: draft]
2576 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2583 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2577 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2584 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2578 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2585 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2579 [log.user|user: person]
2586 [log.user|user: person]
2580 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2587 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2581 [ui.debug log.extra|extra: branch=foo]
2588 [ui.debug log.extra|extra: branch=foo]
2582 [ui.note log.description|description:]
2589 [ui.note log.description|description:]
2583 [ui.note log.description|new branch]
2590 [ui.note log.description|new branch]
2584
2591
2585
2592
2586 $ hg --color=debug log -v -T bisect -r 0:4
2593 $ hg --color=debug log -v -T bisect -r 0:4
2587 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2594 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2588 [log.bisect bisect.good|bisect: good (implicit)]
2595 [log.bisect bisect.good|bisect: good (implicit)]
2589 [log.user|user: User Name <user@hostname>]
2596 [log.user|user: User Name <user@hostname>]
2590 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2597 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2591 [ui.note log.files|files: a]
2598 [ui.note log.files|files: a]
2592 [ui.note log.description|description:]
2599 [ui.note log.description|description:]
2593 [ui.note log.description|line 1
2600 [ui.note log.description|line 1
2594 line 2]
2601 line 2]
2595
2602
2596
2603
2597 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2604 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2598 [log.bisect bisect.good|bisect: good]
2605 [log.bisect bisect.good|bisect: good]
2599 [log.user|user: A. N. Other <other@place>]
2606 [log.user|user: A. N. Other <other@place>]
2600 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2607 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2601 [ui.note log.files|files: b]
2608 [ui.note log.files|files: b]
2602 [ui.note log.description|description:]
2609 [ui.note log.description|description:]
2603 [ui.note log.description|other 1
2610 [ui.note log.description|other 1
2604 other 2
2611 other 2
2605
2612
2606 other 3]
2613 other 3]
2607
2614
2608
2615
2609 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2616 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2610 [log.bisect bisect.untested|bisect: untested]
2617 [log.bisect bisect.untested|bisect: untested]
2611 [log.user|user: other@place]
2618 [log.user|user: other@place]
2612 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2619 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2613 [ui.note log.files|files: c]
2620 [ui.note log.files|files: c]
2614 [ui.note log.description|description:]
2621 [ui.note log.description|description:]
2615 [ui.note log.description|no person]
2622 [ui.note log.description|no person]
2616
2623
2617
2624
2618 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2625 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2619 [log.bisect bisect.bad|bisect: bad]
2626 [log.bisect bisect.bad|bisect: bad]
2620 [log.user|user: person]
2627 [log.user|user: person]
2621 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2628 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2622 [ui.note log.files|files: c]
2629 [ui.note log.files|files: c]
2623 [ui.note log.description|description:]
2630 [ui.note log.description|description:]
2624 [ui.note log.description|no user, no domain]
2631 [ui.note log.description|no user, no domain]
2625
2632
2626
2633
2627 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2634 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2628 [log.bisect bisect.bad|bisect: bad (implicit)]
2635 [log.bisect bisect.bad|bisect: bad (implicit)]
2629 [log.branch|branch: foo]
2636 [log.branch|branch: foo]
2630 [log.user|user: person]
2637 [log.user|user: person]
2631 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2638 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2632 [ui.note log.description|description:]
2639 [ui.note log.description|description:]
2633 [ui.note log.description|new branch]
2640 [ui.note log.description|new branch]
2634
2641
2635
2642
2636 $ hg bisect --reset
2643 $ hg bisect --reset
2637
2644
2638 Error on syntax:
2645 Error on syntax:
2639
2646
2640 $ echo 'x = "f' >> t
2647 $ echo 'x = "f' >> t
2641 $ hg log
2648 $ hg log
2642 hg: parse error at t:3: unmatched quotes
2649 hg: parse error at t:3: unmatched quotes
2643 [255]
2650 [255]
2644
2651
2645 $ hg log -T '{date'
2652 $ hg log -T '{date'
2646 hg: parse error at 1: unterminated template expansion
2653 hg: parse error at 1: unterminated template expansion
2647 [255]
2654 [255]
2648
2655
2649 Behind the scenes, this will throw TypeError
2656 Behind the scenes, this will throw TypeError
2650
2657
2651 $ hg log -l 3 --template '{date|obfuscate}\n'
2658 $ hg log -l 3 --template '{date|obfuscate}\n'
2652 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2659 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2653 [255]
2660 [255]
2654
2661
2655 Behind the scenes, this will throw a ValueError
2662 Behind the scenes, this will throw a ValueError
2656
2663
2657 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2664 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2658 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2665 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2659 [255]
2666 [255]
2660
2667
2661 Behind the scenes, this will throw AttributeError
2668 Behind the scenes, this will throw AttributeError
2662
2669
2663 $ hg log -l 3 --template 'line: {date|escape}\n'
2670 $ hg log -l 3 --template 'line: {date|escape}\n'
2664 abort: template filter 'escape' is not compatible with keyword 'date'
2671 abort: template filter 'escape' is not compatible with keyword 'date'
2665 [255]
2672 [255]
2666
2673
2667 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2674 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2668 hg: parse error: localdate expects a date information
2675 hg: parse error: localdate expects a date information
2669 [255]
2676 [255]
2670
2677
2671 Behind the scenes, this will throw ValueError
2678 Behind the scenes, this will throw ValueError
2672
2679
2673 $ hg tip --template '{author|email|date}\n'
2680 $ hg tip --template '{author|email|date}\n'
2674 hg: parse error: date expects a date information
2681 hg: parse error: date expects a date information
2675 [255]
2682 [255]
2676
2683
2677 Error in nested template:
2684 Error in nested template:
2678
2685
2679 $ hg log -T '{"date'
2686 $ hg log -T '{"date'
2680 hg: parse error at 2: unterminated string
2687 hg: parse error at 2: unterminated string
2681 [255]
2688 [255]
2682
2689
2683 $ hg log -T '{"foo{date|?}"}'
2690 $ hg log -T '{"foo{date|?}"}'
2684 hg: parse error at 11: syntax error
2691 hg: parse error at 11: syntax error
2685 [255]
2692 [255]
2686
2693
2687 Thrown an error if a template function doesn't exist
2694 Thrown an error if a template function doesn't exist
2688
2695
2689 $ hg tip --template '{foo()}\n'
2696 $ hg tip --template '{foo()}\n'
2690 hg: parse error: unknown function 'foo'
2697 hg: parse error: unknown function 'foo'
2691 [255]
2698 [255]
2692
2699
2693 Pass generator object created by template function to filter
2700 Pass generator object created by template function to filter
2694
2701
2695 $ hg log -l 1 --template '{if(author, author)|user}\n'
2702 $ hg log -l 1 --template '{if(author, author)|user}\n'
2696 test
2703 test
2697
2704
2698 Test index keyword:
2705 Test index keyword:
2699
2706
2700 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2707 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2701 10 0:a 1:b 2:fifth 3:fourth 4:third
2708 10 0:a 1:b 2:fifth 3:fourth 4:third
2702 11 0:a
2709 11 0:a
2703
2710
2704 $ hg branches -T '{index} {branch}\n'
2711 $ hg branches -T '{index} {branch}\n'
2705 0 default
2712 0 default
2706 1 foo
2713 1 foo
2707
2714
2708 Test diff function:
2715 Test diff function:
2709
2716
2710 $ hg diff -c 8
2717 $ hg diff -c 8
2711 diff -r 29114dbae42b -r 95c24699272e fourth
2718 diff -r 29114dbae42b -r 95c24699272e fourth
2712 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2719 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2713 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2720 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2714 @@ -0,0 +1,1 @@
2721 @@ -0,0 +1,1 @@
2715 +second
2722 +second
2716 diff -r 29114dbae42b -r 95c24699272e second
2723 diff -r 29114dbae42b -r 95c24699272e second
2717 --- a/second Mon Jan 12 13:46:40 1970 +0000
2724 --- a/second Mon Jan 12 13:46:40 1970 +0000
2718 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2725 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2719 @@ -1,1 +0,0 @@
2726 @@ -1,1 +0,0 @@
2720 -second
2727 -second
2721 diff -r 29114dbae42b -r 95c24699272e third
2728 diff -r 29114dbae42b -r 95c24699272e third
2722 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2729 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2723 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2730 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2724 @@ -0,0 +1,1 @@
2731 @@ -0,0 +1,1 @@
2725 +third
2732 +third
2726
2733
2727 $ hg log -r 8 -T "{diff()}"
2734 $ hg log -r 8 -T "{diff()}"
2728 diff -r 29114dbae42b -r 95c24699272e fourth
2735 diff -r 29114dbae42b -r 95c24699272e fourth
2729 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2736 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2730 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2737 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2731 @@ -0,0 +1,1 @@
2738 @@ -0,0 +1,1 @@
2732 +second
2739 +second
2733 diff -r 29114dbae42b -r 95c24699272e second
2740 diff -r 29114dbae42b -r 95c24699272e second
2734 --- a/second Mon Jan 12 13:46:40 1970 +0000
2741 --- a/second Mon Jan 12 13:46:40 1970 +0000
2735 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2742 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2736 @@ -1,1 +0,0 @@
2743 @@ -1,1 +0,0 @@
2737 -second
2744 -second
2738 diff -r 29114dbae42b -r 95c24699272e third
2745 diff -r 29114dbae42b -r 95c24699272e third
2739 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2746 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2740 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2747 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2741 @@ -0,0 +1,1 @@
2748 @@ -0,0 +1,1 @@
2742 +third
2749 +third
2743
2750
2744 $ hg log -r 8 -T "{diff('glob:f*')}"
2751 $ hg log -r 8 -T "{diff('glob:f*')}"
2745 diff -r 29114dbae42b -r 95c24699272e fourth
2752 diff -r 29114dbae42b -r 95c24699272e fourth
2746 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2753 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2747 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2754 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2748 @@ -0,0 +1,1 @@
2755 @@ -0,0 +1,1 @@
2749 +second
2756 +second
2750
2757
2751 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2758 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2752 diff -r 29114dbae42b -r 95c24699272e second
2759 diff -r 29114dbae42b -r 95c24699272e second
2753 --- a/second Mon Jan 12 13:46:40 1970 +0000
2760 --- a/second Mon Jan 12 13:46:40 1970 +0000
2754 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2761 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2755 @@ -1,1 +0,0 @@
2762 @@ -1,1 +0,0 @@
2756 -second
2763 -second
2757 diff -r 29114dbae42b -r 95c24699272e third
2764 diff -r 29114dbae42b -r 95c24699272e third
2758 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2765 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2759 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2766 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2760 @@ -0,0 +1,1 @@
2767 @@ -0,0 +1,1 @@
2761 +third
2768 +third
2762
2769
2763 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2770 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2764 diff -r 29114dbae42b -r 95c24699272e fourth
2771 diff -r 29114dbae42b -r 95c24699272e fourth
2765 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2772 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2766 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2773 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2767 @@ -0,0 +1,1 @@
2774 @@ -0,0 +1,1 @@
2768 +second
2775 +second
2769
2776
2770 $ cd ..
2777 $ cd ..
2771
2778
2772
2779
2773 latesttag:
2780 latesttag:
2774
2781
2775 $ hg init latesttag
2782 $ hg init latesttag
2776 $ cd latesttag
2783 $ cd latesttag
2777
2784
2778 $ echo a > file
2785 $ echo a > file
2779 $ hg ci -Am a -d '0 0'
2786 $ hg ci -Am a -d '0 0'
2780 adding file
2787 adding file
2781
2788
2782 $ echo b >> file
2789 $ echo b >> file
2783 $ hg ci -m b -d '1 0'
2790 $ hg ci -m b -d '1 0'
2784
2791
2785 $ echo c >> head1
2792 $ echo c >> head1
2786 $ hg ci -Am h1c -d '2 0'
2793 $ hg ci -Am h1c -d '2 0'
2787 adding head1
2794 adding head1
2788
2795
2789 $ hg update -q 1
2796 $ hg update -q 1
2790 $ echo d >> head2
2797 $ echo d >> head2
2791 $ hg ci -Am h2d -d '3 0'
2798 $ hg ci -Am h2d -d '3 0'
2792 adding head2
2799 adding head2
2793 created new head
2800 created new head
2794
2801
2795 $ echo e >> head2
2802 $ echo e >> head2
2796 $ hg ci -m h2e -d '4 0'
2803 $ hg ci -m h2e -d '4 0'
2797
2804
2798 $ hg merge -q
2805 $ hg merge -q
2799 $ hg ci -m merge -d '5 -3600'
2806 $ hg ci -m merge -d '5 -3600'
2800
2807
2801 No tag set:
2808 No tag set:
2802
2809
2803 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2810 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2804 5: null+5
2811 5: null+5
2805 4: null+4
2812 4: null+4
2806 3: null+3
2813 3: null+3
2807 2: null+3
2814 2: null+3
2808 1: null+2
2815 1: null+2
2809 0: null+1
2816 0: null+1
2810
2817
2811 One common tag: longest path wins:
2818 One common tag: longest path wins:
2812
2819
2813 $ hg tag -r 1 -m t1 -d '6 0' t1
2820 $ hg tag -r 1 -m t1 -d '6 0' t1
2814 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2821 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2815 6: t1+4
2822 6: t1+4
2816 5: t1+3
2823 5: t1+3
2817 4: t1+2
2824 4: t1+2
2818 3: t1+1
2825 3: t1+1
2819 2: t1+1
2826 2: t1+1
2820 1: t1+0
2827 1: t1+0
2821 0: null+1
2828 0: null+1
2822
2829
2823 One ancestor tag: more recent wins:
2830 One ancestor tag: more recent wins:
2824
2831
2825 $ hg tag -r 2 -m t2 -d '7 0' t2
2832 $ hg tag -r 2 -m t2 -d '7 0' t2
2826 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2833 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2827 7: t2+3
2834 7: t2+3
2828 6: t2+2
2835 6: t2+2
2829 5: t2+1
2836 5: t2+1
2830 4: t1+2
2837 4: t1+2
2831 3: t1+1
2838 3: t1+1
2832 2: t2+0
2839 2: t2+0
2833 1: t1+0
2840 1: t1+0
2834 0: null+1
2841 0: null+1
2835
2842
2836 Two branch tags: more recent wins:
2843 Two branch tags: more recent wins:
2837
2844
2838 $ hg tag -r 3 -m t3 -d '8 0' t3
2845 $ hg tag -r 3 -m t3 -d '8 0' t3
2839 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2846 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2840 8: t3+5
2847 8: t3+5
2841 7: t3+4
2848 7: t3+4
2842 6: t3+3
2849 6: t3+3
2843 5: t3+2
2850 5: t3+2
2844 4: t3+1
2851 4: t3+1
2845 3: t3+0
2852 3: t3+0
2846 2: t2+0
2853 2: t2+0
2847 1: t1+0
2854 1: t1+0
2848 0: null+1
2855 0: null+1
2849
2856
2850 Merged tag overrides:
2857 Merged tag overrides:
2851
2858
2852 $ hg tag -r 5 -m t5 -d '9 0' t5
2859 $ hg tag -r 5 -m t5 -d '9 0' t5
2853 $ hg tag -r 3 -m at3 -d '10 0' at3
2860 $ hg tag -r 3 -m at3 -d '10 0' at3
2854 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2861 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2855 10: t5+5
2862 10: t5+5
2856 9: t5+4
2863 9: t5+4
2857 8: t5+3
2864 8: t5+3
2858 7: t5+2
2865 7: t5+2
2859 6: t5+1
2866 6: t5+1
2860 5: t5+0
2867 5: t5+0
2861 4: at3:t3+1
2868 4: at3:t3+1
2862 3: at3:t3+0
2869 3: at3:t3+0
2863 2: t2+0
2870 2: t2+0
2864 1: t1+0
2871 1: t1+0
2865 0: null+1
2872 0: null+1
2866
2873
2867 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2874 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2868 10: t5+5,5
2875 10: t5+5,5
2869 9: t5+4,4
2876 9: t5+4,4
2870 8: t5+3,3
2877 8: t5+3,3
2871 7: t5+2,2
2878 7: t5+2,2
2872 6: t5+1,1
2879 6: t5+1,1
2873 5: t5+0,0
2880 5: t5+0,0
2874 4: at3+1,1 t3+1,1
2881 4: at3+1,1 t3+1,1
2875 3: at3+0,0 t3+0,0
2882 3: at3+0,0 t3+0,0
2876 2: t2+0,0
2883 2: t2+0,0
2877 1: t1+0,0
2884 1: t1+0,0
2878 0: null+1,1
2885 0: null+1,1
2879
2886
2880 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2887 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2881 10: t3, C: 8, D: 7
2888 10: t3, C: 8, D: 7
2882 9: t3, C: 7, D: 6
2889 9: t3, C: 7, D: 6
2883 8: t3, C: 6, D: 5
2890 8: t3, C: 6, D: 5
2884 7: t3, C: 5, D: 4
2891 7: t3, C: 5, D: 4
2885 6: t3, C: 4, D: 3
2892 6: t3, C: 4, D: 3
2886 5: t3, C: 3, D: 2
2893 5: t3, C: 3, D: 2
2887 4: t3, C: 1, D: 1
2894 4: t3, C: 1, D: 1
2888 3: t3, C: 0, D: 0
2895 3: t3, C: 0, D: 0
2889 2: t1, C: 1, D: 1
2896 2: t1, C: 1, D: 1
2890 1: t1, C: 0, D: 0
2897 1: t1, C: 0, D: 0
2891 0: null, C: 1, D: 1
2898 0: null, C: 1, D: 1
2892
2899
2893 $ cd ..
2900 $ cd ..
2894
2901
2895
2902
2896 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2903 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2897 if it is a relative path
2904 if it is a relative path
2898
2905
2899 $ mkdir -p home/styles
2906 $ mkdir -p home/styles
2900
2907
2901 $ cat > home/styles/teststyle <<EOF
2908 $ cat > home/styles/teststyle <<EOF
2902 > changeset = 'test {rev}:{node|short}\n'
2909 > changeset = 'test {rev}:{node|short}\n'
2903 > EOF
2910 > EOF
2904
2911
2905 $ HOME=`pwd`/home; export HOME
2912 $ HOME=`pwd`/home; export HOME
2906
2913
2907 $ cat > latesttag/.hg/hgrc <<EOF
2914 $ cat > latesttag/.hg/hgrc <<EOF
2908 > [ui]
2915 > [ui]
2909 > style = ~/styles/teststyle
2916 > style = ~/styles/teststyle
2910 > EOF
2917 > EOF
2911
2918
2912 $ hg -R latesttag tip
2919 $ hg -R latesttag tip
2913 test 10:9b4a630e5f5f
2920 test 10:9b4a630e5f5f
2914
2921
2915 Test recursive showlist template (issue1989):
2922 Test recursive showlist template (issue1989):
2916
2923
2917 $ cat > style1989 <<EOF
2924 $ cat > style1989 <<EOF
2918 > changeset = '{file_mods}{manifest}{extras}'
2925 > changeset = '{file_mods}{manifest}{extras}'
2919 > file_mod = 'M|{author|person}\n'
2926 > file_mod = 'M|{author|person}\n'
2920 > manifest = '{rev},{author}\n'
2927 > manifest = '{rev},{author}\n'
2921 > extra = '{key}: {author}\n'
2928 > extra = '{key}: {author}\n'
2922 > EOF
2929 > EOF
2923
2930
2924 $ hg -R latesttag log -r tip --style=style1989
2931 $ hg -R latesttag log -r tip --style=style1989
2925 M|test
2932 M|test
2926 10,test
2933 10,test
2927 branch: test
2934 branch: test
2928
2935
2929 Test new-style inline templating:
2936 Test new-style inline templating:
2930
2937
2931 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2938 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2932 modified files: .hgtags
2939 modified files: .hgtags
2933
2940
2934
2941
2935 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
2942 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
2936 hg: parse error: keyword 'rev' is not iterable
2943 hg: parse error: keyword 'rev' is not iterable
2937 [255]
2944 [255]
2938 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
2945 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
2939 hg: parse error: None is not iterable
2946 hg: parse error: None is not iterable
2940 [255]
2947 [255]
2941
2948
2942 Test the sub function of templating for expansion:
2949 Test the sub function of templating for expansion:
2943
2950
2944 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2951 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2945 xx
2952 xx
2946
2953
2947 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2954 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2948 hg: parse error: sub got an invalid pattern: [
2955 hg: parse error: sub got an invalid pattern: [
2949 [255]
2956 [255]
2950 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2957 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2951 hg: parse error: sub got an invalid replacement: \1
2958 hg: parse error: sub got an invalid replacement: \1
2952 [255]
2959 [255]
2953
2960
2954 Test the strip function with chars specified:
2961 Test the strip function with chars specified:
2955
2962
2956 $ hg log -R latesttag --template '{desc}\n'
2963 $ hg log -R latesttag --template '{desc}\n'
2957 at3
2964 at3
2958 t5
2965 t5
2959 t3
2966 t3
2960 t2
2967 t2
2961 t1
2968 t1
2962 merge
2969 merge
2963 h2e
2970 h2e
2964 h2d
2971 h2d
2965 h1c
2972 h1c
2966 b
2973 b
2967 a
2974 a
2968
2975
2969 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2976 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2970 at3
2977 at3
2971 5
2978 5
2972 3
2979 3
2973 2
2980 2
2974 1
2981 1
2975 merg
2982 merg
2976 h2
2983 h2
2977 h2d
2984 h2d
2978 h1c
2985 h1c
2979 b
2986 b
2980 a
2987 a
2981
2988
2982 Test date format:
2989 Test date format:
2983
2990
2984 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2991 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2985 date: 70 01 01 10 +0000
2992 date: 70 01 01 10 +0000
2986 date: 70 01 01 09 +0000
2993 date: 70 01 01 09 +0000
2987 date: 70 01 01 08 +0000
2994 date: 70 01 01 08 +0000
2988 date: 70 01 01 07 +0000
2995 date: 70 01 01 07 +0000
2989 date: 70 01 01 06 +0000
2996 date: 70 01 01 06 +0000
2990 date: 70 01 01 05 +0100
2997 date: 70 01 01 05 +0100
2991 date: 70 01 01 04 +0000
2998 date: 70 01 01 04 +0000
2992 date: 70 01 01 03 +0000
2999 date: 70 01 01 03 +0000
2993 date: 70 01 01 02 +0000
3000 date: 70 01 01 02 +0000
2994 date: 70 01 01 01 +0000
3001 date: 70 01 01 01 +0000
2995 date: 70 01 01 00 +0000
3002 date: 70 01 01 00 +0000
2996
3003
2997 Test invalid date:
3004 Test invalid date:
2998
3005
2999 $ hg log -R latesttag -T '{date(rev)}\n'
3006 $ hg log -R latesttag -T '{date(rev)}\n'
3000 hg: parse error: date expects a date information
3007 hg: parse error: date expects a date information
3001 [255]
3008 [255]
3002
3009
3003 Test integer literal:
3010 Test integer literal:
3004
3011
3005 $ hg debugtemplate -v '{(0)}\n'
3012 $ hg debugtemplate -v '{(0)}\n'
3006 (template
3013 (template
3007 (group
3014 (group
3008 ('integer', '0'))
3015 ('integer', '0'))
3009 ('string', '\n'))
3016 ('string', '\n'))
3010 0
3017 0
3011 $ hg debugtemplate -v '{(123)}\n'
3018 $ hg debugtemplate -v '{(123)}\n'
3012 (template
3019 (template
3013 (group
3020 (group
3014 ('integer', '123'))
3021 ('integer', '123'))
3015 ('string', '\n'))
3022 ('string', '\n'))
3016 123
3023 123
3017 $ hg debugtemplate -v '{(-4)}\n'
3024 $ hg debugtemplate -v '{(-4)}\n'
3018 (template
3025 (template
3019 (group
3026 (group
3020 (negate
3027 (negate
3021 ('integer', '4')))
3028 ('integer', '4')))
3022 ('string', '\n'))
3029 ('string', '\n'))
3023 -4
3030 -4
3024 $ hg debugtemplate '{(-)}\n'
3031 $ hg debugtemplate '{(-)}\n'
3025 hg: parse error at 3: not a prefix: )
3032 hg: parse error at 3: not a prefix: )
3026 [255]
3033 [255]
3027 $ hg debugtemplate '{(-a)}\n'
3034 $ hg debugtemplate '{(-a)}\n'
3028 hg: parse error: negation needs an integer argument
3035 hg: parse error: negation needs an integer argument
3029 [255]
3036 [255]
3030
3037
3031 top-level integer literal is interpreted as symbol (i.e. variable name):
3038 top-level integer literal is interpreted as symbol (i.e. variable name):
3032
3039
3033 $ hg debugtemplate -D 1=one -v '{1}\n'
3040 $ hg debugtemplate -D 1=one -v '{1}\n'
3034 (template
3041 (template
3035 ('integer', '1')
3042 ('integer', '1')
3036 ('string', '\n'))
3043 ('string', '\n'))
3037 one
3044 one
3038 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3045 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3039 (template
3046 (template
3040 (func
3047 (func
3041 ('symbol', 'if')
3048 ('symbol', 'if')
3042 (list
3049 (list
3043 ('string', 't')
3050 ('string', 't')
3044 (template
3051 (template
3045 ('integer', '1'))))
3052 ('integer', '1'))))
3046 ('string', '\n'))
3053 ('string', '\n'))
3047 one
3054 one
3048 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3055 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3049 (template
3056 (template
3050 (|
3057 (|
3051 ('integer', '1')
3058 ('integer', '1')
3052 ('symbol', 'stringify'))
3059 ('symbol', 'stringify'))
3053 ('string', '\n'))
3060 ('string', '\n'))
3054 one
3061 one
3055
3062
3056 unless explicit symbol is expected:
3063 unless explicit symbol is expected:
3057
3064
3058 $ hg log -Ra -r0 -T '{desc|1}\n'
3065 $ hg log -Ra -r0 -T '{desc|1}\n'
3059 hg: parse error: expected a symbol, got 'integer'
3066 hg: parse error: expected a symbol, got 'integer'
3060 [255]
3067 [255]
3061 $ hg log -Ra -r0 -T '{1()}\n'
3068 $ hg log -Ra -r0 -T '{1()}\n'
3062 hg: parse error: expected a symbol, got 'integer'
3069 hg: parse error: expected a symbol, got 'integer'
3063 [255]
3070 [255]
3064
3071
3065 Test string literal:
3072 Test string literal:
3066
3073
3067 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3074 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3068 (template
3075 (template
3069 ('string', 'string with no template fragment')
3076 ('string', 'string with no template fragment')
3070 ('string', '\n'))
3077 ('string', '\n'))
3071 string with no template fragment
3078 string with no template fragment
3072 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3079 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3073 (template
3080 (template
3074 (template
3081 (template
3075 ('string', 'template: ')
3082 ('string', 'template: ')
3076 ('symbol', 'rev'))
3083 ('symbol', 'rev'))
3077 ('string', '\n'))
3084 ('string', '\n'))
3078 template: 0
3085 template: 0
3079 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3086 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3080 (template
3087 (template
3081 ('string', 'rawstring: {rev}')
3088 ('string', 'rawstring: {rev}')
3082 ('string', '\n'))
3089 ('string', '\n'))
3083 rawstring: {rev}
3090 rawstring: {rev}
3084 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3091 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3085 (template
3092 (template
3086 (%
3093 (%
3087 ('symbol', 'files')
3094 ('symbol', 'files')
3088 ('string', 'rawstring: {file}'))
3095 ('string', 'rawstring: {file}'))
3089 ('string', '\n'))
3096 ('string', '\n'))
3090 rawstring: {file}
3097 rawstring: {file}
3091
3098
3092 Test string escaping:
3099 Test string escaping:
3093
3100
3094 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3101 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3095 >
3102 >
3096 <>\n<[>
3103 <>\n<[>
3097 <>\n<]>
3104 <>\n<]>
3098 <>\n<
3105 <>\n<
3099
3106
3100 $ hg log -R latesttag -r 0 \
3107 $ hg log -R latesttag -r 0 \
3101 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3108 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3102 >
3109 >
3103 <>\n<[>
3110 <>\n<[>
3104 <>\n<]>
3111 <>\n<]>
3105 <>\n<
3112 <>\n<
3106
3113
3107 $ hg log -R latesttag -r 0 -T esc \
3114 $ hg log -R latesttag -r 0 -T esc \
3108 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3115 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3109 >
3116 >
3110 <>\n<[>
3117 <>\n<[>
3111 <>\n<]>
3118 <>\n<]>
3112 <>\n<
3119 <>\n<
3113
3120
3114 $ cat <<'EOF' > esctmpl
3121 $ cat <<'EOF' > esctmpl
3115 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3122 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3116 > EOF
3123 > EOF
3117 $ hg log -R latesttag -r 0 --style ./esctmpl
3124 $ hg log -R latesttag -r 0 --style ./esctmpl
3118 >
3125 >
3119 <>\n<[>
3126 <>\n<[>
3120 <>\n<]>
3127 <>\n<]>
3121 <>\n<
3128 <>\n<
3122
3129
3123 Test string escaping of quotes:
3130 Test string escaping of quotes:
3124
3131
3125 $ hg log -Ra -r0 -T '{"\""}\n'
3132 $ hg log -Ra -r0 -T '{"\""}\n'
3126 "
3133 "
3127 $ hg log -Ra -r0 -T '{"\\\""}\n'
3134 $ hg log -Ra -r0 -T '{"\\\""}\n'
3128 \"
3135 \"
3129 $ hg log -Ra -r0 -T '{r"\""}\n'
3136 $ hg log -Ra -r0 -T '{r"\""}\n'
3130 \"
3137 \"
3131 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3138 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3132 \\\"
3139 \\\"
3133
3140
3134
3141
3135 $ hg log -Ra -r0 -T '{"\""}\n'
3142 $ hg log -Ra -r0 -T '{"\""}\n'
3136 "
3143 "
3137 $ hg log -Ra -r0 -T '{"\\\""}\n'
3144 $ hg log -Ra -r0 -T '{"\\\""}\n'
3138 \"
3145 \"
3139 $ hg log -Ra -r0 -T '{r"\""}\n'
3146 $ hg log -Ra -r0 -T '{r"\""}\n'
3140 \"
3147 \"
3141 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3148 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3142 \\\"
3149 \\\"
3143
3150
3144 Test exception in quoted template. single backslash before quotation mark is
3151 Test exception in quoted template. single backslash before quotation mark is
3145 stripped before parsing:
3152 stripped before parsing:
3146
3153
3147 $ cat <<'EOF' > escquotetmpl
3154 $ cat <<'EOF' > escquotetmpl
3148 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3155 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3149 > EOF
3156 > EOF
3150 $ cd latesttag
3157 $ cd latesttag
3151 $ hg log -r 2 --style ../escquotetmpl
3158 $ hg log -r 2 --style ../escquotetmpl
3152 " \" \" \\" head1
3159 " \" \" \\" head1
3153
3160
3154 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3161 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3155 valid
3162 valid
3156 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3163 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3157 valid
3164 valid
3158
3165
3159 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3166 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3160 _evalifliteral() templates (issue4733):
3167 _evalifliteral() templates (issue4733):
3161
3168
3162 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3169 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3163 "2
3170 "2
3164 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3171 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3165 "2
3172 "2
3166 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3173 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3167 "2
3174 "2
3168
3175
3169 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3176 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3170 \"
3177 \"
3171 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3178 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3172 \"
3179 \"
3173 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3180 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3174 \"
3181 \"
3175
3182
3176 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3183 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3177 \\\"
3184 \\\"
3178 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3185 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3179 \\\"
3186 \\\"
3180 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3187 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3181 \\\"
3188 \\\"
3182
3189
3183 escaped single quotes and errors:
3190 escaped single quotes and errors:
3184
3191
3185 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3192 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3186 foo
3193 foo
3187 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3194 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3188 foo
3195 foo
3189 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3196 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3190 hg: parse error at 21: unterminated string
3197 hg: parse error at 21: unterminated string
3191 [255]
3198 [255]
3192 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3199 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3193 hg: parse error: trailing \ in string
3200 hg: parse error: trailing \ in string
3194 [255]
3201 [255]
3195 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3202 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3196 hg: parse error: trailing \ in string
3203 hg: parse error: trailing \ in string
3197 [255]
3204 [255]
3198
3205
3199 $ cd ..
3206 $ cd ..
3200
3207
3201 Test leading backslashes:
3208 Test leading backslashes:
3202
3209
3203 $ cd latesttag
3210 $ cd latesttag
3204 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3211 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3205 {rev} {file}
3212 {rev} {file}
3206 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3213 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3207 \2 \head1
3214 \2 \head1
3208 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3215 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3209 \{rev} \{file}
3216 \{rev} \{file}
3210 $ cd ..
3217 $ cd ..
3211
3218
3212 Test leading backslashes in "if" expression (issue4714):
3219 Test leading backslashes in "if" expression (issue4714):
3213
3220
3214 $ cd latesttag
3221 $ cd latesttag
3215 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3222 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3216 {rev} \{rev}
3223 {rev} \{rev}
3217 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3224 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3218 \2 \\{rev}
3225 \2 \\{rev}
3219 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3226 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3220 \{rev} \\\{rev}
3227 \{rev} \\\{rev}
3221 $ cd ..
3228 $ cd ..
3222
3229
3223 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3230 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3224
3231
3225 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3232 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3226 \x6e
3233 \x6e
3227 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3234 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3228 \x5c\x786e
3235 \x5c\x786e
3229 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3236 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3230 \x6e
3237 \x6e
3231 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3238 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3232 \x5c\x786e
3239 \x5c\x786e
3233
3240
3234 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3241 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3235 \x6e
3242 \x6e
3236 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3243 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3237 \x5c\x786e
3244 \x5c\x786e
3238 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3245 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3239 \x6e
3246 \x6e
3240 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3247 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3241 \x5c\x786e
3248 \x5c\x786e
3242
3249
3243 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3250 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3244 fourth
3251 fourth
3245 second
3252 second
3246 third
3253 third
3247 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3254 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3248 fourth\nsecond\nthird
3255 fourth\nsecond\nthird
3249
3256
3250 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3257 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3251 <p>
3258 <p>
3252 1st
3259 1st
3253 </p>
3260 </p>
3254 <p>
3261 <p>
3255 2nd
3262 2nd
3256 </p>
3263 </p>
3257 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3264 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3258 <p>
3265 <p>
3259 1st\n\n2nd
3266 1st\n\n2nd
3260 </p>
3267 </p>
3261 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3268 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3262 1st
3269 1st
3263
3270
3264 2nd
3271 2nd
3265
3272
3266 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3273 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3267 o perso
3274 o perso
3268 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3275 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3269 no person
3276 no person
3270 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3277 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3271 o perso
3278 o perso
3272 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3279 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3273 no perso
3280 no perso
3274
3281
3275 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3282 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3276 -o perso-
3283 -o perso-
3277 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3284 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3278 no person
3285 no person
3279 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3286 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3280 \x2do perso\x2d
3287 \x2do perso\x2d
3281 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3288 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3282 -o perso-
3289 -o perso-
3283 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3290 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3284 \x2do perso\x6e
3291 \x2do perso\x6e
3285
3292
3286 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3293 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3287 fourth
3294 fourth
3288 second
3295 second
3289 third
3296 third
3290
3297
3291 Test string escaping in nested expression:
3298 Test string escaping in nested expression:
3292
3299
3293 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3300 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3294 fourth\x6esecond\x6ethird
3301 fourth\x6esecond\x6ethird
3295 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3302 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3296 fourth\x6esecond\x6ethird
3303 fourth\x6esecond\x6ethird
3297
3304
3298 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3305 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3299 fourth\x6esecond\x6ethird
3306 fourth\x6esecond\x6ethird
3300 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3307 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3301 fourth\x5c\x786esecond\x5c\x786ethird
3308 fourth\x5c\x786esecond\x5c\x786ethird
3302
3309
3303 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3310 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3304 3:\x6eo user, \x6eo domai\x6e
3311 3:\x6eo user, \x6eo domai\x6e
3305 4:\x5c\x786eew bra\x5c\x786ech
3312 4:\x5c\x786eew bra\x5c\x786ech
3306
3313
3307 Test quotes in nested expression are evaluated just like a $(command)
3314 Test quotes in nested expression are evaluated just like a $(command)
3308 substitution in POSIX shells:
3315 substitution in POSIX shells:
3309
3316
3310 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3317 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3311 8:95c24699272e
3318 8:95c24699272e
3312 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3319 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3313 {8} "95c24699272e"
3320 {8} "95c24699272e"
3314
3321
3315 Test recursive evaluation:
3322 Test recursive evaluation:
3316
3323
3317 $ hg init r
3324 $ hg init r
3318 $ cd r
3325 $ cd r
3319 $ echo a > a
3326 $ echo a > a
3320 $ hg ci -Am '{rev}'
3327 $ hg ci -Am '{rev}'
3321 adding a
3328 adding a
3322 $ hg log -r 0 --template '{if(rev, desc)}\n'
3329 $ hg log -r 0 --template '{if(rev, desc)}\n'
3323 {rev}
3330 {rev}
3324 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3331 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3325 test 0
3332 test 0
3326
3333
3327 $ hg branch -q 'text.{rev}'
3334 $ hg branch -q 'text.{rev}'
3328 $ echo aa >> aa
3335 $ echo aa >> aa
3329 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3336 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3330
3337
3331 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3338 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3332 {node|short}desc to
3339 {node|short}desc to
3333 text.{rev}be wrapped
3340 text.{rev}be wrapped
3334 text.{rev}desc to be
3341 text.{rev}desc to be
3335 text.{rev}wrapped (no-eol)
3342 text.{rev}wrapped (no-eol)
3336 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3343 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3337 bcc7ff960b8e:desc to
3344 bcc7ff960b8e:desc to
3338 text.1:be wrapped
3345 text.1:be wrapped
3339 text.1:desc to be
3346 text.1:desc to be
3340 text.1:wrapped (no-eol)
3347 text.1:wrapped (no-eol)
3341 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3348 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3342 hg: parse error: fill expects an integer width
3349 hg: parse error: fill expects an integer width
3343 [255]
3350 [255]
3344
3351
3345 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3352 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3346 bcc7ff960b8e:desc to be
3353 bcc7ff960b8e:desc to be
3347 termwidth.1:wrapped desc
3354 termwidth.1:wrapped desc
3348 termwidth.1:to be wrapped (no-eol)
3355 termwidth.1:to be wrapped (no-eol)
3349
3356
3350 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3357 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3351 {node|short} (no-eol)
3358 {node|short} (no-eol)
3352 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3359 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3353 bcc-ff---b-e (no-eol)
3360 bcc-ff---b-e (no-eol)
3354
3361
3355 $ cat >> .hg/hgrc <<EOF
3362 $ cat >> .hg/hgrc <<EOF
3356 > [extensions]
3363 > [extensions]
3357 > color=
3364 > color=
3358 > [color]
3365 > [color]
3359 > mode=ansi
3366 > mode=ansi
3360 > text.{rev} = red
3367 > text.{rev} = red
3361 > text.1 = green
3368 > text.1 = green
3362 > EOF
3369 > EOF
3363 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3370 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3364 \x1b[0;31mtext\x1b[0m (esc)
3371 \x1b[0;31mtext\x1b[0m (esc)
3365 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3372 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3366 \x1b[0;32mtext\x1b[0m (esc)
3373 \x1b[0;32mtext\x1b[0m (esc)
3367
3374
3368 color effect can be specified without quoting:
3375 color effect can be specified without quoting:
3369
3376
3370 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3377 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3371 \x1b[0;31mtext\x1b[0m (esc)
3378 \x1b[0;31mtext\x1b[0m (esc)
3372
3379
3373 color effects can be nested (issue5413)
3380 color effects can be nested (issue5413)
3374
3381
3375 $ hg debugtemplate --color=always \
3382 $ hg debugtemplate --color=always \
3376 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3383 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3377 \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)
3384 \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)
3378
3385
3379 pad() should interact well with color codes (issue5416)
3386 pad() should interact well with color codes (issue5416)
3380
3387
3381 $ hg debugtemplate --color=always \
3388 $ hg debugtemplate --color=always \
3382 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3389 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3383 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3390 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3384
3391
3385 label should be no-op if color is disabled:
3392 label should be no-op if color is disabled:
3386
3393
3387 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3394 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3388 text
3395 text
3389 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3396 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3390 text
3397 text
3391
3398
3392 Test branches inside if statement:
3399 Test branches inside if statement:
3393
3400
3394 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3401 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3395 no
3402 no
3396
3403
3397 Test get function:
3404 Test get function:
3398
3405
3399 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3406 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3400 default
3407 default
3401 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3408 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3402 default
3409 default
3403 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3410 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3404 hg: parse error: get() expects a dict as first argument
3411 hg: parse error: get() expects a dict as first argument
3405 [255]
3412 [255]
3406
3413
3407 Test json filter applied to hybrid object:
3414 Test json filter applied to hybrid object:
3408
3415
3409 $ hg log -r0 -T '{files|json}\n'
3416 $ hg log -r0 -T '{files|json}\n'
3410 ["a"]
3417 ["a"]
3411 $ hg log -r0 -T '{extras|json}\n'
3418 $ hg log -r0 -T '{extras|json}\n'
3412 {"branch": "default"}
3419 {"branch": "default"}
3413
3420
3414 Test localdate(date, tz) function:
3421 Test localdate(date, tz) function:
3415
3422
3416 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3423 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3417 1970-01-01 09:00 +0900
3424 1970-01-01 09:00 +0900
3418 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3425 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3419 1970-01-01 00:00 +0000
3426 1970-01-01 00:00 +0000
3420 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3427 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3421 hg: parse error: localdate expects a timezone
3428 hg: parse error: localdate expects a timezone
3422 [255]
3429 [255]
3423 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3430 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3424 1970-01-01 02:00 +0200
3431 1970-01-01 02:00 +0200
3425 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3432 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3426 1970-01-01 00:00 +0000
3433 1970-01-01 00:00 +0000
3427 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3434 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3428 1970-01-01 00:00 +0000
3435 1970-01-01 00:00 +0000
3429 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3436 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3430 hg: parse error: localdate expects a timezone
3437 hg: parse error: localdate expects a timezone
3431 [255]
3438 [255]
3432 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3439 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3433 hg: parse error: localdate expects a timezone
3440 hg: parse error: localdate expects a timezone
3434 [255]
3441 [255]
3435
3442
3436 Test shortest(node) function:
3443 Test shortest(node) function:
3437
3444
3438 $ echo b > b
3445 $ echo b > b
3439 $ hg ci -qAm b
3446 $ hg ci -qAm b
3440 $ hg log --template '{shortest(node)}\n'
3447 $ hg log --template '{shortest(node)}\n'
3441 e777
3448 e777
3442 bcc7
3449 bcc7
3443 f776
3450 f776
3444 $ hg log --template '{shortest(node, 10)}\n'
3451 $ hg log --template '{shortest(node, 10)}\n'
3445 e777603221
3452 e777603221
3446 bcc7ff960b
3453 bcc7ff960b
3447 f7769ec2ab
3454 f7769ec2ab
3448 $ hg log --template '{node|shortest}\n' -l1
3455 $ hg log --template '{node|shortest}\n' -l1
3449 e777
3456 e777
3450
3457
3451 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3458 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3452 f7769ec2ab
3459 f7769ec2ab
3453 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3460 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3454 hg: parse error: shortest() expects an integer minlength
3461 hg: parse error: shortest() expects an integer minlength
3455 [255]
3462 [255]
3456
3463
3457 $ cd ..
3464 $ cd ..
3458
3465
3459 Test shortest(node) with the repo having short hash collision:
3466 Test shortest(node) with the repo having short hash collision:
3460
3467
3461 $ hg init hashcollision
3468 $ hg init hashcollision
3462 $ cd hashcollision
3469 $ cd hashcollision
3463 $ cat <<EOF >> .hg/hgrc
3470 $ cat <<EOF >> .hg/hgrc
3464 > [experimental]
3471 > [experimental]
3465 > evolution = createmarkers
3472 > evolution = createmarkers
3466 > EOF
3473 > EOF
3467 $ echo 0 > a
3474 $ echo 0 > a
3468 $ hg ci -qAm 0
3475 $ hg ci -qAm 0
3469 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3476 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
3470 > hg up -q 0
3477 > hg up -q 0
3471 > echo $i > a
3478 > echo $i > a
3472 > hg ci -qm $i
3479 > hg ci -qm $i
3473 > done
3480 > done
3474 $ hg up -q null
3481 $ hg up -q null
3475 $ hg log -r0: -T '{rev}:{node}\n'
3482 $ hg log -r0: -T '{rev}:{node}\n'
3476 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3483 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
3477 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3484 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
3478 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3485 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
3479 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3486 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
3480 4:10776689e627b465361ad5c296a20a487e153ca4
3487 4:10776689e627b465361ad5c296a20a487e153ca4
3481 5:a00be79088084cb3aff086ab799f8790e01a976b
3488 5:a00be79088084cb3aff086ab799f8790e01a976b
3482 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3489 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
3483 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3490 7:a0457b3450b8e1b778f1163b31a435802987fe5d
3484 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3491 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
3485 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3492 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
3486 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3493 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
3487 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3494 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
3488 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3495 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
3489 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3496 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
3490
3497
3491 nodes starting with '11' (we don't have the revision number '11' though)
3498 nodes starting with '11' (we don't have the revision number '11' though)
3492
3499
3493 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3500 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
3494 1:1142
3501 1:1142
3495 2:1140
3502 2:1140
3496 3:11d
3503 3:11d
3497
3504
3498 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3505 '5:a00' is hidden, but still we have two nodes starting with 'a0'
3499
3506
3500 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3507 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
3501 6:a0b
3508 6:a0b
3502 7:a04
3509 7:a04
3503
3510
3504 node '10' conflicts with the revision number '10' even if it is hidden
3511 node '10' conflicts with the revision number '10' even if it is hidden
3505 (we could exclude hidden revision numbers, but currently we don't)
3512 (we could exclude hidden revision numbers, but currently we don't)
3506
3513
3507 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3514 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
3508 4:107
3515 4:107
3509 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3516 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
3510 4:107
3517 4:107
3511
3518
3512 node 'c562' should be unique if the other 'c562' nodes are hidden
3519 node 'c562' should be unique if the other 'c562' nodes are hidden
3513 (but we don't try the slow path to filter out hidden nodes for now)
3520 (but we don't try the slow path to filter out hidden nodes for now)
3514
3521
3515 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3522 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
3516 8:c5625
3523 8:c5625
3517 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3524 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
3518 8:c5625
3525 8:c5625
3519 9:c5623
3526 9:c5623
3520 10:c562d
3527 10:c562d
3521
3528
3522 $ cd ..
3529 $ cd ..
3523
3530
3524 Test pad function
3531 Test pad function
3525
3532
3526 $ cd r
3533 $ cd r
3527
3534
3528 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3535 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3529 2 test
3536 2 test
3530 1 {node|short}
3537 1 {node|short}
3531 0 test
3538 0 test
3532
3539
3533 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3540 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3534 2 test
3541 2 test
3535 1 {node|short}
3542 1 {node|short}
3536 0 test
3543 0 test
3537
3544
3538 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3545 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3539 2------------------- test
3546 2------------------- test
3540 1------------------- {node|short}
3547 1------------------- {node|short}
3541 0------------------- test
3548 0------------------- test
3542
3549
3543 Test template string in pad function
3550 Test template string in pad function
3544
3551
3545 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3552 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3546 {0} test
3553 {0} test
3547
3554
3548 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3555 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3549 \{rev} test
3556 \{rev} test
3550
3557
3551 Test width argument passed to pad function
3558 Test width argument passed to pad function
3552
3559
3553 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3560 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3554 0 test
3561 0 test
3555 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3562 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3556 hg: parse error: pad() expects an integer width
3563 hg: parse error: pad() expects an integer width
3557 [255]
3564 [255]
3558
3565
3559 Test invalid fillchar passed to pad function
3566 Test invalid fillchar passed to pad function
3560
3567
3561 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3568 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
3562 hg: parse error: pad() expects a single fill character
3569 hg: parse error: pad() expects a single fill character
3563 [255]
3570 [255]
3564 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3571 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
3565 hg: parse error: pad() expects a single fill character
3572 hg: parse error: pad() expects a single fill character
3566 [255]
3573 [255]
3567
3574
3568 Test boolean argument passed to pad function
3575 Test boolean argument passed to pad function
3569
3576
3570 no crash
3577 no crash
3571
3578
3572 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3579 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
3573 ---------0
3580 ---------0
3574
3581
3575 string/literal
3582 string/literal
3576
3583
3577 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3584 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
3578 ---------0
3585 ---------0
3579 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3586 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
3580 0---------
3587 0---------
3581 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3588 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
3582 0---------
3589 0---------
3583
3590
3584 unknown keyword is evaluated to ''
3591 unknown keyword is evaluated to ''
3585
3592
3586 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3593 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
3587 0---------
3594 0---------
3588
3595
3589 Test separate function
3596 Test separate function
3590
3597
3591 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3598 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
3592 a-b-c
3599 a-b-c
3593 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3600 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
3594 0:f7769ec2ab97 test default
3601 0:f7769ec2ab97 test default
3595 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3602 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
3596 a \x1b[0;31mb\x1b[0m c d (esc)
3603 a \x1b[0;31mb\x1b[0m c d (esc)
3597
3604
3598 Test boolean expression/literal passed to if function
3605 Test boolean expression/literal passed to if function
3599
3606
3600 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3607 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
3601 rev 0 is True
3608 rev 0 is True
3602 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3609 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
3603 literal 0 is True as well
3610 literal 0 is True as well
3604 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3611 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
3605 empty string is False
3612 empty string is False
3606 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3613 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
3607 empty list is False
3614 empty list is False
3608 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3615 $ hg log -r 0 -T '{if(true, "true is True")}\n'
3609 true is True
3616 true is True
3610 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3617 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
3611 false is False
3618 false is False
3612 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3619 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
3613 non-empty string is True
3620 non-empty string is True
3614
3621
3615 Test ifcontains function
3622 Test ifcontains function
3616
3623
3617 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3624 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3618 2 is in the string
3625 2 is in the string
3619 1 is not
3626 1 is not
3620 0 is in the string
3627 0 is in the string
3621
3628
3622 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3629 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3623 2 is in the string
3630 2 is in the string
3624 1 is not
3631 1 is not
3625 0 is in the string
3632 0 is in the string
3626
3633
3627 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3634 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3628 2 did not add a
3635 2 did not add a
3629 1 did not add a
3636 1 did not add a
3630 0 added a
3637 0 added a
3631
3638
3632 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3639 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3633 2 is parent of 1
3640 2 is parent of 1
3634 1
3641 1
3635 0
3642 0
3636
3643
3637 Test revset function
3644 Test revset function
3638
3645
3639 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3646 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3640 2 current rev
3647 2 current rev
3641 1 not current rev
3648 1 not current rev
3642 0 not current rev
3649 0 not current rev
3643
3650
3644 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3651 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3645 2 match rev
3652 2 match rev
3646 1 match rev
3653 1 match rev
3647 0 not match rev
3654 0 not match rev
3648
3655
3649 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3656 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3650 2 Parents: 1
3657 2 Parents: 1
3651 1 Parents: 0
3658 1 Parents: 0
3652 0 Parents:
3659 0 Parents:
3653
3660
3654 $ cat >> .hg/hgrc <<EOF
3661 $ cat >> .hg/hgrc <<EOF
3655 > [revsetalias]
3662 > [revsetalias]
3656 > myparents(\$1) = parents(\$1)
3663 > myparents(\$1) = parents(\$1)
3657 > EOF
3664 > EOF
3658 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3665 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3659 2 Parents: 1
3666 2 Parents: 1
3660 1 Parents: 0
3667 1 Parents: 0
3661 0 Parents:
3668 0 Parents:
3662
3669
3663 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3670 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3664 Rev: 2
3671 Rev: 2
3665 Ancestor: 0
3672 Ancestor: 0
3666 Ancestor: 1
3673 Ancestor: 1
3667 Ancestor: 2
3674 Ancestor: 2
3668
3675
3669 Rev: 1
3676 Rev: 1
3670 Ancestor: 0
3677 Ancestor: 0
3671 Ancestor: 1
3678 Ancestor: 1
3672
3679
3673 Rev: 0
3680 Rev: 0
3674 Ancestor: 0
3681 Ancestor: 0
3675
3682
3676 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3683 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3677 2
3684 2
3678
3685
3679 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3686 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3680 2
3687 2
3681
3688
3682 a list template is evaluated for each item of revset/parents
3689 a list template is evaluated for each item of revset/parents
3683
3690
3684 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3691 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3685 2 p: 1:bcc7ff960b8e
3692 2 p: 1:bcc7ff960b8e
3686 1 p: 0:f7769ec2ab97
3693 1 p: 0:f7769ec2ab97
3687 0 p:
3694 0 p:
3688
3695
3689 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3696 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3690 2 p: 1:bcc7ff960b8e -1:000000000000
3697 2 p: 1:bcc7ff960b8e -1:000000000000
3691 1 p: 0:f7769ec2ab97 -1:000000000000
3698 1 p: 0:f7769ec2ab97 -1:000000000000
3692 0 p: -1:000000000000 -1:000000000000
3699 0 p: -1:000000000000 -1:000000000000
3693
3700
3694 therefore, 'revcache' should be recreated for each rev
3701 therefore, 'revcache' should be recreated for each rev
3695
3702
3696 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3703 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3697 2 aa b
3704 2 aa b
3698 p
3705 p
3699 1
3706 1
3700 p a
3707 p a
3701 0 a
3708 0 a
3702 p
3709 p
3703
3710
3704 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3711 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3705 2 aa b
3712 2 aa b
3706 p
3713 p
3707 1
3714 1
3708 p a
3715 p a
3709 0 a
3716 0 a
3710 p
3717 p
3711
3718
3712 a revset item must be evaluated as an integer revision, not an offset from tip
3719 a revset item must be evaluated as an integer revision, not an offset from tip
3713
3720
3714 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3721 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3715 -1:000000000000
3722 -1:000000000000
3716 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3723 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3717 -1:000000000000
3724 -1:000000000000
3718
3725
3719 join() should pick '{rev}' from revset items:
3726 join() should pick '{rev}' from revset items:
3720
3727
3721 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
3728 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
3722 4, 5
3729 4, 5
3723
3730
3724 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
3731 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
3725 default. join() should agree with the default formatting:
3732 default. join() should agree with the default formatting:
3726
3733
3727 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
3734 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
3728 5:13207e5a10d9, 4:bbe44766e73d
3735 5:13207e5a10d9, 4:bbe44766e73d
3729
3736
3730 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
3737 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
3731 5:13207e5a10d9fd28ec424934298e176197f2c67f,
3738 5:13207e5a10d9fd28ec424934298e176197f2c67f,
3732 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
3739 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
3733
3740
3734 Test files function
3741 Test files function
3735
3742
3736 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
3743 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
3737 2
3744 2
3738 a
3745 a
3739 aa
3746 aa
3740 b
3747 b
3741 1
3748 1
3742 a
3749 a
3743 0
3750 0
3744 a
3751 a
3745
3752
3746 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
3753 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
3747 2
3754 2
3748 aa
3755 aa
3749 1
3756 1
3750
3757
3751 0
3758 0
3752
3759
3753
3760
3754 Test relpath function
3761 Test relpath function
3755
3762
3756 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
3763 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
3757 a
3764 a
3758 $ cd ..
3765 $ cd ..
3759 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
3766 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
3760 r/a
3767 r/a
3761 $ cd r
3768 $ cd r
3762
3769
3763 Test active bookmark templating
3770 Test active bookmark templating
3764
3771
3765 $ hg book foo
3772 $ hg book foo
3766 $ hg book bar
3773 $ hg book bar
3767 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3774 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3768 2 bar* foo
3775 2 bar* foo
3769 1
3776 1
3770 0
3777 0
3771 $ hg log --template "{rev} {activebookmark}\n"
3778 $ hg log --template "{rev} {activebookmark}\n"
3772 2 bar
3779 2 bar
3773 1
3780 1
3774 0
3781 0
3775 $ hg bookmarks --inactive bar
3782 $ hg bookmarks --inactive bar
3776 $ hg log --template "{rev} {activebookmark}\n"
3783 $ hg log --template "{rev} {activebookmark}\n"
3777 2
3784 2
3778 1
3785 1
3779 0
3786 0
3780 $ hg book -r1 baz
3787 $ hg book -r1 baz
3781 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3788 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3782 2 bar foo
3789 2 bar foo
3783 1 baz
3790 1 baz
3784 0
3791 0
3785 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3792 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3786 2 t
3793 2 t
3787 1 f
3794 1 f
3788 0 f
3795 0 f
3789
3796
3790 Test namespaces dict
3797 Test namespaces dict
3791
3798
3792 $ hg log -T '{rev}{namespaces % " {namespace}={join(names, ",")}"}\n'
3799 $ hg log -T '{rev}{namespaces % " {namespace}={join(names, ",")}"}\n'
3793 2 bookmarks=bar,foo tags=tip branches=text.{rev}
3800 2 bookmarks=bar,foo tags=tip branches=text.{rev}
3794 1 bookmarks=baz tags= branches=text.{rev}
3801 1 bookmarks=baz tags= branches=text.{rev}
3795 0 bookmarks= tags= branches=default
3802 0 bookmarks= tags= branches=default
3796 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
3803 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
3797 bookmarks: bar foo
3804 bookmarks: bar foo
3798 tags: tip
3805 tags: tip
3799 branches: text.{rev}
3806 branches: text.{rev}
3800 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
3807 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
3801 bookmarks:
3808 bookmarks:
3802 bar
3809 bar
3803 foo
3810 foo
3804 tags:
3811 tags:
3805 tip
3812 tip
3806 branches:
3813 branches:
3807 text.{rev}
3814 text.{rev}
3808 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
3815 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
3809 bar
3816 bar
3810 foo
3817 foo
3811
3818
3812 Test stringify on sub expressions
3819 Test stringify on sub expressions
3813
3820
3814 $ cd ..
3821 $ cd ..
3815 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3822 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3816 fourth, second, third
3823 fourth, second, third
3817 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3824 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3818 abc
3825 abc
3819
3826
3820 Test splitlines
3827 Test splitlines
3821
3828
3822 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3829 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3823 @ foo Modify, add, remove, rename
3830 @ foo Modify, add, remove, rename
3824 |
3831 |
3825 o foo future
3832 o foo future
3826 |
3833 |
3827 o foo third
3834 o foo third
3828 |
3835 |
3829 o foo second
3836 o foo second
3830
3837
3831 o foo merge
3838 o foo merge
3832 |\
3839 |\
3833 | o foo new head
3840 | o foo new head
3834 | |
3841 | |
3835 o | foo new branch
3842 o | foo new branch
3836 |/
3843 |/
3837 o foo no user, no domain
3844 o foo no user, no domain
3838 |
3845 |
3839 o foo no person
3846 o foo no person
3840 |
3847 |
3841 o foo other 1
3848 o foo other 1
3842 | foo other 2
3849 | foo other 2
3843 | foo
3850 | foo
3844 | foo other 3
3851 | foo other 3
3845 o foo line 1
3852 o foo line 1
3846 foo line 2
3853 foo line 2
3847
3854
3848 Test startswith
3855 Test startswith
3849 $ hg log -Gv -R a --template "{startswith(desc)}"
3856 $ hg log -Gv -R a --template "{startswith(desc)}"
3850 hg: parse error: startswith expects two arguments
3857 hg: parse error: startswith expects two arguments
3851 [255]
3858 [255]
3852
3859
3853 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3860 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3854 @
3861 @
3855 |
3862 |
3856 o
3863 o
3857 |
3864 |
3858 o
3865 o
3859 |
3866 |
3860 o
3867 o
3861
3868
3862 o
3869 o
3863 |\
3870 |\
3864 | o
3871 | o
3865 | |
3872 | |
3866 o |
3873 o |
3867 |/
3874 |/
3868 o
3875 o
3869 |
3876 |
3870 o
3877 o
3871 |
3878 |
3872 o
3879 o
3873 |
3880 |
3874 o line 1
3881 o line 1
3875 line 2
3882 line 2
3876
3883
3877 Test bad template with better error message
3884 Test bad template with better error message
3878
3885
3879 $ hg log -Gv -R a --template '{desc|user()}'
3886 $ hg log -Gv -R a --template '{desc|user()}'
3880 hg: parse error: expected a symbol, got 'func'
3887 hg: parse error: expected a symbol, got 'func'
3881 [255]
3888 [255]
3882
3889
3883 Test word function (including index out of bounds graceful failure)
3890 Test word function (including index out of bounds graceful failure)
3884
3891
3885 $ hg log -Gv -R a --template "{word('1', desc)}"
3892 $ hg log -Gv -R a --template "{word('1', desc)}"
3886 @ add,
3893 @ add,
3887 |
3894 |
3888 o
3895 o
3889 |
3896 |
3890 o
3897 o
3891 |
3898 |
3892 o
3899 o
3893
3900
3894 o
3901 o
3895 |\
3902 |\
3896 | o head
3903 | o head
3897 | |
3904 | |
3898 o | branch
3905 o | branch
3899 |/
3906 |/
3900 o user,
3907 o user,
3901 |
3908 |
3902 o person
3909 o person
3903 |
3910 |
3904 o 1
3911 o 1
3905 |
3912 |
3906 o 1
3913 o 1
3907
3914
3908
3915
3909 Test word third parameter used as splitter
3916 Test word third parameter used as splitter
3910
3917
3911 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3918 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3912 @ M
3919 @ M
3913 |
3920 |
3914 o future
3921 o future
3915 |
3922 |
3916 o third
3923 o third
3917 |
3924 |
3918 o sec
3925 o sec
3919
3926
3920 o merge
3927 o merge
3921 |\
3928 |\
3922 | o new head
3929 | o new head
3923 | |
3930 | |
3924 o | new branch
3931 o | new branch
3925 |/
3932 |/
3926 o n
3933 o n
3927 |
3934 |
3928 o n
3935 o n
3929 |
3936 |
3930 o
3937 o
3931 |
3938 |
3932 o line 1
3939 o line 1
3933 line 2
3940 line 2
3934
3941
3935 Test word error messages for not enough and too many arguments
3942 Test word error messages for not enough and too many arguments
3936
3943
3937 $ hg log -Gv -R a --template "{word('0')}"
3944 $ hg log -Gv -R a --template "{word('0')}"
3938 hg: parse error: word expects two or three arguments, got 1
3945 hg: parse error: word expects two or three arguments, got 1
3939 [255]
3946 [255]
3940
3947
3941 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3948 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3942 hg: parse error: word expects two or three arguments, got 7
3949 hg: parse error: word expects two or three arguments, got 7
3943 [255]
3950 [255]
3944
3951
3945 Test word for integer literal
3952 Test word for integer literal
3946
3953
3947 $ hg log -R a --template "{word(2, desc)}\n" -r0
3954 $ hg log -R a --template "{word(2, desc)}\n" -r0
3948 line
3955 line
3949
3956
3950 Test word for invalid numbers
3957 Test word for invalid numbers
3951
3958
3952 $ hg log -Gv -R a --template "{word('a', desc)}"
3959 $ hg log -Gv -R a --template "{word('a', desc)}"
3953 hg: parse error: word expects an integer index
3960 hg: parse error: word expects an integer index
3954 [255]
3961 [255]
3955
3962
3956 Test word for out of range
3963 Test word for out of range
3957
3964
3958 $ hg log -R a --template "{word(10000, desc)}"
3965 $ hg log -R a --template "{word(10000, desc)}"
3959 $ hg log -R a --template "{word(-10000, desc)}"
3966 $ hg log -R a --template "{word(-10000, desc)}"
3960
3967
3961 Test indent and not adding to empty lines
3968 Test indent and not adding to empty lines
3962
3969
3963 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3970 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3964 -----
3971 -----
3965 > line 1
3972 > line 1
3966 >> line 2
3973 >> line 2
3967 -----
3974 -----
3968 > other 1
3975 > other 1
3969 >> other 2
3976 >> other 2
3970
3977
3971 >> other 3
3978 >> other 3
3972
3979
3973 Test with non-strings like dates
3980 Test with non-strings like dates
3974
3981
3975 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3982 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3976 1200000.00
3983 1200000.00
3977 1300000.00
3984 1300000.00
3978
3985
3979 Test broken string escapes:
3986 Test broken string escapes:
3980
3987
3981 $ hg log -T "bogus\\" -R a
3988 $ hg log -T "bogus\\" -R a
3982 hg: parse error: trailing \ in string
3989 hg: parse error: trailing \ in string
3983 [255]
3990 [255]
3984 $ hg log -T "\\xy" -R a
3991 $ hg log -T "\\xy" -R a
3985 hg: parse error: invalid \x escape
3992 hg: parse error: invalid \x escape
3986 [255]
3993 [255]
3987
3994
3988 json filter should escape HTML tags so that the output can be embedded in hgweb:
3995 json filter should escape HTML tags so that the output can be embedded in hgweb:
3989
3996
3990 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
3997 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
3991 "\u003cfoo@example.org\u003e"
3998 "\u003cfoo@example.org\u003e"
3992
3999
3993 Templater supports aliases of symbol and func() styles:
4000 Templater supports aliases of symbol and func() styles:
3994
4001
3995 $ hg clone -q a aliases
4002 $ hg clone -q a aliases
3996 $ cd aliases
4003 $ cd aliases
3997 $ cat <<EOF >> .hg/hgrc
4004 $ cat <<EOF >> .hg/hgrc
3998 > [templatealias]
4005 > [templatealias]
3999 > r = rev
4006 > r = rev
4000 > rn = "{r}:{node|short}"
4007 > rn = "{r}:{node|short}"
4001 > status(c, files) = files % "{c} {file}\n"
4008 > status(c, files) = files % "{c} {file}\n"
4002 > utcdate(d) = localdate(d, "UTC")
4009 > utcdate(d) = localdate(d, "UTC")
4003 > EOF
4010 > EOF
4004
4011
4005 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4012 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4006 (template
4013 (template
4007 ('symbol', 'rn')
4014 ('symbol', 'rn')
4008 ('string', ' ')
4015 ('string', ' ')
4009 (|
4016 (|
4010 (func
4017 (func
4011 ('symbol', 'utcdate')
4018 ('symbol', 'utcdate')
4012 ('symbol', 'date'))
4019 ('symbol', 'date'))
4013 ('symbol', 'isodate'))
4020 ('symbol', 'isodate'))
4014 ('string', '\n'))
4021 ('string', '\n'))
4015 * expanded:
4022 * expanded:
4016 (template
4023 (template
4017 (template
4024 (template
4018 ('symbol', 'rev')
4025 ('symbol', 'rev')
4019 ('string', ':')
4026 ('string', ':')
4020 (|
4027 (|
4021 ('symbol', 'node')
4028 ('symbol', 'node')
4022 ('symbol', 'short')))
4029 ('symbol', 'short')))
4023 ('string', ' ')
4030 ('string', ' ')
4024 (|
4031 (|
4025 (func
4032 (func
4026 ('symbol', 'localdate')
4033 ('symbol', 'localdate')
4027 (list
4034 (list
4028 ('symbol', 'date')
4035 ('symbol', 'date')
4029 ('string', 'UTC')))
4036 ('string', 'UTC')))
4030 ('symbol', 'isodate'))
4037 ('symbol', 'isodate'))
4031 ('string', '\n'))
4038 ('string', '\n'))
4032 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4039 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4033
4040
4034 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4041 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4035 (template
4042 (template
4036 (func
4043 (func
4037 ('symbol', 'status')
4044 ('symbol', 'status')
4038 (list
4045 (list
4039 ('string', 'A')
4046 ('string', 'A')
4040 ('symbol', 'file_adds'))))
4047 ('symbol', 'file_adds'))))
4041 * expanded:
4048 * expanded:
4042 (template
4049 (template
4043 (%
4050 (%
4044 ('symbol', 'file_adds')
4051 ('symbol', 'file_adds')
4045 (template
4052 (template
4046 ('string', 'A')
4053 ('string', 'A')
4047 ('string', ' ')
4054 ('string', ' ')
4048 ('symbol', 'file')
4055 ('symbol', 'file')
4049 ('string', '\n'))))
4056 ('string', '\n'))))
4050 A a
4057 A a
4051
4058
4052 A unary function alias can be called as a filter:
4059 A unary function alias can be called as a filter:
4053
4060
4054 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4061 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4055 (template
4062 (template
4056 (|
4063 (|
4057 (|
4064 (|
4058 ('symbol', 'date')
4065 ('symbol', 'date')
4059 ('symbol', 'utcdate'))
4066 ('symbol', 'utcdate'))
4060 ('symbol', 'isodate'))
4067 ('symbol', 'isodate'))
4061 ('string', '\n'))
4068 ('string', '\n'))
4062 * expanded:
4069 * expanded:
4063 (template
4070 (template
4064 (|
4071 (|
4065 (func
4072 (func
4066 ('symbol', 'localdate')
4073 ('symbol', 'localdate')
4067 (list
4074 (list
4068 ('symbol', 'date')
4075 ('symbol', 'date')
4069 ('string', 'UTC')))
4076 ('string', 'UTC')))
4070 ('symbol', 'isodate'))
4077 ('symbol', 'isodate'))
4071 ('string', '\n'))
4078 ('string', '\n'))
4072 1970-01-12 13:46 +0000
4079 1970-01-12 13:46 +0000
4073
4080
4074 Aliases should be applied only to command arguments and templates in hgrc.
4081 Aliases should be applied only to command arguments and templates in hgrc.
4075 Otherwise, our stock styles and web templates could be corrupted:
4082 Otherwise, our stock styles and web templates could be corrupted:
4076
4083
4077 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4084 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4078 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4085 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4079
4086
4080 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4087 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4081 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4088 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4082
4089
4083 $ cat <<EOF > tmpl
4090 $ cat <<EOF > tmpl
4084 > changeset = 'nothing expanded:{rn}\n'
4091 > changeset = 'nothing expanded:{rn}\n'
4085 > EOF
4092 > EOF
4086 $ hg log -r0 --style ./tmpl
4093 $ hg log -r0 --style ./tmpl
4087 nothing expanded:
4094 nothing expanded:
4088
4095
4089 Aliases in formatter:
4096 Aliases in formatter:
4090
4097
4091 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4098 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4092 default 6:d41e714fe50d
4099 default 6:d41e714fe50d
4093 foo 4:bbe44766e73d
4100 foo 4:bbe44766e73d
4094
4101
4095 Aliases should honor HGPLAIN:
4102 Aliases should honor HGPLAIN:
4096
4103
4097 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4104 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4098 nothing expanded:
4105 nothing expanded:
4099 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4106 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4100 0:1e4e1b8f71e0
4107 0:1e4e1b8f71e0
4101
4108
4102 Unparsable alias:
4109 Unparsable alias:
4103
4110
4104 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4111 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4105 (template
4112 (template
4106 ('symbol', 'bad'))
4113 ('symbol', 'bad'))
4107 abort: bad definition of template alias "bad": at 2: not a prefix: end
4114 abort: bad definition of template alias "bad": at 2: not a prefix: end
4108 [255]
4115 [255]
4109 $ hg log --config templatealias.bad='x(' -T '{bad}'
4116 $ hg log --config templatealias.bad='x(' -T '{bad}'
4110 abort: bad definition of template alias "bad": at 2: not a prefix: end
4117 abort: bad definition of template alias "bad": at 2: not a prefix: end
4111 [255]
4118 [255]
4112
4119
4113 $ cd ..
4120 $ cd ..
4114
4121
4115 Set up repository for non-ascii encoding tests:
4122 Set up repository for non-ascii encoding tests:
4116
4123
4117 $ hg init nonascii
4124 $ hg init nonascii
4118 $ cd nonascii
4125 $ cd nonascii
4119 $ python <<EOF
4126 $ python <<EOF
4120 > open('latin1', 'w').write('\xe9')
4127 > open('latin1', 'w').write('\xe9')
4121 > open('utf-8', 'w').write('\xc3\xa9')
4128 > open('utf-8', 'w').write('\xc3\xa9')
4122 > EOF
4129 > EOF
4123 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4130 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4124 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4131 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4125
4132
4126 json filter should try round-trip conversion to utf-8:
4133 json filter should try round-trip conversion to utf-8:
4127
4134
4128 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4135 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4129 "\u00e9"
4136 "\u00e9"
4130 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4137 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4131 "non-ascii branch: \u00e9"
4138 "non-ascii branch: \u00e9"
4132
4139
4133 json filter takes input as utf-8b:
4140 json filter takes input as utf-8b:
4134
4141
4135 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4142 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4136 "\u00e9"
4143 "\u00e9"
4137 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4144 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4138 "\udce9"
4145 "\udce9"
4139
4146
4140 utf8 filter:
4147 utf8 filter:
4141
4148
4142 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4149 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4143 round-trip: c3a9
4150 round-trip: c3a9
4144 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4151 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4145 decoded: c3a9
4152 decoded: c3a9
4146 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4153 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4147 abort: decoding near * (glob)
4154 abort: decoding near * (glob)
4148 [255]
4155 [255]
4149 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4156 $ hg log -T "invalid type: {rev|utf8}\n" -r0
4150 abort: template filter 'utf8' is not compatible with keyword 'rev'
4157 abort: template filter 'utf8' is not compatible with keyword 'rev'
4151 [255]
4158 [255]
4152
4159
4153 pad width:
4160 pad width:
4154
4161
4155 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4162 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4156 \xc3\xa9- (esc)
4163 \xc3\xa9- (esc)
4157
4164
4158 $ cd ..
4165 $ cd ..
4159
4166
4160 Test that template function in extension is registered as expected
4167 Test that template function in extension is registered as expected
4161
4168
4162 $ cd a
4169 $ cd a
4163
4170
4164 $ cat <<EOF > $TESTTMP/customfunc.py
4171 $ cat <<EOF > $TESTTMP/customfunc.py
4165 > from mercurial import registrar
4172 > from mercurial import registrar
4166 >
4173 >
4167 > templatefunc = registrar.templatefunc()
4174 > templatefunc = registrar.templatefunc()
4168 >
4175 >
4169 > @templatefunc('custom()')
4176 > @templatefunc('custom()')
4170 > def custom(context, mapping, args):
4177 > def custom(context, mapping, args):
4171 > return 'custom'
4178 > return 'custom'
4172 > EOF
4179 > EOF
4173 $ cat <<EOF > .hg/hgrc
4180 $ cat <<EOF > .hg/hgrc
4174 > [extensions]
4181 > [extensions]
4175 > customfunc = $TESTTMP/customfunc.py
4182 > customfunc = $TESTTMP/customfunc.py
4176 > EOF
4183 > EOF
4177
4184
4178 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4185 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4179 custom
4186 custom
4180
4187
4181 $ cd ..
4188 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now