##// END OF EJS Templates
templatekw: add default styles for hybrid types (issue3887)...
Matt Mackall -
r18970:3cdb6f2f default
parent child Browse files
Show More
@@ -1,392 +1,396 b''
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2009 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 node import hex
8 from node import hex
9 import patch, util, error
9 import patch, util, error
10 import hbisect
10 import hbisect
11
11
12 # This helper class allows us to handle both:
12 # This helper class allows us to handle both:
13 # "{files}" (legacy command-line-specific list hack) and
13 # "{files}" (legacy command-line-specific list hack) and
14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
15
15
16 class _hybrid(object):
16 class _hybrid(object):
17 def __init__(self, gen, values):
17 def __init__(self, gen, values, joinfmt=None):
18 self.gen = gen
18 self.gen = gen
19 self.values = values
19 self.values = values
20 if joinfmt:
21 self.joinfmt = joinfmt
22 else:
23 self.joinfmt = lambda x: x.values()[0]
20 def __iter__(self):
24 def __iter__(self):
21 return self.gen
25 return self.gen
22 def __call__(self):
26 def __call__(self):
23 for x in self.values:
27 for x in self.values:
24 yield x
28 yield x
25
29
26 def showlist(name, values, plural=None, element=None, **args):
30 def showlist(name, values, plural=None, element=None, **args):
27 if not element:
31 if not element:
28 element = name
32 element = name
29 f = _showlist(name, values, plural, **args)
33 f = _showlist(name, values, plural, **args)
30 return _hybrid(f, [{element: x} for x in values])
34 return _hybrid(f, [{element: x} for x in values])
31
35
32 def _showlist(name, values, plural=None, **args):
36 def _showlist(name, values, plural=None, **args):
33 '''expand set of values.
37 '''expand set of values.
34 name is name of key in template map.
38 name is name of key in template map.
35 values is list of strings or dicts.
39 values is list of strings or dicts.
36 plural is plural of name, if not simply name + 's'.
40 plural is plural of name, if not simply name + 's'.
37
41
38 expansion works like this, given name 'foo'.
42 expansion works like this, given name 'foo'.
39
43
40 if values is empty, expand 'no_foos'.
44 if values is empty, expand 'no_foos'.
41
45
42 if 'foo' not in template map, return values as a string,
46 if 'foo' not in template map, return values as a string,
43 joined by space.
47 joined by space.
44
48
45 expand 'start_foos'.
49 expand 'start_foos'.
46
50
47 for each value, expand 'foo'. if 'last_foo' in template
51 for each value, expand 'foo'. if 'last_foo' in template
48 map, expand it instead of 'foo' for last key.
52 map, expand it instead of 'foo' for last key.
49
53
50 expand 'end_foos'.
54 expand 'end_foos'.
51 '''
55 '''
52 templ = args['templ']
56 templ = args['templ']
53 if plural:
57 if plural:
54 names = plural
58 names = plural
55 else: names = name + 's'
59 else: names = name + 's'
56 if not values:
60 if not values:
57 noname = 'no_' + names
61 noname = 'no_' + names
58 if noname in templ:
62 if noname in templ:
59 yield templ(noname, **args)
63 yield templ(noname, **args)
60 return
64 return
61 if name not in templ:
65 if name not in templ:
62 if isinstance(values[0], str):
66 if isinstance(values[0], str):
63 yield ' '.join(values)
67 yield ' '.join(values)
64 else:
68 else:
65 for v in values:
69 for v in values:
66 yield dict(v, **args)
70 yield dict(v, **args)
67 return
71 return
68 startname = 'start_' + names
72 startname = 'start_' + names
69 if startname in templ:
73 if startname in templ:
70 yield templ(startname, **args)
74 yield templ(startname, **args)
71 vargs = args.copy()
75 vargs = args.copy()
72 def one(v, tag=name):
76 def one(v, tag=name):
73 try:
77 try:
74 vargs.update(v)
78 vargs.update(v)
75 except (AttributeError, ValueError):
79 except (AttributeError, ValueError):
76 try:
80 try:
77 for a, b in v:
81 for a, b in v:
78 vargs[a] = b
82 vargs[a] = b
79 except ValueError:
83 except ValueError:
80 vargs[name] = v
84 vargs[name] = v
81 return templ(tag, **vargs)
85 return templ(tag, **vargs)
82 lastname = 'last_' + name
86 lastname = 'last_' + name
83 if lastname in templ:
87 if lastname in templ:
84 last = values.pop()
88 last = values.pop()
85 else:
89 else:
86 last = None
90 last = None
87 for v in values:
91 for v in values:
88 yield one(v)
92 yield one(v)
89 if last is not None:
93 if last is not None:
90 yield one(last, tag=lastname)
94 yield one(last, tag=lastname)
91 endname = 'end_' + names
95 endname = 'end_' + names
92 if endname in templ:
96 if endname in templ:
93 yield templ(endname, **args)
97 yield templ(endname, **args)
94
98
95 def getfiles(repo, ctx, revcache):
99 def getfiles(repo, ctx, revcache):
96 if 'files' not in revcache:
100 if 'files' not in revcache:
97 revcache['files'] = repo.status(ctx.p1().node(), ctx.node())[:3]
101 revcache['files'] = repo.status(ctx.p1().node(), ctx.node())[:3]
98 return revcache['files']
102 return revcache['files']
99
103
100 def getlatesttags(repo, ctx, cache):
104 def getlatesttags(repo, ctx, cache):
101 '''return date, distance and name for the latest tag of rev'''
105 '''return date, distance and name for the latest tag of rev'''
102
106
103 if 'latesttags' not in cache:
107 if 'latesttags' not in cache:
104 # Cache mapping from rev to a tuple with tag date, tag
108 # Cache mapping from rev to a tuple with tag date, tag
105 # distance and tag name
109 # distance and tag name
106 cache['latesttags'] = {-1: (0, 0, 'null')}
110 cache['latesttags'] = {-1: (0, 0, 'null')}
107 latesttags = cache['latesttags']
111 latesttags = cache['latesttags']
108
112
109 rev = ctx.rev()
113 rev = ctx.rev()
110 todo = [rev]
114 todo = [rev]
111 while todo:
115 while todo:
112 rev = todo.pop()
116 rev = todo.pop()
113 if rev in latesttags:
117 if rev in latesttags:
114 continue
118 continue
115 ctx = repo[rev]
119 ctx = repo[rev]
116 tags = [t for t in ctx.tags() if repo.tagtype(t) == 'global']
120 tags = [t for t in ctx.tags() if repo.tagtype(t) == 'global']
117 if tags:
121 if tags:
118 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
122 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
119 continue
123 continue
120 try:
124 try:
121 # The tuples are laid out so the right one can be found by
125 # The tuples are laid out so the right one can be found by
122 # comparison.
126 # comparison.
123 pdate, pdist, ptag = max(
127 pdate, pdist, ptag = max(
124 latesttags[p.rev()] for p in ctx.parents())
128 latesttags[p.rev()] for p in ctx.parents())
125 except KeyError:
129 except KeyError:
126 # Cache miss - recurse
130 # Cache miss - recurse
127 todo.append(rev)
131 todo.append(rev)
128 todo.extend(p.rev() for p in ctx.parents())
132 todo.extend(p.rev() for p in ctx.parents())
129 continue
133 continue
130 latesttags[rev] = pdate, pdist + 1, ptag
134 latesttags[rev] = pdate, pdist + 1, ptag
131 return latesttags[rev]
135 return latesttags[rev]
132
136
133 def getrenamedfn(repo, endrev=None):
137 def getrenamedfn(repo, endrev=None):
134 rcache = {}
138 rcache = {}
135 if endrev is None:
139 if endrev is None:
136 endrev = len(repo)
140 endrev = len(repo)
137
141
138 def getrenamed(fn, rev):
142 def getrenamed(fn, rev):
139 '''looks up all renames for a file (up to endrev) the first
143 '''looks up all renames for a file (up to endrev) the first
140 time the file is given. It indexes on the changerev and only
144 time the file is given. It indexes on the changerev and only
141 parses the manifest if linkrev != changerev.
145 parses the manifest if linkrev != changerev.
142 Returns rename info for fn at changerev rev.'''
146 Returns rename info for fn at changerev rev.'''
143 if fn not in rcache:
147 if fn not in rcache:
144 rcache[fn] = {}
148 rcache[fn] = {}
145 fl = repo.file(fn)
149 fl = repo.file(fn)
146 for i in fl:
150 for i in fl:
147 lr = fl.linkrev(i)
151 lr = fl.linkrev(i)
148 renamed = fl.renamed(fl.node(i))
152 renamed = fl.renamed(fl.node(i))
149 rcache[fn][lr] = renamed
153 rcache[fn][lr] = renamed
150 if lr >= endrev:
154 if lr >= endrev:
151 break
155 break
152 if rev in rcache[fn]:
156 if rev in rcache[fn]:
153 return rcache[fn][rev]
157 return rcache[fn][rev]
154
158
155 # If linkrev != rev (i.e. rev not found in rcache) fallback to
159 # If linkrev != rev (i.e. rev not found in rcache) fallback to
156 # filectx logic.
160 # filectx logic.
157 try:
161 try:
158 return repo[rev][fn].renamed()
162 return repo[rev][fn].renamed()
159 except error.LookupError:
163 except error.LookupError:
160 return None
164 return None
161
165
162 return getrenamed
166 return getrenamed
163
167
164
168
165 def showauthor(repo, ctx, templ, **args):
169 def showauthor(repo, ctx, templ, **args):
166 """:author: String. The unmodified author of the changeset."""
170 """:author: String. The unmodified author of the changeset."""
167 return ctx.user()
171 return ctx.user()
168
172
169 def showbisect(repo, ctx, templ, **args):
173 def showbisect(repo, ctx, templ, **args):
170 """:bisect: String. The changeset bisection status."""
174 """:bisect: String. The changeset bisection status."""
171 return hbisect.label(repo, ctx.node())
175 return hbisect.label(repo, ctx.node())
172
176
173 def showbranch(**args):
177 def showbranch(**args):
174 """:branch: String. The name of the branch on which the changeset was
178 """:branch: String. The name of the branch on which the changeset was
175 committed.
179 committed.
176 """
180 """
177 return args['ctx'].branch()
181 return args['ctx'].branch()
178
182
179 def showbranches(**args):
183 def showbranches(**args):
180 """:branches: List of strings. The name of the branch on which the
184 """:branches: List of strings. The name of the branch on which the
181 changeset was committed. Will be empty if the branch name was
185 changeset was committed. Will be empty if the branch name was
182 default.
186 default.
183 """
187 """
184 branch = args['ctx'].branch()
188 branch = args['ctx'].branch()
185 if branch != 'default':
189 if branch != 'default':
186 return showlist('branch', [branch], plural='branches', **args)
190 return showlist('branch', [branch], plural='branches', **args)
187
191
188 def showbookmarks(**args):
192 def showbookmarks(**args):
189 """:bookmarks: List of strings. Any bookmarks associated with the
193 """:bookmarks: List of strings. Any bookmarks associated with the
190 changeset.
194 changeset.
191 """
195 """
192 bookmarks = args['ctx'].bookmarks()
196 bookmarks = args['ctx'].bookmarks()
193 return showlist('bookmark', bookmarks, **args)
197 return showlist('bookmark', bookmarks, **args)
194
198
195 def showchildren(**args):
199 def showchildren(**args):
196 """:children: List of strings. The children of the changeset."""
200 """:children: List of strings. The children of the changeset."""
197 ctx = args['ctx']
201 ctx = args['ctx']
198 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
202 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
199 return showlist('children', childrevs, element='child', **args)
203 return showlist('children', childrevs, element='child', **args)
200
204
201 def showdate(repo, ctx, templ, **args):
205 def showdate(repo, ctx, templ, **args):
202 """:date: Date information. The date when the changeset was committed."""
206 """:date: Date information. The date when the changeset was committed."""
203 return ctx.date()
207 return ctx.date()
204
208
205 def showdescription(repo, ctx, templ, **args):
209 def showdescription(repo, ctx, templ, **args):
206 """:desc: String. The text of the changeset description."""
210 """:desc: String. The text of the changeset description."""
207 return ctx.description().strip()
211 return ctx.description().strip()
208
212
209 def showdiffstat(repo, ctx, templ, **args):
213 def showdiffstat(repo, ctx, templ, **args):
210 """:diffstat: String. Statistics of changes with the following format:
214 """:diffstat: String. Statistics of changes with the following format:
211 "modified files: +added/-removed lines"
215 "modified files: +added/-removed lines"
212 """
216 """
213 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
217 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
214 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
218 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
215 return '%s: +%s/-%s' % (len(stats), adds, removes)
219 return '%s: +%s/-%s' % (len(stats), adds, removes)
216
220
217 def showextras(**args):
221 def showextras(**args):
218 templ = args['templ']
222 templ = args['templ']
219 for key, value in sorted(args['ctx'].extra().items()):
223 for key, value in sorted(args['ctx'].extra().items()):
220 args = args.copy()
224 args = args.copy()
221 args.update(dict(key=key, value=value))
225 args.update(dict(key=key, value=value))
222 yield templ('extra', **args)
226 yield templ('extra', **args)
223
227
224 def showfileadds(**args):
228 def showfileadds(**args):
225 """:file_adds: List of strings. Files added by this changeset."""
229 """:file_adds: List of strings. Files added by this changeset."""
226 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
230 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
227 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
231 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
228 element='file', **args)
232 element='file', **args)
229
233
230 def showfilecopies(**args):
234 def showfilecopies(**args):
231 """:file_copies: List of strings. Files copied in this changeset with
235 """:file_copies: List of strings. Files copied in this changeset with
232 their sources.
236 their sources.
233 """
237 """
234 cache, ctx = args['cache'], args['ctx']
238 cache, ctx = args['cache'], args['ctx']
235 copies = args['revcache'].get('copies')
239 copies = args['revcache'].get('copies')
236 if copies is None:
240 if copies is None:
237 if 'getrenamed' not in cache:
241 if 'getrenamed' not in cache:
238 cache['getrenamed'] = getrenamedfn(args['repo'])
242 cache['getrenamed'] = getrenamedfn(args['repo'])
239 copies = []
243 copies = []
240 getrenamed = cache['getrenamed']
244 getrenamed = cache['getrenamed']
241 for fn in ctx.files():
245 for fn in ctx.files():
242 rename = getrenamed(fn, ctx.rev())
246 rename = getrenamed(fn, ctx.rev())
243 if rename:
247 if rename:
244 copies.append((fn, rename[0]))
248 copies.append((fn, rename[0]))
245
249
246 c = [{'name': x[0], 'source': x[1]} for x in copies]
250 c = [{'name': x[0], 'source': x[1]} for x in copies]
247 f = _showlist('file_copy', c, plural='file_copies', **args)
251 f = _showlist('file_copy', c, plural='file_copies', **args)
248 return _hybrid(f, c)
252 return _hybrid(f, c, lambda x: '%s (%s)' % (x['name'], x['source']))
249
253
250 # showfilecopiesswitch() displays file copies only if copy records are
254 # showfilecopiesswitch() displays file copies only if copy records are
251 # provided before calling the templater, usually with a --copies
255 # provided before calling the templater, usually with a --copies
252 # command line switch.
256 # command line switch.
253 def showfilecopiesswitch(**args):
257 def showfilecopiesswitch(**args):
254 """:file_copies_switch: List of strings. Like "file_copies" but displayed
258 """:file_copies_switch: List of strings. Like "file_copies" but displayed
255 only if the --copied switch is set.
259 only if the --copied switch is set.
256 """
260 """
257 copies = args['revcache'].get('copies') or []
261 copies = args['revcache'].get('copies') or []
258 c = [{'name': x[0], 'source': x[1]} for x in copies]
262 c = [{'name': x[0], 'source': x[1]} for x in copies]
259 f = _showlist('file_copy', c, plural='file_copies', **args)
263 f = _showlist('file_copy', c, plural='file_copies', **args)
260 return _hybrid(f, c)
264 return _hybrid(f, c, lambda x: '%s (%s)' % (x['name'], x['source']))
261
265
262 def showfiledels(**args):
266 def showfiledels(**args):
263 """:file_dels: List of strings. Files removed by this changeset."""
267 """:file_dels: List of strings. Files removed by this changeset."""
264 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
268 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
265 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
269 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
266 element='file', **args)
270 element='file', **args)
267
271
268 def showfilemods(**args):
272 def showfilemods(**args):
269 """:file_mods: List of strings. Files modified by this changeset."""
273 """:file_mods: List of strings. Files modified by this changeset."""
270 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
274 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
271 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
275 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
272 element='file', **args)
276 element='file', **args)
273
277
274 def showfiles(**args):
278 def showfiles(**args):
275 """:files: List of strings. All files modified, added, or removed by this
279 """:files: List of strings. All files modified, added, or removed by this
276 changeset.
280 changeset.
277 """
281 """
278 return showlist('file', args['ctx'].files(), **args)
282 return showlist('file', args['ctx'].files(), **args)
279
283
280 def showlatesttag(repo, ctx, templ, cache, **args):
284 def showlatesttag(repo, ctx, templ, cache, **args):
281 """:latesttag: String. Most recent global tag in the ancestors of this
285 """:latesttag: String. Most recent global tag in the ancestors of this
282 changeset.
286 changeset.
283 """
287 """
284 return getlatesttags(repo, ctx, cache)[2]
288 return getlatesttags(repo, ctx, cache)[2]
285
289
286 def showlatesttagdistance(repo, ctx, templ, cache, **args):
290 def showlatesttagdistance(repo, ctx, templ, cache, **args):
287 """:latesttagdistance: Integer. Longest path to the latest tag."""
291 """:latesttagdistance: Integer. Longest path to the latest tag."""
288 return getlatesttags(repo, ctx, cache)[1]
292 return getlatesttags(repo, ctx, cache)[1]
289
293
290 def showmanifest(**args):
294 def showmanifest(**args):
291 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
295 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
292 args = args.copy()
296 args = args.copy()
293 args.update(dict(rev=repo.manifest.rev(ctx.changeset()[0]),
297 args.update(dict(rev=repo.manifest.rev(ctx.changeset()[0]),
294 node=hex(ctx.changeset()[0])))
298 node=hex(ctx.changeset()[0])))
295 return templ('manifest', **args)
299 return templ('manifest', **args)
296
300
297 def shownode(repo, ctx, templ, **args):
301 def shownode(repo, ctx, templ, **args):
298 """:node: String. The changeset identification hash, as a 40 hexadecimal
302 """:node: String. The changeset identification hash, as a 40 hexadecimal
299 digit string.
303 digit string.
300 """
304 """
301 return ctx.hex()
305 return ctx.hex()
302
306
303 def showp1rev(repo, ctx, templ, **args):
307 def showp1rev(repo, ctx, templ, **args):
304 """:p1rev: Integer. The repository-local revision number of the changeset's
308 """:p1rev: Integer. The repository-local revision number of the changeset's
305 first parent, or -1 if the changeset has no parents."""
309 first parent, or -1 if the changeset has no parents."""
306 return ctx.p1().rev()
310 return ctx.p1().rev()
307
311
308 def showp2rev(repo, ctx, templ, **args):
312 def showp2rev(repo, ctx, templ, **args):
309 """:p2rev: Integer. The repository-local revision number of the changeset's
313 """:p2rev: Integer. The repository-local revision number of the changeset's
310 second parent, or -1 if the changeset has no second parent."""
314 second parent, or -1 if the changeset has no second parent."""
311 return ctx.p2().rev()
315 return ctx.p2().rev()
312
316
313 def showp1node(repo, ctx, templ, **args):
317 def showp1node(repo, ctx, templ, **args):
314 """:p1node: String. The identification hash of the changeset's first parent,
318 """:p1node: String. The identification hash of the changeset's first parent,
315 as a 40 digit hexadecimal string. If the changeset has no parents, all
319 as a 40 digit hexadecimal string. If the changeset has no parents, all
316 digits are 0."""
320 digits are 0."""
317 return ctx.p1().hex()
321 return ctx.p1().hex()
318
322
319 def showp2node(repo, ctx, templ, **args):
323 def showp2node(repo, ctx, templ, **args):
320 """:p2node: String. The identification hash of the changeset's second
324 """:p2node: String. The identification hash of the changeset's second
321 parent, as a 40 digit hexadecimal string. If the changeset has no second
325 parent, as a 40 digit hexadecimal string. If the changeset has no second
322 parent, all digits are 0."""
326 parent, all digits are 0."""
323 return ctx.p2().hex()
327 return ctx.p2().hex()
324
328
325 def showphase(repo, ctx, templ, **args):
329 def showphase(repo, ctx, templ, **args):
326 """:phase: String. The changeset phase name."""
330 """:phase: String. The changeset phase name."""
327 return ctx.phasestr()
331 return ctx.phasestr()
328
332
329 def showphaseidx(repo, ctx, templ, **args):
333 def showphaseidx(repo, ctx, templ, **args):
330 """:phaseidx: Integer. The changeset phase index."""
334 """:phaseidx: Integer. The changeset phase index."""
331 return ctx.phase()
335 return ctx.phase()
332
336
333 def showrev(repo, ctx, templ, **args):
337 def showrev(repo, ctx, templ, **args):
334 """:rev: Integer. The repository-local changeset revision number."""
338 """:rev: Integer. The repository-local changeset revision number."""
335 return ctx.rev()
339 return ctx.rev()
336
340
337 def showtags(**args):
341 def showtags(**args):
338 """:tags: List of strings. Any tags associated with the changeset."""
342 """:tags: List of strings. Any tags associated with the changeset."""
339 return showlist('tag', args['ctx'].tags(), **args)
343 return showlist('tag', args['ctx'].tags(), **args)
340
344
341 # keywords are callables like:
345 # keywords are callables like:
342 # fn(repo, ctx, templ, cache, revcache, **args)
346 # fn(repo, ctx, templ, cache, revcache, **args)
343 # with:
347 # with:
344 # repo - current repository instance
348 # repo - current repository instance
345 # ctx - the changectx being displayed
349 # ctx - the changectx being displayed
346 # templ - the templater instance
350 # templ - the templater instance
347 # cache - a cache dictionary for the whole templater run
351 # cache - a cache dictionary for the whole templater run
348 # revcache - a cache dictionary for the current revision
352 # revcache - a cache dictionary for the current revision
349 keywords = {
353 keywords = {
350 'author': showauthor,
354 'author': showauthor,
351 'bisect': showbisect,
355 'bisect': showbisect,
352 'branch': showbranch,
356 'branch': showbranch,
353 'branches': showbranches,
357 'branches': showbranches,
354 'bookmarks': showbookmarks,
358 'bookmarks': showbookmarks,
355 'children': showchildren,
359 'children': showchildren,
356 'date': showdate,
360 'date': showdate,
357 'desc': showdescription,
361 'desc': showdescription,
358 'diffstat': showdiffstat,
362 'diffstat': showdiffstat,
359 'extras': showextras,
363 'extras': showextras,
360 'file_adds': showfileadds,
364 'file_adds': showfileadds,
361 'file_copies': showfilecopies,
365 'file_copies': showfilecopies,
362 'file_copies_switch': showfilecopiesswitch,
366 'file_copies_switch': showfilecopiesswitch,
363 'file_dels': showfiledels,
367 'file_dels': showfiledels,
364 'file_mods': showfilemods,
368 'file_mods': showfilemods,
365 'files': showfiles,
369 'files': showfiles,
366 'latesttag': showlatesttag,
370 'latesttag': showlatesttag,
367 'latesttagdistance': showlatesttagdistance,
371 'latesttagdistance': showlatesttagdistance,
368 'manifest': showmanifest,
372 'manifest': showmanifest,
369 'node': shownode,
373 'node': shownode,
370 'p1rev': showp1rev,
374 'p1rev': showp1rev,
371 'p1node': showp1node,
375 'p1node': showp1node,
372 'p2rev': showp2rev,
376 'p2rev': showp2rev,
373 'p2node': showp2node,
377 'p2node': showp2node,
374 'phase': showphase,
378 'phase': showphase,
375 'phaseidx': showphaseidx,
379 'phaseidx': showphaseidx,
376 'rev': showrev,
380 'rev': showrev,
377 'tags': showtags,
381 'tags': showtags,
378 }
382 }
379
383
380 def _showparents(**args):
384 def _showparents(**args):
381 """:parents: List of strings. The parents of the changeset in "rev:node"
385 """:parents: List of strings. The parents of the changeset in "rev:node"
382 format. If the changeset has only one "natural" parent (the predecessor
386 format. If the changeset has only one "natural" parent (the predecessor
383 revision) nothing is shown."""
387 revision) nothing is shown."""
384 pass
388 pass
385
389
386 dockeywords = {
390 dockeywords = {
387 'parents': _showparents,
391 'parents': _showparents,
388 }
392 }
389 dockeywords.update(keywords)
393 dockeywords.update(keywords)
390
394
391 # tell hggettext to extract docstrings from these functions:
395 # tell hggettext to extract docstrings from these functions:
392 i18nfunctions = dockeywords.values()
396 i18nfunctions = dockeywords.values()
@@ -1,517 +1,518 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 i18n import _
8 from i18n import _
9 import sys, os, re
9 import sys, os, re
10 import util, config, templatefilters, parser, error
10 import util, config, templatefilters, parser, error
11 import types
11 import types
12 import minirst
12 import minirst
13
13
14 # template parsing
14 # template parsing
15
15
16 elements = {
16 elements = {
17 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
17 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
18 ",": (2, None, ("list", 2)),
18 ",": (2, None, ("list", 2)),
19 "|": (5, None, ("|", 5)),
19 "|": (5, None, ("|", 5)),
20 "%": (6, None, ("%", 6)),
20 "%": (6, None, ("%", 6)),
21 ")": (0, None, None),
21 ")": (0, None, None),
22 "symbol": (0, ("symbol",), None),
22 "symbol": (0, ("symbol",), None),
23 "string": (0, ("string",), None),
23 "string": (0, ("string",), None),
24 "end": (0, None, None),
24 "end": (0, None, None),
25 }
25 }
26
26
27 def tokenizer(data):
27 def tokenizer(data):
28 program, start, end = data
28 program, start, end = data
29 pos = start
29 pos = start
30 while pos < end:
30 while pos < end:
31 c = program[pos]
31 c = program[pos]
32 if c.isspace(): # skip inter-token whitespace
32 if c.isspace(): # skip inter-token whitespace
33 pass
33 pass
34 elif c in "(,)%|": # handle simple operators
34 elif c in "(,)%|": # handle simple operators
35 yield (c, None, pos)
35 yield (c, None, pos)
36 elif (c in '"\'' or c == 'r' and
36 elif (c in '"\'' or c == 'r' and
37 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
37 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
38 if c == 'r':
38 if c == 'r':
39 pos += 1
39 pos += 1
40 c = program[pos]
40 c = program[pos]
41 decode = False
41 decode = False
42 else:
42 else:
43 decode = True
43 decode = True
44 pos += 1
44 pos += 1
45 s = pos
45 s = pos
46 while pos < end: # find closing quote
46 while pos < end: # find closing quote
47 d = program[pos]
47 d = program[pos]
48 if decode and d == '\\': # skip over escaped characters
48 if decode and d == '\\': # skip over escaped characters
49 pos += 2
49 pos += 2
50 continue
50 continue
51 if d == c:
51 if d == c:
52 if not decode:
52 if not decode:
53 yield ('string', program[s:pos].replace('\\', r'\\'), s)
53 yield ('string', program[s:pos].replace('\\', r'\\'), s)
54 break
54 break
55 yield ('string', program[s:pos].decode('string-escape'), s)
55 yield ('string', program[s:pos].decode('string-escape'), s)
56 break
56 break
57 pos += 1
57 pos += 1
58 else:
58 else:
59 raise error.ParseError(_("unterminated string"), s)
59 raise error.ParseError(_("unterminated string"), s)
60 elif c.isalnum() or c in '_':
60 elif c.isalnum() or c in '_':
61 s = pos
61 s = pos
62 pos += 1
62 pos += 1
63 while pos < end: # find end of symbol
63 while pos < end: # find end of symbol
64 d = program[pos]
64 d = program[pos]
65 if not (d.isalnum() or d == "_"):
65 if not (d.isalnum() or d == "_"):
66 break
66 break
67 pos += 1
67 pos += 1
68 sym = program[s:pos]
68 sym = program[s:pos]
69 yield ('symbol', sym, s)
69 yield ('symbol', sym, s)
70 pos -= 1
70 pos -= 1
71 elif c == '}':
71 elif c == '}':
72 pos += 1
72 pos += 1
73 break
73 break
74 else:
74 else:
75 raise error.ParseError(_("syntax error"), pos)
75 raise error.ParseError(_("syntax error"), pos)
76 pos += 1
76 pos += 1
77 yield ('end', None, pos)
77 yield ('end', None, pos)
78
78
79 def compiletemplate(tmpl, context):
79 def compiletemplate(tmpl, context):
80 parsed = []
80 parsed = []
81 pos, stop = 0, len(tmpl)
81 pos, stop = 0, len(tmpl)
82 p = parser.parser(tokenizer, elements)
82 p = parser.parser(tokenizer, elements)
83
83
84 while pos < stop:
84 while pos < stop:
85 n = tmpl.find('{', pos)
85 n = tmpl.find('{', pos)
86 if n < 0:
86 if n < 0:
87 parsed.append(("string", tmpl[pos:]))
87 parsed.append(("string", tmpl[pos:]))
88 break
88 break
89 if n > 0 and tmpl[n - 1] == '\\':
89 if n > 0 and tmpl[n - 1] == '\\':
90 # escaped
90 # escaped
91 parsed.append(("string", tmpl[pos:n - 1] + "{"))
91 parsed.append(("string", tmpl[pos:n - 1] + "{"))
92 pos = n + 1
92 pos = n + 1
93 continue
93 continue
94 if n > pos:
94 if n > pos:
95 parsed.append(("string", tmpl[pos:n]))
95 parsed.append(("string", tmpl[pos:n]))
96
96
97 pd = [tmpl, n + 1, stop]
97 pd = [tmpl, n + 1, stop]
98 parseres, pos = p.parse(pd)
98 parseres, pos = p.parse(pd)
99 parsed.append(parseres)
99 parsed.append(parseres)
100
100
101 return [compileexp(e, context) for e in parsed]
101 return [compileexp(e, context) for e in parsed]
102
102
103 def compileexp(exp, context):
103 def compileexp(exp, context):
104 t = exp[0]
104 t = exp[0]
105 if t in methods:
105 if t in methods:
106 return methods[t](exp, context)
106 return methods[t](exp, context)
107 raise error.ParseError(_("unknown method '%s'") % t)
107 raise error.ParseError(_("unknown method '%s'") % t)
108
108
109 # template evaluation
109 # template evaluation
110
110
111 def getsymbol(exp):
111 def getsymbol(exp):
112 if exp[0] == 'symbol':
112 if exp[0] == 'symbol':
113 return exp[1]
113 return exp[1]
114 raise error.ParseError(_("expected a symbol"))
114 raise error.ParseError(_("expected a symbol"))
115
115
116 def getlist(x):
116 def getlist(x):
117 if not x:
117 if not x:
118 return []
118 return []
119 if x[0] == 'list':
119 if x[0] == 'list':
120 return getlist(x[1]) + [x[2]]
120 return getlist(x[1]) + [x[2]]
121 return [x]
121 return [x]
122
122
123 def getfilter(exp, context):
123 def getfilter(exp, context):
124 f = getsymbol(exp)
124 f = getsymbol(exp)
125 if f not in context._filters:
125 if f not in context._filters:
126 raise error.ParseError(_("unknown function '%s'") % f)
126 raise error.ParseError(_("unknown function '%s'") % f)
127 return context._filters[f]
127 return context._filters[f]
128
128
129 def gettemplate(exp, context):
129 def gettemplate(exp, context):
130 if exp[0] == 'string':
130 if exp[0] == 'string':
131 return compiletemplate(exp[1], context)
131 return compiletemplate(exp[1], context)
132 if exp[0] == 'symbol':
132 if exp[0] == 'symbol':
133 return context._load(exp[1])
133 return context._load(exp[1])
134 raise error.ParseError(_("expected template specifier"))
134 raise error.ParseError(_("expected template specifier"))
135
135
136 def runstring(context, mapping, data):
136 def runstring(context, mapping, data):
137 return data
137 return data
138
138
139 def runsymbol(context, mapping, key):
139 def runsymbol(context, mapping, key):
140 v = mapping.get(key)
140 v = mapping.get(key)
141 if v is None:
141 if v is None:
142 v = context._defaults.get(key, '')
142 v = context._defaults.get(key, '')
143 if util.safehasattr(v, '__call__'):
143 if util.safehasattr(v, '__call__'):
144 return v(**mapping)
144 return v(**mapping)
145 if isinstance(v, types.GeneratorType):
145 if isinstance(v, types.GeneratorType):
146 v = list(v)
146 v = list(v)
147 mapping[key] = v
147 mapping[key] = v
148 return v
148 return v
149 return v
149 return v
150
150
151 def buildfilter(exp, context):
151 def buildfilter(exp, context):
152 func, data = compileexp(exp[1], context)
152 func, data = compileexp(exp[1], context)
153 filt = getfilter(exp[2], context)
153 filt = getfilter(exp[2], context)
154 return (runfilter, (func, data, filt))
154 return (runfilter, (func, data, filt))
155
155
156 def runfilter(context, mapping, data):
156 def runfilter(context, mapping, data):
157 func, data, filt = data
157 func, data, filt = data
158 try:
158 try:
159 return filt(func(context, mapping, data))
159 return filt(func(context, mapping, data))
160 except (ValueError, AttributeError, TypeError):
160 except (ValueError, AttributeError, TypeError):
161 if isinstance(data, tuple):
161 if isinstance(data, tuple):
162 dt = data[1]
162 dt = data[1]
163 else:
163 else:
164 dt = data
164 dt = data
165 raise util.Abort(_("template filter '%s' is not compatible with "
165 raise util.Abort(_("template filter '%s' is not compatible with "
166 "keyword '%s'") % (filt.func_name, dt))
166 "keyword '%s'") % (filt.func_name, dt))
167
167
168 def buildmap(exp, context):
168 def buildmap(exp, context):
169 func, data = compileexp(exp[1], context)
169 func, data = compileexp(exp[1], context)
170 ctmpl = gettemplate(exp[2], context)
170 ctmpl = gettemplate(exp[2], context)
171 return (runmap, (func, data, ctmpl))
171 return (runmap, (func, data, ctmpl))
172
172
173 def runtemplate(context, mapping, template):
173 def runtemplate(context, mapping, template):
174 for func, data in template:
174 for func, data in template:
175 yield func(context, mapping, data)
175 yield func(context, mapping, data)
176
176
177 def runmap(context, mapping, data):
177 def runmap(context, mapping, data):
178 func, data, ctmpl = data
178 func, data, ctmpl = data
179 d = func(context, mapping, data)
179 d = func(context, mapping, data)
180 if util.safehasattr(d, '__call__'):
180 if util.safehasattr(d, '__call__'):
181 d = d()
181 d = d()
182
182
183 lm = mapping.copy()
183 lm = mapping.copy()
184
184
185 for i in d:
185 for i in d:
186 if isinstance(i, dict):
186 if isinstance(i, dict):
187 lm.update(i)
187 lm.update(i)
188 lm['originalnode'] = mapping.get('node')
188 lm['originalnode'] = mapping.get('node')
189 yield runtemplate(context, lm, ctmpl)
189 yield runtemplate(context, lm, ctmpl)
190 else:
190 else:
191 # v is not an iterable of dicts, this happen when 'key'
191 # v is not an iterable of dicts, this happen when 'key'
192 # has been fully expanded already and format is useless.
192 # has been fully expanded already and format is useless.
193 # If so, return the expanded value.
193 # If so, return the expanded value.
194 yield i
194 yield i
195
195
196 def buildfunc(exp, context):
196 def buildfunc(exp, context):
197 n = getsymbol(exp[1])
197 n = getsymbol(exp[1])
198 args = [compileexp(x, context) for x in getlist(exp[2])]
198 args = [compileexp(x, context) for x in getlist(exp[2])]
199 if n in funcs:
199 if n in funcs:
200 f = funcs[n]
200 f = funcs[n]
201 return (f, args)
201 return (f, args)
202 if n in templatefilters.funcs:
202 if n in templatefilters.funcs:
203 f = templatefilters.funcs[n]
203 f = templatefilters.funcs[n]
204 return (f, args)
204 return (f, args)
205 if n in context._filters:
205 if n in context._filters:
206 if len(args) != 1:
206 if len(args) != 1:
207 raise error.ParseError(_("filter %s expects one argument") % n)
207 raise error.ParseError(_("filter %s expects one argument") % n)
208 f = context._filters[n]
208 f = context._filters[n]
209 return (runfilter, (args[0][0], args[0][1], f))
209 return (runfilter, (args[0][0], args[0][1], f))
210
210
211 def get(context, mapping, args):
211 def get(context, mapping, args):
212 if len(args) != 2:
212 if len(args) != 2:
213 # i18n: "get" is a keyword
213 # i18n: "get" is a keyword
214 raise error.ParseError(_("get() expects two arguments"))
214 raise error.ParseError(_("get() expects two arguments"))
215
215
216 dictarg = args[0][0](context, mapping, args[0][1])
216 dictarg = args[0][0](context, mapping, args[0][1])
217 if not util.safehasattr(dictarg, 'get'):
217 if not util.safehasattr(dictarg, 'get'):
218 # i18n: "get" is a keyword
218 # i18n: "get" is a keyword
219 raise error.ParseError(_("get() expects a dict as first argument"))
219 raise error.ParseError(_("get() expects a dict as first argument"))
220
220
221 key = args[1][0](context, mapping, args[1][1])
221 key = args[1][0](context, mapping, args[1][1])
222 yield dictarg.get(key)
222 yield dictarg.get(key)
223
223
224 def join(context, mapping, args):
224 def join(context, mapping, args):
225 if not (1 <= len(args) <= 2):
225 if not (1 <= len(args) <= 2):
226 # i18n: "join" is a keyword
226 # i18n: "join" is a keyword
227 raise error.ParseError(_("join expects one or two arguments"))
227 raise error.ParseError(_("join expects one or two arguments"))
228
228
229 joinset = args[0][0](context, mapping, args[0][1])
229 joinset = args[0][0](context, mapping, args[0][1])
230 if util.safehasattr(joinset, '__call__'):
230 if util.safehasattr(joinset, '__call__'):
231 joinset = [x.values()[0] for x in joinset()]
231 jf = joinset.joinfmt
232 joinset = [jf(x) for x in joinset()]
232
233
233 joiner = " "
234 joiner = " "
234 if len(args) > 1:
235 if len(args) > 1:
235 joiner = args[1][0](context, mapping, args[1][1])
236 joiner = args[1][0](context, mapping, args[1][1])
236
237
237 first = True
238 first = True
238 for x in joinset:
239 for x in joinset:
239 if first:
240 if first:
240 first = False
241 first = False
241 else:
242 else:
242 yield joiner
243 yield joiner
243 yield x
244 yield x
244
245
245 def sub(context, mapping, args):
246 def sub(context, mapping, args):
246 if len(args) != 3:
247 if len(args) != 3:
247 # i18n: "sub" is a keyword
248 # i18n: "sub" is a keyword
248 raise error.ParseError(_("sub expects three arguments"))
249 raise error.ParseError(_("sub expects three arguments"))
249
250
250 pat = stringify(args[0][0](context, mapping, args[0][1]))
251 pat = stringify(args[0][0](context, mapping, args[0][1]))
251 rpl = stringify(args[1][0](context, mapping, args[1][1]))
252 rpl = stringify(args[1][0](context, mapping, args[1][1]))
252 src = stringify(args[2][0](context, mapping, args[2][1]))
253 src = stringify(args[2][0](context, mapping, args[2][1]))
253 yield re.sub(pat, rpl, src)
254 yield re.sub(pat, rpl, src)
254
255
255 def if_(context, mapping, args):
256 def if_(context, mapping, args):
256 if not (2 <= len(args) <= 3):
257 if not (2 <= len(args) <= 3):
257 # i18n: "if" is a keyword
258 # i18n: "if" is a keyword
258 raise error.ParseError(_("if expects two or three arguments"))
259 raise error.ParseError(_("if expects two or three arguments"))
259
260
260 test = stringify(args[0][0](context, mapping, args[0][1]))
261 test = stringify(args[0][0](context, mapping, args[0][1]))
261 if test:
262 if test:
262 t = stringify(args[1][0](context, mapping, args[1][1]))
263 t = stringify(args[1][0](context, mapping, args[1][1]))
263 yield runtemplate(context, mapping, compiletemplate(t, context))
264 yield runtemplate(context, mapping, compiletemplate(t, context))
264 elif len(args) == 3:
265 elif len(args) == 3:
265 t = stringify(args[2][0](context, mapping, args[2][1]))
266 t = stringify(args[2][0](context, mapping, args[2][1]))
266 yield runtemplate(context, mapping, compiletemplate(t, context))
267 yield runtemplate(context, mapping, compiletemplate(t, context))
267
268
268 def ifeq(context, mapping, args):
269 def ifeq(context, mapping, args):
269 if not (3 <= len(args) <= 4):
270 if not (3 <= len(args) <= 4):
270 # i18n: "ifeq" is a keyword
271 # i18n: "ifeq" is a keyword
271 raise error.ParseError(_("ifeq expects three or four arguments"))
272 raise error.ParseError(_("ifeq expects three or four arguments"))
272
273
273 test = stringify(args[0][0](context, mapping, args[0][1]))
274 test = stringify(args[0][0](context, mapping, args[0][1]))
274 match = stringify(args[1][0](context, mapping, args[1][1]))
275 match = stringify(args[1][0](context, mapping, args[1][1]))
275 if test == match:
276 if test == match:
276 t = stringify(args[2][0](context, mapping, args[2][1]))
277 t = stringify(args[2][0](context, mapping, args[2][1]))
277 yield runtemplate(context, mapping, compiletemplate(t, context))
278 yield runtemplate(context, mapping, compiletemplate(t, context))
278 elif len(args) == 4:
279 elif len(args) == 4:
279 t = stringify(args[3][0](context, mapping, args[3][1]))
280 t = stringify(args[3][0](context, mapping, args[3][1]))
280 yield runtemplate(context, mapping, compiletemplate(t, context))
281 yield runtemplate(context, mapping, compiletemplate(t, context))
281
282
282 def label(context, mapping, args):
283 def label(context, mapping, args):
283 if len(args) != 2:
284 if len(args) != 2:
284 # i18n: "label" is a keyword
285 # i18n: "label" is a keyword
285 raise error.ParseError(_("label expects two arguments"))
286 raise error.ParseError(_("label expects two arguments"))
286
287
287 # ignore args[0] (the label string) since this is supposed to be a a no-op
288 # ignore args[0] (the label string) since this is supposed to be a a no-op
288 t = stringify(args[1][0](context, mapping, args[1][1]))
289 t = stringify(args[1][0](context, mapping, args[1][1]))
289 yield runtemplate(context, mapping, compiletemplate(t, context))
290 yield runtemplate(context, mapping, compiletemplate(t, context))
290
291
291 def rstdoc(context, mapping, args):
292 def rstdoc(context, mapping, args):
292 if len(args) != 2:
293 if len(args) != 2:
293 # i18n: "rstdoc" is a keyword
294 # i18n: "rstdoc" is a keyword
294 raise error.ParseError(_("rstdoc expects two arguments"))
295 raise error.ParseError(_("rstdoc expects two arguments"))
295
296
296 text = stringify(args[0][0](context, mapping, args[0][1]))
297 text = stringify(args[0][0](context, mapping, args[0][1]))
297 style = stringify(args[1][0](context, mapping, args[1][1]))
298 style = stringify(args[1][0](context, mapping, args[1][1]))
298
299
299 return minirst.format(text, style=style)
300 return minirst.format(text, style=style)
300
301
301 methods = {
302 methods = {
302 "string": lambda e, c: (runstring, e[1]),
303 "string": lambda e, c: (runstring, e[1]),
303 "symbol": lambda e, c: (runsymbol, e[1]),
304 "symbol": lambda e, c: (runsymbol, e[1]),
304 "group": lambda e, c: compileexp(e[1], c),
305 "group": lambda e, c: compileexp(e[1], c),
305 # ".": buildmember,
306 # ".": buildmember,
306 "|": buildfilter,
307 "|": buildfilter,
307 "%": buildmap,
308 "%": buildmap,
308 "func": buildfunc,
309 "func": buildfunc,
309 }
310 }
310
311
311 funcs = {
312 funcs = {
312 "get": get,
313 "get": get,
313 "if": if_,
314 "if": if_,
314 "ifeq": ifeq,
315 "ifeq": ifeq,
315 "join": join,
316 "join": join,
316 "label": label,
317 "label": label,
317 "rstdoc": rstdoc,
318 "rstdoc": rstdoc,
318 "sub": sub,
319 "sub": sub,
319 }
320 }
320
321
321 # template engine
322 # template engine
322
323
323 path = ['templates', '../templates']
324 path = ['templates', '../templates']
324 stringify = templatefilters.stringify
325 stringify = templatefilters.stringify
325
326
326 def _flatten(thing):
327 def _flatten(thing):
327 '''yield a single stream from a possibly nested set of iterators'''
328 '''yield a single stream from a possibly nested set of iterators'''
328 if isinstance(thing, str):
329 if isinstance(thing, str):
329 yield thing
330 yield thing
330 elif not util.safehasattr(thing, '__iter__'):
331 elif not util.safehasattr(thing, '__iter__'):
331 if thing is not None:
332 if thing is not None:
332 yield str(thing)
333 yield str(thing)
333 else:
334 else:
334 for i in thing:
335 for i in thing:
335 if isinstance(i, str):
336 if isinstance(i, str):
336 yield i
337 yield i
337 elif not util.safehasattr(i, '__iter__'):
338 elif not util.safehasattr(i, '__iter__'):
338 if i is not None:
339 if i is not None:
339 yield str(i)
340 yield str(i)
340 elif i is not None:
341 elif i is not None:
341 for j in _flatten(i):
342 for j in _flatten(i):
342 yield j
343 yield j
343
344
344 def parsestring(s, quoted=True):
345 def parsestring(s, quoted=True):
345 '''parse a string using simple c-like syntax.
346 '''parse a string using simple c-like syntax.
346 string must be in quotes if quoted is True.'''
347 string must be in quotes if quoted is True.'''
347 if quoted:
348 if quoted:
348 if len(s) < 2 or s[0] != s[-1]:
349 if len(s) < 2 or s[0] != s[-1]:
349 raise SyntaxError(_('unmatched quotes'))
350 raise SyntaxError(_('unmatched quotes'))
350 return s[1:-1].decode('string_escape')
351 return s[1:-1].decode('string_escape')
351
352
352 return s.decode('string_escape')
353 return s.decode('string_escape')
353
354
354 class engine(object):
355 class engine(object):
355 '''template expansion engine.
356 '''template expansion engine.
356
357
357 template expansion works like this. a map file contains key=value
358 template expansion works like this. a map file contains key=value
358 pairs. if value is quoted, it is treated as string. otherwise, it
359 pairs. if value is quoted, it is treated as string. otherwise, it
359 is treated as name of template file.
360 is treated as name of template file.
360
361
361 templater is asked to expand a key in map. it looks up key, and
362 templater is asked to expand a key in map. it looks up key, and
362 looks for strings like this: {foo}. it expands {foo} by looking up
363 looks for strings like this: {foo}. it expands {foo} by looking up
363 foo in map, and substituting it. expansion is recursive: it stops
364 foo in map, and substituting it. expansion is recursive: it stops
364 when there is no more {foo} to replace.
365 when there is no more {foo} to replace.
365
366
366 expansion also allows formatting and filtering.
367 expansion also allows formatting and filtering.
367
368
368 format uses key to expand each item in list. syntax is
369 format uses key to expand each item in list. syntax is
369 {key%format}.
370 {key%format}.
370
371
371 filter uses function to transform value. syntax is
372 filter uses function to transform value. syntax is
372 {key|filter1|filter2|...}.'''
373 {key|filter1|filter2|...}.'''
373
374
374 def __init__(self, loader, filters={}, defaults={}):
375 def __init__(self, loader, filters={}, defaults={}):
375 self._loader = loader
376 self._loader = loader
376 self._filters = filters
377 self._filters = filters
377 self._defaults = defaults
378 self._defaults = defaults
378 self._cache = {}
379 self._cache = {}
379
380
380 def _load(self, t):
381 def _load(self, t):
381 '''load, parse, and cache a template'''
382 '''load, parse, and cache a template'''
382 if t not in self._cache:
383 if t not in self._cache:
383 self._cache[t] = compiletemplate(self._loader(t), self)
384 self._cache[t] = compiletemplate(self._loader(t), self)
384 return self._cache[t]
385 return self._cache[t]
385
386
386 def process(self, t, mapping):
387 def process(self, t, mapping):
387 '''Perform expansion. t is name of map element to expand.
388 '''Perform expansion. t is name of map element to expand.
388 mapping contains added elements for use during expansion. Is a
389 mapping contains added elements for use during expansion. Is a
389 generator.'''
390 generator.'''
390 return _flatten(runtemplate(self, mapping, self._load(t)))
391 return _flatten(runtemplate(self, mapping, self._load(t)))
391
392
392 engines = {'default': engine}
393 engines = {'default': engine}
393
394
394 class templater(object):
395 class templater(object):
395
396
396 def __init__(self, mapfile, filters={}, defaults={}, cache={},
397 def __init__(self, mapfile, filters={}, defaults={}, cache={},
397 minchunk=1024, maxchunk=65536):
398 minchunk=1024, maxchunk=65536):
398 '''set up template engine.
399 '''set up template engine.
399 mapfile is name of file to read map definitions from.
400 mapfile is name of file to read map definitions from.
400 filters is dict of functions. each transforms a value into another.
401 filters is dict of functions. each transforms a value into another.
401 defaults is dict of default map definitions.'''
402 defaults is dict of default map definitions.'''
402 self.mapfile = mapfile or 'template'
403 self.mapfile = mapfile or 'template'
403 self.cache = cache.copy()
404 self.cache = cache.copy()
404 self.map = {}
405 self.map = {}
405 self.base = (mapfile and os.path.dirname(mapfile)) or ''
406 self.base = (mapfile and os.path.dirname(mapfile)) or ''
406 self.filters = templatefilters.filters.copy()
407 self.filters = templatefilters.filters.copy()
407 self.filters.update(filters)
408 self.filters.update(filters)
408 self.defaults = defaults
409 self.defaults = defaults
409 self.minchunk, self.maxchunk = minchunk, maxchunk
410 self.minchunk, self.maxchunk = minchunk, maxchunk
410 self.ecache = {}
411 self.ecache = {}
411
412
412 if not mapfile:
413 if not mapfile:
413 return
414 return
414 if not os.path.exists(mapfile):
415 if not os.path.exists(mapfile):
415 raise util.Abort(_('style not found: %s') % mapfile)
416 raise util.Abort(_('style not found: %s') % mapfile)
416
417
417 conf = config.config()
418 conf = config.config()
418 conf.read(mapfile)
419 conf.read(mapfile)
419
420
420 for key, val in conf[''].items():
421 for key, val in conf[''].items():
421 if not val:
422 if not val:
422 raise SyntaxError(_('%s: missing value') % conf.source('', key))
423 raise SyntaxError(_('%s: missing value') % conf.source('', key))
423 if val[0] in "'\"":
424 if val[0] in "'\"":
424 try:
425 try:
425 self.cache[key] = parsestring(val)
426 self.cache[key] = parsestring(val)
426 except SyntaxError, inst:
427 except SyntaxError, inst:
427 raise SyntaxError('%s: %s' %
428 raise SyntaxError('%s: %s' %
428 (conf.source('', key), inst.args[0]))
429 (conf.source('', key), inst.args[0]))
429 else:
430 else:
430 val = 'default', val
431 val = 'default', val
431 if ':' in val[1]:
432 if ':' in val[1]:
432 val = val[1].split(':', 1)
433 val = val[1].split(':', 1)
433 self.map[key] = val[0], os.path.join(self.base, val[1])
434 self.map[key] = val[0], os.path.join(self.base, val[1])
434
435
435 def __contains__(self, key):
436 def __contains__(self, key):
436 return key in self.cache or key in self.map
437 return key in self.cache or key in self.map
437
438
438 def load(self, t):
439 def load(self, t):
439 '''Get the template for the given template name. Use a local cache.'''
440 '''Get the template for the given template name. Use a local cache.'''
440 if t not in self.cache:
441 if t not in self.cache:
441 try:
442 try:
442 self.cache[t] = util.readfile(self.map[t][1])
443 self.cache[t] = util.readfile(self.map[t][1])
443 except KeyError, inst:
444 except KeyError, inst:
444 raise util.Abort(_('"%s" not in template map') % inst.args[0])
445 raise util.Abort(_('"%s" not in template map') % inst.args[0])
445 except IOError, inst:
446 except IOError, inst:
446 raise IOError(inst.args[0], _('template file %s: %s') %
447 raise IOError(inst.args[0], _('template file %s: %s') %
447 (self.map[t][1], inst.args[1]))
448 (self.map[t][1], inst.args[1]))
448 return self.cache[t]
449 return self.cache[t]
449
450
450 def __call__(self, t, **mapping):
451 def __call__(self, t, **mapping):
451 ttype = t in self.map and self.map[t][0] or 'default'
452 ttype = t in self.map and self.map[t][0] or 'default'
452 if ttype not in self.ecache:
453 if ttype not in self.ecache:
453 self.ecache[ttype] = engines[ttype](self.load,
454 self.ecache[ttype] = engines[ttype](self.load,
454 self.filters, self.defaults)
455 self.filters, self.defaults)
455 proc = self.ecache[ttype]
456 proc = self.ecache[ttype]
456
457
457 stream = proc.process(t, mapping)
458 stream = proc.process(t, mapping)
458 if self.minchunk:
459 if self.minchunk:
459 stream = util.increasingchunks(stream, min=self.minchunk,
460 stream = util.increasingchunks(stream, min=self.minchunk,
460 max=self.maxchunk)
461 max=self.maxchunk)
461 return stream
462 return stream
462
463
463 def templatepath(name=None):
464 def templatepath(name=None):
464 '''return location of template file or directory (if no name).
465 '''return location of template file or directory (if no name).
465 returns None if not found.'''
466 returns None if not found.'''
466 normpaths = []
467 normpaths = []
467
468
468 # executable version (py2exe) doesn't support __file__
469 # executable version (py2exe) doesn't support __file__
469 if util.mainfrozen():
470 if util.mainfrozen():
470 module = sys.executable
471 module = sys.executable
471 else:
472 else:
472 module = __file__
473 module = __file__
473 for f in path:
474 for f in path:
474 if f.startswith('/'):
475 if f.startswith('/'):
475 p = f
476 p = f
476 else:
477 else:
477 fl = f.split('/')
478 fl = f.split('/')
478 p = os.path.join(os.path.dirname(module), *fl)
479 p = os.path.join(os.path.dirname(module), *fl)
479 if name:
480 if name:
480 p = os.path.join(p, name)
481 p = os.path.join(p, name)
481 if name and os.path.exists(p):
482 if name and os.path.exists(p):
482 return os.path.normpath(p)
483 return os.path.normpath(p)
483 elif os.path.isdir(p):
484 elif os.path.isdir(p):
484 normpaths.append(os.path.normpath(p))
485 normpaths.append(os.path.normpath(p))
485
486
486 return normpaths
487 return normpaths
487
488
488 def stylemap(styles, paths=None):
489 def stylemap(styles, paths=None):
489 """Return path to mapfile for a given style.
490 """Return path to mapfile for a given style.
490
491
491 Searches mapfile in the following locations:
492 Searches mapfile in the following locations:
492 1. templatepath/style/map
493 1. templatepath/style/map
493 2. templatepath/map-style
494 2. templatepath/map-style
494 3. templatepath/map
495 3. templatepath/map
495 """
496 """
496
497
497 if paths is None:
498 if paths is None:
498 paths = templatepath()
499 paths = templatepath()
499 elif isinstance(paths, str):
500 elif isinstance(paths, str):
500 paths = [paths]
501 paths = [paths]
501
502
502 if isinstance(styles, str):
503 if isinstance(styles, str):
503 styles = [styles]
504 styles = [styles]
504
505
505 for style in styles:
506 for style in styles:
506 if not style:
507 if not style:
507 continue
508 continue
508 locations = [os.path.join(style, 'map'), 'map-' + style]
509 locations = [os.path.join(style, 'map'), 'map-' + style]
509 locations.append('map')
510 locations.append('map')
510
511
511 for path in paths:
512 for path in paths:
512 for location in locations:
513 for location in locations:
513 mapfile = os.path.join(path, location)
514 mapfile = os.path.join(path, location)
514 if os.path.isfile(mapfile):
515 if os.path.isfile(mapfile):
515 return style, mapfile
516 return style, mapfile
516
517
517 raise RuntimeError("No hgweb templates found in %r" % paths)
518 raise RuntimeError("No hgweb templates found in %r" % paths)
@@ -1,1531 +1,1533 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 Second branch starting at nullrev:
32 Second branch starting at nullrev:
33
33
34 $ hg update null
34 $ hg update null
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
36 $ echo second > second
36 $ echo second > second
37 $ hg add second
37 $ hg add second
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
39 created new head
39 created new head
40
40
41 $ echo third > third
41 $ echo third > third
42 $ hg add third
42 $ hg add third
43 $ hg mv second fourth
43 $ hg mv second fourth
44 $ hg commit -m third -d "2020-01-01 10:01"
44 $ hg commit -m third -d "2020-01-01 10:01"
45
45
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
47 fourth (second)
46 $ hg log --template '{file_copies % "{source} -> {name}\n"}' -r .
48 $ hg log --template '{file_copies % "{source} -> {name}\n"}' -r .
47 second -> fourth
49 second -> fourth
48
50
49 Quoting for ui.logtemplate
51 Quoting for ui.logtemplate
50
52
51 $ hg tip --config "ui.logtemplate={rev}\n"
53 $ hg tip --config "ui.logtemplate={rev}\n"
52 8
54 8
53 $ hg tip --config "ui.logtemplate='{rev}\n'"
55 $ hg tip --config "ui.logtemplate='{rev}\n'"
54 8
56 8
55 $ hg tip --config 'ui.logtemplate="{rev}\n"'
57 $ hg tip --config 'ui.logtemplate="{rev}\n"'
56 8
58 8
57
59
58 Make sure user/global hgrc does not affect tests
60 Make sure user/global hgrc does not affect tests
59
61
60 $ echo '[ui]' > .hg/hgrc
62 $ echo '[ui]' > .hg/hgrc
61 $ echo 'logtemplate =' >> .hg/hgrc
63 $ echo 'logtemplate =' >> .hg/hgrc
62 $ echo 'style =' >> .hg/hgrc
64 $ echo 'style =' >> .hg/hgrc
63
65
64 Default style is like normal output:
66 Default style is like normal output:
65
67
66 $ hg log > log.out
68 $ hg log > log.out
67 $ hg log --style default > style.out
69 $ hg log --style default > style.out
68 $ cmp log.out style.out || diff -u log.out style.out
70 $ cmp log.out style.out || diff -u log.out style.out
69
71
70 $ hg log -v > log.out
72 $ hg log -v > log.out
71 $ hg log -v --style default > style.out
73 $ hg log -v --style default > style.out
72 $ cmp log.out style.out || diff -u log.out style.out
74 $ cmp log.out style.out || diff -u log.out style.out
73
75
74 $ hg log --debug > log.out
76 $ hg log --debug > log.out
75 $ hg log --debug --style default > style.out
77 $ hg log --debug --style default > style.out
76 $ cmp log.out style.out || diff -u log.out style.out
78 $ cmp log.out style.out || diff -u log.out style.out
77
79
78 Revision with no copies (used to print a traceback):
80 Revision with no copies (used to print a traceback):
79
81
80 $ hg tip -v --template '\n'
82 $ hg tip -v --template '\n'
81
83
82
84
83 Compact style works:
85 Compact style works:
84
86
85 $ hg log --style compact
87 $ hg log --style compact
86 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
88 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
87 third
89 third
88
90
89 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
91 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
90 second
92 second
91
93
92 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
94 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
93 merge
95 merge
94
96
95 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
97 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
96 new head
98 new head
97
99
98 4 bbe44766e73d 1970-01-17 04:53 +0000 person
100 4 bbe44766e73d 1970-01-17 04:53 +0000 person
99 new branch
101 new branch
100
102
101 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
103 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
102 no user, no domain
104 no user, no domain
103
105
104 2 97054abb4ab8 1970-01-14 21:20 +0000 other
106 2 97054abb4ab8 1970-01-14 21:20 +0000 other
105 no person
107 no person
106
108
107 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
109 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
108 other 1
110 other 1
109
111
110 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
112 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
111 line 1
113 line 1
112
114
113
115
114 $ hg log -v --style compact
116 $ hg log -v --style compact
115 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
117 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
116 third
118 third
117
119
118 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
120 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
119 second
121 second
120
122
121 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
123 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
122 merge
124 merge
123
125
124 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
126 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
125 new head
127 new head
126
128
127 4 bbe44766e73d 1970-01-17 04:53 +0000 person
129 4 bbe44766e73d 1970-01-17 04:53 +0000 person
128 new branch
130 new branch
129
131
130 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
132 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
131 no user, no domain
133 no user, no domain
132
134
133 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
135 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
134 no person
136 no person
135
137
136 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
138 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
137 other 1
139 other 1
138 other 2
140 other 2
139
141
140 other 3
142 other 3
141
143
142 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
144 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
143 line 1
145 line 1
144 line 2
146 line 2
145
147
146
148
147 $ hg log --debug --style compact
149 $ hg log --debug --style compact
148 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
150 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
149 third
151 third
150
152
151 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
153 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
152 second
154 second
153
155
154 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
156 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
155 merge
157 merge
156
158
157 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
159 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
158 new head
160 new head
159
161
160 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
162 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
161 new branch
163 new branch
162
164
163 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
165 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
164 no user, no domain
166 no user, no domain
165
167
166 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
168 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
167 no person
169 no person
168
170
169 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
171 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
170 other 1
172 other 1
171 other 2
173 other 2
172
174
173 other 3
175 other 3
174
176
175 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
177 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
176 line 1
178 line 1
177 line 2
179 line 2
178
180
179
181
180 Test xml styles:
182 Test xml styles:
181
183
182 $ hg log --style xml
184 $ hg log --style xml
183 <?xml version="1.0"?>
185 <?xml version="1.0"?>
184 <log>
186 <log>
185 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
187 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
186 <tag>tip</tag>
188 <tag>tip</tag>
187 <author email="test">test</author>
189 <author email="test">test</author>
188 <date>2020-01-01T10:01:00+00:00</date>
190 <date>2020-01-01T10:01:00+00:00</date>
189 <msg xml:space="preserve">third</msg>
191 <msg xml:space="preserve">third</msg>
190 </logentry>
192 </logentry>
191 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
193 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
192 <parent revision="-1" node="0000000000000000000000000000000000000000" />
194 <parent revision="-1" node="0000000000000000000000000000000000000000" />
193 <author email="user@hostname">User Name</author>
195 <author email="user@hostname">User Name</author>
194 <date>1970-01-12T13:46:40+00:00</date>
196 <date>1970-01-12T13:46:40+00:00</date>
195 <msg xml:space="preserve">second</msg>
197 <msg xml:space="preserve">second</msg>
196 </logentry>
198 </logentry>
197 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
199 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
198 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
200 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
199 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
201 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
200 <author email="person">person</author>
202 <author email="person">person</author>
201 <date>1970-01-18T08:40:01+00:00</date>
203 <date>1970-01-18T08:40:01+00:00</date>
202 <msg xml:space="preserve">merge</msg>
204 <msg xml:space="preserve">merge</msg>
203 </logentry>
205 </logentry>
204 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
206 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
205 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
207 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
206 <author email="person">person</author>
208 <author email="person">person</author>
207 <date>1970-01-18T08:40:00+00:00</date>
209 <date>1970-01-18T08:40:00+00:00</date>
208 <msg xml:space="preserve">new head</msg>
210 <msg xml:space="preserve">new head</msg>
209 </logentry>
211 </logentry>
210 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
212 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
211 <branch>foo</branch>
213 <branch>foo</branch>
212 <author email="person">person</author>
214 <author email="person">person</author>
213 <date>1970-01-17T04:53:20+00:00</date>
215 <date>1970-01-17T04:53:20+00:00</date>
214 <msg xml:space="preserve">new branch</msg>
216 <msg xml:space="preserve">new branch</msg>
215 </logentry>
217 </logentry>
216 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
218 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
217 <author email="person">person</author>
219 <author email="person">person</author>
218 <date>1970-01-16T01:06:40+00:00</date>
220 <date>1970-01-16T01:06:40+00:00</date>
219 <msg xml:space="preserve">no user, no domain</msg>
221 <msg xml:space="preserve">no user, no domain</msg>
220 </logentry>
222 </logentry>
221 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
223 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
222 <author email="other@place">other</author>
224 <author email="other@place">other</author>
223 <date>1970-01-14T21:20:00+00:00</date>
225 <date>1970-01-14T21:20:00+00:00</date>
224 <msg xml:space="preserve">no person</msg>
226 <msg xml:space="preserve">no person</msg>
225 </logentry>
227 </logentry>
226 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
228 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
227 <author email="other@place">A. N. Other</author>
229 <author email="other@place">A. N. Other</author>
228 <date>1970-01-13T17:33:20+00:00</date>
230 <date>1970-01-13T17:33:20+00:00</date>
229 <msg xml:space="preserve">other 1
231 <msg xml:space="preserve">other 1
230 other 2
232 other 2
231
233
232 other 3</msg>
234 other 3</msg>
233 </logentry>
235 </logentry>
234 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
236 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
235 <author email="user@hostname">User Name</author>
237 <author email="user@hostname">User Name</author>
236 <date>1970-01-12T13:46:40+00:00</date>
238 <date>1970-01-12T13:46:40+00:00</date>
237 <msg xml:space="preserve">line 1
239 <msg xml:space="preserve">line 1
238 line 2</msg>
240 line 2</msg>
239 </logentry>
241 </logentry>
240 </log>
242 </log>
241
243
242 $ hg log -v --style xml
244 $ hg log -v --style xml
243 <?xml version="1.0"?>
245 <?xml version="1.0"?>
244 <log>
246 <log>
245 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
247 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
246 <tag>tip</tag>
248 <tag>tip</tag>
247 <author email="test">test</author>
249 <author email="test">test</author>
248 <date>2020-01-01T10:01:00+00:00</date>
250 <date>2020-01-01T10:01:00+00:00</date>
249 <msg xml:space="preserve">third</msg>
251 <msg xml:space="preserve">third</msg>
250 <paths>
252 <paths>
251 <path action="A">fourth</path>
253 <path action="A">fourth</path>
252 <path action="A">third</path>
254 <path action="A">third</path>
253 <path action="R">second</path>
255 <path action="R">second</path>
254 </paths>
256 </paths>
255 <copies>
257 <copies>
256 <copy source="second">fourth</copy>
258 <copy source="second">fourth</copy>
257 </copies>
259 </copies>
258 </logentry>
260 </logentry>
259 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
261 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
260 <parent revision="-1" node="0000000000000000000000000000000000000000" />
262 <parent revision="-1" node="0000000000000000000000000000000000000000" />
261 <author email="user@hostname">User Name</author>
263 <author email="user@hostname">User Name</author>
262 <date>1970-01-12T13:46:40+00:00</date>
264 <date>1970-01-12T13:46:40+00:00</date>
263 <msg xml:space="preserve">second</msg>
265 <msg xml:space="preserve">second</msg>
264 <paths>
266 <paths>
265 <path action="A">second</path>
267 <path action="A">second</path>
266 </paths>
268 </paths>
267 </logentry>
269 </logentry>
268 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
270 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
269 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
271 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
270 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
272 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
271 <author email="person">person</author>
273 <author email="person">person</author>
272 <date>1970-01-18T08:40:01+00:00</date>
274 <date>1970-01-18T08:40:01+00:00</date>
273 <msg xml:space="preserve">merge</msg>
275 <msg xml:space="preserve">merge</msg>
274 <paths>
276 <paths>
275 </paths>
277 </paths>
276 </logentry>
278 </logentry>
277 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
279 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
278 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
280 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
279 <author email="person">person</author>
281 <author email="person">person</author>
280 <date>1970-01-18T08:40:00+00:00</date>
282 <date>1970-01-18T08:40:00+00:00</date>
281 <msg xml:space="preserve">new head</msg>
283 <msg xml:space="preserve">new head</msg>
282 <paths>
284 <paths>
283 <path action="A">d</path>
285 <path action="A">d</path>
284 </paths>
286 </paths>
285 </logentry>
287 </logentry>
286 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
288 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
287 <branch>foo</branch>
289 <branch>foo</branch>
288 <author email="person">person</author>
290 <author email="person">person</author>
289 <date>1970-01-17T04:53:20+00:00</date>
291 <date>1970-01-17T04:53:20+00:00</date>
290 <msg xml:space="preserve">new branch</msg>
292 <msg xml:space="preserve">new branch</msg>
291 <paths>
293 <paths>
292 </paths>
294 </paths>
293 </logentry>
295 </logentry>
294 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
296 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
295 <author email="person">person</author>
297 <author email="person">person</author>
296 <date>1970-01-16T01:06:40+00:00</date>
298 <date>1970-01-16T01:06:40+00:00</date>
297 <msg xml:space="preserve">no user, no domain</msg>
299 <msg xml:space="preserve">no user, no domain</msg>
298 <paths>
300 <paths>
299 <path action="M">c</path>
301 <path action="M">c</path>
300 </paths>
302 </paths>
301 </logentry>
303 </logentry>
302 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
304 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
303 <author email="other@place">other</author>
305 <author email="other@place">other</author>
304 <date>1970-01-14T21:20:00+00:00</date>
306 <date>1970-01-14T21:20:00+00:00</date>
305 <msg xml:space="preserve">no person</msg>
307 <msg xml:space="preserve">no person</msg>
306 <paths>
308 <paths>
307 <path action="A">c</path>
309 <path action="A">c</path>
308 </paths>
310 </paths>
309 </logentry>
311 </logentry>
310 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
312 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
311 <author email="other@place">A. N. Other</author>
313 <author email="other@place">A. N. Other</author>
312 <date>1970-01-13T17:33:20+00:00</date>
314 <date>1970-01-13T17:33:20+00:00</date>
313 <msg xml:space="preserve">other 1
315 <msg xml:space="preserve">other 1
314 other 2
316 other 2
315
317
316 other 3</msg>
318 other 3</msg>
317 <paths>
319 <paths>
318 <path action="A">b</path>
320 <path action="A">b</path>
319 </paths>
321 </paths>
320 </logentry>
322 </logentry>
321 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
323 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
322 <author email="user@hostname">User Name</author>
324 <author email="user@hostname">User Name</author>
323 <date>1970-01-12T13:46:40+00:00</date>
325 <date>1970-01-12T13:46:40+00:00</date>
324 <msg xml:space="preserve">line 1
326 <msg xml:space="preserve">line 1
325 line 2</msg>
327 line 2</msg>
326 <paths>
328 <paths>
327 <path action="A">a</path>
329 <path action="A">a</path>
328 </paths>
330 </paths>
329 </logentry>
331 </logentry>
330 </log>
332 </log>
331
333
332 $ hg log --debug --style xml
334 $ hg log --debug --style xml
333 <?xml version="1.0"?>
335 <?xml version="1.0"?>
334 <log>
336 <log>
335 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
337 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
336 <tag>tip</tag>
338 <tag>tip</tag>
337 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
339 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
338 <parent revision="-1" node="0000000000000000000000000000000000000000" />
340 <parent revision="-1" node="0000000000000000000000000000000000000000" />
339 <author email="test">test</author>
341 <author email="test">test</author>
340 <date>2020-01-01T10:01:00+00:00</date>
342 <date>2020-01-01T10:01:00+00:00</date>
341 <msg xml:space="preserve">third</msg>
343 <msg xml:space="preserve">third</msg>
342 <paths>
344 <paths>
343 <path action="A">fourth</path>
345 <path action="A">fourth</path>
344 <path action="A">third</path>
346 <path action="A">third</path>
345 <path action="R">second</path>
347 <path action="R">second</path>
346 </paths>
348 </paths>
347 <copies>
349 <copies>
348 <copy source="second">fourth</copy>
350 <copy source="second">fourth</copy>
349 </copies>
351 </copies>
350 <extra key="branch">default</extra>
352 <extra key="branch">default</extra>
351 </logentry>
353 </logentry>
352 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
354 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
353 <parent revision="-1" node="0000000000000000000000000000000000000000" />
355 <parent revision="-1" node="0000000000000000000000000000000000000000" />
354 <parent revision="-1" node="0000000000000000000000000000000000000000" />
356 <parent revision="-1" node="0000000000000000000000000000000000000000" />
355 <author email="user@hostname">User Name</author>
357 <author email="user@hostname">User Name</author>
356 <date>1970-01-12T13:46:40+00:00</date>
358 <date>1970-01-12T13:46:40+00:00</date>
357 <msg xml:space="preserve">second</msg>
359 <msg xml:space="preserve">second</msg>
358 <paths>
360 <paths>
359 <path action="A">second</path>
361 <path action="A">second</path>
360 </paths>
362 </paths>
361 <extra key="branch">default</extra>
363 <extra key="branch">default</extra>
362 </logentry>
364 </logentry>
363 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
365 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
364 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
366 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
365 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
367 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
366 <author email="person">person</author>
368 <author email="person">person</author>
367 <date>1970-01-18T08:40:01+00:00</date>
369 <date>1970-01-18T08:40:01+00:00</date>
368 <msg xml:space="preserve">merge</msg>
370 <msg xml:space="preserve">merge</msg>
369 <paths>
371 <paths>
370 </paths>
372 </paths>
371 <extra key="branch">default</extra>
373 <extra key="branch">default</extra>
372 </logentry>
374 </logentry>
373 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
375 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
374 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
376 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
375 <parent revision="-1" node="0000000000000000000000000000000000000000" />
377 <parent revision="-1" node="0000000000000000000000000000000000000000" />
376 <author email="person">person</author>
378 <author email="person">person</author>
377 <date>1970-01-18T08:40:00+00:00</date>
379 <date>1970-01-18T08:40:00+00:00</date>
378 <msg xml:space="preserve">new head</msg>
380 <msg xml:space="preserve">new head</msg>
379 <paths>
381 <paths>
380 <path action="A">d</path>
382 <path action="A">d</path>
381 </paths>
383 </paths>
382 <extra key="branch">default</extra>
384 <extra key="branch">default</extra>
383 </logentry>
385 </logentry>
384 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
386 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
385 <branch>foo</branch>
387 <branch>foo</branch>
386 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
388 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
387 <parent revision="-1" node="0000000000000000000000000000000000000000" />
389 <parent revision="-1" node="0000000000000000000000000000000000000000" />
388 <author email="person">person</author>
390 <author email="person">person</author>
389 <date>1970-01-17T04:53:20+00:00</date>
391 <date>1970-01-17T04:53:20+00:00</date>
390 <msg xml:space="preserve">new branch</msg>
392 <msg xml:space="preserve">new branch</msg>
391 <paths>
393 <paths>
392 </paths>
394 </paths>
393 <extra key="branch">foo</extra>
395 <extra key="branch">foo</extra>
394 </logentry>
396 </logentry>
395 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
397 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
396 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
398 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
397 <parent revision="-1" node="0000000000000000000000000000000000000000" />
399 <parent revision="-1" node="0000000000000000000000000000000000000000" />
398 <author email="person">person</author>
400 <author email="person">person</author>
399 <date>1970-01-16T01:06:40+00:00</date>
401 <date>1970-01-16T01:06:40+00:00</date>
400 <msg xml:space="preserve">no user, no domain</msg>
402 <msg xml:space="preserve">no user, no domain</msg>
401 <paths>
403 <paths>
402 <path action="M">c</path>
404 <path action="M">c</path>
403 </paths>
405 </paths>
404 <extra key="branch">default</extra>
406 <extra key="branch">default</extra>
405 </logentry>
407 </logentry>
406 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
408 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
407 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
409 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
408 <parent revision="-1" node="0000000000000000000000000000000000000000" />
410 <parent revision="-1" node="0000000000000000000000000000000000000000" />
409 <author email="other@place">other</author>
411 <author email="other@place">other</author>
410 <date>1970-01-14T21:20:00+00:00</date>
412 <date>1970-01-14T21:20:00+00:00</date>
411 <msg xml:space="preserve">no person</msg>
413 <msg xml:space="preserve">no person</msg>
412 <paths>
414 <paths>
413 <path action="A">c</path>
415 <path action="A">c</path>
414 </paths>
416 </paths>
415 <extra key="branch">default</extra>
417 <extra key="branch">default</extra>
416 </logentry>
418 </logentry>
417 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
419 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
418 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
420 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
419 <parent revision="-1" node="0000000000000000000000000000000000000000" />
421 <parent revision="-1" node="0000000000000000000000000000000000000000" />
420 <author email="other@place">A. N. Other</author>
422 <author email="other@place">A. N. Other</author>
421 <date>1970-01-13T17:33:20+00:00</date>
423 <date>1970-01-13T17:33:20+00:00</date>
422 <msg xml:space="preserve">other 1
424 <msg xml:space="preserve">other 1
423 other 2
425 other 2
424
426
425 other 3</msg>
427 other 3</msg>
426 <paths>
428 <paths>
427 <path action="A">b</path>
429 <path action="A">b</path>
428 </paths>
430 </paths>
429 <extra key="branch">default</extra>
431 <extra key="branch">default</extra>
430 </logentry>
432 </logentry>
431 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
433 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
432 <parent revision="-1" node="0000000000000000000000000000000000000000" />
434 <parent revision="-1" node="0000000000000000000000000000000000000000" />
433 <parent revision="-1" node="0000000000000000000000000000000000000000" />
435 <parent revision="-1" node="0000000000000000000000000000000000000000" />
434 <author email="user@hostname">User Name</author>
436 <author email="user@hostname">User Name</author>
435 <date>1970-01-12T13:46:40+00:00</date>
437 <date>1970-01-12T13:46:40+00:00</date>
436 <msg xml:space="preserve">line 1
438 <msg xml:space="preserve">line 1
437 line 2</msg>
439 line 2</msg>
438 <paths>
440 <paths>
439 <path action="A">a</path>
441 <path action="A">a</path>
440 </paths>
442 </paths>
441 <extra key="branch">default</extra>
443 <extra key="branch">default</extra>
442 </logentry>
444 </logentry>
443 </log>
445 </log>
444
446
445
447
446 Error if style not readable:
448 Error if style not readable:
447
449
448 #if unix-permissions
450 #if unix-permissions
449 $ touch q
451 $ touch q
450 $ chmod 0 q
452 $ chmod 0 q
451 $ hg log --style ./q
453 $ hg log --style ./q
452 abort: Permission denied: ./q
454 abort: Permission denied: ./q
453 [255]
455 [255]
454 #endif
456 #endif
455
457
456 Error if no style:
458 Error if no style:
457
459
458 $ hg log --style notexist
460 $ hg log --style notexist
459 abort: style not found: notexist
461 abort: style not found: notexist
460 [255]
462 [255]
461
463
462 Error if style missing key:
464 Error if style missing key:
463
465
464 $ echo 'q = q' > t
466 $ echo 'q = q' > t
465 $ hg log --style ./t
467 $ hg log --style ./t
466 abort: "changeset" not in template map
468 abort: "changeset" not in template map
467 [255]
469 [255]
468
470
469 Error if style missing value:
471 Error if style missing value:
470
472
471 $ echo 'changeset =' > t
473 $ echo 'changeset =' > t
472 $ hg log --style t
474 $ hg log --style t
473 abort: t:1: missing value
475 abort: t:1: missing value
474 [255]
476 [255]
475
477
476 Error if include fails:
478 Error if include fails:
477
479
478 $ echo 'changeset = q' >> t
480 $ echo 'changeset = q' >> t
479 #if unix-permissions
481 #if unix-permissions
480 $ hg log --style ./t
482 $ hg log --style ./t
481 abort: template file ./q: Permission denied
483 abort: template file ./q: Permission denied
482 [255]
484 [255]
483 $ rm q
485 $ rm q
484 #endif
486 #endif
485
487
486 Include works:
488 Include works:
487
489
488 $ echo '{rev}' > q
490 $ echo '{rev}' > q
489 $ hg log --style ./t
491 $ hg log --style ./t
490 8
492 8
491 7
493 7
492 6
494 6
493 5
495 5
494 4
496 4
495 3
497 3
496 2
498 2
497 1
499 1
498 0
500 0
499
501
500 ui.style works:
502 ui.style works:
501
503
502 $ echo '[ui]' > .hg/hgrc
504 $ echo '[ui]' > .hg/hgrc
503 $ echo 'style = t' >> .hg/hgrc
505 $ echo 'style = t' >> .hg/hgrc
504 $ hg log
506 $ hg log
505 8
507 8
506 7
508 7
507 6
509 6
508 5
510 5
509 4
511 4
510 3
512 3
511 2
513 2
512 1
514 1
513 0
515 0
514
516
515
517
516 Issue338:
518 Issue338:
517
519
518 $ hg log --style=changelog > changelog
520 $ hg log --style=changelog > changelog
519
521
520 $ cat changelog
522 $ cat changelog
521 2020-01-01 test <test>
523 2020-01-01 test <test>
522
524
523 * fourth, second, third:
525 * fourth, second, third:
524 third
526 third
525 [95c24699272e] [tip]
527 [95c24699272e] [tip]
526
528
527 1970-01-12 User Name <user@hostname>
529 1970-01-12 User Name <user@hostname>
528
530
529 * second:
531 * second:
530 second
532 second
531 [29114dbae42b]
533 [29114dbae42b]
532
534
533 1970-01-18 person <person>
535 1970-01-18 person <person>
534
536
535 * merge
537 * merge
536 [d41e714fe50d]
538 [d41e714fe50d]
537
539
538 * d:
540 * d:
539 new head
541 new head
540 [13207e5a10d9]
542 [13207e5a10d9]
541
543
542 1970-01-17 person <person>
544 1970-01-17 person <person>
543
545
544 * new branch
546 * new branch
545 [bbe44766e73d] <foo>
547 [bbe44766e73d] <foo>
546
548
547 1970-01-16 person <person>
549 1970-01-16 person <person>
548
550
549 * c:
551 * c:
550 no user, no domain
552 no user, no domain
551 [10e46f2dcbf4]
553 [10e46f2dcbf4]
552
554
553 1970-01-14 other <other@place>
555 1970-01-14 other <other@place>
554
556
555 * c:
557 * c:
556 no person
558 no person
557 [97054abb4ab8]
559 [97054abb4ab8]
558
560
559 1970-01-13 A. N. Other <other@place>
561 1970-01-13 A. N. Other <other@place>
560
562
561 * b:
563 * b:
562 other 1 other 2
564 other 1 other 2
563
565
564 other 3
566 other 3
565 [b608e9d1a3f0]
567 [b608e9d1a3f0]
566
568
567 1970-01-12 User Name <user@hostname>
569 1970-01-12 User Name <user@hostname>
568
570
569 * a:
571 * a:
570 line 1 line 2
572 line 1 line 2
571 [1e4e1b8f71e0]
573 [1e4e1b8f71e0]
572
574
573
575
574 Issue2130: xml output for 'hg heads' is malformed
576 Issue2130: xml output for 'hg heads' is malformed
575
577
576 $ hg heads --style changelog
578 $ hg heads --style changelog
577 2020-01-01 test <test>
579 2020-01-01 test <test>
578
580
579 * fourth, second, third:
581 * fourth, second, third:
580 third
582 third
581 [95c24699272e] [tip]
583 [95c24699272e] [tip]
582
584
583 1970-01-18 person <person>
585 1970-01-18 person <person>
584
586
585 * merge
587 * merge
586 [d41e714fe50d]
588 [d41e714fe50d]
587
589
588 1970-01-17 person <person>
590 1970-01-17 person <person>
589
591
590 * new branch
592 * new branch
591 [bbe44766e73d] <foo>
593 [bbe44766e73d] <foo>
592
594
593
595
594 Keys work:
596 Keys work:
595
597
596 $ for key in author branch branches date desc file_adds file_dels file_mods \
598 $ for key in author branch branches date desc file_adds file_dels file_mods \
597 > file_copies file_copies_switch files \
599 > file_copies file_copies_switch files \
598 > manifest node parents rev tags diffstat extras \
600 > manifest node parents rev tags diffstat extras \
599 > p1rev p2rev p1node p2node; do
601 > p1rev p2rev p1node p2node; do
600 > for mode in '' --verbose --debug; do
602 > for mode in '' --verbose --debug; do
601 > hg log $mode --template "$key$mode: {$key}\n"
603 > hg log $mode --template "$key$mode: {$key}\n"
602 > done
604 > done
603 > done
605 > done
604 author: test
606 author: test
605 author: User Name <user@hostname>
607 author: User Name <user@hostname>
606 author: person
608 author: person
607 author: person
609 author: person
608 author: person
610 author: person
609 author: person
611 author: person
610 author: other@place
612 author: other@place
611 author: A. N. Other <other@place>
613 author: A. N. Other <other@place>
612 author: User Name <user@hostname>
614 author: User Name <user@hostname>
613 author--verbose: test
615 author--verbose: test
614 author--verbose: User Name <user@hostname>
616 author--verbose: User Name <user@hostname>
615 author--verbose: person
617 author--verbose: person
616 author--verbose: person
618 author--verbose: person
617 author--verbose: person
619 author--verbose: person
618 author--verbose: person
620 author--verbose: person
619 author--verbose: other@place
621 author--verbose: other@place
620 author--verbose: A. N. Other <other@place>
622 author--verbose: A. N. Other <other@place>
621 author--verbose: User Name <user@hostname>
623 author--verbose: User Name <user@hostname>
622 author--debug: test
624 author--debug: test
623 author--debug: User Name <user@hostname>
625 author--debug: User Name <user@hostname>
624 author--debug: person
626 author--debug: person
625 author--debug: person
627 author--debug: person
626 author--debug: person
628 author--debug: person
627 author--debug: person
629 author--debug: person
628 author--debug: other@place
630 author--debug: other@place
629 author--debug: A. N. Other <other@place>
631 author--debug: A. N. Other <other@place>
630 author--debug: User Name <user@hostname>
632 author--debug: User Name <user@hostname>
631 branch: default
633 branch: default
632 branch: default
634 branch: default
633 branch: default
635 branch: default
634 branch: default
636 branch: default
635 branch: foo
637 branch: foo
636 branch: default
638 branch: default
637 branch: default
639 branch: default
638 branch: default
640 branch: default
639 branch: default
641 branch: default
640 branch--verbose: default
642 branch--verbose: default
641 branch--verbose: default
643 branch--verbose: default
642 branch--verbose: default
644 branch--verbose: default
643 branch--verbose: default
645 branch--verbose: default
644 branch--verbose: foo
646 branch--verbose: foo
645 branch--verbose: default
647 branch--verbose: default
646 branch--verbose: default
648 branch--verbose: default
647 branch--verbose: default
649 branch--verbose: default
648 branch--verbose: default
650 branch--verbose: default
649 branch--debug: default
651 branch--debug: default
650 branch--debug: default
652 branch--debug: default
651 branch--debug: default
653 branch--debug: default
652 branch--debug: default
654 branch--debug: default
653 branch--debug: foo
655 branch--debug: foo
654 branch--debug: default
656 branch--debug: default
655 branch--debug: default
657 branch--debug: default
656 branch--debug: default
658 branch--debug: default
657 branch--debug: default
659 branch--debug: default
658 branches:
660 branches:
659 branches:
661 branches:
660 branches:
662 branches:
661 branches:
663 branches:
662 branches: foo
664 branches: foo
663 branches:
665 branches:
664 branches:
666 branches:
665 branches:
667 branches:
666 branches:
668 branches:
667 branches--verbose:
669 branches--verbose:
668 branches--verbose:
670 branches--verbose:
669 branches--verbose:
671 branches--verbose:
670 branches--verbose:
672 branches--verbose:
671 branches--verbose: foo
673 branches--verbose: foo
672 branches--verbose:
674 branches--verbose:
673 branches--verbose:
675 branches--verbose:
674 branches--verbose:
676 branches--verbose:
675 branches--verbose:
677 branches--verbose:
676 branches--debug:
678 branches--debug:
677 branches--debug:
679 branches--debug:
678 branches--debug:
680 branches--debug:
679 branches--debug:
681 branches--debug:
680 branches--debug: foo
682 branches--debug: foo
681 branches--debug:
683 branches--debug:
682 branches--debug:
684 branches--debug:
683 branches--debug:
685 branches--debug:
684 branches--debug:
686 branches--debug:
685 date: 1577872860.00
687 date: 1577872860.00
686 date: 1000000.00
688 date: 1000000.00
687 date: 1500001.00
689 date: 1500001.00
688 date: 1500000.00
690 date: 1500000.00
689 date: 1400000.00
691 date: 1400000.00
690 date: 1300000.00
692 date: 1300000.00
691 date: 1200000.00
693 date: 1200000.00
692 date: 1100000.00
694 date: 1100000.00
693 date: 1000000.00
695 date: 1000000.00
694 date--verbose: 1577872860.00
696 date--verbose: 1577872860.00
695 date--verbose: 1000000.00
697 date--verbose: 1000000.00
696 date--verbose: 1500001.00
698 date--verbose: 1500001.00
697 date--verbose: 1500000.00
699 date--verbose: 1500000.00
698 date--verbose: 1400000.00
700 date--verbose: 1400000.00
699 date--verbose: 1300000.00
701 date--verbose: 1300000.00
700 date--verbose: 1200000.00
702 date--verbose: 1200000.00
701 date--verbose: 1100000.00
703 date--verbose: 1100000.00
702 date--verbose: 1000000.00
704 date--verbose: 1000000.00
703 date--debug: 1577872860.00
705 date--debug: 1577872860.00
704 date--debug: 1000000.00
706 date--debug: 1000000.00
705 date--debug: 1500001.00
707 date--debug: 1500001.00
706 date--debug: 1500000.00
708 date--debug: 1500000.00
707 date--debug: 1400000.00
709 date--debug: 1400000.00
708 date--debug: 1300000.00
710 date--debug: 1300000.00
709 date--debug: 1200000.00
711 date--debug: 1200000.00
710 date--debug: 1100000.00
712 date--debug: 1100000.00
711 date--debug: 1000000.00
713 date--debug: 1000000.00
712 desc: third
714 desc: third
713 desc: second
715 desc: second
714 desc: merge
716 desc: merge
715 desc: new head
717 desc: new head
716 desc: new branch
718 desc: new branch
717 desc: no user, no domain
719 desc: no user, no domain
718 desc: no person
720 desc: no person
719 desc: other 1
721 desc: other 1
720 other 2
722 other 2
721
723
722 other 3
724 other 3
723 desc: line 1
725 desc: line 1
724 line 2
726 line 2
725 desc--verbose: third
727 desc--verbose: third
726 desc--verbose: second
728 desc--verbose: second
727 desc--verbose: merge
729 desc--verbose: merge
728 desc--verbose: new head
730 desc--verbose: new head
729 desc--verbose: new branch
731 desc--verbose: new branch
730 desc--verbose: no user, no domain
732 desc--verbose: no user, no domain
731 desc--verbose: no person
733 desc--verbose: no person
732 desc--verbose: other 1
734 desc--verbose: other 1
733 other 2
735 other 2
734
736
735 other 3
737 other 3
736 desc--verbose: line 1
738 desc--verbose: line 1
737 line 2
739 line 2
738 desc--debug: third
740 desc--debug: third
739 desc--debug: second
741 desc--debug: second
740 desc--debug: merge
742 desc--debug: merge
741 desc--debug: new head
743 desc--debug: new head
742 desc--debug: new branch
744 desc--debug: new branch
743 desc--debug: no user, no domain
745 desc--debug: no user, no domain
744 desc--debug: no person
746 desc--debug: no person
745 desc--debug: other 1
747 desc--debug: other 1
746 other 2
748 other 2
747
749
748 other 3
750 other 3
749 desc--debug: line 1
751 desc--debug: line 1
750 line 2
752 line 2
751 file_adds: fourth third
753 file_adds: fourth third
752 file_adds: second
754 file_adds: second
753 file_adds:
755 file_adds:
754 file_adds: d
756 file_adds: d
755 file_adds:
757 file_adds:
756 file_adds:
758 file_adds:
757 file_adds: c
759 file_adds: c
758 file_adds: b
760 file_adds: b
759 file_adds: a
761 file_adds: a
760 file_adds--verbose: fourth third
762 file_adds--verbose: fourth third
761 file_adds--verbose: second
763 file_adds--verbose: second
762 file_adds--verbose:
764 file_adds--verbose:
763 file_adds--verbose: d
765 file_adds--verbose: d
764 file_adds--verbose:
766 file_adds--verbose:
765 file_adds--verbose:
767 file_adds--verbose:
766 file_adds--verbose: c
768 file_adds--verbose: c
767 file_adds--verbose: b
769 file_adds--verbose: b
768 file_adds--verbose: a
770 file_adds--verbose: a
769 file_adds--debug: fourth third
771 file_adds--debug: fourth third
770 file_adds--debug: second
772 file_adds--debug: second
771 file_adds--debug:
773 file_adds--debug:
772 file_adds--debug: d
774 file_adds--debug: d
773 file_adds--debug:
775 file_adds--debug:
774 file_adds--debug:
776 file_adds--debug:
775 file_adds--debug: c
777 file_adds--debug: c
776 file_adds--debug: b
778 file_adds--debug: b
777 file_adds--debug: a
779 file_adds--debug: a
778 file_dels: second
780 file_dels: second
779 file_dels:
781 file_dels:
780 file_dels:
782 file_dels:
781 file_dels:
783 file_dels:
782 file_dels:
784 file_dels:
783 file_dels:
785 file_dels:
784 file_dels:
786 file_dels:
785 file_dels:
787 file_dels:
786 file_dels:
788 file_dels:
787 file_dels--verbose: second
789 file_dels--verbose: second
788 file_dels--verbose:
790 file_dels--verbose:
789 file_dels--verbose:
791 file_dels--verbose:
790 file_dels--verbose:
792 file_dels--verbose:
791 file_dels--verbose:
793 file_dels--verbose:
792 file_dels--verbose:
794 file_dels--verbose:
793 file_dels--verbose:
795 file_dels--verbose:
794 file_dels--verbose:
796 file_dels--verbose:
795 file_dels--verbose:
797 file_dels--verbose:
796 file_dels--debug: second
798 file_dels--debug: second
797 file_dels--debug:
799 file_dels--debug:
798 file_dels--debug:
800 file_dels--debug:
799 file_dels--debug:
801 file_dels--debug:
800 file_dels--debug:
802 file_dels--debug:
801 file_dels--debug:
803 file_dels--debug:
802 file_dels--debug:
804 file_dels--debug:
803 file_dels--debug:
805 file_dels--debug:
804 file_dels--debug:
806 file_dels--debug:
805 file_mods:
807 file_mods:
806 file_mods:
808 file_mods:
807 file_mods:
809 file_mods:
808 file_mods:
810 file_mods:
809 file_mods:
811 file_mods:
810 file_mods: c
812 file_mods: c
811 file_mods:
813 file_mods:
812 file_mods:
814 file_mods:
813 file_mods:
815 file_mods:
814 file_mods--verbose:
816 file_mods--verbose:
815 file_mods--verbose:
817 file_mods--verbose:
816 file_mods--verbose:
818 file_mods--verbose:
817 file_mods--verbose:
819 file_mods--verbose:
818 file_mods--verbose:
820 file_mods--verbose:
819 file_mods--verbose: c
821 file_mods--verbose: c
820 file_mods--verbose:
822 file_mods--verbose:
821 file_mods--verbose:
823 file_mods--verbose:
822 file_mods--verbose:
824 file_mods--verbose:
823 file_mods--debug:
825 file_mods--debug:
824 file_mods--debug:
826 file_mods--debug:
825 file_mods--debug:
827 file_mods--debug:
826 file_mods--debug:
828 file_mods--debug:
827 file_mods--debug:
829 file_mods--debug:
828 file_mods--debug: c
830 file_mods--debug: c
829 file_mods--debug:
831 file_mods--debug:
830 file_mods--debug:
832 file_mods--debug:
831 file_mods--debug:
833 file_mods--debug:
832 file_copies: fourth (second)
834 file_copies: fourth (second)
833 file_copies:
835 file_copies:
834 file_copies:
836 file_copies:
835 file_copies:
837 file_copies:
836 file_copies:
838 file_copies:
837 file_copies:
839 file_copies:
838 file_copies:
840 file_copies:
839 file_copies:
841 file_copies:
840 file_copies:
842 file_copies:
841 file_copies--verbose: fourth (second)
843 file_copies--verbose: fourth (second)
842 file_copies--verbose:
844 file_copies--verbose:
843 file_copies--verbose:
845 file_copies--verbose:
844 file_copies--verbose:
846 file_copies--verbose:
845 file_copies--verbose:
847 file_copies--verbose:
846 file_copies--verbose:
848 file_copies--verbose:
847 file_copies--verbose:
849 file_copies--verbose:
848 file_copies--verbose:
850 file_copies--verbose:
849 file_copies--verbose:
851 file_copies--verbose:
850 file_copies--debug: fourth (second)
852 file_copies--debug: fourth (second)
851 file_copies--debug:
853 file_copies--debug:
852 file_copies--debug:
854 file_copies--debug:
853 file_copies--debug:
855 file_copies--debug:
854 file_copies--debug:
856 file_copies--debug:
855 file_copies--debug:
857 file_copies--debug:
856 file_copies--debug:
858 file_copies--debug:
857 file_copies--debug:
859 file_copies--debug:
858 file_copies--debug:
860 file_copies--debug:
859 file_copies_switch:
861 file_copies_switch:
860 file_copies_switch:
862 file_copies_switch:
861 file_copies_switch:
863 file_copies_switch:
862 file_copies_switch:
864 file_copies_switch:
863 file_copies_switch:
865 file_copies_switch:
864 file_copies_switch:
866 file_copies_switch:
865 file_copies_switch:
867 file_copies_switch:
866 file_copies_switch:
868 file_copies_switch:
867 file_copies_switch:
869 file_copies_switch:
868 file_copies_switch--verbose:
870 file_copies_switch--verbose:
869 file_copies_switch--verbose:
871 file_copies_switch--verbose:
870 file_copies_switch--verbose:
872 file_copies_switch--verbose:
871 file_copies_switch--verbose:
873 file_copies_switch--verbose:
872 file_copies_switch--verbose:
874 file_copies_switch--verbose:
873 file_copies_switch--verbose:
875 file_copies_switch--verbose:
874 file_copies_switch--verbose:
876 file_copies_switch--verbose:
875 file_copies_switch--verbose:
877 file_copies_switch--verbose:
876 file_copies_switch--verbose:
878 file_copies_switch--verbose:
877 file_copies_switch--debug:
879 file_copies_switch--debug:
878 file_copies_switch--debug:
880 file_copies_switch--debug:
879 file_copies_switch--debug:
881 file_copies_switch--debug:
880 file_copies_switch--debug:
882 file_copies_switch--debug:
881 file_copies_switch--debug:
883 file_copies_switch--debug:
882 file_copies_switch--debug:
884 file_copies_switch--debug:
883 file_copies_switch--debug:
885 file_copies_switch--debug:
884 file_copies_switch--debug:
886 file_copies_switch--debug:
885 file_copies_switch--debug:
887 file_copies_switch--debug:
886 files: fourth second third
888 files: fourth second third
887 files: second
889 files: second
888 files:
890 files:
889 files: d
891 files: d
890 files:
892 files:
891 files: c
893 files: c
892 files: c
894 files: c
893 files: b
895 files: b
894 files: a
896 files: a
895 files--verbose: fourth second third
897 files--verbose: fourth second third
896 files--verbose: second
898 files--verbose: second
897 files--verbose:
899 files--verbose:
898 files--verbose: d
900 files--verbose: d
899 files--verbose:
901 files--verbose:
900 files--verbose: c
902 files--verbose: c
901 files--verbose: c
903 files--verbose: c
902 files--verbose: b
904 files--verbose: b
903 files--verbose: a
905 files--verbose: a
904 files--debug: fourth second third
906 files--debug: fourth second third
905 files--debug: second
907 files--debug: second
906 files--debug:
908 files--debug:
907 files--debug: d
909 files--debug: d
908 files--debug:
910 files--debug:
909 files--debug: c
911 files--debug: c
910 files--debug: c
912 files--debug: c
911 files--debug: b
913 files--debug: b
912 files--debug: a
914 files--debug: a
913 manifest: 6:94961b75a2da
915 manifest: 6:94961b75a2da
914 manifest: 5:f2dbc354b94e
916 manifest: 5:f2dbc354b94e
915 manifest: 4:4dc3def4f9b4
917 manifest: 4:4dc3def4f9b4
916 manifest: 4:4dc3def4f9b4
918 manifest: 4:4dc3def4f9b4
917 manifest: 3:cb5a1327723b
919 manifest: 3:cb5a1327723b
918 manifest: 3:cb5a1327723b
920 manifest: 3:cb5a1327723b
919 manifest: 2:6e0e82995c35
921 manifest: 2:6e0e82995c35
920 manifest: 1:4e8d705b1e53
922 manifest: 1:4e8d705b1e53
921 manifest: 0:a0c8bcbbb45c
923 manifest: 0:a0c8bcbbb45c
922 manifest--verbose: 6:94961b75a2da
924 manifest--verbose: 6:94961b75a2da
923 manifest--verbose: 5:f2dbc354b94e
925 manifest--verbose: 5:f2dbc354b94e
924 manifest--verbose: 4:4dc3def4f9b4
926 manifest--verbose: 4:4dc3def4f9b4
925 manifest--verbose: 4:4dc3def4f9b4
927 manifest--verbose: 4:4dc3def4f9b4
926 manifest--verbose: 3:cb5a1327723b
928 manifest--verbose: 3:cb5a1327723b
927 manifest--verbose: 3:cb5a1327723b
929 manifest--verbose: 3:cb5a1327723b
928 manifest--verbose: 2:6e0e82995c35
930 manifest--verbose: 2:6e0e82995c35
929 manifest--verbose: 1:4e8d705b1e53
931 manifest--verbose: 1:4e8d705b1e53
930 manifest--verbose: 0:a0c8bcbbb45c
932 manifest--verbose: 0:a0c8bcbbb45c
931 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
933 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
932 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
934 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
933 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
935 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
934 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
936 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
935 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
937 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
936 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
938 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
937 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
939 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
938 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
940 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
939 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
941 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
940 node: 95c24699272ef57d062b8bccc32c878bf841784a
942 node: 95c24699272ef57d062b8bccc32c878bf841784a
941 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
943 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
942 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
944 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
943 node: 13207e5a10d9fd28ec424934298e176197f2c67f
945 node: 13207e5a10d9fd28ec424934298e176197f2c67f
944 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
946 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
945 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
947 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
946 node: 97054abb4ab824450e9164180baf491ae0078465
948 node: 97054abb4ab824450e9164180baf491ae0078465
947 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
949 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
948 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
950 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
949 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
951 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
950 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
952 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
951 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
953 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
952 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
954 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
953 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
955 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
954 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
956 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
955 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
957 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
956 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
958 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
957 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
959 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
958 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
960 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
959 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
961 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
960 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
962 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
961 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
963 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
962 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
964 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
963 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
965 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
964 node--debug: 97054abb4ab824450e9164180baf491ae0078465
966 node--debug: 97054abb4ab824450e9164180baf491ae0078465
965 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
967 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
966 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
968 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
967 parents:
969 parents:
968 parents: -1:000000000000
970 parents: -1:000000000000
969 parents: 5:13207e5a10d9 4:bbe44766e73d
971 parents: 5:13207e5a10d9 4:bbe44766e73d
970 parents: 3:10e46f2dcbf4
972 parents: 3:10e46f2dcbf4
971 parents:
973 parents:
972 parents:
974 parents:
973 parents:
975 parents:
974 parents:
976 parents:
975 parents:
977 parents:
976 parents--verbose:
978 parents--verbose:
977 parents--verbose: -1:000000000000
979 parents--verbose: -1:000000000000
978 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
980 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
979 parents--verbose: 3:10e46f2dcbf4
981 parents--verbose: 3:10e46f2dcbf4
980 parents--verbose:
982 parents--verbose:
981 parents--verbose:
983 parents--verbose:
982 parents--verbose:
984 parents--verbose:
983 parents--verbose:
985 parents--verbose:
984 parents--verbose:
986 parents--verbose:
985 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
987 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
986 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
988 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
987 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
989 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
988 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
990 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
989 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
991 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
990 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
992 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
991 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
993 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
992 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
994 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
993 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
995 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
994 rev: 8
996 rev: 8
995 rev: 7
997 rev: 7
996 rev: 6
998 rev: 6
997 rev: 5
999 rev: 5
998 rev: 4
1000 rev: 4
999 rev: 3
1001 rev: 3
1000 rev: 2
1002 rev: 2
1001 rev: 1
1003 rev: 1
1002 rev: 0
1004 rev: 0
1003 rev--verbose: 8
1005 rev--verbose: 8
1004 rev--verbose: 7
1006 rev--verbose: 7
1005 rev--verbose: 6
1007 rev--verbose: 6
1006 rev--verbose: 5
1008 rev--verbose: 5
1007 rev--verbose: 4
1009 rev--verbose: 4
1008 rev--verbose: 3
1010 rev--verbose: 3
1009 rev--verbose: 2
1011 rev--verbose: 2
1010 rev--verbose: 1
1012 rev--verbose: 1
1011 rev--verbose: 0
1013 rev--verbose: 0
1012 rev--debug: 8
1014 rev--debug: 8
1013 rev--debug: 7
1015 rev--debug: 7
1014 rev--debug: 6
1016 rev--debug: 6
1015 rev--debug: 5
1017 rev--debug: 5
1016 rev--debug: 4
1018 rev--debug: 4
1017 rev--debug: 3
1019 rev--debug: 3
1018 rev--debug: 2
1020 rev--debug: 2
1019 rev--debug: 1
1021 rev--debug: 1
1020 rev--debug: 0
1022 rev--debug: 0
1021 tags: tip
1023 tags: tip
1022 tags:
1024 tags:
1023 tags:
1025 tags:
1024 tags:
1026 tags:
1025 tags:
1027 tags:
1026 tags:
1028 tags:
1027 tags:
1029 tags:
1028 tags:
1030 tags:
1029 tags:
1031 tags:
1030 tags--verbose: tip
1032 tags--verbose: tip
1031 tags--verbose:
1033 tags--verbose:
1032 tags--verbose:
1034 tags--verbose:
1033 tags--verbose:
1035 tags--verbose:
1034 tags--verbose:
1036 tags--verbose:
1035 tags--verbose:
1037 tags--verbose:
1036 tags--verbose:
1038 tags--verbose:
1037 tags--verbose:
1039 tags--verbose:
1038 tags--verbose:
1040 tags--verbose:
1039 tags--debug: tip
1041 tags--debug: tip
1040 tags--debug:
1042 tags--debug:
1041 tags--debug:
1043 tags--debug:
1042 tags--debug:
1044 tags--debug:
1043 tags--debug:
1045 tags--debug:
1044 tags--debug:
1046 tags--debug:
1045 tags--debug:
1047 tags--debug:
1046 tags--debug:
1048 tags--debug:
1047 tags--debug:
1049 tags--debug:
1048 diffstat: 3: +2/-1
1050 diffstat: 3: +2/-1
1049 diffstat: 1: +1/-0
1051 diffstat: 1: +1/-0
1050 diffstat: 0: +0/-0
1052 diffstat: 0: +0/-0
1051 diffstat: 1: +1/-0
1053 diffstat: 1: +1/-0
1052 diffstat: 0: +0/-0
1054 diffstat: 0: +0/-0
1053 diffstat: 1: +1/-0
1055 diffstat: 1: +1/-0
1054 diffstat: 1: +4/-0
1056 diffstat: 1: +4/-0
1055 diffstat: 1: +2/-0
1057 diffstat: 1: +2/-0
1056 diffstat: 1: +1/-0
1058 diffstat: 1: +1/-0
1057 diffstat--verbose: 3: +2/-1
1059 diffstat--verbose: 3: +2/-1
1058 diffstat--verbose: 1: +1/-0
1060 diffstat--verbose: 1: +1/-0
1059 diffstat--verbose: 0: +0/-0
1061 diffstat--verbose: 0: +0/-0
1060 diffstat--verbose: 1: +1/-0
1062 diffstat--verbose: 1: +1/-0
1061 diffstat--verbose: 0: +0/-0
1063 diffstat--verbose: 0: +0/-0
1062 diffstat--verbose: 1: +1/-0
1064 diffstat--verbose: 1: +1/-0
1063 diffstat--verbose: 1: +4/-0
1065 diffstat--verbose: 1: +4/-0
1064 diffstat--verbose: 1: +2/-0
1066 diffstat--verbose: 1: +2/-0
1065 diffstat--verbose: 1: +1/-0
1067 diffstat--verbose: 1: +1/-0
1066 diffstat--debug: 3: +2/-1
1068 diffstat--debug: 3: +2/-1
1067 diffstat--debug: 1: +1/-0
1069 diffstat--debug: 1: +1/-0
1068 diffstat--debug: 0: +0/-0
1070 diffstat--debug: 0: +0/-0
1069 diffstat--debug: 1: +1/-0
1071 diffstat--debug: 1: +1/-0
1070 diffstat--debug: 0: +0/-0
1072 diffstat--debug: 0: +0/-0
1071 diffstat--debug: 1: +1/-0
1073 diffstat--debug: 1: +1/-0
1072 diffstat--debug: 1: +4/-0
1074 diffstat--debug: 1: +4/-0
1073 diffstat--debug: 1: +2/-0
1075 diffstat--debug: 1: +2/-0
1074 diffstat--debug: 1: +1/-0
1076 diffstat--debug: 1: +1/-0
1075 extras: branch=default
1077 extras: branch=default
1076 extras: branch=default
1078 extras: branch=default
1077 extras: branch=default
1079 extras: branch=default
1078 extras: branch=default
1080 extras: branch=default
1079 extras: branch=foo
1081 extras: branch=foo
1080 extras: branch=default
1082 extras: branch=default
1081 extras: branch=default
1083 extras: branch=default
1082 extras: branch=default
1084 extras: branch=default
1083 extras: branch=default
1085 extras: branch=default
1084 extras--verbose: branch=default
1086 extras--verbose: branch=default
1085 extras--verbose: branch=default
1087 extras--verbose: branch=default
1086 extras--verbose: branch=default
1088 extras--verbose: branch=default
1087 extras--verbose: branch=default
1089 extras--verbose: branch=default
1088 extras--verbose: branch=foo
1090 extras--verbose: branch=foo
1089 extras--verbose: branch=default
1091 extras--verbose: branch=default
1090 extras--verbose: branch=default
1092 extras--verbose: branch=default
1091 extras--verbose: branch=default
1093 extras--verbose: branch=default
1092 extras--verbose: branch=default
1094 extras--verbose: branch=default
1093 extras--debug: branch=default
1095 extras--debug: branch=default
1094 extras--debug: branch=default
1096 extras--debug: branch=default
1095 extras--debug: branch=default
1097 extras--debug: branch=default
1096 extras--debug: branch=default
1098 extras--debug: branch=default
1097 extras--debug: branch=foo
1099 extras--debug: branch=foo
1098 extras--debug: branch=default
1100 extras--debug: branch=default
1099 extras--debug: branch=default
1101 extras--debug: branch=default
1100 extras--debug: branch=default
1102 extras--debug: branch=default
1101 extras--debug: branch=default
1103 extras--debug: branch=default
1102 p1rev: 7
1104 p1rev: 7
1103 p1rev: -1
1105 p1rev: -1
1104 p1rev: 5
1106 p1rev: 5
1105 p1rev: 3
1107 p1rev: 3
1106 p1rev: 3
1108 p1rev: 3
1107 p1rev: 2
1109 p1rev: 2
1108 p1rev: 1
1110 p1rev: 1
1109 p1rev: 0
1111 p1rev: 0
1110 p1rev: -1
1112 p1rev: -1
1111 p1rev--verbose: 7
1113 p1rev--verbose: 7
1112 p1rev--verbose: -1
1114 p1rev--verbose: -1
1113 p1rev--verbose: 5
1115 p1rev--verbose: 5
1114 p1rev--verbose: 3
1116 p1rev--verbose: 3
1115 p1rev--verbose: 3
1117 p1rev--verbose: 3
1116 p1rev--verbose: 2
1118 p1rev--verbose: 2
1117 p1rev--verbose: 1
1119 p1rev--verbose: 1
1118 p1rev--verbose: 0
1120 p1rev--verbose: 0
1119 p1rev--verbose: -1
1121 p1rev--verbose: -1
1120 p1rev--debug: 7
1122 p1rev--debug: 7
1121 p1rev--debug: -1
1123 p1rev--debug: -1
1122 p1rev--debug: 5
1124 p1rev--debug: 5
1123 p1rev--debug: 3
1125 p1rev--debug: 3
1124 p1rev--debug: 3
1126 p1rev--debug: 3
1125 p1rev--debug: 2
1127 p1rev--debug: 2
1126 p1rev--debug: 1
1128 p1rev--debug: 1
1127 p1rev--debug: 0
1129 p1rev--debug: 0
1128 p1rev--debug: -1
1130 p1rev--debug: -1
1129 p2rev: -1
1131 p2rev: -1
1130 p2rev: -1
1132 p2rev: -1
1131 p2rev: 4
1133 p2rev: 4
1132 p2rev: -1
1134 p2rev: -1
1133 p2rev: -1
1135 p2rev: -1
1134 p2rev: -1
1136 p2rev: -1
1135 p2rev: -1
1137 p2rev: -1
1136 p2rev: -1
1138 p2rev: -1
1137 p2rev: -1
1139 p2rev: -1
1138 p2rev--verbose: -1
1140 p2rev--verbose: -1
1139 p2rev--verbose: -1
1141 p2rev--verbose: -1
1140 p2rev--verbose: 4
1142 p2rev--verbose: 4
1141 p2rev--verbose: -1
1143 p2rev--verbose: -1
1142 p2rev--verbose: -1
1144 p2rev--verbose: -1
1143 p2rev--verbose: -1
1145 p2rev--verbose: -1
1144 p2rev--verbose: -1
1146 p2rev--verbose: -1
1145 p2rev--verbose: -1
1147 p2rev--verbose: -1
1146 p2rev--verbose: -1
1148 p2rev--verbose: -1
1147 p2rev--debug: -1
1149 p2rev--debug: -1
1148 p2rev--debug: -1
1150 p2rev--debug: -1
1149 p2rev--debug: 4
1151 p2rev--debug: 4
1150 p2rev--debug: -1
1152 p2rev--debug: -1
1151 p2rev--debug: -1
1153 p2rev--debug: -1
1152 p2rev--debug: -1
1154 p2rev--debug: -1
1153 p2rev--debug: -1
1155 p2rev--debug: -1
1154 p2rev--debug: -1
1156 p2rev--debug: -1
1155 p2rev--debug: -1
1157 p2rev--debug: -1
1156 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1158 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1157 p1node: 0000000000000000000000000000000000000000
1159 p1node: 0000000000000000000000000000000000000000
1158 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1160 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1159 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1161 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1160 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1162 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1161 p1node: 97054abb4ab824450e9164180baf491ae0078465
1163 p1node: 97054abb4ab824450e9164180baf491ae0078465
1162 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1164 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1163 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1165 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1164 p1node: 0000000000000000000000000000000000000000
1166 p1node: 0000000000000000000000000000000000000000
1165 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1167 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1166 p1node--verbose: 0000000000000000000000000000000000000000
1168 p1node--verbose: 0000000000000000000000000000000000000000
1167 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1169 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1168 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1170 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1169 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1171 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1170 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1172 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1171 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1173 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1172 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1174 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1173 p1node--verbose: 0000000000000000000000000000000000000000
1175 p1node--verbose: 0000000000000000000000000000000000000000
1174 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1176 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1175 p1node--debug: 0000000000000000000000000000000000000000
1177 p1node--debug: 0000000000000000000000000000000000000000
1176 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1178 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1177 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1179 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1178 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1180 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1179 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1181 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1180 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1182 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1181 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1183 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1182 p1node--debug: 0000000000000000000000000000000000000000
1184 p1node--debug: 0000000000000000000000000000000000000000
1183 p2node: 0000000000000000000000000000000000000000
1185 p2node: 0000000000000000000000000000000000000000
1184 p2node: 0000000000000000000000000000000000000000
1186 p2node: 0000000000000000000000000000000000000000
1185 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1187 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1186 p2node: 0000000000000000000000000000000000000000
1188 p2node: 0000000000000000000000000000000000000000
1187 p2node: 0000000000000000000000000000000000000000
1189 p2node: 0000000000000000000000000000000000000000
1188 p2node: 0000000000000000000000000000000000000000
1190 p2node: 0000000000000000000000000000000000000000
1189 p2node: 0000000000000000000000000000000000000000
1191 p2node: 0000000000000000000000000000000000000000
1190 p2node: 0000000000000000000000000000000000000000
1192 p2node: 0000000000000000000000000000000000000000
1191 p2node: 0000000000000000000000000000000000000000
1193 p2node: 0000000000000000000000000000000000000000
1192 p2node--verbose: 0000000000000000000000000000000000000000
1194 p2node--verbose: 0000000000000000000000000000000000000000
1193 p2node--verbose: 0000000000000000000000000000000000000000
1195 p2node--verbose: 0000000000000000000000000000000000000000
1194 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1196 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1195 p2node--verbose: 0000000000000000000000000000000000000000
1197 p2node--verbose: 0000000000000000000000000000000000000000
1196 p2node--verbose: 0000000000000000000000000000000000000000
1198 p2node--verbose: 0000000000000000000000000000000000000000
1197 p2node--verbose: 0000000000000000000000000000000000000000
1199 p2node--verbose: 0000000000000000000000000000000000000000
1198 p2node--verbose: 0000000000000000000000000000000000000000
1200 p2node--verbose: 0000000000000000000000000000000000000000
1199 p2node--verbose: 0000000000000000000000000000000000000000
1201 p2node--verbose: 0000000000000000000000000000000000000000
1200 p2node--verbose: 0000000000000000000000000000000000000000
1202 p2node--verbose: 0000000000000000000000000000000000000000
1201 p2node--debug: 0000000000000000000000000000000000000000
1203 p2node--debug: 0000000000000000000000000000000000000000
1202 p2node--debug: 0000000000000000000000000000000000000000
1204 p2node--debug: 0000000000000000000000000000000000000000
1203 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1205 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1204 p2node--debug: 0000000000000000000000000000000000000000
1206 p2node--debug: 0000000000000000000000000000000000000000
1205 p2node--debug: 0000000000000000000000000000000000000000
1207 p2node--debug: 0000000000000000000000000000000000000000
1206 p2node--debug: 0000000000000000000000000000000000000000
1208 p2node--debug: 0000000000000000000000000000000000000000
1207 p2node--debug: 0000000000000000000000000000000000000000
1209 p2node--debug: 0000000000000000000000000000000000000000
1208 p2node--debug: 0000000000000000000000000000000000000000
1210 p2node--debug: 0000000000000000000000000000000000000000
1209 p2node--debug: 0000000000000000000000000000000000000000
1211 p2node--debug: 0000000000000000000000000000000000000000
1210
1212
1211 Filters work:
1213 Filters work:
1212
1214
1213 $ hg log --template '{author|domain}\n'
1215 $ hg log --template '{author|domain}\n'
1214
1216
1215 hostname
1217 hostname
1216
1218
1217
1219
1218
1220
1219
1221
1220 place
1222 place
1221 place
1223 place
1222 hostname
1224 hostname
1223
1225
1224 $ hg log --template '{author|person}\n'
1226 $ hg log --template '{author|person}\n'
1225 test
1227 test
1226 User Name
1228 User Name
1227 person
1229 person
1228 person
1230 person
1229 person
1231 person
1230 person
1232 person
1231 other
1233 other
1232 A. N. Other
1234 A. N. Other
1233 User Name
1235 User Name
1234
1236
1235 $ hg log --template '{author|user}\n'
1237 $ hg log --template '{author|user}\n'
1236 test
1238 test
1237 user
1239 user
1238 person
1240 person
1239 person
1241 person
1240 person
1242 person
1241 person
1243 person
1242 other
1244 other
1243 other
1245 other
1244 user
1246 user
1245
1247
1246 $ hg log --template '{date|date}\n'
1248 $ hg log --template '{date|date}\n'
1247 Wed Jan 01 10:01:00 2020 +0000
1249 Wed Jan 01 10:01:00 2020 +0000
1248 Mon Jan 12 13:46:40 1970 +0000
1250 Mon Jan 12 13:46:40 1970 +0000
1249 Sun Jan 18 08:40:01 1970 +0000
1251 Sun Jan 18 08:40:01 1970 +0000
1250 Sun Jan 18 08:40:00 1970 +0000
1252 Sun Jan 18 08:40:00 1970 +0000
1251 Sat Jan 17 04:53:20 1970 +0000
1253 Sat Jan 17 04:53:20 1970 +0000
1252 Fri Jan 16 01:06:40 1970 +0000
1254 Fri Jan 16 01:06:40 1970 +0000
1253 Wed Jan 14 21:20:00 1970 +0000
1255 Wed Jan 14 21:20:00 1970 +0000
1254 Tue Jan 13 17:33:20 1970 +0000
1256 Tue Jan 13 17:33:20 1970 +0000
1255 Mon Jan 12 13:46:40 1970 +0000
1257 Mon Jan 12 13:46:40 1970 +0000
1256
1258
1257 $ hg log --template '{date|isodate}\n'
1259 $ hg log --template '{date|isodate}\n'
1258 2020-01-01 10:01 +0000
1260 2020-01-01 10:01 +0000
1259 1970-01-12 13:46 +0000
1261 1970-01-12 13:46 +0000
1260 1970-01-18 08:40 +0000
1262 1970-01-18 08:40 +0000
1261 1970-01-18 08:40 +0000
1263 1970-01-18 08:40 +0000
1262 1970-01-17 04:53 +0000
1264 1970-01-17 04:53 +0000
1263 1970-01-16 01:06 +0000
1265 1970-01-16 01:06 +0000
1264 1970-01-14 21:20 +0000
1266 1970-01-14 21:20 +0000
1265 1970-01-13 17:33 +0000
1267 1970-01-13 17:33 +0000
1266 1970-01-12 13:46 +0000
1268 1970-01-12 13:46 +0000
1267
1269
1268 $ hg log --template '{date|isodatesec}\n'
1270 $ hg log --template '{date|isodatesec}\n'
1269 2020-01-01 10:01:00 +0000
1271 2020-01-01 10:01:00 +0000
1270 1970-01-12 13:46:40 +0000
1272 1970-01-12 13:46:40 +0000
1271 1970-01-18 08:40:01 +0000
1273 1970-01-18 08:40:01 +0000
1272 1970-01-18 08:40:00 +0000
1274 1970-01-18 08:40:00 +0000
1273 1970-01-17 04:53:20 +0000
1275 1970-01-17 04:53:20 +0000
1274 1970-01-16 01:06:40 +0000
1276 1970-01-16 01:06:40 +0000
1275 1970-01-14 21:20:00 +0000
1277 1970-01-14 21:20:00 +0000
1276 1970-01-13 17:33:20 +0000
1278 1970-01-13 17:33:20 +0000
1277 1970-01-12 13:46:40 +0000
1279 1970-01-12 13:46:40 +0000
1278
1280
1279 $ hg log --template '{date|rfc822date}\n'
1281 $ hg log --template '{date|rfc822date}\n'
1280 Wed, 01 Jan 2020 10:01:00 +0000
1282 Wed, 01 Jan 2020 10:01:00 +0000
1281 Mon, 12 Jan 1970 13:46:40 +0000
1283 Mon, 12 Jan 1970 13:46:40 +0000
1282 Sun, 18 Jan 1970 08:40:01 +0000
1284 Sun, 18 Jan 1970 08:40:01 +0000
1283 Sun, 18 Jan 1970 08:40:00 +0000
1285 Sun, 18 Jan 1970 08:40:00 +0000
1284 Sat, 17 Jan 1970 04:53:20 +0000
1286 Sat, 17 Jan 1970 04:53:20 +0000
1285 Fri, 16 Jan 1970 01:06:40 +0000
1287 Fri, 16 Jan 1970 01:06:40 +0000
1286 Wed, 14 Jan 1970 21:20:00 +0000
1288 Wed, 14 Jan 1970 21:20:00 +0000
1287 Tue, 13 Jan 1970 17:33:20 +0000
1289 Tue, 13 Jan 1970 17:33:20 +0000
1288 Mon, 12 Jan 1970 13:46:40 +0000
1290 Mon, 12 Jan 1970 13:46:40 +0000
1289
1291
1290 $ hg log --template '{desc|firstline}\n'
1292 $ hg log --template '{desc|firstline}\n'
1291 third
1293 third
1292 second
1294 second
1293 merge
1295 merge
1294 new head
1296 new head
1295 new branch
1297 new branch
1296 no user, no domain
1298 no user, no domain
1297 no person
1299 no person
1298 other 1
1300 other 1
1299 line 1
1301 line 1
1300
1302
1301 $ hg log --template '{node|short}\n'
1303 $ hg log --template '{node|short}\n'
1302 95c24699272e
1304 95c24699272e
1303 29114dbae42b
1305 29114dbae42b
1304 d41e714fe50d
1306 d41e714fe50d
1305 13207e5a10d9
1307 13207e5a10d9
1306 bbe44766e73d
1308 bbe44766e73d
1307 10e46f2dcbf4
1309 10e46f2dcbf4
1308 97054abb4ab8
1310 97054abb4ab8
1309 b608e9d1a3f0
1311 b608e9d1a3f0
1310 1e4e1b8f71e0
1312 1e4e1b8f71e0
1311
1313
1312 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1314 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1313 <changeset author="test"/>
1315 <changeset author="test"/>
1314 <changeset author="User Name &lt;user@hostname&gt;"/>
1316 <changeset author="User Name &lt;user@hostname&gt;"/>
1315 <changeset author="person"/>
1317 <changeset author="person"/>
1316 <changeset author="person"/>
1318 <changeset author="person"/>
1317 <changeset author="person"/>
1319 <changeset author="person"/>
1318 <changeset author="person"/>
1320 <changeset author="person"/>
1319 <changeset author="other@place"/>
1321 <changeset author="other@place"/>
1320 <changeset author="A. N. Other &lt;other@place&gt;"/>
1322 <changeset author="A. N. Other &lt;other@place&gt;"/>
1321 <changeset author="User Name &lt;user@hostname&gt;"/>
1323 <changeset author="User Name &lt;user@hostname&gt;"/>
1322
1324
1323 $ hg log --template '{rev}: {children}\n'
1325 $ hg log --template '{rev}: {children}\n'
1324 8:
1326 8:
1325 7: 8:95c24699272e
1327 7: 8:95c24699272e
1326 6:
1328 6:
1327 5: 6:d41e714fe50d
1329 5: 6:d41e714fe50d
1328 4: 6:d41e714fe50d
1330 4: 6:d41e714fe50d
1329 3: 4:bbe44766e73d 5:13207e5a10d9
1331 3: 4:bbe44766e73d 5:13207e5a10d9
1330 2: 3:10e46f2dcbf4
1332 2: 3:10e46f2dcbf4
1331 1: 2:97054abb4ab8
1333 1: 2:97054abb4ab8
1332 0: 1:b608e9d1a3f0
1334 0: 1:b608e9d1a3f0
1333
1335
1334 Formatnode filter works:
1336 Formatnode filter works:
1335
1337
1336 $ hg -q log -r 0 --template '{node|formatnode}\n'
1338 $ hg -q log -r 0 --template '{node|formatnode}\n'
1337 1e4e1b8f71e0
1339 1e4e1b8f71e0
1338
1340
1339 $ hg log -r 0 --template '{node|formatnode}\n'
1341 $ hg log -r 0 --template '{node|formatnode}\n'
1340 1e4e1b8f71e0
1342 1e4e1b8f71e0
1341
1343
1342 $ hg -v log -r 0 --template '{node|formatnode}\n'
1344 $ hg -v log -r 0 --template '{node|formatnode}\n'
1343 1e4e1b8f71e0
1345 1e4e1b8f71e0
1344
1346
1345 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1347 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1346 1e4e1b8f71e05681d422154f5421e385fec3454f
1348 1e4e1b8f71e05681d422154f5421e385fec3454f
1347
1349
1348 Age filter:
1350 Age filter:
1349
1351
1350 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1352 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1351
1353
1352 >>> from datetime import datetime, timedelta
1354 >>> from datetime import datetime, timedelta
1353 >>> fp = open('a', 'w')
1355 >>> fp = open('a', 'w')
1354 >>> n = datetime.now() + timedelta(366 * 7)
1356 >>> n = datetime.now() + timedelta(366 * 7)
1355 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1357 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1356 >>> fp.close()
1358 >>> fp.close()
1357 $ hg add a
1359 $ hg add a
1358 $ hg commit -m future -d "`cat a`"
1360 $ hg commit -m future -d "`cat a`"
1359
1361
1360 $ hg log -l1 --template '{date|age}\n'
1362 $ hg log -l1 --template '{date|age}\n'
1361 7 years from now
1363 7 years from now
1362
1364
1363 Error on syntax:
1365 Error on syntax:
1364
1366
1365 $ echo 'x = "f' >> t
1367 $ echo 'x = "f' >> t
1366 $ hg log
1368 $ hg log
1367 abort: t:3: unmatched quotes
1369 abort: t:3: unmatched quotes
1368 [255]
1370 [255]
1369
1371
1370 Behind the scenes, this will throw TypeError
1372 Behind the scenes, this will throw TypeError
1371
1373
1372 $ hg log -l 3 --template '{date|obfuscate}\n'
1374 $ hg log -l 3 --template '{date|obfuscate}\n'
1373 abort: template filter 'obfuscate' is not compatible with keyword 'date'
1375 abort: template filter 'obfuscate' is not compatible with keyword 'date'
1374 [255]
1376 [255]
1375
1377
1376 Behind the scenes, this will throw a ValueError
1378 Behind the scenes, this will throw a ValueError
1377
1379
1378 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
1380 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
1379 abort: template filter 'shortdate' is not compatible with keyword 'desc'
1381 abort: template filter 'shortdate' is not compatible with keyword 'desc'
1380 [255]
1382 [255]
1381
1383
1382 Behind the scenes, this will throw AttributeError
1384 Behind the scenes, this will throw AttributeError
1383
1385
1384 $ hg log -l 3 --template 'line: {date|escape}\n'
1386 $ hg log -l 3 --template 'line: {date|escape}\n'
1385 abort: template filter 'escape' is not compatible with keyword 'date'
1387 abort: template filter 'escape' is not compatible with keyword 'date'
1386 [255]
1388 [255]
1387
1389
1388 Behind the scenes, this will throw ValueError
1390 Behind the scenes, this will throw ValueError
1389
1391
1390 $ hg tip --template '{author|email|date}\n'
1392 $ hg tip --template '{author|email|date}\n'
1391 abort: template filter 'datefilter' is not compatible with keyword 'author'
1393 abort: template filter 'datefilter' is not compatible with keyword 'author'
1392 [255]
1394 [255]
1393
1395
1394 $ cd ..
1396 $ cd ..
1395
1397
1396
1398
1397 latesttag:
1399 latesttag:
1398
1400
1399 $ hg init latesttag
1401 $ hg init latesttag
1400 $ cd latesttag
1402 $ cd latesttag
1401
1403
1402 $ echo a > file
1404 $ echo a > file
1403 $ hg ci -Am a -d '0 0'
1405 $ hg ci -Am a -d '0 0'
1404 adding file
1406 adding file
1405
1407
1406 $ echo b >> file
1408 $ echo b >> file
1407 $ hg ci -m b -d '1 0'
1409 $ hg ci -m b -d '1 0'
1408
1410
1409 $ echo c >> head1
1411 $ echo c >> head1
1410 $ hg ci -Am h1c -d '2 0'
1412 $ hg ci -Am h1c -d '2 0'
1411 adding head1
1413 adding head1
1412
1414
1413 $ hg update -q 1
1415 $ hg update -q 1
1414 $ echo d >> head2
1416 $ echo d >> head2
1415 $ hg ci -Am h2d -d '3 0'
1417 $ hg ci -Am h2d -d '3 0'
1416 adding head2
1418 adding head2
1417 created new head
1419 created new head
1418
1420
1419 $ echo e >> head2
1421 $ echo e >> head2
1420 $ hg ci -m h2e -d '4 0'
1422 $ hg ci -m h2e -d '4 0'
1421
1423
1422 $ hg merge -q
1424 $ hg merge -q
1423 $ hg ci -m merge -d '5 0'
1425 $ hg ci -m merge -d '5 0'
1424
1426
1425 No tag set:
1427 No tag set:
1426
1428
1427 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1429 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1428 5: null+5
1430 5: null+5
1429 4: null+4
1431 4: null+4
1430 3: null+3
1432 3: null+3
1431 2: null+3
1433 2: null+3
1432 1: null+2
1434 1: null+2
1433 0: null+1
1435 0: null+1
1434
1436
1435 One common tag: longuest path wins:
1437 One common tag: longuest path wins:
1436
1438
1437 $ hg tag -r 1 -m t1 -d '6 0' t1
1439 $ hg tag -r 1 -m t1 -d '6 0' t1
1438 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1440 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1439 6: t1+4
1441 6: t1+4
1440 5: t1+3
1442 5: t1+3
1441 4: t1+2
1443 4: t1+2
1442 3: t1+1
1444 3: t1+1
1443 2: t1+1
1445 2: t1+1
1444 1: t1+0
1446 1: t1+0
1445 0: null+1
1447 0: null+1
1446
1448
1447 One ancestor tag: more recent wins:
1449 One ancestor tag: more recent wins:
1448
1450
1449 $ hg tag -r 2 -m t2 -d '7 0' t2
1451 $ hg tag -r 2 -m t2 -d '7 0' t2
1450 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1452 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1451 7: t2+3
1453 7: t2+3
1452 6: t2+2
1454 6: t2+2
1453 5: t2+1
1455 5: t2+1
1454 4: t1+2
1456 4: t1+2
1455 3: t1+1
1457 3: t1+1
1456 2: t2+0
1458 2: t2+0
1457 1: t1+0
1459 1: t1+0
1458 0: null+1
1460 0: null+1
1459
1461
1460 Two branch tags: more recent wins:
1462 Two branch tags: more recent wins:
1461
1463
1462 $ hg tag -r 3 -m t3 -d '8 0' t3
1464 $ hg tag -r 3 -m t3 -d '8 0' t3
1463 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1465 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1464 8: t3+5
1466 8: t3+5
1465 7: t3+4
1467 7: t3+4
1466 6: t3+3
1468 6: t3+3
1467 5: t3+2
1469 5: t3+2
1468 4: t3+1
1470 4: t3+1
1469 3: t3+0
1471 3: t3+0
1470 2: t2+0
1472 2: t2+0
1471 1: t1+0
1473 1: t1+0
1472 0: null+1
1474 0: null+1
1473
1475
1474 Merged tag overrides:
1476 Merged tag overrides:
1475
1477
1476 $ hg tag -r 5 -m t5 -d '9 0' t5
1478 $ hg tag -r 5 -m t5 -d '9 0' t5
1477 $ hg tag -r 3 -m at3 -d '10 0' at3
1479 $ hg tag -r 3 -m at3 -d '10 0' at3
1478 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1480 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1479 10: t5+5
1481 10: t5+5
1480 9: t5+4
1482 9: t5+4
1481 8: t5+3
1483 8: t5+3
1482 7: t5+2
1484 7: t5+2
1483 6: t5+1
1485 6: t5+1
1484 5: t5+0
1486 5: t5+0
1485 4: at3:t3+1
1487 4: at3:t3+1
1486 3: at3:t3+0
1488 3: at3:t3+0
1487 2: t2+0
1489 2: t2+0
1488 1: t1+0
1490 1: t1+0
1489 0: null+1
1491 0: null+1
1490
1492
1491 $ cd ..
1493 $ cd ..
1492
1494
1493
1495
1494 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1496 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1495 if it is a relative path
1497 if it is a relative path
1496
1498
1497 $ mkdir -p home/styles
1499 $ mkdir -p home/styles
1498
1500
1499 $ cat > home/styles/teststyle <<EOF
1501 $ cat > home/styles/teststyle <<EOF
1500 > changeset = 'test {rev}:{node|short}\n'
1502 > changeset = 'test {rev}:{node|short}\n'
1501 > EOF
1503 > EOF
1502
1504
1503 $ HOME=`pwd`/home; export HOME
1505 $ HOME=`pwd`/home; export HOME
1504
1506
1505 $ cat > latesttag/.hg/hgrc <<EOF
1507 $ cat > latesttag/.hg/hgrc <<EOF
1506 > [ui]
1508 > [ui]
1507 > style = ~/styles/teststyle
1509 > style = ~/styles/teststyle
1508 > EOF
1510 > EOF
1509
1511
1510 $ hg -R latesttag tip
1512 $ hg -R latesttag tip
1511 test 10:dee8f28249af
1513 test 10:dee8f28249af
1512
1514
1513 Test recursive showlist template (issue1989):
1515 Test recursive showlist template (issue1989):
1514
1516
1515 $ cat > style1989 <<EOF
1517 $ cat > style1989 <<EOF
1516 > changeset = '{file_mods}{manifest}{extras}'
1518 > changeset = '{file_mods}{manifest}{extras}'
1517 > file_mod = 'M|{author|person}\n'
1519 > file_mod = 'M|{author|person}\n'
1518 > manifest = '{rev},{author}\n'
1520 > manifest = '{rev},{author}\n'
1519 > extra = '{key}: {author}\n'
1521 > extra = '{key}: {author}\n'
1520 > EOF
1522 > EOF
1521
1523
1522 $ hg -R latesttag log -r tip --style=style1989
1524 $ hg -R latesttag log -r tip --style=style1989
1523 M|test
1525 M|test
1524 10,test
1526 10,test
1525 branch: test
1527 branch: test
1526
1528
1527 Test new-style inline templating:
1529 Test new-style inline templating:
1528
1530
1529 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
1531 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
1530 modified files: .hgtags
1532 modified files: .hgtags
1531
1533
General Comments 0
You need to be logged in to leave comments. Login now