##// END OF EJS Templates
templater: abstract truth testing to fix {if(list_of_empty_strings)}...
Yuya Nishihara -
r38308:f9c42638 default
parent child Browse files
Show More
@@ -1,797 +1,800 b''
1 # hgweb/webutil.py - utility library for the web interface.
1 # hgweb/webutil.py - utility library for the web interface.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import copy
11 import copy
12 import difflib
12 import difflib
13 import os
13 import os
14 import re
14 import re
15
15
16 from ..i18n import _
16 from ..i18n import _
17 from ..node import hex, nullid, short
17 from ..node import hex, nullid, short
18
18
19 from .common import (
19 from .common import (
20 ErrorResponse,
20 ErrorResponse,
21 HTTP_BAD_REQUEST,
21 HTTP_BAD_REQUEST,
22 HTTP_NOT_FOUND,
22 HTTP_NOT_FOUND,
23 paritygen,
23 paritygen,
24 )
24 )
25
25
26 from .. import (
26 from .. import (
27 context,
27 context,
28 error,
28 error,
29 match,
29 match,
30 mdiff,
30 mdiff,
31 obsutil,
31 obsutil,
32 patch,
32 patch,
33 pathutil,
33 pathutil,
34 pycompat,
34 pycompat,
35 scmutil,
35 scmutil,
36 templatefilters,
36 templatefilters,
37 templatekw,
37 templatekw,
38 templateutil,
38 templateutil,
39 ui as uimod,
39 ui as uimod,
40 util,
40 util,
41 )
41 )
42
42
43 from ..utils import (
43 from ..utils import (
44 stringutil,
44 stringutil,
45 )
45 )
46
46
47 archivespecs = util.sortdict((
47 archivespecs = util.sortdict((
48 ('zip', ('application/zip', 'zip', '.zip', None)),
48 ('zip', ('application/zip', 'zip', '.zip', None)),
49 ('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)),
49 ('gz', ('application/x-gzip', 'tgz', '.tar.gz', None)),
50 ('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)),
50 ('bz2', ('application/x-bzip2', 'tbz2', '.tar.bz2', None)),
51 ))
51 ))
52
52
53 def archivelist(ui, nodeid, url=None):
53 def archivelist(ui, nodeid, url=None):
54 allowed = ui.configlist('web', 'allow-archive', untrusted=True)
54 allowed = ui.configlist('web', 'allow-archive', untrusted=True)
55 archives = []
55 archives = []
56
56
57 for typ, spec in archivespecs.iteritems():
57 for typ, spec in archivespecs.iteritems():
58 if typ in allowed or ui.configbool('web', 'allow' + typ,
58 if typ in allowed or ui.configbool('web', 'allow' + typ,
59 untrusted=True):
59 untrusted=True):
60 archives.append({
60 archives.append({
61 'type': typ,
61 'type': typ,
62 'extension': spec[2],
62 'extension': spec[2],
63 'node': nodeid,
63 'node': nodeid,
64 'url': url,
64 'url': url,
65 })
65 })
66
66
67 return templateutil.mappinglist(archives)
67 return templateutil.mappinglist(archives)
68
68
69 def up(p):
69 def up(p):
70 if p[0:1] != "/":
70 if p[0:1] != "/":
71 p = "/" + p
71 p = "/" + p
72 if p[-1:] == "/":
72 if p[-1:] == "/":
73 p = p[:-1]
73 p = p[:-1]
74 up = os.path.dirname(p)
74 up = os.path.dirname(p)
75 if up == "/":
75 if up == "/":
76 return "/"
76 return "/"
77 return up + "/"
77 return up + "/"
78
78
79 def _navseq(step, firststep=None):
79 def _navseq(step, firststep=None):
80 if firststep:
80 if firststep:
81 yield firststep
81 yield firststep
82 if firststep >= 20 and firststep <= 40:
82 if firststep >= 20 and firststep <= 40:
83 firststep = 50
83 firststep = 50
84 yield firststep
84 yield firststep
85 assert step > 0
85 assert step > 0
86 assert firststep > 0
86 assert firststep > 0
87 while step <= firststep:
87 while step <= firststep:
88 step *= 10
88 step *= 10
89 while True:
89 while True:
90 yield 1 * step
90 yield 1 * step
91 yield 3 * step
91 yield 3 * step
92 step *= 10
92 step *= 10
93
93
94 class revnav(object):
94 class revnav(object):
95
95
96 def __init__(self, repo):
96 def __init__(self, repo):
97 """Navigation generation object
97 """Navigation generation object
98
98
99 :repo: repo object we generate nav for
99 :repo: repo object we generate nav for
100 """
100 """
101 # used for hex generation
101 # used for hex generation
102 self._revlog = repo.changelog
102 self._revlog = repo.changelog
103
103
104 def __nonzero__(self):
104 def __nonzero__(self):
105 """return True if any revision to navigate over"""
105 """return True if any revision to navigate over"""
106 return self._first() is not None
106 return self._first() is not None
107
107
108 __bool__ = __nonzero__
108 __bool__ = __nonzero__
109
109
110 def _first(self):
110 def _first(self):
111 """return the minimum non-filtered changeset or None"""
111 """return the minimum non-filtered changeset or None"""
112 try:
112 try:
113 return next(iter(self._revlog))
113 return next(iter(self._revlog))
114 except StopIteration:
114 except StopIteration:
115 return None
115 return None
116
116
117 def hex(self, rev):
117 def hex(self, rev):
118 return hex(self._revlog.node(rev))
118 return hex(self._revlog.node(rev))
119
119
120 def gen(self, pos, pagelen, limit):
120 def gen(self, pos, pagelen, limit):
121 """computes label and revision id for navigation link
121 """computes label and revision id for navigation link
122
122
123 :pos: is the revision relative to which we generate navigation.
123 :pos: is the revision relative to which we generate navigation.
124 :pagelen: the size of each navigation page
124 :pagelen: the size of each navigation page
125 :limit: how far shall we link
125 :limit: how far shall we link
126
126
127 The return is:
127 The return is:
128 - a single element mappinglist
128 - a single element mappinglist
129 - containing a dictionary with a `before` and `after` key
129 - containing a dictionary with a `before` and `after` key
130 - values are dictionaries with `label` and `node` keys
130 - values are dictionaries with `label` and `node` keys
131 """
131 """
132 if not self:
132 if not self:
133 # empty repo
133 # empty repo
134 return templateutil.mappinglist([
134 return templateutil.mappinglist([
135 {'before': templateutil.mappinglist([]),
135 {'before': templateutil.mappinglist([]),
136 'after': templateutil.mappinglist([])},
136 'after': templateutil.mappinglist([])},
137 ])
137 ])
138
138
139 targets = []
139 targets = []
140 for f in _navseq(1, pagelen):
140 for f in _navseq(1, pagelen):
141 if f > limit:
141 if f > limit:
142 break
142 break
143 targets.append(pos + f)
143 targets.append(pos + f)
144 targets.append(pos - f)
144 targets.append(pos - f)
145 targets.sort()
145 targets.sort()
146
146
147 first = self._first()
147 first = self._first()
148 navbefore = [{'label': '(%i)' % first, 'node': self.hex(first)}]
148 navbefore = [{'label': '(%i)' % first, 'node': self.hex(first)}]
149 navafter = []
149 navafter = []
150 for rev in targets:
150 for rev in targets:
151 if rev not in self._revlog:
151 if rev not in self._revlog:
152 continue
152 continue
153 if pos < rev < limit:
153 if pos < rev < limit:
154 navafter.append({'label': '+%d' % abs(rev - pos),
154 navafter.append({'label': '+%d' % abs(rev - pos),
155 'node': self.hex(rev)})
155 'node': self.hex(rev)})
156 if 0 < rev < pos:
156 if 0 < rev < pos:
157 navbefore.append({'label': '-%d' % abs(rev - pos),
157 navbefore.append({'label': '-%d' % abs(rev - pos),
158 'node': self.hex(rev)})
158 'node': self.hex(rev)})
159
159
160 navafter.append({'label': 'tip', 'node': 'tip'})
160 navafter.append({'label': 'tip', 'node': 'tip'})
161
161
162 # TODO: maybe this can be a scalar object supporting tomap()
162 # TODO: maybe this can be a scalar object supporting tomap()
163 return templateutil.mappinglist([
163 return templateutil.mappinglist([
164 {'before': templateutil.mappinglist(navbefore),
164 {'before': templateutil.mappinglist(navbefore),
165 'after': templateutil.mappinglist(navafter)},
165 'after': templateutil.mappinglist(navafter)},
166 ])
166 ])
167
167
168 class filerevnav(revnav):
168 class filerevnav(revnav):
169
169
170 def __init__(self, repo, path):
170 def __init__(self, repo, path):
171 """Navigation generation object
171 """Navigation generation object
172
172
173 :repo: repo object we generate nav for
173 :repo: repo object we generate nav for
174 :path: path of the file we generate nav for
174 :path: path of the file we generate nav for
175 """
175 """
176 # used for iteration
176 # used for iteration
177 self._changelog = repo.unfiltered().changelog
177 self._changelog = repo.unfiltered().changelog
178 # used for hex generation
178 # used for hex generation
179 self._revlog = repo.file(path)
179 self._revlog = repo.file(path)
180
180
181 def hex(self, rev):
181 def hex(self, rev):
182 return hex(self._changelog.node(self._revlog.linkrev(rev)))
182 return hex(self._changelog.node(self._revlog.linkrev(rev)))
183
183
184 # TODO: maybe this can be a wrapper class for changectx/filectx list, which
184 # TODO: maybe this can be a wrapper class for changectx/filectx list, which
185 # yields {'ctx': ctx}
185 # yields {'ctx': ctx}
186 def _ctxsgen(context, ctxs):
186 def _ctxsgen(context, ctxs):
187 for s in ctxs:
187 for s in ctxs:
188 d = {
188 d = {
189 'node': s.hex(),
189 'node': s.hex(),
190 'rev': s.rev(),
190 'rev': s.rev(),
191 'user': s.user(),
191 'user': s.user(),
192 'date': s.date(),
192 'date': s.date(),
193 'description': s.description(),
193 'description': s.description(),
194 'branch': s.branch(),
194 'branch': s.branch(),
195 }
195 }
196 if util.safehasattr(s, 'path'):
196 if util.safehasattr(s, 'path'):
197 d['file'] = s.path()
197 d['file'] = s.path()
198 yield d
198 yield d
199
199
200 def _siblings(siblings=None, hiderev=None):
200 def _siblings(siblings=None, hiderev=None):
201 if siblings is None:
201 if siblings is None:
202 siblings = []
202 siblings = []
203 siblings = [s for s in siblings if s.node() != nullid]
203 siblings = [s for s in siblings if s.node() != nullid]
204 if len(siblings) == 1 and siblings[0].rev() == hiderev:
204 if len(siblings) == 1 and siblings[0].rev() == hiderev:
205 siblings = []
205 siblings = []
206 return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
206 return templateutil.mappinggenerator(_ctxsgen, args=(siblings,))
207
207
208 def difffeatureopts(req, ui, section):
208 def difffeatureopts(req, ui, section):
209 diffopts = patch.difffeatureopts(ui, untrusted=True,
209 diffopts = patch.difffeatureopts(ui, untrusted=True,
210 section=section, whitespace=True)
210 section=section, whitespace=True)
211
211
212 for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'):
212 for k in ('ignorews', 'ignorewsamount', 'ignorewseol', 'ignoreblanklines'):
213 v = req.qsparams.get(k)
213 v = req.qsparams.get(k)
214 if v is not None:
214 if v is not None:
215 v = stringutil.parsebool(v)
215 v = stringutil.parsebool(v)
216 setattr(diffopts, k, v if v is not None else True)
216 setattr(diffopts, k, v if v is not None else True)
217
217
218 return diffopts
218 return diffopts
219
219
220 def annotate(req, fctx, ui):
220 def annotate(req, fctx, ui):
221 diffopts = difffeatureopts(req, ui, 'annotate')
221 diffopts = difffeatureopts(req, ui, 'annotate')
222 return fctx.annotate(follow=True, diffopts=diffopts)
222 return fctx.annotate(follow=True, diffopts=diffopts)
223
223
224 def parents(ctx, hide=None):
224 def parents(ctx, hide=None):
225 if isinstance(ctx, context.basefilectx):
225 if isinstance(ctx, context.basefilectx):
226 introrev = ctx.introrev()
226 introrev = ctx.introrev()
227 if ctx.changectx().rev() != introrev:
227 if ctx.changectx().rev() != introrev:
228 return _siblings([ctx.repo()[introrev]], hide)
228 return _siblings([ctx.repo()[introrev]], hide)
229 return _siblings(ctx.parents(), hide)
229 return _siblings(ctx.parents(), hide)
230
230
231 def children(ctx, hide=None):
231 def children(ctx, hide=None):
232 return _siblings(ctx.children(), hide)
232 return _siblings(ctx.children(), hide)
233
233
234 def renamelink(fctx):
234 def renamelink(fctx):
235 r = fctx.renamed()
235 r = fctx.renamed()
236 if r:
236 if r:
237 return templateutil.mappinglist([{'file': r[0], 'node': hex(r[1])}])
237 return templateutil.mappinglist([{'file': r[0], 'node': hex(r[1])}])
238 return templateutil.mappinglist([])
238 return templateutil.mappinglist([])
239
239
240 def nodetagsdict(repo, node):
240 def nodetagsdict(repo, node):
241 return templateutil.hybridlist(repo.nodetags(node), name='name')
241 return templateutil.hybridlist(repo.nodetags(node), name='name')
242
242
243 def nodebookmarksdict(repo, node):
243 def nodebookmarksdict(repo, node):
244 return templateutil.hybridlist(repo.nodebookmarks(node), name='name')
244 return templateutil.hybridlist(repo.nodebookmarks(node), name='name')
245
245
246 def nodebranchdict(repo, ctx):
246 def nodebranchdict(repo, ctx):
247 branches = []
247 branches = []
248 branch = ctx.branch()
248 branch = ctx.branch()
249 # If this is an empty repo, ctx.node() == nullid,
249 # If this is an empty repo, ctx.node() == nullid,
250 # ctx.branch() == 'default'.
250 # ctx.branch() == 'default'.
251 try:
251 try:
252 branchnode = repo.branchtip(branch)
252 branchnode = repo.branchtip(branch)
253 except error.RepoLookupError:
253 except error.RepoLookupError:
254 branchnode = None
254 branchnode = None
255 if branchnode == ctx.node():
255 if branchnode == ctx.node():
256 branches.append(branch)
256 branches.append(branch)
257 return templateutil.hybridlist(branches, name='name')
257 return templateutil.hybridlist(branches, name='name')
258
258
259 def nodeinbranch(repo, ctx):
259 def nodeinbranch(repo, ctx):
260 branches = []
260 branches = []
261 branch = ctx.branch()
261 branch = ctx.branch()
262 try:
262 try:
263 branchnode = repo.branchtip(branch)
263 branchnode = repo.branchtip(branch)
264 except error.RepoLookupError:
264 except error.RepoLookupError:
265 branchnode = None
265 branchnode = None
266 if branch != 'default' and branchnode != ctx.node():
266 if branch != 'default' and branchnode != ctx.node():
267 branches.append(branch)
267 branches.append(branch)
268 return templateutil.hybridlist(branches, name='name')
268 return templateutil.hybridlist(branches, name='name')
269
269
270 def nodebranchnodefault(ctx):
270 def nodebranchnodefault(ctx):
271 branches = []
271 branches = []
272 branch = ctx.branch()
272 branch = ctx.branch()
273 if branch != 'default':
273 if branch != 'default':
274 branches.append(branch)
274 branches.append(branch)
275 return templateutil.hybridlist(branches, name='name')
275 return templateutil.hybridlist(branches, name='name')
276
276
277 def _nodenamesgen(context, f, node, name):
277 def _nodenamesgen(context, f, node, name):
278 for t in f(node):
278 for t in f(node):
279 yield {name: t}
279 yield {name: t}
280
280
281 def showtag(repo, t1, node=nullid):
281 def showtag(repo, t1, node=nullid):
282 args = (repo.nodetags, node, 'tag')
282 args = (repo.nodetags, node, 'tag')
283 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
283 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
284
284
285 def showbookmark(repo, t1, node=nullid):
285 def showbookmark(repo, t1, node=nullid):
286 args = (repo.nodebookmarks, node, 'bookmark')
286 args = (repo.nodebookmarks, node, 'bookmark')
287 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
287 return templateutil.mappinggenerator(_nodenamesgen, args=args, name=t1)
288
288
289 def branchentries(repo, stripecount, limit=0):
289 def branchentries(repo, stripecount, limit=0):
290 tips = []
290 tips = []
291 heads = repo.heads()
291 heads = repo.heads()
292 parity = paritygen(stripecount)
292 parity = paritygen(stripecount)
293 sortkey = lambda item: (not item[1], item[0].rev())
293 sortkey = lambda item: (not item[1], item[0].rev())
294
294
295 def entries(context):
295 def entries(context):
296 count = 0
296 count = 0
297 if not tips:
297 if not tips:
298 for tag, hs, tip, closed in repo.branchmap().iterbranches():
298 for tag, hs, tip, closed in repo.branchmap().iterbranches():
299 tips.append((repo[tip], closed))
299 tips.append((repo[tip], closed))
300 for ctx, closed in sorted(tips, key=sortkey, reverse=True):
300 for ctx, closed in sorted(tips, key=sortkey, reverse=True):
301 if limit > 0 and count >= limit:
301 if limit > 0 and count >= limit:
302 return
302 return
303 count += 1
303 count += 1
304 if closed:
304 if closed:
305 status = 'closed'
305 status = 'closed'
306 elif ctx.node() not in heads:
306 elif ctx.node() not in heads:
307 status = 'inactive'
307 status = 'inactive'
308 else:
308 else:
309 status = 'open'
309 status = 'open'
310 yield {
310 yield {
311 'parity': next(parity),
311 'parity': next(parity),
312 'branch': ctx.branch(),
312 'branch': ctx.branch(),
313 'status': status,
313 'status': status,
314 'node': ctx.hex(),
314 'node': ctx.hex(),
315 'date': ctx.date()
315 'date': ctx.date()
316 }
316 }
317
317
318 return templateutil.mappinggenerator(entries)
318 return templateutil.mappinggenerator(entries)
319
319
320 def cleanpath(repo, path):
320 def cleanpath(repo, path):
321 path = path.lstrip('/')
321 path = path.lstrip('/')
322 return pathutil.canonpath(repo.root, '', path)
322 return pathutil.canonpath(repo.root, '', path)
323
323
324 def changectx(repo, req):
324 def changectx(repo, req):
325 changeid = "tip"
325 changeid = "tip"
326 if 'node' in req.qsparams:
326 if 'node' in req.qsparams:
327 changeid = req.qsparams['node']
327 changeid = req.qsparams['node']
328 ipos = changeid.find(':')
328 ipos = changeid.find(':')
329 if ipos != -1:
329 if ipos != -1:
330 changeid = changeid[(ipos + 1):]
330 changeid = changeid[(ipos + 1):]
331
331
332 return scmutil.revsymbol(repo, changeid)
332 return scmutil.revsymbol(repo, changeid)
333
333
334 def basechangectx(repo, req):
334 def basechangectx(repo, req):
335 if 'node' in req.qsparams:
335 if 'node' in req.qsparams:
336 changeid = req.qsparams['node']
336 changeid = req.qsparams['node']
337 ipos = changeid.find(':')
337 ipos = changeid.find(':')
338 if ipos != -1:
338 if ipos != -1:
339 changeid = changeid[:ipos]
339 changeid = changeid[:ipos]
340 return scmutil.revsymbol(repo, changeid)
340 return scmutil.revsymbol(repo, changeid)
341
341
342 return None
342 return None
343
343
344 def filectx(repo, req):
344 def filectx(repo, req):
345 if 'file' not in req.qsparams:
345 if 'file' not in req.qsparams:
346 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
346 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
347 path = cleanpath(repo, req.qsparams['file'])
347 path = cleanpath(repo, req.qsparams['file'])
348 if 'node' in req.qsparams:
348 if 'node' in req.qsparams:
349 changeid = req.qsparams['node']
349 changeid = req.qsparams['node']
350 elif 'filenode' in req.qsparams:
350 elif 'filenode' in req.qsparams:
351 changeid = req.qsparams['filenode']
351 changeid = req.qsparams['filenode']
352 else:
352 else:
353 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
353 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
354 try:
354 try:
355 fctx = scmutil.revsymbol(repo, changeid)[path]
355 fctx = scmutil.revsymbol(repo, changeid)[path]
356 except error.RepoError:
356 except error.RepoError:
357 fctx = repo.filectx(path, fileid=changeid)
357 fctx = repo.filectx(path, fileid=changeid)
358
358
359 return fctx
359 return fctx
360
360
361 def linerange(req):
361 def linerange(req):
362 linerange = req.qsparams.getall('linerange')
362 linerange = req.qsparams.getall('linerange')
363 if not linerange:
363 if not linerange:
364 return None
364 return None
365 if len(linerange) > 1:
365 if len(linerange) > 1:
366 raise ErrorResponse(HTTP_BAD_REQUEST,
366 raise ErrorResponse(HTTP_BAD_REQUEST,
367 'redundant linerange parameter')
367 'redundant linerange parameter')
368 try:
368 try:
369 fromline, toline = map(int, linerange[0].split(':', 1))
369 fromline, toline = map(int, linerange[0].split(':', 1))
370 except ValueError:
370 except ValueError:
371 raise ErrorResponse(HTTP_BAD_REQUEST,
371 raise ErrorResponse(HTTP_BAD_REQUEST,
372 'invalid linerange parameter')
372 'invalid linerange parameter')
373 try:
373 try:
374 return util.processlinerange(fromline, toline)
374 return util.processlinerange(fromline, toline)
375 except error.ParseError as exc:
375 except error.ParseError as exc:
376 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc))
376 raise ErrorResponse(HTTP_BAD_REQUEST, pycompat.bytestr(exc))
377
377
378 def formatlinerange(fromline, toline):
378 def formatlinerange(fromline, toline):
379 return '%d:%d' % (fromline + 1, toline)
379 return '%d:%d' % (fromline + 1, toline)
380
380
381 def _succsandmarkersgen(context, mapping):
381 def _succsandmarkersgen(context, mapping):
382 repo = context.resource(mapping, 'repo')
382 repo = context.resource(mapping, 'repo')
383 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
383 itemmappings = templatekw.showsuccsandmarkers(context, mapping)
384 for item in itemmappings.tovalue(context, mapping):
384 for item in itemmappings.tovalue(context, mapping):
385 item['successors'] = _siblings(repo[successor]
385 item['successors'] = _siblings(repo[successor]
386 for successor in item['successors'])
386 for successor in item['successors'])
387 yield item
387 yield item
388
388
389 def succsandmarkers(context, mapping):
389 def succsandmarkers(context, mapping):
390 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
390 return templateutil.mappinggenerator(_succsandmarkersgen, args=(mapping,))
391
391
392 # teach templater succsandmarkers is switched to (context, mapping) API
392 # teach templater succsandmarkers is switched to (context, mapping) API
393 succsandmarkers._requires = {'repo', 'ctx'}
393 succsandmarkers._requires = {'repo', 'ctx'}
394
394
395 def _whyunstablegen(context, mapping):
395 def _whyunstablegen(context, mapping):
396 repo = context.resource(mapping, 'repo')
396 repo = context.resource(mapping, 'repo')
397 ctx = context.resource(mapping, 'ctx')
397 ctx = context.resource(mapping, 'ctx')
398
398
399 entries = obsutil.whyunstable(repo, ctx)
399 entries = obsutil.whyunstable(repo, ctx)
400 for entry in entries:
400 for entry in entries:
401 if entry.get('divergentnodes'):
401 if entry.get('divergentnodes'):
402 entry['divergentnodes'] = _siblings(entry['divergentnodes'])
402 entry['divergentnodes'] = _siblings(entry['divergentnodes'])
403 yield entry
403 yield entry
404
404
405 def whyunstable(context, mapping):
405 def whyunstable(context, mapping):
406 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
406 return templateutil.mappinggenerator(_whyunstablegen, args=(mapping,))
407
407
408 whyunstable._requires = {'repo', 'ctx'}
408 whyunstable._requires = {'repo', 'ctx'}
409
409
410 def commonentry(repo, ctx):
410 def commonentry(repo, ctx):
411 node = ctx.node()
411 node = ctx.node()
412 return {
412 return {
413 # TODO: perhaps ctx.changectx() should be assigned if ctx is a
413 # TODO: perhaps ctx.changectx() should be assigned if ctx is a
414 # filectx, but I'm not pretty sure if that would always work because
414 # filectx, but I'm not pretty sure if that would always work because
415 # fctx.parents() != fctx.changectx.parents() for example.
415 # fctx.parents() != fctx.changectx.parents() for example.
416 'ctx': ctx,
416 'ctx': ctx,
417 'rev': ctx.rev(),
417 'rev': ctx.rev(),
418 'node': hex(node),
418 'node': hex(node),
419 'author': ctx.user(),
419 'author': ctx.user(),
420 'desc': ctx.description(),
420 'desc': ctx.description(),
421 'date': ctx.date(),
421 'date': ctx.date(),
422 'extra': ctx.extra(),
422 'extra': ctx.extra(),
423 'phase': ctx.phasestr(),
423 'phase': ctx.phasestr(),
424 'obsolete': ctx.obsolete(),
424 'obsolete': ctx.obsolete(),
425 'succsandmarkers': succsandmarkers,
425 'succsandmarkers': succsandmarkers,
426 'instabilities': templateutil.hybridlist(ctx.instabilities(),
426 'instabilities': templateutil.hybridlist(ctx.instabilities(),
427 name='instability'),
427 name='instability'),
428 'whyunstable': whyunstable,
428 'whyunstable': whyunstable,
429 'branch': nodebranchnodefault(ctx),
429 'branch': nodebranchnodefault(ctx),
430 'inbranch': nodeinbranch(repo, ctx),
430 'inbranch': nodeinbranch(repo, ctx),
431 'branches': nodebranchdict(repo, ctx),
431 'branches': nodebranchdict(repo, ctx),
432 'tags': nodetagsdict(repo, node),
432 'tags': nodetagsdict(repo, node),
433 'bookmarks': nodebookmarksdict(repo, node),
433 'bookmarks': nodebookmarksdict(repo, node),
434 'parent': lambda **x: parents(ctx),
434 'parent': lambda **x: parents(ctx),
435 'child': lambda **x: children(ctx),
435 'child': lambda **x: children(ctx),
436 }
436 }
437
437
438 def changelistentry(web, ctx):
438 def changelistentry(web, ctx):
439 '''Obtain a dictionary to be used for entries in a changelist.
439 '''Obtain a dictionary to be used for entries in a changelist.
440
440
441 This function is called when producing items for the "entries" list passed
441 This function is called when producing items for the "entries" list passed
442 to the "shortlog" and "changelog" templates.
442 to the "shortlog" and "changelog" templates.
443 '''
443 '''
444 repo = web.repo
444 repo = web.repo
445 rev = ctx.rev()
445 rev = ctx.rev()
446 n = ctx.node()
446 n = ctx.node()
447 showtags = showtag(repo, 'changelogtag', n)
447 showtags = showtag(repo, 'changelogtag', n)
448 files = listfilediffs(ctx.files(), n, web.maxfiles)
448 files = listfilediffs(ctx.files(), n, web.maxfiles)
449
449
450 entry = commonentry(repo, ctx)
450 entry = commonentry(repo, ctx)
451 entry.update(
451 entry.update(
452 allparents=lambda **x: parents(ctx),
452 allparents=lambda **x: parents(ctx),
453 parent=lambda **x: parents(ctx, rev - 1),
453 parent=lambda **x: parents(ctx, rev - 1),
454 child=lambda **x: children(ctx, rev + 1),
454 child=lambda **x: children(ctx, rev + 1),
455 changelogtag=showtags,
455 changelogtag=showtags,
456 files=files,
456 files=files,
457 )
457 )
458 return entry
458 return entry
459
459
460 def changelistentries(web, revs, maxcount, parityfn):
460 def changelistentries(web, revs, maxcount, parityfn):
461 """Emit up to N records for an iterable of revisions."""
461 """Emit up to N records for an iterable of revisions."""
462 repo = web.repo
462 repo = web.repo
463
463
464 count = 0
464 count = 0
465 for rev in revs:
465 for rev in revs:
466 if count >= maxcount:
466 if count >= maxcount:
467 break
467 break
468
468
469 count += 1
469 count += 1
470
470
471 entry = changelistentry(web, repo[rev])
471 entry = changelistentry(web, repo[rev])
472 entry['parity'] = next(parityfn)
472 entry['parity'] = next(parityfn)
473
473
474 yield entry
474 yield entry
475
475
476 def symrevorshortnode(req, ctx):
476 def symrevorshortnode(req, ctx):
477 if 'node' in req.qsparams:
477 if 'node' in req.qsparams:
478 return templatefilters.revescape(req.qsparams['node'])
478 return templatefilters.revescape(req.qsparams['node'])
479 else:
479 else:
480 return short(ctx.node())
480 return short(ctx.node())
481
481
482 def _listfilesgen(context, ctx, stripecount):
482 def _listfilesgen(context, ctx, stripecount):
483 parity = paritygen(stripecount)
483 parity = paritygen(stripecount)
484 for blockno, f in enumerate(ctx.files()):
484 for blockno, f in enumerate(ctx.files()):
485 template = 'filenodelink' if f in ctx else 'filenolink'
485 template = 'filenodelink' if f in ctx else 'filenolink'
486 yield context.process(template, {
486 yield context.process(template, {
487 'node': ctx.hex(),
487 'node': ctx.hex(),
488 'file': f,
488 'file': f,
489 'blockno': blockno + 1,
489 'blockno': blockno + 1,
490 'parity': next(parity),
490 'parity': next(parity),
491 })
491 })
492
492
493 def changesetentry(web, ctx):
493 def changesetentry(web, ctx):
494 '''Obtain a dictionary to be used to render the "changeset" template.'''
494 '''Obtain a dictionary to be used to render the "changeset" template.'''
495
495
496 showtags = showtag(web.repo, 'changesettag', ctx.node())
496 showtags = showtag(web.repo, 'changesettag', ctx.node())
497 showbookmarks = showbookmark(web.repo, 'changesetbookmark', ctx.node())
497 showbookmarks = showbookmark(web.repo, 'changesetbookmark', ctx.node())
498 showbranch = nodebranchnodefault(ctx)
498 showbranch = nodebranchnodefault(ctx)
499
499
500 basectx = basechangectx(web.repo, web.req)
500 basectx = basechangectx(web.repo, web.req)
501 if basectx is None:
501 if basectx is None:
502 basectx = ctx.p1()
502 basectx = ctx.p1()
503
503
504 style = web.config('web', 'style')
504 style = web.config('web', 'style')
505 if 'style' in web.req.qsparams:
505 if 'style' in web.req.qsparams:
506 style = web.req.qsparams['style']
506 style = web.req.qsparams['style']
507
507
508 diff = diffs(web, ctx, basectx, None, style)
508 diff = diffs(web, ctx, basectx, None, style)
509
509
510 parity = paritygen(web.stripecount)
510 parity = paritygen(web.stripecount)
511 diffstatsgen = diffstatgen(ctx, basectx)
511 diffstatsgen = diffstatgen(ctx, basectx)
512 diffstats = diffstat(ctx, diffstatsgen, parity)
512 diffstats = diffstat(ctx, diffstatsgen, parity)
513
513
514 return dict(
514 return dict(
515 diff=diff,
515 diff=diff,
516 symrev=symrevorshortnode(web.req, ctx),
516 symrev=symrevorshortnode(web.req, ctx),
517 basenode=basectx.hex(),
517 basenode=basectx.hex(),
518 changesettag=showtags,
518 changesettag=showtags,
519 changesetbookmark=showbookmarks,
519 changesetbookmark=showbookmarks,
520 changesetbranch=showbranch,
520 changesetbranch=showbranch,
521 files=templateutil.mappedgenerator(_listfilesgen,
521 files=templateutil.mappedgenerator(_listfilesgen,
522 args=(ctx, web.stripecount)),
522 args=(ctx, web.stripecount)),
523 diffsummary=lambda **x: diffsummary(diffstatsgen),
523 diffsummary=lambda **x: diffsummary(diffstatsgen),
524 diffstat=diffstats,
524 diffstat=diffstats,
525 archives=web.archivelist(ctx.hex()),
525 archives=web.archivelist(ctx.hex()),
526 **pycompat.strkwargs(commonentry(web.repo, ctx)))
526 **pycompat.strkwargs(commonentry(web.repo, ctx)))
527
527
528 def _listfilediffsgen(context, files, node, max):
528 def _listfilediffsgen(context, files, node, max):
529 for f in files[:max]:
529 for f in files[:max]:
530 yield context.process('filedifflink', {'node': hex(node), 'file': f})
530 yield context.process('filedifflink', {'node': hex(node), 'file': f})
531 if len(files) > max:
531 if len(files) > max:
532 yield context.process('fileellipses', {})
532 yield context.process('fileellipses', {})
533
533
534 def listfilediffs(files, node, max):
534 def listfilediffs(files, node, max):
535 return templateutil.mappedgenerator(_listfilediffsgen,
535 return templateutil.mappedgenerator(_listfilediffsgen,
536 args=(files, node, max))
536 args=(files, node, max))
537
537
538 def _prettyprintdifflines(context, lines, blockno, lineidprefix):
538 def _prettyprintdifflines(context, lines, blockno, lineidprefix):
539 for lineno, l in enumerate(lines, 1):
539 for lineno, l in enumerate(lines, 1):
540 difflineno = "%d.%d" % (blockno, lineno)
540 difflineno = "%d.%d" % (blockno, lineno)
541 if l.startswith('+'):
541 if l.startswith('+'):
542 ltype = "difflineplus"
542 ltype = "difflineplus"
543 elif l.startswith('-'):
543 elif l.startswith('-'):
544 ltype = "difflineminus"
544 ltype = "difflineminus"
545 elif l.startswith('@'):
545 elif l.startswith('@'):
546 ltype = "difflineat"
546 ltype = "difflineat"
547 else:
547 else:
548 ltype = "diffline"
548 ltype = "diffline"
549 yield context.process(ltype, {
549 yield context.process(ltype, {
550 'line': l,
550 'line': l,
551 'lineno': lineno,
551 'lineno': lineno,
552 'lineid': lineidprefix + "l%s" % difflineno,
552 'lineid': lineidprefix + "l%s" % difflineno,
553 'linenumber': "% 8s" % difflineno,
553 'linenumber': "% 8s" % difflineno,
554 })
554 })
555
555
556 def _diffsgen(context, repo, ctx, basectx, files, style, stripecount,
556 def _diffsgen(context, repo, ctx, basectx, files, style, stripecount,
557 linerange, lineidprefix):
557 linerange, lineidprefix):
558 if files:
558 if files:
559 m = match.exact(repo.root, repo.getcwd(), files)
559 m = match.exact(repo.root, repo.getcwd(), files)
560 else:
560 else:
561 m = match.always(repo.root, repo.getcwd())
561 m = match.always(repo.root, repo.getcwd())
562
562
563 diffopts = patch.diffopts(repo.ui, untrusted=True)
563 diffopts = patch.diffopts(repo.ui, untrusted=True)
564 node1 = basectx.node()
564 node1 = basectx.node()
565 node2 = ctx.node()
565 node2 = ctx.node()
566 parity = paritygen(stripecount)
566 parity = paritygen(stripecount)
567
567
568 diffhunks = patch.diffhunks(repo, node1, node2, m, opts=diffopts)
568 diffhunks = patch.diffhunks(repo, node1, node2, m, opts=diffopts)
569 for blockno, (fctx1, fctx2, header, hunks) in enumerate(diffhunks, 1):
569 for blockno, (fctx1, fctx2, header, hunks) in enumerate(diffhunks, 1):
570 if style != 'raw':
570 if style != 'raw':
571 header = header[1:]
571 header = header[1:]
572 lines = [h + '\n' for h in header]
572 lines = [h + '\n' for h in header]
573 for hunkrange, hunklines in hunks:
573 for hunkrange, hunklines in hunks:
574 if linerange is not None and hunkrange is not None:
574 if linerange is not None and hunkrange is not None:
575 s1, l1, s2, l2 = hunkrange
575 s1, l1, s2, l2 = hunkrange
576 if not mdiff.hunkinrange((s2, l2), linerange):
576 if not mdiff.hunkinrange((s2, l2), linerange):
577 continue
577 continue
578 lines.extend(hunklines)
578 lines.extend(hunklines)
579 if lines:
579 if lines:
580 l = templateutil.mappedgenerator(_prettyprintdifflines,
580 l = templateutil.mappedgenerator(_prettyprintdifflines,
581 args=(lines, blockno,
581 args=(lines, blockno,
582 lineidprefix))
582 lineidprefix))
583 yield {
583 yield {
584 'parity': next(parity),
584 'parity': next(parity),
585 'blockno': blockno,
585 'blockno': blockno,
586 'lines': l,
586 'lines': l,
587 }
587 }
588
588
589 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=''):
589 def diffs(web, ctx, basectx, files, style, linerange=None, lineidprefix=''):
590 args = (web.repo, ctx, basectx, files, style, web.stripecount,
590 args = (web.repo, ctx, basectx, files, style, web.stripecount,
591 linerange, lineidprefix)
591 linerange, lineidprefix)
592 return templateutil.mappinggenerator(_diffsgen, args=args, name='diffblock')
592 return templateutil.mappinggenerator(_diffsgen, args=args, name='diffblock')
593
593
594 def _compline(type, leftlineno, leftline, rightlineno, rightline):
594 def _compline(type, leftlineno, leftline, rightlineno, rightline):
595 lineid = leftlineno and ("l%d" % leftlineno) or ''
595 lineid = leftlineno and ("l%d" % leftlineno) or ''
596 lineid += rightlineno and ("r%d" % rightlineno) or ''
596 lineid += rightlineno and ("r%d" % rightlineno) or ''
597 llno = '%d' % leftlineno if leftlineno else ''
597 llno = '%d' % leftlineno if leftlineno else ''
598 rlno = '%d' % rightlineno if rightlineno else ''
598 rlno = '%d' % rightlineno if rightlineno else ''
599 return {
599 return {
600 'type': type,
600 'type': type,
601 'lineid': lineid,
601 'lineid': lineid,
602 'leftlineno': leftlineno,
602 'leftlineno': leftlineno,
603 'leftlinenumber': "% 6s" % llno,
603 'leftlinenumber': "% 6s" % llno,
604 'leftline': leftline or '',
604 'leftline': leftline or '',
605 'rightlineno': rightlineno,
605 'rightlineno': rightlineno,
606 'rightlinenumber': "% 6s" % rlno,
606 'rightlinenumber': "% 6s" % rlno,
607 'rightline': rightline or '',
607 'rightline': rightline or '',
608 }
608 }
609
609
610 def _getcompblockgen(context, leftlines, rightlines, opcodes):
610 def _getcompblockgen(context, leftlines, rightlines, opcodes):
611 for type, llo, lhi, rlo, rhi in opcodes:
611 for type, llo, lhi, rlo, rhi in opcodes:
612 len1 = lhi - llo
612 len1 = lhi - llo
613 len2 = rhi - rlo
613 len2 = rhi - rlo
614 count = min(len1, len2)
614 count = min(len1, len2)
615 for i in xrange(count):
615 for i in xrange(count):
616 yield _compline(type=type,
616 yield _compline(type=type,
617 leftlineno=llo + i + 1,
617 leftlineno=llo + i + 1,
618 leftline=leftlines[llo + i],
618 leftline=leftlines[llo + i],
619 rightlineno=rlo + i + 1,
619 rightlineno=rlo + i + 1,
620 rightline=rightlines[rlo + i])
620 rightline=rightlines[rlo + i])
621 if len1 > len2:
621 if len1 > len2:
622 for i in xrange(llo + count, lhi):
622 for i in xrange(llo + count, lhi):
623 yield _compline(type=type,
623 yield _compline(type=type,
624 leftlineno=i + 1,
624 leftlineno=i + 1,
625 leftline=leftlines[i],
625 leftline=leftlines[i],
626 rightlineno=None,
626 rightlineno=None,
627 rightline=None)
627 rightline=None)
628 elif len2 > len1:
628 elif len2 > len1:
629 for i in xrange(rlo + count, rhi):
629 for i in xrange(rlo + count, rhi):
630 yield _compline(type=type,
630 yield _compline(type=type,
631 leftlineno=None,
631 leftlineno=None,
632 leftline=None,
632 leftline=None,
633 rightlineno=i + 1,
633 rightlineno=i + 1,
634 rightline=rightlines[i])
634 rightline=rightlines[i])
635
635
636 def _getcompblock(leftlines, rightlines, opcodes):
636 def _getcompblock(leftlines, rightlines, opcodes):
637 args = (leftlines, rightlines, opcodes)
637 args = (leftlines, rightlines, opcodes)
638 return templateutil.mappinggenerator(_getcompblockgen, args=args,
638 return templateutil.mappinggenerator(_getcompblockgen, args=args,
639 name='comparisonline')
639 name='comparisonline')
640
640
641 def _comparegen(context, contextnum, leftlines, rightlines):
641 def _comparegen(context, contextnum, leftlines, rightlines):
642 '''Generator function that provides side-by-side comparison data.'''
642 '''Generator function that provides side-by-side comparison data.'''
643 s = difflib.SequenceMatcher(None, leftlines, rightlines)
643 s = difflib.SequenceMatcher(None, leftlines, rightlines)
644 if contextnum < 0:
644 if contextnum < 0:
645 l = _getcompblock(leftlines, rightlines, s.get_opcodes())
645 l = _getcompblock(leftlines, rightlines, s.get_opcodes())
646 yield {'lines': l}
646 yield {'lines': l}
647 else:
647 else:
648 for oc in s.get_grouped_opcodes(n=contextnum):
648 for oc in s.get_grouped_opcodes(n=contextnum):
649 l = _getcompblock(leftlines, rightlines, oc)
649 l = _getcompblock(leftlines, rightlines, oc)
650 yield {'lines': l}
650 yield {'lines': l}
651
651
652 def compare(contextnum, leftlines, rightlines):
652 def compare(contextnum, leftlines, rightlines):
653 args = (contextnum, leftlines, rightlines)
653 args = (contextnum, leftlines, rightlines)
654 return templateutil.mappinggenerator(_comparegen, args=args,
654 return templateutil.mappinggenerator(_comparegen, args=args,
655 name='comparisonblock')
655 name='comparisonblock')
656
656
657 def diffstatgen(ctx, basectx):
657 def diffstatgen(ctx, basectx):
658 '''Generator function that provides the diffstat data.'''
658 '''Generator function that provides the diffstat data.'''
659
659
660 stats = patch.diffstatdata(
660 stats = patch.diffstatdata(
661 util.iterlines(ctx.diff(basectx, noprefix=False)))
661 util.iterlines(ctx.diff(basectx, noprefix=False)))
662 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
662 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
663 while True:
663 while True:
664 yield stats, maxname, maxtotal, addtotal, removetotal, binary
664 yield stats, maxname, maxtotal, addtotal, removetotal, binary
665
665
666 def diffsummary(statgen):
666 def diffsummary(statgen):
667 '''Return a short summary of the diff.'''
667 '''Return a short summary of the diff.'''
668
668
669 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
669 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
670 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
670 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
671 len(stats), addtotal, removetotal)
671 len(stats), addtotal, removetotal)
672
672
673 def _diffstattmplgen(context, ctx, statgen, parity):
673 def _diffstattmplgen(context, ctx, statgen, parity):
674 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
674 stats, maxname, maxtotal, addtotal, removetotal, binary = next(statgen)
675 files = ctx.files()
675 files = ctx.files()
676
676
677 def pct(i):
677 def pct(i):
678 if maxtotal == 0:
678 if maxtotal == 0:
679 return 0
679 return 0
680 return (float(i) / maxtotal) * 100
680 return (float(i) / maxtotal) * 100
681
681
682 fileno = 0
682 fileno = 0
683 for filename, adds, removes, isbinary in stats:
683 for filename, adds, removes, isbinary in stats:
684 template = 'diffstatlink' if filename in files else 'diffstatnolink'
684 template = 'diffstatlink' if filename in files else 'diffstatnolink'
685 total = adds + removes
685 total = adds + removes
686 fileno += 1
686 fileno += 1
687 yield context.process(template, {
687 yield context.process(template, {
688 'node': ctx.hex(),
688 'node': ctx.hex(),
689 'file': filename,
689 'file': filename,
690 'fileno': fileno,
690 'fileno': fileno,
691 'total': total,
691 'total': total,
692 'addpct': pct(adds),
692 'addpct': pct(adds),
693 'removepct': pct(removes),
693 'removepct': pct(removes),
694 'parity': next(parity),
694 'parity': next(parity),
695 })
695 })
696
696
697 def diffstat(ctx, statgen, parity):
697 def diffstat(ctx, statgen, parity):
698 '''Return a diffstat template for each file in the diff.'''
698 '''Return a diffstat template for each file in the diff.'''
699 args = (ctx, statgen, parity)
699 args = (ctx, statgen, parity)
700 return templateutil.mappedgenerator(_diffstattmplgen, args=args)
700 return templateutil.mappedgenerator(_diffstattmplgen, args=args)
701
701
702 class sessionvars(templateutil.wrapped):
702 class sessionvars(templateutil.wrapped):
703 def __init__(self, vars, start='?'):
703 def __init__(self, vars, start='?'):
704 self._start = start
704 self._start = start
705 self._vars = vars
705 self._vars = vars
706
706
707 def __getitem__(self, key):
707 def __getitem__(self, key):
708 return self._vars[key]
708 return self._vars[key]
709
709
710 def __setitem__(self, key, value):
710 def __setitem__(self, key, value):
711 self._vars[key] = value
711 self._vars[key] = value
712
712
713 def __copy__(self):
713 def __copy__(self):
714 return sessionvars(copy.copy(self._vars), self._start)
714 return sessionvars(copy.copy(self._vars), self._start)
715
715
716 def contains(self, context, mapping, item):
716 def contains(self, context, mapping, item):
717 item = templateutil.unwrapvalue(context, mapping, item)
717 item = templateutil.unwrapvalue(context, mapping, item)
718 return item in self._vars
718 return item in self._vars
719
719
720 def getmember(self, context, mapping, key):
720 def getmember(self, context, mapping, key):
721 key = templateutil.unwrapvalue(context, mapping, key)
721 key = templateutil.unwrapvalue(context, mapping, key)
722 return self._vars.get(key)
722 return self._vars.get(key)
723
723
724 def getmin(self, context, mapping):
724 def getmin(self, context, mapping):
725 raise error.ParseError(_('not comparable'))
725 raise error.ParseError(_('not comparable'))
726
726
727 def getmax(self, context, mapping):
727 def getmax(self, context, mapping):
728 raise error.ParseError(_('not comparable'))
728 raise error.ParseError(_('not comparable'))
729
729
730 def itermaps(self, context):
730 def itermaps(self, context):
731 separator = self._start
731 separator = self._start
732 for key, value in sorted(self._vars.iteritems()):
732 for key, value in sorted(self._vars.iteritems()):
733 yield {'name': key,
733 yield {'name': key,
734 'value': pycompat.bytestr(value),
734 'value': pycompat.bytestr(value),
735 'separator': separator,
735 'separator': separator,
736 }
736 }
737 separator = '&'
737 separator = '&'
738
738
739 def join(self, context, mapping, sep):
739 def join(self, context, mapping, sep):
740 # could be '{separator}{name}={value|urlescape}'
740 # could be '{separator}{name}={value|urlescape}'
741 raise error.ParseError(_('not displayable without template'))
741 raise error.ParseError(_('not displayable without template'))
742
742
743 def show(self, context, mapping):
743 def show(self, context, mapping):
744 return self.join(context, '')
744 return self.join(context, '')
745
745
746 def tobool(self, context, mapping):
747 return bool(self._vars)
748
746 def tovalue(self, context, mapping):
749 def tovalue(self, context, mapping):
747 return self._vars
750 return self._vars
748
751
749 class wsgiui(uimod.ui):
752 class wsgiui(uimod.ui):
750 # default termwidth breaks under mod_wsgi
753 # default termwidth breaks under mod_wsgi
751 def termwidth(self):
754 def termwidth(self):
752 return 80
755 return 80
753
756
754 def getwebsubs(repo):
757 def getwebsubs(repo):
755 websubtable = []
758 websubtable = []
756 websubdefs = repo.ui.configitems('websub')
759 websubdefs = repo.ui.configitems('websub')
757 # we must maintain interhg backwards compatibility
760 # we must maintain interhg backwards compatibility
758 websubdefs += repo.ui.configitems('interhg')
761 websubdefs += repo.ui.configitems('interhg')
759 for key, pattern in websubdefs:
762 for key, pattern in websubdefs:
760 # grab the delimiter from the character after the "s"
763 # grab the delimiter from the character after the "s"
761 unesc = pattern[1:2]
764 unesc = pattern[1:2]
762 delim = re.escape(unesc)
765 delim = re.escape(unesc)
763
766
764 # identify portions of the pattern, taking care to avoid escaped
767 # identify portions of the pattern, taking care to avoid escaped
765 # delimiters. the replace format and flags are optional, but
768 # delimiters. the replace format and flags are optional, but
766 # delimiters are required.
769 # delimiters are required.
767 match = re.match(
770 match = re.match(
768 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
771 br'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
769 % (delim, delim, delim), pattern)
772 % (delim, delim, delim), pattern)
770 if not match:
773 if not match:
771 repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
774 repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
772 % (key, pattern))
775 % (key, pattern))
773 continue
776 continue
774
777
775 # we need to unescape the delimiter for regexp and format
778 # we need to unescape the delimiter for regexp and format
776 delim_re = re.compile(br'(?<!\\)\\%s' % delim)
779 delim_re = re.compile(br'(?<!\\)\\%s' % delim)
777 regexp = delim_re.sub(unesc, match.group(1))
780 regexp = delim_re.sub(unesc, match.group(1))
778 format = delim_re.sub(unesc, match.group(2))
781 format = delim_re.sub(unesc, match.group(2))
779
782
780 # the pattern allows for 6 regexp flags, so set them if necessary
783 # the pattern allows for 6 regexp flags, so set them if necessary
781 flagin = match.group(3)
784 flagin = match.group(3)
782 flags = 0
785 flags = 0
783 if flagin:
786 if flagin:
784 for flag in flagin.upper():
787 for flag in flagin.upper():
785 flags |= re.__dict__[flag]
788 flags |= re.__dict__[flag]
786
789
787 try:
790 try:
788 regexp = re.compile(regexp, flags)
791 regexp = re.compile(regexp, flags)
789 websubtable.append((regexp, format))
792 websubtable.append((regexp, format))
790 except re.error:
793 except re.error:
791 repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
794 repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
792 % (key, regexp))
795 % (key, regexp))
793 return websubtable
796 return websubtable
794
797
795 def getgraphnode(repo, ctx):
798 def getgraphnode(repo, ctx):
796 return (templatekw.getgraphnodecurrent(repo, ctx) +
799 return (templatekw.getgraphnodecurrent(repo, ctx) +
797 templatekw.getgraphnodesymbol(ctx))
800 templatekw.getgraphnodesymbol(ctx))
@@ -1,851 +1,885 b''
1 # templateutil.py - utility for template evaluation
1 # templateutil.py - utility for template evaluation
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import abc
10 import abc
11 import types
11 import types
12
12
13 from .i18n import _
13 from .i18n import _
14 from . import (
14 from . import (
15 error,
15 error,
16 pycompat,
16 pycompat,
17 util,
17 util,
18 )
18 )
19 from .utils import (
19 from .utils import (
20 dateutil,
20 dateutil,
21 stringutil,
21 stringutil,
22 )
22 )
23
23
24 class ResourceUnavailable(error.Abort):
24 class ResourceUnavailable(error.Abort):
25 pass
25 pass
26
26
27 class TemplateNotFound(error.Abort):
27 class TemplateNotFound(error.Abort):
28 pass
28 pass
29
29
30 class wrapped(object):
30 class wrapped(object):
31 """Object requiring extra conversion prior to displaying or processing
31 """Object requiring extra conversion prior to displaying or processing
32 as value
32 as value
33
33
34 Use unwrapvalue() or unwrapastype() to obtain the inner object.
34 Use unwrapvalue() or unwrapastype() to obtain the inner object.
35 """
35 """
36
36
37 __metaclass__ = abc.ABCMeta
37 __metaclass__ = abc.ABCMeta
38
38
39 @abc.abstractmethod
39 @abc.abstractmethod
40 def contains(self, context, mapping, item):
40 def contains(self, context, mapping, item):
41 """Test if the specified item is in self
41 """Test if the specified item is in self
42
42
43 The item argument may be a wrapped object.
43 The item argument may be a wrapped object.
44 """
44 """
45
45
46 @abc.abstractmethod
46 @abc.abstractmethod
47 def getmember(self, context, mapping, key):
47 def getmember(self, context, mapping, key):
48 """Return a member item for the specified key
48 """Return a member item for the specified key
49
49
50 The key argument may be a wrapped object.
50 The key argument may be a wrapped object.
51 A returned object may be either a wrapped object or a pure value
51 A returned object may be either a wrapped object or a pure value
52 depending on the self type.
52 depending on the self type.
53 """
53 """
54
54
55 @abc.abstractmethod
55 @abc.abstractmethod
56 def getmin(self, context, mapping):
56 def getmin(self, context, mapping):
57 """Return the smallest item, which may be either a wrapped or a pure
57 """Return the smallest item, which may be either a wrapped or a pure
58 value depending on the self type"""
58 value depending on the self type"""
59
59
60 @abc.abstractmethod
60 @abc.abstractmethod
61 def getmax(self, context, mapping):
61 def getmax(self, context, mapping):
62 """Return the largest item, which may be either a wrapped or a pure
62 """Return the largest item, which may be either a wrapped or a pure
63 value depending on the self type"""
63 value depending on the self type"""
64
64
65 @abc.abstractmethod
65 @abc.abstractmethod
66 def itermaps(self, context):
66 def itermaps(self, context):
67 """Yield each template mapping"""
67 """Yield each template mapping"""
68
68
69 @abc.abstractmethod
69 @abc.abstractmethod
70 def join(self, context, mapping, sep):
70 def join(self, context, mapping, sep):
71 """Join items with the separator; Returns a bytes or (possibly nested)
71 """Join items with the separator; Returns a bytes or (possibly nested)
72 generator of bytes
72 generator of bytes
73
73
74 A pre-configured template may be rendered per item if this container
74 A pre-configured template may be rendered per item if this container
75 holds unprintable items.
75 holds unprintable items.
76 """
76 """
77
77
78 @abc.abstractmethod
78 @abc.abstractmethod
79 def show(self, context, mapping):
79 def show(self, context, mapping):
80 """Return a bytes or (possibly nested) generator of bytes representing
80 """Return a bytes or (possibly nested) generator of bytes representing
81 the underlying object
81 the underlying object
82
82
83 A pre-configured template may be rendered if the underlying object is
83 A pre-configured template may be rendered if the underlying object is
84 not printable.
84 not printable.
85 """
85 """
86
86
87 @abc.abstractmethod
87 @abc.abstractmethod
88 def tobool(self, context, mapping):
89 """Return a boolean representation of the inner value"""
90
91 @abc.abstractmethod
88 def tovalue(self, context, mapping):
92 def tovalue(self, context, mapping):
89 """Move the inner value object out or create a value representation
93 """Move the inner value object out or create a value representation
90
94
91 A returned value must be serializable by templaterfilters.json().
95 A returned value must be serializable by templaterfilters.json().
92 """
96 """
93
97
94 class mappable(object):
98 class mappable(object):
95 """Object which can be converted to a single template mapping"""
99 """Object which can be converted to a single template mapping"""
96
100
97 def itermaps(self, context):
101 def itermaps(self, context):
98 yield self.tomap(context)
102 yield self.tomap(context)
99
103
100 @abc.abstractmethod
104 @abc.abstractmethod
101 def tomap(self, context):
105 def tomap(self, context):
102 """Create a single template mapping representing this"""
106 """Create a single template mapping representing this"""
103
107
104 class wrappedbytes(wrapped):
108 class wrappedbytes(wrapped):
105 """Wrapper for byte string"""
109 """Wrapper for byte string"""
106
110
107 def __init__(self, value):
111 def __init__(self, value):
108 self._value = value
112 self._value = value
109
113
110 def contains(self, context, mapping, item):
114 def contains(self, context, mapping, item):
111 item = stringify(context, mapping, item)
115 item = stringify(context, mapping, item)
112 return item in self._value
116 return item in self._value
113
117
114 def getmember(self, context, mapping, key):
118 def getmember(self, context, mapping, key):
115 raise error.ParseError(_('%r is not a dictionary')
119 raise error.ParseError(_('%r is not a dictionary')
116 % pycompat.bytestr(self._value))
120 % pycompat.bytestr(self._value))
117
121
118 def getmin(self, context, mapping):
122 def getmin(self, context, mapping):
119 return self._getby(context, mapping, min)
123 return self._getby(context, mapping, min)
120
124
121 def getmax(self, context, mapping):
125 def getmax(self, context, mapping):
122 return self._getby(context, mapping, max)
126 return self._getby(context, mapping, max)
123
127
124 def _getby(self, context, mapping, func):
128 def _getby(self, context, mapping, func):
125 if not self._value:
129 if not self._value:
126 raise error.ParseError(_('empty string'))
130 raise error.ParseError(_('empty string'))
127 return func(pycompat.iterbytestr(self._value))
131 return func(pycompat.iterbytestr(self._value))
128
132
129 def itermaps(self, context):
133 def itermaps(self, context):
130 raise error.ParseError(_('%r is not iterable of mappings')
134 raise error.ParseError(_('%r is not iterable of mappings')
131 % pycompat.bytestr(self._value))
135 % pycompat.bytestr(self._value))
132
136
133 def join(self, context, mapping, sep):
137 def join(self, context, mapping, sep):
134 return joinitems(pycompat.iterbytestr(self._value), sep)
138 return joinitems(pycompat.iterbytestr(self._value), sep)
135
139
136 def show(self, context, mapping):
140 def show(self, context, mapping):
137 return self._value
141 return self._value
138
142
143 def tobool(self, context, mapping):
144 return bool(self._value)
145
139 def tovalue(self, context, mapping):
146 def tovalue(self, context, mapping):
140 return self._value
147 return self._value
141
148
142 class wrappedvalue(wrapped):
149 class wrappedvalue(wrapped):
143 """Generic wrapper for pure non-list/dict/bytes value"""
150 """Generic wrapper for pure non-list/dict/bytes value"""
144
151
145 def __init__(self, value):
152 def __init__(self, value):
146 self._value = value
153 self._value = value
147
154
148 def contains(self, context, mapping, item):
155 def contains(self, context, mapping, item):
149 raise error.ParseError(_("%r is not iterable") % self._value)
156 raise error.ParseError(_("%r is not iterable") % self._value)
150
157
151 def getmember(self, context, mapping, key):
158 def getmember(self, context, mapping, key):
152 raise error.ParseError(_('%r is not a dictionary') % self._value)
159 raise error.ParseError(_('%r is not a dictionary') % self._value)
153
160
154 def getmin(self, context, mapping):
161 def getmin(self, context, mapping):
155 raise error.ParseError(_("%r is not iterable") % self._value)
162 raise error.ParseError(_("%r is not iterable") % self._value)
156
163
157 def getmax(self, context, mapping):
164 def getmax(self, context, mapping):
158 raise error.ParseError(_("%r is not iterable") % self._value)
165 raise error.ParseError(_("%r is not iterable") % self._value)
159
166
160 def itermaps(self, context):
167 def itermaps(self, context):
161 raise error.ParseError(_('%r is not iterable of mappings')
168 raise error.ParseError(_('%r is not iterable of mappings')
162 % self._value)
169 % self._value)
163
170
164 def join(self, context, mapping, sep):
171 def join(self, context, mapping, sep):
165 raise error.ParseError(_('%r is not iterable') % self._value)
172 raise error.ParseError(_('%r is not iterable') % self._value)
166
173
167 def show(self, context, mapping):
174 def show(self, context, mapping):
168 if self._value is None:
175 if self._value is None:
169 return b''
176 return b''
170 return pycompat.bytestr(self._value)
177 return pycompat.bytestr(self._value)
171
178
179 def tobool(self, context, mapping):
180 if self._value is None:
181 return False
182 if isinstance(self._value, bool):
183 return self._value
184 # otherwise evaluate as string, which means 0 is True
185 return bool(pycompat.bytestr(self._value))
186
172 def tovalue(self, context, mapping):
187 def tovalue(self, context, mapping):
173 return self._value
188 return self._value
174
189
175 class date(mappable, wrapped):
190 class date(mappable, wrapped):
176 """Wrapper for date tuple"""
191 """Wrapper for date tuple"""
177
192
178 def __init__(self, value):
193 def __init__(self, value):
179 # value may be (float, int), but public interface shouldn't support
194 # value may be (float, int), but public interface shouldn't support
180 # floating-point timestamp
195 # floating-point timestamp
181 self._unixtime, self._tzoffset = map(int, value)
196 self._unixtime, self._tzoffset = map(int, value)
182
197
183 def contains(self, context, mapping, item):
198 def contains(self, context, mapping, item):
184 raise error.ParseError(_('date is not iterable'))
199 raise error.ParseError(_('date is not iterable'))
185
200
186 def getmember(self, context, mapping, key):
201 def getmember(self, context, mapping, key):
187 raise error.ParseError(_('date is not a dictionary'))
202 raise error.ParseError(_('date is not a dictionary'))
188
203
189 def getmin(self, context, mapping):
204 def getmin(self, context, mapping):
190 raise error.ParseError(_('date is not iterable'))
205 raise error.ParseError(_('date is not iterable'))
191
206
192 def getmax(self, context, mapping):
207 def getmax(self, context, mapping):
193 raise error.ParseError(_('date is not iterable'))
208 raise error.ParseError(_('date is not iterable'))
194
209
195 def join(self, context, mapping, sep):
210 def join(self, context, mapping, sep):
196 raise error.ParseError(_("date is not iterable"))
211 raise error.ParseError(_("date is not iterable"))
197
212
198 def show(self, context, mapping):
213 def show(self, context, mapping):
199 return '%d %d' % (self._unixtime, self._tzoffset)
214 return '%d %d' % (self._unixtime, self._tzoffset)
200
215
201 def tomap(self, context):
216 def tomap(self, context):
202 return {'unixtime': self._unixtime, 'tzoffset': self._tzoffset}
217 return {'unixtime': self._unixtime, 'tzoffset': self._tzoffset}
203
218
219 def tobool(self, context, mapping):
220 return True
221
204 def tovalue(self, context, mapping):
222 def tovalue(self, context, mapping):
205 return (self._unixtime, self._tzoffset)
223 return (self._unixtime, self._tzoffset)
206
224
207 class hybrid(wrapped):
225 class hybrid(wrapped):
208 """Wrapper for list or dict to support legacy template
226 """Wrapper for list or dict to support legacy template
209
227
210 This class allows us to handle both:
228 This class allows us to handle both:
211 - "{files}" (legacy command-line-specific list hack) and
229 - "{files}" (legacy command-line-specific list hack) and
212 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
230 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
213 and to access raw values:
231 and to access raw values:
214 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
232 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
215 - "{get(extras, key)}"
233 - "{get(extras, key)}"
216 - "{files|json}"
234 - "{files|json}"
217 """
235 """
218
236
219 def __init__(self, gen, values, makemap, joinfmt, keytype=None):
237 def __init__(self, gen, values, makemap, joinfmt, keytype=None):
220 self._gen = gen # generator or function returning generator
238 self._gen = gen # generator or function returning generator
221 self._values = values
239 self._values = values
222 self._makemap = makemap
240 self._makemap = makemap
223 self._joinfmt = joinfmt
241 self._joinfmt = joinfmt
224 self._keytype = keytype # hint for 'x in y' where type(x) is unresolved
242 self._keytype = keytype # hint for 'x in y' where type(x) is unresolved
225
243
226 def contains(self, context, mapping, item):
244 def contains(self, context, mapping, item):
227 item = unwrapastype(context, mapping, item, self._keytype)
245 item = unwrapastype(context, mapping, item, self._keytype)
228 return item in self._values
246 return item in self._values
229
247
230 def getmember(self, context, mapping, key):
248 def getmember(self, context, mapping, key):
231 # TODO: maybe split hybrid list/dict types?
249 # TODO: maybe split hybrid list/dict types?
232 if not util.safehasattr(self._values, 'get'):
250 if not util.safehasattr(self._values, 'get'):
233 raise error.ParseError(_('not a dictionary'))
251 raise error.ParseError(_('not a dictionary'))
234 key = unwrapastype(context, mapping, key, self._keytype)
252 key = unwrapastype(context, mapping, key, self._keytype)
235 return self._wrapvalue(key, self._values.get(key))
253 return self._wrapvalue(key, self._values.get(key))
236
254
237 def getmin(self, context, mapping):
255 def getmin(self, context, mapping):
238 return self._getby(context, mapping, min)
256 return self._getby(context, mapping, min)
239
257
240 def getmax(self, context, mapping):
258 def getmax(self, context, mapping):
241 return self._getby(context, mapping, max)
259 return self._getby(context, mapping, max)
242
260
243 def _getby(self, context, mapping, func):
261 def _getby(self, context, mapping, func):
244 if not self._values:
262 if not self._values:
245 raise error.ParseError(_('empty sequence'))
263 raise error.ParseError(_('empty sequence'))
246 val = func(self._values)
264 val = func(self._values)
247 return self._wrapvalue(val, val)
265 return self._wrapvalue(val, val)
248
266
249 def _wrapvalue(self, key, val):
267 def _wrapvalue(self, key, val):
250 if val is None:
268 if val is None:
251 return
269 return
252 if util.safehasattr(val, '_makemap'):
270 if util.safehasattr(val, '_makemap'):
253 # a nested hybrid list/dict, which has its own way of map operation
271 # a nested hybrid list/dict, which has its own way of map operation
254 return val
272 return val
255 return hybriditem(None, key, val, self._makemap)
273 return hybriditem(None, key, val, self._makemap)
256
274
257 def itermaps(self, context):
275 def itermaps(self, context):
258 makemap = self._makemap
276 makemap = self._makemap
259 for x in self._values:
277 for x in self._values:
260 yield makemap(x)
278 yield makemap(x)
261
279
262 def join(self, context, mapping, sep):
280 def join(self, context, mapping, sep):
263 # TODO: switch gen to (context, mapping) API?
281 # TODO: switch gen to (context, mapping) API?
264 return joinitems((self._joinfmt(x) for x in self._values), sep)
282 return joinitems((self._joinfmt(x) for x in self._values), sep)
265
283
266 def show(self, context, mapping):
284 def show(self, context, mapping):
267 # TODO: switch gen to (context, mapping) API?
285 # TODO: switch gen to (context, mapping) API?
268 gen = self._gen
286 gen = self._gen
269 if gen is None:
287 if gen is None:
270 return self.join(context, mapping, ' ')
288 return self.join(context, mapping, ' ')
271 if callable(gen):
289 if callable(gen):
272 return gen()
290 return gen()
273 return gen
291 return gen
274
292
293 def tobool(self, context, mapping):
294 return bool(self._values)
295
275 def tovalue(self, context, mapping):
296 def tovalue(self, context, mapping):
276 # TODO: make it non-recursive for trivial lists/dicts
297 # TODO: make it non-recursive for trivial lists/dicts
277 xs = self._values
298 xs = self._values
278 if util.safehasattr(xs, 'get'):
299 if util.safehasattr(xs, 'get'):
279 return {k: unwrapvalue(context, mapping, v)
300 return {k: unwrapvalue(context, mapping, v)
280 for k, v in xs.iteritems()}
301 for k, v in xs.iteritems()}
281 return [unwrapvalue(context, mapping, x) for x in xs]
302 return [unwrapvalue(context, mapping, x) for x in xs]
282
303
283 class hybriditem(mappable, wrapped):
304 class hybriditem(mappable, wrapped):
284 """Wrapper for non-list/dict object to support map operation
305 """Wrapper for non-list/dict object to support map operation
285
306
286 This class allows us to handle both:
307 This class allows us to handle both:
287 - "{manifest}"
308 - "{manifest}"
288 - "{manifest % '{rev}:{node}'}"
309 - "{manifest % '{rev}:{node}'}"
289 - "{manifest.rev}"
310 - "{manifest.rev}"
290 """
311 """
291
312
292 def __init__(self, gen, key, value, makemap):
313 def __init__(self, gen, key, value, makemap):
293 self._gen = gen # generator or function returning generator
314 self._gen = gen # generator or function returning generator
294 self._key = key
315 self._key = key
295 self._value = value # may be generator of strings
316 self._value = value # may be generator of strings
296 self._makemap = makemap
317 self._makemap = makemap
297
318
298 def tomap(self, context):
319 def tomap(self, context):
299 return self._makemap(self._key)
320 return self._makemap(self._key)
300
321
301 def contains(self, context, mapping, item):
322 def contains(self, context, mapping, item):
302 w = makewrapped(context, mapping, self._value)
323 w = makewrapped(context, mapping, self._value)
303 return w.contains(context, mapping, item)
324 return w.contains(context, mapping, item)
304
325
305 def getmember(self, context, mapping, key):
326 def getmember(self, context, mapping, key):
306 w = makewrapped(context, mapping, self._value)
327 w = makewrapped(context, mapping, self._value)
307 return w.getmember(context, mapping, key)
328 return w.getmember(context, mapping, key)
308
329
309 def getmin(self, context, mapping):
330 def getmin(self, context, mapping):
310 w = makewrapped(context, mapping, self._value)
331 w = makewrapped(context, mapping, self._value)
311 return w.getmin(context, mapping)
332 return w.getmin(context, mapping)
312
333
313 def getmax(self, context, mapping):
334 def getmax(self, context, mapping):
314 w = makewrapped(context, mapping, self._value)
335 w = makewrapped(context, mapping, self._value)
315 return w.getmax(context, mapping)
336 return w.getmax(context, mapping)
316
337
317 def join(self, context, mapping, sep):
338 def join(self, context, mapping, sep):
318 w = makewrapped(context, mapping, self._value)
339 w = makewrapped(context, mapping, self._value)
319 return w.join(context, mapping, sep)
340 return w.join(context, mapping, sep)
320
341
321 def show(self, context, mapping):
342 def show(self, context, mapping):
322 # TODO: switch gen to (context, mapping) API?
343 # TODO: switch gen to (context, mapping) API?
323 gen = self._gen
344 gen = self._gen
324 if gen is None:
345 if gen is None:
325 return pycompat.bytestr(self._value)
346 return pycompat.bytestr(self._value)
326 if callable(gen):
347 if callable(gen):
327 return gen()
348 return gen()
328 return gen
349 return gen
329
350
351 def tobool(self, context, mapping):
352 return bool(self.tovalue(context, mapping))
353
330 def tovalue(self, context, mapping):
354 def tovalue(self, context, mapping):
331 return _unthunk(context, mapping, self._value)
355 return _unthunk(context, mapping, self._value)
332
356
333 class _mappingsequence(wrapped):
357 class _mappingsequence(wrapped):
334 """Wrapper for sequence of template mappings
358 """Wrapper for sequence of template mappings
335
359
336 This represents an inner template structure (i.e. a list of dicts),
360 This represents an inner template structure (i.e. a list of dicts),
337 which can also be rendered by the specified named/literal template.
361 which can also be rendered by the specified named/literal template.
338
362
339 Template mappings may be nested.
363 Template mappings may be nested.
340 """
364 """
341
365
342 def __init__(self, name=None, tmpl=None, sep=''):
366 def __init__(self, name=None, tmpl=None, sep=''):
343 if name is not None and tmpl is not None:
367 if name is not None and tmpl is not None:
344 raise error.ProgrammingError('name and tmpl are mutually exclusive')
368 raise error.ProgrammingError('name and tmpl are mutually exclusive')
345 self._name = name
369 self._name = name
346 self._tmpl = tmpl
370 self._tmpl = tmpl
347 self._defaultsep = sep
371 self._defaultsep = sep
348
372
349 def contains(self, context, mapping, item):
373 def contains(self, context, mapping, item):
350 raise error.ParseError(_('not comparable'))
374 raise error.ParseError(_('not comparable'))
351
375
352 def getmember(self, context, mapping, key):
376 def getmember(self, context, mapping, key):
353 raise error.ParseError(_('not a dictionary'))
377 raise error.ParseError(_('not a dictionary'))
354
378
355 def getmin(self, context, mapping):
379 def getmin(self, context, mapping):
356 raise error.ParseError(_('not comparable'))
380 raise error.ParseError(_('not comparable'))
357
381
358 def getmax(self, context, mapping):
382 def getmax(self, context, mapping):
359 raise error.ParseError(_('not comparable'))
383 raise error.ParseError(_('not comparable'))
360
384
361 def join(self, context, mapping, sep):
385 def join(self, context, mapping, sep):
362 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
386 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
363 if self._name:
387 if self._name:
364 itemiter = (context.process(self._name, m) for m in mapsiter)
388 itemiter = (context.process(self._name, m) for m in mapsiter)
365 elif self._tmpl:
389 elif self._tmpl:
366 itemiter = (context.expand(self._tmpl, m) for m in mapsiter)
390 itemiter = (context.expand(self._tmpl, m) for m in mapsiter)
367 else:
391 else:
368 raise error.ParseError(_('not displayable without template'))
392 raise error.ParseError(_('not displayable without template'))
369 return joinitems(itemiter, sep)
393 return joinitems(itemiter, sep)
370
394
371 def show(self, context, mapping):
395 def show(self, context, mapping):
372 return self.join(context, mapping, self._defaultsep)
396 return self.join(context, mapping, self._defaultsep)
373
397
374 def tovalue(self, context, mapping):
398 def tovalue(self, context, mapping):
375 knownres = context.knownresourcekeys()
399 knownres = context.knownresourcekeys()
376 items = []
400 items = []
377 for nm in self.itermaps(context):
401 for nm in self.itermaps(context):
378 # drop internal resources (recursively) which shouldn't be displayed
402 # drop internal resources (recursively) which shouldn't be displayed
379 lm = context.overlaymap(mapping, nm)
403 lm = context.overlaymap(mapping, nm)
380 items.append({k: unwrapvalue(context, lm, v)
404 items.append({k: unwrapvalue(context, lm, v)
381 for k, v in nm.iteritems() if k not in knownres})
405 for k, v in nm.iteritems() if k not in knownres})
382 return items
406 return items
383
407
384 class mappinggenerator(_mappingsequence):
408 class mappinggenerator(_mappingsequence):
385 """Wrapper for generator of template mappings
409 """Wrapper for generator of template mappings
386
410
387 The function ``make(context, *args)`` should return a generator of
411 The function ``make(context, *args)`` should return a generator of
388 mapping dicts.
412 mapping dicts.
389 """
413 """
390
414
391 def __init__(self, make, args=(), name=None, tmpl=None, sep=''):
415 def __init__(self, make, args=(), name=None, tmpl=None, sep=''):
392 super(mappinggenerator, self).__init__(name, tmpl, sep)
416 super(mappinggenerator, self).__init__(name, tmpl, sep)
393 self._make = make
417 self._make = make
394 self._args = args
418 self._args = args
395
419
396 def itermaps(self, context):
420 def itermaps(self, context):
397 return self._make(context, *self._args)
421 return self._make(context, *self._args)
398
422
423 def tobool(self, context, mapping):
424 return _nonempty(self.itermaps(context))
425
399 class mappinglist(_mappingsequence):
426 class mappinglist(_mappingsequence):
400 """Wrapper for list of template mappings"""
427 """Wrapper for list of template mappings"""
401
428
402 def __init__(self, mappings, name=None, tmpl=None, sep=''):
429 def __init__(self, mappings, name=None, tmpl=None, sep=''):
403 super(mappinglist, self).__init__(name, tmpl, sep)
430 super(mappinglist, self).__init__(name, tmpl, sep)
404 self._mappings = mappings
431 self._mappings = mappings
405
432
406 def itermaps(self, context):
433 def itermaps(self, context):
407 return iter(self._mappings)
434 return iter(self._mappings)
408
435
436 def tobool(self, context, mapping):
437 return bool(self._mappings)
438
409 class mappedgenerator(wrapped):
439 class mappedgenerator(wrapped):
410 """Wrapper for generator of strings which acts as a list
440 """Wrapper for generator of strings which acts as a list
411
441
412 The function ``make(context, *args)`` should return a generator of
442 The function ``make(context, *args)`` should return a generator of
413 byte strings, or a generator of (possibly nested) generators of byte
443 byte strings, or a generator of (possibly nested) generators of byte
414 strings (i.e. a generator for a list of byte strings.)
444 strings (i.e. a generator for a list of byte strings.)
415 """
445 """
416
446
417 def __init__(self, make, args=()):
447 def __init__(self, make, args=()):
418 self._make = make
448 self._make = make
419 self._args = args
449 self._args = args
420
450
421 def contains(self, context, mapping, item):
451 def contains(self, context, mapping, item):
422 item = stringify(context, mapping, item)
452 item = stringify(context, mapping, item)
423 return item in self.tovalue(context, mapping)
453 return item in self.tovalue(context, mapping)
424
454
425 def _gen(self, context):
455 def _gen(self, context):
426 return self._make(context, *self._args)
456 return self._make(context, *self._args)
427
457
428 def getmember(self, context, mapping, key):
458 def getmember(self, context, mapping, key):
429 raise error.ParseError(_('not a dictionary'))
459 raise error.ParseError(_('not a dictionary'))
430
460
431 def getmin(self, context, mapping):
461 def getmin(self, context, mapping):
432 return self._getby(context, mapping, min)
462 return self._getby(context, mapping, min)
433
463
434 def getmax(self, context, mapping):
464 def getmax(self, context, mapping):
435 return self._getby(context, mapping, max)
465 return self._getby(context, mapping, max)
436
466
437 def _getby(self, context, mapping, func):
467 def _getby(self, context, mapping, func):
438 xs = self.tovalue(context, mapping)
468 xs = self.tovalue(context, mapping)
439 if not xs:
469 if not xs:
440 raise error.ParseError(_('empty sequence'))
470 raise error.ParseError(_('empty sequence'))
441 return func(xs)
471 return func(xs)
442
472
443 def itermaps(self, context):
473 def itermaps(self, context):
444 raise error.ParseError(_('list of strings is not mappable'))
474 raise error.ParseError(_('list of strings is not mappable'))
445
475
446 def join(self, context, mapping, sep):
476 def join(self, context, mapping, sep):
447 return joinitems(self._gen(context), sep)
477 return joinitems(self._gen(context), sep)
448
478
449 def show(self, context, mapping):
479 def show(self, context, mapping):
450 return self.join(context, mapping, '')
480 return self.join(context, mapping, '')
451
481
482 def tobool(self, context, mapping):
483 return _nonempty(self._gen(context))
484
452 def tovalue(self, context, mapping):
485 def tovalue(self, context, mapping):
453 return [stringify(context, mapping, x) for x in self._gen(context)]
486 return [stringify(context, mapping, x) for x in self._gen(context)]
454
487
455 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
488 def hybriddict(data, key='key', value='value', fmt=None, gen=None):
456 """Wrap data to support both dict-like and string-like operations"""
489 """Wrap data to support both dict-like and string-like operations"""
457 prefmt = pycompat.identity
490 prefmt = pycompat.identity
458 if fmt is None:
491 if fmt is None:
459 fmt = '%s=%s'
492 fmt = '%s=%s'
460 prefmt = pycompat.bytestr
493 prefmt = pycompat.bytestr
461 return hybrid(gen, data, lambda k: {key: k, value: data[k]},
494 return hybrid(gen, data, lambda k: {key: k, value: data[k]},
462 lambda k: fmt % (prefmt(k), prefmt(data[k])))
495 lambda k: fmt % (prefmt(k), prefmt(data[k])))
463
496
464 def hybridlist(data, name, fmt=None, gen=None):
497 def hybridlist(data, name, fmt=None, gen=None):
465 """Wrap data to support both list-like and string-like operations"""
498 """Wrap data to support both list-like and string-like operations"""
466 prefmt = pycompat.identity
499 prefmt = pycompat.identity
467 if fmt is None:
500 if fmt is None:
468 fmt = '%s'
501 fmt = '%s'
469 prefmt = pycompat.bytestr
502 prefmt = pycompat.bytestr
470 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
503 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
471
504
472 def compatdict(context, mapping, name, data, key='key', value='value',
505 def compatdict(context, mapping, name, data, key='key', value='value',
473 fmt=None, plural=None, separator=' '):
506 fmt=None, plural=None, separator=' '):
474 """Wrap data like hybriddict(), but also supports old-style list template
507 """Wrap data like hybriddict(), but also supports old-style list template
475
508
476 This exists for backward compatibility with the old-style template. Use
509 This exists for backward compatibility with the old-style template. Use
477 hybriddict() for new template keywords.
510 hybriddict() for new template keywords.
478 """
511 """
479 c = [{key: k, value: v} for k, v in data.iteritems()]
512 c = [{key: k, value: v} for k, v in data.iteritems()]
480 f = _showcompatlist(context, mapping, name, c, plural, separator)
513 f = _showcompatlist(context, mapping, name, c, plural, separator)
481 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
514 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
482
515
483 def compatlist(context, mapping, name, data, element=None, fmt=None,
516 def compatlist(context, mapping, name, data, element=None, fmt=None,
484 plural=None, separator=' '):
517 plural=None, separator=' '):
485 """Wrap data like hybridlist(), but also supports old-style list template
518 """Wrap data like hybridlist(), but also supports old-style list template
486
519
487 This exists for backward compatibility with the old-style template. Use
520 This exists for backward compatibility with the old-style template. Use
488 hybridlist() for new template keywords.
521 hybridlist() for new template keywords.
489 """
522 """
490 f = _showcompatlist(context, mapping, name, data, plural, separator)
523 f = _showcompatlist(context, mapping, name, data, plural, separator)
491 return hybridlist(data, name=element or name, fmt=fmt, gen=f)
524 return hybridlist(data, name=element or name, fmt=fmt, gen=f)
492
525
493 def _showcompatlist(context, mapping, name, values, plural=None, separator=' '):
526 def _showcompatlist(context, mapping, name, values, plural=None, separator=' '):
494 """Return a generator that renders old-style list template
527 """Return a generator that renders old-style list template
495
528
496 name is name of key in template map.
529 name is name of key in template map.
497 values is list of strings or dicts.
530 values is list of strings or dicts.
498 plural is plural of name, if not simply name + 's'.
531 plural is plural of name, if not simply name + 's'.
499 separator is used to join values as a string
532 separator is used to join values as a string
500
533
501 expansion works like this, given name 'foo'.
534 expansion works like this, given name 'foo'.
502
535
503 if values is empty, expand 'no_foos'.
536 if values is empty, expand 'no_foos'.
504
537
505 if 'foo' not in template map, return values as a string,
538 if 'foo' not in template map, return values as a string,
506 joined by 'separator'.
539 joined by 'separator'.
507
540
508 expand 'start_foos'.
541 expand 'start_foos'.
509
542
510 for each value, expand 'foo'. if 'last_foo' in template
543 for each value, expand 'foo'. if 'last_foo' in template
511 map, expand it instead of 'foo' for last key.
544 map, expand it instead of 'foo' for last key.
512
545
513 expand 'end_foos'.
546 expand 'end_foos'.
514 """
547 """
515 if not plural:
548 if not plural:
516 plural = name + 's'
549 plural = name + 's'
517 if not values:
550 if not values:
518 noname = 'no_' + plural
551 noname = 'no_' + plural
519 if context.preload(noname):
552 if context.preload(noname):
520 yield context.process(noname, mapping)
553 yield context.process(noname, mapping)
521 return
554 return
522 if not context.preload(name):
555 if not context.preload(name):
523 if isinstance(values[0], bytes):
556 if isinstance(values[0], bytes):
524 yield separator.join(values)
557 yield separator.join(values)
525 else:
558 else:
526 for v in values:
559 for v in values:
527 r = dict(v)
560 r = dict(v)
528 r.update(mapping)
561 r.update(mapping)
529 yield r
562 yield r
530 return
563 return
531 startname = 'start_' + plural
564 startname = 'start_' + plural
532 if context.preload(startname):
565 if context.preload(startname):
533 yield context.process(startname, mapping)
566 yield context.process(startname, mapping)
534 def one(v, tag=name):
567 def one(v, tag=name):
535 vmapping = {}
568 vmapping = {}
536 try:
569 try:
537 vmapping.update(v)
570 vmapping.update(v)
538 # Python 2 raises ValueError if the type of v is wrong. Python
571 # Python 2 raises ValueError if the type of v is wrong. Python
539 # 3 raises TypeError.
572 # 3 raises TypeError.
540 except (AttributeError, TypeError, ValueError):
573 except (AttributeError, TypeError, ValueError):
541 try:
574 try:
542 # Python 2 raises ValueError trying to destructure an e.g.
575 # Python 2 raises ValueError trying to destructure an e.g.
543 # bytes. Python 3 raises TypeError.
576 # bytes. Python 3 raises TypeError.
544 for a, b in v:
577 for a, b in v:
545 vmapping[a] = b
578 vmapping[a] = b
546 except (TypeError, ValueError):
579 except (TypeError, ValueError):
547 vmapping[name] = v
580 vmapping[name] = v
548 vmapping = context.overlaymap(mapping, vmapping)
581 vmapping = context.overlaymap(mapping, vmapping)
549 return context.process(tag, vmapping)
582 return context.process(tag, vmapping)
550 lastname = 'last_' + name
583 lastname = 'last_' + name
551 if context.preload(lastname):
584 if context.preload(lastname):
552 last = values.pop()
585 last = values.pop()
553 else:
586 else:
554 last = None
587 last = None
555 for v in values:
588 for v in values:
556 yield one(v)
589 yield one(v)
557 if last is not None:
590 if last is not None:
558 yield one(last, tag=lastname)
591 yield one(last, tag=lastname)
559 endname = 'end_' + plural
592 endname = 'end_' + plural
560 if context.preload(endname):
593 if context.preload(endname):
561 yield context.process(endname, mapping)
594 yield context.process(endname, mapping)
562
595
563 def flatten(context, mapping, thing):
596 def flatten(context, mapping, thing):
564 """Yield a single stream from a possibly nested set of iterators"""
597 """Yield a single stream from a possibly nested set of iterators"""
565 if isinstance(thing, wrapped):
598 if isinstance(thing, wrapped):
566 thing = thing.show(context, mapping)
599 thing = thing.show(context, mapping)
567 if isinstance(thing, bytes):
600 if isinstance(thing, bytes):
568 yield thing
601 yield thing
569 elif isinstance(thing, str):
602 elif isinstance(thing, str):
570 # We can only hit this on Python 3, and it's here to guard
603 # We can only hit this on Python 3, and it's here to guard
571 # against infinite recursion.
604 # against infinite recursion.
572 raise error.ProgrammingError('Mercurial IO including templates is done'
605 raise error.ProgrammingError('Mercurial IO including templates is done'
573 ' with bytes, not strings, got %r' % thing)
606 ' with bytes, not strings, got %r' % thing)
574 elif thing is None:
607 elif thing is None:
575 pass
608 pass
576 elif not util.safehasattr(thing, '__iter__'):
609 elif not util.safehasattr(thing, '__iter__'):
577 yield pycompat.bytestr(thing)
610 yield pycompat.bytestr(thing)
578 else:
611 else:
579 for i in thing:
612 for i in thing:
580 if isinstance(i, wrapped):
613 if isinstance(i, wrapped):
581 i = i.show(context, mapping)
614 i = i.show(context, mapping)
582 if isinstance(i, bytes):
615 if isinstance(i, bytes):
583 yield i
616 yield i
584 elif i is None:
617 elif i is None:
585 pass
618 pass
586 elif not util.safehasattr(i, '__iter__'):
619 elif not util.safehasattr(i, '__iter__'):
587 yield pycompat.bytestr(i)
620 yield pycompat.bytestr(i)
588 else:
621 else:
589 for j in flatten(context, mapping, i):
622 for j in flatten(context, mapping, i):
590 yield j
623 yield j
591
624
592 def stringify(context, mapping, thing):
625 def stringify(context, mapping, thing):
593 """Turn values into bytes by converting into text and concatenating them"""
626 """Turn values into bytes by converting into text and concatenating them"""
594 if isinstance(thing, bytes):
627 if isinstance(thing, bytes):
595 return thing # retain localstr to be round-tripped
628 return thing # retain localstr to be round-tripped
596 return b''.join(flatten(context, mapping, thing))
629 return b''.join(flatten(context, mapping, thing))
597
630
598 def findsymbolicname(arg):
631 def findsymbolicname(arg):
599 """Find symbolic name for the given compiled expression; returns None
632 """Find symbolic name for the given compiled expression; returns None
600 if nothing found reliably"""
633 if nothing found reliably"""
601 while True:
634 while True:
602 func, data = arg
635 func, data = arg
603 if func is runsymbol:
636 if func is runsymbol:
604 return data
637 return data
605 elif func is runfilter:
638 elif func is runfilter:
606 arg = data[0]
639 arg = data[0]
607 else:
640 else:
608 return None
641 return None
609
642
643 def _nonempty(xiter):
644 try:
645 next(xiter)
646 return True
647 except StopIteration:
648 return False
649
610 def _unthunk(context, mapping, thing):
650 def _unthunk(context, mapping, thing):
611 """Evaluate a lazy byte string into value"""
651 """Evaluate a lazy byte string into value"""
612 if not isinstance(thing, types.GeneratorType):
652 if not isinstance(thing, types.GeneratorType):
613 return thing
653 return thing
614 return stringify(context, mapping, thing)
654 return stringify(context, mapping, thing)
615
655
616 def evalrawexp(context, mapping, arg):
656 def evalrawexp(context, mapping, arg):
617 """Evaluate given argument as a bare template object which may require
657 """Evaluate given argument as a bare template object which may require
618 further processing (such as folding generator of strings)"""
658 further processing (such as folding generator of strings)"""
619 func, data = arg
659 func, data = arg
620 return func(context, mapping, data)
660 return func(context, mapping, data)
621
661
622 def evalwrapped(context, mapping, arg):
662 def evalwrapped(context, mapping, arg):
623 """Evaluate given argument to wrapped object"""
663 """Evaluate given argument to wrapped object"""
624 thing = evalrawexp(context, mapping, arg)
664 thing = evalrawexp(context, mapping, arg)
625 return makewrapped(context, mapping, thing)
665 return makewrapped(context, mapping, thing)
626
666
627 def makewrapped(context, mapping, thing):
667 def makewrapped(context, mapping, thing):
628 """Lift object to a wrapped type"""
668 """Lift object to a wrapped type"""
629 if isinstance(thing, wrapped):
669 if isinstance(thing, wrapped):
630 return thing
670 return thing
631 thing = _unthunk(context, mapping, thing)
671 thing = _unthunk(context, mapping, thing)
632 if isinstance(thing, bytes):
672 if isinstance(thing, bytes):
633 return wrappedbytes(thing)
673 return wrappedbytes(thing)
634 return wrappedvalue(thing)
674 return wrappedvalue(thing)
635
675
636 def evalfuncarg(context, mapping, arg):
676 def evalfuncarg(context, mapping, arg):
637 """Evaluate given argument as value type"""
677 """Evaluate given argument as value type"""
638 return unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))
678 return unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))
639
679
640 def unwrapvalue(context, mapping, thing):
680 def unwrapvalue(context, mapping, thing):
641 """Move the inner value object out of the wrapper"""
681 """Move the inner value object out of the wrapper"""
642 if isinstance(thing, wrapped):
682 if isinstance(thing, wrapped):
643 return thing.tovalue(context, mapping)
683 return thing.tovalue(context, mapping)
644 # evalrawexp() may return string, generator of strings or arbitrary object
684 # evalrawexp() may return string, generator of strings or arbitrary object
645 # such as date tuple, but filter does not want generator.
685 # such as date tuple, but filter does not want generator.
646 return _unthunk(context, mapping, thing)
686 return _unthunk(context, mapping, thing)
647
687
648 def evalboolean(context, mapping, arg):
688 def evalboolean(context, mapping, arg):
649 """Evaluate given argument as boolean, but also takes boolean literals"""
689 """Evaluate given argument as boolean, but also takes boolean literals"""
650 func, data = arg
690 func, data = arg
651 if func is runsymbol:
691 if func is runsymbol:
652 thing = func(context, mapping, data, default=None)
692 thing = func(context, mapping, data, default=None)
653 if thing is None:
693 if thing is None:
654 # not a template keyword, takes as a boolean literal
694 # not a template keyword, takes as a boolean literal
655 thing = stringutil.parsebool(data)
695 thing = stringutil.parsebool(data)
656 else:
696 else:
657 thing = func(context, mapping, data)
697 thing = func(context, mapping, data)
658 if isinstance(thing, wrapped):
698 return makewrapped(context, mapping, thing).tobool(context, mapping)
659 thing = thing.tovalue(context, mapping)
660 if isinstance(thing, bool):
661 return thing
662 # other objects are evaluated as strings, which means 0 is True, but
663 # empty dict/list should be False as they are expected to be ''
664 return bool(stringify(context, mapping, thing))
665
699
666 def evaldate(context, mapping, arg, err=None):
700 def evaldate(context, mapping, arg, err=None):
667 """Evaluate given argument as a date tuple or a date string; returns
701 """Evaluate given argument as a date tuple or a date string; returns
668 a (unixtime, offset) tuple"""
702 a (unixtime, offset) tuple"""
669 thing = evalrawexp(context, mapping, arg)
703 thing = evalrawexp(context, mapping, arg)
670 return unwrapdate(context, mapping, thing, err)
704 return unwrapdate(context, mapping, thing, err)
671
705
672 def unwrapdate(context, mapping, thing, err=None):
706 def unwrapdate(context, mapping, thing, err=None):
673 if isinstance(thing, date):
707 if isinstance(thing, date):
674 return thing.tovalue(context, mapping)
708 return thing.tovalue(context, mapping)
675 # TODO: update hgweb to not return bare tuple; then just stringify 'thing'
709 # TODO: update hgweb to not return bare tuple; then just stringify 'thing'
676 thing = unwrapvalue(context, mapping, thing)
710 thing = unwrapvalue(context, mapping, thing)
677 try:
711 try:
678 return dateutil.parsedate(thing)
712 return dateutil.parsedate(thing)
679 except AttributeError:
713 except AttributeError:
680 raise error.ParseError(err or _('not a date tuple nor a string'))
714 raise error.ParseError(err or _('not a date tuple nor a string'))
681 except error.ParseError:
715 except error.ParseError:
682 if not err:
716 if not err:
683 raise
717 raise
684 raise error.ParseError(err)
718 raise error.ParseError(err)
685
719
686 def evalinteger(context, mapping, arg, err=None):
720 def evalinteger(context, mapping, arg, err=None):
687 thing = evalrawexp(context, mapping, arg)
721 thing = evalrawexp(context, mapping, arg)
688 return unwrapinteger(context, mapping, thing, err)
722 return unwrapinteger(context, mapping, thing, err)
689
723
690 def unwrapinteger(context, mapping, thing, err=None):
724 def unwrapinteger(context, mapping, thing, err=None):
691 thing = unwrapvalue(context, mapping, thing)
725 thing = unwrapvalue(context, mapping, thing)
692 try:
726 try:
693 return int(thing)
727 return int(thing)
694 except (TypeError, ValueError):
728 except (TypeError, ValueError):
695 raise error.ParseError(err or _('not an integer'))
729 raise error.ParseError(err or _('not an integer'))
696
730
697 def evalstring(context, mapping, arg):
731 def evalstring(context, mapping, arg):
698 return stringify(context, mapping, evalrawexp(context, mapping, arg))
732 return stringify(context, mapping, evalrawexp(context, mapping, arg))
699
733
700 def evalstringliteral(context, mapping, arg):
734 def evalstringliteral(context, mapping, arg):
701 """Evaluate given argument as string template, but returns symbol name
735 """Evaluate given argument as string template, but returns symbol name
702 if it is unknown"""
736 if it is unknown"""
703 func, data = arg
737 func, data = arg
704 if func is runsymbol:
738 if func is runsymbol:
705 thing = func(context, mapping, data, default=data)
739 thing = func(context, mapping, data, default=data)
706 else:
740 else:
707 thing = func(context, mapping, data)
741 thing = func(context, mapping, data)
708 return stringify(context, mapping, thing)
742 return stringify(context, mapping, thing)
709
743
710 _unwrapfuncbytype = {
744 _unwrapfuncbytype = {
711 None: unwrapvalue,
745 None: unwrapvalue,
712 bytes: stringify,
746 bytes: stringify,
713 date: unwrapdate,
747 date: unwrapdate,
714 int: unwrapinteger,
748 int: unwrapinteger,
715 }
749 }
716
750
717 def unwrapastype(context, mapping, thing, typ):
751 def unwrapastype(context, mapping, thing, typ):
718 """Move the inner value object out of the wrapper and coerce its type"""
752 """Move the inner value object out of the wrapper and coerce its type"""
719 try:
753 try:
720 f = _unwrapfuncbytype[typ]
754 f = _unwrapfuncbytype[typ]
721 except KeyError:
755 except KeyError:
722 raise error.ProgrammingError('invalid type specified: %r' % typ)
756 raise error.ProgrammingError('invalid type specified: %r' % typ)
723 return f(context, mapping, thing)
757 return f(context, mapping, thing)
724
758
725 def runinteger(context, mapping, data):
759 def runinteger(context, mapping, data):
726 return int(data)
760 return int(data)
727
761
728 def runstring(context, mapping, data):
762 def runstring(context, mapping, data):
729 return data
763 return data
730
764
731 def _recursivesymbolblocker(key):
765 def _recursivesymbolblocker(key):
732 def showrecursion(**args):
766 def showrecursion(**args):
733 raise error.Abort(_("recursive reference '%s' in template") % key)
767 raise error.Abort(_("recursive reference '%s' in template") % key)
734 return showrecursion
768 return showrecursion
735
769
736 def runsymbol(context, mapping, key, default=''):
770 def runsymbol(context, mapping, key, default=''):
737 v = context.symbol(mapping, key)
771 v = context.symbol(mapping, key)
738 if v is None:
772 if v is None:
739 # put poison to cut recursion. we can't move this to parsing phase
773 # put poison to cut recursion. we can't move this to parsing phase
740 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
774 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
741 safemapping = mapping.copy()
775 safemapping = mapping.copy()
742 safemapping[key] = _recursivesymbolblocker(key)
776 safemapping[key] = _recursivesymbolblocker(key)
743 try:
777 try:
744 v = context.process(key, safemapping)
778 v = context.process(key, safemapping)
745 except TemplateNotFound:
779 except TemplateNotFound:
746 v = default
780 v = default
747 if callable(v) and getattr(v, '_requires', None) is None:
781 if callable(v) and getattr(v, '_requires', None) is None:
748 # old templatekw: expand all keywords and resources
782 # old templatekw: expand all keywords and resources
749 # (TODO: deprecate this after porting web template keywords to new API)
783 # (TODO: deprecate this after porting web template keywords to new API)
750 props = {k: context._resources.lookup(context, mapping, k)
784 props = {k: context._resources.lookup(context, mapping, k)
751 for k in context._resources.knownkeys()}
785 for k in context._resources.knownkeys()}
752 # pass context to _showcompatlist() through templatekw._showlist()
786 # pass context to _showcompatlist() through templatekw._showlist()
753 props['templ'] = context
787 props['templ'] = context
754 props.update(mapping)
788 props.update(mapping)
755 return v(**pycompat.strkwargs(props))
789 return v(**pycompat.strkwargs(props))
756 if callable(v):
790 if callable(v):
757 # new templatekw
791 # new templatekw
758 try:
792 try:
759 return v(context, mapping)
793 return v(context, mapping)
760 except ResourceUnavailable:
794 except ResourceUnavailable:
761 # unsupported keyword is mapped to empty just like unknown keyword
795 # unsupported keyword is mapped to empty just like unknown keyword
762 return None
796 return None
763 return v
797 return v
764
798
765 def runtemplate(context, mapping, template):
799 def runtemplate(context, mapping, template):
766 for arg in template:
800 for arg in template:
767 yield evalrawexp(context, mapping, arg)
801 yield evalrawexp(context, mapping, arg)
768
802
769 def runfilter(context, mapping, data):
803 def runfilter(context, mapping, data):
770 arg, filt = data
804 arg, filt = data
771 thing = evalrawexp(context, mapping, arg)
805 thing = evalrawexp(context, mapping, arg)
772 intype = getattr(filt, '_intype', None)
806 intype = getattr(filt, '_intype', None)
773 try:
807 try:
774 thing = unwrapastype(context, mapping, thing, intype)
808 thing = unwrapastype(context, mapping, thing, intype)
775 return filt(thing)
809 return filt(thing)
776 except error.ParseError as e:
810 except error.ParseError as e:
777 raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
811 raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
778
812
779 def _formatfiltererror(arg, filt):
813 def _formatfiltererror(arg, filt):
780 fn = pycompat.sysbytes(filt.__name__)
814 fn = pycompat.sysbytes(filt.__name__)
781 sym = findsymbolicname(arg)
815 sym = findsymbolicname(arg)
782 if not sym:
816 if not sym:
783 return _("incompatible use of template filter '%s'") % fn
817 return _("incompatible use of template filter '%s'") % fn
784 return (_("template filter '%s' is not compatible with keyword '%s'")
818 return (_("template filter '%s' is not compatible with keyword '%s'")
785 % (fn, sym))
819 % (fn, sym))
786
820
787 def _iteroverlaymaps(context, origmapping, newmappings):
821 def _iteroverlaymaps(context, origmapping, newmappings):
788 """Generate combined mappings from the original mapping and an iterable
822 """Generate combined mappings from the original mapping and an iterable
789 of partial mappings to override the original"""
823 of partial mappings to override the original"""
790 for i, nm in enumerate(newmappings):
824 for i, nm in enumerate(newmappings):
791 lm = context.overlaymap(origmapping, nm)
825 lm = context.overlaymap(origmapping, nm)
792 lm['index'] = i
826 lm['index'] = i
793 yield lm
827 yield lm
794
828
795 def _applymap(context, mapping, d, darg, targ):
829 def _applymap(context, mapping, d, darg, targ):
796 try:
830 try:
797 diter = d.itermaps(context)
831 diter = d.itermaps(context)
798 except error.ParseError as err:
832 except error.ParseError as err:
799 sym = findsymbolicname(darg)
833 sym = findsymbolicname(darg)
800 if not sym:
834 if not sym:
801 raise
835 raise
802 hint = _("keyword '%s' does not support map operation") % sym
836 hint = _("keyword '%s' does not support map operation") % sym
803 raise error.ParseError(bytes(err), hint=hint)
837 raise error.ParseError(bytes(err), hint=hint)
804 for lm in _iteroverlaymaps(context, mapping, diter):
838 for lm in _iteroverlaymaps(context, mapping, diter):
805 yield evalrawexp(context, lm, targ)
839 yield evalrawexp(context, lm, targ)
806
840
807 def runmap(context, mapping, data):
841 def runmap(context, mapping, data):
808 darg, targ = data
842 darg, targ = data
809 d = evalwrapped(context, mapping, darg)
843 d = evalwrapped(context, mapping, darg)
810 return mappedgenerator(_applymap, args=(mapping, d, darg, targ))
844 return mappedgenerator(_applymap, args=(mapping, d, darg, targ))
811
845
812 def runmember(context, mapping, data):
846 def runmember(context, mapping, data):
813 darg, memb = data
847 darg, memb = data
814 d = evalwrapped(context, mapping, darg)
848 d = evalwrapped(context, mapping, darg)
815 if isinstance(d, mappable):
849 if isinstance(d, mappable):
816 lm = context.overlaymap(mapping, d.tomap(context))
850 lm = context.overlaymap(mapping, d.tomap(context))
817 return runsymbol(context, lm, memb)
851 return runsymbol(context, lm, memb)
818 try:
852 try:
819 return d.getmember(context, mapping, memb)
853 return d.getmember(context, mapping, memb)
820 except error.ParseError as err:
854 except error.ParseError as err:
821 sym = findsymbolicname(darg)
855 sym = findsymbolicname(darg)
822 if not sym:
856 if not sym:
823 raise
857 raise
824 hint = _("keyword '%s' does not support member operation") % sym
858 hint = _("keyword '%s' does not support member operation") % sym
825 raise error.ParseError(bytes(err), hint=hint)
859 raise error.ParseError(bytes(err), hint=hint)
826
860
827 def runnegate(context, mapping, data):
861 def runnegate(context, mapping, data):
828 data = evalinteger(context, mapping, data,
862 data = evalinteger(context, mapping, data,
829 _('negation needs an integer argument'))
863 _('negation needs an integer argument'))
830 return -data
864 return -data
831
865
832 def runarithmetic(context, mapping, data):
866 def runarithmetic(context, mapping, data):
833 func, left, right = data
867 func, left, right = data
834 left = evalinteger(context, mapping, left,
868 left = evalinteger(context, mapping, left,
835 _('arithmetic only defined on integers'))
869 _('arithmetic only defined on integers'))
836 right = evalinteger(context, mapping, right,
870 right = evalinteger(context, mapping, right,
837 _('arithmetic only defined on integers'))
871 _('arithmetic only defined on integers'))
838 try:
872 try:
839 return func(left, right)
873 return func(left, right)
840 except ZeroDivisionError:
874 except ZeroDivisionError:
841 raise error.Abort(_('division by zero is not defined'))
875 raise error.Abort(_('division by zero is not defined'))
842
876
843 def joinitems(itemiter, sep):
877 def joinitems(itemiter, sep):
844 """Join items with the separator; Returns generator of bytes"""
878 """Join items with the separator; Returns generator of bytes"""
845 first = True
879 first = True
846 for x in itemiter:
880 for x in itemiter:
847 if first:
881 if first:
848 first = False
882 first = False
849 elif sep:
883 elif sep:
850 yield sep
884 yield sep
851 yield x
885 yield x
@@ -1,4987 +1,4991 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Test arithmetic operators have the right precedence:
32 Test arithmetic operators have the right precedence:
33
33
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
34 $ hg log -l 1 -T '{date(date, "%Y") + 5 * 10} {date(date, "%Y") - 2 * 3}\n'
35 2020 1964
35 2020 1964
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
36 $ hg log -l 1 -T '{date(date, "%Y") * 5 + 10} {date(date, "%Y") * 3 - 2}\n'
37 9860 5908
37 9860 5908
38
38
39 Test division:
39 Test division:
40
40
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
41 $ hg debugtemplate -r0 -v '{5 / 2} {mod(5, 2)}\n'
42 (template
42 (template
43 (/
43 (/
44 (integer '5')
44 (integer '5')
45 (integer '2'))
45 (integer '2'))
46 (string ' ')
46 (string ' ')
47 (func
47 (func
48 (symbol 'mod')
48 (symbol 'mod')
49 (list
49 (list
50 (integer '5')
50 (integer '5')
51 (integer '2')))
51 (integer '2')))
52 (string '\n'))
52 (string '\n'))
53 2 1
53 2 1
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
54 $ hg debugtemplate -r0 -v '{5 / -2} {mod(5, -2)}\n'
55 (template
55 (template
56 (/
56 (/
57 (integer '5')
57 (integer '5')
58 (negate
58 (negate
59 (integer '2')))
59 (integer '2')))
60 (string ' ')
60 (string ' ')
61 (func
61 (func
62 (symbol 'mod')
62 (symbol 'mod')
63 (list
63 (list
64 (integer '5')
64 (integer '5')
65 (negate
65 (negate
66 (integer '2'))))
66 (integer '2'))))
67 (string '\n'))
67 (string '\n'))
68 -3 -1
68 -3 -1
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
69 $ hg debugtemplate -r0 -v '{-5 / 2} {mod(-5, 2)}\n'
70 (template
70 (template
71 (/
71 (/
72 (negate
72 (negate
73 (integer '5'))
73 (integer '5'))
74 (integer '2'))
74 (integer '2'))
75 (string ' ')
75 (string ' ')
76 (func
76 (func
77 (symbol 'mod')
77 (symbol 'mod')
78 (list
78 (list
79 (negate
79 (negate
80 (integer '5'))
80 (integer '5'))
81 (integer '2')))
81 (integer '2')))
82 (string '\n'))
82 (string '\n'))
83 -3 1
83 -3 1
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
84 $ hg debugtemplate -r0 -v '{-5 / -2} {mod(-5, -2)}\n'
85 (template
85 (template
86 (/
86 (/
87 (negate
87 (negate
88 (integer '5'))
88 (integer '5'))
89 (negate
89 (negate
90 (integer '2')))
90 (integer '2')))
91 (string ' ')
91 (string ' ')
92 (func
92 (func
93 (symbol 'mod')
93 (symbol 'mod')
94 (list
94 (list
95 (negate
95 (negate
96 (integer '5'))
96 (integer '5'))
97 (negate
97 (negate
98 (integer '2'))))
98 (integer '2'))))
99 (string '\n'))
99 (string '\n'))
100 2 -1
100 2 -1
101
101
102 Filters bind closer than arithmetic:
102 Filters bind closer than arithmetic:
103
103
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
104 $ hg debugtemplate -r0 -v '{revset(".")|count - 1}\n'
105 (template
105 (template
106 (-
106 (-
107 (|
107 (|
108 (func
108 (func
109 (symbol 'revset')
109 (symbol 'revset')
110 (string '.'))
110 (string '.'))
111 (symbol 'count'))
111 (symbol 'count'))
112 (integer '1'))
112 (integer '1'))
113 (string '\n'))
113 (string '\n'))
114 0
114 0
115
115
116 But negate binds closer still:
116 But negate binds closer still:
117
117
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
118 $ hg debugtemplate -r0 -v '{1-3|stringify}\n'
119 (template
119 (template
120 (-
120 (-
121 (integer '1')
121 (integer '1')
122 (|
122 (|
123 (integer '3')
123 (integer '3')
124 (symbol 'stringify')))
124 (symbol 'stringify')))
125 (string '\n'))
125 (string '\n'))
126 hg: parse error: arithmetic only defined on integers
126 hg: parse error: arithmetic only defined on integers
127 [255]
127 [255]
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
128 $ hg debugtemplate -r0 -v '{-3|stringify}\n'
129 (template
129 (template
130 (|
130 (|
131 (negate
131 (negate
132 (integer '3'))
132 (integer '3'))
133 (symbol 'stringify'))
133 (symbol 'stringify'))
134 (string '\n'))
134 (string '\n'))
135 -3
135 -3
136
136
137 Filters bind as close as map operator:
137 Filters bind as close as map operator:
138
138
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
139 $ hg debugtemplate -r0 -v '{desc|splitlines % "{line}\n"}'
140 (template
140 (template
141 (%
141 (%
142 (|
142 (|
143 (symbol 'desc')
143 (symbol 'desc')
144 (symbol 'splitlines'))
144 (symbol 'splitlines'))
145 (template
145 (template
146 (symbol 'line')
146 (symbol 'line')
147 (string '\n'))))
147 (string '\n'))))
148 line 1
148 line 1
149 line 2
149 line 2
150
150
151 Keyword arguments:
151 Keyword arguments:
152
152
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
153 $ hg debugtemplate -r0 -v '{foo=bar|baz}'
154 (template
154 (template
155 (keyvalue
155 (keyvalue
156 (symbol 'foo')
156 (symbol 'foo')
157 (|
157 (|
158 (symbol 'bar')
158 (symbol 'bar')
159 (symbol 'baz'))))
159 (symbol 'baz'))))
160 hg: parse error: can't use a key-value pair in this context
160 hg: parse error: can't use a key-value pair in this context
161 [255]
161 [255]
162
162
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
163 $ hg debugtemplate '{pad("foo", width=10, left=true)}\n'
164 foo
164 foo
165
165
166 Call function which takes named arguments by filter syntax:
166 Call function which takes named arguments by filter syntax:
167
167
168 $ hg debugtemplate '{" "|separate}'
168 $ hg debugtemplate '{" "|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
169 $ hg debugtemplate '{("not", "an", "argument", "list")|separate}'
170 hg: parse error: unknown method 'list'
170 hg: parse error: unknown method 'list'
171 [255]
171 [255]
172
172
173 Second branch starting at nullrev:
173 Second branch starting at nullrev:
174
174
175 $ hg update null
175 $ hg update null
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
176 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
177 $ echo second > second
177 $ echo second > second
178 $ hg add second
178 $ hg add second
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
179 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
180 created new head
180 created new head
181
181
182 $ echo third > third
182 $ echo third > third
183 $ hg add third
183 $ hg add third
184 $ hg mv second fourth
184 $ hg mv second fourth
185 $ hg commit -m third -d "2020-01-01 10:01"
185 $ hg commit -m third -d "2020-01-01 10:01"
186
186
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
187 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
188 fourth (second)
188 fourth (second)
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
189 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
190 second -> fourth
190 second -> fourth
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
191 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
192 8 t
192 8 t
193 7 f
193 7 f
194
194
195 Working-directory revision has special identifiers, though they are still
195 Working-directory revision has special identifiers, though they are still
196 experimental:
196 experimental:
197
197
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
198 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
199 2147483647:ffffffffffffffffffffffffffffffffffffffff
200
200
201 Some keywords are invalid for working-directory revision, but they should
201 Some keywords are invalid for working-directory revision, but they should
202 never cause crash:
202 never cause crash:
203
203
204 $ hg log -r 'wdir()' -T '{manifest}\n'
204 $ hg log -r 'wdir()' -T '{manifest}\n'
205
205
206
206
207 Internal resources shouldn't be exposed (issue5699):
207 Internal resources shouldn't be exposed (issue5699):
208
208
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
209 $ hg log -r. -T '{cache}{ctx}{repo}{revcache}{templ}{ui}'
210
210
211 Never crash on internal resource not available:
211 Never crash on internal resource not available:
212
212
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
213 $ hg --cwd .. debugtemplate '{"c0bebeef"|shortest}\n'
214 abort: template resource not available: ctx
214 abort: template resource not available: ctx
215 [255]
215 [255]
216
216
217 $ hg config -T '{author}'
217 $ hg config -T '{author}'
218
218
219 Quoting for ui.logtemplate
219 Quoting for ui.logtemplate
220
220
221 $ hg tip --config "ui.logtemplate={rev}\n"
221 $ hg tip --config "ui.logtemplate={rev}\n"
222 8
222 8
223 $ hg tip --config "ui.logtemplate='{rev}\n'"
223 $ hg tip --config "ui.logtemplate='{rev}\n'"
224 8
224 8
225 $ hg tip --config 'ui.logtemplate="{rev}\n"'
225 $ hg tip --config 'ui.logtemplate="{rev}\n"'
226 8
226 8
227 $ hg tip --config 'ui.logtemplate=n{rev}\n'
227 $ hg tip --config 'ui.logtemplate=n{rev}\n'
228 n8
228 n8
229
229
230 Make sure user/global hgrc does not affect tests
230 Make sure user/global hgrc does not affect tests
231
231
232 $ echo '[ui]' > .hg/hgrc
232 $ echo '[ui]' > .hg/hgrc
233 $ echo 'logtemplate =' >> .hg/hgrc
233 $ echo 'logtemplate =' >> .hg/hgrc
234 $ echo 'style =' >> .hg/hgrc
234 $ echo 'style =' >> .hg/hgrc
235
235
236 Add some simple styles to settings
236 Add some simple styles to settings
237
237
238 $ cat <<'EOF' >> .hg/hgrc
238 $ cat <<'EOF' >> .hg/hgrc
239 > [templates]
239 > [templates]
240 > simple = "{rev}\n"
240 > simple = "{rev}\n"
241 > simple2 = {rev}\n
241 > simple2 = {rev}\n
242 > rev = "should not precede {rev} keyword\n"
242 > rev = "should not precede {rev} keyword\n"
243 > EOF
243 > EOF
244
244
245 $ hg log -l1 -Tsimple
245 $ hg log -l1 -Tsimple
246 8
246 8
247 $ hg log -l1 -Tsimple2
247 $ hg log -l1 -Tsimple2
248 8
248 8
249 $ hg log -l1 -Trev
249 $ hg log -l1 -Trev
250 should not precede 8 keyword
250 should not precede 8 keyword
251 $ hg log -l1 -T '{simple}'
251 $ hg log -l1 -T '{simple}'
252 8
252 8
253
253
254 Map file shouldn't see user templates:
254 Map file shouldn't see user templates:
255
255
256 $ cat <<EOF > tmpl
256 $ cat <<EOF > tmpl
257 > changeset = 'nothing expanded:{simple}\n'
257 > changeset = 'nothing expanded:{simple}\n'
258 > EOF
258 > EOF
259 $ hg log -l1 --style ./tmpl
259 $ hg log -l1 --style ./tmpl
260 nothing expanded:
260 nothing expanded:
261
261
262 Test templates and style maps in files:
262 Test templates and style maps in files:
263
263
264 $ echo "{rev}" > tmpl
264 $ echo "{rev}" > tmpl
265 $ hg log -l1 -T./tmpl
265 $ hg log -l1 -T./tmpl
266 8
266 8
267 $ hg log -l1 -Tblah/blah
267 $ hg log -l1 -Tblah/blah
268 blah/blah (no-eol)
268 blah/blah (no-eol)
269
269
270 $ printf 'changeset = "{rev}\\n"\n' > map-simple
270 $ printf 'changeset = "{rev}\\n"\n' > map-simple
271 $ hg log -l1 -T./map-simple
271 $ hg log -l1 -T./map-simple
272 8
272 8
273
273
274 a map file may have [templates] and [templatealias] sections:
274 a map file may have [templates] and [templatealias] sections:
275
275
276 $ cat <<'EOF' > map-simple
276 $ cat <<'EOF' > map-simple
277 > [templates]
277 > [templates]
278 > changeset = "{a}\n"
278 > changeset = "{a}\n"
279 > [templatealias]
279 > [templatealias]
280 > a = rev
280 > a = rev
281 > EOF
281 > EOF
282 $ hg log -l1 -T./map-simple
282 $ hg log -l1 -T./map-simple
283 8
283 8
284
284
285 so it can be included in hgrc
285 so it can be included in hgrc
286
286
287 $ cat <<EOF > myhgrc
287 $ cat <<EOF > myhgrc
288 > %include $HGRCPATH
288 > %include $HGRCPATH
289 > %include map-simple
289 > %include map-simple
290 > [templates]
290 > [templates]
291 > foo = "{changeset}"
291 > foo = "{changeset}"
292 > EOF
292 > EOF
293 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
293 $ HGRCPATH=./myhgrc hg log -l1 -Tfoo
294 8
294 8
295 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
295 $ HGRCPATH=./myhgrc hg log -l1 -T'{a}\n'
296 8
296 8
297
297
298 Test template map inheritance
298 Test template map inheritance
299
299
300 $ echo "__base__ = map-cmdline.default" > map-simple
300 $ echo "__base__ = map-cmdline.default" > map-simple
301 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
301 $ printf 'cset = "changeset: ***{rev}***\\n"\n' >> map-simple
302 $ hg log -l1 -T./map-simple
302 $ hg log -l1 -T./map-simple
303 changeset: ***8***
303 changeset: ***8***
304 tag: tip
304 tag: tip
305 user: test
305 user: test
306 date: Wed Jan 01 10:01:00 2020 +0000
306 date: Wed Jan 01 10:01:00 2020 +0000
307 summary: third
307 summary: third
308
308
309
309
310 Test docheader, docfooter and separator in template map
310 Test docheader, docfooter and separator in template map
311
311
312 $ cat <<'EOF' > map-myjson
312 $ cat <<'EOF' > map-myjson
313 > docheader = '\{\n'
313 > docheader = '\{\n'
314 > docfooter = '\n}\n'
314 > docfooter = '\n}\n'
315 > separator = ',\n'
315 > separator = ',\n'
316 > changeset = ' {dict(rev, node|short)|json}'
316 > changeset = ' {dict(rev, node|short)|json}'
317 > EOF
317 > EOF
318 $ hg log -l2 -T./map-myjson
318 $ hg log -l2 -T./map-myjson
319 {
319 {
320 {"node": "95c24699272e", "rev": 8},
320 {"node": "95c24699272e", "rev": 8},
321 {"node": "29114dbae42b", "rev": 7}
321 {"node": "29114dbae42b", "rev": 7}
322 }
322 }
323
323
324 Test docheader, docfooter and separator in [templates] section
324 Test docheader, docfooter and separator in [templates] section
325
325
326 $ cat <<'EOF' >> .hg/hgrc
326 $ cat <<'EOF' >> .hg/hgrc
327 > [templates]
327 > [templates]
328 > myjson = ' {dict(rev, node|short)|json}'
328 > myjson = ' {dict(rev, node|short)|json}'
329 > myjson:docheader = '\{\n'
329 > myjson:docheader = '\{\n'
330 > myjson:docfooter = '\n}\n'
330 > myjson:docfooter = '\n}\n'
331 > myjson:separator = ',\n'
331 > myjson:separator = ',\n'
332 > :docheader = 'should not be selected as a docheader for literal templates\n'
332 > :docheader = 'should not be selected as a docheader for literal templates\n'
333 > EOF
333 > EOF
334 $ hg log -l2 -Tmyjson
334 $ hg log -l2 -Tmyjson
335 {
335 {
336 {"node": "95c24699272e", "rev": 8},
336 {"node": "95c24699272e", "rev": 8},
337 {"node": "29114dbae42b", "rev": 7}
337 {"node": "29114dbae42b", "rev": 7}
338 }
338 }
339 $ hg log -l1 -T'{rev}\n'
339 $ hg log -l1 -T'{rev}\n'
340 8
340 8
341
341
342 Template should precede style option
342 Template should precede style option
343
343
344 $ hg log -l1 --style default -T '{rev}\n'
344 $ hg log -l1 --style default -T '{rev}\n'
345 8
345 8
346
346
347 Add a commit with empty description, to ensure that the templates
347 Add a commit with empty description, to ensure that the templates
348 below will omit the description line.
348 below will omit the description line.
349
349
350 $ echo c >> c
350 $ echo c >> c
351 $ hg add c
351 $ hg add c
352 $ hg commit -qm ' '
352 $ hg commit -qm ' '
353
353
354 Default style is like normal output. Phases style should be the same
354 Default style is like normal output. Phases style should be the same
355 as default style, except for extra phase lines.
355 as default style, except for extra phase lines.
356
356
357 $ hg log > log.out
357 $ hg log > log.out
358 $ hg log --style default > style.out
358 $ hg log --style default > style.out
359 $ cmp log.out style.out || diff -u log.out style.out
359 $ cmp log.out style.out || diff -u log.out style.out
360 $ hg log -T phases > phases.out
360 $ hg log -T phases > phases.out
361 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
361 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
362 +phase: draft
362 +phase: draft
363 +phase: draft
363 +phase: draft
364 +phase: draft
364 +phase: draft
365 +phase: draft
365 +phase: draft
366 +phase: draft
366 +phase: draft
367 +phase: draft
367 +phase: draft
368 +phase: draft
368 +phase: draft
369 +phase: draft
369 +phase: draft
370 +phase: draft
370 +phase: draft
371 +phase: draft
371 +phase: draft
372
372
373 $ hg log -v > log.out
373 $ hg log -v > log.out
374 $ hg log -v --style default > style.out
374 $ hg log -v --style default > style.out
375 $ cmp log.out style.out || diff -u log.out style.out
375 $ cmp log.out style.out || diff -u log.out style.out
376 $ hg log -v -T phases > phases.out
376 $ hg log -v -T phases > phases.out
377 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
377 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
378 +phase: draft
378 +phase: draft
379 +phase: draft
379 +phase: draft
380 +phase: draft
380 +phase: draft
381 +phase: draft
381 +phase: draft
382 +phase: draft
382 +phase: draft
383 +phase: draft
383 +phase: draft
384 +phase: draft
384 +phase: draft
385 +phase: draft
385 +phase: draft
386 +phase: draft
386 +phase: draft
387 +phase: draft
387 +phase: draft
388
388
389 $ hg log -q > log.out
389 $ hg log -q > log.out
390 $ hg log -q --style default > style.out
390 $ hg log -q --style default > style.out
391 $ cmp log.out style.out || diff -u log.out style.out
391 $ cmp log.out style.out || diff -u log.out style.out
392 $ hg log -q -T phases > phases.out
392 $ hg log -q -T phases > phases.out
393 $ cmp log.out phases.out || diff -u log.out phases.out
393 $ cmp log.out phases.out || diff -u log.out phases.out
394
394
395 $ hg log --debug > log.out
395 $ hg log --debug > log.out
396 $ hg log --debug --style default > style.out
396 $ hg log --debug --style default > style.out
397 $ cmp log.out style.out || diff -u log.out style.out
397 $ cmp log.out style.out || diff -u log.out style.out
398 $ hg log --debug -T phases > phases.out
398 $ hg log --debug -T phases > phases.out
399 $ cmp log.out phases.out || diff -u log.out phases.out
399 $ cmp log.out phases.out || diff -u log.out phases.out
400
400
401 Default style of working-directory revision should also be the same (but
401 Default style of working-directory revision should also be the same (but
402 date may change while running tests):
402 date may change while running tests):
403
403
404 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
404 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
405 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
405 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
406 $ cmp log.out style.out || diff -u log.out style.out
406 $ cmp log.out style.out || diff -u log.out style.out
407
407
408 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
408 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
409 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
409 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
410 $ cmp log.out style.out || diff -u log.out style.out
410 $ cmp log.out style.out || diff -u log.out style.out
411
411
412 $ hg log -r 'wdir()' -q > log.out
412 $ hg log -r 'wdir()' -q > log.out
413 $ hg log -r 'wdir()' -q --style default > style.out
413 $ hg log -r 'wdir()' -q --style default > style.out
414 $ cmp log.out style.out || diff -u log.out style.out
414 $ cmp log.out style.out || diff -u log.out style.out
415
415
416 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
416 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
417 $ hg log -r 'wdir()' --debug --style default \
417 $ hg log -r 'wdir()' --debug --style default \
418 > | sed 's|^date:.*|date:|' > style.out
418 > | sed 's|^date:.*|date:|' > style.out
419 $ cmp log.out style.out || diff -u log.out style.out
419 $ cmp log.out style.out || diff -u log.out style.out
420
420
421 Default style should also preserve color information (issue2866):
421 Default style should also preserve color information (issue2866):
422
422
423 $ cp $HGRCPATH $HGRCPATH-bak
423 $ cp $HGRCPATH $HGRCPATH-bak
424 $ cat <<EOF >> $HGRCPATH
424 $ cat <<EOF >> $HGRCPATH
425 > [extensions]
425 > [extensions]
426 > color=
426 > color=
427 > EOF
427 > EOF
428
428
429 $ hg --color=debug log > log.out
429 $ hg --color=debug log > log.out
430 $ hg --color=debug log --style default > style.out
430 $ hg --color=debug log --style default > style.out
431 $ cmp log.out style.out || diff -u log.out style.out
431 $ cmp log.out style.out || diff -u log.out style.out
432 $ hg --color=debug log -T phases > phases.out
432 $ hg --color=debug log -T phases > phases.out
433 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
433 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
434 +[log.phase|phase: draft]
434 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
435 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
436 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
437 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
438 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
439 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
440 +[log.phase|phase: draft]
441 +[log.phase|phase: draft]
441 +[log.phase|phase: draft]
442 +[log.phase|phase: draft]
442 +[log.phase|phase: draft]
443 +[log.phase|phase: draft]
443 +[log.phase|phase: draft]
444
444
445 $ hg --color=debug -v log > log.out
445 $ hg --color=debug -v log > log.out
446 $ hg --color=debug -v log --style default > style.out
446 $ hg --color=debug -v log --style default > style.out
447 $ cmp log.out style.out || diff -u log.out style.out
447 $ cmp log.out style.out || diff -u log.out style.out
448 $ hg --color=debug -v log -T phases > phases.out
448 $ hg --color=debug -v log -T phases > phases.out
449 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
449 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
450 +[log.phase|phase: draft]
450 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
451 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
452 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
453 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
454 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
455 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
456 +[log.phase|phase: draft]
457 +[log.phase|phase: draft]
457 +[log.phase|phase: draft]
458 +[log.phase|phase: draft]
458 +[log.phase|phase: draft]
459 +[log.phase|phase: draft]
459 +[log.phase|phase: draft]
460
460
461 $ hg --color=debug -q log > log.out
461 $ hg --color=debug -q log > log.out
462 $ hg --color=debug -q log --style default > style.out
462 $ hg --color=debug -q log --style default > style.out
463 $ cmp log.out style.out || diff -u log.out style.out
463 $ cmp log.out style.out || diff -u log.out style.out
464 $ hg --color=debug -q log -T phases > phases.out
464 $ hg --color=debug -q log -T phases > phases.out
465 $ cmp log.out phases.out || diff -u log.out phases.out
465 $ cmp log.out phases.out || diff -u log.out phases.out
466
466
467 $ hg --color=debug --debug log > log.out
467 $ hg --color=debug --debug log > log.out
468 $ hg --color=debug --debug log --style default > style.out
468 $ hg --color=debug --debug log --style default > style.out
469 $ cmp log.out style.out || diff -u log.out style.out
469 $ cmp log.out style.out || diff -u log.out style.out
470 $ hg --color=debug --debug log -T phases > phases.out
470 $ hg --color=debug --debug log -T phases > phases.out
471 $ cmp log.out phases.out || diff -u log.out phases.out
471 $ cmp log.out phases.out || diff -u log.out phases.out
472
472
473 $ mv $HGRCPATH-bak $HGRCPATH
473 $ mv $HGRCPATH-bak $HGRCPATH
474
474
475 Remove commit with empty commit message, so as to not pollute further
475 Remove commit with empty commit message, so as to not pollute further
476 tests.
476 tests.
477
477
478 $ hg --config extensions.strip= strip -q .
478 $ hg --config extensions.strip= strip -q .
479
479
480 Revision with no copies (used to print a traceback):
480 Revision with no copies (used to print a traceback):
481
481
482 $ hg tip -v --template '\n'
482 $ hg tip -v --template '\n'
483
483
484
484
485 Compact style works:
485 Compact style works:
486
486
487 $ hg log -Tcompact
487 $ hg log -Tcompact
488 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
488 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
489 third
489 third
490
490
491 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
491 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
492 second
492 second
493
493
494 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
494 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
495 merge
495 merge
496
496
497 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
497 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
498 new head
498 new head
499
499
500 4 bbe44766e73d 1970-01-17 04:53 +0000 person
500 4 bbe44766e73d 1970-01-17 04:53 +0000 person
501 new branch
501 new branch
502
502
503 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
503 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
504 no user, no domain
504 no user, no domain
505
505
506 2 97054abb4ab8 1970-01-14 21:20 +0000 other
506 2 97054abb4ab8 1970-01-14 21:20 +0000 other
507 no person
507 no person
508
508
509 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
509 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
510 other 1
510 other 1
511
511
512 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
512 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
513 line 1
513 line 1
514
514
515
515
516 $ hg log -v --style compact
516 $ hg log -v --style compact
517 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
517 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
518 third
518 third
519
519
520 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
520 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
521 second
521 second
522
522
523 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
523 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
524 merge
524 merge
525
525
526 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
526 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
527 new head
527 new head
528
528
529 4 bbe44766e73d 1970-01-17 04:53 +0000 person
529 4 bbe44766e73d 1970-01-17 04:53 +0000 person
530 new branch
530 new branch
531
531
532 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
532 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
533 no user, no domain
533 no user, no domain
534
534
535 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
535 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
536 no person
536 no person
537
537
538 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
538 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
539 other 1
539 other 1
540 other 2
540 other 2
541
541
542 other 3
542 other 3
543
543
544 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
544 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
545 line 1
545 line 1
546 line 2
546 line 2
547
547
548
548
549 $ hg log --debug --style compact
549 $ hg log --debug --style compact
550 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
550 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
551 third
551 third
552
552
553 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
553 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
554 second
554 second
555
555
556 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
556 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
557 merge
557 merge
558
558
559 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
559 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
560 new head
560 new head
561
561
562 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
562 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
563 new branch
563 new branch
564
564
565 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
565 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
566 no user, no domain
566 no user, no domain
567
567
568 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
568 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
569 no person
569 no person
570
570
571 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
571 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
572 other 1
572 other 1
573 other 2
573 other 2
574
574
575 other 3
575 other 3
576
576
577 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
577 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
578 line 1
578 line 1
579 line 2
579 line 2
580
580
581
581
582 Test xml styles:
582 Test xml styles:
583
583
584 $ hg log --style xml -r 'not all()'
584 $ hg log --style xml -r 'not all()'
585 <?xml version="1.0"?>
585 <?xml version="1.0"?>
586 <log>
586 <log>
587 </log>
587 </log>
588
588
589 $ hg log --style xml
589 $ hg log --style xml
590 <?xml version="1.0"?>
590 <?xml version="1.0"?>
591 <log>
591 <log>
592 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
592 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
593 <tag>tip</tag>
593 <tag>tip</tag>
594 <author email="test">test</author>
594 <author email="test">test</author>
595 <date>2020-01-01T10:01:00+00:00</date>
595 <date>2020-01-01T10:01:00+00:00</date>
596 <msg xml:space="preserve">third</msg>
596 <msg xml:space="preserve">third</msg>
597 </logentry>
597 </logentry>
598 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
598 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
599 <parent revision="-1" node="0000000000000000000000000000000000000000" />
599 <parent revision="-1" node="0000000000000000000000000000000000000000" />
600 <author email="user@hostname">User Name</author>
600 <author email="user@hostname">User Name</author>
601 <date>1970-01-12T13:46:40+00:00</date>
601 <date>1970-01-12T13:46:40+00:00</date>
602 <msg xml:space="preserve">second</msg>
602 <msg xml:space="preserve">second</msg>
603 </logentry>
603 </logentry>
604 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
604 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
605 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
605 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
606 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
606 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
607 <author email="person">person</author>
607 <author email="person">person</author>
608 <date>1970-01-18T08:40:01+00:00</date>
608 <date>1970-01-18T08:40:01+00:00</date>
609 <msg xml:space="preserve">merge</msg>
609 <msg xml:space="preserve">merge</msg>
610 </logentry>
610 </logentry>
611 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
611 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
612 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
613 <author email="person">person</author>
613 <author email="person">person</author>
614 <date>1970-01-18T08:40:00+00:00</date>
614 <date>1970-01-18T08:40:00+00:00</date>
615 <msg xml:space="preserve">new head</msg>
615 <msg xml:space="preserve">new head</msg>
616 </logentry>
616 </logentry>
617 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
617 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
618 <branch>foo</branch>
618 <branch>foo</branch>
619 <author email="person">person</author>
619 <author email="person">person</author>
620 <date>1970-01-17T04:53:20+00:00</date>
620 <date>1970-01-17T04:53:20+00:00</date>
621 <msg xml:space="preserve">new branch</msg>
621 <msg xml:space="preserve">new branch</msg>
622 </logentry>
622 </logentry>
623 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
623 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
624 <author email="person">person</author>
624 <author email="person">person</author>
625 <date>1970-01-16T01:06:40+00:00</date>
625 <date>1970-01-16T01:06:40+00:00</date>
626 <msg xml:space="preserve">no user, no domain</msg>
626 <msg xml:space="preserve">no user, no domain</msg>
627 </logentry>
627 </logentry>
628 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
628 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
629 <author email="other@place">other</author>
629 <author email="other@place">other</author>
630 <date>1970-01-14T21:20:00+00:00</date>
630 <date>1970-01-14T21:20:00+00:00</date>
631 <msg xml:space="preserve">no person</msg>
631 <msg xml:space="preserve">no person</msg>
632 </logentry>
632 </logentry>
633 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
633 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
634 <author email="other@place">A. N. Other</author>
634 <author email="other@place">A. N. Other</author>
635 <date>1970-01-13T17:33:20+00:00</date>
635 <date>1970-01-13T17:33:20+00:00</date>
636 <msg xml:space="preserve">other 1
636 <msg xml:space="preserve">other 1
637 other 2
637 other 2
638
638
639 other 3</msg>
639 other 3</msg>
640 </logentry>
640 </logentry>
641 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
641 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
642 <author email="user@hostname">User Name</author>
642 <author email="user@hostname">User Name</author>
643 <date>1970-01-12T13:46:40+00:00</date>
643 <date>1970-01-12T13:46:40+00:00</date>
644 <msg xml:space="preserve">line 1
644 <msg xml:space="preserve">line 1
645 line 2</msg>
645 line 2</msg>
646 </logentry>
646 </logentry>
647 </log>
647 </log>
648
648
649 $ hg log -v --style xml
649 $ hg log -v --style xml
650 <?xml version="1.0"?>
650 <?xml version="1.0"?>
651 <log>
651 <log>
652 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
652 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
653 <tag>tip</tag>
653 <tag>tip</tag>
654 <author email="test">test</author>
654 <author email="test">test</author>
655 <date>2020-01-01T10:01:00+00:00</date>
655 <date>2020-01-01T10:01:00+00:00</date>
656 <msg xml:space="preserve">third</msg>
656 <msg xml:space="preserve">third</msg>
657 <paths>
657 <paths>
658 <path action="A">fourth</path>
658 <path action="A">fourth</path>
659 <path action="A">third</path>
659 <path action="A">third</path>
660 <path action="R">second</path>
660 <path action="R">second</path>
661 </paths>
661 </paths>
662 <copies>
662 <copies>
663 <copy source="second">fourth</copy>
663 <copy source="second">fourth</copy>
664 </copies>
664 </copies>
665 </logentry>
665 </logentry>
666 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
666 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
667 <parent revision="-1" node="0000000000000000000000000000000000000000" />
667 <parent revision="-1" node="0000000000000000000000000000000000000000" />
668 <author email="user@hostname">User Name</author>
668 <author email="user@hostname">User Name</author>
669 <date>1970-01-12T13:46:40+00:00</date>
669 <date>1970-01-12T13:46:40+00:00</date>
670 <msg xml:space="preserve">second</msg>
670 <msg xml:space="preserve">second</msg>
671 <paths>
671 <paths>
672 <path action="A">second</path>
672 <path action="A">second</path>
673 </paths>
673 </paths>
674 </logentry>
674 </logentry>
675 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
675 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
676 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
676 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
677 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
677 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
678 <author email="person">person</author>
678 <author email="person">person</author>
679 <date>1970-01-18T08:40:01+00:00</date>
679 <date>1970-01-18T08:40:01+00:00</date>
680 <msg xml:space="preserve">merge</msg>
680 <msg xml:space="preserve">merge</msg>
681 <paths>
681 <paths>
682 </paths>
682 </paths>
683 </logentry>
683 </logentry>
684 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
684 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
685 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
685 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
686 <author email="person">person</author>
686 <author email="person">person</author>
687 <date>1970-01-18T08:40:00+00:00</date>
687 <date>1970-01-18T08:40:00+00:00</date>
688 <msg xml:space="preserve">new head</msg>
688 <msg xml:space="preserve">new head</msg>
689 <paths>
689 <paths>
690 <path action="A">d</path>
690 <path action="A">d</path>
691 </paths>
691 </paths>
692 </logentry>
692 </logentry>
693 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
693 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
694 <branch>foo</branch>
694 <branch>foo</branch>
695 <author email="person">person</author>
695 <author email="person">person</author>
696 <date>1970-01-17T04:53:20+00:00</date>
696 <date>1970-01-17T04:53:20+00:00</date>
697 <msg xml:space="preserve">new branch</msg>
697 <msg xml:space="preserve">new branch</msg>
698 <paths>
698 <paths>
699 </paths>
699 </paths>
700 </logentry>
700 </logentry>
701 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
701 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
702 <author email="person">person</author>
702 <author email="person">person</author>
703 <date>1970-01-16T01:06:40+00:00</date>
703 <date>1970-01-16T01:06:40+00:00</date>
704 <msg xml:space="preserve">no user, no domain</msg>
704 <msg xml:space="preserve">no user, no domain</msg>
705 <paths>
705 <paths>
706 <path action="M">c</path>
706 <path action="M">c</path>
707 </paths>
707 </paths>
708 </logentry>
708 </logentry>
709 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
709 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
710 <author email="other@place">other</author>
710 <author email="other@place">other</author>
711 <date>1970-01-14T21:20:00+00:00</date>
711 <date>1970-01-14T21:20:00+00:00</date>
712 <msg xml:space="preserve">no person</msg>
712 <msg xml:space="preserve">no person</msg>
713 <paths>
713 <paths>
714 <path action="A">c</path>
714 <path action="A">c</path>
715 </paths>
715 </paths>
716 </logentry>
716 </logentry>
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
717 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
718 <author email="other@place">A. N. Other</author>
718 <author email="other@place">A. N. Other</author>
719 <date>1970-01-13T17:33:20+00:00</date>
719 <date>1970-01-13T17:33:20+00:00</date>
720 <msg xml:space="preserve">other 1
720 <msg xml:space="preserve">other 1
721 other 2
721 other 2
722
722
723 other 3</msg>
723 other 3</msg>
724 <paths>
724 <paths>
725 <path action="A">b</path>
725 <path action="A">b</path>
726 </paths>
726 </paths>
727 </logentry>
727 </logentry>
728 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
728 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
729 <author email="user@hostname">User Name</author>
729 <author email="user@hostname">User Name</author>
730 <date>1970-01-12T13:46:40+00:00</date>
730 <date>1970-01-12T13:46:40+00:00</date>
731 <msg xml:space="preserve">line 1
731 <msg xml:space="preserve">line 1
732 line 2</msg>
732 line 2</msg>
733 <paths>
733 <paths>
734 <path action="A">a</path>
734 <path action="A">a</path>
735 </paths>
735 </paths>
736 </logentry>
736 </logentry>
737 </log>
737 </log>
738
738
739 $ hg log --debug --style xml
739 $ hg log --debug --style xml
740 <?xml version="1.0"?>
740 <?xml version="1.0"?>
741 <log>
741 <log>
742 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
742 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
743 <tag>tip</tag>
743 <tag>tip</tag>
744 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
744 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
745 <parent revision="-1" node="0000000000000000000000000000000000000000" />
745 <parent revision="-1" node="0000000000000000000000000000000000000000" />
746 <author email="test">test</author>
746 <author email="test">test</author>
747 <date>2020-01-01T10:01:00+00:00</date>
747 <date>2020-01-01T10:01:00+00:00</date>
748 <msg xml:space="preserve">third</msg>
748 <msg xml:space="preserve">third</msg>
749 <paths>
749 <paths>
750 <path action="A">fourth</path>
750 <path action="A">fourth</path>
751 <path action="A">third</path>
751 <path action="A">third</path>
752 <path action="R">second</path>
752 <path action="R">second</path>
753 </paths>
753 </paths>
754 <copies>
754 <copies>
755 <copy source="second">fourth</copy>
755 <copy source="second">fourth</copy>
756 </copies>
756 </copies>
757 <extra key="branch">default</extra>
757 <extra key="branch">default</extra>
758 </logentry>
758 </logentry>
759 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
759 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
760 <parent revision="-1" node="0000000000000000000000000000000000000000" />
760 <parent revision="-1" node="0000000000000000000000000000000000000000" />
761 <parent revision="-1" node="0000000000000000000000000000000000000000" />
761 <parent revision="-1" node="0000000000000000000000000000000000000000" />
762 <author email="user@hostname">User Name</author>
762 <author email="user@hostname">User Name</author>
763 <date>1970-01-12T13:46:40+00:00</date>
763 <date>1970-01-12T13:46:40+00:00</date>
764 <msg xml:space="preserve">second</msg>
764 <msg xml:space="preserve">second</msg>
765 <paths>
765 <paths>
766 <path action="A">second</path>
766 <path action="A">second</path>
767 </paths>
767 </paths>
768 <extra key="branch">default</extra>
768 <extra key="branch">default</extra>
769 </logentry>
769 </logentry>
770 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
770 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
771 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
771 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
772 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
772 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
773 <author email="person">person</author>
773 <author email="person">person</author>
774 <date>1970-01-18T08:40:01+00:00</date>
774 <date>1970-01-18T08:40:01+00:00</date>
775 <msg xml:space="preserve">merge</msg>
775 <msg xml:space="preserve">merge</msg>
776 <paths>
776 <paths>
777 </paths>
777 </paths>
778 <extra key="branch">default</extra>
778 <extra key="branch">default</extra>
779 </logentry>
779 </logentry>
780 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
780 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
781 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
781 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
782 <parent revision="-1" node="0000000000000000000000000000000000000000" />
782 <parent revision="-1" node="0000000000000000000000000000000000000000" />
783 <author email="person">person</author>
783 <author email="person">person</author>
784 <date>1970-01-18T08:40:00+00:00</date>
784 <date>1970-01-18T08:40:00+00:00</date>
785 <msg xml:space="preserve">new head</msg>
785 <msg xml:space="preserve">new head</msg>
786 <paths>
786 <paths>
787 <path action="A">d</path>
787 <path action="A">d</path>
788 </paths>
788 </paths>
789 <extra key="branch">default</extra>
789 <extra key="branch">default</extra>
790 </logentry>
790 </logentry>
791 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
791 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
792 <branch>foo</branch>
792 <branch>foo</branch>
793 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
793 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
794 <parent revision="-1" node="0000000000000000000000000000000000000000" />
794 <parent revision="-1" node="0000000000000000000000000000000000000000" />
795 <author email="person">person</author>
795 <author email="person">person</author>
796 <date>1970-01-17T04:53:20+00:00</date>
796 <date>1970-01-17T04:53:20+00:00</date>
797 <msg xml:space="preserve">new branch</msg>
797 <msg xml:space="preserve">new branch</msg>
798 <paths>
798 <paths>
799 </paths>
799 </paths>
800 <extra key="branch">foo</extra>
800 <extra key="branch">foo</extra>
801 </logentry>
801 </logentry>
802 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
802 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
803 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
803 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
804 <parent revision="-1" node="0000000000000000000000000000000000000000" />
805 <author email="person">person</author>
805 <author email="person">person</author>
806 <date>1970-01-16T01:06:40+00:00</date>
806 <date>1970-01-16T01:06:40+00:00</date>
807 <msg xml:space="preserve">no user, no domain</msg>
807 <msg xml:space="preserve">no user, no domain</msg>
808 <paths>
808 <paths>
809 <path action="M">c</path>
809 <path action="M">c</path>
810 </paths>
810 </paths>
811 <extra key="branch">default</extra>
811 <extra key="branch">default</extra>
812 </logentry>
812 </logentry>
813 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
813 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
814 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
814 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
815 <parent revision="-1" node="0000000000000000000000000000000000000000" />
815 <parent revision="-1" node="0000000000000000000000000000000000000000" />
816 <author email="other@place">other</author>
816 <author email="other@place">other</author>
817 <date>1970-01-14T21:20:00+00:00</date>
817 <date>1970-01-14T21:20:00+00:00</date>
818 <msg xml:space="preserve">no person</msg>
818 <msg xml:space="preserve">no person</msg>
819 <paths>
819 <paths>
820 <path action="A">c</path>
820 <path action="A">c</path>
821 </paths>
821 </paths>
822 <extra key="branch">default</extra>
822 <extra key="branch">default</extra>
823 </logentry>
823 </logentry>
824 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
824 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
825 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
825 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
826 <parent revision="-1" node="0000000000000000000000000000000000000000" />
826 <parent revision="-1" node="0000000000000000000000000000000000000000" />
827 <author email="other@place">A. N. Other</author>
827 <author email="other@place">A. N. Other</author>
828 <date>1970-01-13T17:33:20+00:00</date>
828 <date>1970-01-13T17:33:20+00:00</date>
829 <msg xml:space="preserve">other 1
829 <msg xml:space="preserve">other 1
830 other 2
830 other 2
831
831
832 other 3</msg>
832 other 3</msg>
833 <paths>
833 <paths>
834 <path action="A">b</path>
834 <path action="A">b</path>
835 </paths>
835 </paths>
836 <extra key="branch">default</extra>
836 <extra key="branch">default</extra>
837 </logentry>
837 </logentry>
838 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
838 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
839 <parent revision="-1" node="0000000000000000000000000000000000000000" />
839 <parent revision="-1" node="0000000000000000000000000000000000000000" />
840 <parent revision="-1" node="0000000000000000000000000000000000000000" />
840 <parent revision="-1" node="0000000000000000000000000000000000000000" />
841 <author email="user@hostname">User Name</author>
841 <author email="user@hostname">User Name</author>
842 <date>1970-01-12T13:46:40+00:00</date>
842 <date>1970-01-12T13:46:40+00:00</date>
843 <msg xml:space="preserve">line 1
843 <msg xml:space="preserve">line 1
844 line 2</msg>
844 line 2</msg>
845 <paths>
845 <paths>
846 <path action="A">a</path>
846 <path action="A">a</path>
847 </paths>
847 </paths>
848 <extra key="branch">default</extra>
848 <extra key="branch">default</extra>
849 </logentry>
849 </logentry>
850 </log>
850 </log>
851
851
852
852
853 Test JSON style:
853 Test JSON style:
854
854
855 $ hg log -k nosuch -Tjson
855 $ hg log -k nosuch -Tjson
856 [
856 [
857 ]
857 ]
858
858
859 $ hg log -qr . -Tjson
859 $ hg log -qr . -Tjson
860 [
860 [
861 {
861 {
862 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
862 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
863 "rev": 8
863 "rev": 8
864 }
864 }
865 ]
865 ]
866
866
867 $ hg log -vpr . -Tjson --stat
867 $ hg log -vpr . -Tjson --stat
868 [
868 [
869 {
869 {
870 "bookmarks": [],
870 "bookmarks": [],
871 "branch": "default",
871 "branch": "default",
872 "date": [1577872860, 0],
872 "date": [1577872860, 0],
873 "desc": "third",
873 "desc": "third",
874 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n",
874 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n",
875 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
875 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
876 "files": ["fourth", "second", "third"],
876 "files": ["fourth", "second", "third"],
877 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
877 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
878 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
878 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
879 "phase": "draft",
879 "phase": "draft",
880 "rev": 8,
880 "rev": 8,
881 "tags": ["tip"],
881 "tags": ["tip"],
882 "user": "test"
882 "user": "test"
883 }
883 }
884 ]
884 ]
885
885
886 honor --git but not format-breaking diffopts
886 honor --git but not format-breaking diffopts
887 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
887 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
888 [
888 [
889 {
889 {
890 "bookmarks": [],
890 "bookmarks": [],
891 "branch": "default",
891 "branch": "default",
892 "date": [1577872860, 0],
892 "date": [1577872860, 0],
893 "desc": "third",
893 "desc": "third",
894 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n",
894 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n",
895 "files": ["fourth", "second", "third"],
895 "files": ["fourth", "second", "third"],
896 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
896 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
897 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
897 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
898 "phase": "draft",
898 "phase": "draft",
899 "rev": 8,
899 "rev": 8,
900 "tags": ["tip"],
900 "tags": ["tip"],
901 "user": "test"
901 "user": "test"
902 }
902 }
903 ]
903 ]
904
904
905 $ hg log -T json
905 $ hg log -T json
906 [
906 [
907 {
907 {
908 "bookmarks": [],
908 "bookmarks": [],
909 "branch": "default",
909 "branch": "default",
910 "date": [1577872860, 0],
910 "date": [1577872860, 0],
911 "desc": "third",
911 "desc": "third",
912 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
912 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
913 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
914 "phase": "draft",
914 "phase": "draft",
915 "rev": 8,
915 "rev": 8,
916 "tags": ["tip"],
916 "tags": ["tip"],
917 "user": "test"
917 "user": "test"
918 },
918 },
919 {
919 {
920 "bookmarks": [],
920 "bookmarks": [],
921 "branch": "default",
921 "branch": "default",
922 "date": [1000000, 0],
922 "date": [1000000, 0],
923 "desc": "second",
923 "desc": "second",
924 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
924 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
925 "parents": ["0000000000000000000000000000000000000000"],
925 "parents": ["0000000000000000000000000000000000000000"],
926 "phase": "draft",
926 "phase": "draft",
927 "rev": 7,
927 "rev": 7,
928 "tags": [],
928 "tags": [],
929 "user": "User Name <user@hostname>"
929 "user": "User Name <user@hostname>"
930 },
930 },
931 {
931 {
932 "bookmarks": [],
932 "bookmarks": [],
933 "branch": "default",
933 "branch": "default",
934 "date": [1500001, 0],
934 "date": [1500001, 0],
935 "desc": "merge",
935 "desc": "merge",
936 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
936 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
937 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
938 "phase": "draft",
938 "phase": "draft",
939 "rev": 6,
939 "rev": 6,
940 "tags": [],
940 "tags": [],
941 "user": "person"
941 "user": "person"
942 },
942 },
943 {
943 {
944 "bookmarks": [],
944 "bookmarks": [],
945 "branch": "default",
945 "branch": "default",
946 "date": [1500000, 0],
946 "date": [1500000, 0],
947 "desc": "new head",
947 "desc": "new head",
948 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
948 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
949 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
950 "phase": "draft",
950 "phase": "draft",
951 "rev": 5,
951 "rev": 5,
952 "tags": [],
952 "tags": [],
953 "user": "person"
953 "user": "person"
954 },
954 },
955 {
955 {
956 "bookmarks": [],
956 "bookmarks": [],
957 "branch": "foo",
957 "branch": "foo",
958 "date": [1400000, 0],
958 "date": [1400000, 0],
959 "desc": "new branch",
959 "desc": "new branch",
960 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
960 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
961 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
962 "phase": "draft",
962 "phase": "draft",
963 "rev": 4,
963 "rev": 4,
964 "tags": [],
964 "tags": [],
965 "user": "person"
965 "user": "person"
966 },
966 },
967 {
967 {
968 "bookmarks": [],
968 "bookmarks": [],
969 "branch": "default",
969 "branch": "default",
970 "date": [1300000, 0],
970 "date": [1300000, 0],
971 "desc": "no user, no domain",
971 "desc": "no user, no domain",
972 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
972 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
973 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
974 "phase": "draft",
974 "phase": "draft",
975 "rev": 3,
975 "rev": 3,
976 "tags": [],
976 "tags": [],
977 "user": "person"
977 "user": "person"
978 },
978 },
979 {
979 {
980 "bookmarks": [],
980 "bookmarks": [],
981 "branch": "default",
981 "branch": "default",
982 "date": [1200000, 0],
982 "date": [1200000, 0],
983 "desc": "no person",
983 "desc": "no person",
984 "node": "97054abb4ab824450e9164180baf491ae0078465",
984 "node": "97054abb4ab824450e9164180baf491ae0078465",
985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
985 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
986 "phase": "draft",
986 "phase": "draft",
987 "rev": 2,
987 "rev": 2,
988 "tags": [],
988 "tags": [],
989 "user": "other@place"
989 "user": "other@place"
990 },
990 },
991 {
991 {
992 "bookmarks": [],
992 "bookmarks": [],
993 "branch": "default",
993 "branch": "default",
994 "date": [1100000, 0],
994 "date": [1100000, 0],
995 "desc": "other 1\nother 2\n\nother 3",
995 "desc": "other 1\nother 2\n\nother 3",
996 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
996 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
997 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
998 "phase": "draft",
998 "phase": "draft",
999 "rev": 1,
999 "rev": 1,
1000 "tags": [],
1000 "tags": [],
1001 "user": "A. N. Other <other@place>"
1001 "user": "A. N. Other <other@place>"
1002 },
1002 },
1003 {
1003 {
1004 "bookmarks": [],
1004 "bookmarks": [],
1005 "branch": "default",
1005 "branch": "default",
1006 "date": [1000000, 0],
1006 "date": [1000000, 0],
1007 "desc": "line 1\nline 2",
1007 "desc": "line 1\nline 2",
1008 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1008 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1009 "parents": ["0000000000000000000000000000000000000000"],
1009 "parents": ["0000000000000000000000000000000000000000"],
1010 "phase": "draft",
1010 "phase": "draft",
1011 "rev": 0,
1011 "rev": 0,
1012 "tags": [],
1012 "tags": [],
1013 "user": "User Name <user@hostname>"
1013 "user": "User Name <user@hostname>"
1014 }
1014 }
1015 ]
1015 ]
1016
1016
1017 $ hg heads -v -Tjson
1017 $ hg heads -v -Tjson
1018 [
1018 [
1019 {
1019 {
1020 "bookmarks": [],
1020 "bookmarks": [],
1021 "branch": "default",
1021 "branch": "default",
1022 "date": [1577872860, 0],
1022 "date": [1577872860, 0],
1023 "desc": "third",
1023 "desc": "third",
1024 "files": ["fourth", "second", "third"],
1024 "files": ["fourth", "second", "third"],
1025 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1025 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1026 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1026 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1027 "phase": "draft",
1027 "phase": "draft",
1028 "rev": 8,
1028 "rev": 8,
1029 "tags": ["tip"],
1029 "tags": ["tip"],
1030 "user": "test"
1030 "user": "test"
1031 },
1031 },
1032 {
1032 {
1033 "bookmarks": [],
1033 "bookmarks": [],
1034 "branch": "default",
1034 "branch": "default",
1035 "date": [1500001, 0],
1035 "date": [1500001, 0],
1036 "desc": "merge",
1036 "desc": "merge",
1037 "files": [],
1037 "files": [],
1038 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1038 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1039 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1039 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1040 "phase": "draft",
1040 "phase": "draft",
1041 "rev": 6,
1041 "rev": 6,
1042 "tags": [],
1042 "tags": [],
1043 "user": "person"
1043 "user": "person"
1044 },
1044 },
1045 {
1045 {
1046 "bookmarks": [],
1046 "bookmarks": [],
1047 "branch": "foo",
1047 "branch": "foo",
1048 "date": [1400000, 0],
1048 "date": [1400000, 0],
1049 "desc": "new branch",
1049 "desc": "new branch",
1050 "files": [],
1050 "files": [],
1051 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1051 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1052 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1052 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1053 "phase": "draft",
1053 "phase": "draft",
1054 "rev": 4,
1054 "rev": 4,
1055 "tags": [],
1055 "tags": [],
1056 "user": "person"
1056 "user": "person"
1057 }
1057 }
1058 ]
1058 ]
1059
1059
1060 $ hg log --debug -Tjson
1060 $ hg log --debug -Tjson
1061 [
1061 [
1062 {
1062 {
1063 "added": ["fourth", "third"],
1063 "added": ["fourth", "third"],
1064 "bookmarks": [],
1064 "bookmarks": [],
1065 "branch": "default",
1065 "branch": "default",
1066 "date": [1577872860, 0],
1066 "date": [1577872860, 0],
1067 "desc": "third",
1067 "desc": "third",
1068 "extra": {"branch": "default"},
1068 "extra": {"branch": "default"},
1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1069 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
1070 "modified": [],
1070 "modified": [],
1071 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1071 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
1072 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1072 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
1073 "phase": "draft",
1073 "phase": "draft",
1074 "removed": ["second"],
1074 "removed": ["second"],
1075 "rev": 8,
1075 "rev": 8,
1076 "tags": ["tip"],
1076 "tags": ["tip"],
1077 "user": "test"
1077 "user": "test"
1078 },
1078 },
1079 {
1079 {
1080 "added": ["second"],
1080 "added": ["second"],
1081 "bookmarks": [],
1081 "bookmarks": [],
1082 "branch": "default",
1082 "branch": "default",
1083 "date": [1000000, 0],
1083 "date": [1000000, 0],
1084 "desc": "second",
1084 "desc": "second",
1085 "extra": {"branch": "default"},
1085 "extra": {"branch": "default"},
1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1086 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
1087 "modified": [],
1087 "modified": [],
1088 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1088 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
1089 "parents": ["0000000000000000000000000000000000000000"],
1089 "parents": ["0000000000000000000000000000000000000000"],
1090 "phase": "draft",
1090 "phase": "draft",
1091 "removed": [],
1091 "removed": [],
1092 "rev": 7,
1092 "rev": 7,
1093 "tags": [],
1093 "tags": [],
1094 "user": "User Name <user@hostname>"
1094 "user": "User Name <user@hostname>"
1095 },
1095 },
1096 {
1096 {
1097 "added": [],
1097 "added": [],
1098 "bookmarks": [],
1098 "bookmarks": [],
1099 "branch": "default",
1099 "branch": "default",
1100 "date": [1500001, 0],
1100 "date": [1500001, 0],
1101 "desc": "merge",
1101 "desc": "merge",
1102 "extra": {"branch": "default"},
1102 "extra": {"branch": "default"},
1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1103 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1104 "modified": [],
1104 "modified": [],
1105 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1105 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
1106 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1106 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
1107 "phase": "draft",
1107 "phase": "draft",
1108 "removed": [],
1108 "removed": [],
1109 "rev": 6,
1109 "rev": 6,
1110 "tags": [],
1110 "tags": [],
1111 "user": "person"
1111 "user": "person"
1112 },
1112 },
1113 {
1113 {
1114 "added": ["d"],
1114 "added": ["d"],
1115 "bookmarks": [],
1115 "bookmarks": [],
1116 "branch": "default",
1116 "branch": "default",
1117 "date": [1500000, 0],
1117 "date": [1500000, 0],
1118 "desc": "new head",
1118 "desc": "new head",
1119 "extra": {"branch": "default"},
1119 "extra": {"branch": "default"},
1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1120 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
1121 "modified": [],
1121 "modified": [],
1122 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1122 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
1123 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1123 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1124 "phase": "draft",
1124 "phase": "draft",
1125 "removed": [],
1125 "removed": [],
1126 "rev": 5,
1126 "rev": 5,
1127 "tags": [],
1127 "tags": [],
1128 "user": "person"
1128 "user": "person"
1129 },
1129 },
1130 {
1130 {
1131 "added": [],
1131 "added": [],
1132 "bookmarks": [],
1132 "bookmarks": [],
1133 "branch": "foo",
1133 "branch": "foo",
1134 "date": [1400000, 0],
1134 "date": [1400000, 0],
1135 "desc": "new branch",
1135 "desc": "new branch",
1136 "extra": {"branch": "foo"},
1136 "extra": {"branch": "foo"},
1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1137 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1138 "modified": [],
1138 "modified": [],
1139 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1139 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
1140 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1140 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
1141 "phase": "draft",
1141 "phase": "draft",
1142 "removed": [],
1142 "removed": [],
1143 "rev": 4,
1143 "rev": 4,
1144 "tags": [],
1144 "tags": [],
1145 "user": "person"
1145 "user": "person"
1146 },
1146 },
1147 {
1147 {
1148 "added": [],
1148 "added": [],
1149 "bookmarks": [],
1149 "bookmarks": [],
1150 "branch": "default",
1150 "branch": "default",
1151 "date": [1300000, 0],
1151 "date": [1300000, 0],
1152 "desc": "no user, no domain",
1152 "desc": "no user, no domain",
1153 "extra": {"branch": "default"},
1153 "extra": {"branch": "default"},
1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1154 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
1155 "modified": ["c"],
1155 "modified": ["c"],
1156 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1156 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
1157 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1157 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
1158 "phase": "draft",
1158 "phase": "draft",
1159 "removed": [],
1159 "removed": [],
1160 "rev": 3,
1160 "rev": 3,
1161 "tags": [],
1161 "tags": [],
1162 "user": "person"
1162 "user": "person"
1163 },
1163 },
1164 {
1164 {
1165 "added": ["c"],
1165 "added": ["c"],
1166 "bookmarks": [],
1166 "bookmarks": [],
1167 "branch": "default",
1167 "branch": "default",
1168 "date": [1200000, 0],
1168 "date": [1200000, 0],
1169 "desc": "no person",
1169 "desc": "no person",
1170 "extra": {"branch": "default"},
1170 "extra": {"branch": "default"},
1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1171 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
1172 "modified": [],
1172 "modified": [],
1173 "node": "97054abb4ab824450e9164180baf491ae0078465",
1173 "node": "97054abb4ab824450e9164180baf491ae0078465",
1174 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1174 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
1175 "phase": "draft",
1175 "phase": "draft",
1176 "removed": [],
1176 "removed": [],
1177 "rev": 2,
1177 "rev": 2,
1178 "tags": [],
1178 "tags": [],
1179 "user": "other@place"
1179 "user": "other@place"
1180 },
1180 },
1181 {
1181 {
1182 "added": ["b"],
1182 "added": ["b"],
1183 "bookmarks": [],
1183 "bookmarks": [],
1184 "branch": "default",
1184 "branch": "default",
1185 "date": [1100000, 0],
1185 "date": [1100000, 0],
1186 "desc": "other 1\nother 2\n\nother 3",
1186 "desc": "other 1\nother 2\n\nother 3",
1187 "extra": {"branch": "default"},
1187 "extra": {"branch": "default"},
1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1188 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
1189 "modified": [],
1189 "modified": [],
1190 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1190 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
1191 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1191 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
1192 "phase": "draft",
1192 "phase": "draft",
1193 "removed": [],
1193 "removed": [],
1194 "rev": 1,
1194 "rev": 1,
1195 "tags": [],
1195 "tags": [],
1196 "user": "A. N. Other <other@place>"
1196 "user": "A. N. Other <other@place>"
1197 },
1197 },
1198 {
1198 {
1199 "added": ["a"],
1199 "added": ["a"],
1200 "bookmarks": [],
1200 "bookmarks": [],
1201 "branch": "default",
1201 "branch": "default",
1202 "date": [1000000, 0],
1202 "date": [1000000, 0],
1203 "desc": "line 1\nline 2",
1203 "desc": "line 1\nline 2",
1204 "extra": {"branch": "default"},
1204 "extra": {"branch": "default"},
1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1205 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
1206 "modified": [],
1206 "modified": [],
1207 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1207 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
1208 "parents": ["0000000000000000000000000000000000000000"],
1208 "parents": ["0000000000000000000000000000000000000000"],
1209 "phase": "draft",
1209 "phase": "draft",
1210 "removed": [],
1210 "removed": [],
1211 "rev": 0,
1211 "rev": 0,
1212 "tags": [],
1212 "tags": [],
1213 "user": "User Name <user@hostname>"
1213 "user": "User Name <user@hostname>"
1214 }
1214 }
1215 ]
1215 ]
1216
1216
1217 Error if style not readable:
1217 Error if style not readable:
1218
1218
1219 #if unix-permissions no-root
1219 #if unix-permissions no-root
1220 $ touch q
1220 $ touch q
1221 $ chmod 0 q
1221 $ chmod 0 q
1222 $ hg log --style ./q
1222 $ hg log --style ./q
1223 abort: Permission denied: ./q
1223 abort: Permission denied: ./q
1224 [255]
1224 [255]
1225 #endif
1225 #endif
1226
1226
1227 Error if no style:
1227 Error if no style:
1228
1228
1229 $ hg log --style notexist
1229 $ hg log --style notexist
1230 abort: style 'notexist' not found
1230 abort: style 'notexist' not found
1231 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1231 (available styles: bisect, changelog, compact, default, phases, show, status, xml)
1232 [255]
1232 [255]
1233
1233
1234 $ hg log -T list
1234 $ hg log -T list
1235 available styles: bisect, changelog, compact, default, phases, show, status, xml
1235 available styles: bisect, changelog, compact, default, phases, show, status, xml
1236 abort: specify a template
1236 abort: specify a template
1237 [255]
1237 [255]
1238
1238
1239 Error if style missing key:
1239 Error if style missing key:
1240
1240
1241 $ echo 'q = q' > t
1241 $ echo 'q = q' > t
1242 $ hg log --style ./t
1242 $ hg log --style ./t
1243 abort: "changeset" not in template map
1243 abort: "changeset" not in template map
1244 [255]
1244 [255]
1245
1245
1246 Error if style missing value:
1246 Error if style missing value:
1247
1247
1248 $ echo 'changeset =' > t
1248 $ echo 'changeset =' > t
1249 $ hg log --style t
1249 $ hg log --style t
1250 hg: parse error at t:1: missing value
1250 hg: parse error at t:1: missing value
1251 [255]
1251 [255]
1252
1252
1253 Error if include fails:
1253 Error if include fails:
1254
1254
1255 $ echo 'changeset = q' >> t
1255 $ echo 'changeset = q' >> t
1256 #if unix-permissions no-root
1256 #if unix-permissions no-root
1257 $ hg log --style ./t
1257 $ hg log --style ./t
1258 abort: template file ./q: Permission denied
1258 abort: template file ./q: Permission denied
1259 [255]
1259 [255]
1260 $ rm -f q
1260 $ rm -f q
1261 #endif
1261 #endif
1262
1262
1263 Include works:
1263 Include works:
1264
1264
1265 $ echo '{rev}' > q
1265 $ echo '{rev}' > q
1266 $ hg log --style ./t
1266 $ hg log --style ./t
1267 8
1267 8
1268 7
1268 7
1269 6
1269 6
1270 5
1270 5
1271 4
1271 4
1272 3
1272 3
1273 2
1273 2
1274 1
1274 1
1275 0
1275 0
1276
1276
1277 Check that recursive reference does not fall into RuntimeError (issue4758):
1277 Check that recursive reference does not fall into RuntimeError (issue4758):
1278
1278
1279 common mistake:
1279 common mistake:
1280
1280
1281 $ cat << EOF > issue4758
1281 $ cat << EOF > issue4758
1282 > changeset = '{changeset}\n'
1282 > changeset = '{changeset}\n'
1283 > EOF
1283 > EOF
1284 $ hg log --style ./issue4758
1284 $ hg log --style ./issue4758
1285 abort: recursive reference 'changeset' in template
1285 abort: recursive reference 'changeset' in template
1286 [255]
1286 [255]
1287
1287
1288 circular reference:
1288 circular reference:
1289
1289
1290 $ cat << EOF > issue4758
1290 $ cat << EOF > issue4758
1291 > changeset = '{foo}'
1291 > changeset = '{foo}'
1292 > foo = '{changeset}'
1292 > foo = '{changeset}'
1293 > EOF
1293 > EOF
1294 $ hg log --style ./issue4758
1294 $ hg log --style ./issue4758
1295 abort: recursive reference 'foo' in template
1295 abort: recursive reference 'foo' in template
1296 [255]
1296 [255]
1297
1297
1298 buildmap() -> gettemplate(), where no thunk was made:
1298 buildmap() -> gettemplate(), where no thunk was made:
1299
1299
1300 $ cat << EOF > issue4758
1300 $ cat << EOF > issue4758
1301 > changeset = '{files % changeset}\n'
1301 > changeset = '{files % changeset}\n'
1302 > EOF
1302 > EOF
1303 $ hg log --style ./issue4758
1303 $ hg log --style ./issue4758
1304 abort: recursive reference 'changeset' in template
1304 abort: recursive reference 'changeset' in template
1305 [255]
1305 [255]
1306
1306
1307 not a recursion if a keyword of the same name exists:
1307 not a recursion if a keyword of the same name exists:
1308
1308
1309 $ cat << EOF > issue4758
1309 $ cat << EOF > issue4758
1310 > changeset = '{tags % rev}'
1310 > changeset = '{tags % rev}'
1311 > rev = '{rev} {tag}\n'
1311 > rev = '{rev} {tag}\n'
1312 > EOF
1312 > EOF
1313 $ hg log --style ./issue4758 -r tip
1313 $ hg log --style ./issue4758 -r tip
1314 8 tip
1314 8 tip
1315
1315
1316 Check that {phase} works correctly on parents:
1316 Check that {phase} works correctly on parents:
1317
1317
1318 $ cat << EOF > parentphase
1318 $ cat << EOF > parentphase
1319 > changeset_debug = '{rev} ({phase}):{parents}\n'
1319 > changeset_debug = '{rev} ({phase}):{parents}\n'
1320 > parent = ' {rev} ({phase})'
1320 > parent = ' {rev} ({phase})'
1321 > EOF
1321 > EOF
1322 $ hg phase -r 5 --public
1322 $ hg phase -r 5 --public
1323 $ hg phase -r 7 --secret --force
1323 $ hg phase -r 7 --secret --force
1324 $ hg log --debug -G --style ./parentphase
1324 $ hg log --debug -G --style ./parentphase
1325 @ 8 (secret): 7 (secret) -1 (public)
1325 @ 8 (secret): 7 (secret) -1 (public)
1326 |
1326 |
1327 o 7 (secret): -1 (public) -1 (public)
1327 o 7 (secret): -1 (public) -1 (public)
1328
1328
1329 o 6 (draft): 5 (public) 4 (draft)
1329 o 6 (draft): 5 (public) 4 (draft)
1330 |\
1330 |\
1331 | o 5 (public): 3 (public) -1 (public)
1331 | o 5 (public): 3 (public) -1 (public)
1332 | |
1332 | |
1333 o | 4 (draft): 3 (public) -1 (public)
1333 o | 4 (draft): 3 (public) -1 (public)
1334 |/
1334 |/
1335 o 3 (public): 2 (public) -1 (public)
1335 o 3 (public): 2 (public) -1 (public)
1336 |
1336 |
1337 o 2 (public): 1 (public) -1 (public)
1337 o 2 (public): 1 (public) -1 (public)
1338 |
1338 |
1339 o 1 (public): 0 (public) -1 (public)
1339 o 1 (public): 0 (public) -1 (public)
1340 |
1340 |
1341 o 0 (public): -1 (public) -1 (public)
1341 o 0 (public): -1 (public) -1 (public)
1342
1342
1343
1343
1344 Missing non-standard names give no error (backward compatibility):
1344 Missing non-standard names give no error (backward compatibility):
1345
1345
1346 $ echo "changeset = '{c}'" > t
1346 $ echo "changeset = '{c}'" > t
1347 $ hg log --style ./t
1347 $ hg log --style ./t
1348
1348
1349 Defining non-standard name works:
1349 Defining non-standard name works:
1350
1350
1351 $ cat <<EOF > t
1351 $ cat <<EOF > t
1352 > changeset = '{c}'
1352 > changeset = '{c}'
1353 > c = q
1353 > c = q
1354 > EOF
1354 > EOF
1355 $ hg log --style ./t
1355 $ hg log --style ./t
1356 8
1356 8
1357 7
1357 7
1358 6
1358 6
1359 5
1359 5
1360 4
1360 4
1361 3
1361 3
1362 2
1362 2
1363 1
1363 1
1364 0
1364 0
1365
1365
1366 ui.style works:
1366 ui.style works:
1367
1367
1368 $ echo '[ui]' > .hg/hgrc
1368 $ echo '[ui]' > .hg/hgrc
1369 $ echo 'style = t' >> .hg/hgrc
1369 $ echo 'style = t' >> .hg/hgrc
1370 $ hg log
1370 $ hg log
1371 8
1371 8
1372 7
1372 7
1373 6
1373 6
1374 5
1374 5
1375 4
1375 4
1376 3
1376 3
1377 2
1377 2
1378 1
1378 1
1379 0
1379 0
1380
1380
1381
1381
1382 Issue338:
1382 Issue338:
1383
1383
1384 $ hg log --style=changelog > changelog
1384 $ hg log --style=changelog > changelog
1385
1385
1386 $ cat changelog
1386 $ cat changelog
1387 2020-01-01 test <test>
1387 2020-01-01 test <test>
1388
1388
1389 * fourth, second, third:
1389 * fourth, second, third:
1390 third
1390 third
1391 [95c24699272e] [tip]
1391 [95c24699272e] [tip]
1392
1392
1393 1970-01-12 User Name <user@hostname>
1393 1970-01-12 User Name <user@hostname>
1394
1394
1395 * second:
1395 * second:
1396 second
1396 second
1397 [29114dbae42b]
1397 [29114dbae42b]
1398
1398
1399 1970-01-18 person <person>
1399 1970-01-18 person <person>
1400
1400
1401 * merge
1401 * merge
1402 [d41e714fe50d]
1402 [d41e714fe50d]
1403
1403
1404 * d:
1404 * d:
1405 new head
1405 new head
1406 [13207e5a10d9]
1406 [13207e5a10d9]
1407
1407
1408 1970-01-17 person <person>
1408 1970-01-17 person <person>
1409
1409
1410 * new branch
1410 * new branch
1411 [bbe44766e73d] <foo>
1411 [bbe44766e73d] <foo>
1412
1412
1413 1970-01-16 person <person>
1413 1970-01-16 person <person>
1414
1414
1415 * c:
1415 * c:
1416 no user, no domain
1416 no user, no domain
1417 [10e46f2dcbf4]
1417 [10e46f2dcbf4]
1418
1418
1419 1970-01-14 other <other@place>
1419 1970-01-14 other <other@place>
1420
1420
1421 * c:
1421 * c:
1422 no person
1422 no person
1423 [97054abb4ab8]
1423 [97054abb4ab8]
1424
1424
1425 1970-01-13 A. N. Other <other@place>
1425 1970-01-13 A. N. Other <other@place>
1426
1426
1427 * b:
1427 * b:
1428 other 1 other 2
1428 other 1 other 2
1429
1429
1430 other 3
1430 other 3
1431 [b608e9d1a3f0]
1431 [b608e9d1a3f0]
1432
1432
1433 1970-01-12 User Name <user@hostname>
1433 1970-01-12 User Name <user@hostname>
1434
1434
1435 * a:
1435 * a:
1436 line 1 line 2
1436 line 1 line 2
1437 [1e4e1b8f71e0]
1437 [1e4e1b8f71e0]
1438
1438
1439
1439
1440 Issue2130: xml output for 'hg heads' is malformed
1440 Issue2130: xml output for 'hg heads' is malformed
1441
1441
1442 $ hg heads --style changelog
1442 $ hg heads --style changelog
1443 2020-01-01 test <test>
1443 2020-01-01 test <test>
1444
1444
1445 * fourth, second, third:
1445 * fourth, second, third:
1446 third
1446 third
1447 [95c24699272e] [tip]
1447 [95c24699272e] [tip]
1448
1448
1449 1970-01-18 person <person>
1449 1970-01-18 person <person>
1450
1450
1451 * merge
1451 * merge
1452 [d41e714fe50d]
1452 [d41e714fe50d]
1453
1453
1454 1970-01-17 person <person>
1454 1970-01-17 person <person>
1455
1455
1456 * new branch
1456 * new branch
1457 [bbe44766e73d] <foo>
1457 [bbe44766e73d] <foo>
1458
1458
1459
1459
1460 Keys work:
1460 Keys work:
1461
1461
1462 $ for key in author branch branches date desc file_adds file_dels file_mods \
1462 $ for key in author branch branches date desc file_adds file_dels file_mods \
1463 > file_copies file_copies_switch files \
1463 > file_copies file_copies_switch files \
1464 > manifest node parents rev tags diffstat extras \
1464 > manifest node parents rev tags diffstat extras \
1465 > p1rev p2rev p1node p2node; do
1465 > p1rev p2rev p1node p2node; do
1466 > for mode in '' --verbose --debug; do
1466 > for mode in '' --verbose --debug; do
1467 > hg log $mode --template "$key$mode: {$key}\n"
1467 > hg log $mode --template "$key$mode: {$key}\n"
1468 > done
1468 > done
1469 > done
1469 > done
1470 author: test
1470 author: test
1471 author: User Name <user@hostname>
1471 author: User Name <user@hostname>
1472 author: person
1472 author: person
1473 author: person
1473 author: person
1474 author: person
1474 author: person
1475 author: person
1475 author: person
1476 author: other@place
1476 author: other@place
1477 author: A. N. Other <other@place>
1477 author: A. N. Other <other@place>
1478 author: User Name <user@hostname>
1478 author: User Name <user@hostname>
1479 author--verbose: test
1479 author--verbose: test
1480 author--verbose: User Name <user@hostname>
1480 author--verbose: User Name <user@hostname>
1481 author--verbose: person
1481 author--verbose: person
1482 author--verbose: person
1482 author--verbose: person
1483 author--verbose: person
1483 author--verbose: person
1484 author--verbose: person
1484 author--verbose: person
1485 author--verbose: other@place
1485 author--verbose: other@place
1486 author--verbose: A. N. Other <other@place>
1486 author--verbose: A. N. Other <other@place>
1487 author--verbose: User Name <user@hostname>
1487 author--verbose: User Name <user@hostname>
1488 author--debug: test
1488 author--debug: test
1489 author--debug: User Name <user@hostname>
1489 author--debug: User Name <user@hostname>
1490 author--debug: person
1490 author--debug: person
1491 author--debug: person
1491 author--debug: person
1492 author--debug: person
1492 author--debug: person
1493 author--debug: person
1493 author--debug: person
1494 author--debug: other@place
1494 author--debug: other@place
1495 author--debug: A. N. Other <other@place>
1495 author--debug: A. N. Other <other@place>
1496 author--debug: User Name <user@hostname>
1496 author--debug: User Name <user@hostname>
1497 branch: default
1497 branch: default
1498 branch: default
1498 branch: default
1499 branch: default
1499 branch: default
1500 branch: default
1500 branch: default
1501 branch: foo
1501 branch: foo
1502 branch: default
1502 branch: default
1503 branch: default
1503 branch: default
1504 branch: default
1504 branch: default
1505 branch: default
1505 branch: default
1506 branch--verbose: default
1506 branch--verbose: default
1507 branch--verbose: default
1507 branch--verbose: default
1508 branch--verbose: default
1508 branch--verbose: default
1509 branch--verbose: default
1509 branch--verbose: default
1510 branch--verbose: foo
1510 branch--verbose: foo
1511 branch--verbose: default
1511 branch--verbose: default
1512 branch--verbose: default
1512 branch--verbose: default
1513 branch--verbose: default
1513 branch--verbose: default
1514 branch--verbose: default
1514 branch--verbose: default
1515 branch--debug: default
1515 branch--debug: default
1516 branch--debug: default
1516 branch--debug: default
1517 branch--debug: default
1517 branch--debug: default
1518 branch--debug: default
1518 branch--debug: default
1519 branch--debug: foo
1519 branch--debug: foo
1520 branch--debug: default
1520 branch--debug: default
1521 branch--debug: default
1521 branch--debug: default
1522 branch--debug: default
1522 branch--debug: default
1523 branch--debug: default
1523 branch--debug: default
1524 branches:
1524 branches:
1525 branches:
1525 branches:
1526 branches:
1526 branches:
1527 branches:
1527 branches:
1528 branches: foo
1528 branches: foo
1529 branches:
1529 branches:
1530 branches:
1530 branches:
1531 branches:
1531 branches:
1532 branches:
1532 branches:
1533 branches--verbose:
1533 branches--verbose:
1534 branches--verbose:
1534 branches--verbose:
1535 branches--verbose:
1535 branches--verbose:
1536 branches--verbose:
1536 branches--verbose:
1537 branches--verbose: foo
1537 branches--verbose: foo
1538 branches--verbose:
1538 branches--verbose:
1539 branches--verbose:
1539 branches--verbose:
1540 branches--verbose:
1540 branches--verbose:
1541 branches--verbose:
1541 branches--verbose:
1542 branches--debug:
1542 branches--debug:
1543 branches--debug:
1543 branches--debug:
1544 branches--debug:
1544 branches--debug:
1545 branches--debug:
1545 branches--debug:
1546 branches--debug: foo
1546 branches--debug: foo
1547 branches--debug:
1547 branches--debug:
1548 branches--debug:
1548 branches--debug:
1549 branches--debug:
1549 branches--debug:
1550 branches--debug:
1550 branches--debug:
1551 date: 1577872860 0
1551 date: 1577872860 0
1552 date: 1000000 0
1552 date: 1000000 0
1553 date: 1500001 0
1553 date: 1500001 0
1554 date: 1500000 0
1554 date: 1500000 0
1555 date: 1400000 0
1555 date: 1400000 0
1556 date: 1300000 0
1556 date: 1300000 0
1557 date: 1200000 0
1557 date: 1200000 0
1558 date: 1100000 0
1558 date: 1100000 0
1559 date: 1000000 0
1559 date: 1000000 0
1560 date--verbose: 1577872860 0
1560 date--verbose: 1577872860 0
1561 date--verbose: 1000000 0
1561 date--verbose: 1000000 0
1562 date--verbose: 1500001 0
1562 date--verbose: 1500001 0
1563 date--verbose: 1500000 0
1563 date--verbose: 1500000 0
1564 date--verbose: 1400000 0
1564 date--verbose: 1400000 0
1565 date--verbose: 1300000 0
1565 date--verbose: 1300000 0
1566 date--verbose: 1200000 0
1566 date--verbose: 1200000 0
1567 date--verbose: 1100000 0
1567 date--verbose: 1100000 0
1568 date--verbose: 1000000 0
1568 date--verbose: 1000000 0
1569 date--debug: 1577872860 0
1569 date--debug: 1577872860 0
1570 date--debug: 1000000 0
1570 date--debug: 1000000 0
1571 date--debug: 1500001 0
1571 date--debug: 1500001 0
1572 date--debug: 1500000 0
1572 date--debug: 1500000 0
1573 date--debug: 1400000 0
1573 date--debug: 1400000 0
1574 date--debug: 1300000 0
1574 date--debug: 1300000 0
1575 date--debug: 1200000 0
1575 date--debug: 1200000 0
1576 date--debug: 1100000 0
1576 date--debug: 1100000 0
1577 date--debug: 1000000 0
1577 date--debug: 1000000 0
1578 desc: third
1578 desc: third
1579 desc: second
1579 desc: second
1580 desc: merge
1580 desc: merge
1581 desc: new head
1581 desc: new head
1582 desc: new branch
1582 desc: new branch
1583 desc: no user, no domain
1583 desc: no user, no domain
1584 desc: no person
1584 desc: no person
1585 desc: other 1
1585 desc: other 1
1586 other 2
1586 other 2
1587
1587
1588 other 3
1588 other 3
1589 desc: line 1
1589 desc: line 1
1590 line 2
1590 line 2
1591 desc--verbose: third
1591 desc--verbose: third
1592 desc--verbose: second
1592 desc--verbose: second
1593 desc--verbose: merge
1593 desc--verbose: merge
1594 desc--verbose: new head
1594 desc--verbose: new head
1595 desc--verbose: new branch
1595 desc--verbose: new branch
1596 desc--verbose: no user, no domain
1596 desc--verbose: no user, no domain
1597 desc--verbose: no person
1597 desc--verbose: no person
1598 desc--verbose: other 1
1598 desc--verbose: other 1
1599 other 2
1599 other 2
1600
1600
1601 other 3
1601 other 3
1602 desc--verbose: line 1
1602 desc--verbose: line 1
1603 line 2
1603 line 2
1604 desc--debug: third
1604 desc--debug: third
1605 desc--debug: second
1605 desc--debug: second
1606 desc--debug: merge
1606 desc--debug: merge
1607 desc--debug: new head
1607 desc--debug: new head
1608 desc--debug: new branch
1608 desc--debug: new branch
1609 desc--debug: no user, no domain
1609 desc--debug: no user, no domain
1610 desc--debug: no person
1610 desc--debug: no person
1611 desc--debug: other 1
1611 desc--debug: other 1
1612 other 2
1612 other 2
1613
1613
1614 other 3
1614 other 3
1615 desc--debug: line 1
1615 desc--debug: line 1
1616 line 2
1616 line 2
1617 file_adds: fourth third
1617 file_adds: fourth third
1618 file_adds: second
1618 file_adds: second
1619 file_adds:
1619 file_adds:
1620 file_adds: d
1620 file_adds: d
1621 file_adds:
1621 file_adds:
1622 file_adds:
1622 file_adds:
1623 file_adds: c
1623 file_adds: c
1624 file_adds: b
1624 file_adds: b
1625 file_adds: a
1625 file_adds: a
1626 file_adds--verbose: fourth third
1626 file_adds--verbose: fourth third
1627 file_adds--verbose: second
1627 file_adds--verbose: second
1628 file_adds--verbose:
1628 file_adds--verbose:
1629 file_adds--verbose: d
1629 file_adds--verbose: d
1630 file_adds--verbose:
1630 file_adds--verbose:
1631 file_adds--verbose:
1631 file_adds--verbose:
1632 file_adds--verbose: c
1632 file_adds--verbose: c
1633 file_adds--verbose: b
1633 file_adds--verbose: b
1634 file_adds--verbose: a
1634 file_adds--verbose: a
1635 file_adds--debug: fourth third
1635 file_adds--debug: fourth third
1636 file_adds--debug: second
1636 file_adds--debug: second
1637 file_adds--debug:
1637 file_adds--debug:
1638 file_adds--debug: d
1638 file_adds--debug: d
1639 file_adds--debug:
1639 file_adds--debug:
1640 file_adds--debug:
1640 file_adds--debug:
1641 file_adds--debug: c
1641 file_adds--debug: c
1642 file_adds--debug: b
1642 file_adds--debug: b
1643 file_adds--debug: a
1643 file_adds--debug: a
1644 file_dels: second
1644 file_dels: second
1645 file_dels:
1645 file_dels:
1646 file_dels:
1646 file_dels:
1647 file_dels:
1647 file_dels:
1648 file_dels:
1648 file_dels:
1649 file_dels:
1649 file_dels:
1650 file_dels:
1650 file_dels:
1651 file_dels:
1651 file_dels:
1652 file_dels:
1652 file_dels:
1653 file_dels--verbose: second
1653 file_dels--verbose: second
1654 file_dels--verbose:
1654 file_dels--verbose:
1655 file_dels--verbose:
1655 file_dels--verbose:
1656 file_dels--verbose:
1656 file_dels--verbose:
1657 file_dels--verbose:
1657 file_dels--verbose:
1658 file_dels--verbose:
1658 file_dels--verbose:
1659 file_dels--verbose:
1659 file_dels--verbose:
1660 file_dels--verbose:
1660 file_dels--verbose:
1661 file_dels--verbose:
1661 file_dels--verbose:
1662 file_dels--debug: second
1662 file_dels--debug: second
1663 file_dels--debug:
1663 file_dels--debug:
1664 file_dels--debug:
1664 file_dels--debug:
1665 file_dels--debug:
1665 file_dels--debug:
1666 file_dels--debug:
1666 file_dels--debug:
1667 file_dels--debug:
1667 file_dels--debug:
1668 file_dels--debug:
1668 file_dels--debug:
1669 file_dels--debug:
1669 file_dels--debug:
1670 file_dels--debug:
1670 file_dels--debug:
1671 file_mods:
1671 file_mods:
1672 file_mods:
1672 file_mods:
1673 file_mods:
1673 file_mods:
1674 file_mods:
1674 file_mods:
1675 file_mods:
1675 file_mods:
1676 file_mods: c
1676 file_mods: c
1677 file_mods:
1677 file_mods:
1678 file_mods:
1678 file_mods:
1679 file_mods:
1679 file_mods:
1680 file_mods--verbose:
1680 file_mods--verbose:
1681 file_mods--verbose:
1681 file_mods--verbose:
1682 file_mods--verbose:
1682 file_mods--verbose:
1683 file_mods--verbose:
1683 file_mods--verbose:
1684 file_mods--verbose:
1684 file_mods--verbose:
1685 file_mods--verbose: c
1685 file_mods--verbose: c
1686 file_mods--verbose:
1686 file_mods--verbose:
1687 file_mods--verbose:
1687 file_mods--verbose:
1688 file_mods--verbose:
1688 file_mods--verbose:
1689 file_mods--debug:
1689 file_mods--debug:
1690 file_mods--debug:
1690 file_mods--debug:
1691 file_mods--debug:
1691 file_mods--debug:
1692 file_mods--debug:
1692 file_mods--debug:
1693 file_mods--debug:
1693 file_mods--debug:
1694 file_mods--debug: c
1694 file_mods--debug: c
1695 file_mods--debug:
1695 file_mods--debug:
1696 file_mods--debug:
1696 file_mods--debug:
1697 file_mods--debug:
1697 file_mods--debug:
1698 file_copies: fourth (second)
1698 file_copies: fourth (second)
1699 file_copies:
1699 file_copies:
1700 file_copies:
1700 file_copies:
1701 file_copies:
1701 file_copies:
1702 file_copies:
1702 file_copies:
1703 file_copies:
1703 file_copies:
1704 file_copies:
1704 file_copies:
1705 file_copies:
1705 file_copies:
1706 file_copies:
1706 file_copies:
1707 file_copies--verbose: fourth (second)
1707 file_copies--verbose: fourth (second)
1708 file_copies--verbose:
1708 file_copies--verbose:
1709 file_copies--verbose:
1709 file_copies--verbose:
1710 file_copies--verbose:
1710 file_copies--verbose:
1711 file_copies--verbose:
1711 file_copies--verbose:
1712 file_copies--verbose:
1712 file_copies--verbose:
1713 file_copies--verbose:
1713 file_copies--verbose:
1714 file_copies--verbose:
1714 file_copies--verbose:
1715 file_copies--verbose:
1715 file_copies--verbose:
1716 file_copies--debug: fourth (second)
1716 file_copies--debug: fourth (second)
1717 file_copies--debug:
1717 file_copies--debug:
1718 file_copies--debug:
1718 file_copies--debug:
1719 file_copies--debug:
1719 file_copies--debug:
1720 file_copies--debug:
1720 file_copies--debug:
1721 file_copies--debug:
1721 file_copies--debug:
1722 file_copies--debug:
1722 file_copies--debug:
1723 file_copies--debug:
1723 file_copies--debug:
1724 file_copies--debug:
1724 file_copies--debug:
1725 file_copies_switch:
1725 file_copies_switch:
1726 file_copies_switch:
1726 file_copies_switch:
1727 file_copies_switch:
1727 file_copies_switch:
1728 file_copies_switch:
1728 file_copies_switch:
1729 file_copies_switch:
1729 file_copies_switch:
1730 file_copies_switch:
1730 file_copies_switch:
1731 file_copies_switch:
1731 file_copies_switch:
1732 file_copies_switch:
1732 file_copies_switch:
1733 file_copies_switch:
1733 file_copies_switch:
1734 file_copies_switch--verbose:
1734 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1735 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1736 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1737 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1738 file_copies_switch--verbose:
1739 file_copies_switch--verbose:
1739 file_copies_switch--verbose:
1740 file_copies_switch--verbose:
1740 file_copies_switch--verbose:
1741 file_copies_switch--verbose:
1741 file_copies_switch--verbose:
1742 file_copies_switch--verbose:
1742 file_copies_switch--verbose:
1743 file_copies_switch--debug:
1743 file_copies_switch--debug:
1744 file_copies_switch--debug:
1744 file_copies_switch--debug:
1745 file_copies_switch--debug:
1745 file_copies_switch--debug:
1746 file_copies_switch--debug:
1746 file_copies_switch--debug:
1747 file_copies_switch--debug:
1747 file_copies_switch--debug:
1748 file_copies_switch--debug:
1748 file_copies_switch--debug:
1749 file_copies_switch--debug:
1749 file_copies_switch--debug:
1750 file_copies_switch--debug:
1750 file_copies_switch--debug:
1751 file_copies_switch--debug:
1751 file_copies_switch--debug:
1752 files: fourth second third
1752 files: fourth second third
1753 files: second
1753 files: second
1754 files:
1754 files:
1755 files: d
1755 files: d
1756 files:
1756 files:
1757 files: c
1757 files: c
1758 files: c
1758 files: c
1759 files: b
1759 files: b
1760 files: a
1760 files: a
1761 files--verbose: fourth second third
1761 files--verbose: fourth second third
1762 files--verbose: second
1762 files--verbose: second
1763 files--verbose:
1763 files--verbose:
1764 files--verbose: d
1764 files--verbose: d
1765 files--verbose:
1765 files--verbose:
1766 files--verbose: c
1766 files--verbose: c
1767 files--verbose: c
1767 files--verbose: c
1768 files--verbose: b
1768 files--verbose: b
1769 files--verbose: a
1769 files--verbose: a
1770 files--debug: fourth second third
1770 files--debug: fourth second third
1771 files--debug: second
1771 files--debug: second
1772 files--debug:
1772 files--debug:
1773 files--debug: d
1773 files--debug: d
1774 files--debug:
1774 files--debug:
1775 files--debug: c
1775 files--debug: c
1776 files--debug: c
1776 files--debug: c
1777 files--debug: b
1777 files--debug: b
1778 files--debug: a
1778 files--debug: a
1779 manifest: 6:94961b75a2da
1779 manifest: 6:94961b75a2da
1780 manifest: 5:f2dbc354b94e
1780 manifest: 5:f2dbc354b94e
1781 manifest: 4:4dc3def4f9b4
1781 manifest: 4:4dc3def4f9b4
1782 manifest: 4:4dc3def4f9b4
1782 manifest: 4:4dc3def4f9b4
1783 manifest: 3:cb5a1327723b
1783 manifest: 3:cb5a1327723b
1784 manifest: 3:cb5a1327723b
1784 manifest: 3:cb5a1327723b
1785 manifest: 2:6e0e82995c35
1785 manifest: 2:6e0e82995c35
1786 manifest: 1:4e8d705b1e53
1786 manifest: 1:4e8d705b1e53
1787 manifest: 0:a0c8bcbbb45c
1787 manifest: 0:a0c8bcbbb45c
1788 manifest--verbose: 6:94961b75a2da
1788 manifest--verbose: 6:94961b75a2da
1789 manifest--verbose: 5:f2dbc354b94e
1789 manifest--verbose: 5:f2dbc354b94e
1790 manifest--verbose: 4:4dc3def4f9b4
1790 manifest--verbose: 4:4dc3def4f9b4
1791 manifest--verbose: 4:4dc3def4f9b4
1791 manifest--verbose: 4:4dc3def4f9b4
1792 manifest--verbose: 3:cb5a1327723b
1792 manifest--verbose: 3:cb5a1327723b
1793 manifest--verbose: 3:cb5a1327723b
1793 manifest--verbose: 3:cb5a1327723b
1794 manifest--verbose: 2:6e0e82995c35
1794 manifest--verbose: 2:6e0e82995c35
1795 manifest--verbose: 1:4e8d705b1e53
1795 manifest--verbose: 1:4e8d705b1e53
1796 manifest--verbose: 0:a0c8bcbbb45c
1796 manifest--verbose: 0:a0c8bcbbb45c
1797 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1797 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1798 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1798 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1799 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1799 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1800 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1800 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1801 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1801 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1802 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1802 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1803 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1803 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1804 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1804 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1805 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1805 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1806 node: 95c24699272ef57d062b8bccc32c878bf841784a
1806 node: 95c24699272ef57d062b8bccc32c878bf841784a
1807 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1807 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1808 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1808 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1809 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1809 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1810 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1810 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1811 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1811 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1812 node: 97054abb4ab824450e9164180baf491ae0078465
1812 node: 97054abb4ab824450e9164180baf491ae0078465
1813 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1813 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1814 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1814 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1815 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1815 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1816 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1816 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1817 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1817 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1818 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1818 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1819 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1819 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1820 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1820 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1821 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1821 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1822 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1822 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1823 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1823 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1824 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1824 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1825 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1825 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1826 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1826 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1827 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1827 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1828 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1828 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1829 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1829 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1830 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1830 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1831 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1831 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1832 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1832 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1833 parents:
1833 parents:
1834 parents: -1:000000000000
1834 parents: -1:000000000000
1835 parents: 5:13207e5a10d9 4:bbe44766e73d
1835 parents: 5:13207e5a10d9 4:bbe44766e73d
1836 parents: 3:10e46f2dcbf4
1836 parents: 3:10e46f2dcbf4
1837 parents:
1837 parents:
1838 parents:
1838 parents:
1839 parents:
1839 parents:
1840 parents:
1840 parents:
1841 parents:
1841 parents:
1842 parents--verbose:
1842 parents--verbose:
1843 parents--verbose: -1:000000000000
1843 parents--verbose: -1:000000000000
1844 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1844 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1845 parents--verbose: 3:10e46f2dcbf4
1845 parents--verbose: 3:10e46f2dcbf4
1846 parents--verbose:
1846 parents--verbose:
1847 parents--verbose:
1847 parents--verbose:
1848 parents--verbose:
1848 parents--verbose:
1849 parents--verbose:
1849 parents--verbose:
1850 parents--verbose:
1850 parents--verbose:
1851 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1851 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1852 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1852 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1853 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1853 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1854 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1854 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1855 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1855 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1856 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1856 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1857 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1857 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1858 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1858 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1859 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1859 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1860 rev: 8
1860 rev: 8
1861 rev: 7
1861 rev: 7
1862 rev: 6
1862 rev: 6
1863 rev: 5
1863 rev: 5
1864 rev: 4
1864 rev: 4
1865 rev: 3
1865 rev: 3
1866 rev: 2
1866 rev: 2
1867 rev: 1
1867 rev: 1
1868 rev: 0
1868 rev: 0
1869 rev--verbose: 8
1869 rev--verbose: 8
1870 rev--verbose: 7
1870 rev--verbose: 7
1871 rev--verbose: 6
1871 rev--verbose: 6
1872 rev--verbose: 5
1872 rev--verbose: 5
1873 rev--verbose: 4
1873 rev--verbose: 4
1874 rev--verbose: 3
1874 rev--verbose: 3
1875 rev--verbose: 2
1875 rev--verbose: 2
1876 rev--verbose: 1
1876 rev--verbose: 1
1877 rev--verbose: 0
1877 rev--verbose: 0
1878 rev--debug: 8
1878 rev--debug: 8
1879 rev--debug: 7
1879 rev--debug: 7
1880 rev--debug: 6
1880 rev--debug: 6
1881 rev--debug: 5
1881 rev--debug: 5
1882 rev--debug: 4
1882 rev--debug: 4
1883 rev--debug: 3
1883 rev--debug: 3
1884 rev--debug: 2
1884 rev--debug: 2
1885 rev--debug: 1
1885 rev--debug: 1
1886 rev--debug: 0
1886 rev--debug: 0
1887 tags: tip
1887 tags: tip
1888 tags:
1888 tags:
1889 tags:
1889 tags:
1890 tags:
1890 tags:
1891 tags:
1891 tags:
1892 tags:
1892 tags:
1893 tags:
1893 tags:
1894 tags:
1894 tags:
1895 tags:
1895 tags:
1896 tags--verbose: tip
1896 tags--verbose: tip
1897 tags--verbose:
1897 tags--verbose:
1898 tags--verbose:
1898 tags--verbose:
1899 tags--verbose:
1899 tags--verbose:
1900 tags--verbose:
1900 tags--verbose:
1901 tags--verbose:
1901 tags--verbose:
1902 tags--verbose:
1902 tags--verbose:
1903 tags--verbose:
1903 tags--verbose:
1904 tags--verbose:
1904 tags--verbose:
1905 tags--debug: tip
1905 tags--debug: tip
1906 tags--debug:
1906 tags--debug:
1907 tags--debug:
1907 tags--debug:
1908 tags--debug:
1908 tags--debug:
1909 tags--debug:
1909 tags--debug:
1910 tags--debug:
1910 tags--debug:
1911 tags--debug:
1911 tags--debug:
1912 tags--debug:
1912 tags--debug:
1913 tags--debug:
1913 tags--debug:
1914 diffstat: 3: +2/-1
1914 diffstat: 3: +2/-1
1915 diffstat: 1: +1/-0
1915 diffstat: 1: +1/-0
1916 diffstat: 0: +0/-0
1916 diffstat: 0: +0/-0
1917 diffstat: 1: +1/-0
1917 diffstat: 1: +1/-0
1918 diffstat: 0: +0/-0
1918 diffstat: 0: +0/-0
1919 diffstat: 1: +1/-0
1919 diffstat: 1: +1/-0
1920 diffstat: 1: +4/-0
1920 diffstat: 1: +4/-0
1921 diffstat: 1: +2/-0
1921 diffstat: 1: +2/-0
1922 diffstat: 1: +1/-0
1922 diffstat: 1: +1/-0
1923 diffstat--verbose: 3: +2/-1
1923 diffstat--verbose: 3: +2/-1
1924 diffstat--verbose: 1: +1/-0
1924 diffstat--verbose: 1: +1/-0
1925 diffstat--verbose: 0: +0/-0
1925 diffstat--verbose: 0: +0/-0
1926 diffstat--verbose: 1: +1/-0
1926 diffstat--verbose: 1: +1/-0
1927 diffstat--verbose: 0: +0/-0
1927 diffstat--verbose: 0: +0/-0
1928 diffstat--verbose: 1: +1/-0
1928 diffstat--verbose: 1: +1/-0
1929 diffstat--verbose: 1: +4/-0
1929 diffstat--verbose: 1: +4/-0
1930 diffstat--verbose: 1: +2/-0
1930 diffstat--verbose: 1: +2/-0
1931 diffstat--verbose: 1: +1/-0
1931 diffstat--verbose: 1: +1/-0
1932 diffstat--debug: 3: +2/-1
1932 diffstat--debug: 3: +2/-1
1933 diffstat--debug: 1: +1/-0
1933 diffstat--debug: 1: +1/-0
1934 diffstat--debug: 0: +0/-0
1934 diffstat--debug: 0: +0/-0
1935 diffstat--debug: 1: +1/-0
1935 diffstat--debug: 1: +1/-0
1936 diffstat--debug: 0: +0/-0
1936 diffstat--debug: 0: +0/-0
1937 diffstat--debug: 1: +1/-0
1937 diffstat--debug: 1: +1/-0
1938 diffstat--debug: 1: +4/-0
1938 diffstat--debug: 1: +4/-0
1939 diffstat--debug: 1: +2/-0
1939 diffstat--debug: 1: +2/-0
1940 diffstat--debug: 1: +1/-0
1940 diffstat--debug: 1: +1/-0
1941 extras: branch=default
1941 extras: branch=default
1942 extras: branch=default
1942 extras: branch=default
1943 extras: branch=default
1943 extras: branch=default
1944 extras: branch=default
1944 extras: branch=default
1945 extras: branch=foo
1945 extras: branch=foo
1946 extras: branch=default
1946 extras: branch=default
1947 extras: branch=default
1947 extras: branch=default
1948 extras: branch=default
1948 extras: branch=default
1949 extras: branch=default
1949 extras: branch=default
1950 extras--verbose: branch=default
1950 extras--verbose: branch=default
1951 extras--verbose: branch=default
1951 extras--verbose: branch=default
1952 extras--verbose: branch=default
1952 extras--verbose: branch=default
1953 extras--verbose: branch=default
1953 extras--verbose: branch=default
1954 extras--verbose: branch=foo
1954 extras--verbose: branch=foo
1955 extras--verbose: branch=default
1955 extras--verbose: branch=default
1956 extras--verbose: branch=default
1956 extras--verbose: branch=default
1957 extras--verbose: branch=default
1957 extras--verbose: branch=default
1958 extras--verbose: branch=default
1958 extras--verbose: branch=default
1959 extras--debug: branch=default
1959 extras--debug: branch=default
1960 extras--debug: branch=default
1960 extras--debug: branch=default
1961 extras--debug: branch=default
1961 extras--debug: branch=default
1962 extras--debug: branch=default
1962 extras--debug: branch=default
1963 extras--debug: branch=foo
1963 extras--debug: branch=foo
1964 extras--debug: branch=default
1964 extras--debug: branch=default
1965 extras--debug: branch=default
1965 extras--debug: branch=default
1966 extras--debug: branch=default
1966 extras--debug: branch=default
1967 extras--debug: branch=default
1967 extras--debug: branch=default
1968 p1rev: 7
1968 p1rev: 7
1969 p1rev: -1
1969 p1rev: -1
1970 p1rev: 5
1970 p1rev: 5
1971 p1rev: 3
1971 p1rev: 3
1972 p1rev: 3
1972 p1rev: 3
1973 p1rev: 2
1973 p1rev: 2
1974 p1rev: 1
1974 p1rev: 1
1975 p1rev: 0
1975 p1rev: 0
1976 p1rev: -1
1976 p1rev: -1
1977 p1rev--verbose: 7
1977 p1rev--verbose: 7
1978 p1rev--verbose: -1
1978 p1rev--verbose: -1
1979 p1rev--verbose: 5
1979 p1rev--verbose: 5
1980 p1rev--verbose: 3
1980 p1rev--verbose: 3
1981 p1rev--verbose: 3
1981 p1rev--verbose: 3
1982 p1rev--verbose: 2
1982 p1rev--verbose: 2
1983 p1rev--verbose: 1
1983 p1rev--verbose: 1
1984 p1rev--verbose: 0
1984 p1rev--verbose: 0
1985 p1rev--verbose: -1
1985 p1rev--verbose: -1
1986 p1rev--debug: 7
1986 p1rev--debug: 7
1987 p1rev--debug: -1
1987 p1rev--debug: -1
1988 p1rev--debug: 5
1988 p1rev--debug: 5
1989 p1rev--debug: 3
1989 p1rev--debug: 3
1990 p1rev--debug: 3
1990 p1rev--debug: 3
1991 p1rev--debug: 2
1991 p1rev--debug: 2
1992 p1rev--debug: 1
1992 p1rev--debug: 1
1993 p1rev--debug: 0
1993 p1rev--debug: 0
1994 p1rev--debug: -1
1994 p1rev--debug: -1
1995 p2rev: -1
1995 p2rev: -1
1996 p2rev: -1
1996 p2rev: -1
1997 p2rev: 4
1997 p2rev: 4
1998 p2rev: -1
1998 p2rev: -1
1999 p2rev: -1
1999 p2rev: -1
2000 p2rev: -1
2000 p2rev: -1
2001 p2rev: -1
2001 p2rev: -1
2002 p2rev: -1
2002 p2rev: -1
2003 p2rev: -1
2003 p2rev: -1
2004 p2rev--verbose: -1
2004 p2rev--verbose: -1
2005 p2rev--verbose: -1
2005 p2rev--verbose: -1
2006 p2rev--verbose: 4
2006 p2rev--verbose: 4
2007 p2rev--verbose: -1
2007 p2rev--verbose: -1
2008 p2rev--verbose: -1
2008 p2rev--verbose: -1
2009 p2rev--verbose: -1
2009 p2rev--verbose: -1
2010 p2rev--verbose: -1
2010 p2rev--verbose: -1
2011 p2rev--verbose: -1
2011 p2rev--verbose: -1
2012 p2rev--verbose: -1
2012 p2rev--verbose: -1
2013 p2rev--debug: -1
2013 p2rev--debug: -1
2014 p2rev--debug: -1
2014 p2rev--debug: -1
2015 p2rev--debug: 4
2015 p2rev--debug: 4
2016 p2rev--debug: -1
2016 p2rev--debug: -1
2017 p2rev--debug: -1
2017 p2rev--debug: -1
2018 p2rev--debug: -1
2018 p2rev--debug: -1
2019 p2rev--debug: -1
2019 p2rev--debug: -1
2020 p2rev--debug: -1
2020 p2rev--debug: -1
2021 p2rev--debug: -1
2021 p2rev--debug: -1
2022 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2022 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2023 p1node: 0000000000000000000000000000000000000000
2023 p1node: 0000000000000000000000000000000000000000
2024 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2024 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
2025 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2025 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2026 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2026 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2027 p1node: 97054abb4ab824450e9164180baf491ae0078465
2027 p1node: 97054abb4ab824450e9164180baf491ae0078465
2028 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2028 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2029 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2029 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
2030 p1node: 0000000000000000000000000000000000000000
2030 p1node: 0000000000000000000000000000000000000000
2031 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2031 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2032 p1node--verbose: 0000000000000000000000000000000000000000
2032 p1node--verbose: 0000000000000000000000000000000000000000
2033 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2033 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
2034 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2034 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2035 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2035 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2036 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2036 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
2037 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2037 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2038 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2038 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
2039 p1node--verbose: 0000000000000000000000000000000000000000
2039 p1node--verbose: 0000000000000000000000000000000000000000
2040 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2040 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
2041 p1node--debug: 0000000000000000000000000000000000000000
2041 p1node--debug: 0000000000000000000000000000000000000000
2042 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2042 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
2043 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2043 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2044 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2044 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
2045 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2045 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
2046 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2046 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2047 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2047 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
2048 p1node--debug: 0000000000000000000000000000000000000000
2048 p1node--debug: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2049 p2node: 0000000000000000000000000000000000000000
2050 p2node: 0000000000000000000000000000000000000000
2050 p2node: 0000000000000000000000000000000000000000
2051 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2051 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2052 p2node: 0000000000000000000000000000000000000000
2052 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2053 p2node: 0000000000000000000000000000000000000000
2054 p2node: 0000000000000000000000000000000000000000
2054 p2node: 0000000000000000000000000000000000000000
2055 p2node: 0000000000000000000000000000000000000000
2055 p2node: 0000000000000000000000000000000000000000
2056 p2node: 0000000000000000000000000000000000000000
2056 p2node: 0000000000000000000000000000000000000000
2057 p2node: 0000000000000000000000000000000000000000
2057 p2node: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2058 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: 0000000000000000000000000000000000000000
2059 p2node--verbose: 0000000000000000000000000000000000000000
2060 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2060 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2061 p2node--verbose: 0000000000000000000000000000000000000000
2061 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2062 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--verbose: 0000000000000000000000000000000000000000
2063 p2node--verbose: 0000000000000000000000000000000000000000
2064 p2node--verbose: 0000000000000000000000000000000000000000
2064 p2node--verbose: 0000000000000000000000000000000000000000
2065 p2node--verbose: 0000000000000000000000000000000000000000
2065 p2node--verbose: 0000000000000000000000000000000000000000
2066 p2node--verbose: 0000000000000000000000000000000000000000
2066 p2node--verbose: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2067 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: 0000000000000000000000000000000000000000
2068 p2node--debug: 0000000000000000000000000000000000000000
2069 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2069 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
2070 p2node--debug: 0000000000000000000000000000000000000000
2070 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2071 p2node--debug: 0000000000000000000000000000000000000000
2072 p2node--debug: 0000000000000000000000000000000000000000
2072 p2node--debug: 0000000000000000000000000000000000000000
2073 p2node--debug: 0000000000000000000000000000000000000000
2073 p2node--debug: 0000000000000000000000000000000000000000
2074 p2node--debug: 0000000000000000000000000000000000000000
2074 p2node--debug: 0000000000000000000000000000000000000000
2075 p2node--debug: 0000000000000000000000000000000000000000
2075 p2node--debug: 0000000000000000000000000000000000000000
2076
2076
2077 Filters work:
2077 Filters work:
2078
2078
2079 $ hg log --template '{author|domain}\n'
2079 $ hg log --template '{author|domain}\n'
2080
2080
2081 hostname
2081 hostname
2082
2082
2083
2083
2084
2084
2085
2085
2086 place
2086 place
2087 place
2087 place
2088 hostname
2088 hostname
2089
2089
2090 $ hg log --template '{author|person}\n'
2090 $ hg log --template '{author|person}\n'
2091 test
2091 test
2092 User Name
2092 User Name
2093 person
2093 person
2094 person
2094 person
2095 person
2095 person
2096 person
2096 person
2097 other
2097 other
2098 A. N. Other
2098 A. N. Other
2099 User Name
2099 User Name
2100
2100
2101 $ hg log --template '{author|user}\n'
2101 $ hg log --template '{author|user}\n'
2102 test
2102 test
2103 user
2103 user
2104 person
2104 person
2105 person
2105 person
2106 person
2106 person
2107 person
2107 person
2108 other
2108 other
2109 other
2109 other
2110 user
2110 user
2111
2111
2112 $ hg log --template '{date|date}\n'
2112 $ hg log --template '{date|date}\n'
2113 Wed Jan 01 10:01:00 2020 +0000
2113 Wed Jan 01 10:01:00 2020 +0000
2114 Mon Jan 12 13:46:40 1970 +0000
2114 Mon Jan 12 13:46:40 1970 +0000
2115 Sun Jan 18 08:40:01 1970 +0000
2115 Sun Jan 18 08:40:01 1970 +0000
2116 Sun Jan 18 08:40:00 1970 +0000
2116 Sun Jan 18 08:40:00 1970 +0000
2117 Sat Jan 17 04:53:20 1970 +0000
2117 Sat Jan 17 04:53:20 1970 +0000
2118 Fri Jan 16 01:06:40 1970 +0000
2118 Fri Jan 16 01:06:40 1970 +0000
2119 Wed Jan 14 21:20:00 1970 +0000
2119 Wed Jan 14 21:20:00 1970 +0000
2120 Tue Jan 13 17:33:20 1970 +0000
2120 Tue Jan 13 17:33:20 1970 +0000
2121 Mon Jan 12 13:46:40 1970 +0000
2121 Mon Jan 12 13:46:40 1970 +0000
2122
2122
2123 $ hg log --template '{date|isodate}\n'
2123 $ hg log --template '{date|isodate}\n'
2124 2020-01-01 10:01 +0000
2124 2020-01-01 10:01 +0000
2125 1970-01-12 13:46 +0000
2125 1970-01-12 13:46 +0000
2126 1970-01-18 08:40 +0000
2126 1970-01-18 08:40 +0000
2127 1970-01-18 08:40 +0000
2127 1970-01-18 08:40 +0000
2128 1970-01-17 04:53 +0000
2128 1970-01-17 04:53 +0000
2129 1970-01-16 01:06 +0000
2129 1970-01-16 01:06 +0000
2130 1970-01-14 21:20 +0000
2130 1970-01-14 21:20 +0000
2131 1970-01-13 17:33 +0000
2131 1970-01-13 17:33 +0000
2132 1970-01-12 13:46 +0000
2132 1970-01-12 13:46 +0000
2133
2133
2134 $ hg log --template '{date|isodatesec}\n'
2134 $ hg log --template '{date|isodatesec}\n'
2135 2020-01-01 10:01:00 +0000
2135 2020-01-01 10:01:00 +0000
2136 1970-01-12 13:46:40 +0000
2136 1970-01-12 13:46:40 +0000
2137 1970-01-18 08:40:01 +0000
2137 1970-01-18 08:40:01 +0000
2138 1970-01-18 08:40:00 +0000
2138 1970-01-18 08:40:00 +0000
2139 1970-01-17 04:53:20 +0000
2139 1970-01-17 04:53:20 +0000
2140 1970-01-16 01:06:40 +0000
2140 1970-01-16 01:06:40 +0000
2141 1970-01-14 21:20:00 +0000
2141 1970-01-14 21:20:00 +0000
2142 1970-01-13 17:33:20 +0000
2142 1970-01-13 17:33:20 +0000
2143 1970-01-12 13:46:40 +0000
2143 1970-01-12 13:46:40 +0000
2144
2144
2145 $ hg log --template '{date|rfc822date}\n'
2145 $ hg log --template '{date|rfc822date}\n'
2146 Wed, 01 Jan 2020 10:01:00 +0000
2146 Wed, 01 Jan 2020 10:01:00 +0000
2147 Mon, 12 Jan 1970 13:46:40 +0000
2147 Mon, 12 Jan 1970 13:46:40 +0000
2148 Sun, 18 Jan 1970 08:40:01 +0000
2148 Sun, 18 Jan 1970 08:40:01 +0000
2149 Sun, 18 Jan 1970 08:40:00 +0000
2149 Sun, 18 Jan 1970 08:40:00 +0000
2150 Sat, 17 Jan 1970 04:53:20 +0000
2150 Sat, 17 Jan 1970 04:53:20 +0000
2151 Fri, 16 Jan 1970 01:06:40 +0000
2151 Fri, 16 Jan 1970 01:06:40 +0000
2152 Wed, 14 Jan 1970 21:20:00 +0000
2152 Wed, 14 Jan 1970 21:20:00 +0000
2153 Tue, 13 Jan 1970 17:33:20 +0000
2153 Tue, 13 Jan 1970 17:33:20 +0000
2154 Mon, 12 Jan 1970 13:46:40 +0000
2154 Mon, 12 Jan 1970 13:46:40 +0000
2155
2155
2156 $ hg log --template '{desc|firstline}\n'
2156 $ hg log --template '{desc|firstline}\n'
2157 third
2157 third
2158 second
2158 second
2159 merge
2159 merge
2160 new head
2160 new head
2161 new branch
2161 new branch
2162 no user, no domain
2162 no user, no domain
2163 no person
2163 no person
2164 other 1
2164 other 1
2165 line 1
2165 line 1
2166
2166
2167 $ hg log --template '{node|short}\n'
2167 $ hg log --template '{node|short}\n'
2168 95c24699272e
2168 95c24699272e
2169 29114dbae42b
2169 29114dbae42b
2170 d41e714fe50d
2170 d41e714fe50d
2171 13207e5a10d9
2171 13207e5a10d9
2172 bbe44766e73d
2172 bbe44766e73d
2173 10e46f2dcbf4
2173 10e46f2dcbf4
2174 97054abb4ab8
2174 97054abb4ab8
2175 b608e9d1a3f0
2175 b608e9d1a3f0
2176 1e4e1b8f71e0
2176 1e4e1b8f71e0
2177
2177
2178 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2178 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
2179 <changeset author="test"/>
2179 <changeset author="test"/>
2180 <changeset author="User Name &lt;user@hostname&gt;"/>
2180 <changeset author="User Name &lt;user@hostname&gt;"/>
2181 <changeset author="person"/>
2181 <changeset author="person"/>
2182 <changeset author="person"/>
2182 <changeset author="person"/>
2183 <changeset author="person"/>
2183 <changeset author="person"/>
2184 <changeset author="person"/>
2184 <changeset author="person"/>
2185 <changeset author="other@place"/>
2185 <changeset author="other@place"/>
2186 <changeset author="A. N. Other &lt;other@place&gt;"/>
2186 <changeset author="A. N. Other &lt;other@place&gt;"/>
2187 <changeset author="User Name &lt;user@hostname&gt;"/>
2187 <changeset author="User Name &lt;user@hostname&gt;"/>
2188
2188
2189 $ hg log --template '{rev}: {children}\n'
2189 $ hg log --template '{rev}: {children}\n'
2190 8:
2190 8:
2191 7: 8:95c24699272e
2191 7: 8:95c24699272e
2192 6:
2192 6:
2193 5: 6:d41e714fe50d
2193 5: 6:d41e714fe50d
2194 4: 6:d41e714fe50d
2194 4: 6:d41e714fe50d
2195 3: 4:bbe44766e73d 5:13207e5a10d9
2195 3: 4:bbe44766e73d 5:13207e5a10d9
2196 2: 3:10e46f2dcbf4
2196 2: 3:10e46f2dcbf4
2197 1: 2:97054abb4ab8
2197 1: 2:97054abb4ab8
2198 0: 1:b608e9d1a3f0
2198 0: 1:b608e9d1a3f0
2199
2199
2200 Formatnode filter works:
2200 Formatnode filter works:
2201
2201
2202 $ hg -q log -r 0 --template '{node|formatnode}\n'
2202 $ hg -q log -r 0 --template '{node|formatnode}\n'
2203 1e4e1b8f71e0
2203 1e4e1b8f71e0
2204
2204
2205 $ hg log -r 0 --template '{node|formatnode}\n'
2205 $ hg log -r 0 --template '{node|formatnode}\n'
2206 1e4e1b8f71e0
2206 1e4e1b8f71e0
2207
2207
2208 $ hg -v log -r 0 --template '{node|formatnode}\n'
2208 $ hg -v log -r 0 --template '{node|formatnode}\n'
2209 1e4e1b8f71e0
2209 1e4e1b8f71e0
2210
2210
2211 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2211 $ hg --debug log -r 0 --template '{node|formatnode}\n'
2212 1e4e1b8f71e05681d422154f5421e385fec3454f
2212 1e4e1b8f71e05681d422154f5421e385fec3454f
2213
2213
2214 Age filter:
2214 Age filter:
2215
2215
2216 $ hg init unstable-hash
2216 $ hg init unstable-hash
2217 $ cd unstable-hash
2217 $ cd unstable-hash
2218 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2218 $ hg log --template '{date|age}\n' > /dev/null || exit 1
2219
2219
2220 >>> from __future__ import absolute_import
2220 >>> from __future__ import absolute_import
2221 >>> import datetime
2221 >>> import datetime
2222 >>> fp = open('a', 'wb')
2222 >>> fp = open('a', 'wb')
2223 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2223 >>> n = datetime.datetime.now() + datetime.timedelta(366 * 7)
2224 >>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None
2224 >>> fp.write(b'%d-%d-%d 00:00' % (n.year, n.month, n.day)) and None
2225 >>> fp.close()
2225 >>> fp.close()
2226 $ hg add a
2226 $ hg add a
2227 $ hg commit -m future -d "`cat a`"
2227 $ hg commit -m future -d "`cat a`"
2228
2228
2229 $ hg log -l1 --template '{date|age}\n'
2229 $ hg log -l1 --template '{date|age}\n'
2230 7 years from now
2230 7 years from now
2231
2231
2232 $ cd ..
2232 $ cd ..
2233 $ rm -rf unstable-hash
2233 $ rm -rf unstable-hash
2234
2234
2235 Filename filters:
2235 Filename filters:
2236
2236
2237 $ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n'
2237 $ hg debugtemplate '{"foo/bar"|basename}|{"foo/"|basename}|{"foo"|basename}|\n'
2238 bar||foo|
2238 bar||foo|
2239 $ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n'
2239 $ hg debugtemplate '{"foo/bar"|dirname}|{"foo/"|dirname}|{"foo"|dirname}|\n'
2240 foo|foo||
2240 foo|foo||
2241 $ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n'
2241 $ hg debugtemplate '{"foo/bar"|stripdir}|{"foo/"|stripdir}|{"foo"|stripdir}|\n'
2242 foo|foo|foo|
2242 foo|foo|foo|
2243
2243
2244 Add a dummy commit to make up for the instability of the above:
2244 Add a dummy commit to make up for the instability of the above:
2245
2245
2246 $ echo a > a
2246 $ echo a > a
2247 $ hg add a
2247 $ hg add a
2248 $ hg ci -m future
2248 $ hg ci -m future
2249
2249
2250 Count filter:
2250 Count filter:
2251
2251
2252 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2252 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2253 40 12
2253 40 12
2254
2254
2255 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2255 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2256 0 1 4
2256 0 1 4
2257
2257
2258 $ hg log -G --template '{rev}: children: {children|count}, \
2258 $ hg log -G --template '{rev}: children: {children|count}, \
2259 > tags: {tags|count}, file_adds: {file_adds|count}, \
2259 > tags: {tags|count}, file_adds: {file_adds|count}, \
2260 > ancestors: {revset("ancestors(%s)", rev)|count}'
2260 > ancestors: {revset("ancestors(%s)", rev)|count}'
2261 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2261 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2262 |
2262 |
2263 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2263 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2264 |
2264 |
2265 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2265 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2266
2266
2267 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2267 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2268 |\
2268 |\
2269 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2269 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2270 | |
2270 | |
2271 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2271 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2272 |/
2272 |/
2273 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2273 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2274 |
2274 |
2275 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2275 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2276 |
2276 |
2277 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2277 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2278 |
2278 |
2279 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2279 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2280
2280
2281
2281
2282 $ hg log -l1 -T '{termwidth|count}\n'
2282 $ hg log -l1 -T '{termwidth|count}\n'
2283 hg: parse error: not countable
2283 hg: parse error: not countable
2284 (template filter 'count' is not compatible with keyword 'termwidth')
2284 (template filter 'count' is not compatible with keyword 'termwidth')
2285 [255]
2285 [255]
2286
2286
2287 Upper/lower filters:
2287 Upper/lower filters:
2288
2288
2289 $ hg log -r0 --template '{branch|upper}\n'
2289 $ hg log -r0 --template '{branch|upper}\n'
2290 DEFAULT
2290 DEFAULT
2291 $ hg log -r0 --template '{author|lower}\n'
2291 $ hg log -r0 --template '{author|lower}\n'
2292 user name <user@hostname>
2292 user name <user@hostname>
2293 $ hg log -r0 --template '{date|upper}\n'
2293 $ hg log -r0 --template '{date|upper}\n'
2294 1000000 0
2294 1000000 0
2295
2295
2296 Add a commit that does all possible modifications at once
2296 Add a commit that does all possible modifications at once
2297
2297
2298 $ echo modify >> third
2298 $ echo modify >> third
2299 $ touch b
2299 $ touch b
2300 $ hg add b
2300 $ hg add b
2301 $ hg mv fourth fifth
2301 $ hg mv fourth fifth
2302 $ hg rm a
2302 $ hg rm a
2303 $ hg ci -m "Modify, add, remove, rename"
2303 $ hg ci -m "Modify, add, remove, rename"
2304
2304
2305 Check the status template
2305 Check the status template
2306
2306
2307 $ cat <<EOF >> $HGRCPATH
2307 $ cat <<EOF >> $HGRCPATH
2308 > [extensions]
2308 > [extensions]
2309 > color=
2309 > color=
2310 > EOF
2310 > EOF
2311
2311
2312 $ hg log -T status -r 10
2312 $ hg log -T status -r 10
2313 changeset: 10:0f9759ec227a
2313 changeset: 10:0f9759ec227a
2314 tag: tip
2314 tag: tip
2315 user: test
2315 user: test
2316 date: Thu Jan 01 00:00:00 1970 +0000
2316 date: Thu Jan 01 00:00:00 1970 +0000
2317 summary: Modify, add, remove, rename
2317 summary: Modify, add, remove, rename
2318 files:
2318 files:
2319 M third
2319 M third
2320 A b
2320 A b
2321 A fifth
2321 A fifth
2322 R a
2322 R a
2323 R fourth
2323 R fourth
2324
2324
2325 $ hg log -T status -C -r 10
2325 $ hg log -T status -C -r 10
2326 changeset: 10:0f9759ec227a
2326 changeset: 10:0f9759ec227a
2327 tag: tip
2327 tag: tip
2328 user: test
2328 user: test
2329 date: Thu Jan 01 00:00:00 1970 +0000
2329 date: Thu Jan 01 00:00:00 1970 +0000
2330 summary: Modify, add, remove, rename
2330 summary: Modify, add, remove, rename
2331 files:
2331 files:
2332 M third
2332 M third
2333 A b
2333 A b
2334 A fifth
2334 A fifth
2335 fourth
2335 fourth
2336 R a
2336 R a
2337 R fourth
2337 R fourth
2338
2338
2339 $ hg log -T status -C -r 10 -v
2339 $ hg log -T status -C -r 10 -v
2340 changeset: 10:0f9759ec227a
2340 changeset: 10:0f9759ec227a
2341 tag: tip
2341 tag: tip
2342 user: test
2342 user: test
2343 date: Thu Jan 01 00:00:00 1970 +0000
2343 date: Thu Jan 01 00:00:00 1970 +0000
2344 description:
2344 description:
2345 Modify, add, remove, rename
2345 Modify, add, remove, rename
2346
2346
2347 files:
2347 files:
2348 M third
2348 M third
2349 A b
2349 A b
2350 A fifth
2350 A fifth
2351 fourth
2351 fourth
2352 R a
2352 R a
2353 R fourth
2353 R fourth
2354
2354
2355 $ hg log -T status -C -r 10 --debug
2355 $ hg log -T status -C -r 10 --debug
2356 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2356 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2357 tag: tip
2357 tag: tip
2358 phase: secret
2358 phase: secret
2359 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2359 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2360 parent: -1:0000000000000000000000000000000000000000
2360 parent: -1:0000000000000000000000000000000000000000
2361 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2361 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2362 user: test
2362 user: test
2363 date: Thu Jan 01 00:00:00 1970 +0000
2363 date: Thu Jan 01 00:00:00 1970 +0000
2364 extra: branch=default
2364 extra: branch=default
2365 description:
2365 description:
2366 Modify, add, remove, rename
2366 Modify, add, remove, rename
2367
2367
2368 files:
2368 files:
2369 M third
2369 M third
2370 A b
2370 A b
2371 A fifth
2371 A fifth
2372 fourth
2372 fourth
2373 R a
2373 R a
2374 R fourth
2374 R fourth
2375
2375
2376 $ hg log -T status -C -r 10 --quiet
2376 $ hg log -T status -C -r 10 --quiet
2377 10:0f9759ec227a
2377 10:0f9759ec227a
2378 $ hg --color=debug log -T status -r 10
2378 $ hg --color=debug log -T status -r 10
2379 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2379 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2380 [log.tag|tag: tip]
2380 [log.tag|tag: tip]
2381 [log.user|user: test]
2381 [log.user|user: test]
2382 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2382 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2383 [log.summary|summary: Modify, add, remove, rename]
2383 [log.summary|summary: Modify, add, remove, rename]
2384 [ui.note log.files|files:]
2384 [ui.note log.files|files:]
2385 [status.modified|M third]
2385 [status.modified|M third]
2386 [status.added|A b]
2386 [status.added|A b]
2387 [status.added|A fifth]
2387 [status.added|A fifth]
2388 [status.removed|R a]
2388 [status.removed|R a]
2389 [status.removed|R fourth]
2389 [status.removed|R fourth]
2390
2390
2391 $ hg --color=debug log -T status -C -r 10
2391 $ hg --color=debug log -T status -C -r 10
2392 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2392 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2393 [log.tag|tag: tip]
2393 [log.tag|tag: tip]
2394 [log.user|user: test]
2394 [log.user|user: test]
2395 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2395 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2396 [log.summary|summary: Modify, add, remove, rename]
2396 [log.summary|summary: Modify, add, remove, rename]
2397 [ui.note log.files|files:]
2397 [ui.note log.files|files:]
2398 [status.modified|M third]
2398 [status.modified|M third]
2399 [status.added|A b]
2399 [status.added|A b]
2400 [status.added|A fifth]
2400 [status.added|A fifth]
2401 [status.copied| fourth]
2401 [status.copied| fourth]
2402 [status.removed|R a]
2402 [status.removed|R a]
2403 [status.removed|R fourth]
2403 [status.removed|R fourth]
2404
2404
2405 $ hg --color=debug log -T status -C -r 10 -v
2405 $ hg --color=debug log -T status -C -r 10 -v
2406 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2406 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2407 [log.tag|tag: tip]
2407 [log.tag|tag: tip]
2408 [log.user|user: test]
2408 [log.user|user: test]
2409 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2409 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2410 [ui.note log.description|description:]
2410 [ui.note log.description|description:]
2411 [ui.note log.description|Modify, add, remove, rename]
2411 [ui.note log.description|Modify, add, remove, rename]
2412
2412
2413 [ui.note log.files|files:]
2413 [ui.note log.files|files:]
2414 [status.modified|M third]
2414 [status.modified|M third]
2415 [status.added|A b]
2415 [status.added|A b]
2416 [status.added|A fifth]
2416 [status.added|A fifth]
2417 [status.copied| fourth]
2417 [status.copied| fourth]
2418 [status.removed|R a]
2418 [status.removed|R a]
2419 [status.removed|R fourth]
2419 [status.removed|R fourth]
2420
2420
2421 $ hg --color=debug log -T status -C -r 10 --debug
2421 $ hg --color=debug log -T status -C -r 10 --debug
2422 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2422 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2423 [log.tag|tag: tip]
2423 [log.tag|tag: tip]
2424 [log.phase|phase: secret]
2424 [log.phase|phase: secret]
2425 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2425 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2426 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2426 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2427 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2427 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2428 [log.user|user: test]
2428 [log.user|user: test]
2429 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2429 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2430 [ui.debug log.extra|extra: branch=default]
2430 [ui.debug log.extra|extra: branch=default]
2431 [ui.note log.description|description:]
2431 [ui.note log.description|description:]
2432 [ui.note log.description|Modify, add, remove, rename]
2432 [ui.note log.description|Modify, add, remove, rename]
2433
2433
2434 [ui.note log.files|files:]
2434 [ui.note log.files|files:]
2435 [status.modified|M third]
2435 [status.modified|M third]
2436 [status.added|A b]
2436 [status.added|A b]
2437 [status.added|A fifth]
2437 [status.added|A fifth]
2438 [status.copied| fourth]
2438 [status.copied| fourth]
2439 [status.removed|R a]
2439 [status.removed|R a]
2440 [status.removed|R fourth]
2440 [status.removed|R fourth]
2441
2441
2442 $ hg --color=debug log -T status -C -r 10 --quiet
2442 $ hg --color=debug log -T status -C -r 10 --quiet
2443 [log.node|10:0f9759ec227a]
2443 [log.node|10:0f9759ec227a]
2444
2444
2445 Check the bisect template
2445 Check the bisect template
2446
2446
2447 $ hg bisect -g 1
2447 $ hg bisect -g 1
2448 $ hg bisect -b 3 --noupdate
2448 $ hg bisect -b 3 --noupdate
2449 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2449 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2450 $ hg log -T bisect -r 0:4
2450 $ hg log -T bisect -r 0:4
2451 changeset: 0:1e4e1b8f71e0
2451 changeset: 0:1e4e1b8f71e0
2452 bisect: good (implicit)
2452 bisect: good (implicit)
2453 user: User Name <user@hostname>
2453 user: User Name <user@hostname>
2454 date: Mon Jan 12 13:46:40 1970 +0000
2454 date: Mon Jan 12 13:46:40 1970 +0000
2455 summary: line 1
2455 summary: line 1
2456
2456
2457 changeset: 1:b608e9d1a3f0
2457 changeset: 1:b608e9d1a3f0
2458 bisect: good
2458 bisect: good
2459 user: A. N. Other <other@place>
2459 user: A. N. Other <other@place>
2460 date: Tue Jan 13 17:33:20 1970 +0000
2460 date: Tue Jan 13 17:33:20 1970 +0000
2461 summary: other 1
2461 summary: other 1
2462
2462
2463 changeset: 2:97054abb4ab8
2463 changeset: 2:97054abb4ab8
2464 bisect: untested
2464 bisect: untested
2465 user: other@place
2465 user: other@place
2466 date: Wed Jan 14 21:20:00 1970 +0000
2466 date: Wed Jan 14 21:20:00 1970 +0000
2467 summary: no person
2467 summary: no person
2468
2468
2469 changeset: 3:10e46f2dcbf4
2469 changeset: 3:10e46f2dcbf4
2470 bisect: bad
2470 bisect: bad
2471 user: person
2471 user: person
2472 date: Fri Jan 16 01:06:40 1970 +0000
2472 date: Fri Jan 16 01:06:40 1970 +0000
2473 summary: no user, no domain
2473 summary: no user, no domain
2474
2474
2475 changeset: 4:bbe44766e73d
2475 changeset: 4:bbe44766e73d
2476 bisect: bad (implicit)
2476 bisect: bad (implicit)
2477 branch: foo
2477 branch: foo
2478 user: person
2478 user: person
2479 date: Sat Jan 17 04:53:20 1970 +0000
2479 date: Sat Jan 17 04:53:20 1970 +0000
2480 summary: new branch
2480 summary: new branch
2481
2481
2482 $ hg log --debug -T bisect -r 0:4
2482 $ hg log --debug -T bisect -r 0:4
2483 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2483 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2484 bisect: good (implicit)
2484 bisect: good (implicit)
2485 phase: public
2485 phase: public
2486 parent: -1:0000000000000000000000000000000000000000
2486 parent: -1:0000000000000000000000000000000000000000
2487 parent: -1:0000000000000000000000000000000000000000
2487 parent: -1:0000000000000000000000000000000000000000
2488 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2488 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2489 user: User Name <user@hostname>
2489 user: User Name <user@hostname>
2490 date: Mon Jan 12 13:46:40 1970 +0000
2490 date: Mon Jan 12 13:46:40 1970 +0000
2491 files+: a
2491 files+: a
2492 extra: branch=default
2492 extra: branch=default
2493 description:
2493 description:
2494 line 1
2494 line 1
2495 line 2
2495 line 2
2496
2496
2497
2497
2498 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2498 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2499 bisect: good
2499 bisect: good
2500 phase: public
2500 phase: public
2501 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2501 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2502 parent: -1:0000000000000000000000000000000000000000
2502 parent: -1:0000000000000000000000000000000000000000
2503 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2503 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2504 user: A. N. Other <other@place>
2504 user: A. N. Other <other@place>
2505 date: Tue Jan 13 17:33:20 1970 +0000
2505 date: Tue Jan 13 17:33:20 1970 +0000
2506 files+: b
2506 files+: b
2507 extra: branch=default
2507 extra: branch=default
2508 description:
2508 description:
2509 other 1
2509 other 1
2510 other 2
2510 other 2
2511
2511
2512 other 3
2512 other 3
2513
2513
2514
2514
2515 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2515 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2516 bisect: untested
2516 bisect: untested
2517 phase: public
2517 phase: public
2518 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2518 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2519 parent: -1:0000000000000000000000000000000000000000
2519 parent: -1:0000000000000000000000000000000000000000
2520 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2520 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2521 user: other@place
2521 user: other@place
2522 date: Wed Jan 14 21:20:00 1970 +0000
2522 date: Wed Jan 14 21:20:00 1970 +0000
2523 files+: c
2523 files+: c
2524 extra: branch=default
2524 extra: branch=default
2525 description:
2525 description:
2526 no person
2526 no person
2527
2527
2528
2528
2529 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2529 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2530 bisect: bad
2530 bisect: bad
2531 phase: public
2531 phase: public
2532 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2532 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2533 parent: -1:0000000000000000000000000000000000000000
2533 parent: -1:0000000000000000000000000000000000000000
2534 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2534 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2535 user: person
2535 user: person
2536 date: Fri Jan 16 01:06:40 1970 +0000
2536 date: Fri Jan 16 01:06:40 1970 +0000
2537 files: c
2537 files: c
2538 extra: branch=default
2538 extra: branch=default
2539 description:
2539 description:
2540 no user, no domain
2540 no user, no domain
2541
2541
2542
2542
2543 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2543 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2544 bisect: bad (implicit)
2544 bisect: bad (implicit)
2545 branch: foo
2545 branch: foo
2546 phase: draft
2546 phase: draft
2547 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2547 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2548 parent: -1:0000000000000000000000000000000000000000
2548 parent: -1:0000000000000000000000000000000000000000
2549 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2549 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2550 user: person
2550 user: person
2551 date: Sat Jan 17 04:53:20 1970 +0000
2551 date: Sat Jan 17 04:53:20 1970 +0000
2552 extra: branch=foo
2552 extra: branch=foo
2553 description:
2553 description:
2554 new branch
2554 new branch
2555
2555
2556
2556
2557 $ hg log -v -T bisect -r 0:4
2557 $ hg log -v -T bisect -r 0:4
2558 changeset: 0:1e4e1b8f71e0
2558 changeset: 0:1e4e1b8f71e0
2559 bisect: good (implicit)
2559 bisect: good (implicit)
2560 user: User Name <user@hostname>
2560 user: User Name <user@hostname>
2561 date: Mon Jan 12 13:46:40 1970 +0000
2561 date: Mon Jan 12 13:46:40 1970 +0000
2562 files: a
2562 files: a
2563 description:
2563 description:
2564 line 1
2564 line 1
2565 line 2
2565 line 2
2566
2566
2567
2567
2568 changeset: 1:b608e9d1a3f0
2568 changeset: 1:b608e9d1a3f0
2569 bisect: good
2569 bisect: good
2570 user: A. N. Other <other@place>
2570 user: A. N. Other <other@place>
2571 date: Tue Jan 13 17:33:20 1970 +0000
2571 date: Tue Jan 13 17:33:20 1970 +0000
2572 files: b
2572 files: b
2573 description:
2573 description:
2574 other 1
2574 other 1
2575 other 2
2575 other 2
2576
2576
2577 other 3
2577 other 3
2578
2578
2579
2579
2580 changeset: 2:97054abb4ab8
2580 changeset: 2:97054abb4ab8
2581 bisect: untested
2581 bisect: untested
2582 user: other@place
2582 user: other@place
2583 date: Wed Jan 14 21:20:00 1970 +0000
2583 date: Wed Jan 14 21:20:00 1970 +0000
2584 files: c
2584 files: c
2585 description:
2585 description:
2586 no person
2586 no person
2587
2587
2588
2588
2589 changeset: 3:10e46f2dcbf4
2589 changeset: 3:10e46f2dcbf4
2590 bisect: bad
2590 bisect: bad
2591 user: person
2591 user: person
2592 date: Fri Jan 16 01:06:40 1970 +0000
2592 date: Fri Jan 16 01:06:40 1970 +0000
2593 files: c
2593 files: c
2594 description:
2594 description:
2595 no user, no domain
2595 no user, no domain
2596
2596
2597
2597
2598 changeset: 4:bbe44766e73d
2598 changeset: 4:bbe44766e73d
2599 bisect: bad (implicit)
2599 bisect: bad (implicit)
2600 branch: foo
2600 branch: foo
2601 user: person
2601 user: person
2602 date: Sat Jan 17 04:53:20 1970 +0000
2602 date: Sat Jan 17 04:53:20 1970 +0000
2603 description:
2603 description:
2604 new branch
2604 new branch
2605
2605
2606
2606
2607 $ hg --color=debug log -T bisect -r 0:4
2607 $ hg --color=debug log -T bisect -r 0:4
2608 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2608 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2609 [log.bisect bisect.good|bisect: good (implicit)]
2609 [log.bisect bisect.good|bisect: good (implicit)]
2610 [log.user|user: User Name <user@hostname>]
2610 [log.user|user: User Name <user@hostname>]
2611 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2611 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2612 [log.summary|summary: line 1]
2612 [log.summary|summary: line 1]
2613
2613
2614 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2614 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2615 [log.bisect bisect.good|bisect: good]
2615 [log.bisect bisect.good|bisect: good]
2616 [log.user|user: A. N. Other <other@place>]
2616 [log.user|user: A. N. Other <other@place>]
2617 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2617 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2618 [log.summary|summary: other 1]
2618 [log.summary|summary: other 1]
2619
2619
2620 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2620 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2621 [log.bisect bisect.untested|bisect: untested]
2621 [log.bisect bisect.untested|bisect: untested]
2622 [log.user|user: other@place]
2622 [log.user|user: other@place]
2623 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2623 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2624 [log.summary|summary: no person]
2624 [log.summary|summary: no person]
2625
2625
2626 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2626 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2627 [log.bisect bisect.bad|bisect: bad]
2627 [log.bisect bisect.bad|bisect: bad]
2628 [log.user|user: person]
2628 [log.user|user: person]
2629 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2629 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2630 [log.summary|summary: no user, no domain]
2630 [log.summary|summary: no user, no domain]
2631
2631
2632 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2632 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2633 [log.bisect bisect.bad|bisect: bad (implicit)]
2633 [log.bisect bisect.bad|bisect: bad (implicit)]
2634 [log.branch|branch: foo]
2634 [log.branch|branch: foo]
2635 [log.user|user: person]
2635 [log.user|user: person]
2636 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2636 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2637 [log.summary|summary: new branch]
2637 [log.summary|summary: new branch]
2638
2638
2639 $ hg --color=debug log --debug -T bisect -r 0:4
2639 $ hg --color=debug log --debug -T bisect -r 0:4
2640 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2640 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2641 [log.bisect bisect.good|bisect: good (implicit)]
2641 [log.bisect bisect.good|bisect: good (implicit)]
2642 [log.phase|phase: public]
2642 [log.phase|phase: public]
2643 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2643 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2644 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2644 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2645 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2645 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2646 [log.user|user: User Name <user@hostname>]
2646 [log.user|user: User Name <user@hostname>]
2647 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2647 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2648 [ui.debug log.files|files+: a]
2648 [ui.debug log.files|files+: a]
2649 [ui.debug log.extra|extra: branch=default]
2649 [ui.debug log.extra|extra: branch=default]
2650 [ui.note log.description|description:]
2650 [ui.note log.description|description:]
2651 [ui.note log.description|line 1
2651 [ui.note log.description|line 1
2652 line 2]
2652 line 2]
2653
2653
2654
2654
2655 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2655 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2656 [log.bisect bisect.good|bisect: good]
2656 [log.bisect bisect.good|bisect: good]
2657 [log.phase|phase: public]
2657 [log.phase|phase: public]
2658 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2658 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2659 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2660 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2660 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2661 [log.user|user: A. N. Other <other@place>]
2661 [log.user|user: A. N. Other <other@place>]
2662 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2662 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2663 [ui.debug log.files|files+: b]
2663 [ui.debug log.files|files+: b]
2664 [ui.debug log.extra|extra: branch=default]
2664 [ui.debug log.extra|extra: branch=default]
2665 [ui.note log.description|description:]
2665 [ui.note log.description|description:]
2666 [ui.note log.description|other 1
2666 [ui.note log.description|other 1
2667 other 2
2667 other 2
2668
2668
2669 other 3]
2669 other 3]
2670
2670
2671
2671
2672 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2672 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2673 [log.bisect bisect.untested|bisect: untested]
2673 [log.bisect bisect.untested|bisect: untested]
2674 [log.phase|phase: public]
2674 [log.phase|phase: public]
2675 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2675 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2676 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2676 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2677 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2677 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2678 [log.user|user: other@place]
2678 [log.user|user: other@place]
2679 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2679 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2680 [ui.debug log.files|files+: c]
2680 [ui.debug log.files|files+: c]
2681 [ui.debug log.extra|extra: branch=default]
2681 [ui.debug log.extra|extra: branch=default]
2682 [ui.note log.description|description:]
2682 [ui.note log.description|description:]
2683 [ui.note log.description|no person]
2683 [ui.note log.description|no person]
2684
2684
2685
2685
2686 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2686 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2687 [log.bisect bisect.bad|bisect: bad]
2687 [log.bisect bisect.bad|bisect: bad]
2688 [log.phase|phase: public]
2688 [log.phase|phase: public]
2689 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2689 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2690 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2690 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2691 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2691 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2692 [log.user|user: person]
2692 [log.user|user: person]
2693 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2693 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2694 [ui.debug log.files|files: c]
2694 [ui.debug log.files|files: c]
2695 [ui.debug log.extra|extra: branch=default]
2695 [ui.debug log.extra|extra: branch=default]
2696 [ui.note log.description|description:]
2696 [ui.note log.description|description:]
2697 [ui.note log.description|no user, no domain]
2697 [ui.note log.description|no user, no domain]
2698
2698
2699
2699
2700 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2700 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2701 [log.bisect bisect.bad|bisect: bad (implicit)]
2701 [log.bisect bisect.bad|bisect: bad (implicit)]
2702 [log.branch|branch: foo]
2702 [log.branch|branch: foo]
2703 [log.phase|phase: draft]
2703 [log.phase|phase: draft]
2704 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2704 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2705 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2705 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2706 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2706 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2707 [log.user|user: person]
2707 [log.user|user: person]
2708 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2708 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2709 [ui.debug log.extra|extra: branch=foo]
2709 [ui.debug log.extra|extra: branch=foo]
2710 [ui.note log.description|description:]
2710 [ui.note log.description|description:]
2711 [ui.note log.description|new branch]
2711 [ui.note log.description|new branch]
2712
2712
2713
2713
2714 $ hg --color=debug log -v -T bisect -r 0:4
2714 $ hg --color=debug log -v -T bisect -r 0:4
2715 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2715 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2716 [log.bisect bisect.good|bisect: good (implicit)]
2716 [log.bisect bisect.good|bisect: good (implicit)]
2717 [log.user|user: User Name <user@hostname>]
2717 [log.user|user: User Name <user@hostname>]
2718 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2718 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2719 [ui.note log.files|files: a]
2719 [ui.note log.files|files: a]
2720 [ui.note log.description|description:]
2720 [ui.note log.description|description:]
2721 [ui.note log.description|line 1
2721 [ui.note log.description|line 1
2722 line 2]
2722 line 2]
2723
2723
2724
2724
2725 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2725 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2726 [log.bisect bisect.good|bisect: good]
2726 [log.bisect bisect.good|bisect: good]
2727 [log.user|user: A. N. Other <other@place>]
2727 [log.user|user: A. N. Other <other@place>]
2728 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2728 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2729 [ui.note log.files|files: b]
2729 [ui.note log.files|files: b]
2730 [ui.note log.description|description:]
2730 [ui.note log.description|description:]
2731 [ui.note log.description|other 1
2731 [ui.note log.description|other 1
2732 other 2
2732 other 2
2733
2733
2734 other 3]
2734 other 3]
2735
2735
2736
2736
2737 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2737 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2738 [log.bisect bisect.untested|bisect: untested]
2738 [log.bisect bisect.untested|bisect: untested]
2739 [log.user|user: other@place]
2739 [log.user|user: other@place]
2740 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2740 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2741 [ui.note log.files|files: c]
2741 [ui.note log.files|files: c]
2742 [ui.note log.description|description:]
2742 [ui.note log.description|description:]
2743 [ui.note log.description|no person]
2743 [ui.note log.description|no person]
2744
2744
2745
2745
2746 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2746 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2747 [log.bisect bisect.bad|bisect: bad]
2747 [log.bisect bisect.bad|bisect: bad]
2748 [log.user|user: person]
2748 [log.user|user: person]
2749 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2749 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2750 [ui.note log.files|files: c]
2750 [ui.note log.files|files: c]
2751 [ui.note log.description|description:]
2751 [ui.note log.description|description:]
2752 [ui.note log.description|no user, no domain]
2752 [ui.note log.description|no user, no domain]
2753
2753
2754
2754
2755 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2755 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2756 [log.bisect bisect.bad|bisect: bad (implicit)]
2756 [log.bisect bisect.bad|bisect: bad (implicit)]
2757 [log.branch|branch: foo]
2757 [log.branch|branch: foo]
2758 [log.user|user: person]
2758 [log.user|user: person]
2759 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2759 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2760 [ui.note log.description|description:]
2760 [ui.note log.description|description:]
2761 [ui.note log.description|new branch]
2761 [ui.note log.description|new branch]
2762
2762
2763
2763
2764 $ hg bisect --reset
2764 $ hg bisect --reset
2765
2765
2766 Error on syntax:
2766 Error on syntax:
2767
2767
2768 $ echo 'x = "f' >> t
2768 $ echo 'x = "f' >> t
2769 $ hg log
2769 $ hg log
2770 hg: parse error at t:3: unmatched quotes
2770 hg: parse error at t:3: unmatched quotes
2771 [255]
2771 [255]
2772
2772
2773 $ hg log -T '{date'
2773 $ hg log -T '{date'
2774 hg: parse error at 1: unterminated template expansion
2774 hg: parse error at 1: unterminated template expansion
2775 ({date
2775 ({date
2776 ^ here)
2776 ^ here)
2777 [255]
2777 [255]
2778 $ hg log -T '{date(}'
2778 $ hg log -T '{date(}'
2779 hg: parse error at 6: not a prefix: end
2779 hg: parse error at 6: not a prefix: end
2780 ({date(}
2780 ({date(}
2781 ^ here)
2781 ^ here)
2782 [255]
2782 [255]
2783 $ hg log -T '{date)}'
2783 $ hg log -T '{date)}'
2784 hg: parse error at 5: invalid token
2784 hg: parse error at 5: invalid token
2785 ({date)}
2785 ({date)}
2786 ^ here)
2786 ^ here)
2787 [255]
2787 [255]
2788 $ hg log -T '{date date}'
2788 $ hg log -T '{date date}'
2789 hg: parse error at 6: invalid token
2789 hg: parse error at 6: invalid token
2790 ({date date}
2790 ({date date}
2791 ^ here)
2791 ^ here)
2792 [255]
2792 [255]
2793
2793
2794 $ hg log -T '{}'
2794 $ hg log -T '{}'
2795 hg: parse error at 1: not a prefix: end
2795 hg: parse error at 1: not a prefix: end
2796 ({}
2796 ({}
2797 ^ here)
2797 ^ here)
2798 [255]
2798 [255]
2799 $ hg debugtemplate -v '{()}'
2799 $ hg debugtemplate -v '{()}'
2800 (template
2800 (template
2801 (group
2801 (group
2802 None))
2802 None))
2803 hg: parse error: missing argument
2803 hg: parse error: missing argument
2804 [255]
2804 [255]
2805
2805
2806 Behind the scenes, this would throw TypeError without intype=bytes
2806 Behind the scenes, this would throw TypeError without intype=bytes
2807
2807
2808 $ hg log -l 3 --template '{date|obfuscate}\n'
2808 $ hg log -l 3 --template '{date|obfuscate}\n'
2809 &#48;&#32;&#48;
2809 &#48;&#32;&#48;
2810 &#48;&#32;&#48;
2810 &#48;&#32;&#48;
2811 &#49;&#53;&#55;&#55;&#56;&#55;&#50;&#56;&#54;&#48;&#32;&#48;
2811 &#49;&#53;&#55;&#55;&#56;&#55;&#50;&#56;&#54;&#48;&#32;&#48;
2812
2812
2813 Behind the scenes, this will throw a ValueError
2813 Behind the scenes, this will throw a ValueError
2814
2814
2815 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2815 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2816 hg: parse error: invalid date: 'Modify, add, remove, rename'
2816 hg: parse error: invalid date: 'Modify, add, remove, rename'
2817 (template filter 'shortdate' is not compatible with keyword 'desc')
2817 (template filter 'shortdate' is not compatible with keyword 'desc')
2818 [255]
2818 [255]
2819
2819
2820 Behind the scenes, this would throw AttributeError without intype=bytes
2820 Behind the scenes, this would throw AttributeError without intype=bytes
2821
2821
2822 $ hg log -l 3 --template 'line: {date|escape}\n'
2822 $ hg log -l 3 --template 'line: {date|escape}\n'
2823 line: 0 0
2823 line: 0 0
2824 line: 0 0
2824 line: 0 0
2825 line: 1577872860 0
2825 line: 1577872860 0
2826
2826
2827 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2827 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2828 hg: parse error: localdate expects a date information
2828 hg: parse error: localdate expects a date information
2829 [255]
2829 [255]
2830
2830
2831 Behind the scenes, this will throw ValueError
2831 Behind the scenes, this will throw ValueError
2832
2832
2833 $ hg tip --template '{author|email|date}\n'
2833 $ hg tip --template '{author|email|date}\n'
2834 hg: parse error: date expects a date information
2834 hg: parse error: date expects a date information
2835 [255]
2835 [255]
2836
2836
2837 $ hg tip -T '{author|email|shortdate}\n'
2837 $ hg tip -T '{author|email|shortdate}\n'
2838 hg: parse error: invalid date: 'test'
2838 hg: parse error: invalid date: 'test'
2839 (template filter 'shortdate' is not compatible with keyword 'author')
2839 (template filter 'shortdate' is not compatible with keyword 'author')
2840 [255]
2840 [255]
2841
2841
2842 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2842 $ hg tip -T '{get(extras, "branch")|shortdate}\n'
2843 hg: parse error: invalid date: 'default'
2843 hg: parse error: invalid date: 'default'
2844 (incompatible use of template filter 'shortdate')
2844 (incompatible use of template filter 'shortdate')
2845 [255]
2845 [255]
2846
2846
2847 Error in nested template:
2847 Error in nested template:
2848
2848
2849 $ hg log -T '{"date'
2849 $ hg log -T '{"date'
2850 hg: parse error at 2: unterminated string
2850 hg: parse error at 2: unterminated string
2851 ({"date
2851 ({"date
2852 ^ here)
2852 ^ here)
2853 [255]
2853 [255]
2854
2854
2855 $ hg log -T '{"foo{date|?}"}'
2855 $ hg log -T '{"foo{date|?}"}'
2856 hg: parse error at 11: syntax error
2856 hg: parse error at 11: syntax error
2857 ({"foo{date|?}"}
2857 ({"foo{date|?}"}
2858 ^ here)
2858 ^ here)
2859 [255]
2859 [255]
2860
2860
2861 Thrown an error if a template function doesn't exist
2861 Thrown an error if a template function doesn't exist
2862
2862
2863 $ hg tip --template '{foo()}\n'
2863 $ hg tip --template '{foo()}\n'
2864 hg: parse error: unknown function 'foo'
2864 hg: parse error: unknown function 'foo'
2865 [255]
2865 [255]
2866
2866
2867 Pass generator object created by template function to filter
2867 Pass generator object created by template function to filter
2868
2868
2869 $ hg log -l 1 --template '{if(author, author)|user}\n'
2869 $ hg log -l 1 --template '{if(author, author)|user}\n'
2870 test
2870 test
2871
2871
2872 Test index keyword:
2872 Test index keyword:
2873
2873
2874 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2874 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
2875 10 0:a 1:b 2:fifth 3:fourth 4:third
2875 10 0:a 1:b 2:fifth 3:fourth 4:third
2876 11 0:a
2876 11 0:a
2877
2877
2878 $ hg branches -T '{index} {branch}\n'
2878 $ hg branches -T '{index} {branch}\n'
2879 0 default
2879 0 default
2880 1 foo
2880 1 foo
2881
2881
2882 Test diff function:
2882 Test diff function:
2883
2883
2884 $ hg diff -c 8
2884 $ hg diff -c 8
2885 diff -r 29114dbae42b -r 95c24699272e fourth
2885 diff -r 29114dbae42b -r 95c24699272e fourth
2886 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2886 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2887 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2887 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2888 @@ -0,0 +1,1 @@
2888 @@ -0,0 +1,1 @@
2889 +second
2889 +second
2890 diff -r 29114dbae42b -r 95c24699272e second
2890 diff -r 29114dbae42b -r 95c24699272e second
2891 --- a/second Mon Jan 12 13:46:40 1970 +0000
2891 --- a/second Mon Jan 12 13:46:40 1970 +0000
2892 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2892 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2893 @@ -1,1 +0,0 @@
2893 @@ -1,1 +0,0 @@
2894 -second
2894 -second
2895 diff -r 29114dbae42b -r 95c24699272e third
2895 diff -r 29114dbae42b -r 95c24699272e third
2896 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2896 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2897 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2897 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2898 @@ -0,0 +1,1 @@
2898 @@ -0,0 +1,1 @@
2899 +third
2899 +third
2900
2900
2901 $ hg log -r 8 -T "{diff()}"
2901 $ hg log -r 8 -T "{diff()}"
2902 diff -r 29114dbae42b -r 95c24699272e fourth
2902 diff -r 29114dbae42b -r 95c24699272e fourth
2903 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2903 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2904 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2904 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2905 @@ -0,0 +1,1 @@
2905 @@ -0,0 +1,1 @@
2906 +second
2906 +second
2907 diff -r 29114dbae42b -r 95c24699272e second
2907 diff -r 29114dbae42b -r 95c24699272e second
2908 --- a/second Mon Jan 12 13:46:40 1970 +0000
2908 --- a/second Mon Jan 12 13:46:40 1970 +0000
2909 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2909 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2910 @@ -1,1 +0,0 @@
2910 @@ -1,1 +0,0 @@
2911 -second
2911 -second
2912 diff -r 29114dbae42b -r 95c24699272e third
2912 diff -r 29114dbae42b -r 95c24699272e third
2913 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2913 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2914 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2914 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2915 @@ -0,0 +1,1 @@
2915 @@ -0,0 +1,1 @@
2916 +third
2916 +third
2917
2917
2918 $ hg log -r 8 -T "{diff('glob:f*')}"
2918 $ hg log -r 8 -T "{diff('glob:f*')}"
2919 diff -r 29114dbae42b -r 95c24699272e fourth
2919 diff -r 29114dbae42b -r 95c24699272e fourth
2920 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2920 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2921 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2921 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2922 @@ -0,0 +1,1 @@
2922 @@ -0,0 +1,1 @@
2923 +second
2923 +second
2924
2924
2925 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2925 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2926 diff -r 29114dbae42b -r 95c24699272e second
2926 diff -r 29114dbae42b -r 95c24699272e second
2927 --- a/second Mon Jan 12 13:46:40 1970 +0000
2927 --- a/second Mon Jan 12 13:46:40 1970 +0000
2928 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2928 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2929 @@ -1,1 +0,0 @@
2929 @@ -1,1 +0,0 @@
2930 -second
2930 -second
2931 diff -r 29114dbae42b -r 95c24699272e third
2931 diff -r 29114dbae42b -r 95c24699272e third
2932 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2932 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2933 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2933 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2934 @@ -0,0 +1,1 @@
2934 @@ -0,0 +1,1 @@
2935 +third
2935 +third
2936
2936
2937 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2937 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2938 diff -r 29114dbae42b -r 95c24699272e fourth
2938 diff -r 29114dbae42b -r 95c24699272e fourth
2939 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2939 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2940 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2940 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2941 @@ -0,0 +1,1 @@
2941 @@ -0,0 +1,1 @@
2942 +second
2942 +second
2943
2943
2944 ui verbosity:
2944 ui verbosity:
2945
2945
2946 $ hg log -l1 -T '{verbosity}\n'
2946 $ hg log -l1 -T '{verbosity}\n'
2947
2947
2948 $ hg log -l1 -T '{verbosity}\n' --debug
2948 $ hg log -l1 -T '{verbosity}\n' --debug
2949 debug
2949 debug
2950 $ hg log -l1 -T '{verbosity}\n' --quiet
2950 $ hg log -l1 -T '{verbosity}\n' --quiet
2951 quiet
2951 quiet
2952 $ hg log -l1 -T '{verbosity}\n' --verbose
2952 $ hg log -l1 -T '{verbosity}\n' --verbose
2953 verbose
2953 verbose
2954
2954
2955 $ cd ..
2955 $ cd ..
2956
2956
2957
2957
2958 latesttag:
2958 latesttag:
2959
2959
2960 $ hg init latesttag
2960 $ hg init latesttag
2961 $ cd latesttag
2961 $ cd latesttag
2962
2962
2963 $ echo a > file
2963 $ echo a > file
2964 $ hg ci -Am a -d '0 0'
2964 $ hg ci -Am a -d '0 0'
2965 adding file
2965 adding file
2966
2966
2967 $ echo b >> file
2967 $ echo b >> file
2968 $ hg ci -m b -d '1 0'
2968 $ hg ci -m b -d '1 0'
2969
2969
2970 $ echo c >> head1
2970 $ echo c >> head1
2971 $ hg ci -Am h1c -d '2 0'
2971 $ hg ci -Am h1c -d '2 0'
2972 adding head1
2972 adding head1
2973
2973
2974 $ hg update -q 1
2974 $ hg update -q 1
2975 $ echo d >> head2
2975 $ echo d >> head2
2976 $ hg ci -Am h2d -d '3 0'
2976 $ hg ci -Am h2d -d '3 0'
2977 adding head2
2977 adding head2
2978 created new head
2978 created new head
2979
2979
2980 $ echo e >> head2
2980 $ echo e >> head2
2981 $ hg ci -m h2e -d '4 0'
2981 $ hg ci -m h2e -d '4 0'
2982
2982
2983 $ hg merge -q
2983 $ hg merge -q
2984 $ hg ci -m merge -d '5 -3600'
2984 $ hg ci -m merge -d '5 -3600'
2985
2985
2986 No tag set:
2986 No tag set:
2987
2987
2988 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2988 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
2989 @ 5: null+5
2989 @ 5: null+5
2990 |\
2990 |\
2991 | o 4: null+4
2991 | o 4: null+4
2992 | |
2992 | |
2993 | o 3: null+3
2993 | o 3: null+3
2994 | |
2994 | |
2995 o | 2: null+3
2995 o | 2: null+3
2996 |/
2996 |/
2997 o 1: null+2
2997 o 1: null+2
2998 |
2998 |
2999 o 0: null+1
2999 o 0: null+1
3000
3000
3001
3001
3002 One common tag: longest path wins for {latesttagdistance}:
3002 One common tag: longest path wins for {latesttagdistance}:
3003
3003
3004 $ hg tag -r 1 -m t1 -d '6 0' t1
3004 $ hg tag -r 1 -m t1 -d '6 0' t1
3005 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3005 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3006 @ 6: t1+4
3006 @ 6: t1+4
3007 |
3007 |
3008 o 5: t1+3
3008 o 5: t1+3
3009 |\
3009 |\
3010 | o 4: t1+2
3010 | o 4: t1+2
3011 | |
3011 | |
3012 | o 3: t1+1
3012 | o 3: t1+1
3013 | |
3013 | |
3014 o | 2: t1+1
3014 o | 2: t1+1
3015 |/
3015 |/
3016 o 1: t1+0
3016 o 1: t1+0
3017 |
3017 |
3018 o 0: null+1
3018 o 0: null+1
3019
3019
3020
3020
3021 One ancestor tag: closest wins:
3021 One ancestor tag: closest wins:
3022
3022
3023 $ hg tag -r 2 -m t2 -d '7 0' t2
3023 $ hg tag -r 2 -m t2 -d '7 0' t2
3024 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3024 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3025 @ 7: t2+3
3025 @ 7: t2+3
3026 |
3026 |
3027 o 6: t2+2
3027 o 6: t2+2
3028 |
3028 |
3029 o 5: t2+1
3029 o 5: t2+1
3030 |\
3030 |\
3031 | o 4: t1+2
3031 | o 4: t1+2
3032 | |
3032 | |
3033 | o 3: t1+1
3033 | o 3: t1+1
3034 | |
3034 | |
3035 o | 2: t2+0
3035 o | 2: t2+0
3036 |/
3036 |/
3037 o 1: t1+0
3037 o 1: t1+0
3038 |
3038 |
3039 o 0: null+1
3039 o 0: null+1
3040
3040
3041
3041
3042 Two branch tags: more recent wins if same number of changes:
3042 Two branch tags: more recent wins if same number of changes:
3043
3043
3044 $ hg tag -r 3 -m t3 -d '8 0' t3
3044 $ hg tag -r 3 -m t3 -d '8 0' t3
3045 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3045 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3046 @ 8: t3+5
3046 @ 8: t3+5
3047 |
3047 |
3048 o 7: t3+4
3048 o 7: t3+4
3049 |
3049 |
3050 o 6: t3+3
3050 o 6: t3+3
3051 |
3051 |
3052 o 5: t3+2
3052 o 5: t3+2
3053 |\
3053 |\
3054 | o 4: t3+1
3054 | o 4: t3+1
3055 | |
3055 | |
3056 | o 3: t3+0
3056 | o 3: t3+0
3057 | |
3057 | |
3058 o | 2: t2+0
3058 o | 2: t2+0
3059 |/
3059 |/
3060 o 1: t1+0
3060 o 1: t1+0
3061 |
3061 |
3062 o 0: null+1
3062 o 0: null+1
3063
3063
3064
3064
3065 Two branch tags: fewest changes wins:
3065 Two branch tags: fewest changes wins:
3066
3066
3067 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3067 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
3068 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3068 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3069 @ 9: t4+5,6
3069 @ 9: t4+5,6
3070 |
3070 |
3071 o 8: t4+4,5
3071 o 8: t4+4,5
3072 |
3072 |
3073 o 7: t4+3,4
3073 o 7: t4+3,4
3074 |
3074 |
3075 o 6: t4+2,3
3075 o 6: t4+2,3
3076 |
3076 |
3077 o 5: t4+1,2
3077 o 5: t4+1,2
3078 |\
3078 |\
3079 | o 4: t4+0,0
3079 | o 4: t4+0,0
3080 | |
3080 | |
3081 | o 3: t3+0,0
3081 | o 3: t3+0,0
3082 | |
3082 | |
3083 o | 2: t2+0,0
3083 o | 2: t2+0,0
3084 |/
3084 |/
3085 o 1: t1+0,0
3085 o 1: t1+0,0
3086 |
3086 |
3087 o 0: null+1,1
3087 o 0: null+1,1
3088
3088
3089
3089
3090 Merged tag overrides:
3090 Merged tag overrides:
3091
3091
3092 $ hg tag -r 5 -m t5 -d '9 0' t5
3092 $ hg tag -r 5 -m t5 -d '9 0' t5
3093 $ hg tag -r 3 -m at3 -d '10 0' at3
3093 $ hg tag -r 3 -m at3 -d '10 0' at3
3094 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3094 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
3095 @ 11: t5+6
3095 @ 11: t5+6
3096 |
3096 |
3097 o 10: t5+5
3097 o 10: t5+5
3098 |
3098 |
3099 o 9: t5+4
3099 o 9: t5+4
3100 |
3100 |
3101 o 8: t5+3
3101 o 8: t5+3
3102 |
3102 |
3103 o 7: t5+2
3103 o 7: t5+2
3104 |
3104 |
3105 o 6: t5+1
3105 o 6: t5+1
3106 |
3106 |
3107 o 5: t5+0
3107 o 5: t5+0
3108 |\
3108 |\
3109 | o 4: t4+0
3109 | o 4: t4+0
3110 | |
3110 | |
3111 | o 3: at3:t3+0
3111 | o 3: at3:t3+0
3112 | |
3112 | |
3113 o | 2: t2+0
3113 o | 2: t2+0
3114 |/
3114 |/
3115 o 1: t1+0
3115 o 1: t1+0
3116 |
3116 |
3117 o 0: null+1
3117 o 0: null+1
3118
3118
3119
3119
3120 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3120 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
3121 @ 11: t5+6,6
3121 @ 11: t5+6,6
3122 |
3122 |
3123 o 10: t5+5,5
3123 o 10: t5+5,5
3124 |
3124 |
3125 o 9: t5+4,4
3125 o 9: t5+4,4
3126 |
3126 |
3127 o 8: t5+3,3
3127 o 8: t5+3,3
3128 |
3128 |
3129 o 7: t5+2,2
3129 o 7: t5+2,2
3130 |
3130 |
3131 o 6: t5+1,1
3131 o 6: t5+1,1
3132 |
3132 |
3133 o 5: t5+0,0
3133 o 5: t5+0,0
3134 |\
3134 |\
3135 | o 4: t4+0,0
3135 | o 4: t4+0,0
3136 | |
3136 | |
3137 | o 3: at3+0,0 t3+0,0
3137 | o 3: at3+0,0 t3+0,0
3138 | |
3138 | |
3139 o | 2: t2+0,0
3139 o | 2: t2+0,0
3140 |/
3140 |/
3141 o 1: t1+0,0
3141 o 1: t1+0,0
3142 |
3142 |
3143 o 0: null+1,1
3143 o 0: null+1,1
3144
3144
3145
3145
3146 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3146 $ hg log -G --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
3147 @ 11: t3, C: 9, D: 8
3147 @ 11: t3, C: 9, D: 8
3148 |
3148 |
3149 o 10: t3, C: 8, D: 7
3149 o 10: t3, C: 8, D: 7
3150 |
3150 |
3151 o 9: t3, C: 7, D: 6
3151 o 9: t3, C: 7, D: 6
3152 |
3152 |
3153 o 8: t3, C: 6, D: 5
3153 o 8: t3, C: 6, D: 5
3154 |
3154 |
3155 o 7: t3, C: 5, D: 4
3155 o 7: t3, C: 5, D: 4
3156 |
3156 |
3157 o 6: t3, C: 4, D: 3
3157 o 6: t3, C: 4, D: 3
3158 |
3158 |
3159 o 5: t3, C: 3, D: 2
3159 o 5: t3, C: 3, D: 2
3160 |\
3160 |\
3161 | o 4: t3, C: 1, D: 1
3161 | o 4: t3, C: 1, D: 1
3162 | |
3162 | |
3163 | o 3: t3, C: 0, D: 0
3163 | o 3: t3, C: 0, D: 0
3164 | |
3164 | |
3165 o | 2: t1, C: 1, D: 1
3165 o | 2: t1, C: 1, D: 1
3166 |/
3166 |/
3167 o 1: t1, C: 0, D: 0
3167 o 1: t1, C: 0, D: 0
3168 |
3168 |
3169 o 0: null, C: 1, D: 1
3169 o 0: null, C: 1, D: 1
3170
3170
3171
3171
3172 $ cd ..
3172 $ cd ..
3173
3173
3174
3174
3175 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3175 Style path expansion: issue1948 - ui.style option doesn't work on OSX
3176 if it is a relative path
3176 if it is a relative path
3177
3177
3178 $ mkdir -p home/styles
3178 $ mkdir -p home/styles
3179
3179
3180 $ cat > home/styles/teststyle <<EOF
3180 $ cat > home/styles/teststyle <<EOF
3181 > changeset = 'test {rev}:{node|short}\n'
3181 > changeset = 'test {rev}:{node|short}\n'
3182 > EOF
3182 > EOF
3183
3183
3184 $ HOME=`pwd`/home; export HOME
3184 $ HOME=`pwd`/home; export HOME
3185
3185
3186 $ cat > latesttag/.hg/hgrc <<EOF
3186 $ cat > latesttag/.hg/hgrc <<EOF
3187 > [ui]
3187 > [ui]
3188 > style = ~/styles/teststyle
3188 > style = ~/styles/teststyle
3189 > EOF
3189 > EOF
3190
3190
3191 $ hg -R latesttag tip
3191 $ hg -R latesttag tip
3192 test 11:97e5943b523a
3192 test 11:97e5943b523a
3193
3193
3194 Test recursive showlist template (issue1989):
3194 Test recursive showlist template (issue1989):
3195
3195
3196 $ cat > style1989 <<EOF
3196 $ cat > style1989 <<EOF
3197 > changeset = '{file_mods}{manifest}{extras}'
3197 > changeset = '{file_mods}{manifest}{extras}'
3198 > file_mod = 'M|{author|person}\n'
3198 > file_mod = 'M|{author|person}\n'
3199 > manifest = '{rev},{author}\n'
3199 > manifest = '{rev},{author}\n'
3200 > extra = '{key}: {author}\n'
3200 > extra = '{key}: {author}\n'
3201 > EOF
3201 > EOF
3202
3202
3203 $ hg -R latesttag log -r tip --style=style1989
3203 $ hg -R latesttag log -r tip --style=style1989
3204 M|test
3204 M|test
3205 11,test
3205 11,test
3206 branch: test
3206 branch: test
3207
3207
3208 Test new-style inline templating:
3208 Test new-style inline templating:
3209
3209
3210 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3210 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
3211 modified files: .hgtags
3211 modified files: .hgtags
3212
3212
3213
3213
3214 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3214 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
3215 hg: parse error: 11 is not iterable of mappings
3215 hg: parse error: 11 is not iterable of mappings
3216 (keyword 'rev' does not support map operation)
3216 (keyword 'rev' does not support map operation)
3217 [255]
3217 [255]
3218 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3218 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
3219 hg: parse error: None is not iterable of mappings
3219 hg: parse error: None is not iterable of mappings
3220 [255]
3220 [255]
3221 $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
3221 $ hg log -R latesttag -r tip -T '{extras % "{key}\n" % "{key}\n"}'
3222 hg: parse error: list of strings is not mappable
3222 hg: parse error: list of strings is not mappable
3223 [255]
3223 [255]
3224
3224
3225 Test new-style inline templating of non-list/dict type:
3225 Test new-style inline templating of non-list/dict type:
3226
3226
3227 $ hg log -R latesttag -r tip -T '{manifest}\n'
3227 $ hg log -R latesttag -r tip -T '{manifest}\n'
3228 11:2bc6e9006ce2
3228 11:2bc6e9006ce2
3229 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3229 $ hg log -R latesttag -r tip -T 'string length: {manifest|count}\n'
3230 string length: 15
3230 string length: 15
3231 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3231 $ hg log -R latesttag -r tip -T '{manifest % "{rev}:{node}"}\n'
3232 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3232 11:2bc6e9006ce29882383a22d39fd1f4e66dd3e2fc
3233
3233
3234 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3234 $ hg log -R latesttag -r tip -T '{get(extras, "branch") % "{key}: {value}\n"}'
3235 branch: default
3235 branch: default
3236 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3236 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "{key}\n"}'
3237 hg: parse error: None is not iterable of mappings
3237 hg: parse error: None is not iterable of mappings
3238 [255]
3238 [255]
3239 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3239 $ hg log -R latesttag -r tip -T '{min(extras) % "{key}: {value}\n"}'
3240 branch: default
3240 branch: default
3241 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3241 $ hg log -R latesttag -l1 -T '{min(revset("0:9")) % "{rev}:{node|short}\n"}'
3242 0:ce3cec86e6c2
3242 0:ce3cec86e6c2
3243 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3243 $ hg log -R latesttag -l1 -T '{max(revset("0:9")) % "{rev}:{node|short}\n"}'
3244 9:fbc7cd862e9c
3244 9:fbc7cd862e9c
3245
3245
3246 Test manifest/get() can be join()-ed as string, though it's silly:
3246 Test manifest/get() can be join()-ed as string, though it's silly:
3247
3247
3248 $ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n'
3248 $ hg log -R latesttag -r tip -T '{join(manifest, ".")}\n'
3249 1.1.:.2.b.c.6.e.9.0.0.6.c.e.2
3249 1.1.:.2.b.c.6.e.9.0.0.6.c.e.2
3250 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), ".")}\n'
3250 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), ".")}\n'
3251 d.e.f.a.u.l.t
3251 d.e.f.a.u.l.t
3252
3252
3253 Test join() over string
3253 Test join() over string
3254
3254
3255 $ hg log -R latesttag -r tip -T '{join(rev|stringify, ".")}\n'
3255 $ hg log -R latesttag -r tip -T '{join(rev|stringify, ".")}\n'
3256 1.1
3256 1.1
3257
3257
3258 Test join() over uniterable
3258 Test join() over uniterable
3259
3259
3260 $ hg log -R latesttag -r tip -T '{join(rev, "")}\n'
3260 $ hg log -R latesttag -r tip -T '{join(rev, "")}\n'
3261 hg: parse error: 11 is not iterable
3261 hg: parse error: 11 is not iterable
3262 [255]
3262 [255]
3263
3263
3264 Test min/max of integers
3264 Test min/max of integers
3265
3265
3266 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3266 $ hg log -R latesttag -l1 -T '{min(revset("9:10"))}\n'
3267 9
3267 9
3268 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3268 $ hg log -R latesttag -l1 -T '{max(revset("9:10"))}\n'
3269 10
3269 10
3270
3270
3271 Test min/max over map operation:
3271 Test min/max over map operation:
3272
3272
3273 $ hg log -R latesttag -r3 -T '{min(tags % "{tag}")}\n'
3273 $ hg log -R latesttag -r3 -T '{min(tags % "{tag}")}\n'
3274 at3
3274 at3
3275 $ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n'
3275 $ hg log -R latesttag -r3 -T '{max(tags % "{tag}")}\n'
3276 t3
3276 t3
3277
3277
3278 Test min/max of strings:
3278 Test min/max of strings:
3279
3279
3280 $ hg log -R latesttag -l1 -T '{min(desc)}\n'
3280 $ hg log -R latesttag -l1 -T '{min(desc)}\n'
3281 3
3281 3
3282 $ hg log -R latesttag -l1 -T '{max(desc)}\n'
3282 $ hg log -R latesttag -l1 -T '{max(desc)}\n'
3283 t
3283 t
3284
3284
3285 Test min/max of non-iterable:
3285 Test min/max of non-iterable:
3286
3286
3287 $ hg debugtemplate '{min(1)}'
3287 $ hg debugtemplate '{min(1)}'
3288 hg: parse error: 1 is not iterable
3288 hg: parse error: 1 is not iterable
3289 (min first argument should be an iterable)
3289 (min first argument should be an iterable)
3290 [255]
3290 [255]
3291 $ hg debugtemplate '{max(2)}'
3291 $ hg debugtemplate '{max(2)}'
3292 hg: parse error: 2 is not iterable
3292 hg: parse error: 2 is not iterable
3293 (max first argument should be an iterable)
3293 (max first argument should be an iterable)
3294 [255]
3294 [255]
3295
3295
3296 $ hg log -R latesttag -l1 -T '{min(date)}'
3296 $ hg log -R latesttag -l1 -T '{min(date)}'
3297 hg: parse error: date is not iterable
3297 hg: parse error: date is not iterable
3298 (min first argument should be an iterable)
3298 (min first argument should be an iterable)
3299 [255]
3299 [255]
3300 $ hg log -R latesttag -l1 -T '{max(date)}'
3300 $ hg log -R latesttag -l1 -T '{max(date)}'
3301 hg: parse error: date is not iterable
3301 hg: parse error: date is not iterable
3302 (max first argument should be an iterable)
3302 (max first argument should be an iterable)
3303 [255]
3303 [255]
3304
3304
3305 Test min/max of empty sequence:
3305 Test min/max of empty sequence:
3306
3306
3307 $ hg debugtemplate '{min("")}'
3307 $ hg debugtemplate '{min("")}'
3308 hg: parse error: empty string
3308 hg: parse error: empty string
3309 (min first argument should be an iterable)
3309 (min first argument should be an iterable)
3310 [255]
3310 [255]
3311 $ hg debugtemplate '{max("")}'
3311 $ hg debugtemplate '{max("")}'
3312 hg: parse error: empty string
3312 hg: parse error: empty string
3313 (max first argument should be an iterable)
3313 (max first argument should be an iterable)
3314 [255]
3314 [255]
3315 $ hg debugtemplate '{min(dict())}'
3315 $ hg debugtemplate '{min(dict())}'
3316 hg: parse error: empty sequence
3316 hg: parse error: empty sequence
3317 (min first argument should be an iterable)
3317 (min first argument should be an iterable)
3318 [255]
3318 [255]
3319 $ hg debugtemplate '{max(dict())}'
3319 $ hg debugtemplate '{max(dict())}'
3320 hg: parse error: empty sequence
3320 hg: parse error: empty sequence
3321 (max first argument should be an iterable)
3321 (max first argument should be an iterable)
3322 [255]
3322 [255]
3323 $ hg debugtemplate '{min(dict() % "")}'
3323 $ hg debugtemplate '{min(dict() % "")}'
3324 hg: parse error: empty sequence
3324 hg: parse error: empty sequence
3325 (min first argument should be an iterable)
3325 (min first argument should be an iterable)
3326 [255]
3326 [255]
3327 $ hg debugtemplate '{max(dict() % "")}'
3327 $ hg debugtemplate '{max(dict() % "")}'
3328 hg: parse error: empty sequence
3328 hg: parse error: empty sequence
3329 (max first argument should be an iterable)
3329 (max first argument should be an iterable)
3330 [255]
3330 [255]
3331
3331
3332 Test min/max of if() result
3332 Test min/max of if() result
3333
3333
3334 $ cd latesttag
3334 $ cd latesttag
3335 $ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n'
3335 $ hg log -l1 -T '{min(if(true, revset("9:10"), ""))}\n'
3336 9
3336 9
3337 $ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n'
3337 $ hg log -l1 -T '{max(if(false, "", revset("9:10")))}\n'
3338 10
3338 10
3339 $ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n'
3339 $ hg log -l1 -T '{min(ifcontains("a", "aa", revset("9:10"), ""))}\n'
3340 9
3340 9
3341 $ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n'
3341 $ hg log -l1 -T '{max(ifcontains("a", "bb", "", revset("9:10")))}\n'
3342 10
3342 10
3343 $ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n'
3343 $ hg log -l1 -T '{min(ifeq(0, 0, revset("9:10"), ""))}\n'
3344 9
3344 9
3345 $ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n'
3345 $ hg log -l1 -T '{max(ifeq(0, 1, "", revset("9:10")))}\n'
3346 10
3346 10
3347 $ cd ..
3347 $ cd ..
3348
3348
3349 Test laziness of if() then/else clause
3349 Test laziness of if() then/else clause
3350
3350
3351 $ hg debugtemplate '{count(0)}'
3351 $ hg debugtemplate '{count(0)}'
3352 hg: parse error: not countable
3352 hg: parse error: not countable
3353 (incompatible use of template filter 'count')
3353 (incompatible use of template filter 'count')
3354 [255]
3354 [255]
3355 $ hg debugtemplate '{if(true, "", count(0))}'
3355 $ hg debugtemplate '{if(true, "", count(0))}'
3356 $ hg debugtemplate '{if(false, count(0), "")}'
3356 $ hg debugtemplate '{if(false, count(0), "")}'
3357 $ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}'
3357 $ hg debugtemplate '{ifcontains("a", "aa", "", count(0))}'
3358 $ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}'
3358 $ hg debugtemplate '{ifcontains("a", "bb", count(0), "")}'
3359 $ hg debugtemplate '{ifeq(0, 0, "", count(0))}'
3359 $ hg debugtemplate '{ifeq(0, 0, "", count(0))}'
3360 $ hg debugtemplate '{ifeq(0, 1, count(0), "")}'
3360 $ hg debugtemplate '{ifeq(0, 1, count(0), "")}'
3361
3361
3362 Test dot operator precedence:
3362 Test dot operator precedence:
3363
3363
3364 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3364 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3365 (template
3365 (template
3366 (|
3366 (|
3367 (.
3367 (.
3368 (symbol 'manifest')
3368 (symbol 'manifest')
3369 (symbol 'node'))
3369 (symbol 'node'))
3370 (symbol 'short'))
3370 (symbol 'short'))
3371 (string '\n'))
3371 (string '\n'))
3372 89f4071fec70
3372 89f4071fec70
3373
3373
3374 (the following examples are invalid, but seem natural in parsing POV)
3374 (the following examples are invalid, but seem natural in parsing POV)
3375
3375
3376 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3376 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3377 (template
3377 (template
3378 (|
3378 (|
3379 (symbol 'foo')
3379 (symbol 'foo')
3380 (.
3380 (.
3381 (symbol 'bar')
3381 (symbol 'bar')
3382 (symbol 'baz')))
3382 (symbol 'baz')))
3383 (string '\n'))
3383 (string '\n'))
3384 [255]
3384 [255]
3385 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3385 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3386 (template
3386 (template
3387 (.
3387 (.
3388 (symbol 'foo')
3388 (symbol 'foo')
3389 (func
3389 (func
3390 (symbol 'bar')
3390 (symbol 'bar')
3391 None))
3391 None))
3392 (string '\n'))
3392 (string '\n'))
3393 [255]
3393 [255]
3394
3394
3395 Test evaluation of dot operator:
3395 Test evaluation of dot operator:
3396
3396
3397 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3397 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3398 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3398 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3399 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3399 $ hg log -R latesttag -r0 -T '{extras.branch}\n'
3400 default
3400 default
3401 $ hg log -R latesttag -r0 -T '{date.unixtime} {localdate(date, "+0200").tzoffset}\n'
3401 $ hg log -R latesttag -r0 -T '{date.unixtime} {localdate(date, "+0200").tzoffset}\n'
3402 0 -7200
3402 0 -7200
3403
3403
3404 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3404 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3405 hg: parse error: 'test' is not a dictionary
3405 hg: parse error: 'test' is not a dictionary
3406 (keyword 'author' does not support member operation)
3406 (keyword 'author' does not support member operation)
3407 [255]
3407 [255]
3408 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3408 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3409 hg: parse error: 'a' is not a dictionary
3409 hg: parse error: 'a' is not a dictionary
3410 [255]
3410 [255]
3411
3411
3412 Test the sub function of templating for expansion:
3412 Test the sub function of templating for expansion:
3413
3413
3414 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3414 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3415 xx
3415 xx
3416
3416
3417 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3417 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
3418 hg: parse error: sub got an invalid pattern: [
3418 hg: parse error: sub got an invalid pattern: [
3419 [255]
3419 [255]
3420 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3420 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
3421 hg: parse error: sub got an invalid replacement: \1
3421 hg: parse error: sub got an invalid replacement: \1
3422 [255]
3422 [255]
3423
3423
3424 Test the strip function with chars specified:
3424 Test the strip function with chars specified:
3425
3425
3426 $ hg log -R latesttag --template '{desc}\n'
3426 $ hg log -R latesttag --template '{desc}\n'
3427 at3
3427 at3
3428 t5
3428 t5
3429 t4
3429 t4
3430 t3
3430 t3
3431 t2
3431 t2
3432 t1
3432 t1
3433 merge
3433 merge
3434 h2e
3434 h2e
3435 h2d
3435 h2d
3436 h1c
3436 h1c
3437 b
3437 b
3438 a
3438 a
3439
3439
3440 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3440 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
3441 at3
3441 at3
3442 5
3442 5
3443 4
3443 4
3444 3
3444 3
3445 2
3445 2
3446 1
3446 1
3447 merg
3447 merg
3448 h2
3448 h2
3449 h2d
3449 h2d
3450 h1c
3450 h1c
3451 b
3451 b
3452 a
3452 a
3453
3453
3454 Test date format:
3454 Test date format:
3455
3455
3456 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3456 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
3457 date: 70 01 01 10 +0000
3457 date: 70 01 01 10 +0000
3458 date: 70 01 01 09 +0000
3458 date: 70 01 01 09 +0000
3459 date: 70 01 01 04 +0000
3459 date: 70 01 01 04 +0000
3460 date: 70 01 01 08 +0000
3460 date: 70 01 01 08 +0000
3461 date: 70 01 01 07 +0000
3461 date: 70 01 01 07 +0000
3462 date: 70 01 01 06 +0000
3462 date: 70 01 01 06 +0000
3463 date: 70 01 01 05 +0100
3463 date: 70 01 01 05 +0100
3464 date: 70 01 01 04 +0000
3464 date: 70 01 01 04 +0000
3465 date: 70 01 01 03 +0000
3465 date: 70 01 01 03 +0000
3466 date: 70 01 01 02 +0000
3466 date: 70 01 01 02 +0000
3467 date: 70 01 01 01 +0000
3467 date: 70 01 01 01 +0000
3468 date: 70 01 01 00 +0000
3468 date: 70 01 01 00 +0000
3469
3469
3470 Test invalid date:
3470 Test invalid date:
3471
3471
3472 $ hg log -R latesttag -T '{date(rev)}\n'
3472 $ hg log -R latesttag -T '{date(rev)}\n'
3473 hg: parse error: date expects a date information
3473 hg: parse error: date expects a date information
3474 [255]
3474 [255]
3475
3475
3476 Test integer literal:
3476 Test integer literal:
3477
3477
3478 $ hg debugtemplate -v '{(0)}\n'
3478 $ hg debugtemplate -v '{(0)}\n'
3479 (template
3479 (template
3480 (group
3480 (group
3481 (integer '0'))
3481 (integer '0'))
3482 (string '\n'))
3482 (string '\n'))
3483 0
3483 0
3484 $ hg debugtemplate -v '{(123)}\n'
3484 $ hg debugtemplate -v '{(123)}\n'
3485 (template
3485 (template
3486 (group
3486 (group
3487 (integer '123'))
3487 (integer '123'))
3488 (string '\n'))
3488 (string '\n'))
3489 123
3489 123
3490 $ hg debugtemplate -v '{(-4)}\n'
3490 $ hg debugtemplate -v '{(-4)}\n'
3491 (template
3491 (template
3492 (group
3492 (group
3493 (negate
3493 (negate
3494 (integer '4')))
3494 (integer '4')))
3495 (string '\n'))
3495 (string '\n'))
3496 -4
3496 -4
3497 $ hg debugtemplate '{(-)}\n'
3497 $ hg debugtemplate '{(-)}\n'
3498 hg: parse error at 3: not a prefix: )
3498 hg: parse error at 3: not a prefix: )
3499 ({(-)}\n
3499 ({(-)}\n
3500 ^ here)
3500 ^ here)
3501 [255]
3501 [255]
3502 $ hg debugtemplate '{(-a)}\n'
3502 $ hg debugtemplate '{(-a)}\n'
3503 hg: parse error: negation needs an integer argument
3503 hg: parse error: negation needs an integer argument
3504 [255]
3504 [255]
3505
3505
3506 top-level integer literal is interpreted as symbol (i.e. variable name):
3506 top-level integer literal is interpreted as symbol (i.e. variable name):
3507
3507
3508 $ hg debugtemplate -D 1=one -v '{1}\n'
3508 $ hg debugtemplate -D 1=one -v '{1}\n'
3509 (template
3509 (template
3510 (integer '1')
3510 (integer '1')
3511 (string '\n'))
3511 (string '\n'))
3512 one
3512 one
3513 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3513 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
3514 (template
3514 (template
3515 (func
3515 (func
3516 (symbol 'if')
3516 (symbol 'if')
3517 (list
3517 (list
3518 (string 't')
3518 (string 't')
3519 (template
3519 (template
3520 (integer '1'))))
3520 (integer '1'))))
3521 (string '\n'))
3521 (string '\n'))
3522 one
3522 one
3523 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3523 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
3524 (template
3524 (template
3525 (|
3525 (|
3526 (integer '1')
3526 (integer '1')
3527 (symbol 'stringify'))
3527 (symbol 'stringify'))
3528 (string '\n'))
3528 (string '\n'))
3529 one
3529 one
3530
3530
3531 unless explicit symbol is expected:
3531 unless explicit symbol is expected:
3532
3532
3533 $ hg log -Ra -r0 -T '{desc|1}\n'
3533 $ hg log -Ra -r0 -T '{desc|1}\n'
3534 hg: parse error: expected a symbol, got 'integer'
3534 hg: parse error: expected a symbol, got 'integer'
3535 [255]
3535 [255]
3536 $ hg log -Ra -r0 -T '{1()}\n'
3536 $ hg log -Ra -r0 -T '{1()}\n'
3537 hg: parse error: expected a symbol, got 'integer'
3537 hg: parse error: expected a symbol, got 'integer'
3538 [255]
3538 [255]
3539
3539
3540 Test string literal:
3540 Test string literal:
3541
3541
3542 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3542 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
3543 (template
3543 (template
3544 (string 'string with no template fragment')
3544 (string 'string with no template fragment')
3545 (string '\n'))
3545 (string '\n'))
3546 string with no template fragment
3546 string with no template fragment
3547 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3547 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
3548 (template
3548 (template
3549 (template
3549 (template
3550 (string 'template: ')
3550 (string 'template: ')
3551 (symbol 'rev'))
3551 (symbol 'rev'))
3552 (string '\n'))
3552 (string '\n'))
3553 template: 0
3553 template: 0
3554 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3554 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
3555 (template
3555 (template
3556 (string 'rawstring: {rev}')
3556 (string 'rawstring: {rev}')
3557 (string '\n'))
3557 (string '\n'))
3558 rawstring: {rev}
3558 rawstring: {rev}
3559 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3559 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
3560 (template
3560 (template
3561 (%
3561 (%
3562 (symbol 'files')
3562 (symbol 'files')
3563 (string 'rawstring: {file}'))
3563 (string 'rawstring: {file}'))
3564 (string '\n'))
3564 (string '\n'))
3565 rawstring: {file}
3565 rawstring: {file}
3566
3566
3567 Test string escaping:
3567 Test string escaping:
3568
3568
3569 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3569 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3570 >
3570 >
3571 <>\n<[>
3571 <>\n<[>
3572 <>\n<]>
3572 <>\n<]>
3573 <>\n<
3573 <>\n<
3574
3574
3575 $ hg log -R latesttag -r 0 \
3575 $ hg log -R latesttag -r 0 \
3576 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3576 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3577 >
3577 >
3578 <>\n<[>
3578 <>\n<[>
3579 <>\n<]>
3579 <>\n<]>
3580 <>\n<
3580 <>\n<
3581
3581
3582 $ hg log -R latesttag -r 0 -T esc \
3582 $ hg log -R latesttag -r 0 -T esc \
3583 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3583 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3584 >
3584 >
3585 <>\n<[>
3585 <>\n<[>
3586 <>\n<]>
3586 <>\n<]>
3587 <>\n<
3587 <>\n<
3588
3588
3589 $ cat <<'EOF' > esctmpl
3589 $ cat <<'EOF' > esctmpl
3590 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3590 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
3591 > EOF
3591 > EOF
3592 $ hg log -R latesttag -r 0 --style ./esctmpl
3592 $ hg log -R latesttag -r 0 --style ./esctmpl
3593 >
3593 >
3594 <>\n<[>
3594 <>\n<[>
3595 <>\n<]>
3595 <>\n<]>
3596 <>\n<
3596 <>\n<
3597
3597
3598 Test string escaping of quotes:
3598 Test string escaping of quotes:
3599
3599
3600 $ hg log -Ra -r0 -T '{"\""}\n'
3600 $ hg log -Ra -r0 -T '{"\""}\n'
3601 "
3601 "
3602 $ hg log -Ra -r0 -T '{"\\\""}\n'
3602 $ hg log -Ra -r0 -T '{"\\\""}\n'
3603 \"
3603 \"
3604 $ hg log -Ra -r0 -T '{r"\""}\n'
3604 $ hg log -Ra -r0 -T '{r"\""}\n'
3605 \"
3605 \"
3606 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3606 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3607 \\\"
3607 \\\"
3608
3608
3609
3609
3610 $ hg log -Ra -r0 -T '{"\""}\n'
3610 $ hg log -Ra -r0 -T '{"\""}\n'
3611 "
3611 "
3612 $ hg log -Ra -r0 -T '{"\\\""}\n'
3612 $ hg log -Ra -r0 -T '{"\\\""}\n'
3613 \"
3613 \"
3614 $ hg log -Ra -r0 -T '{r"\""}\n'
3614 $ hg log -Ra -r0 -T '{r"\""}\n'
3615 \"
3615 \"
3616 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3616 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3617 \\\"
3617 \\\"
3618
3618
3619 Test exception in quoted template. single backslash before quotation mark is
3619 Test exception in quoted template. single backslash before quotation mark is
3620 stripped before parsing:
3620 stripped before parsing:
3621
3621
3622 $ cat <<'EOF' > escquotetmpl
3622 $ cat <<'EOF' > escquotetmpl
3623 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3623 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3624 > EOF
3624 > EOF
3625 $ cd latesttag
3625 $ cd latesttag
3626 $ hg log -r 2 --style ../escquotetmpl
3626 $ hg log -r 2 --style ../escquotetmpl
3627 " \" \" \\" head1
3627 " \" \" \\" head1
3628
3628
3629 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3629 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3630 valid
3630 valid
3631 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3631 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3632 valid
3632 valid
3633
3633
3634 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3634 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3635 _evalifliteral() templates (issue4733):
3635 _evalifliteral() templates (issue4733):
3636
3636
3637 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3637 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3638 "2
3638 "2
3639 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3639 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3640 "2
3640 "2
3641 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3641 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3642 "2
3642 "2
3643
3643
3644 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3644 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3645 \"
3645 \"
3646 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3646 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3647 \"
3647 \"
3648 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3648 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3649 \"
3649 \"
3650
3650
3651 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3651 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3652 \\\"
3652 \\\"
3653 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3653 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3654 \\\"
3654 \\\"
3655 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3655 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3656 \\\"
3656 \\\"
3657
3657
3658 escaped single quotes and errors:
3658 escaped single quotes and errors:
3659
3659
3660 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3660 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3661 foo
3661 foo
3662 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3662 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3663 foo
3663 foo
3664 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3664 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3665 hg: parse error at 21: unterminated string
3665 hg: parse error at 21: unterminated string
3666 ({if(rev, "{if(rev, \")}")}\n
3666 ({if(rev, "{if(rev, \")}")}\n
3667 ^ here)
3667 ^ here)
3668 [255]
3668 [255]
3669 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3669 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3670 hg: parse error: trailing \ in string
3670 hg: parse error: trailing \ in string
3671 [255]
3671 [255]
3672 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3672 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3673 hg: parse error: trailing \ in string
3673 hg: parse error: trailing \ in string
3674 [255]
3674 [255]
3675
3675
3676 $ cd ..
3676 $ cd ..
3677
3677
3678 Test leading backslashes:
3678 Test leading backslashes:
3679
3679
3680 $ cd latesttag
3680 $ cd latesttag
3681 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3681 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3682 {rev} {file}
3682 {rev} {file}
3683 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3683 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3684 \2 \head1
3684 \2 \head1
3685 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3685 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3686 \{rev} \{file}
3686 \{rev} \{file}
3687 $ cd ..
3687 $ cd ..
3688
3688
3689 Test leading backslashes in "if" expression (issue4714):
3689 Test leading backslashes in "if" expression (issue4714):
3690
3690
3691 $ cd latesttag
3691 $ cd latesttag
3692 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3692 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3693 {rev} \{rev}
3693 {rev} \{rev}
3694 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3694 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3695 \2 \\{rev}
3695 \2 \\{rev}
3696 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3696 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3697 \{rev} \\\{rev}
3697 \{rev} \\\{rev}
3698 $ cd ..
3698 $ cd ..
3699
3699
3700 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3700 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3701
3701
3702 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3702 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3703 \x6e
3703 \x6e
3704 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3704 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3705 \x5c\x786e
3705 \x5c\x786e
3706 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3706 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3707 \x6e
3707 \x6e
3708 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3708 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3709 \x5c\x786e
3709 \x5c\x786e
3710
3710
3711 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3711 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3712 \x6e
3712 \x6e
3713 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3713 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3714 \x5c\x786e
3714 \x5c\x786e
3715 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3715 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3716 \x6e
3716 \x6e
3717 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3717 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3718 \x5c\x786e
3718 \x5c\x786e
3719
3719
3720 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3720 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3721 fourth
3721 fourth
3722 second
3722 second
3723 third
3723 third
3724 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3724 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3725 fourth\nsecond\nthird
3725 fourth\nsecond\nthird
3726
3726
3727 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3727 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3728 <p>
3728 <p>
3729 1st
3729 1st
3730 </p>
3730 </p>
3731 <p>
3731 <p>
3732 2nd
3732 2nd
3733 </p>
3733 </p>
3734 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3734 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3735 <p>
3735 <p>
3736 1st\n\n2nd
3736 1st\n\n2nd
3737 </p>
3737 </p>
3738 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3738 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3739 1st
3739 1st
3740
3740
3741 2nd
3741 2nd
3742
3742
3743 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3743 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3744 o perso
3744 o perso
3745 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3745 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3746 no person
3746 no person
3747 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3747 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3748 o perso
3748 o perso
3749 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3749 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3750 no perso
3750 no perso
3751
3751
3752 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3752 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3753 -o perso-
3753 -o perso-
3754 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3754 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3755 no person
3755 no person
3756 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3756 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3757 \x2do perso\x2d
3757 \x2do perso\x2d
3758 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3758 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3759 -o perso-
3759 -o perso-
3760 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3760 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3761 \x2do perso\x6e
3761 \x2do perso\x6e
3762
3762
3763 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3763 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3764 fourth
3764 fourth
3765 second
3765 second
3766 third
3766 third
3767
3767
3768 Test string escaping in nested expression:
3768 Test string escaping in nested expression:
3769
3769
3770 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3770 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3771 fourth\x6esecond\x6ethird
3771 fourth\x6esecond\x6ethird
3772 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3772 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3773 fourth\x6esecond\x6ethird
3773 fourth\x6esecond\x6ethird
3774
3774
3775 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3775 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3776 fourth\x6esecond\x6ethird
3776 fourth\x6esecond\x6ethird
3777 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3777 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3778 fourth\x5c\x786esecond\x5c\x786ethird
3778 fourth\x5c\x786esecond\x5c\x786ethird
3779
3779
3780 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3780 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3781 3:\x6eo user, \x6eo domai\x6e
3781 3:\x6eo user, \x6eo domai\x6e
3782 4:\x5c\x786eew bra\x5c\x786ech
3782 4:\x5c\x786eew bra\x5c\x786ech
3783
3783
3784 Test quotes in nested expression are evaluated just like a $(command)
3784 Test quotes in nested expression are evaluated just like a $(command)
3785 substitution in POSIX shells:
3785 substitution in POSIX shells:
3786
3786
3787 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3787 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3788 8:95c24699272e
3788 8:95c24699272e
3789 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3789 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3790 {8} "95c24699272e"
3790 {8} "95c24699272e"
3791
3791
3792 Test recursive evaluation:
3792 Test recursive evaluation:
3793
3793
3794 $ hg init r
3794 $ hg init r
3795 $ cd r
3795 $ cd r
3796 $ echo a > a
3796 $ echo a > a
3797 $ hg ci -Am '{rev}'
3797 $ hg ci -Am '{rev}'
3798 adding a
3798 adding a
3799 $ hg log -r 0 --template '{if(rev, desc)}\n'
3799 $ hg log -r 0 --template '{if(rev, desc)}\n'
3800 {rev}
3800 {rev}
3801 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3801 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3802 test 0
3802 test 0
3803
3803
3804 $ hg branch -q 'text.{rev}'
3804 $ hg branch -q 'text.{rev}'
3805 $ echo aa >> aa
3805 $ echo aa >> aa
3806 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3806 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3807
3807
3808 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3808 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3809 {node|short}desc to
3809 {node|short}desc to
3810 text.{rev}be wrapped
3810 text.{rev}be wrapped
3811 text.{rev}desc to be
3811 text.{rev}desc to be
3812 text.{rev}wrapped (no-eol)
3812 text.{rev}wrapped (no-eol)
3813 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3813 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3814 bcc7ff960b8e:desc to
3814 bcc7ff960b8e:desc to
3815 text.1:be wrapped
3815 text.1:be wrapped
3816 text.1:desc to be
3816 text.1:desc to be
3817 text.1:wrapped (no-eol)
3817 text.1:wrapped (no-eol)
3818 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3818 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3819 hg: parse error: fill expects an integer width
3819 hg: parse error: fill expects an integer width
3820 [255]
3820 [255]
3821
3821
3822 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3822 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
3823 bcc7ff960b8e:desc to be
3823 bcc7ff960b8e:desc to be
3824 termwidth.1:wrapped desc
3824 termwidth.1:wrapped desc
3825 termwidth.1:to be wrapped (no-eol)
3825 termwidth.1:to be wrapped (no-eol)
3826
3826
3827 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3827 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3828 {node|short} (no-eol)
3828 {node|short} (no-eol)
3829 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3829 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3830 bcc-ff---b-e (no-eol)
3830 bcc-ff---b-e (no-eol)
3831
3831
3832 $ cat >> .hg/hgrc <<EOF
3832 $ cat >> .hg/hgrc <<EOF
3833 > [extensions]
3833 > [extensions]
3834 > color=
3834 > color=
3835 > [color]
3835 > [color]
3836 > mode=ansi
3836 > mode=ansi
3837 > text.{rev} = red
3837 > text.{rev} = red
3838 > text.1 = green
3838 > text.1 = green
3839 > EOF
3839 > EOF
3840 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3840 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3841 \x1b[0;31mtext\x1b[0m (esc)
3841 \x1b[0;31mtext\x1b[0m (esc)
3842 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3842 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3843 \x1b[0;32mtext\x1b[0m (esc)
3843 \x1b[0;32mtext\x1b[0m (esc)
3844
3844
3845 color effect can be specified without quoting:
3845 color effect can be specified without quoting:
3846
3846
3847 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3847 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3848 \x1b[0;31mtext\x1b[0m (esc)
3848 \x1b[0;31mtext\x1b[0m (esc)
3849
3849
3850 color effects can be nested (issue5413)
3850 color effects can be nested (issue5413)
3851
3851
3852 $ hg debugtemplate --color=always \
3852 $ hg debugtemplate --color=always \
3853 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3853 > '{label(red, "red{label(magenta, "ma{label(cyan, "cyan")}{label(yellow, "yellow")}genta")}")}\n'
3854 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3854 \x1b[0;31mred\x1b[0;35mma\x1b[0;36mcyan\x1b[0m\x1b[0;31m\x1b[0;35m\x1b[0;33myellow\x1b[0m\x1b[0;31m\x1b[0;35mgenta\x1b[0m (esc)
3855
3855
3856 pad() should interact well with color codes (issue5416)
3856 pad() should interact well with color codes (issue5416)
3857
3857
3858 $ hg debugtemplate --color=always \
3858 $ hg debugtemplate --color=always \
3859 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3859 > '{pad(label(red, "red"), 5, label(cyan, "-"))}\n'
3860 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3860 \x1b[0;31mred\x1b[0m\x1b[0;36m-\x1b[0m\x1b[0;36m-\x1b[0m (esc)
3861
3861
3862 label should be no-op if color is disabled:
3862 label should be no-op if color is disabled:
3863
3863
3864 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3864 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3865 text
3865 text
3866 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3866 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3867 text
3867 text
3868
3868
3869 Test branches inside if statement:
3869 Test branches inside if statement:
3870
3870
3871 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3871 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3872 no
3872 no
3873
3873
3874 Test dict constructor:
3874 Test dict constructor:
3875
3875
3876 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3876 $ hg log -r 0 -T '{dict(y=node|short, x=rev)}\n'
3877 y=f7769ec2ab97 x=0
3877 y=f7769ec2ab97 x=0
3878 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3878 $ hg log -r 0 -T '{dict(x=rev, y=node|short) % "{key}={value}\n"}'
3879 x=0
3879 x=0
3880 y=f7769ec2ab97
3880 y=f7769ec2ab97
3881 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3881 $ hg log -r 0 -T '{dict(x=rev, y=node|short)|json}\n'
3882 {"x": 0, "y": "f7769ec2ab97"}
3882 {"x": 0, "y": "f7769ec2ab97"}
3883 $ hg log -r 0 -T '{dict()|json}\n'
3883 $ hg log -r 0 -T '{dict()|json}\n'
3884 {}
3884 {}
3885
3885
3886 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3886 $ hg log -r 0 -T '{dict(rev, node=node|short)}\n'
3887 rev=0 node=f7769ec2ab97
3887 rev=0 node=f7769ec2ab97
3888 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3888 $ hg log -r 0 -T '{dict(rev, node|short)}\n'
3889 rev=0 node=f7769ec2ab97
3889 rev=0 node=f7769ec2ab97
3890
3890
3891 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3891 $ hg log -r 0 -T '{dict(rev, rev=rev)}\n'
3892 hg: parse error: duplicated dict key 'rev' inferred
3892 hg: parse error: duplicated dict key 'rev' inferred
3893 [255]
3893 [255]
3894 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3894 $ hg log -r 0 -T '{dict(node, node|short)}\n'
3895 hg: parse error: duplicated dict key 'node' inferred
3895 hg: parse error: duplicated dict key 'node' inferred
3896 [255]
3896 [255]
3897 $ hg log -r 0 -T '{dict(1 + 2)}'
3897 $ hg log -r 0 -T '{dict(1 + 2)}'
3898 hg: parse error: dict key cannot be inferred
3898 hg: parse error: dict key cannot be inferred
3899 [255]
3899 [255]
3900
3900
3901 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3901 $ hg log -r 0 -T '{dict(x=rev, x=node)}'
3902 hg: parse error: dict got multiple values for keyword argument 'x'
3902 hg: parse error: dict got multiple values for keyword argument 'x'
3903 [255]
3903 [255]
3904
3904
3905 Test get function:
3905 Test get function:
3906
3906
3907 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3907 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3908 default
3908 default
3909 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3909 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3910 default
3910 default
3911 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3911 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3912 hg: parse error: not a dictionary
3912 hg: parse error: not a dictionary
3913 (get() expects a dict as first argument)
3913 (get() expects a dict as first argument)
3914 [255]
3914 [255]
3915
3915
3916 Test json filter applied to wrapped object:
3916 Test json filter applied to wrapped object:
3917
3917
3918 $ hg log -r0 -T '{files|json}\n'
3918 $ hg log -r0 -T '{files|json}\n'
3919 ["a"]
3919 ["a"]
3920 $ hg log -r0 -T '{extras|json}\n'
3920 $ hg log -r0 -T '{extras|json}\n'
3921 {"branch": "default"}
3921 {"branch": "default"}
3922 $ hg log -r0 -T '{date|json}\n'
3922 $ hg log -r0 -T '{date|json}\n'
3923 [0, 0]
3923 [0, 0]
3924
3924
3925 Test json filter applied to map result:
3925 Test json filter applied to map result:
3926
3926
3927 $ hg log -r0 -T '{json(extras % "{key}")}\n'
3927 $ hg log -r0 -T '{json(extras % "{key}")}\n'
3928 ["branch"]
3928 ["branch"]
3929
3929
3930 Test localdate(date, tz) function:
3930 Test localdate(date, tz) function:
3931
3931
3932 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3932 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3933 1970-01-01 09:00 +0900
3933 1970-01-01 09:00 +0900
3934 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3934 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3935 1970-01-01 00:00 +0000
3935 1970-01-01 00:00 +0000
3936 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3936 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "blahUTC")|isodate}\n'
3937 hg: parse error: localdate expects a timezone
3937 hg: parse error: localdate expects a timezone
3938 [255]
3938 [255]
3939 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3939 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3940 1970-01-01 02:00 +0200
3940 1970-01-01 02:00 +0200
3941 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3941 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3942 1970-01-01 00:00 +0000
3942 1970-01-01 00:00 +0000
3943 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3943 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3944 1970-01-01 00:00 +0000
3944 1970-01-01 00:00 +0000
3945 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3945 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3946 hg: parse error: localdate expects a timezone
3946 hg: parse error: localdate expects a timezone
3947 [255]
3947 [255]
3948 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3948 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3949 hg: parse error: localdate expects a timezone
3949 hg: parse error: localdate expects a timezone
3950 [255]
3950 [255]
3951
3951
3952 Test shortest(node) function:
3952 Test shortest(node) function:
3953
3953
3954 $ echo b > b
3954 $ echo b > b
3955 $ hg ci -qAm b
3955 $ hg ci -qAm b
3956 $ hg log --template '{shortest(node)}\n'
3956 $ hg log --template '{shortest(node)}\n'
3957 e777
3957 e777
3958 bcc7
3958 bcc7
3959 f776
3959 f776
3960 $ hg log --template '{shortest(node, 10)}\n'
3960 $ hg log --template '{shortest(node, 10)}\n'
3961 e777603221
3961 e777603221
3962 bcc7ff960b
3962 bcc7ff960b
3963 f7769ec2ab
3963 f7769ec2ab
3964 $ hg log --template '{node|shortest}\n' -l1
3964 $ hg log --template '{node|shortest}\n' -l1
3965 e777
3965 e777
3966
3966
3967 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3967 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3968 f7769ec2ab
3968 f7769ec2ab
3969 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3969 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3970 hg: parse error: shortest() expects an integer minlength
3970 hg: parse error: shortest() expects an integer minlength
3971 [255]
3971 [255]
3972
3972
3973 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3973 $ hg log -r 'wdir()' -T '{node|shortest}\n'
3974 ffff
3974 ffff
3975
3975
3976 $ hg log --template '{shortest("f")}\n' -l1
3976 $ hg log --template '{shortest("f")}\n' -l1
3977 f
3977 f
3978
3978
3979 $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1
3979 $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1
3980 0123456789012345678901234567890123456789
3980 0123456789012345678901234567890123456789
3981
3981
3982 $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1
3982 $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1
3983 01234567890123456789012345678901234567890123456789
3983 01234567890123456789012345678901234567890123456789
3984
3984
3985 $ hg log --template '{shortest("not a hex string")}\n' -l1
3985 $ hg log --template '{shortest("not a hex string")}\n' -l1
3986 not a hex string
3986 not a hex string
3987
3987
3988 $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1
3988 $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1
3989 not a hex string, but it's 40 bytes long
3989 not a hex string, but it's 40 bytes long
3990
3990
3991 $ hg log --template '{shortest("ffffffffffffffffffffffffffffffffffffffff")}\n' -l1
3991 $ hg log --template '{shortest("ffffffffffffffffffffffffffffffffffffffff")}\n' -l1
3992 ffff
3992 ffff
3993
3993
3994 $ hg log --template '{shortest("fffffff")}\n' -l1
3994 $ hg log --template '{shortest("fffffff")}\n' -l1
3995 ffff
3995 ffff
3996
3996
3997 $ hg log --template '{shortest("ff")}\n' -l1
3997 $ hg log --template '{shortest("ff")}\n' -l1
3998 ffff
3998 ffff
3999
3999
4000 $ cd ..
4000 $ cd ..
4001
4001
4002 Test shortest(node) with the repo having short hash collision:
4002 Test shortest(node) with the repo having short hash collision:
4003
4003
4004 $ hg init hashcollision
4004 $ hg init hashcollision
4005 $ cd hashcollision
4005 $ cd hashcollision
4006 $ cat <<EOF >> .hg/hgrc
4006 $ cat <<EOF >> .hg/hgrc
4007 > [experimental]
4007 > [experimental]
4008 > evolution.createmarkers=True
4008 > evolution.createmarkers=True
4009 > EOF
4009 > EOF
4010 $ echo 0 > a
4010 $ echo 0 > a
4011 $ hg ci -qAm 0
4011 $ hg ci -qAm 0
4012 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
4012 $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
4013 > hg up -q 0
4013 > hg up -q 0
4014 > echo $i > a
4014 > echo $i > a
4015 > hg ci -qm $i
4015 > hg ci -qm $i
4016 > done
4016 > done
4017 $ hg up -q null
4017 $ hg up -q null
4018 $ hg log -r0: -T '{rev}:{node}\n'
4018 $ hg log -r0: -T '{rev}:{node}\n'
4019 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
4019 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
4020 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
4020 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
4021 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
4021 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
4022 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
4022 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
4023 4:10776689e627b465361ad5c296a20a487e153ca4
4023 4:10776689e627b465361ad5c296a20a487e153ca4
4024 5:a00be79088084cb3aff086ab799f8790e01a976b
4024 5:a00be79088084cb3aff086ab799f8790e01a976b
4025 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
4025 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
4026 7:a0457b3450b8e1b778f1163b31a435802987fe5d
4026 7:a0457b3450b8e1b778f1163b31a435802987fe5d
4027 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
4027 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
4028 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
4028 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
4029 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
4029 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
4030 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
4030 $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
4031 obsoleted 1 changesets
4031 obsoleted 1 changesets
4032 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
4032 $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
4033 obsoleted 1 changesets
4033 obsoleted 1 changesets
4034 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
4034 $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
4035 obsoleted 1 changesets
4035 obsoleted 1 changesets
4036
4036
4037 nodes starting with '11' (we don't have the revision number '11' though)
4037 nodes starting with '11' (we don't have the revision number '11' though)
4038
4038
4039 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
4039 $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
4040 1:1142
4040 1:1142
4041 2:1140
4041 2:1140
4042 3:11d
4042 3:11d
4043
4043
4044 '5:a00' is hidden, but still we have two nodes starting with 'a0'
4044 '5:a00' is hidden, but still we have two nodes starting with 'a0'
4045
4045
4046 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
4046 $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
4047 6:a0b
4047 6:a0b
4048 7:a04
4048 7:a04
4049
4049
4050 node '10' conflicts with the revision number '10' even if it is hidden
4050 node '10' conflicts with the revision number '10' even if it is hidden
4051 (we could exclude hidden revision numbers, but currently we don't)
4051 (we could exclude hidden revision numbers, but currently we don't)
4052
4052
4053 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
4053 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
4054 4:107
4054 4:107
4055 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
4055 $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
4056 4:107
4056 4:107
4057
4057
4058 node 'c562' should be unique if the other 'c562' nodes are hidden
4058 node 'c562' should be unique if the other 'c562' nodes are hidden
4059 (but we don't try the slow path to filter out hidden nodes for now)
4059 (but we don't try the slow path to filter out hidden nodes for now)
4060
4060
4061 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
4061 $ hg log -r 8 -T '{rev}:{node|shortest}\n'
4062 8:c5625
4062 8:c5625
4063 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
4063 $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
4064 8:c5625
4064 8:c5625
4065 9:c5623
4065 9:c5623
4066 10:c562d
4066 10:c562d
4067
4067
4068 $ cd ..
4068 $ cd ..
4069
4069
4070 Test pad function
4070 Test pad function
4071
4071
4072 $ cd r
4072 $ cd r
4073
4073
4074 $ hg log --template '{pad(rev, 20)} {author|user}\n'
4074 $ hg log --template '{pad(rev, 20)} {author|user}\n'
4075 2 test
4075 2 test
4076 1 {node|short}
4076 1 {node|short}
4077 0 test
4077 0 test
4078
4078
4079 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
4079 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
4080 2 test
4080 2 test
4081 1 {node|short}
4081 1 {node|short}
4082 0 test
4082 0 test
4083
4083
4084 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
4084 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
4085 2------------------- test
4085 2------------------- test
4086 1------------------- {node|short}
4086 1------------------- {node|short}
4087 0------------------- test
4087 0------------------- test
4088
4088
4089 Test template string in pad function
4089 Test template string in pad function
4090
4090
4091 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
4091 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
4092 {0} test
4092 {0} test
4093
4093
4094 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
4094 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
4095 \{rev} test
4095 \{rev} test
4096
4096
4097 Test width argument passed to pad function
4097 Test width argument passed to pad function
4098
4098
4099 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
4099 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
4100 0 test
4100 0 test
4101 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
4101 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
4102 hg: parse error: pad() expects an integer width
4102 hg: parse error: pad() expects an integer width
4103 [255]
4103 [255]
4104
4104
4105 Test invalid fillchar passed to pad function
4105 Test invalid fillchar passed to pad function
4106
4106
4107 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
4107 $ hg log -r 0 -T '{pad(rev, 10, "")}\n'
4108 hg: parse error: pad() expects a single fill character
4108 hg: parse error: pad() expects a single fill character
4109 [255]
4109 [255]
4110 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
4110 $ hg log -r 0 -T '{pad(rev, 10, "--")}\n'
4111 hg: parse error: pad() expects a single fill character
4111 hg: parse error: pad() expects a single fill character
4112 [255]
4112 [255]
4113
4113
4114 Test boolean argument passed to pad function
4114 Test boolean argument passed to pad function
4115
4115
4116 no crash
4116 no crash
4117
4117
4118 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
4118 $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
4119 ---------0
4119 ---------0
4120
4120
4121 string/literal
4121 string/literal
4122
4122
4123 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
4123 $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
4124 ---------0
4124 ---------0
4125 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
4125 $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
4126 0---------
4126 0---------
4127 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
4127 $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
4128 0---------
4128 0---------
4129
4129
4130 unknown keyword is evaluated to ''
4130 unknown keyword is evaluated to ''
4131
4131
4132 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
4132 $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
4133 0---------
4133 0---------
4134
4134
4135 Test separate function
4135 Test separate function
4136
4136
4137 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
4137 $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
4138 a-b-c
4138 a-b-c
4139 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
4139 $ hg log -r 0 -T '{separate(" ", "{rev}:{node|short}", author|user, branch)}\n'
4140 0:f7769ec2ab97 test default
4140 0:f7769ec2ab97 test default
4141 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
4141 $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
4142 a \x1b[0;31mb\x1b[0m c d (esc)
4142 a \x1b[0;31mb\x1b[0m c d (esc)
4143
4143
4144 Test boolean expression/literal passed to if function
4144 Test boolean expression/literal passed to if function
4145
4145
4146 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
4146 $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
4147 rev 0 is True
4147 rev 0 is True
4148 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
4148 $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
4149 literal 0 is True as well
4149 literal 0 is True as well
4150 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
4150 $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
4151 empty string is False
4151 empty string is False
4152 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
4152 $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
4153 empty list is False
4153 empty list is False
4154 $ hg log -r 0 -T '{if(revset(r"0"), "non-empty list is True")}\n'
4155 non-empty list is True
4156 $ hg log -r 0 -T '{if(revset(r"0") % "", "list of empty strings is True")}\n'
4157 list of empty strings is True
4154 $ hg log -r 0 -T '{if(true, "true is True")}\n'
4158 $ hg log -r 0 -T '{if(true, "true is True")}\n'
4155 true is True
4159 true is True
4156 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
4160 $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
4157 false is False
4161 false is False
4158 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
4162 $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
4159 non-empty string is True
4163 non-empty string is True
4160
4164
4161 Test ifcontains function
4165 Test ifcontains function
4162
4166
4163 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
4167 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
4164 2 is in the string
4168 2 is in the string
4165 1 is not
4169 1 is not
4166 0 is in the string
4170 0 is in the string
4167
4171
4168 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
4172 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
4169 2 is in the string
4173 2 is in the string
4170 1 is not
4174 1 is not
4171 0 is in the string
4175 0 is in the string
4172
4176
4173 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
4177 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
4174 2 did not add a
4178 2 did not add a
4175 1 did not add a
4179 1 did not add a
4176 0 added a
4180 0 added a
4177
4181
4178 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
4182 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
4179 2 is parent of 1
4183 2 is parent of 1
4180 1
4184 1
4181 0
4185 0
4182
4186
4183 $ hg log -l1 -T '{ifcontains("branch", extras, "t", "f")}\n'
4187 $ hg log -l1 -T '{ifcontains("branch", extras, "t", "f")}\n'
4184 t
4188 t
4185 $ hg log -l1 -T '{ifcontains("branch", extras % "{key}", "t", "f")}\n'
4189 $ hg log -l1 -T '{ifcontains("branch", extras % "{key}", "t", "f")}\n'
4186 t
4190 t
4187 $ hg log -l1 -T '{ifcontains("branc", extras % "{key}", "t", "f")}\n'
4191 $ hg log -l1 -T '{ifcontains("branc", extras % "{key}", "t", "f")}\n'
4188 f
4192 f
4189 $ hg log -l1 -T '{ifcontains("branc", stringify(extras % "{key}"), "t", "f")}\n'
4193 $ hg log -l1 -T '{ifcontains("branc", stringify(extras % "{key}"), "t", "f")}\n'
4190 t
4194 t
4191
4195
4192 Test revset function
4196 Test revset function
4193
4197
4194 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4198 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
4195 2 current rev
4199 2 current rev
4196 1 not current rev
4200 1 not current rev
4197 0 not current rev
4201 0 not current rev
4198
4202
4199 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4203 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
4200 2 match rev
4204 2 match rev
4201 1 match rev
4205 1 match rev
4202 0 not match rev
4206 0 not match rev
4203
4207
4204 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4208 $ hg log -T '{ifcontains(desc, revset(":"), "", "type not match")}\n' -l1
4205 type not match
4209 type not match
4206
4210
4207 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4211 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
4208 2 Parents: 1
4212 2 Parents: 1
4209 1 Parents: 0
4213 1 Parents: 0
4210 0 Parents:
4214 0 Parents:
4211
4215
4212 $ cat >> .hg/hgrc <<EOF
4216 $ cat >> .hg/hgrc <<EOF
4213 > [revsetalias]
4217 > [revsetalias]
4214 > myparents(\$1) = parents(\$1)
4218 > myparents(\$1) = parents(\$1)
4215 > EOF
4219 > EOF
4216 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4220 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
4217 2 Parents: 1
4221 2 Parents: 1
4218 1 Parents: 0
4222 1 Parents: 0
4219 0 Parents:
4223 0 Parents:
4220
4224
4221 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4225 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
4222 Rev: 2
4226 Rev: 2
4223 Ancestor: 0
4227 Ancestor: 0
4224 Ancestor: 1
4228 Ancestor: 1
4225 Ancestor: 2
4229 Ancestor: 2
4226
4230
4227 Rev: 1
4231 Rev: 1
4228 Ancestor: 0
4232 Ancestor: 0
4229 Ancestor: 1
4233 Ancestor: 1
4230
4234
4231 Rev: 0
4235 Rev: 0
4232 Ancestor: 0
4236 Ancestor: 0
4233
4237
4234 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4238 $ hg log --template '{revset("TIP"|lower)}\n' -l1
4235 2
4239 2
4236
4240
4237 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4241 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
4238 2
4242 2
4239
4243
4240 a list template is evaluated for each item of revset/parents
4244 a list template is evaluated for each item of revset/parents
4241
4245
4242 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4246 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
4243 2 p: 1:bcc7ff960b8e
4247 2 p: 1:bcc7ff960b8e
4244 1 p: 0:f7769ec2ab97
4248 1 p: 0:f7769ec2ab97
4245 0 p:
4249 0 p:
4246
4250
4247 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4251 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
4248 2 p: 1:bcc7ff960b8e -1:000000000000
4252 2 p: 1:bcc7ff960b8e -1:000000000000
4249 1 p: 0:f7769ec2ab97 -1:000000000000
4253 1 p: 0:f7769ec2ab97 -1:000000000000
4250 0 p: -1:000000000000 -1:000000000000
4254 0 p: -1:000000000000 -1:000000000000
4251
4255
4252 therefore, 'revcache' should be recreated for each rev
4256 therefore, 'revcache' should be recreated for each rev
4253
4257
4254 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4258 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
4255 2 aa b
4259 2 aa b
4256 p
4260 p
4257 1
4261 1
4258 p a
4262 p a
4259 0 a
4263 0 a
4260 p
4264 p
4261
4265
4262 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4266 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
4263 2 aa b
4267 2 aa b
4264 p
4268 p
4265 1
4269 1
4266 p a
4270 p a
4267 0 a
4271 0 a
4268 p
4272 p
4269
4273
4270 a revset item must be evaluated as an integer revision, not an offset from tip
4274 a revset item must be evaluated as an integer revision, not an offset from tip
4271
4275
4272 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4276 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
4273 -1:000000000000
4277 -1:000000000000
4274 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4278 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
4275 -1:000000000000
4279 -1:000000000000
4276
4280
4277 join() should pick '{rev}' from revset items:
4281 join() should pick '{rev}' from revset items:
4278
4282
4279 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4283 $ hg log -R ../a -T '{join(revset("parents(%d)", rev), ", ")}\n' -r6
4280 4, 5
4284 4, 5
4281
4285
4282 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4286 on the other hand, parents are formatted as '{rev}:{node|formatnode}' by
4283 default. join() should agree with the default formatting:
4287 default. join() should agree with the default formatting:
4284
4288
4285 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4289 $ hg log -R ../a -T '{join(parents, ", ")}\n' -r6
4286 5:13207e5a10d9, 4:bbe44766e73d
4290 5:13207e5a10d9, 4:bbe44766e73d
4287
4291
4288 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4292 $ hg log -R ../a -T '{join(parents, ",\n")}\n' -r6 --debug
4289 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4293 5:13207e5a10d9fd28ec424934298e176197f2c67f,
4290 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4294 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
4291
4295
4292 Invalid arguments passed to revset()
4296 Invalid arguments passed to revset()
4293
4297
4294 $ hg log -T '{revset("%whatever", 0)}\n'
4298 $ hg log -T '{revset("%whatever", 0)}\n'
4295 hg: parse error: unexpected revspec format character w
4299 hg: parse error: unexpected revspec format character w
4296 [255]
4300 [255]
4297 $ hg log -T '{revset("%lwhatever", files)}\n'
4301 $ hg log -T '{revset("%lwhatever", files)}\n'
4298 hg: parse error: unexpected revspec format character w
4302 hg: parse error: unexpected revspec format character w
4299 [255]
4303 [255]
4300 $ hg log -T '{revset("%s %s", 0)}\n'
4304 $ hg log -T '{revset("%s %s", 0)}\n'
4301 hg: parse error: missing argument for revspec
4305 hg: parse error: missing argument for revspec
4302 [255]
4306 [255]
4303 $ hg log -T '{revset("", 0)}\n'
4307 $ hg log -T '{revset("", 0)}\n'
4304 hg: parse error: too many revspec arguments specified
4308 hg: parse error: too many revspec arguments specified
4305 [255]
4309 [255]
4306 $ hg log -T '{revset("%s", 0, 1)}\n'
4310 $ hg log -T '{revset("%s", 0, 1)}\n'
4307 hg: parse error: too many revspec arguments specified
4311 hg: parse error: too many revspec arguments specified
4308 [255]
4312 [255]
4309 $ hg log -T '{revset("%", 0)}\n'
4313 $ hg log -T '{revset("%", 0)}\n'
4310 hg: parse error: incomplete revspec format character
4314 hg: parse error: incomplete revspec format character
4311 [255]
4315 [255]
4312 $ hg log -T '{revset("%l", 0)}\n'
4316 $ hg log -T '{revset("%l", 0)}\n'
4313 hg: parse error: incomplete revspec format character
4317 hg: parse error: incomplete revspec format character
4314 [255]
4318 [255]
4315 $ hg log -T '{revset("%d", 'foo')}\n'
4319 $ hg log -T '{revset("%d", 'foo')}\n'
4316 hg: parse error: invalid argument for revspec
4320 hg: parse error: invalid argument for revspec
4317 [255]
4321 [255]
4318 $ hg log -T '{revset("%ld", files)}\n'
4322 $ hg log -T '{revset("%ld", files)}\n'
4319 hg: parse error: invalid argument for revspec
4323 hg: parse error: invalid argument for revspec
4320 [255]
4324 [255]
4321 $ hg log -T '{revset("%ls", 0)}\n'
4325 $ hg log -T '{revset("%ls", 0)}\n'
4322 hg: parse error: invalid argument for revspec
4326 hg: parse error: invalid argument for revspec
4323 [255]
4327 [255]
4324 $ hg log -T '{revset("%b", 'foo')}\n'
4328 $ hg log -T '{revset("%b", 'foo')}\n'
4325 hg: parse error: invalid argument for revspec
4329 hg: parse error: invalid argument for revspec
4326 [255]
4330 [255]
4327 $ hg log -T '{revset("%lb", files)}\n'
4331 $ hg log -T '{revset("%lb", files)}\n'
4328 hg: parse error: invalid argument for revspec
4332 hg: parse error: invalid argument for revspec
4329 [255]
4333 [255]
4330 $ hg log -T '{revset("%r", 0)}\n'
4334 $ hg log -T '{revset("%r", 0)}\n'
4331 hg: parse error: invalid argument for revspec
4335 hg: parse error: invalid argument for revspec
4332 [255]
4336 [255]
4333
4337
4334 Test 'originalnode'
4338 Test 'originalnode'
4335
4339
4336 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
4340 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
4337 000000000000 bcc7ff960b8e
4341 000000000000 bcc7ff960b8e
4338 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
4342 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
4339 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
4343 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
4340
4344
4341 Test files function
4345 Test files function
4342
4346
4343 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4347 $ hg log -T "{rev}\n{join(files('*'), '\n')}\n"
4344 2
4348 2
4345 a
4349 a
4346 aa
4350 aa
4347 b
4351 b
4348 1
4352 1
4349 a
4353 a
4350 0
4354 0
4351 a
4355 a
4352
4356
4353 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4357 $ hg log -T "{rev}\n{join(files('aa'), '\n')}\n"
4354 2
4358 2
4355 aa
4359 aa
4356 1
4360 1
4357
4361
4358 0
4362 0
4359
4363
4360 $ hg rm a
4364 $ hg rm a
4361 $ hg log -r "wdir()" -T "{rev}\n{join(files('*'), '\n')}\n"
4365 $ hg log -r "wdir()" -T "{rev}\n{join(files('*'), '\n')}\n"
4362 2147483647
4366 2147483647
4363 aa
4367 aa
4364 b
4368 b
4365 $ hg revert a
4369 $ hg revert a
4366
4370
4367 Test relpath function
4371 Test relpath function
4368
4372
4369 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4373 $ hg log -r0 -T '{files % "{file|relpath}\n"}'
4370 a
4374 a
4371 $ cd ..
4375 $ cd ..
4372 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4376 $ hg log -R r -r0 -T '{files % "{file|relpath}\n"}'
4373 r/a
4377 r/a
4374 $ cd r
4378 $ cd r
4375
4379
4376 Test active bookmark templating
4380 Test active bookmark templating
4377
4381
4378 $ hg book foo
4382 $ hg book foo
4379 $ hg book bar
4383 $ hg book bar
4380 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4384 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
4381 2 bar* foo
4385 2 bar* foo
4382 1
4386 1
4383 0
4387 0
4384 $ hg log --template "{rev} {activebookmark}\n"
4388 $ hg log --template "{rev} {activebookmark}\n"
4385 2 bar
4389 2 bar
4386 1
4390 1
4387 0
4391 0
4388 $ hg bookmarks --inactive bar
4392 $ hg bookmarks --inactive bar
4389 $ hg log --template "{rev} {activebookmark}\n"
4393 $ hg log --template "{rev} {activebookmark}\n"
4390 2
4394 2
4391 1
4395 1
4392 0
4396 0
4393 $ hg book -r1 baz
4397 $ hg book -r1 baz
4394 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4398 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
4395 2 bar foo
4399 2 bar foo
4396 1 baz
4400 1 baz
4397 0
4401 0
4398 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4402 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
4399 2 t
4403 2 t
4400 1 f
4404 1 f
4401 0 f
4405 0 f
4402
4406
4403 Test namespaces dict
4407 Test namespaces dict
4404
4408
4405 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4409 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
4406 2
4410 2
4407 bookmarks color=bookmark builtin=True
4411 bookmarks color=bookmark builtin=True
4408 bar,foo
4412 bar,foo
4409 tags color=tag builtin=True
4413 tags color=tag builtin=True
4410 tip
4414 tip
4411 branches color=branch builtin=True
4415 branches color=branch builtin=True
4412 text.{rev}
4416 text.{rev}
4413 revnames color=revname builtin=False
4417 revnames color=revname builtin=False
4414 r2
4418 r2
4415
4419
4416 1
4420 1
4417 bookmarks color=bookmark builtin=True
4421 bookmarks color=bookmark builtin=True
4418 baz
4422 baz
4419 tags color=tag builtin=True
4423 tags color=tag builtin=True
4420
4424
4421 branches color=branch builtin=True
4425 branches color=branch builtin=True
4422 text.{rev}
4426 text.{rev}
4423 revnames color=revname builtin=False
4427 revnames color=revname builtin=False
4424 r1
4428 r1
4425
4429
4426 0
4430 0
4427 bookmarks color=bookmark builtin=True
4431 bookmarks color=bookmark builtin=True
4428
4432
4429 tags color=tag builtin=True
4433 tags color=tag builtin=True
4430
4434
4431 branches color=branch builtin=True
4435 branches color=branch builtin=True
4432 default
4436 default
4433 revnames color=revname builtin=False
4437 revnames color=revname builtin=False
4434 r0
4438 r0
4435
4439
4436 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4440 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
4437 bookmarks: bar foo
4441 bookmarks: bar foo
4438 tags: tip
4442 tags: tip
4439 branches: text.{rev}
4443 branches: text.{rev}
4440 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4444 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
4441 bookmarks:
4445 bookmarks:
4442 bar
4446 bar
4443 foo
4447 foo
4444 tags:
4448 tags:
4445 tip
4449 tip
4446 branches:
4450 branches:
4447 text.{rev}
4451 text.{rev}
4448 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4452 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
4449 bar
4453 bar
4450 foo
4454 foo
4451 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4455 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
4452 bar
4456 bar
4453 foo
4457 foo
4454
4458
4455 Test stringify on sub expressions
4459 Test stringify on sub expressions
4456
4460
4457 $ cd ..
4461 $ cd ..
4458 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4462 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
4459 fourth, second, third
4463 fourth, second, third
4460 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4464 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
4461 abc
4465 abc
4462
4466
4463 Test splitlines
4467 Test splitlines
4464
4468
4465 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4469 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
4466 @ foo Modify, add, remove, rename
4470 @ foo Modify, add, remove, rename
4467 |
4471 |
4468 o foo future
4472 o foo future
4469 |
4473 |
4470 o foo third
4474 o foo third
4471 |
4475 |
4472 o foo second
4476 o foo second
4473
4477
4474 o foo merge
4478 o foo merge
4475 |\
4479 |\
4476 | o foo new head
4480 | o foo new head
4477 | |
4481 | |
4478 o | foo new branch
4482 o | foo new branch
4479 |/
4483 |/
4480 o foo no user, no domain
4484 o foo no user, no domain
4481 |
4485 |
4482 o foo no person
4486 o foo no person
4483 |
4487 |
4484 o foo other 1
4488 o foo other 1
4485 | foo other 2
4489 | foo other 2
4486 | foo
4490 | foo
4487 | foo other 3
4491 | foo other 3
4488 o foo line 1
4492 o foo line 1
4489 foo line 2
4493 foo line 2
4490
4494
4491 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4495 $ hg log -R a -r0 -T '{desc|splitlines}\n'
4492 line 1 line 2
4496 line 1 line 2
4493 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4497 $ hg log -R a -r0 -T '{join(desc|splitlines, "|")}\n'
4494 line 1|line 2
4498 line 1|line 2
4495
4499
4496 Test startswith
4500 Test startswith
4497 $ hg log -Gv -R a --template "{startswith(desc)}"
4501 $ hg log -Gv -R a --template "{startswith(desc)}"
4498 hg: parse error: startswith expects two arguments
4502 hg: parse error: startswith expects two arguments
4499 [255]
4503 [255]
4500
4504
4501 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4505 $ hg log -Gv -R a --template "{startswith('line', desc)}"
4502 @
4506 @
4503 |
4507 |
4504 o
4508 o
4505 |
4509 |
4506 o
4510 o
4507 |
4511 |
4508 o
4512 o
4509
4513
4510 o
4514 o
4511 |\
4515 |\
4512 | o
4516 | o
4513 | |
4517 | |
4514 o |
4518 o |
4515 |/
4519 |/
4516 o
4520 o
4517 |
4521 |
4518 o
4522 o
4519 |
4523 |
4520 o
4524 o
4521 |
4525 |
4522 o line 1
4526 o line 1
4523 line 2
4527 line 2
4524
4528
4525 Test bad template with better error message
4529 Test bad template with better error message
4526
4530
4527 $ hg log -Gv -R a --template '{desc|user()}'
4531 $ hg log -Gv -R a --template '{desc|user()}'
4528 hg: parse error: expected a symbol, got 'func'
4532 hg: parse error: expected a symbol, got 'func'
4529 [255]
4533 [255]
4530
4534
4531 Test word function (including index out of bounds graceful failure)
4535 Test word function (including index out of bounds graceful failure)
4532
4536
4533 $ hg log -Gv -R a --template "{word('1', desc)}"
4537 $ hg log -Gv -R a --template "{word('1', desc)}"
4534 @ add,
4538 @ add,
4535 |
4539 |
4536 o
4540 o
4537 |
4541 |
4538 o
4542 o
4539 |
4543 |
4540 o
4544 o
4541
4545
4542 o
4546 o
4543 |\
4547 |\
4544 | o head
4548 | o head
4545 | |
4549 | |
4546 o | branch
4550 o | branch
4547 |/
4551 |/
4548 o user,
4552 o user,
4549 |
4553 |
4550 o person
4554 o person
4551 |
4555 |
4552 o 1
4556 o 1
4553 |
4557 |
4554 o 1
4558 o 1
4555
4559
4556
4560
4557 Test word third parameter used as splitter
4561 Test word third parameter used as splitter
4558
4562
4559 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4563 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
4560 @ M
4564 @ M
4561 |
4565 |
4562 o future
4566 o future
4563 |
4567 |
4564 o third
4568 o third
4565 |
4569 |
4566 o sec
4570 o sec
4567
4571
4568 o merge
4572 o merge
4569 |\
4573 |\
4570 | o new head
4574 | o new head
4571 | |
4575 | |
4572 o | new branch
4576 o | new branch
4573 |/
4577 |/
4574 o n
4578 o n
4575 |
4579 |
4576 o n
4580 o n
4577 |
4581 |
4578 o
4582 o
4579 |
4583 |
4580 o line 1
4584 o line 1
4581 line 2
4585 line 2
4582
4586
4583 Test word error messages for not enough and too many arguments
4587 Test word error messages for not enough and too many arguments
4584
4588
4585 $ hg log -Gv -R a --template "{word('0')}"
4589 $ hg log -Gv -R a --template "{word('0')}"
4586 hg: parse error: word expects two or three arguments, got 1
4590 hg: parse error: word expects two or three arguments, got 1
4587 [255]
4591 [255]
4588
4592
4589 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4593 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
4590 hg: parse error: word expects two or three arguments, got 7
4594 hg: parse error: word expects two or three arguments, got 7
4591 [255]
4595 [255]
4592
4596
4593 Test word for integer literal
4597 Test word for integer literal
4594
4598
4595 $ hg log -R a --template "{word(2, desc)}\n" -r0
4599 $ hg log -R a --template "{word(2, desc)}\n" -r0
4596 line
4600 line
4597
4601
4598 Test word for invalid numbers
4602 Test word for invalid numbers
4599
4603
4600 $ hg log -Gv -R a --template "{word('a', desc)}"
4604 $ hg log -Gv -R a --template "{word('a', desc)}"
4601 hg: parse error: word expects an integer index
4605 hg: parse error: word expects an integer index
4602 [255]
4606 [255]
4603
4607
4604 Test word for out of range
4608 Test word for out of range
4605
4609
4606 $ hg log -R a --template "{word(10000, desc)}"
4610 $ hg log -R a --template "{word(10000, desc)}"
4607 $ hg log -R a --template "{word(-10000, desc)}"
4611 $ hg log -R a --template "{word(-10000, desc)}"
4608
4612
4609 Test indent and not adding to empty lines
4613 Test indent and not adding to empty lines
4610
4614
4611 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4615 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
4612 -----
4616 -----
4613 > line 1
4617 > line 1
4614 >> line 2
4618 >> line 2
4615 -----
4619 -----
4616 > other 1
4620 > other 1
4617 >> other 2
4621 >> other 2
4618
4622
4619 >> other 3
4623 >> other 3
4620
4624
4621 Test with non-strings like dates
4625 Test with non-strings like dates
4622
4626
4623 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4627 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
4624 1200000 0
4628 1200000 0
4625 1300000 0
4629 1300000 0
4626
4630
4627 Test broken string escapes:
4631 Test broken string escapes:
4628
4632
4629 $ hg log -T "bogus\\" -R a
4633 $ hg log -T "bogus\\" -R a
4630 hg: parse error: trailing \ in string
4634 hg: parse error: trailing \ in string
4631 [255]
4635 [255]
4632 $ hg log -T "\\xy" -R a
4636 $ hg log -T "\\xy" -R a
4633 hg: parse error: invalid \x escape* (glob)
4637 hg: parse error: invalid \x escape* (glob)
4634 [255]
4638 [255]
4635
4639
4636 json filter should escape HTML tags so that the output can be embedded in hgweb:
4640 json filter should escape HTML tags so that the output can be embedded in hgweb:
4637
4641
4638 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4642 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
4639 "\u003cfoo@example.org\u003e"
4643 "\u003cfoo@example.org\u003e"
4640
4644
4641 Templater supports aliases of symbol and func() styles:
4645 Templater supports aliases of symbol and func() styles:
4642
4646
4643 $ hg clone -q a aliases
4647 $ hg clone -q a aliases
4644 $ cd aliases
4648 $ cd aliases
4645 $ cat <<EOF >> .hg/hgrc
4649 $ cat <<EOF >> .hg/hgrc
4646 > [templatealias]
4650 > [templatealias]
4647 > r = rev
4651 > r = rev
4648 > rn = "{r}:{node|short}"
4652 > rn = "{r}:{node|short}"
4649 > status(c, files) = files % "{c} {file}\n"
4653 > status(c, files) = files % "{c} {file}\n"
4650 > utcdate(d) = localdate(d, "UTC")
4654 > utcdate(d) = localdate(d, "UTC")
4651 > EOF
4655 > EOF
4652
4656
4653 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4657 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
4654 (template
4658 (template
4655 (symbol 'rn')
4659 (symbol 'rn')
4656 (string ' ')
4660 (string ' ')
4657 (|
4661 (|
4658 (func
4662 (func
4659 (symbol 'utcdate')
4663 (symbol 'utcdate')
4660 (symbol 'date'))
4664 (symbol 'date'))
4661 (symbol 'isodate'))
4665 (symbol 'isodate'))
4662 (string '\n'))
4666 (string '\n'))
4663 * expanded:
4667 * expanded:
4664 (template
4668 (template
4665 (template
4669 (template
4666 (symbol 'rev')
4670 (symbol 'rev')
4667 (string ':')
4671 (string ':')
4668 (|
4672 (|
4669 (symbol 'node')
4673 (symbol 'node')
4670 (symbol 'short')))
4674 (symbol 'short')))
4671 (string ' ')
4675 (string ' ')
4672 (|
4676 (|
4673 (func
4677 (func
4674 (symbol 'localdate')
4678 (symbol 'localdate')
4675 (list
4679 (list
4676 (symbol 'date')
4680 (symbol 'date')
4677 (string 'UTC')))
4681 (string 'UTC')))
4678 (symbol 'isodate'))
4682 (symbol 'isodate'))
4679 (string '\n'))
4683 (string '\n'))
4680 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4684 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4681
4685
4682 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4686 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
4683 (template
4687 (template
4684 (func
4688 (func
4685 (symbol 'status')
4689 (symbol 'status')
4686 (list
4690 (list
4687 (string 'A')
4691 (string 'A')
4688 (symbol 'file_adds'))))
4692 (symbol 'file_adds'))))
4689 * expanded:
4693 * expanded:
4690 (template
4694 (template
4691 (%
4695 (%
4692 (symbol 'file_adds')
4696 (symbol 'file_adds')
4693 (template
4697 (template
4694 (string 'A')
4698 (string 'A')
4695 (string ' ')
4699 (string ' ')
4696 (symbol 'file')
4700 (symbol 'file')
4697 (string '\n'))))
4701 (string '\n'))))
4698 A a
4702 A a
4699
4703
4700 A unary function alias can be called as a filter:
4704 A unary function alias can be called as a filter:
4701
4705
4702 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4706 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
4703 (template
4707 (template
4704 (|
4708 (|
4705 (|
4709 (|
4706 (symbol 'date')
4710 (symbol 'date')
4707 (symbol 'utcdate'))
4711 (symbol 'utcdate'))
4708 (symbol 'isodate'))
4712 (symbol 'isodate'))
4709 (string '\n'))
4713 (string '\n'))
4710 * expanded:
4714 * expanded:
4711 (template
4715 (template
4712 (|
4716 (|
4713 (func
4717 (func
4714 (symbol 'localdate')
4718 (symbol 'localdate')
4715 (list
4719 (list
4716 (symbol 'date')
4720 (symbol 'date')
4717 (string 'UTC')))
4721 (string 'UTC')))
4718 (symbol 'isodate'))
4722 (symbol 'isodate'))
4719 (string '\n'))
4723 (string '\n'))
4720 1970-01-12 13:46 +0000
4724 1970-01-12 13:46 +0000
4721
4725
4722 Aliases should be applied only to command arguments and templates in hgrc.
4726 Aliases should be applied only to command arguments and templates in hgrc.
4723 Otherwise, our stock styles and web templates could be corrupted:
4727 Otherwise, our stock styles and web templates could be corrupted:
4724
4728
4725 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4729 $ hg log -r0 -T '{rn} {utcdate(date)|isodate}\n'
4726 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4730 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4727
4731
4728 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4732 $ hg log -r0 --config ui.logtemplate='"{rn} {utcdate(date)|isodate}\n"'
4729 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4733 0:1e4e1b8f71e0 1970-01-12 13:46 +0000
4730
4734
4731 $ cat <<EOF > tmpl
4735 $ cat <<EOF > tmpl
4732 > changeset = 'nothing expanded:{rn}\n'
4736 > changeset = 'nothing expanded:{rn}\n'
4733 > EOF
4737 > EOF
4734 $ hg log -r0 --style ./tmpl
4738 $ hg log -r0 --style ./tmpl
4735 nothing expanded:
4739 nothing expanded:
4736
4740
4737 Aliases in formatter:
4741 Aliases in formatter:
4738
4742
4739 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4743 $ hg branches -T '{pad(branch, 7)} {rn}\n'
4740 default 6:d41e714fe50d
4744 default 6:d41e714fe50d
4741 foo 4:bbe44766e73d
4745 foo 4:bbe44766e73d
4742
4746
4743 Aliases should honor HGPLAIN:
4747 Aliases should honor HGPLAIN:
4744
4748
4745 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4749 $ HGPLAIN= hg log -r0 -T 'nothing expanded:{rn}\n'
4746 nothing expanded:
4750 nothing expanded:
4747 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4751 $ HGPLAINEXCEPT=templatealias hg log -r0 -T '{rn}\n'
4748 0:1e4e1b8f71e0
4752 0:1e4e1b8f71e0
4749
4753
4750 Unparsable alias:
4754 Unparsable alias:
4751
4755
4752 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4756 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
4753 (template
4757 (template
4754 (symbol 'bad'))
4758 (symbol 'bad'))
4755 abort: bad definition of template alias "bad": at 2: not a prefix: end
4759 abort: bad definition of template alias "bad": at 2: not a prefix: end
4756 [255]
4760 [255]
4757 $ hg log --config templatealias.bad='x(' -T '{bad}'
4761 $ hg log --config templatealias.bad='x(' -T '{bad}'
4758 abort: bad definition of template alias "bad": at 2: not a prefix: end
4762 abort: bad definition of template alias "bad": at 2: not a prefix: end
4759 [255]
4763 [255]
4760
4764
4761 $ cd ..
4765 $ cd ..
4762
4766
4763 Set up repository for non-ascii encoding tests:
4767 Set up repository for non-ascii encoding tests:
4764
4768
4765 $ hg init nonascii
4769 $ hg init nonascii
4766 $ cd nonascii
4770 $ cd nonascii
4767 $ $PYTHON <<EOF
4771 $ $PYTHON <<EOF
4768 > open('latin1', 'wb').write(b'\xe9')
4772 > open('latin1', 'wb').write(b'\xe9')
4769 > open('utf-8', 'wb').write(b'\xc3\xa9')
4773 > open('utf-8', 'wb').write(b'\xc3\xa9')
4770 > EOF
4774 > EOF
4771 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4775 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
4772 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4776 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
4773
4777
4774 json filter should try round-trip conversion to utf-8:
4778 json filter should try round-trip conversion to utf-8:
4775
4779
4776 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4780 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
4777 "\u00e9"
4781 "\u00e9"
4778 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4782 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
4779 "non-ascii branch: \u00e9"
4783 "non-ascii branch: \u00e9"
4780
4784
4781 json filter should take input as utf-8 if it was converted from utf-8:
4785 json filter should take input as utf-8 if it was converted from utf-8:
4782
4786
4783 $ HGENCODING=latin-1 hg log -T "{branch|json}\n" -r0
4787 $ HGENCODING=latin-1 hg log -T "{branch|json}\n" -r0
4784 "\u00e9"
4788 "\u00e9"
4785 $ HGENCODING=latin-1 hg log -T "{desc|json}\n" -r0
4789 $ HGENCODING=latin-1 hg log -T "{desc|json}\n" -r0
4786 "non-ascii branch: \u00e9"
4790 "non-ascii branch: \u00e9"
4787
4791
4788 json filter takes input as utf-8b:
4792 json filter takes input as utf-8b:
4789
4793
4790 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4794 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
4791 "\u00e9"
4795 "\u00e9"
4792 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4796 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
4793 "\udce9"
4797 "\udce9"
4794
4798
4795 utf8 filter:
4799 utf8 filter:
4796
4800
4797 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4801 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
4798 round-trip: c3a9
4802 round-trip: c3a9
4799 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4803 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
4800 decoded: c3a9
4804 decoded: c3a9
4801 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4805 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
4802 abort: decoding near * (glob)
4806 abort: decoding near * (glob)
4803 [255]
4807 [255]
4804 $ hg log -T "coerced to string: {rev|utf8}\n" -r0
4808 $ hg log -T "coerced to string: {rev|utf8}\n" -r0
4805 coerced to string: 0
4809 coerced to string: 0
4806
4810
4807 pad width:
4811 pad width:
4808
4812
4809 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4813 $ HGENCODING=utf-8 hg debugtemplate "{pad('`cat utf-8`', 2, '-')}\n"
4810 \xc3\xa9- (esc)
4814 \xc3\xa9- (esc)
4811
4815
4812 $ cd ..
4816 $ cd ..
4813
4817
4814 Test that template function in extension is registered as expected
4818 Test that template function in extension is registered as expected
4815
4819
4816 $ cd a
4820 $ cd a
4817
4821
4818 $ cat <<EOF > $TESTTMP/customfunc.py
4822 $ cat <<EOF > $TESTTMP/customfunc.py
4819 > from mercurial import registrar
4823 > from mercurial import registrar
4820 >
4824 >
4821 > templatefunc = registrar.templatefunc()
4825 > templatefunc = registrar.templatefunc()
4822 >
4826 >
4823 > @templatefunc(b'custom()')
4827 > @templatefunc(b'custom()')
4824 > def custom(context, mapping, args):
4828 > def custom(context, mapping, args):
4825 > return b'custom'
4829 > return b'custom'
4826 > EOF
4830 > EOF
4827 $ cat <<EOF > .hg/hgrc
4831 $ cat <<EOF > .hg/hgrc
4828 > [extensions]
4832 > [extensions]
4829 > customfunc = $TESTTMP/customfunc.py
4833 > customfunc = $TESTTMP/customfunc.py
4830 > EOF
4834 > EOF
4831
4835
4832 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4836 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
4833 custom
4837 custom
4834
4838
4835 $ cd ..
4839 $ cd ..
4836
4840
4837 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4841 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
4838 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4842 printed graphwidths 3, 5, 7, etc. should all line up in their respective
4839 columns. We don't care about other aspects of the graph rendering here.
4843 columns. We don't care about other aspects of the graph rendering here.
4840
4844
4841 $ hg init graphwidth
4845 $ hg init graphwidth
4842 $ cd graphwidth
4846 $ cd graphwidth
4843
4847
4844 $ wrappabletext="a a a a a a a a a a a a"
4848 $ wrappabletext="a a a a a a a a a a a a"
4845
4849
4846 $ printf "first\n" > file
4850 $ printf "first\n" > file
4847 $ hg add file
4851 $ hg add file
4848 $ hg commit -m "$wrappabletext"
4852 $ hg commit -m "$wrappabletext"
4849
4853
4850 $ printf "first\nsecond\n" > file
4854 $ printf "first\nsecond\n" > file
4851 $ hg commit -m "$wrappabletext"
4855 $ hg commit -m "$wrappabletext"
4852
4856
4853 $ hg checkout 0
4857 $ hg checkout 0
4854 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4858 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4855 $ printf "third\nfirst\n" > file
4859 $ printf "third\nfirst\n" > file
4856 $ hg commit -m "$wrappabletext"
4860 $ hg commit -m "$wrappabletext"
4857 created new head
4861 created new head
4858
4862
4859 $ hg merge
4863 $ hg merge
4860 merging file
4864 merging file
4861 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4865 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
4862 (branch merge, don't forget to commit)
4866 (branch merge, don't forget to commit)
4863
4867
4864 $ hg log --graph -T "{graphwidth}"
4868 $ hg log --graph -T "{graphwidth}"
4865 @ 3
4869 @ 3
4866 |
4870 |
4867 | @ 5
4871 | @ 5
4868 |/
4872 |/
4869 o 3
4873 o 3
4870
4874
4871 $ hg commit -m "$wrappabletext"
4875 $ hg commit -m "$wrappabletext"
4872
4876
4873 $ hg log --graph -T "{graphwidth}"
4877 $ hg log --graph -T "{graphwidth}"
4874 @ 5
4878 @ 5
4875 |\
4879 |\
4876 | o 5
4880 | o 5
4877 | |
4881 | |
4878 o | 5
4882 o | 5
4879 |/
4883 |/
4880 o 3
4884 o 3
4881
4885
4882
4886
4883 $ hg checkout 0
4887 $ hg checkout 0
4884 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4888 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4885 $ printf "third\nfirst\nsecond\n" > file
4889 $ printf "third\nfirst\nsecond\n" > file
4886 $ hg commit -m "$wrappabletext"
4890 $ hg commit -m "$wrappabletext"
4887 created new head
4891 created new head
4888
4892
4889 $ hg log --graph -T "{graphwidth}"
4893 $ hg log --graph -T "{graphwidth}"
4890 @ 3
4894 @ 3
4891 |
4895 |
4892 | o 7
4896 | o 7
4893 | |\
4897 | |\
4894 +---o 7
4898 +---o 7
4895 | |
4899 | |
4896 | o 5
4900 | o 5
4897 |/
4901 |/
4898 o 3
4902 o 3
4899
4903
4900
4904
4901 $ hg log --graph -T "{graphwidth}" -r 3
4905 $ hg log --graph -T "{graphwidth}" -r 3
4902 o 5
4906 o 5
4903 |\
4907 |\
4904 ~ ~
4908 ~ ~
4905
4909
4906 $ hg log --graph -T "{graphwidth}" -r 1
4910 $ hg log --graph -T "{graphwidth}" -r 1
4907 o 3
4911 o 3
4908 |
4912 |
4909 ~
4913 ~
4910
4914
4911 $ hg merge
4915 $ hg merge
4912 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4916 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4913 (branch merge, don't forget to commit)
4917 (branch merge, don't forget to commit)
4914 $ hg commit -m "$wrappabletext"
4918 $ hg commit -m "$wrappabletext"
4915
4919
4916 $ printf "seventh\n" >> file
4920 $ printf "seventh\n" >> file
4917 $ hg commit -m "$wrappabletext"
4921 $ hg commit -m "$wrappabletext"
4918
4922
4919 $ hg log --graph -T "{graphwidth}"
4923 $ hg log --graph -T "{graphwidth}"
4920 @ 3
4924 @ 3
4921 |
4925 |
4922 o 5
4926 o 5
4923 |\
4927 |\
4924 | o 5
4928 | o 5
4925 | |
4929 | |
4926 o | 7
4930 o | 7
4927 |\ \
4931 |\ \
4928 | o | 7
4932 | o | 7
4929 | |/
4933 | |/
4930 o / 5
4934 o / 5
4931 |/
4935 |/
4932 o 3
4936 o 3
4933
4937
4934
4938
4935 The point of graphwidth is to allow wrapping that accounts for the space taken
4939 The point of graphwidth is to allow wrapping that accounts for the space taken
4936 by the graph.
4940 by the graph.
4937
4941
4938 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4942 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
4939 @ a a a a
4943 @ a a a a
4940 | a a a a
4944 | a a a a
4941 | a a a a
4945 | a a a a
4942 o a a a
4946 o a a a
4943 |\ a a a
4947 |\ a a a
4944 | | a a a
4948 | | a a a
4945 | | a a a
4949 | | a a a
4946 | o a a a
4950 | o a a a
4947 | | a a a
4951 | | a a a
4948 | | a a a
4952 | | a a a
4949 | | a a a
4953 | | a a a
4950 o | a a
4954 o | a a
4951 |\ \ a a
4955 |\ \ a a
4952 | | | a a
4956 | | | a a
4953 | | | a a
4957 | | | a a
4954 | | | a a
4958 | | | a a
4955 | | | a a
4959 | | | a a
4956 | o | a a
4960 | o | a a
4957 | |/ a a
4961 | |/ a a
4958 | | a a
4962 | | a a
4959 | | a a
4963 | | a a
4960 | | a a
4964 | | a a
4961 | | a a
4965 | | a a
4962 o | a a a
4966 o | a a a
4963 |/ a a a
4967 |/ a a a
4964 | a a a
4968 | a a a
4965 | a a a
4969 | a a a
4966 o a a a a
4970 o a a a a
4967 a a a a
4971 a a a a
4968 a a a a
4972 a a a a
4969
4973
4970 Something tricky happens when there are elided nodes; the next drawn row of
4974 Something tricky happens when there are elided nodes; the next drawn row of
4971 edges can be more than one column wider, but the graph width only increases by
4975 edges can be more than one column wider, but the graph width only increases by
4972 one column. The remaining columns are added in between the nodes.
4976 one column. The remaining columns are added in between the nodes.
4973
4977
4974 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4978 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
4975 o 5
4979 o 5
4976 |\
4980 |\
4977 | \
4981 | \
4978 | :\
4982 | :\
4979 o : : 7
4983 o : : 7
4980 :/ /
4984 :/ /
4981 : o 5
4985 : o 5
4982 :/
4986 :/
4983 o 3
4987 o 3
4984
4988
4985
4989
4986 $ cd ..
4990 $ cd ..
4987
4991
General Comments 0
You need to be logged in to leave comments. Login now