##// END OF EJS Templates
merge with stable
Matt Mackall -
r26504:875e5d89 merge default
parent child Browse files
Show More
@@ -1,416 +1,418 b''
1 # notify.py - email notifications for mercurial
1 # notify.py - email notifications for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.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 '''hooks for sending email push notifications
8 '''hooks for sending email push notifications
9
9
10 This extension implements hooks to send email notifications when
10 This extension implements hooks to send email notifications when
11 changesets are sent from or received by the local repository.
11 changesets are sent from or received by the local repository.
12
12
13 First, enable the extension as explained in :hg:`help extensions`, and
13 First, enable the extension as explained in :hg:`help extensions`, and
14 register the hook you want to run. ``incoming`` and ``changegroup`` hooks
14 register the hook you want to run. ``incoming`` and ``changegroup`` hooks
15 are run when changesets are received, while ``outgoing`` hooks are for
15 are run when changesets are received, while ``outgoing`` hooks are for
16 changesets sent to another repository::
16 changesets sent to another repository::
17
17
18 [hooks]
18 [hooks]
19 # one email for each incoming changeset
19 # one email for each incoming changeset
20 incoming.notify = python:hgext.notify.hook
20 incoming.notify = python:hgext.notify.hook
21 # one email for all incoming changesets
21 # one email for all incoming changesets
22 changegroup.notify = python:hgext.notify.hook
22 changegroup.notify = python:hgext.notify.hook
23
23
24 # one email for all outgoing changesets
24 # one email for all outgoing changesets
25 outgoing.notify = python:hgext.notify.hook
25 outgoing.notify = python:hgext.notify.hook
26
26
27 This registers the hooks. To enable notification, subscribers must
27 This registers the hooks. To enable notification, subscribers must
28 be assigned to repositories. The ``[usersubs]`` section maps multiple
28 be assigned to repositories. The ``[usersubs]`` section maps multiple
29 repositories to a given recipient. The ``[reposubs]`` section maps
29 repositories to a given recipient. The ``[reposubs]`` section maps
30 multiple recipients to a single repository::
30 multiple recipients to a single repository::
31
31
32 [usersubs]
32 [usersubs]
33 # key is subscriber email, value is a comma-separated list of repo patterns
33 # key is subscriber email, value is a comma-separated list of repo patterns
34 user@host = pattern
34 user@host = pattern
35
35
36 [reposubs]
36 [reposubs]
37 # key is repo pattern, value is a comma-separated list of subscriber emails
37 # key is repo pattern, value is a comma-separated list of subscriber emails
38 pattern = user@host
38 pattern = user@host
39
39
40 A ``pattern`` is a ``glob`` matching the absolute path to a repository,
40 A ``pattern`` is a ``glob`` matching the absolute path to a repository,
41 optionally combined with a revset expression. A revset expression, if
41 optionally combined with a revset expression. A revset expression, if
42 present, is separated from the glob by a hash. Example::
42 present, is separated from the glob by a hash. Example::
43
43
44 [reposubs]
44 [reposubs]
45 */widgets#branch(release) = qa-team@example.com
45 */widgets#branch(release) = qa-team@example.com
46
46
47 This sends to ``qa-team@example.com`` whenever a changeset on the ``release``
47 This sends to ``qa-team@example.com`` whenever a changeset on the ``release``
48 branch triggers a notification in any repository ending in ``widgets``.
48 branch triggers a notification in any repository ending in ``widgets``.
49
49
50 In order to place them under direct user management, ``[usersubs]`` and
50 In order to place them under direct user management, ``[usersubs]`` and
51 ``[reposubs]`` sections may be placed in a separate ``hgrc`` file and
51 ``[reposubs]`` sections may be placed in a separate ``hgrc`` file and
52 incorporated by reference::
52 incorporated by reference::
53
53
54 [notify]
54 [notify]
55 config = /path/to/subscriptionsfile
55 config = /path/to/subscriptionsfile
56
56
57 Notifications will not be sent until the ``notify.test`` value is set
57 Notifications will not be sent until the ``notify.test`` value is set
58 to ``False``; see below.
58 to ``False``; see below.
59
59
60 Notifications content can be tweaked with the following configuration entries:
60 Notifications content can be tweaked with the following configuration entries:
61
61
62 notify.test
62 notify.test
63 If ``True``, print messages to stdout instead of sending them. Default: True.
63 If ``True``, print messages to stdout instead of sending them. Default: True.
64
64
65 notify.sources
65 notify.sources
66 Space-separated list of change sources. Notifications are activated only
66 Space-separated list of change sources. Notifications are activated only
67 when a changeset's source is in this list. Sources may be:
67 when a changeset's source is in this list. Sources may be:
68
68
69 :``serve``: changesets received via http or ssh
69 :``serve``: changesets received via http or ssh
70 :``pull``: changesets received via ``hg pull``
70 :``pull``: changesets received via ``hg pull``
71 :``unbundle``: changesets received via ``hg unbundle``
71 :``unbundle``: changesets received via ``hg unbundle``
72 :``push``: changesets sent or received via ``hg push``
72 :``push``: changesets sent or received via ``hg push``
73 :``bundle``: changesets sent via ``hg unbundle``
73 :``bundle``: changesets sent via ``hg unbundle``
74
74
75 Default: serve.
75 Default: serve.
76
76
77 notify.strip
77 notify.strip
78 Number of leading slashes to strip from url paths. By default, notifications
78 Number of leading slashes to strip from url paths. By default, notifications
79 reference repositories with their absolute path. ``notify.strip`` lets you
79 reference repositories with their absolute path. ``notify.strip`` lets you
80 turn them into relative paths. For example, ``notify.strip=3`` will change
80 turn them into relative paths. For example, ``notify.strip=3`` will change
81 ``/long/path/repository`` into ``repository``. Default: 0.
81 ``/long/path/repository`` into ``repository``. Default: 0.
82
82
83 notify.domain
83 notify.domain
84 Default email domain for sender or recipients with no explicit domain.
84 Default email domain for sender or recipients with no explicit domain.
85
85
86 notify.style
86 notify.style
87 Style file to use when formatting emails.
87 Style file to use when formatting emails.
88
88
89 notify.template
89 notify.template
90 Template to use when formatting emails.
90 Template to use when formatting emails.
91
91
92 notify.incoming
92 notify.incoming
93 Template to use when run as an incoming hook, overriding ``notify.template``.
93 Template to use when run as an incoming hook, overriding ``notify.template``.
94
94
95 notify.outgoing
95 notify.outgoing
96 Template to use when run as an outgoing hook, overriding ``notify.template``.
96 Template to use when run as an outgoing hook, overriding ``notify.template``.
97
97
98 notify.changegroup
98 notify.changegroup
99 Template to use when running as a changegroup hook, overriding
99 Template to use when running as a changegroup hook, overriding
100 ``notify.template``.
100 ``notify.template``.
101
101
102 notify.maxdiff
102 notify.maxdiff
103 Maximum number of diff lines to include in notification email. Set to 0
103 Maximum number of diff lines to include in notification email. Set to 0
104 to disable the diff, or -1 to include all of it. Default: 300.
104 to disable the diff, or -1 to include all of it. Default: 300.
105
105
106 notify.maxsubject
106 notify.maxsubject
107 Maximum number of characters in email's subject line. Default: 67.
107 Maximum number of characters in email's subject line. Default: 67.
108
108
109 notify.diffstat
109 notify.diffstat
110 Set to True to include a diffstat before diff content. Default: True.
110 Set to True to include a diffstat before diff content. Default: True.
111
111
112 notify.merge
112 notify.merge
113 If True, send notifications for merge changesets. Default: True.
113 If True, send notifications for merge changesets. Default: True.
114
114
115 notify.mbox
115 notify.mbox
116 If set, append mails to this mbox file instead of sending. Default: None.
116 If set, append mails to this mbox file instead of sending. Default: None.
117
117
118 notify.fromauthor
118 notify.fromauthor
119 If set, use the committer of the first changeset in a changegroup for
119 If set, use the committer of the first changeset in a changegroup for
120 the "From" field of the notification mail. If not set, take the user
120 the "From" field of the notification mail. If not set, take the user
121 from the pushing repo. Default: False.
121 from the pushing repo. Default: False.
122
122
123 If set, the following entries will also be used to customize the
123 If set, the following entries will also be used to customize the
124 notifications:
124 notifications:
125
125
126 email.from
126 email.from
127 Email ``From`` address to use if none can be found in the generated
127 Email ``From`` address to use if none can be found in the generated
128 email content.
128 email content.
129
129
130 web.baseurl
130 web.baseurl
131 Root repository URL to combine with repository paths when making
131 Root repository URL to combine with repository paths when making
132 references. See also ``notify.strip``.
132 references. See also ``notify.strip``.
133
133
134 '''
134 '''
135
135
136 import email, socket, time
136 import email, socket, time
137 from mercurial.i18n import _
137 from mercurial.i18n import _
138 from mercurial import patch, cmdutil, util, mail
138 from mercurial import patch, cmdutil, util, mail
139 import fnmatch
139 import fnmatch
140
140
141 # Note for extension authors: ONLY specify testedwith = 'internal' for
141 # Note for extension authors: ONLY specify testedwith = 'internal' for
142 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
142 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
143 # be specifying the version(s) of Mercurial they are tested with, or
143 # be specifying the version(s) of Mercurial they are tested with, or
144 # leave the attribute unspecified.
144 # leave the attribute unspecified.
145 testedwith = 'internal'
145 testedwith = 'internal'
146
146
147 # template for single changeset can include email headers.
147 # template for single changeset can include email headers.
148 single_template = '''
148 single_template = '''
149 Subject: changeset in {webroot}: {desc|firstline|strip}
149 Subject: changeset in {webroot}: {desc|firstline|strip}
150 From: {author}
150 From: {author}
151
151
152 changeset {node|short} in {root}
152 changeset {node|short} in {root}
153 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
153 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
154 description:
154 description:
155 \t{desc|tabindent|strip}
155 \t{desc|tabindent|strip}
156 '''.lstrip()
156 '''.lstrip()
157
157
158 # template for multiple changesets should not contain email headers,
158 # template for multiple changesets should not contain email headers,
159 # because only first set of headers will be used and result will look
159 # because only first set of headers will be used and result will look
160 # strange.
160 # strange.
161 multiple_template = '''
161 multiple_template = '''
162 changeset {node|short} in {root}
162 changeset {node|short} in {root}
163 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
163 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
164 summary: {desc|firstline}
164 summary: {desc|firstline}
165 '''
165 '''
166
166
167 deftemplates = {
167 deftemplates = {
168 'changegroup': multiple_template,
168 'changegroup': multiple_template,
169 }
169 }
170
170
171 class notifier(object):
171 class notifier(object):
172 '''email notification class.'''
172 '''email notification class.'''
173
173
174 def __init__(self, ui, repo, hooktype):
174 def __init__(self, ui, repo, hooktype):
175 self.ui = ui
175 self.ui = ui
176 cfg = self.ui.config('notify', 'config')
176 cfg = self.ui.config('notify', 'config')
177 if cfg:
177 if cfg:
178 self.ui.readconfig(cfg, sections=['usersubs', 'reposubs'])
178 self.ui.readconfig(cfg, sections=['usersubs', 'reposubs'])
179 self.repo = repo
179 self.repo = repo
180 self.stripcount = int(self.ui.config('notify', 'strip', 0))
180 self.stripcount = int(self.ui.config('notify', 'strip', 0))
181 self.root = self.strip(self.repo.root)
181 self.root = self.strip(self.repo.root)
182 self.domain = self.ui.config('notify', 'domain')
182 self.domain = self.ui.config('notify', 'domain')
183 self.mbox = self.ui.config('notify', 'mbox')
183 self.mbox = self.ui.config('notify', 'mbox')
184 self.test = self.ui.configbool('notify', 'test', True)
184 self.test = self.ui.configbool('notify', 'test', True)
185 self.charsets = mail._charsets(self.ui)
185 self.charsets = mail._charsets(self.ui)
186 self.subs = self.subscribers()
186 self.subs = self.subscribers()
187 self.merge = self.ui.configbool('notify', 'merge', True)
187 self.merge = self.ui.configbool('notify', 'merge', True)
188
188
189 mapfile = self.ui.config('notify', 'style')
189 mapfile = self.ui.config('notify', 'style')
190 template = (self.ui.config('notify', hooktype) or
190 template = (self.ui.config('notify', hooktype) or
191 self.ui.config('notify', 'template'))
191 self.ui.config('notify', 'template'))
192 if not mapfile and not template:
192 if not mapfile and not template:
193 template = deftemplates.get(hooktype) or single_template
193 template = deftemplates.get(hooktype) or single_template
194 self.t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
194 self.t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
195 template, mapfile, False)
195 template, mapfile, False)
196
196
197 def strip(self, path):
197 def strip(self, path):
198 '''strip leading slashes from local path, turn into web-safe path.'''
198 '''strip leading slashes from local path, turn into web-safe path.'''
199
199
200 path = util.pconvert(path)
200 path = util.pconvert(path)
201 count = self.stripcount
201 count = self.stripcount
202 while count > 0:
202 while count > 0:
203 c = path.find('/')
203 c = path.find('/')
204 if c == -1:
204 if c == -1:
205 break
205 break
206 path = path[c + 1:]
206 path = path[c + 1:]
207 count -= 1
207 count -= 1
208 return path
208 return path
209
209
210 def fixmail(self, addr):
210 def fixmail(self, addr):
211 '''try to clean up email addresses.'''
211 '''try to clean up email addresses.'''
212
212
213 addr = util.email(addr.strip())
213 addr = util.email(addr.strip())
214 if self.domain:
214 if self.domain:
215 a = addr.find('@localhost')
215 a = addr.find('@localhost')
216 if a != -1:
216 if a != -1:
217 addr = addr[:a]
217 addr = addr[:a]
218 if '@' not in addr:
218 if '@' not in addr:
219 return addr + '@' + self.domain
219 return addr + '@' + self.domain
220 return addr
220 return addr
221
221
222 def subscribers(self):
222 def subscribers(self):
223 '''return list of email addresses of subscribers to this repo.'''
223 '''return list of email addresses of subscribers to this repo.'''
224 subs = set()
224 subs = set()
225 for user, pats in self.ui.configitems('usersubs'):
225 for user, pats in self.ui.configitems('usersubs'):
226 for pat in pats.split(','):
226 for pat in pats.split(','):
227 if '#' in pat:
227 if '#' in pat:
228 pat, revs = pat.split('#', 1)
228 pat, revs = pat.split('#', 1)
229 else:
229 else:
230 revs = None
230 revs = None
231 if fnmatch.fnmatch(self.repo.root, pat.strip()):
231 if fnmatch.fnmatch(self.repo.root, pat.strip()):
232 subs.add((self.fixmail(user), revs))
232 subs.add((self.fixmail(user), revs))
233 for pat, users in self.ui.configitems('reposubs'):
233 for pat, users in self.ui.configitems('reposubs'):
234 if '#' in pat:
234 if '#' in pat:
235 pat, revs = pat.split('#', 1)
235 pat, revs = pat.split('#', 1)
236 else:
236 else:
237 revs = None
237 revs = None
238 if fnmatch.fnmatch(self.repo.root, pat):
238 if fnmatch.fnmatch(self.repo.root, pat):
239 for user in users.split(','):
239 for user in users.split(','):
240 subs.add((self.fixmail(user), revs))
240 subs.add((self.fixmail(user), revs))
241 return [(mail.addressencode(self.ui, s, self.charsets, self.test), r)
241 return [(mail.addressencode(self.ui, s, self.charsets, self.test), r)
242 for s, r in sorted(subs)]
242 for s, r in sorted(subs)]
243
243
244 def node(self, ctx, **props):
244 def node(self, ctx, **props):
245 '''format one changeset, unless it is a suppressed merge.'''
245 '''format one changeset, unless it is a suppressed merge.'''
246 if not self.merge and len(ctx.parents()) > 1:
246 if not self.merge and len(ctx.parents()) > 1:
247 return False
247 return False
248 self.t.show(ctx, changes=ctx.changeset(),
248 self.t.show(ctx, changes=ctx.changeset(),
249 baseurl=self.ui.config('web', 'baseurl'),
249 baseurl=self.ui.config('web', 'baseurl'),
250 root=self.repo.root, webroot=self.root, **props)
250 root=self.repo.root, webroot=self.root, **props)
251 return True
251 return True
252
252
253 def skipsource(self, source):
253 def skipsource(self, source):
254 '''true if incoming changes from this source should be skipped.'''
254 '''true if incoming changes from this source should be skipped.'''
255 ok_sources = self.ui.config('notify', 'sources', 'serve').split()
255 ok_sources = self.ui.config('notify', 'sources', 'serve').split()
256 return source not in ok_sources
256 return source not in ok_sources
257
257
258 def send(self, ctx, count, data):
258 def send(self, ctx, count, data):
259 '''send message.'''
259 '''send message.'''
260
260
261 # Select subscribers by revset
261 # Select subscribers by revset
262 subs = set()
262 subs = set()
263 for sub, spec in self.subs:
263 for sub, spec in self.subs:
264 if spec is None:
264 if spec is None:
265 subs.add(sub)
265 subs.add(sub)
266 continue
266 continue
267 revs = self.repo.revs('%r and %d:', spec, ctx.rev())
267 revs = self.repo.revs('%r and %d:', spec, ctx.rev())
268 if len(revs):
268 if len(revs):
269 subs.add(sub)
269 subs.add(sub)
270 continue
270 continue
271 if len(subs) == 0:
271 if len(subs) == 0:
272 self.ui.debug('notify: no subscribers to selected repo '
272 self.ui.debug('notify: no subscribers to selected repo '
273 'and revset\n')
273 'and revset\n')
274 return
274 return
275
275
276 p = email.Parser.Parser()
276 p = email.Parser.Parser()
277 try:
277 try:
278 msg = p.parsestr(data)
278 msg = p.parsestr(data)
279 except email.Errors.MessageParseError as inst:
279 except email.Errors.MessageParseError as inst:
280 raise util.Abort(inst)
280 raise util.Abort(inst)
281
281
282 # store sender and subject
282 # store sender and subject
283 sender, subject = msg['From'], msg['Subject']
283 sender, subject = msg['From'], msg['Subject']
284 del msg['From'], msg['Subject']
284 del msg['From'], msg['Subject']
285
285
286 if not msg.is_multipart():
286 if not msg.is_multipart():
287 # create fresh mime message from scratch
287 # create fresh mime message from scratch
288 # (multipart templates must take care of this themselves)
288 # (multipart templates must take care of this themselves)
289 headers = msg.items()
289 headers = msg.items()
290 payload = msg.get_payload()
290 payload = msg.get_payload()
291 # for notification prefer readability over data precision
291 # for notification prefer readability over data precision
292 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
292 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
293 # reinstate custom headers
293 # reinstate custom headers
294 for k, v in headers:
294 for k, v in headers:
295 msg[k] = v
295 msg[k] = v
296
296
297 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
297 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
298
298
299 # try to make subject line exist and be useful
299 # try to make subject line exist and be useful
300 if not subject:
300 if not subject:
301 if count > 1:
301 if count > 1:
302 subject = _('%s: %d new changesets') % (self.root, count)
302 subject = _('%s: %d new changesets') % (self.root, count)
303 else:
303 else:
304 s = ctx.description().lstrip().split('\n', 1)[0].rstrip()
304 s = ctx.description().lstrip().split('\n', 1)[0].rstrip()
305 subject = '%s: %s' % (self.root, s)
305 subject = '%s: %s' % (self.root, s)
306 maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
306 maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
307 if maxsubject:
307 if maxsubject:
308 subject = util.ellipsis(subject, maxsubject)
308 subject = util.ellipsis(subject, maxsubject)
309 msg['Subject'] = mail.headencode(self.ui, subject,
309 msg['Subject'] = mail.headencode(self.ui, subject,
310 self.charsets, self.test)
310 self.charsets, self.test)
311
311
312 # try to make message have proper sender
312 # try to make message have proper sender
313 if not sender:
313 if not sender:
314 sender = self.ui.config('email', 'from') or self.ui.username()
314 sender = self.ui.config('email', 'from') or self.ui.username()
315 if '@' not in sender or '@localhost' in sender:
315 if '@' not in sender or '@localhost' in sender:
316 sender = self.fixmail(sender)
316 sender = self.fixmail(sender)
317 msg['From'] = mail.addressencode(self.ui, sender,
317 msg['From'] = mail.addressencode(self.ui, sender,
318 self.charsets, self.test)
318 self.charsets, self.test)
319
319
320 msg['X-Hg-Notification'] = 'changeset %s' % ctx
320 msg['X-Hg-Notification'] = 'changeset %s' % ctx
321 if not msg['Message-Id']:
321 if not msg['Message-Id']:
322 msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
322 msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
323 (ctx, int(time.time()),
323 (ctx, int(time.time()),
324 hash(self.repo.root), socket.getfqdn()))
324 hash(self.repo.root), socket.getfqdn()))
325 msg['To'] = ', '.join(sorted(subs))
325 msg['To'] = ', '.join(sorted(subs))
326
326
327 msgtext = msg.as_string()
327 msgtext = msg.as_string()
328 if self.test:
328 if self.test:
329 self.ui.write(msgtext)
329 self.ui.write(msgtext)
330 if not msgtext.endswith('\n'):
330 if not msgtext.endswith('\n'):
331 self.ui.write('\n')
331 self.ui.write('\n')
332 else:
332 else:
333 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
333 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
334 (len(subs), count))
334 (len(subs), count))
335 mail.sendmail(self.ui, util.email(msg['From']),
335 mail.sendmail(self.ui, util.email(msg['From']),
336 subs, msgtext, mbox=self.mbox)
336 subs, msgtext, mbox=self.mbox)
337
337
338 def diff(self, ctx, ref=None):
338 def diff(self, ctx, ref=None):
339
339
340 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
340 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
341 prev = ctx.p1().node()
341 prev = ctx.p1().node()
342 if ref:
342 if ref:
343 ref = ref.node()
343 ref = ref.node()
344 else:
344 else:
345 ref = ctx.node()
345 ref = ctx.node()
346 chunks = patch.diff(self.repo, prev, ref,
346 chunks = patch.diff(self.repo, prev, ref,
347 opts=patch.diffallopts(self.ui))
347 opts=patch.diffallopts(self.ui))
348 difflines = ''.join(chunks).splitlines()
348 difflines = ''.join(chunks).splitlines()
349
349
350 if self.ui.configbool('notify', 'diffstat', True):
350 if self.ui.configbool('notify', 'diffstat', True):
351 s = patch.diffstat(difflines)
351 s = patch.diffstat(difflines)
352 # s may be nil, don't include the header if it is
352 # s may be nil, don't include the header if it is
353 if s:
353 if s:
354 self.ui.write('\ndiffstat:\n\n%s' % s)
354 self.ui.write('\ndiffstat:\n\n%s' % s)
355
355
356 if maxdiff == 0:
356 if maxdiff == 0:
357 return
357 return
358 elif maxdiff > 0 and len(difflines) > maxdiff:
358 elif maxdiff > 0 and len(difflines) > maxdiff:
359 msg = _('\ndiffs (truncated from %d to %d lines):\n\n')
359 msg = _('\ndiffs (truncated from %d to %d lines):\n\n')
360 self.ui.write(msg % (len(difflines), maxdiff))
360 self.ui.write(msg % (len(difflines), maxdiff))
361 difflines = difflines[:maxdiff]
361 difflines = difflines[:maxdiff]
362 elif difflines:
362 elif difflines:
363 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
363 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
364
364
365 self.ui.write("\n".join(difflines))
365 self.ui.write("\n".join(difflines))
366
366
367 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
367 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
368 '''send email notifications to interested subscribers.
368 '''send email notifications to interested subscribers.
369
369
370 if used as changegroup hook, send one email for all changesets in
370 if used as changegroup hook, send one email for all changesets in
371 changegroup. else send one email per changeset.'''
371 changegroup. else send one email per changeset.'''
372
372
373 n = notifier(ui, repo, hooktype)
373 n = notifier(ui, repo, hooktype)
374 ctx = repo[node]
374 ctx = repo[node]
375
375
376 if not n.subs:
376 if not n.subs:
377 ui.debug('notify: no subscribers to repository %s\n' % n.root)
377 ui.debug('notify: no subscribers to repository %s\n' % n.root)
378 return
378 return
379 if n.skipsource(source):
379 if n.skipsource(source):
380 ui.debug('notify: changes have source "%s" - skipping\n' % source)
380 ui.debug('notify: changes have source "%s" - skipping\n' % source)
381 return
381 return
382
382
383 ui.pushbuffer()
383 ui.pushbuffer()
384 data = ''
384 data = ''
385 count = 0
385 count = 0
386 author = ''
386 author = ''
387 if hooktype == 'changegroup' or hooktype == 'outgoing':
387 if hooktype == 'changegroup' or hooktype == 'outgoing':
388 start, end = ctx.rev(), len(repo)
388 start, end = ctx.rev(), len(repo)
389 for rev in xrange(start, end):
389 for rev in xrange(start, end):
390 if n.node(repo[rev]):
390 if n.node(repo[rev]):
391 count += 1
391 count += 1
392 if not author:
392 if not author:
393 author = repo[rev].user()
393 author = repo[rev].user()
394 else:
394 else:
395 data += ui.popbuffer()
395 data += ui.popbuffer()
396 ui.note(_('notify: suppressing notification for merge %d:%s\n')
396 ui.note(_('notify: suppressing notification for merge %d:%s\n')
397 % (rev, repo[rev].hex()[:12]))
397 % (rev, repo[rev].hex()[:12]))
398 ui.pushbuffer()
398 ui.pushbuffer()
399 if count:
399 if count:
400 n.diff(ctx, repo['tip'])
400 n.diff(ctx, repo['tip'])
401 else:
401 else:
402 if not n.node(ctx):
402 if not n.node(ctx):
403 ui.popbuffer()
403 ui.popbuffer()
404 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
404 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
405 (ctx.rev(), ctx.hex()[:12]))
405 (ctx.rev(), ctx.hex()[:12]))
406 return
406 return
407 count += 1
407 count += 1
408 n.diff(ctx)
408 n.diff(ctx)
409 if not author:
410 author = ctx.user()
409
411
410 data += ui.popbuffer()
412 data += ui.popbuffer()
411 fromauthor = ui.config('notify', 'fromauthor')
413 fromauthor = ui.config('notify', 'fromauthor')
412 if author and fromauthor:
414 if author and fromauthor:
413 data = '\n'.join(['From: %s' % author, data])
415 data = '\n'.join(['From: %s' % author, data])
414
416
415 if count:
417 if count:
416 n.send(ctx, count, data)
418 n.send(ctx, count, data)
@@ -1,979 +1,979 b''
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import re
11 import re
12 import types
12 import types
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 config,
16 config,
17 error,
17 error,
18 minirst,
18 minirst,
19 parser,
19 parser,
20 revset as revsetmod,
20 revset as revsetmod,
21 templatefilters,
21 templatefilters,
22 templatekw,
22 templatekw,
23 util,
23 util,
24 )
24 )
25
25
26 # template parsing
26 # template parsing
27
27
28 elements = {
28 elements = {
29 # token-type: binding-strength, primary, prefix, infix, suffix
29 # token-type: binding-strength, primary, prefix, infix, suffix
30 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
30 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
31 ",": (2, None, None, ("list", 2), None),
31 ",": (2, None, None, ("list", 2), None),
32 "|": (5, None, None, ("|", 5), None),
32 "|": (5, None, None, ("|", 5), None),
33 "%": (6, None, None, ("%", 6), None),
33 "%": (6, None, None, ("%", 6), None),
34 ")": (0, None, None, None, None),
34 ")": (0, None, None, None, None),
35 "integer": (0, "integer", None, None, None),
35 "integer": (0, "integer", None, None, None),
36 "symbol": (0, "symbol", None, None, None),
36 "symbol": (0, "symbol", None, None, None),
37 "string": (0, "string", None, None, None),
37 "string": (0, "string", None, None, None),
38 "template": (0, "template", None, None, None),
38 "template": (0, "template", None, None, None),
39 "end": (0, None, None, None, None),
39 "end": (0, None, None, None, None),
40 }
40 }
41
41
42 def tokenize(program, start, end):
42 def tokenize(program, start, end):
43 pos = start
43 pos = start
44 while pos < end:
44 while pos < end:
45 c = program[pos]
45 c = program[pos]
46 if c.isspace(): # skip inter-token whitespace
46 if c.isspace(): # skip inter-token whitespace
47 pass
47 pass
48 elif c in "(,)%|": # handle simple operators
48 elif c in "(,)%|": # handle simple operators
49 yield (c, None, pos)
49 yield (c, None, pos)
50 elif c in '"\'': # handle quoted templates
50 elif c in '"\'': # handle quoted templates
51 s = pos + 1
51 s = pos + 1
52 data, pos = _parsetemplate(program, s, end, c)
52 data, pos = _parsetemplate(program, s, end, c)
53 yield ('template', data, s)
53 yield ('template', data, s)
54 pos -= 1
54 pos -= 1
55 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
55 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
56 # handle quoted strings
56 # handle quoted strings
57 c = program[pos + 1]
57 c = program[pos + 1]
58 s = pos = pos + 2
58 s = pos = pos + 2
59 while pos < end: # find closing quote
59 while pos < end: # find closing quote
60 d = program[pos]
60 d = program[pos]
61 if d == '\\': # skip over escaped characters
61 if d == '\\': # skip over escaped characters
62 pos += 2
62 pos += 2
63 continue
63 continue
64 if d == c:
64 if d == c:
65 yield ('string', program[s:pos], s)
65 yield ('string', program[s:pos], s)
66 break
66 break
67 pos += 1
67 pos += 1
68 else:
68 else:
69 raise error.ParseError(_("unterminated string"), s)
69 raise error.ParseError(_("unterminated string"), s)
70 elif c.isdigit() or c == '-':
70 elif c.isdigit() or c == '-':
71 s = pos
71 s = pos
72 if c == '-': # simply take negate operator as part of integer
72 if c == '-': # simply take negate operator as part of integer
73 pos += 1
73 pos += 1
74 if pos >= end or not program[pos].isdigit():
74 if pos >= end or not program[pos].isdigit():
75 raise error.ParseError(_("integer literal without digits"), s)
75 raise error.ParseError(_("integer literal without digits"), s)
76 pos += 1
76 pos += 1
77 while pos < end:
77 while pos < end:
78 d = program[pos]
78 d = program[pos]
79 if not d.isdigit():
79 if not d.isdigit():
80 break
80 break
81 pos += 1
81 pos += 1
82 yield ('integer', program[s:pos], s)
82 yield ('integer', program[s:pos], s)
83 pos -= 1
83 pos -= 1
84 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
84 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
85 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
85 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
86 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
86 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
87 # where some of nested templates were preprocessed as strings and
87 # where some of nested templates were preprocessed as strings and
88 # then compiled. therefore, \"...\" was allowed. (issue4733)
88 # then compiled. therefore, \"...\" was allowed. (issue4733)
89 #
89 #
90 # processing flow of _evalifliteral() at 5ab28a2e9962:
90 # processing flow of _evalifliteral() at 5ab28a2e9962:
91 # outer template string -> stringify() -> compiletemplate()
91 # outer template string -> stringify() -> compiletemplate()
92 # ------------------------ ------------ ------------------
92 # ------------------------ ------------ ------------------
93 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
93 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
94 # ~~~~~~~~
94 # ~~~~~~~~
95 # escaped quoted string
95 # escaped quoted string
96 if c == 'r':
96 if c == 'r':
97 pos += 1
97 pos += 1
98 token = 'string'
98 token = 'string'
99 else:
99 else:
100 token = 'template'
100 token = 'template'
101 quote = program[pos:pos + 2]
101 quote = program[pos:pos + 2]
102 s = pos = pos + 2
102 s = pos = pos + 2
103 while pos < end: # find closing escaped quote
103 while pos < end: # find closing escaped quote
104 if program.startswith('\\\\\\', pos, end):
104 if program.startswith('\\\\\\', pos, end):
105 pos += 4 # skip over double escaped characters
105 pos += 4 # skip over double escaped characters
106 continue
106 continue
107 if program.startswith(quote, pos, end):
107 if program.startswith(quote, pos, end):
108 # interpret as if it were a part of an outer string
108 # interpret as if it were a part of an outer string
109 data = parser.unescapestr(program[s:pos])
109 data = parser.unescapestr(program[s:pos])
110 if token == 'template':
110 if token == 'template':
111 data = _parsetemplate(data, 0, len(data))[0]
111 data = _parsetemplate(data, 0, len(data))[0]
112 yield (token, data, s)
112 yield (token, data, s)
113 pos += 1
113 pos += 1
114 break
114 break
115 pos += 1
115 pos += 1
116 else:
116 else:
117 raise error.ParseError(_("unterminated string"), s)
117 raise error.ParseError(_("unterminated string"), s)
118 elif c.isalnum() or c in '_':
118 elif c.isalnum() or c in '_':
119 s = pos
119 s = pos
120 pos += 1
120 pos += 1
121 while pos < end: # find end of symbol
121 while pos < end: # find end of symbol
122 d = program[pos]
122 d = program[pos]
123 if not (d.isalnum() or d == "_"):
123 if not (d.isalnum() or d == "_"):
124 break
124 break
125 pos += 1
125 pos += 1
126 sym = program[s:pos]
126 sym = program[s:pos]
127 yield ('symbol', sym, s)
127 yield ('symbol', sym, s)
128 pos -= 1
128 pos -= 1
129 elif c == '}':
129 elif c == '}':
130 yield ('end', None, pos + 1)
130 yield ('end', None, pos + 1)
131 return
131 return
132 else:
132 else:
133 raise error.ParseError(_("syntax error"), pos)
133 raise error.ParseError(_("syntax error"), pos)
134 pos += 1
134 pos += 1
135 raise error.ParseError(_("unterminated template expansion"), start)
135 raise error.ParseError(_("unterminated template expansion"), start)
136
136
137 def _parsetemplate(tmpl, start, stop, quote=''):
137 def _parsetemplate(tmpl, start, stop, quote=''):
138 r"""
138 r"""
139 >>> _parsetemplate('foo{bar}"baz', 0, 12)
139 >>> _parsetemplate('foo{bar}"baz', 0, 12)
140 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
140 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
141 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
141 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
142 ([('string', 'foo'), ('symbol', 'bar')], 9)
142 ([('string', 'foo'), ('symbol', 'bar')], 9)
143 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
143 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
144 ([('string', 'foo')], 4)
144 ([('string', 'foo')], 4)
145 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
145 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
146 ([('string', 'foo"'), ('string', 'bar')], 9)
146 ([('string', 'foo"'), ('string', 'bar')], 9)
147 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
147 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
148 ([('string', 'foo\\')], 6)
148 ([('string', 'foo\\')], 6)
149 """
149 """
150 parsed = []
150 parsed = []
151 sepchars = '{' + quote
151 sepchars = '{' + quote
152 pos = start
152 pos = start
153 p = parser.parser(elements)
153 p = parser.parser(elements)
154 while pos < stop:
154 while pos < stop:
155 n = min((tmpl.find(c, pos, stop) for c in sepchars),
155 n = min((tmpl.find(c, pos, stop) for c in sepchars),
156 key=lambda n: (n < 0, n))
156 key=lambda n: (n < 0, n))
157 if n < 0:
157 if n < 0:
158 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
158 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
159 pos = stop
159 pos = stop
160 break
160 break
161 c = tmpl[n]
161 c = tmpl[n]
162 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
162 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
163 if bs % 2 == 1:
163 if bs % 2 == 1:
164 # escaped (e.g. '\{', '\\\{', but not '\\{')
164 # escaped (e.g. '\{', '\\\{', but not '\\{')
165 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
165 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
166 pos = n + 1
166 pos = n + 1
167 continue
167 continue
168 if n > pos:
168 if n > pos:
169 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
169 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
170 if c == quote:
170 if c == quote:
171 return parsed, n + 1
171 return parsed, n + 1
172
172
173 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
173 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
174 parsed.append(parseres)
174 parsed.append(parseres)
175
175
176 if quote:
176 if quote:
177 raise error.ParseError(_("unterminated string"), start)
177 raise error.ParseError(_("unterminated string"), start)
178 return parsed, pos
178 return parsed, pos
179
179
180 def compiletemplate(tmpl, context):
180 def compiletemplate(tmpl, context):
181 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
181 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
182 return [compileexp(e, context, methods) for e in parsed]
182 return [compileexp(e, context, methods) for e in parsed]
183
183
184 def compileexp(exp, context, curmethods):
184 def compileexp(exp, context, curmethods):
185 t = exp[0]
185 t = exp[0]
186 if t in curmethods:
186 if t in curmethods:
187 return curmethods[t](exp, context)
187 return curmethods[t](exp, context)
188 raise error.ParseError(_("unknown method '%s'") % t)
188 raise error.ParseError(_("unknown method '%s'") % t)
189
189
190 # template evaluation
190 # template evaluation
191
191
192 def getsymbol(exp):
192 def getsymbol(exp):
193 if exp[0] == 'symbol':
193 if exp[0] == 'symbol':
194 return exp[1]
194 return exp[1]
195 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
195 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
196
196
197 def getlist(x):
197 def getlist(x):
198 if not x:
198 if not x:
199 return []
199 return []
200 if x[0] == 'list':
200 if x[0] == 'list':
201 return getlist(x[1]) + [x[2]]
201 return getlist(x[1]) + [x[2]]
202 return [x]
202 return [x]
203
203
204 def gettemplate(exp, context):
204 def gettemplate(exp, context):
205 if exp[0] == 'template':
205 if exp[0] == 'template':
206 return [compileexp(e, context, methods) for e in exp[1]]
206 return [compileexp(e, context, methods) for e in exp[1]]
207 if exp[0] == 'symbol':
207 if exp[0] == 'symbol':
208 # unlike runsymbol(), here 'symbol' is always taken as template name
208 # unlike runsymbol(), here 'symbol' is always taken as template name
209 # even if it exists in mapping. this allows us to override mapping
209 # even if it exists in mapping. this allows us to override mapping
210 # by web templates, e.g. 'changelogtag' is redefined in map file.
210 # by web templates, e.g. 'changelogtag' is redefined in map file.
211 return context._load(exp[1])
211 return context._load(exp[1])
212 raise error.ParseError(_("expected template specifier"))
212 raise error.ParseError(_("expected template specifier"))
213
213
214 def evalfuncarg(context, mapping, arg):
214 def evalfuncarg(context, mapping, arg):
215 func, data = arg
215 func, data = arg
216 # func() may return string, generator of strings or arbitrary object such
216 # func() may return string, generator of strings or arbitrary object such
217 # as date tuple, but filter does not want generator.
217 # as date tuple, but filter does not want generator.
218 thing = func(context, mapping, data)
218 thing = func(context, mapping, data)
219 if isinstance(thing, types.GeneratorType):
219 if isinstance(thing, types.GeneratorType):
220 thing = stringify(thing)
220 thing = stringify(thing)
221 return thing
221 return thing
222
222
223 def runinteger(context, mapping, data):
223 def runinteger(context, mapping, data):
224 return int(data)
224 return int(data)
225
225
226 def runstring(context, mapping, data):
226 def runstring(context, mapping, data):
227 return data
227 return data
228
228
229 def runsymbol(context, mapping, key):
229 def runsymbol(context, mapping, key):
230 v = mapping.get(key)
230 v = mapping.get(key)
231 if v is None:
231 if v is None:
232 v = context._defaults.get(key)
232 v = context._defaults.get(key)
233 if v is None:
233 if v is None:
234 try:
234 try:
235 v = context.process(key, mapping)
235 v = context.process(key, mapping)
236 except TemplateNotFound:
236 except TemplateNotFound:
237 v = ''
237 v = ''
238 if callable(v):
238 if callable(v):
239 return v(**mapping)
239 return v(**mapping)
240 if isinstance(v, types.GeneratorType):
240 if isinstance(v, types.GeneratorType):
241 v = list(v)
241 v = list(v)
242 return v
242 return v
243
243
244 def buildtemplate(exp, context):
244 def buildtemplate(exp, context):
245 ctmpl = [compileexp(e, context, methods) for e in exp[1]]
245 ctmpl = [compileexp(e, context, methods) for e in exp[1]]
246 if len(ctmpl) == 1:
246 if len(ctmpl) == 1:
247 return ctmpl[0] # fast path for string with no template fragment
247 return ctmpl[0] # fast path for string with no template fragment
248 return (runtemplate, ctmpl)
248 return (runtemplate, ctmpl)
249
249
250 def runtemplate(context, mapping, template):
250 def runtemplate(context, mapping, template):
251 for func, data in template:
251 for func, data in template:
252 yield func(context, mapping, data)
252 yield func(context, mapping, data)
253
253
254 def buildfilter(exp, context):
254 def buildfilter(exp, context):
255 arg = compileexp(exp[1], context, methods)
255 arg = compileexp(exp[1], context, methods)
256 n = getsymbol(exp[2])
256 n = getsymbol(exp[2])
257 if n in context._filters:
257 if n in context._filters:
258 filt = context._filters[n]
258 filt = context._filters[n]
259 return (runfilter, (arg, filt))
259 return (runfilter, (arg, filt))
260 if n in funcs:
260 if n in funcs:
261 f = funcs[n]
261 f = funcs[n]
262 return (f, [arg])
262 return (f, [arg])
263 raise error.ParseError(_("unknown function '%s'") % n)
263 raise error.ParseError(_("unknown function '%s'") % n)
264
264
265 def runfilter(context, mapping, data):
265 def runfilter(context, mapping, data):
266 arg, filt = data
266 arg, filt = data
267 thing = evalfuncarg(context, mapping, arg)
267 thing = evalfuncarg(context, mapping, arg)
268 try:
268 try:
269 return filt(thing)
269 return filt(thing)
270 except (ValueError, AttributeError, TypeError):
270 except (ValueError, AttributeError, TypeError):
271 if isinstance(arg[1], tuple):
271 if isinstance(arg[1], tuple):
272 dt = arg[1][1]
272 dt = arg[1][1]
273 else:
273 else:
274 dt = arg[1]
274 dt = arg[1]
275 raise util.Abort(_("template filter '%s' is not compatible with "
275 raise util.Abort(_("template filter '%s' is not compatible with "
276 "keyword '%s'") % (filt.func_name, dt))
276 "keyword '%s'") % (filt.func_name, dt))
277
277
278 def buildmap(exp, context):
278 def buildmap(exp, context):
279 func, data = compileexp(exp[1], context, methods)
279 func, data = compileexp(exp[1], context, methods)
280 ctmpl = gettemplate(exp[2], context)
280 ctmpl = gettemplate(exp[2], context)
281 return (runmap, (func, data, ctmpl))
281 return (runmap, (func, data, ctmpl))
282
282
283 def runmap(context, mapping, data):
283 def runmap(context, mapping, data):
284 func, data, ctmpl = data
284 func, data, ctmpl = data
285 d = func(context, mapping, data)
285 d = func(context, mapping, data)
286 if callable(d):
286 if callable(d):
287 d = d()
287 d = d()
288
288
289 lm = mapping.copy()
289 lm = mapping.copy()
290
290
291 for i in d:
291 for i in d:
292 if isinstance(i, dict):
292 if isinstance(i, dict):
293 lm.update(i)
293 lm.update(i)
294 lm['originalnode'] = mapping.get('node')
294 lm['originalnode'] = mapping.get('node')
295 yield runtemplate(context, lm, ctmpl)
295 yield runtemplate(context, lm, ctmpl)
296 else:
296 else:
297 # v is not an iterable of dicts, this happen when 'key'
297 # v is not an iterable of dicts, this happen when 'key'
298 # has been fully expanded already and format is useless.
298 # has been fully expanded already and format is useless.
299 # If so, return the expanded value.
299 # If so, return the expanded value.
300 yield i
300 yield i
301
301
302 def buildfunc(exp, context):
302 def buildfunc(exp, context):
303 n = getsymbol(exp[1])
303 n = getsymbol(exp[1])
304 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
304 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
305 if n in funcs:
305 if n in funcs:
306 f = funcs[n]
306 f = funcs[n]
307 return (f, args)
307 return (f, args)
308 if n in context._filters:
308 if n in context._filters:
309 if len(args) != 1:
309 if len(args) != 1:
310 raise error.ParseError(_("filter %s expects one argument") % n)
310 raise error.ParseError(_("filter %s expects one argument") % n)
311 f = context._filters[n]
311 f = context._filters[n]
312 return (runfilter, (args[0], f))
312 return (runfilter, (args[0], f))
313 raise error.ParseError(_("unknown function '%s'") % n)
313 raise error.ParseError(_("unknown function '%s'") % n)
314
314
315 def date(context, mapping, args):
315 def date(context, mapping, args):
316 """:date(date[, fmt]): Format a date. See :hg:`help dates` for formatting
316 """:date(date[, fmt]): Format a date. See :hg:`help dates` for formatting
317 strings. The default is a Unix date format, including the timezone:
317 strings. The default is a Unix date format, including the timezone:
318 "Mon Sep 04 15:13:13 2006 0700"."""
318 "Mon Sep 04 15:13:13 2006 0700"."""
319 if not (1 <= len(args) <= 2):
319 if not (1 <= len(args) <= 2):
320 # i18n: "date" is a keyword
320 # i18n: "date" is a keyword
321 raise error.ParseError(_("date expects one or two arguments"))
321 raise error.ParseError(_("date expects one or two arguments"))
322
322
323 date = args[0][0](context, mapping, args[0][1])
323 date = args[0][0](context, mapping, args[0][1])
324 fmt = None
324 fmt = None
325 if len(args) == 2:
325 if len(args) == 2:
326 fmt = stringify(args[1][0](context, mapping, args[1][1]))
326 fmt = stringify(args[1][0](context, mapping, args[1][1]))
327 try:
327 try:
328 if fmt is None:
328 if fmt is None:
329 return util.datestr(date)
329 return util.datestr(date)
330 else:
330 else:
331 return util.datestr(date, fmt)
331 return util.datestr(date, fmt)
332 except (TypeError, ValueError):
332 except (TypeError, ValueError):
333 # i18n: "date" is a keyword
333 # i18n: "date" is a keyword
334 raise error.ParseError(_("date expects a date information"))
334 raise error.ParseError(_("date expects a date information"))
335
335
336 def diff(context, mapping, args):
336 def diff(context, mapping, args):
337 """:diff([includepattern [, excludepattern]]): Show a diff, optionally
337 """:diff([includepattern [, excludepattern]]): Show a diff, optionally
338 specifying files to include or exclude."""
338 specifying files to include or exclude."""
339 if len(args) > 2:
339 if len(args) > 2:
340 # i18n: "diff" is a keyword
340 # i18n: "diff" is a keyword
341 raise error.ParseError(_("diff expects one, two or no arguments"))
341 raise error.ParseError(_("diff expects one, two or no arguments"))
342
342
343 def getpatterns(i):
343 def getpatterns(i):
344 if i < len(args):
344 if i < len(args):
345 s = stringify(args[i][0](context, mapping, args[i][1])).strip()
345 s = stringify(args[i][0](context, mapping, args[i][1])).strip()
346 if s:
346 if s:
347 return [s]
347 return [s]
348 return []
348 return []
349
349
350 ctx = mapping['ctx']
350 ctx = mapping['ctx']
351 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
351 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
352
352
353 return ''.join(chunks)
353 return ''.join(chunks)
354
354
355 def fill(context, mapping, args):
355 def fill(context, mapping, args):
356 """:fill(text[, width[, initialident[, hangindent]]]): Fill many
356 """:fill(text[, width[, initialident[, hangindent]]]): Fill many
357 paragraphs with optional indentation. See the "fill" filter."""
357 paragraphs with optional indentation. See the "fill" filter."""
358 if not (1 <= len(args) <= 4):
358 if not (1 <= len(args) <= 4):
359 # i18n: "fill" is a keyword
359 # i18n: "fill" is a keyword
360 raise error.ParseError(_("fill expects one to four arguments"))
360 raise error.ParseError(_("fill expects one to four arguments"))
361
361
362 text = stringify(args[0][0](context, mapping, args[0][1]))
362 text = stringify(args[0][0](context, mapping, args[0][1]))
363 width = 76
363 width = 76
364 initindent = ''
364 initindent = ''
365 hangindent = ''
365 hangindent = ''
366 if 2 <= len(args) <= 4:
366 if 2 <= len(args) <= 4:
367 try:
367 try:
368 width = int(stringify(args[1][0](context, mapping, args[1][1])))
368 width = int(stringify(args[1][0](context, mapping, args[1][1])))
369 except ValueError:
369 except ValueError:
370 # i18n: "fill" is a keyword
370 # i18n: "fill" is a keyword
371 raise error.ParseError(_("fill expects an integer width"))
371 raise error.ParseError(_("fill expects an integer width"))
372 try:
372 try:
373 initindent = stringify(args[2][0](context, mapping, args[2][1]))
373 initindent = stringify(args[2][0](context, mapping, args[2][1]))
374 hangindent = stringify(args[3][0](context, mapping, args[3][1]))
374 hangindent = stringify(args[3][0](context, mapping, args[3][1]))
375 except IndexError:
375 except IndexError:
376 pass
376 pass
377
377
378 return templatefilters.fill(text, width, initindent, hangindent)
378 return templatefilters.fill(text, width, initindent, hangindent)
379
379
380 def pad(context, mapping, args):
380 def pad(context, mapping, args):
381 """:pad(text, width[, fillchar=' '[, right=False]]): Pad text with a
381 """:pad(text, width[, fillchar=' '[, right=False]]): Pad text with a
382 fill character."""
382 fill character."""
383 if not (2 <= len(args) <= 4):
383 if not (2 <= len(args) <= 4):
384 # i18n: "pad" is a keyword
384 # i18n: "pad" is a keyword
385 raise error.ParseError(_("pad() expects two to four arguments"))
385 raise error.ParseError(_("pad() expects two to four arguments"))
386
386
387 width = int(args[1][1])
387 width = int(args[1][1])
388
388
389 text = stringify(args[0][0](context, mapping, args[0][1]))
389 text = stringify(args[0][0](context, mapping, args[0][1]))
390
390
391 right = False
391 right = False
392 fillchar = ' '
392 fillchar = ' '
393 if len(args) > 2:
393 if len(args) > 2:
394 fillchar = stringify(args[2][0](context, mapping, args[2][1]))
394 fillchar = stringify(args[2][0](context, mapping, args[2][1]))
395 if len(args) > 3:
395 if len(args) > 3:
396 right = util.parsebool(args[3][1])
396 right = util.parsebool(args[3][1])
397
397
398 if right:
398 if right:
399 return text.rjust(width, fillchar)
399 return text.rjust(width, fillchar)
400 else:
400 else:
401 return text.ljust(width, fillchar)
401 return text.ljust(width, fillchar)
402
402
403 def indent(context, mapping, args):
403 def indent(context, mapping, args):
404 """:indent(text, indentchars[, firstline]): Indents all non-empty lines
404 """:indent(text, indentchars[, firstline]): Indents all non-empty lines
405 with the characters given in the indentchars string. An optional
405 with the characters given in the indentchars string. An optional
406 third parameter will override the indent for the first line only
406 third parameter will override the indent for the first line only
407 if present."""
407 if present."""
408 if not (2 <= len(args) <= 3):
408 if not (2 <= len(args) <= 3):
409 # i18n: "indent" is a keyword
409 # i18n: "indent" is a keyword
410 raise error.ParseError(_("indent() expects two or three arguments"))
410 raise error.ParseError(_("indent() expects two or three arguments"))
411
411
412 text = stringify(args[0][0](context, mapping, args[0][1]))
412 text = stringify(args[0][0](context, mapping, args[0][1]))
413 indent = stringify(args[1][0](context, mapping, args[1][1]))
413 indent = stringify(args[1][0](context, mapping, args[1][1]))
414
414
415 if len(args) == 3:
415 if len(args) == 3:
416 firstline = stringify(args[2][0](context, mapping, args[2][1]))
416 firstline = stringify(args[2][0](context, mapping, args[2][1]))
417 else:
417 else:
418 firstline = indent
418 firstline = indent
419
419
420 # the indent function doesn't indent the first line, so we do it here
420 # the indent function doesn't indent the first line, so we do it here
421 return templatefilters.indent(firstline + text, indent)
421 return templatefilters.indent(firstline + text, indent)
422
422
423 def get(context, mapping, args):
423 def get(context, mapping, args):
424 """:get(dict, key): Get an attribute/key from an object. Some keywords
424 """:get(dict, key): Get an attribute/key from an object. Some keywords
425 are complex types. This function allows you to obtain the value of an
425 are complex types. This function allows you to obtain the value of an
426 attribute on these types."""
426 attribute on these types."""
427 if len(args) != 2:
427 if len(args) != 2:
428 # i18n: "get" is a keyword
428 # i18n: "get" is a keyword
429 raise error.ParseError(_("get() expects two arguments"))
429 raise error.ParseError(_("get() expects two arguments"))
430
430
431 dictarg = args[0][0](context, mapping, args[0][1])
431 dictarg = args[0][0](context, mapping, args[0][1])
432 if not util.safehasattr(dictarg, 'get'):
432 if not util.safehasattr(dictarg, 'get'):
433 # i18n: "get" is a keyword
433 # i18n: "get" is a keyword
434 raise error.ParseError(_("get() expects a dict as first argument"))
434 raise error.ParseError(_("get() expects a dict as first argument"))
435
435
436 key = args[1][0](context, mapping, args[1][1])
436 key = args[1][0](context, mapping, args[1][1])
437 yield dictarg.get(key)
437 yield dictarg.get(key)
438
438
439 def if_(context, mapping, args):
439 def if_(context, mapping, args):
440 """:if(expr, then[, else]): Conditionally execute based on the result of
440 """:if(expr, then[, else]): Conditionally execute based on the result of
441 an expression."""
441 an expression."""
442 if not (2 <= len(args) <= 3):
442 if not (2 <= len(args) <= 3):
443 # i18n: "if" is a keyword
443 # i18n: "if" is a keyword
444 raise error.ParseError(_("if expects two or three arguments"))
444 raise error.ParseError(_("if expects two or three arguments"))
445
445
446 test = stringify(args[0][0](context, mapping, args[0][1]))
446 test = stringify(args[0][0](context, mapping, args[0][1]))
447 if test:
447 if test:
448 yield args[1][0](context, mapping, args[1][1])
448 yield args[1][0](context, mapping, args[1][1])
449 elif len(args) == 3:
449 elif len(args) == 3:
450 yield args[2][0](context, mapping, args[2][1])
450 yield args[2][0](context, mapping, args[2][1])
451
451
452 def ifcontains(context, mapping, args):
452 def ifcontains(context, mapping, args):
453 """:ifcontains(search, thing, then[, else]): Conditionally execute based
453 """:ifcontains(search, thing, then[, else]): Conditionally execute based
454 on whether the item "search" is in "thing"."""
454 on whether the item "search" is in "thing"."""
455 if not (3 <= len(args) <= 4):
455 if not (3 <= len(args) <= 4):
456 # i18n: "ifcontains" is a keyword
456 # i18n: "ifcontains" is a keyword
457 raise error.ParseError(_("ifcontains expects three or four arguments"))
457 raise error.ParseError(_("ifcontains expects three or four arguments"))
458
458
459 item = stringify(args[0][0](context, mapping, args[0][1]))
459 item = stringify(args[0][0](context, mapping, args[0][1]))
460 items = args[1][0](context, mapping, args[1][1])
460 items = args[1][0](context, mapping, args[1][1])
461
461
462 if item in items:
462 if item in items:
463 yield args[2][0](context, mapping, args[2][1])
463 yield args[2][0](context, mapping, args[2][1])
464 elif len(args) == 4:
464 elif len(args) == 4:
465 yield args[3][0](context, mapping, args[3][1])
465 yield args[3][0](context, mapping, args[3][1])
466
466
467 def ifeq(context, mapping, args):
467 def ifeq(context, mapping, args):
468 """:ifeq(expr1, expr2, then[, else]): Conditionally execute based on
468 """:ifeq(expr1, expr2, then[, else]): Conditionally execute based on
469 whether 2 items are equivalent."""
469 whether 2 items are equivalent."""
470 if not (3 <= len(args) <= 4):
470 if not (3 <= len(args) <= 4):
471 # i18n: "ifeq" is a keyword
471 # i18n: "ifeq" is a keyword
472 raise error.ParseError(_("ifeq expects three or four arguments"))
472 raise error.ParseError(_("ifeq expects three or four arguments"))
473
473
474 test = stringify(args[0][0](context, mapping, args[0][1]))
474 test = stringify(args[0][0](context, mapping, args[0][1]))
475 match = stringify(args[1][0](context, mapping, args[1][1]))
475 match = stringify(args[1][0](context, mapping, args[1][1]))
476 if test == match:
476 if test == match:
477 yield args[2][0](context, mapping, args[2][1])
477 yield args[2][0](context, mapping, args[2][1])
478 elif len(args) == 4:
478 elif len(args) == 4:
479 yield args[3][0](context, mapping, args[3][1])
479 yield args[3][0](context, mapping, args[3][1])
480
480
481 def join(context, mapping, args):
481 def join(context, mapping, args):
482 """:join(list, sep): Join items in a list with a delimiter."""
482 """:join(list, sep): Join items in a list with a delimiter."""
483 if not (1 <= len(args) <= 2):
483 if not (1 <= len(args) <= 2):
484 # i18n: "join" is a keyword
484 # i18n: "join" is a keyword
485 raise error.ParseError(_("join expects one or two arguments"))
485 raise error.ParseError(_("join expects one or two arguments"))
486
486
487 joinset = args[0][0](context, mapping, args[0][1])
487 joinset = args[0][0](context, mapping, args[0][1])
488 if callable(joinset):
488 if callable(joinset):
489 jf = joinset.joinfmt
489 jf = joinset.joinfmt
490 joinset = [jf(x) for x in joinset()]
490 joinset = [jf(x) for x in joinset()]
491
491
492 joiner = " "
492 joiner = " "
493 if len(args) > 1:
493 if len(args) > 1:
494 joiner = stringify(args[1][0](context, mapping, args[1][1]))
494 joiner = stringify(args[1][0](context, mapping, args[1][1]))
495
495
496 first = True
496 first = True
497 for x in joinset:
497 for x in joinset:
498 if first:
498 if first:
499 first = False
499 first = False
500 else:
500 else:
501 yield joiner
501 yield joiner
502 yield x
502 yield x
503
503
504 def label(context, mapping, args):
504 def label(context, mapping, args):
505 """:label(label, expr): Apply a label to generated content. Content with
505 """:label(label, expr): Apply a label to generated content. Content with
506 a label applied can result in additional post-processing, such as
506 a label applied can result in additional post-processing, such as
507 automatic colorization."""
507 automatic colorization."""
508 if len(args) != 2:
508 if len(args) != 2:
509 # i18n: "label" is a keyword
509 # i18n: "label" is a keyword
510 raise error.ParseError(_("label expects two arguments"))
510 raise error.ParseError(_("label expects two arguments"))
511
511
512 # ignore args[0] (the label string) since this is supposed to be a a no-op
512 # ignore args[0] (the label string) since this is supposed to be a a no-op
513 yield args[1][0](context, mapping, args[1][1])
513 yield args[1][0](context, mapping, args[1][1])
514
514
515 def latesttag(context, mapping, args):
515 def latesttag(context, mapping, args):
516 """:latesttag([pattern]): The global tags matching the given pattern on the
516 """:latesttag([pattern]): The global tags matching the given pattern on the
517 most recent globally tagged ancestor of this changeset."""
517 most recent globally tagged ancestor of this changeset."""
518 if len(args) > 1:
518 if len(args) > 1:
519 # i18n: "latesttag" is a keyword
519 # i18n: "latesttag" is a keyword
520 raise error.ParseError(_("latesttag expects at most one argument"))
520 raise error.ParseError(_("latesttag expects at most one argument"))
521
521
522 pattern = None
522 pattern = None
523 if len(args) == 1:
523 if len(args) == 1:
524 pattern = stringify(args[0][0](context, mapping, args[0][1]))
524 pattern = stringify(args[0][0](context, mapping, args[0][1]))
525
525
526 return templatekw.showlatesttags(pattern, **mapping)
526 return templatekw.showlatesttags(pattern, **mapping)
527
527
528 def localdate(context, mapping, args):
528 def localdate(context, mapping, args):
529 """:localdate(date[, tz]): Converts a date to the specified timezone.
529 """:localdate(date[, tz]): Converts a date to the specified timezone.
530 The default is local date."""
530 The default is local date."""
531 if not (1 <= len(args) <= 2):
531 if not (1 <= len(args) <= 2):
532 # i18n: "localdate" is a keyword
532 # i18n: "localdate" is a keyword
533 raise error.ParseError(_("localdate expects one or two arguments"))
533 raise error.ParseError(_("localdate expects one or two arguments"))
534
534
535 date = evalfuncarg(context, mapping, args[0])
535 date = evalfuncarg(context, mapping, args[0])
536 try:
536 try:
537 date = util.parsedate(date)
537 date = util.parsedate(date)
538 except AttributeError: # not str nor date tuple
538 except AttributeError: # not str nor date tuple
539 # i18n: "localdate" is a keyword
539 # i18n: "localdate" is a keyword
540 raise error.ParseError(_("localdate expects a date information"))
540 raise error.ParseError(_("localdate expects a date information"))
541 if len(args) >= 2:
541 if len(args) >= 2:
542 tzoffset = None
542 tzoffset = None
543 tz = evalfuncarg(context, mapping, args[1])
543 tz = evalfuncarg(context, mapping, args[1])
544 if isinstance(tz, str):
544 if isinstance(tz, str):
545 tzoffset = util.parsetimezone(tz)
545 tzoffset = util.parsetimezone(tz)
546 if tzoffset is None:
546 if tzoffset is None:
547 try:
547 try:
548 tzoffset = int(tz)
548 tzoffset = int(tz)
549 except (TypeError, ValueError):
549 except (TypeError, ValueError):
550 # i18n: "localdate" is a keyword
550 # i18n: "localdate" is a keyword
551 raise error.ParseError(_("localdate expects a timezone"))
551 raise error.ParseError(_("localdate expects a timezone"))
552 else:
552 else:
553 tzoffset = util.makedate()[1]
553 tzoffset = util.makedate()[1]
554 return (date[0], tzoffset)
554 return (date[0], tzoffset)
555
555
556 def revset(context, mapping, args):
556 def revset(context, mapping, args):
557 """:revset(query[, formatargs...]): Execute a revision set query. See
557 """:revset(query[, formatargs...]): Execute a revision set query. See
558 :hg:`help revset`."""
558 :hg:`help revset`."""
559 if not len(args) > 0:
559 if not len(args) > 0:
560 # i18n: "revset" is a keyword
560 # i18n: "revset" is a keyword
561 raise error.ParseError(_("revset expects one or more arguments"))
561 raise error.ParseError(_("revset expects one or more arguments"))
562
562
563 raw = stringify(args[0][0](context, mapping, args[0][1]))
563 raw = stringify(args[0][0](context, mapping, args[0][1]))
564 ctx = mapping['ctx']
564 ctx = mapping['ctx']
565 repo = ctx.repo()
565 repo = ctx.repo()
566
566
567 def query(expr):
567 def query(expr):
568 m = revsetmod.match(repo.ui, expr)
568 m = revsetmod.match(repo.ui, expr)
569 return m(repo)
569 return m(repo)
570
570
571 if len(args) > 1:
571 if len(args) > 1:
572 formatargs = list([a[0](context, mapping, a[1]) for a in args[1:]])
572 formatargs = list([a[0](context, mapping, a[1]) for a in args[1:]])
573 revs = query(revsetmod.formatspec(raw, *formatargs))
573 revs = query(revsetmod.formatspec(raw, *formatargs))
574 revs = list([str(r) for r in revs])
574 revs = list([str(r) for r in revs])
575 else:
575 else:
576 revsetcache = mapping['cache'].setdefault("revsetcache", {})
576 revsetcache = mapping['cache'].setdefault("revsetcache", {})
577 if raw in revsetcache:
577 if raw in revsetcache:
578 revs = revsetcache[raw]
578 revs = revsetcache[raw]
579 else:
579 else:
580 revs = query(raw)
580 revs = query(raw)
581 revs = list([str(r) for r in revs])
581 revs = list([str(r) for r in revs])
582 revsetcache[raw] = revs
582 revsetcache[raw] = revs
583
583
584 return templatekw.showrevslist("revision", revs, **mapping)
584 return templatekw.showrevslist("revision", revs, **mapping)
585
585
586 def rstdoc(context, mapping, args):
586 def rstdoc(context, mapping, args):
587 """:rstdoc(text, style): Format ReStructuredText."""
587 """:rstdoc(text, style): Format ReStructuredText."""
588 if len(args) != 2:
588 if len(args) != 2:
589 # i18n: "rstdoc" is a keyword
589 # i18n: "rstdoc" is a keyword
590 raise error.ParseError(_("rstdoc expects two arguments"))
590 raise error.ParseError(_("rstdoc expects two arguments"))
591
591
592 text = stringify(args[0][0](context, mapping, args[0][1]))
592 text = stringify(args[0][0](context, mapping, args[0][1]))
593 style = stringify(args[1][0](context, mapping, args[1][1]))
593 style = stringify(args[1][0](context, mapping, args[1][1]))
594
594
595 return minirst.format(text, style=style, keep=['verbose'])
595 return minirst.format(text, style=style, keep=['verbose'])
596
596
597 def shortest(context, mapping, args):
597 def shortest(context, mapping, args):
598 """:shortest(node, minlength=4): Obtain the shortest representation of
598 """:shortest(node, minlength=4): Obtain the shortest representation of
599 a node."""
599 a node."""
600 if not (1 <= len(args) <= 2):
600 if not (1 <= len(args) <= 2):
601 # i18n: "shortest" is a keyword
601 # i18n: "shortest" is a keyword
602 raise error.ParseError(_("shortest() expects one or two arguments"))
602 raise error.ParseError(_("shortest() expects one or two arguments"))
603
603
604 node = stringify(args[0][0](context, mapping, args[0][1]))
604 node = stringify(args[0][0](context, mapping, args[0][1]))
605
605
606 minlength = 4
606 minlength = 4
607 if len(args) > 1:
607 if len(args) > 1:
608 minlength = int(args[1][1])
608 minlength = int(args[1][1])
609
609
610 cl = mapping['ctx']._repo.changelog
610 cl = mapping['ctx']._repo.changelog
611 def isvalid(test):
611 def isvalid(test):
612 try:
612 try:
613 try:
613 try:
614 cl.index.partialmatch(test)
614 cl.index.partialmatch(test)
615 except AttributeError:
615 except AttributeError:
616 # Pure mercurial doesn't support partialmatch on the index.
616 # Pure mercurial doesn't support partialmatch on the index.
617 # Fallback to the slow way.
617 # Fallback to the slow way.
618 if cl._partialmatch(test) is None:
618 if cl._partialmatch(test) is None:
619 return False
619 return False
620
620
621 try:
621 try:
622 i = int(test)
622 i = int(test)
623 # if we are a pure int, then starting with zero will not be
623 # if we are a pure int, then starting with zero will not be
624 # confused as a rev; or, obviously, if the int is larger than
624 # confused as a rev; or, obviously, if the int is larger than
625 # the value of the tip rev
625 # the value of the tip rev
626 if test[0] == '0' or i > len(cl):
626 if test[0] == '0' or i > len(cl):
627 return True
627 return True
628 return False
628 return False
629 except ValueError:
629 except ValueError:
630 return True
630 return True
631 except error.RevlogError:
631 except error.RevlogError:
632 return False
632 return False
633
633
634 shortest = node
634 shortest = node
635 startlength = max(6, minlength)
635 startlength = max(6, minlength)
636 length = startlength
636 length = startlength
637 while True:
637 while True:
638 test = node[:length]
638 test = node[:length]
639 if isvalid(test):
639 if isvalid(test):
640 shortest = test
640 shortest = test
641 if length == minlength or length > startlength:
641 if length == minlength or length > startlength:
642 return shortest
642 return shortest
643 length -= 1
643 length -= 1
644 else:
644 else:
645 length += 1
645 length += 1
646 if len(shortest) <= length:
646 if len(shortest) <= length:
647 return shortest
647 return shortest
648
648
649 def strip(context, mapping, args):
649 def strip(context, mapping, args):
650 """:strip(text[, chars]): Strip characters from a string. By default,
650 """:strip(text[, chars]): Strip characters from a string. By default,
651 strips all leading and trailing whitespace."""
651 strips all leading and trailing whitespace."""
652 if not (1 <= len(args) <= 2):
652 if not (1 <= len(args) <= 2):
653 # i18n: "strip" is a keyword
653 # i18n: "strip" is a keyword
654 raise error.ParseError(_("strip expects one or two arguments"))
654 raise error.ParseError(_("strip expects one or two arguments"))
655
655
656 text = stringify(args[0][0](context, mapping, args[0][1]))
656 text = stringify(args[0][0](context, mapping, args[0][1]))
657 if len(args) == 2:
657 if len(args) == 2:
658 chars = stringify(args[1][0](context, mapping, args[1][1]))
658 chars = stringify(args[1][0](context, mapping, args[1][1]))
659 return text.strip(chars)
659 return text.strip(chars)
660 return text.strip()
660 return text.strip()
661
661
662 def sub(context, mapping, args):
662 def sub(context, mapping, args):
663 """:sub(pattern, replacement, expression): Perform text substitution
663 """:sub(pattern, replacement, expression): Perform text substitution
664 using regular expressions."""
664 using regular expressions."""
665 if len(args) != 3:
665 if len(args) != 3:
666 # i18n: "sub" is a keyword
666 # i18n: "sub" is a keyword
667 raise error.ParseError(_("sub expects three arguments"))
667 raise error.ParseError(_("sub expects three arguments"))
668
668
669 pat = stringify(args[0][0](context, mapping, args[0][1]))
669 pat = stringify(args[0][0](context, mapping, args[0][1]))
670 rpl = stringify(args[1][0](context, mapping, args[1][1]))
670 rpl = stringify(args[1][0](context, mapping, args[1][1]))
671 src = stringify(args[2][0](context, mapping, args[2][1]))
671 src = stringify(args[2][0](context, mapping, args[2][1]))
672 try:
672 try:
673 patre = re.compile(pat)
673 patre = re.compile(pat)
674 except re.error:
674 except re.error:
675 # i18n: "sub" is a keyword
675 # i18n: "sub" is a keyword
676 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
676 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
677 try:
677 try:
678 yield patre.sub(rpl, src)
678 yield patre.sub(rpl, src)
679 except re.error:
679 except re.error:
680 # i18n: "sub" is a keyword
680 # i18n: "sub" is a keyword
681 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
681 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
682
682
683 def startswith(context, mapping, args):
683 def startswith(context, mapping, args):
684 """:startswith(pattern, text): Returns the value from the "text" argument
684 """:startswith(pattern, text): Returns the value from the "text" argument
685 if it begins with the content from the "pattern" argument."""
685 if it begins with the content from the "pattern" argument."""
686 if len(args) != 2:
686 if len(args) != 2:
687 # i18n: "startswith" is a keyword
687 # i18n: "startswith" is a keyword
688 raise error.ParseError(_("startswith expects two arguments"))
688 raise error.ParseError(_("startswith expects two arguments"))
689
689
690 patn = stringify(args[0][0](context, mapping, args[0][1]))
690 patn = stringify(args[0][0](context, mapping, args[0][1]))
691 text = stringify(args[1][0](context, mapping, args[1][1]))
691 text = stringify(args[1][0](context, mapping, args[1][1]))
692 if text.startswith(patn):
692 if text.startswith(patn):
693 return text
693 return text
694 return ''
694 return ''
695
695
696
696
697 def word(context, mapping, args):
697 def word(context, mapping, args):
698 """:word(number, text[, separator]): Return the nth word from a string."""
698 """:word(number, text[, separator]): Return the nth word from a string."""
699 if not (2 <= len(args) <= 3):
699 if not (2 <= len(args) <= 3):
700 # i18n: "word" is a keyword
700 # i18n: "word" is a keyword
701 raise error.ParseError(_("word expects two or three arguments, got %d")
701 raise error.ParseError(_("word expects two or three arguments, got %d")
702 % len(args))
702 % len(args))
703
703
704 try:
704 try:
705 num = int(stringify(args[0][0](context, mapping, args[0][1])))
705 num = int(stringify(args[0][0](context, mapping, args[0][1])))
706 except ValueError:
706 except ValueError:
707 # i18n: "word" is a keyword
707 # i18n: "word" is a keyword
708 raise error.ParseError(_("word expects an integer index"))
708 raise error.ParseError(_("word expects an integer index"))
709 text = stringify(args[1][0](context, mapping, args[1][1]))
709 text = stringify(args[1][0](context, mapping, args[1][1]))
710 if len(args) == 3:
710 if len(args) == 3:
711 splitter = stringify(args[2][0](context, mapping, args[2][1]))
711 splitter = stringify(args[2][0](context, mapping, args[2][1]))
712 else:
712 else:
713 splitter = None
713 splitter = None
714
714
715 tokens = text.split(splitter)
715 tokens = text.split(splitter)
716 if num >= len(tokens):
716 if num >= len(tokens) or num < -len(tokens):
717 return ''
717 return ''
718 else:
718 else:
719 return tokens[num]
719 return tokens[num]
720
720
721 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
721 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
722 exprmethods = {
722 exprmethods = {
723 "integer": lambda e, c: (runinteger, e[1]),
723 "integer": lambda e, c: (runinteger, e[1]),
724 "string": lambda e, c: (runstring, e[1]),
724 "string": lambda e, c: (runstring, e[1]),
725 "symbol": lambda e, c: (runsymbol, e[1]),
725 "symbol": lambda e, c: (runsymbol, e[1]),
726 "template": buildtemplate,
726 "template": buildtemplate,
727 "group": lambda e, c: compileexp(e[1], c, exprmethods),
727 "group": lambda e, c: compileexp(e[1], c, exprmethods),
728 # ".": buildmember,
728 # ".": buildmember,
729 "|": buildfilter,
729 "|": buildfilter,
730 "%": buildmap,
730 "%": buildmap,
731 "func": buildfunc,
731 "func": buildfunc,
732 }
732 }
733
733
734 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
734 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
735 methods = exprmethods.copy()
735 methods = exprmethods.copy()
736 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
736 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
737
737
738 funcs = {
738 funcs = {
739 "date": date,
739 "date": date,
740 "diff": diff,
740 "diff": diff,
741 "fill": fill,
741 "fill": fill,
742 "get": get,
742 "get": get,
743 "if": if_,
743 "if": if_,
744 "ifcontains": ifcontains,
744 "ifcontains": ifcontains,
745 "ifeq": ifeq,
745 "ifeq": ifeq,
746 "indent": indent,
746 "indent": indent,
747 "join": join,
747 "join": join,
748 "label": label,
748 "label": label,
749 "latesttag": latesttag,
749 "latesttag": latesttag,
750 "localdate": localdate,
750 "localdate": localdate,
751 "pad": pad,
751 "pad": pad,
752 "revset": revset,
752 "revset": revset,
753 "rstdoc": rstdoc,
753 "rstdoc": rstdoc,
754 "shortest": shortest,
754 "shortest": shortest,
755 "startswith": startswith,
755 "startswith": startswith,
756 "strip": strip,
756 "strip": strip,
757 "sub": sub,
757 "sub": sub,
758 "word": word,
758 "word": word,
759 }
759 }
760
760
761 # template engine
761 # template engine
762
762
763 stringify = templatefilters.stringify
763 stringify = templatefilters.stringify
764
764
765 def _flatten(thing):
765 def _flatten(thing):
766 '''yield a single stream from a possibly nested set of iterators'''
766 '''yield a single stream from a possibly nested set of iterators'''
767 if isinstance(thing, str):
767 if isinstance(thing, str):
768 yield thing
768 yield thing
769 elif not util.safehasattr(thing, '__iter__'):
769 elif not util.safehasattr(thing, '__iter__'):
770 if thing is not None:
770 if thing is not None:
771 yield str(thing)
771 yield str(thing)
772 else:
772 else:
773 for i in thing:
773 for i in thing:
774 if isinstance(i, str):
774 if isinstance(i, str):
775 yield i
775 yield i
776 elif not util.safehasattr(i, '__iter__'):
776 elif not util.safehasattr(i, '__iter__'):
777 if i is not None:
777 if i is not None:
778 yield str(i)
778 yield str(i)
779 elif i is not None:
779 elif i is not None:
780 for j in _flatten(i):
780 for j in _flatten(i):
781 yield j
781 yield j
782
782
783 def unquotestring(s):
783 def unquotestring(s):
784 '''unwrap quotes'''
784 '''unwrap quotes'''
785 if len(s) < 2 or s[0] != s[-1]:
785 if len(s) < 2 or s[0] != s[-1]:
786 raise SyntaxError(_('unmatched quotes'))
786 raise SyntaxError(_('unmatched quotes'))
787 return s[1:-1]
787 return s[1:-1]
788
788
789 class engine(object):
789 class engine(object):
790 '''template expansion engine.
790 '''template expansion engine.
791
791
792 template expansion works like this. a map file contains key=value
792 template expansion works like this. a map file contains key=value
793 pairs. if value is quoted, it is treated as string. otherwise, it
793 pairs. if value is quoted, it is treated as string. otherwise, it
794 is treated as name of template file.
794 is treated as name of template file.
795
795
796 templater is asked to expand a key in map. it looks up key, and
796 templater is asked to expand a key in map. it looks up key, and
797 looks for strings like this: {foo}. it expands {foo} by looking up
797 looks for strings like this: {foo}. it expands {foo} by looking up
798 foo in map, and substituting it. expansion is recursive: it stops
798 foo in map, and substituting it. expansion is recursive: it stops
799 when there is no more {foo} to replace.
799 when there is no more {foo} to replace.
800
800
801 expansion also allows formatting and filtering.
801 expansion also allows formatting and filtering.
802
802
803 format uses key to expand each item in list. syntax is
803 format uses key to expand each item in list. syntax is
804 {key%format}.
804 {key%format}.
805
805
806 filter uses function to transform value. syntax is
806 filter uses function to transform value. syntax is
807 {key|filter1|filter2|...}.'''
807 {key|filter1|filter2|...}.'''
808
808
809 def __init__(self, loader, filters=None, defaults=None):
809 def __init__(self, loader, filters=None, defaults=None):
810 self._loader = loader
810 self._loader = loader
811 if filters is None:
811 if filters is None:
812 filters = {}
812 filters = {}
813 self._filters = filters
813 self._filters = filters
814 if defaults is None:
814 if defaults is None:
815 defaults = {}
815 defaults = {}
816 self._defaults = defaults
816 self._defaults = defaults
817 self._cache = {}
817 self._cache = {}
818
818
819 def _load(self, t):
819 def _load(self, t):
820 '''load, parse, and cache a template'''
820 '''load, parse, and cache a template'''
821 if t not in self._cache:
821 if t not in self._cache:
822 self._cache[t] = compiletemplate(self._loader(t), self)
822 self._cache[t] = compiletemplate(self._loader(t), self)
823 return self._cache[t]
823 return self._cache[t]
824
824
825 def process(self, t, mapping):
825 def process(self, t, mapping):
826 '''Perform expansion. t is name of map element to expand.
826 '''Perform expansion. t is name of map element to expand.
827 mapping contains added elements for use during expansion. Is a
827 mapping contains added elements for use during expansion. Is a
828 generator.'''
828 generator.'''
829 return _flatten(runtemplate(self, mapping, self._load(t)))
829 return _flatten(runtemplate(self, mapping, self._load(t)))
830
830
831 engines = {'default': engine}
831 engines = {'default': engine}
832
832
833 def stylelist():
833 def stylelist():
834 paths = templatepaths()
834 paths = templatepaths()
835 if not paths:
835 if not paths:
836 return _('no templates found, try `hg debuginstall` for more info')
836 return _('no templates found, try `hg debuginstall` for more info')
837 dirlist = os.listdir(paths[0])
837 dirlist = os.listdir(paths[0])
838 stylelist = []
838 stylelist = []
839 for file in dirlist:
839 for file in dirlist:
840 split = file.split(".")
840 split = file.split(".")
841 if split[0] == "map-cmdline":
841 if split[0] == "map-cmdline":
842 stylelist.append(split[1])
842 stylelist.append(split[1])
843 return ", ".join(sorted(stylelist))
843 return ", ".join(sorted(stylelist))
844
844
845 class TemplateNotFound(util.Abort):
845 class TemplateNotFound(util.Abort):
846 pass
846 pass
847
847
848 class templater(object):
848 class templater(object):
849
849
850 def __init__(self, mapfile, filters=None, defaults=None, cache=None,
850 def __init__(self, mapfile, filters=None, defaults=None, cache=None,
851 minchunk=1024, maxchunk=65536):
851 minchunk=1024, maxchunk=65536):
852 '''set up template engine.
852 '''set up template engine.
853 mapfile is name of file to read map definitions from.
853 mapfile is name of file to read map definitions from.
854 filters is dict of functions. each transforms a value into another.
854 filters is dict of functions. each transforms a value into another.
855 defaults is dict of default map definitions.'''
855 defaults is dict of default map definitions.'''
856 if filters is None:
856 if filters is None:
857 filters = {}
857 filters = {}
858 if defaults is None:
858 if defaults is None:
859 defaults = {}
859 defaults = {}
860 if cache is None:
860 if cache is None:
861 cache = {}
861 cache = {}
862 self.mapfile = mapfile or 'template'
862 self.mapfile = mapfile or 'template'
863 self.cache = cache.copy()
863 self.cache = cache.copy()
864 self.map = {}
864 self.map = {}
865 if mapfile:
865 if mapfile:
866 self.base = os.path.dirname(mapfile)
866 self.base = os.path.dirname(mapfile)
867 else:
867 else:
868 self.base = ''
868 self.base = ''
869 self.filters = templatefilters.filters.copy()
869 self.filters = templatefilters.filters.copy()
870 self.filters.update(filters)
870 self.filters.update(filters)
871 self.defaults = defaults
871 self.defaults = defaults
872 self.minchunk, self.maxchunk = minchunk, maxchunk
872 self.minchunk, self.maxchunk = minchunk, maxchunk
873 self.ecache = {}
873 self.ecache = {}
874
874
875 if not mapfile:
875 if not mapfile:
876 return
876 return
877 if not os.path.exists(mapfile):
877 if not os.path.exists(mapfile):
878 raise util.Abort(_("style '%s' not found") % mapfile,
878 raise util.Abort(_("style '%s' not found") % mapfile,
879 hint=_("available styles: %s") % stylelist())
879 hint=_("available styles: %s") % stylelist())
880
880
881 conf = config.config(includepaths=templatepaths())
881 conf = config.config(includepaths=templatepaths())
882 conf.read(mapfile)
882 conf.read(mapfile)
883
883
884 for key, val in conf[''].items():
884 for key, val in conf[''].items():
885 if not val:
885 if not val:
886 raise SyntaxError(_('%s: missing value') % conf.source('', key))
886 raise SyntaxError(_('%s: missing value') % conf.source('', key))
887 if val[0] in "'\"":
887 if val[0] in "'\"":
888 try:
888 try:
889 self.cache[key] = unquotestring(val)
889 self.cache[key] = unquotestring(val)
890 except SyntaxError as inst:
890 except SyntaxError as inst:
891 raise SyntaxError('%s: %s' %
891 raise SyntaxError('%s: %s' %
892 (conf.source('', key), inst.args[0]))
892 (conf.source('', key), inst.args[0]))
893 else:
893 else:
894 val = 'default', val
894 val = 'default', val
895 if ':' in val[1]:
895 if ':' in val[1]:
896 val = val[1].split(':', 1)
896 val = val[1].split(':', 1)
897 self.map[key] = val[0], os.path.join(self.base, val[1])
897 self.map[key] = val[0], os.path.join(self.base, val[1])
898
898
899 def __contains__(self, key):
899 def __contains__(self, key):
900 return key in self.cache or key in self.map
900 return key in self.cache or key in self.map
901
901
902 def load(self, t):
902 def load(self, t):
903 '''Get the template for the given template name. Use a local cache.'''
903 '''Get the template for the given template name. Use a local cache.'''
904 if t not in self.cache:
904 if t not in self.cache:
905 try:
905 try:
906 self.cache[t] = util.readfile(self.map[t][1])
906 self.cache[t] = util.readfile(self.map[t][1])
907 except KeyError as inst:
907 except KeyError as inst:
908 raise TemplateNotFound(_('"%s" not in template map') %
908 raise TemplateNotFound(_('"%s" not in template map') %
909 inst.args[0])
909 inst.args[0])
910 except IOError as inst:
910 except IOError as inst:
911 raise IOError(inst.args[0], _('template file %s: %s') %
911 raise IOError(inst.args[0], _('template file %s: %s') %
912 (self.map[t][1], inst.args[1]))
912 (self.map[t][1], inst.args[1]))
913 return self.cache[t]
913 return self.cache[t]
914
914
915 def __call__(self, t, **mapping):
915 def __call__(self, t, **mapping):
916 ttype = t in self.map and self.map[t][0] or 'default'
916 ttype = t in self.map and self.map[t][0] or 'default'
917 if ttype not in self.ecache:
917 if ttype not in self.ecache:
918 self.ecache[ttype] = engines[ttype](self.load,
918 self.ecache[ttype] = engines[ttype](self.load,
919 self.filters, self.defaults)
919 self.filters, self.defaults)
920 proc = self.ecache[ttype]
920 proc = self.ecache[ttype]
921
921
922 stream = proc.process(t, mapping)
922 stream = proc.process(t, mapping)
923 if self.minchunk:
923 if self.minchunk:
924 stream = util.increasingchunks(stream, min=self.minchunk,
924 stream = util.increasingchunks(stream, min=self.minchunk,
925 max=self.maxchunk)
925 max=self.maxchunk)
926 return stream
926 return stream
927
927
928 def templatepaths():
928 def templatepaths():
929 '''return locations used for template files.'''
929 '''return locations used for template files.'''
930 pathsrel = ['templates']
930 pathsrel = ['templates']
931 paths = [os.path.normpath(os.path.join(util.datapath, f))
931 paths = [os.path.normpath(os.path.join(util.datapath, f))
932 for f in pathsrel]
932 for f in pathsrel]
933 return [p for p in paths if os.path.isdir(p)]
933 return [p for p in paths if os.path.isdir(p)]
934
934
935 def templatepath(name):
935 def templatepath(name):
936 '''return location of template file. returns None if not found.'''
936 '''return location of template file. returns None if not found.'''
937 for p in templatepaths():
937 for p in templatepaths():
938 f = os.path.join(p, name)
938 f = os.path.join(p, name)
939 if os.path.exists(f):
939 if os.path.exists(f):
940 return f
940 return f
941 return None
941 return None
942
942
943 def stylemap(styles, paths=None):
943 def stylemap(styles, paths=None):
944 """Return path to mapfile for a given style.
944 """Return path to mapfile for a given style.
945
945
946 Searches mapfile in the following locations:
946 Searches mapfile in the following locations:
947 1. templatepath/style/map
947 1. templatepath/style/map
948 2. templatepath/map-style
948 2. templatepath/map-style
949 3. templatepath/map
949 3. templatepath/map
950 """
950 """
951
951
952 if paths is None:
952 if paths is None:
953 paths = templatepaths()
953 paths = templatepaths()
954 elif isinstance(paths, str):
954 elif isinstance(paths, str):
955 paths = [paths]
955 paths = [paths]
956
956
957 if isinstance(styles, str):
957 if isinstance(styles, str):
958 styles = [styles]
958 styles = [styles]
959
959
960 for style in styles:
960 for style in styles:
961 # only plain name is allowed to honor template paths
961 # only plain name is allowed to honor template paths
962 if (not style
962 if (not style
963 or style in (os.curdir, os.pardir)
963 or style in (os.curdir, os.pardir)
964 or os.sep in style
964 or os.sep in style
965 or os.altsep and os.altsep in style):
965 or os.altsep and os.altsep in style):
966 continue
966 continue
967 locations = [os.path.join(style, 'map'), 'map-' + style]
967 locations = [os.path.join(style, 'map'), 'map-' + style]
968 locations.append('map')
968 locations.append('map')
969
969
970 for path in paths:
970 for path in paths:
971 for location in locations:
971 for location in locations:
972 mapfile = os.path.join(path, location)
972 mapfile = os.path.join(path, location)
973 if os.path.isfile(mapfile):
973 if os.path.isfile(mapfile):
974 return style, mapfile
974 return style, mapfile
975
975
976 raise RuntimeError("No hgweb templates found in %r" % paths)
976 raise RuntimeError("No hgweb templates found in %r" % paths)
977
977
978 # tell hggettext to extract docstrings from these functions:
978 # tell hggettext to extract docstrings from these functions:
979 i18nfunctions = funcs.values()
979 i18nfunctions = funcs.values()
@@ -1,3476 +1,3481 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Second branch starting at nullrev:
32 Second branch starting at nullrev:
33
33
34 $ hg update null
34 $ hg update null
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
36 $ echo second > second
36 $ echo second > second
37 $ hg add second
37 $ hg add second
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
39 created new head
39 created new head
40
40
41 $ echo third > third
41 $ echo third > third
42 $ hg add third
42 $ hg add third
43 $ hg mv second fourth
43 $ hg mv second fourth
44 $ hg commit -m third -d "2020-01-01 10:01"
44 $ hg commit -m third -d "2020-01-01 10:01"
45
45
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
47 fourth (second)
47 fourth (second)
48 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
48 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
49 second -> fourth
49 second -> fourth
50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
51 8 t
51 8 t
52 7 f
52 7 f
53
53
54 Working-directory revision has special identifiers, though they are still
54 Working-directory revision has special identifiers, though they are still
55 experimental:
55 experimental:
56
56
57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
58 2147483647:ffffffffffffffffffffffffffffffffffffffff
58 2147483647:ffffffffffffffffffffffffffffffffffffffff
59
59
60 Some keywords are invalid for working-directory revision, but they should
60 Some keywords are invalid for working-directory revision, but they should
61 never cause crash:
61 never cause crash:
62
62
63 $ hg log -r 'wdir()' -T '{manifest}\n'
63 $ hg log -r 'wdir()' -T '{manifest}\n'
64
64
65
65
66 Quoting for ui.logtemplate
66 Quoting for ui.logtemplate
67
67
68 $ hg tip --config "ui.logtemplate={rev}\n"
68 $ hg tip --config "ui.logtemplate={rev}\n"
69 8
69 8
70 $ hg tip --config "ui.logtemplate='{rev}\n'"
70 $ hg tip --config "ui.logtemplate='{rev}\n'"
71 8
71 8
72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
73 8
73 8
74
74
75 Make sure user/global hgrc does not affect tests
75 Make sure user/global hgrc does not affect tests
76
76
77 $ echo '[ui]' > .hg/hgrc
77 $ echo '[ui]' > .hg/hgrc
78 $ echo 'logtemplate =' >> .hg/hgrc
78 $ echo 'logtemplate =' >> .hg/hgrc
79 $ echo 'style =' >> .hg/hgrc
79 $ echo 'style =' >> .hg/hgrc
80
80
81 Add some simple styles to settings
81 Add some simple styles to settings
82
82
83 $ echo '[templates]' >> .hg/hgrc
83 $ echo '[templates]' >> .hg/hgrc
84 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
84 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
85 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
85 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
86
86
87 $ hg log -l1 -Tsimple
87 $ hg log -l1 -Tsimple
88 8
88 8
89 $ hg log -l1 -Tsimple2
89 $ hg log -l1 -Tsimple2
90 8
90 8
91
91
92 Test templates and style maps in files:
92 Test templates and style maps in files:
93
93
94 $ echo "{rev}" > tmpl
94 $ echo "{rev}" > tmpl
95 $ hg log -l1 -T./tmpl
95 $ hg log -l1 -T./tmpl
96 8
96 8
97 $ hg log -l1 -Tblah/blah
97 $ hg log -l1 -Tblah/blah
98 blah/blah (no-eol)
98 blah/blah (no-eol)
99
99
100 $ printf 'changeset = "{rev}\\n"\n' > map-simple
100 $ printf 'changeset = "{rev}\\n"\n' > map-simple
101 $ hg log -l1 -T./map-simple
101 $ hg log -l1 -T./map-simple
102 8
102 8
103
103
104 Template should precede style option
104 Template should precede style option
105
105
106 $ hg log -l1 --style default -T '{rev}\n'
106 $ hg log -l1 --style default -T '{rev}\n'
107 8
107 8
108
108
109 Add a commit with empty description, to ensure that the templates
109 Add a commit with empty description, to ensure that the templates
110 below will omit the description line.
110 below will omit the description line.
111
111
112 $ echo c >> c
112 $ echo c >> c
113 $ hg add c
113 $ hg add c
114 $ hg commit -qm ' '
114 $ hg commit -qm ' '
115
115
116 Default style is like normal output. Phases style should be the same
116 Default style is like normal output. Phases style should be the same
117 as default style, except for extra phase lines.
117 as default style, except for extra phase lines.
118
118
119 $ hg log > log.out
119 $ hg log > log.out
120 $ hg log --style default > style.out
120 $ hg log --style default > style.out
121 $ cmp log.out style.out || diff -u log.out style.out
121 $ cmp log.out style.out || diff -u log.out style.out
122 $ hg log -T phases > phases.out
122 $ hg log -T phases > phases.out
123 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
123 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
124 +phase: draft
124 +phase: draft
125 +phase: draft
125 +phase: draft
126 +phase: draft
126 +phase: draft
127 +phase: draft
127 +phase: draft
128 +phase: draft
128 +phase: draft
129 +phase: draft
129 +phase: draft
130 +phase: draft
130 +phase: draft
131 +phase: draft
131 +phase: draft
132 +phase: draft
132 +phase: draft
133 +phase: draft
133 +phase: draft
134
134
135 $ hg log -v > log.out
135 $ hg log -v > log.out
136 $ hg log -v --style default > style.out
136 $ hg log -v --style default > style.out
137 $ cmp log.out style.out || diff -u log.out style.out
137 $ cmp log.out style.out || diff -u log.out style.out
138 $ hg log -v -T phases > phases.out
138 $ hg log -v -T phases > phases.out
139 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
139 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
140 +phase: draft
140 +phase: draft
141 +phase: draft
141 +phase: draft
142 +phase: draft
142 +phase: draft
143 +phase: draft
143 +phase: draft
144 +phase: draft
144 +phase: draft
145 +phase: draft
145 +phase: draft
146 +phase: draft
146 +phase: draft
147 +phase: draft
147 +phase: draft
148 +phase: draft
148 +phase: draft
149 +phase: draft
149 +phase: draft
150
150
151 $ hg log -q > log.out
151 $ hg log -q > log.out
152 $ hg log -q --style default > style.out
152 $ hg log -q --style default > style.out
153 $ cmp log.out style.out || diff -u log.out style.out
153 $ cmp log.out style.out || diff -u log.out style.out
154 $ hg log -q -T phases > phases.out
154 $ hg log -q -T phases > phases.out
155 $ cmp log.out phases.out || diff -u log.out phases.out
155 $ cmp log.out phases.out || diff -u log.out phases.out
156
156
157 $ hg log --debug > log.out
157 $ hg log --debug > log.out
158 $ hg log --debug --style default > style.out
158 $ hg log --debug --style default > style.out
159 $ cmp log.out style.out || diff -u log.out style.out
159 $ cmp log.out style.out || diff -u log.out style.out
160 $ hg log --debug -T phases > phases.out
160 $ hg log --debug -T phases > phases.out
161 $ cmp log.out phases.out || diff -u log.out phases.out
161 $ cmp log.out phases.out || diff -u log.out phases.out
162
162
163 Default style of working-directory revision should also be the same (but
163 Default style of working-directory revision should also be the same (but
164 date may change while running tests):
164 date may change while running tests):
165
165
166 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
166 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
167 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
167 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
168 $ cmp log.out style.out || diff -u log.out style.out
168 $ cmp log.out style.out || diff -u log.out style.out
169
169
170 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
170 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
171 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
171 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
172 $ cmp log.out style.out || diff -u log.out style.out
172 $ cmp log.out style.out || diff -u log.out style.out
173
173
174 $ hg log -r 'wdir()' -q > log.out
174 $ hg log -r 'wdir()' -q > log.out
175 $ hg log -r 'wdir()' -q --style default > style.out
175 $ hg log -r 'wdir()' -q --style default > style.out
176 $ cmp log.out style.out || diff -u log.out style.out
176 $ cmp log.out style.out || diff -u log.out style.out
177
177
178 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
178 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
179 $ hg log -r 'wdir()' --debug --style default \
179 $ hg log -r 'wdir()' --debug --style default \
180 > | sed 's|^date:.*|date:|' > style.out
180 > | sed 's|^date:.*|date:|' > style.out
181 $ cmp log.out style.out || diff -u log.out style.out
181 $ cmp log.out style.out || diff -u log.out style.out
182
182
183 Default style should also preserve color information (issue2866):
183 Default style should also preserve color information (issue2866):
184
184
185 $ cp $HGRCPATH $HGRCPATH-bak
185 $ cp $HGRCPATH $HGRCPATH-bak
186 $ cat <<EOF >> $HGRCPATH
186 $ cat <<EOF >> $HGRCPATH
187 > [extensions]
187 > [extensions]
188 > color=
188 > color=
189 > EOF
189 > EOF
190
190
191 $ hg --color=debug log > log.out
191 $ hg --color=debug log > log.out
192 $ hg --color=debug log --style default > style.out
192 $ hg --color=debug log --style default > style.out
193 $ cmp log.out style.out || diff -u log.out style.out
193 $ cmp log.out style.out || diff -u log.out style.out
194 $ hg --color=debug log -T phases > phases.out
194 $ hg --color=debug log -T phases > phases.out
195 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
195 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
196 +[log.phase|phase: draft]
196 +[log.phase|phase: draft]
197 +[log.phase|phase: draft]
197 +[log.phase|phase: draft]
198 +[log.phase|phase: draft]
198 +[log.phase|phase: draft]
199 +[log.phase|phase: draft]
199 +[log.phase|phase: draft]
200 +[log.phase|phase: draft]
200 +[log.phase|phase: draft]
201 +[log.phase|phase: draft]
201 +[log.phase|phase: draft]
202 +[log.phase|phase: draft]
202 +[log.phase|phase: draft]
203 +[log.phase|phase: draft]
203 +[log.phase|phase: draft]
204 +[log.phase|phase: draft]
204 +[log.phase|phase: draft]
205 +[log.phase|phase: draft]
205 +[log.phase|phase: draft]
206
206
207 $ hg --color=debug -v log > log.out
207 $ hg --color=debug -v log > log.out
208 $ hg --color=debug -v log --style default > style.out
208 $ hg --color=debug -v log --style default > style.out
209 $ cmp log.out style.out || diff -u log.out style.out
209 $ cmp log.out style.out || diff -u log.out style.out
210 $ hg --color=debug -v log -T phases > phases.out
210 $ hg --color=debug -v log -T phases > phases.out
211 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
211 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
212 +[log.phase|phase: draft]
212 +[log.phase|phase: draft]
213 +[log.phase|phase: draft]
213 +[log.phase|phase: draft]
214 +[log.phase|phase: draft]
214 +[log.phase|phase: draft]
215 +[log.phase|phase: draft]
215 +[log.phase|phase: draft]
216 +[log.phase|phase: draft]
216 +[log.phase|phase: draft]
217 +[log.phase|phase: draft]
217 +[log.phase|phase: draft]
218 +[log.phase|phase: draft]
218 +[log.phase|phase: draft]
219 +[log.phase|phase: draft]
219 +[log.phase|phase: draft]
220 +[log.phase|phase: draft]
220 +[log.phase|phase: draft]
221 +[log.phase|phase: draft]
221 +[log.phase|phase: draft]
222
222
223 $ hg --color=debug -q log > log.out
223 $ hg --color=debug -q log > log.out
224 $ hg --color=debug -q log --style default > style.out
224 $ hg --color=debug -q log --style default > style.out
225 $ cmp log.out style.out || diff -u log.out style.out
225 $ cmp log.out style.out || diff -u log.out style.out
226 $ hg --color=debug -q log -T phases > phases.out
226 $ hg --color=debug -q log -T phases > phases.out
227 $ cmp log.out phases.out || diff -u log.out phases.out
227 $ cmp log.out phases.out || diff -u log.out phases.out
228
228
229 $ hg --color=debug --debug log > log.out
229 $ hg --color=debug --debug log > log.out
230 $ hg --color=debug --debug log --style default > style.out
230 $ hg --color=debug --debug log --style default > style.out
231 $ cmp log.out style.out || diff -u log.out style.out
231 $ cmp log.out style.out || diff -u log.out style.out
232 $ hg --color=debug --debug log -T phases > phases.out
232 $ hg --color=debug --debug log -T phases > phases.out
233 $ cmp log.out phases.out || diff -u log.out phases.out
233 $ cmp log.out phases.out || diff -u log.out phases.out
234
234
235 $ mv $HGRCPATH-bak $HGRCPATH
235 $ mv $HGRCPATH-bak $HGRCPATH
236
236
237 Remove commit with empty commit message, so as to not pollute further
237 Remove commit with empty commit message, so as to not pollute further
238 tests.
238 tests.
239
239
240 $ hg --config extensions.strip= strip -q .
240 $ hg --config extensions.strip= strip -q .
241
241
242 Revision with no copies (used to print a traceback):
242 Revision with no copies (used to print a traceback):
243
243
244 $ hg tip -v --template '\n'
244 $ hg tip -v --template '\n'
245
245
246
246
247 Compact style works:
247 Compact style works:
248
248
249 $ hg log -Tcompact
249 $ hg log -Tcompact
250 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
250 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
251 third
251 third
252
252
253 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
253 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
254 second
254 second
255
255
256 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
256 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
257 merge
257 merge
258
258
259 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
259 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
260 new head
260 new head
261
261
262 4 bbe44766e73d 1970-01-17 04:53 +0000 person
262 4 bbe44766e73d 1970-01-17 04:53 +0000 person
263 new branch
263 new branch
264
264
265 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
265 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
266 no user, no domain
266 no user, no domain
267
267
268 2 97054abb4ab8 1970-01-14 21:20 +0000 other
268 2 97054abb4ab8 1970-01-14 21:20 +0000 other
269 no person
269 no person
270
270
271 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
271 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
272 other 1
272 other 1
273
273
274 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
274 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
275 line 1
275 line 1
276
276
277
277
278 $ hg log -v --style compact
278 $ hg log -v --style compact
279 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
279 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
280 third
280 third
281
281
282 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
282 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
283 second
283 second
284
284
285 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
285 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
286 merge
286 merge
287
287
288 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
288 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
289 new head
289 new head
290
290
291 4 bbe44766e73d 1970-01-17 04:53 +0000 person
291 4 bbe44766e73d 1970-01-17 04:53 +0000 person
292 new branch
292 new branch
293
293
294 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
294 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
295 no user, no domain
295 no user, no domain
296
296
297 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
297 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
298 no person
298 no person
299
299
300 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
300 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
301 other 1
301 other 1
302 other 2
302 other 2
303
303
304 other 3
304 other 3
305
305
306 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
306 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
307 line 1
307 line 1
308 line 2
308 line 2
309
309
310
310
311 $ hg log --debug --style compact
311 $ hg log --debug --style compact
312 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
312 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
313 third
313 third
314
314
315 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
315 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
316 second
316 second
317
317
318 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
318 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
319 merge
319 merge
320
320
321 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
321 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
322 new head
322 new head
323
323
324 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
324 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
325 new branch
325 new branch
326
326
327 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
327 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
328 no user, no domain
328 no user, no domain
329
329
330 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
330 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
331 no person
331 no person
332
332
333 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
333 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
334 other 1
334 other 1
335 other 2
335 other 2
336
336
337 other 3
337 other 3
338
338
339 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
339 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
340 line 1
340 line 1
341 line 2
341 line 2
342
342
343
343
344 Test xml styles:
344 Test xml styles:
345
345
346 $ hg log --style xml -r 'not all()'
346 $ hg log --style xml -r 'not all()'
347 <?xml version="1.0"?>
347 <?xml version="1.0"?>
348 <log>
348 <log>
349 </log>
349 </log>
350
350
351 $ hg log --style xml
351 $ hg log --style xml
352 <?xml version="1.0"?>
352 <?xml version="1.0"?>
353 <log>
353 <log>
354 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
354 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
355 <tag>tip</tag>
355 <tag>tip</tag>
356 <author email="test">test</author>
356 <author email="test">test</author>
357 <date>2020-01-01T10:01:00+00:00</date>
357 <date>2020-01-01T10:01:00+00:00</date>
358 <msg xml:space="preserve">third</msg>
358 <msg xml:space="preserve">third</msg>
359 </logentry>
359 </logentry>
360 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
360 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
361 <parent revision="-1" node="0000000000000000000000000000000000000000" />
361 <parent revision="-1" node="0000000000000000000000000000000000000000" />
362 <author email="user@hostname">User Name</author>
362 <author email="user@hostname">User Name</author>
363 <date>1970-01-12T13:46:40+00:00</date>
363 <date>1970-01-12T13:46:40+00:00</date>
364 <msg xml:space="preserve">second</msg>
364 <msg xml:space="preserve">second</msg>
365 </logentry>
365 </logentry>
366 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
366 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
367 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
367 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
368 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
368 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
369 <author email="person">person</author>
369 <author email="person">person</author>
370 <date>1970-01-18T08:40:01+00:00</date>
370 <date>1970-01-18T08:40:01+00:00</date>
371 <msg xml:space="preserve">merge</msg>
371 <msg xml:space="preserve">merge</msg>
372 </logentry>
372 </logentry>
373 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
373 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
374 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
374 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
375 <author email="person">person</author>
375 <author email="person">person</author>
376 <date>1970-01-18T08:40:00+00:00</date>
376 <date>1970-01-18T08:40:00+00:00</date>
377 <msg xml:space="preserve">new head</msg>
377 <msg xml:space="preserve">new head</msg>
378 </logentry>
378 </logentry>
379 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
379 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
380 <branch>foo</branch>
380 <branch>foo</branch>
381 <author email="person">person</author>
381 <author email="person">person</author>
382 <date>1970-01-17T04:53:20+00:00</date>
382 <date>1970-01-17T04:53:20+00:00</date>
383 <msg xml:space="preserve">new branch</msg>
383 <msg xml:space="preserve">new branch</msg>
384 </logentry>
384 </logentry>
385 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
385 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
386 <author email="person">person</author>
386 <author email="person">person</author>
387 <date>1970-01-16T01:06:40+00:00</date>
387 <date>1970-01-16T01:06:40+00:00</date>
388 <msg xml:space="preserve">no user, no domain</msg>
388 <msg xml:space="preserve">no user, no domain</msg>
389 </logentry>
389 </logentry>
390 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
390 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
391 <author email="other@place">other</author>
391 <author email="other@place">other</author>
392 <date>1970-01-14T21:20:00+00:00</date>
392 <date>1970-01-14T21:20:00+00:00</date>
393 <msg xml:space="preserve">no person</msg>
393 <msg xml:space="preserve">no person</msg>
394 </logentry>
394 </logentry>
395 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
395 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
396 <author email="other@place">A. N. Other</author>
396 <author email="other@place">A. N. Other</author>
397 <date>1970-01-13T17:33:20+00:00</date>
397 <date>1970-01-13T17:33:20+00:00</date>
398 <msg xml:space="preserve">other 1
398 <msg xml:space="preserve">other 1
399 other 2
399 other 2
400
400
401 other 3</msg>
401 other 3</msg>
402 </logentry>
402 </logentry>
403 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
403 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
404 <author email="user@hostname">User Name</author>
404 <author email="user@hostname">User Name</author>
405 <date>1970-01-12T13:46:40+00:00</date>
405 <date>1970-01-12T13:46:40+00:00</date>
406 <msg xml:space="preserve">line 1
406 <msg xml:space="preserve">line 1
407 line 2</msg>
407 line 2</msg>
408 </logentry>
408 </logentry>
409 </log>
409 </log>
410
410
411 $ hg log -v --style xml
411 $ hg log -v --style xml
412 <?xml version="1.0"?>
412 <?xml version="1.0"?>
413 <log>
413 <log>
414 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
414 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
415 <tag>tip</tag>
415 <tag>tip</tag>
416 <author email="test">test</author>
416 <author email="test">test</author>
417 <date>2020-01-01T10:01:00+00:00</date>
417 <date>2020-01-01T10:01:00+00:00</date>
418 <msg xml:space="preserve">third</msg>
418 <msg xml:space="preserve">third</msg>
419 <paths>
419 <paths>
420 <path action="A">fourth</path>
420 <path action="A">fourth</path>
421 <path action="A">third</path>
421 <path action="A">third</path>
422 <path action="R">second</path>
422 <path action="R">second</path>
423 </paths>
423 </paths>
424 <copies>
424 <copies>
425 <copy source="second">fourth</copy>
425 <copy source="second">fourth</copy>
426 </copies>
426 </copies>
427 </logentry>
427 </logentry>
428 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
428 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
429 <parent revision="-1" node="0000000000000000000000000000000000000000" />
429 <parent revision="-1" node="0000000000000000000000000000000000000000" />
430 <author email="user@hostname">User Name</author>
430 <author email="user@hostname">User Name</author>
431 <date>1970-01-12T13:46:40+00:00</date>
431 <date>1970-01-12T13:46:40+00:00</date>
432 <msg xml:space="preserve">second</msg>
432 <msg xml:space="preserve">second</msg>
433 <paths>
433 <paths>
434 <path action="A">second</path>
434 <path action="A">second</path>
435 </paths>
435 </paths>
436 </logentry>
436 </logentry>
437 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
437 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
438 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
438 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
439 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
439 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
440 <author email="person">person</author>
440 <author email="person">person</author>
441 <date>1970-01-18T08:40:01+00:00</date>
441 <date>1970-01-18T08:40:01+00:00</date>
442 <msg xml:space="preserve">merge</msg>
442 <msg xml:space="preserve">merge</msg>
443 <paths>
443 <paths>
444 </paths>
444 </paths>
445 </logentry>
445 </logentry>
446 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
446 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
447 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
447 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
448 <author email="person">person</author>
448 <author email="person">person</author>
449 <date>1970-01-18T08:40:00+00:00</date>
449 <date>1970-01-18T08:40:00+00:00</date>
450 <msg xml:space="preserve">new head</msg>
450 <msg xml:space="preserve">new head</msg>
451 <paths>
451 <paths>
452 <path action="A">d</path>
452 <path action="A">d</path>
453 </paths>
453 </paths>
454 </logentry>
454 </logentry>
455 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
455 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
456 <branch>foo</branch>
456 <branch>foo</branch>
457 <author email="person">person</author>
457 <author email="person">person</author>
458 <date>1970-01-17T04:53:20+00:00</date>
458 <date>1970-01-17T04:53:20+00:00</date>
459 <msg xml:space="preserve">new branch</msg>
459 <msg xml:space="preserve">new branch</msg>
460 <paths>
460 <paths>
461 </paths>
461 </paths>
462 </logentry>
462 </logentry>
463 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
463 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
464 <author email="person">person</author>
464 <author email="person">person</author>
465 <date>1970-01-16T01:06:40+00:00</date>
465 <date>1970-01-16T01:06:40+00:00</date>
466 <msg xml:space="preserve">no user, no domain</msg>
466 <msg xml:space="preserve">no user, no domain</msg>
467 <paths>
467 <paths>
468 <path action="M">c</path>
468 <path action="M">c</path>
469 </paths>
469 </paths>
470 </logentry>
470 </logentry>
471 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
471 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
472 <author email="other@place">other</author>
472 <author email="other@place">other</author>
473 <date>1970-01-14T21:20:00+00:00</date>
473 <date>1970-01-14T21:20:00+00:00</date>
474 <msg xml:space="preserve">no person</msg>
474 <msg xml:space="preserve">no person</msg>
475 <paths>
475 <paths>
476 <path action="A">c</path>
476 <path action="A">c</path>
477 </paths>
477 </paths>
478 </logentry>
478 </logentry>
479 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
479 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
480 <author email="other@place">A. N. Other</author>
480 <author email="other@place">A. N. Other</author>
481 <date>1970-01-13T17:33:20+00:00</date>
481 <date>1970-01-13T17:33:20+00:00</date>
482 <msg xml:space="preserve">other 1
482 <msg xml:space="preserve">other 1
483 other 2
483 other 2
484
484
485 other 3</msg>
485 other 3</msg>
486 <paths>
486 <paths>
487 <path action="A">b</path>
487 <path action="A">b</path>
488 </paths>
488 </paths>
489 </logentry>
489 </logentry>
490 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
490 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
491 <author email="user@hostname">User Name</author>
491 <author email="user@hostname">User Name</author>
492 <date>1970-01-12T13:46:40+00:00</date>
492 <date>1970-01-12T13:46:40+00:00</date>
493 <msg xml:space="preserve">line 1
493 <msg xml:space="preserve">line 1
494 line 2</msg>
494 line 2</msg>
495 <paths>
495 <paths>
496 <path action="A">a</path>
496 <path action="A">a</path>
497 </paths>
497 </paths>
498 </logentry>
498 </logentry>
499 </log>
499 </log>
500
500
501 $ hg log --debug --style xml
501 $ hg log --debug --style xml
502 <?xml version="1.0"?>
502 <?xml version="1.0"?>
503 <log>
503 <log>
504 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
504 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
505 <tag>tip</tag>
505 <tag>tip</tag>
506 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
506 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
507 <parent revision="-1" node="0000000000000000000000000000000000000000" />
507 <parent revision="-1" node="0000000000000000000000000000000000000000" />
508 <author email="test">test</author>
508 <author email="test">test</author>
509 <date>2020-01-01T10:01:00+00:00</date>
509 <date>2020-01-01T10:01:00+00:00</date>
510 <msg xml:space="preserve">third</msg>
510 <msg xml:space="preserve">third</msg>
511 <paths>
511 <paths>
512 <path action="A">fourth</path>
512 <path action="A">fourth</path>
513 <path action="A">third</path>
513 <path action="A">third</path>
514 <path action="R">second</path>
514 <path action="R">second</path>
515 </paths>
515 </paths>
516 <copies>
516 <copies>
517 <copy source="second">fourth</copy>
517 <copy source="second">fourth</copy>
518 </copies>
518 </copies>
519 <extra key="branch">default</extra>
519 <extra key="branch">default</extra>
520 </logentry>
520 </logentry>
521 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
521 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
522 <parent revision="-1" node="0000000000000000000000000000000000000000" />
522 <parent revision="-1" node="0000000000000000000000000000000000000000" />
523 <parent revision="-1" node="0000000000000000000000000000000000000000" />
523 <parent revision="-1" node="0000000000000000000000000000000000000000" />
524 <author email="user@hostname">User Name</author>
524 <author email="user@hostname">User Name</author>
525 <date>1970-01-12T13:46:40+00:00</date>
525 <date>1970-01-12T13:46:40+00:00</date>
526 <msg xml:space="preserve">second</msg>
526 <msg xml:space="preserve">second</msg>
527 <paths>
527 <paths>
528 <path action="A">second</path>
528 <path action="A">second</path>
529 </paths>
529 </paths>
530 <extra key="branch">default</extra>
530 <extra key="branch">default</extra>
531 </logentry>
531 </logentry>
532 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
532 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
533 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
533 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
534 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
534 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
535 <author email="person">person</author>
535 <author email="person">person</author>
536 <date>1970-01-18T08:40:01+00:00</date>
536 <date>1970-01-18T08:40:01+00:00</date>
537 <msg xml:space="preserve">merge</msg>
537 <msg xml:space="preserve">merge</msg>
538 <paths>
538 <paths>
539 </paths>
539 </paths>
540 <extra key="branch">default</extra>
540 <extra key="branch">default</extra>
541 </logentry>
541 </logentry>
542 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
542 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
543 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
543 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
544 <parent revision="-1" node="0000000000000000000000000000000000000000" />
544 <parent revision="-1" node="0000000000000000000000000000000000000000" />
545 <author email="person">person</author>
545 <author email="person">person</author>
546 <date>1970-01-18T08:40:00+00:00</date>
546 <date>1970-01-18T08:40:00+00:00</date>
547 <msg xml:space="preserve">new head</msg>
547 <msg xml:space="preserve">new head</msg>
548 <paths>
548 <paths>
549 <path action="A">d</path>
549 <path action="A">d</path>
550 </paths>
550 </paths>
551 <extra key="branch">default</extra>
551 <extra key="branch">default</extra>
552 </logentry>
552 </logentry>
553 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
553 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
554 <branch>foo</branch>
554 <branch>foo</branch>
555 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
555 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
556 <parent revision="-1" node="0000000000000000000000000000000000000000" />
556 <parent revision="-1" node="0000000000000000000000000000000000000000" />
557 <author email="person">person</author>
557 <author email="person">person</author>
558 <date>1970-01-17T04:53:20+00:00</date>
558 <date>1970-01-17T04:53:20+00:00</date>
559 <msg xml:space="preserve">new branch</msg>
559 <msg xml:space="preserve">new branch</msg>
560 <paths>
560 <paths>
561 </paths>
561 </paths>
562 <extra key="branch">foo</extra>
562 <extra key="branch">foo</extra>
563 </logentry>
563 </logentry>
564 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
564 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
565 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
565 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
566 <parent revision="-1" node="0000000000000000000000000000000000000000" />
566 <parent revision="-1" node="0000000000000000000000000000000000000000" />
567 <author email="person">person</author>
567 <author email="person">person</author>
568 <date>1970-01-16T01:06:40+00:00</date>
568 <date>1970-01-16T01:06:40+00:00</date>
569 <msg xml:space="preserve">no user, no domain</msg>
569 <msg xml:space="preserve">no user, no domain</msg>
570 <paths>
570 <paths>
571 <path action="M">c</path>
571 <path action="M">c</path>
572 </paths>
572 </paths>
573 <extra key="branch">default</extra>
573 <extra key="branch">default</extra>
574 </logentry>
574 </logentry>
575 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
575 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
576 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
576 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
577 <parent revision="-1" node="0000000000000000000000000000000000000000" />
577 <parent revision="-1" node="0000000000000000000000000000000000000000" />
578 <author email="other@place">other</author>
578 <author email="other@place">other</author>
579 <date>1970-01-14T21:20:00+00:00</date>
579 <date>1970-01-14T21:20:00+00:00</date>
580 <msg xml:space="preserve">no person</msg>
580 <msg xml:space="preserve">no person</msg>
581 <paths>
581 <paths>
582 <path action="A">c</path>
582 <path action="A">c</path>
583 </paths>
583 </paths>
584 <extra key="branch">default</extra>
584 <extra key="branch">default</extra>
585 </logentry>
585 </logentry>
586 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
586 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
587 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
587 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
588 <parent revision="-1" node="0000000000000000000000000000000000000000" />
588 <parent revision="-1" node="0000000000000000000000000000000000000000" />
589 <author email="other@place">A. N. Other</author>
589 <author email="other@place">A. N. Other</author>
590 <date>1970-01-13T17:33:20+00:00</date>
590 <date>1970-01-13T17:33:20+00:00</date>
591 <msg xml:space="preserve">other 1
591 <msg xml:space="preserve">other 1
592 other 2
592 other 2
593
593
594 other 3</msg>
594 other 3</msg>
595 <paths>
595 <paths>
596 <path action="A">b</path>
596 <path action="A">b</path>
597 </paths>
597 </paths>
598 <extra key="branch">default</extra>
598 <extra key="branch">default</extra>
599 </logentry>
599 </logentry>
600 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
600 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
602 <parent revision="-1" node="0000000000000000000000000000000000000000" />
602 <parent revision="-1" node="0000000000000000000000000000000000000000" />
603 <author email="user@hostname">User Name</author>
603 <author email="user@hostname">User Name</author>
604 <date>1970-01-12T13:46:40+00:00</date>
604 <date>1970-01-12T13:46:40+00:00</date>
605 <msg xml:space="preserve">line 1
605 <msg xml:space="preserve">line 1
606 line 2</msg>
606 line 2</msg>
607 <paths>
607 <paths>
608 <path action="A">a</path>
608 <path action="A">a</path>
609 </paths>
609 </paths>
610 <extra key="branch">default</extra>
610 <extra key="branch">default</extra>
611 </logentry>
611 </logentry>
612 </log>
612 </log>
613
613
614
614
615 Test JSON style:
615 Test JSON style:
616
616
617 $ hg log -k nosuch -Tjson
617 $ hg log -k nosuch -Tjson
618 []
618 []
619
619
620 $ hg log -qr . -Tjson
620 $ hg log -qr . -Tjson
621 [
621 [
622 {
622 {
623 "rev": 8,
623 "rev": 8,
624 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
624 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
625 }
625 }
626 ]
626 ]
627
627
628 $ hg log -vpr . -Tjson --stat
628 $ hg log -vpr . -Tjson --stat
629 [
629 [
630 {
630 {
631 "rev": 8,
631 "rev": 8,
632 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
632 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
633 "branch": "default",
633 "branch": "default",
634 "phase": "draft",
634 "phase": "draft",
635 "user": "test",
635 "user": "test",
636 "date": [1577872860, 0],
636 "date": [1577872860, 0],
637 "desc": "third",
637 "desc": "third",
638 "bookmarks": [],
638 "bookmarks": [],
639 "tags": ["tip"],
639 "tags": ["tip"],
640 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
640 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
641 "files": ["fourth", "second", "third"],
641 "files": ["fourth", "second", "third"],
642 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
642 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
643 "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"
643 "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"
644 }
644 }
645 ]
645 ]
646
646
647 honor --git but not format-breaking diffopts
647 honor --git but not format-breaking diffopts
648 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
648 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
649 [
649 [
650 {
650 {
651 "rev": 8,
651 "rev": 8,
652 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
652 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
653 "branch": "default",
653 "branch": "default",
654 "phase": "draft",
654 "phase": "draft",
655 "user": "test",
655 "user": "test",
656 "date": [1577872860, 0],
656 "date": [1577872860, 0],
657 "desc": "third",
657 "desc": "third",
658 "bookmarks": [],
658 "bookmarks": [],
659 "tags": ["tip"],
659 "tags": ["tip"],
660 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
660 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
661 "files": ["fourth", "second", "third"],
661 "files": ["fourth", "second", "third"],
662 "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"
662 "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"
663 }
663 }
664 ]
664 ]
665
665
666 $ hg log -T json
666 $ hg log -T json
667 [
667 [
668 {
668 {
669 "rev": 8,
669 "rev": 8,
670 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
670 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
671 "branch": "default",
671 "branch": "default",
672 "phase": "draft",
672 "phase": "draft",
673 "user": "test",
673 "user": "test",
674 "date": [1577872860, 0],
674 "date": [1577872860, 0],
675 "desc": "third",
675 "desc": "third",
676 "bookmarks": [],
676 "bookmarks": [],
677 "tags": ["tip"],
677 "tags": ["tip"],
678 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
678 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
679 },
679 },
680 {
680 {
681 "rev": 7,
681 "rev": 7,
682 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
682 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
683 "branch": "default",
683 "branch": "default",
684 "phase": "draft",
684 "phase": "draft",
685 "user": "User Name <user@hostname>",
685 "user": "User Name <user@hostname>",
686 "date": [1000000, 0],
686 "date": [1000000, 0],
687 "desc": "second",
687 "desc": "second",
688 "bookmarks": [],
688 "bookmarks": [],
689 "tags": [],
689 "tags": [],
690 "parents": ["0000000000000000000000000000000000000000"]
690 "parents": ["0000000000000000000000000000000000000000"]
691 },
691 },
692 {
692 {
693 "rev": 6,
693 "rev": 6,
694 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
694 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
695 "branch": "default",
695 "branch": "default",
696 "phase": "draft",
696 "phase": "draft",
697 "user": "person",
697 "user": "person",
698 "date": [1500001, 0],
698 "date": [1500001, 0],
699 "desc": "merge",
699 "desc": "merge",
700 "bookmarks": [],
700 "bookmarks": [],
701 "tags": [],
701 "tags": [],
702 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
702 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
703 },
703 },
704 {
704 {
705 "rev": 5,
705 "rev": 5,
706 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
706 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
707 "branch": "default",
707 "branch": "default",
708 "phase": "draft",
708 "phase": "draft",
709 "user": "person",
709 "user": "person",
710 "date": [1500000, 0],
710 "date": [1500000, 0],
711 "desc": "new head",
711 "desc": "new head",
712 "bookmarks": [],
712 "bookmarks": [],
713 "tags": [],
713 "tags": [],
714 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
714 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
715 },
715 },
716 {
716 {
717 "rev": 4,
717 "rev": 4,
718 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
718 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
719 "branch": "foo",
719 "branch": "foo",
720 "phase": "draft",
720 "phase": "draft",
721 "user": "person",
721 "user": "person",
722 "date": [1400000, 0],
722 "date": [1400000, 0],
723 "desc": "new branch",
723 "desc": "new branch",
724 "bookmarks": [],
724 "bookmarks": [],
725 "tags": [],
725 "tags": [],
726 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
726 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
727 },
727 },
728 {
728 {
729 "rev": 3,
729 "rev": 3,
730 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
730 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
731 "branch": "default",
731 "branch": "default",
732 "phase": "draft",
732 "phase": "draft",
733 "user": "person",
733 "user": "person",
734 "date": [1300000, 0],
734 "date": [1300000, 0],
735 "desc": "no user, no domain",
735 "desc": "no user, no domain",
736 "bookmarks": [],
736 "bookmarks": [],
737 "tags": [],
737 "tags": [],
738 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
738 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
739 },
739 },
740 {
740 {
741 "rev": 2,
741 "rev": 2,
742 "node": "97054abb4ab824450e9164180baf491ae0078465",
742 "node": "97054abb4ab824450e9164180baf491ae0078465",
743 "branch": "default",
743 "branch": "default",
744 "phase": "draft",
744 "phase": "draft",
745 "user": "other@place",
745 "user": "other@place",
746 "date": [1200000, 0],
746 "date": [1200000, 0],
747 "desc": "no person",
747 "desc": "no person",
748 "bookmarks": [],
748 "bookmarks": [],
749 "tags": [],
749 "tags": [],
750 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
750 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
751 },
751 },
752 {
752 {
753 "rev": 1,
753 "rev": 1,
754 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
754 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
755 "branch": "default",
755 "branch": "default",
756 "phase": "draft",
756 "phase": "draft",
757 "user": "A. N. Other <other@place>",
757 "user": "A. N. Other <other@place>",
758 "date": [1100000, 0],
758 "date": [1100000, 0],
759 "desc": "other 1\nother 2\n\nother 3",
759 "desc": "other 1\nother 2\n\nother 3",
760 "bookmarks": [],
760 "bookmarks": [],
761 "tags": [],
761 "tags": [],
762 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
762 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
763 },
763 },
764 {
764 {
765 "rev": 0,
765 "rev": 0,
766 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
766 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
767 "branch": "default",
767 "branch": "default",
768 "phase": "draft",
768 "phase": "draft",
769 "user": "User Name <user@hostname>",
769 "user": "User Name <user@hostname>",
770 "date": [1000000, 0],
770 "date": [1000000, 0],
771 "desc": "line 1\nline 2",
771 "desc": "line 1\nline 2",
772 "bookmarks": [],
772 "bookmarks": [],
773 "tags": [],
773 "tags": [],
774 "parents": ["0000000000000000000000000000000000000000"]
774 "parents": ["0000000000000000000000000000000000000000"]
775 }
775 }
776 ]
776 ]
777
777
778 $ hg heads -v -Tjson
778 $ hg heads -v -Tjson
779 [
779 [
780 {
780 {
781 "rev": 8,
781 "rev": 8,
782 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
782 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
783 "branch": "default",
783 "branch": "default",
784 "phase": "draft",
784 "phase": "draft",
785 "user": "test",
785 "user": "test",
786 "date": [1577872860, 0],
786 "date": [1577872860, 0],
787 "desc": "third",
787 "desc": "third",
788 "bookmarks": [],
788 "bookmarks": [],
789 "tags": ["tip"],
789 "tags": ["tip"],
790 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
790 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
791 "files": ["fourth", "second", "third"]
791 "files": ["fourth", "second", "third"]
792 },
792 },
793 {
793 {
794 "rev": 6,
794 "rev": 6,
795 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
795 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
796 "branch": "default",
796 "branch": "default",
797 "phase": "draft",
797 "phase": "draft",
798 "user": "person",
798 "user": "person",
799 "date": [1500001, 0],
799 "date": [1500001, 0],
800 "desc": "merge",
800 "desc": "merge",
801 "bookmarks": [],
801 "bookmarks": [],
802 "tags": [],
802 "tags": [],
803 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
803 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
804 "files": []
804 "files": []
805 },
805 },
806 {
806 {
807 "rev": 4,
807 "rev": 4,
808 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
808 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
809 "branch": "foo",
809 "branch": "foo",
810 "phase": "draft",
810 "phase": "draft",
811 "user": "person",
811 "user": "person",
812 "date": [1400000, 0],
812 "date": [1400000, 0],
813 "desc": "new branch",
813 "desc": "new branch",
814 "bookmarks": [],
814 "bookmarks": [],
815 "tags": [],
815 "tags": [],
816 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
816 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
817 "files": []
817 "files": []
818 }
818 }
819 ]
819 ]
820
820
821 $ hg log --debug -Tjson
821 $ hg log --debug -Tjson
822 [
822 [
823 {
823 {
824 "rev": 8,
824 "rev": 8,
825 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
825 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
826 "branch": "default",
826 "branch": "default",
827 "phase": "draft",
827 "phase": "draft",
828 "user": "test",
828 "user": "test",
829 "date": [1577872860, 0],
829 "date": [1577872860, 0],
830 "desc": "third",
830 "desc": "third",
831 "bookmarks": [],
831 "bookmarks": [],
832 "tags": ["tip"],
832 "tags": ["tip"],
833 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
833 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
834 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
834 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
835 "extra": {"branch": "default"},
835 "extra": {"branch": "default"},
836 "modified": [],
836 "modified": [],
837 "added": ["fourth", "third"],
837 "added": ["fourth", "third"],
838 "removed": ["second"]
838 "removed": ["second"]
839 },
839 },
840 {
840 {
841 "rev": 7,
841 "rev": 7,
842 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
842 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
843 "branch": "default",
843 "branch": "default",
844 "phase": "draft",
844 "phase": "draft",
845 "user": "User Name <user@hostname>",
845 "user": "User Name <user@hostname>",
846 "date": [1000000, 0],
846 "date": [1000000, 0],
847 "desc": "second",
847 "desc": "second",
848 "bookmarks": [],
848 "bookmarks": [],
849 "tags": [],
849 "tags": [],
850 "parents": ["0000000000000000000000000000000000000000"],
850 "parents": ["0000000000000000000000000000000000000000"],
851 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
851 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
852 "extra": {"branch": "default"},
852 "extra": {"branch": "default"},
853 "modified": [],
853 "modified": [],
854 "added": ["second"],
854 "added": ["second"],
855 "removed": []
855 "removed": []
856 },
856 },
857 {
857 {
858 "rev": 6,
858 "rev": 6,
859 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
859 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
860 "branch": "default",
860 "branch": "default",
861 "phase": "draft",
861 "phase": "draft",
862 "user": "person",
862 "user": "person",
863 "date": [1500001, 0],
863 "date": [1500001, 0],
864 "desc": "merge",
864 "desc": "merge",
865 "bookmarks": [],
865 "bookmarks": [],
866 "tags": [],
866 "tags": [],
867 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
867 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
868 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
868 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
869 "extra": {"branch": "default"},
869 "extra": {"branch": "default"},
870 "modified": [],
870 "modified": [],
871 "added": [],
871 "added": [],
872 "removed": []
872 "removed": []
873 },
873 },
874 {
874 {
875 "rev": 5,
875 "rev": 5,
876 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
876 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
877 "branch": "default",
877 "branch": "default",
878 "phase": "draft",
878 "phase": "draft",
879 "user": "person",
879 "user": "person",
880 "date": [1500000, 0],
880 "date": [1500000, 0],
881 "desc": "new head",
881 "desc": "new head",
882 "bookmarks": [],
882 "bookmarks": [],
883 "tags": [],
883 "tags": [],
884 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
884 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
885 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
885 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
886 "extra": {"branch": "default"},
886 "extra": {"branch": "default"},
887 "modified": [],
887 "modified": [],
888 "added": ["d"],
888 "added": ["d"],
889 "removed": []
889 "removed": []
890 },
890 },
891 {
891 {
892 "rev": 4,
892 "rev": 4,
893 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
893 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
894 "branch": "foo",
894 "branch": "foo",
895 "phase": "draft",
895 "phase": "draft",
896 "user": "person",
896 "user": "person",
897 "date": [1400000, 0],
897 "date": [1400000, 0],
898 "desc": "new branch",
898 "desc": "new branch",
899 "bookmarks": [],
899 "bookmarks": [],
900 "tags": [],
900 "tags": [],
901 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
901 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
902 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
902 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
903 "extra": {"branch": "foo"},
903 "extra": {"branch": "foo"},
904 "modified": [],
904 "modified": [],
905 "added": [],
905 "added": [],
906 "removed": []
906 "removed": []
907 },
907 },
908 {
908 {
909 "rev": 3,
909 "rev": 3,
910 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
910 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
911 "branch": "default",
911 "branch": "default",
912 "phase": "draft",
912 "phase": "draft",
913 "user": "person",
913 "user": "person",
914 "date": [1300000, 0],
914 "date": [1300000, 0],
915 "desc": "no user, no domain",
915 "desc": "no user, no domain",
916 "bookmarks": [],
916 "bookmarks": [],
917 "tags": [],
917 "tags": [],
918 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
918 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
919 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
919 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
920 "extra": {"branch": "default"},
920 "extra": {"branch": "default"},
921 "modified": ["c"],
921 "modified": ["c"],
922 "added": [],
922 "added": [],
923 "removed": []
923 "removed": []
924 },
924 },
925 {
925 {
926 "rev": 2,
926 "rev": 2,
927 "node": "97054abb4ab824450e9164180baf491ae0078465",
927 "node": "97054abb4ab824450e9164180baf491ae0078465",
928 "branch": "default",
928 "branch": "default",
929 "phase": "draft",
929 "phase": "draft",
930 "user": "other@place",
930 "user": "other@place",
931 "date": [1200000, 0],
931 "date": [1200000, 0],
932 "desc": "no person",
932 "desc": "no person",
933 "bookmarks": [],
933 "bookmarks": [],
934 "tags": [],
934 "tags": [],
935 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
935 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
936 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
936 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
937 "extra": {"branch": "default"},
937 "extra": {"branch": "default"},
938 "modified": [],
938 "modified": [],
939 "added": ["c"],
939 "added": ["c"],
940 "removed": []
940 "removed": []
941 },
941 },
942 {
942 {
943 "rev": 1,
943 "rev": 1,
944 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
944 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
945 "branch": "default",
945 "branch": "default",
946 "phase": "draft",
946 "phase": "draft",
947 "user": "A. N. Other <other@place>",
947 "user": "A. N. Other <other@place>",
948 "date": [1100000, 0],
948 "date": [1100000, 0],
949 "desc": "other 1\nother 2\n\nother 3",
949 "desc": "other 1\nother 2\n\nother 3",
950 "bookmarks": [],
950 "bookmarks": [],
951 "tags": [],
951 "tags": [],
952 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
952 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
953 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
953 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
954 "extra": {"branch": "default"},
954 "extra": {"branch": "default"},
955 "modified": [],
955 "modified": [],
956 "added": ["b"],
956 "added": ["b"],
957 "removed": []
957 "removed": []
958 },
958 },
959 {
959 {
960 "rev": 0,
960 "rev": 0,
961 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
961 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
962 "branch": "default",
962 "branch": "default",
963 "phase": "draft",
963 "phase": "draft",
964 "user": "User Name <user@hostname>",
964 "user": "User Name <user@hostname>",
965 "date": [1000000, 0],
965 "date": [1000000, 0],
966 "desc": "line 1\nline 2",
966 "desc": "line 1\nline 2",
967 "bookmarks": [],
967 "bookmarks": [],
968 "tags": [],
968 "tags": [],
969 "parents": ["0000000000000000000000000000000000000000"],
969 "parents": ["0000000000000000000000000000000000000000"],
970 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
970 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
971 "extra": {"branch": "default"},
971 "extra": {"branch": "default"},
972 "modified": [],
972 "modified": [],
973 "added": ["a"],
973 "added": ["a"],
974 "removed": []
974 "removed": []
975 }
975 }
976 ]
976 ]
977
977
978 Error if style not readable:
978 Error if style not readable:
979
979
980 #if unix-permissions no-root
980 #if unix-permissions no-root
981 $ touch q
981 $ touch q
982 $ chmod 0 q
982 $ chmod 0 q
983 $ hg log --style ./q
983 $ hg log --style ./q
984 abort: Permission denied: ./q
984 abort: Permission denied: ./q
985 [255]
985 [255]
986 #endif
986 #endif
987
987
988 Error if no style:
988 Error if no style:
989
989
990 $ hg log --style notexist
990 $ hg log --style notexist
991 abort: style 'notexist' not found
991 abort: style 'notexist' not found
992 (available styles: bisect, changelog, compact, default, phases, status, xml)
992 (available styles: bisect, changelog, compact, default, phases, status, xml)
993 [255]
993 [255]
994
994
995 $ hg log -T list
995 $ hg log -T list
996 available styles: bisect, changelog, compact, default, phases, status, xml
996 available styles: bisect, changelog, compact, default, phases, status, xml
997 abort: specify a template
997 abort: specify a template
998 [255]
998 [255]
999
999
1000 Error if style missing key:
1000 Error if style missing key:
1001
1001
1002 $ echo 'q = q' > t
1002 $ echo 'q = q' > t
1003 $ hg log --style ./t
1003 $ hg log --style ./t
1004 abort: "changeset" not in template map
1004 abort: "changeset" not in template map
1005 [255]
1005 [255]
1006
1006
1007 Error if style missing value:
1007 Error if style missing value:
1008
1008
1009 $ echo 'changeset =' > t
1009 $ echo 'changeset =' > t
1010 $ hg log --style t
1010 $ hg log --style t
1011 abort: t:1: missing value
1011 abort: t:1: missing value
1012 [255]
1012 [255]
1013
1013
1014 Error if include fails:
1014 Error if include fails:
1015
1015
1016 $ echo 'changeset = q' >> t
1016 $ echo 'changeset = q' >> t
1017 #if unix-permissions no-root
1017 #if unix-permissions no-root
1018 $ hg log --style ./t
1018 $ hg log --style ./t
1019 abort: template file ./q: Permission denied
1019 abort: template file ./q: Permission denied
1020 [255]
1020 [255]
1021 $ rm q
1021 $ rm q
1022 #endif
1022 #endif
1023
1023
1024 Include works:
1024 Include works:
1025
1025
1026 $ echo '{rev}' > q
1026 $ echo '{rev}' > q
1027 $ hg log --style ./t
1027 $ hg log --style ./t
1028 8
1028 8
1029 7
1029 7
1030 6
1030 6
1031 5
1031 5
1032 4
1032 4
1033 3
1033 3
1034 2
1034 2
1035 1
1035 1
1036 0
1036 0
1037
1037
1038 Check that {phase} works correctly on parents:
1038 Check that {phase} works correctly on parents:
1039
1039
1040 $ cat << EOF > parentphase
1040 $ cat << EOF > parentphase
1041 > changeset_debug = '{rev} ({phase}):{parents}\n'
1041 > changeset_debug = '{rev} ({phase}):{parents}\n'
1042 > parent = ' {rev} ({phase})'
1042 > parent = ' {rev} ({phase})'
1043 > EOF
1043 > EOF
1044 $ hg phase -r 5 --public
1044 $ hg phase -r 5 --public
1045 $ hg phase -r 7 --secret --force
1045 $ hg phase -r 7 --secret --force
1046 $ hg log --debug -G --style ./parentphase
1046 $ hg log --debug -G --style ./parentphase
1047 @ 8 (secret): 7 (secret) -1 (public)
1047 @ 8 (secret): 7 (secret) -1 (public)
1048 |
1048 |
1049 o 7 (secret): -1 (public) -1 (public)
1049 o 7 (secret): -1 (public) -1 (public)
1050
1050
1051 o 6 (draft): 5 (public) 4 (draft)
1051 o 6 (draft): 5 (public) 4 (draft)
1052 |\
1052 |\
1053 | o 5 (public): 3 (public) -1 (public)
1053 | o 5 (public): 3 (public) -1 (public)
1054 | |
1054 | |
1055 o | 4 (draft): 3 (public) -1 (public)
1055 o | 4 (draft): 3 (public) -1 (public)
1056 |/
1056 |/
1057 o 3 (public): 2 (public) -1 (public)
1057 o 3 (public): 2 (public) -1 (public)
1058 |
1058 |
1059 o 2 (public): 1 (public) -1 (public)
1059 o 2 (public): 1 (public) -1 (public)
1060 |
1060 |
1061 o 1 (public): 0 (public) -1 (public)
1061 o 1 (public): 0 (public) -1 (public)
1062 |
1062 |
1063 o 0 (public): -1 (public) -1 (public)
1063 o 0 (public): -1 (public) -1 (public)
1064
1064
1065
1065
1066 Missing non-standard names give no error (backward compatibility):
1066 Missing non-standard names give no error (backward compatibility):
1067
1067
1068 $ echo "changeset = '{c}'" > t
1068 $ echo "changeset = '{c}'" > t
1069 $ hg log --style ./t
1069 $ hg log --style ./t
1070
1070
1071 Defining non-standard name works:
1071 Defining non-standard name works:
1072
1072
1073 $ cat <<EOF > t
1073 $ cat <<EOF > t
1074 > changeset = '{c}'
1074 > changeset = '{c}'
1075 > c = q
1075 > c = q
1076 > EOF
1076 > EOF
1077 $ hg log --style ./t
1077 $ hg log --style ./t
1078 8
1078 8
1079 7
1079 7
1080 6
1080 6
1081 5
1081 5
1082 4
1082 4
1083 3
1083 3
1084 2
1084 2
1085 1
1085 1
1086 0
1086 0
1087
1087
1088 ui.style works:
1088 ui.style works:
1089
1089
1090 $ echo '[ui]' > .hg/hgrc
1090 $ echo '[ui]' > .hg/hgrc
1091 $ echo 'style = t' >> .hg/hgrc
1091 $ echo 'style = t' >> .hg/hgrc
1092 $ hg log
1092 $ hg log
1093 8
1093 8
1094 7
1094 7
1095 6
1095 6
1096 5
1096 5
1097 4
1097 4
1098 3
1098 3
1099 2
1099 2
1100 1
1100 1
1101 0
1101 0
1102
1102
1103
1103
1104 Issue338:
1104 Issue338:
1105
1105
1106 $ hg log --style=changelog > changelog
1106 $ hg log --style=changelog > changelog
1107
1107
1108 $ cat changelog
1108 $ cat changelog
1109 2020-01-01 test <test>
1109 2020-01-01 test <test>
1110
1110
1111 * fourth, second, third:
1111 * fourth, second, third:
1112 third
1112 third
1113 [95c24699272e] [tip]
1113 [95c24699272e] [tip]
1114
1114
1115 1970-01-12 User Name <user@hostname>
1115 1970-01-12 User Name <user@hostname>
1116
1116
1117 * second:
1117 * second:
1118 second
1118 second
1119 [29114dbae42b]
1119 [29114dbae42b]
1120
1120
1121 1970-01-18 person <person>
1121 1970-01-18 person <person>
1122
1122
1123 * merge
1123 * merge
1124 [d41e714fe50d]
1124 [d41e714fe50d]
1125
1125
1126 * d:
1126 * d:
1127 new head
1127 new head
1128 [13207e5a10d9]
1128 [13207e5a10d9]
1129
1129
1130 1970-01-17 person <person>
1130 1970-01-17 person <person>
1131
1131
1132 * new branch
1132 * new branch
1133 [bbe44766e73d] <foo>
1133 [bbe44766e73d] <foo>
1134
1134
1135 1970-01-16 person <person>
1135 1970-01-16 person <person>
1136
1136
1137 * c:
1137 * c:
1138 no user, no domain
1138 no user, no domain
1139 [10e46f2dcbf4]
1139 [10e46f2dcbf4]
1140
1140
1141 1970-01-14 other <other@place>
1141 1970-01-14 other <other@place>
1142
1142
1143 * c:
1143 * c:
1144 no person
1144 no person
1145 [97054abb4ab8]
1145 [97054abb4ab8]
1146
1146
1147 1970-01-13 A. N. Other <other@place>
1147 1970-01-13 A. N. Other <other@place>
1148
1148
1149 * b:
1149 * b:
1150 other 1 other 2
1150 other 1 other 2
1151
1151
1152 other 3
1152 other 3
1153 [b608e9d1a3f0]
1153 [b608e9d1a3f0]
1154
1154
1155 1970-01-12 User Name <user@hostname>
1155 1970-01-12 User Name <user@hostname>
1156
1156
1157 * a:
1157 * a:
1158 line 1 line 2
1158 line 1 line 2
1159 [1e4e1b8f71e0]
1159 [1e4e1b8f71e0]
1160
1160
1161
1161
1162 Issue2130: xml output for 'hg heads' is malformed
1162 Issue2130: xml output for 'hg heads' is malformed
1163
1163
1164 $ hg heads --style changelog
1164 $ hg heads --style changelog
1165 2020-01-01 test <test>
1165 2020-01-01 test <test>
1166
1166
1167 * fourth, second, third:
1167 * fourth, second, third:
1168 third
1168 third
1169 [95c24699272e] [tip]
1169 [95c24699272e] [tip]
1170
1170
1171 1970-01-18 person <person>
1171 1970-01-18 person <person>
1172
1172
1173 * merge
1173 * merge
1174 [d41e714fe50d]
1174 [d41e714fe50d]
1175
1175
1176 1970-01-17 person <person>
1176 1970-01-17 person <person>
1177
1177
1178 * new branch
1178 * new branch
1179 [bbe44766e73d] <foo>
1179 [bbe44766e73d] <foo>
1180
1180
1181
1181
1182 Keys work:
1182 Keys work:
1183
1183
1184 $ for key in author branch branches date desc file_adds file_dels file_mods \
1184 $ for key in author branch branches date desc file_adds file_dels file_mods \
1185 > file_copies file_copies_switch files \
1185 > file_copies file_copies_switch files \
1186 > manifest node parents rev tags diffstat extras \
1186 > manifest node parents rev tags diffstat extras \
1187 > p1rev p2rev p1node p2node; do
1187 > p1rev p2rev p1node p2node; do
1188 > for mode in '' --verbose --debug; do
1188 > for mode in '' --verbose --debug; do
1189 > hg log $mode --template "$key$mode: {$key}\n"
1189 > hg log $mode --template "$key$mode: {$key}\n"
1190 > done
1190 > done
1191 > done
1191 > done
1192 author: test
1192 author: test
1193 author: User Name <user@hostname>
1193 author: User Name <user@hostname>
1194 author: person
1194 author: person
1195 author: person
1195 author: person
1196 author: person
1196 author: person
1197 author: person
1197 author: person
1198 author: other@place
1198 author: other@place
1199 author: A. N. Other <other@place>
1199 author: A. N. Other <other@place>
1200 author: User Name <user@hostname>
1200 author: User Name <user@hostname>
1201 author--verbose: test
1201 author--verbose: test
1202 author--verbose: User Name <user@hostname>
1202 author--verbose: User Name <user@hostname>
1203 author--verbose: person
1203 author--verbose: person
1204 author--verbose: person
1204 author--verbose: person
1205 author--verbose: person
1205 author--verbose: person
1206 author--verbose: person
1206 author--verbose: person
1207 author--verbose: other@place
1207 author--verbose: other@place
1208 author--verbose: A. N. Other <other@place>
1208 author--verbose: A. N. Other <other@place>
1209 author--verbose: User Name <user@hostname>
1209 author--verbose: User Name <user@hostname>
1210 author--debug: test
1210 author--debug: test
1211 author--debug: User Name <user@hostname>
1211 author--debug: User Name <user@hostname>
1212 author--debug: person
1212 author--debug: person
1213 author--debug: person
1213 author--debug: person
1214 author--debug: person
1214 author--debug: person
1215 author--debug: person
1215 author--debug: person
1216 author--debug: other@place
1216 author--debug: other@place
1217 author--debug: A. N. Other <other@place>
1217 author--debug: A. N. Other <other@place>
1218 author--debug: User Name <user@hostname>
1218 author--debug: User Name <user@hostname>
1219 branch: default
1219 branch: default
1220 branch: default
1220 branch: default
1221 branch: default
1221 branch: default
1222 branch: default
1222 branch: default
1223 branch: foo
1223 branch: foo
1224 branch: default
1224 branch: default
1225 branch: default
1225 branch: default
1226 branch: default
1226 branch: default
1227 branch: default
1227 branch: default
1228 branch--verbose: default
1228 branch--verbose: default
1229 branch--verbose: default
1229 branch--verbose: default
1230 branch--verbose: default
1230 branch--verbose: default
1231 branch--verbose: default
1231 branch--verbose: default
1232 branch--verbose: foo
1232 branch--verbose: foo
1233 branch--verbose: default
1233 branch--verbose: default
1234 branch--verbose: default
1234 branch--verbose: default
1235 branch--verbose: default
1235 branch--verbose: default
1236 branch--verbose: default
1236 branch--verbose: default
1237 branch--debug: default
1237 branch--debug: default
1238 branch--debug: default
1238 branch--debug: default
1239 branch--debug: default
1239 branch--debug: default
1240 branch--debug: default
1240 branch--debug: default
1241 branch--debug: foo
1241 branch--debug: foo
1242 branch--debug: default
1242 branch--debug: default
1243 branch--debug: default
1243 branch--debug: default
1244 branch--debug: default
1244 branch--debug: default
1245 branch--debug: default
1245 branch--debug: default
1246 branches:
1246 branches:
1247 branches:
1247 branches:
1248 branches:
1248 branches:
1249 branches:
1249 branches:
1250 branches: foo
1250 branches: foo
1251 branches:
1251 branches:
1252 branches:
1252 branches:
1253 branches:
1253 branches:
1254 branches:
1254 branches:
1255 branches--verbose:
1255 branches--verbose:
1256 branches--verbose:
1256 branches--verbose:
1257 branches--verbose:
1257 branches--verbose:
1258 branches--verbose:
1258 branches--verbose:
1259 branches--verbose: foo
1259 branches--verbose: foo
1260 branches--verbose:
1260 branches--verbose:
1261 branches--verbose:
1261 branches--verbose:
1262 branches--verbose:
1262 branches--verbose:
1263 branches--verbose:
1263 branches--verbose:
1264 branches--debug:
1264 branches--debug:
1265 branches--debug:
1265 branches--debug:
1266 branches--debug:
1266 branches--debug:
1267 branches--debug:
1267 branches--debug:
1268 branches--debug: foo
1268 branches--debug: foo
1269 branches--debug:
1269 branches--debug:
1270 branches--debug:
1270 branches--debug:
1271 branches--debug:
1271 branches--debug:
1272 branches--debug:
1272 branches--debug:
1273 date: 1577872860.00
1273 date: 1577872860.00
1274 date: 1000000.00
1274 date: 1000000.00
1275 date: 1500001.00
1275 date: 1500001.00
1276 date: 1500000.00
1276 date: 1500000.00
1277 date: 1400000.00
1277 date: 1400000.00
1278 date: 1300000.00
1278 date: 1300000.00
1279 date: 1200000.00
1279 date: 1200000.00
1280 date: 1100000.00
1280 date: 1100000.00
1281 date: 1000000.00
1281 date: 1000000.00
1282 date--verbose: 1577872860.00
1282 date--verbose: 1577872860.00
1283 date--verbose: 1000000.00
1283 date--verbose: 1000000.00
1284 date--verbose: 1500001.00
1284 date--verbose: 1500001.00
1285 date--verbose: 1500000.00
1285 date--verbose: 1500000.00
1286 date--verbose: 1400000.00
1286 date--verbose: 1400000.00
1287 date--verbose: 1300000.00
1287 date--verbose: 1300000.00
1288 date--verbose: 1200000.00
1288 date--verbose: 1200000.00
1289 date--verbose: 1100000.00
1289 date--verbose: 1100000.00
1290 date--verbose: 1000000.00
1290 date--verbose: 1000000.00
1291 date--debug: 1577872860.00
1291 date--debug: 1577872860.00
1292 date--debug: 1000000.00
1292 date--debug: 1000000.00
1293 date--debug: 1500001.00
1293 date--debug: 1500001.00
1294 date--debug: 1500000.00
1294 date--debug: 1500000.00
1295 date--debug: 1400000.00
1295 date--debug: 1400000.00
1296 date--debug: 1300000.00
1296 date--debug: 1300000.00
1297 date--debug: 1200000.00
1297 date--debug: 1200000.00
1298 date--debug: 1100000.00
1298 date--debug: 1100000.00
1299 date--debug: 1000000.00
1299 date--debug: 1000000.00
1300 desc: third
1300 desc: third
1301 desc: second
1301 desc: second
1302 desc: merge
1302 desc: merge
1303 desc: new head
1303 desc: new head
1304 desc: new branch
1304 desc: new branch
1305 desc: no user, no domain
1305 desc: no user, no domain
1306 desc: no person
1306 desc: no person
1307 desc: other 1
1307 desc: other 1
1308 other 2
1308 other 2
1309
1309
1310 other 3
1310 other 3
1311 desc: line 1
1311 desc: line 1
1312 line 2
1312 line 2
1313 desc--verbose: third
1313 desc--verbose: third
1314 desc--verbose: second
1314 desc--verbose: second
1315 desc--verbose: merge
1315 desc--verbose: merge
1316 desc--verbose: new head
1316 desc--verbose: new head
1317 desc--verbose: new branch
1317 desc--verbose: new branch
1318 desc--verbose: no user, no domain
1318 desc--verbose: no user, no domain
1319 desc--verbose: no person
1319 desc--verbose: no person
1320 desc--verbose: other 1
1320 desc--verbose: other 1
1321 other 2
1321 other 2
1322
1322
1323 other 3
1323 other 3
1324 desc--verbose: line 1
1324 desc--verbose: line 1
1325 line 2
1325 line 2
1326 desc--debug: third
1326 desc--debug: third
1327 desc--debug: second
1327 desc--debug: second
1328 desc--debug: merge
1328 desc--debug: merge
1329 desc--debug: new head
1329 desc--debug: new head
1330 desc--debug: new branch
1330 desc--debug: new branch
1331 desc--debug: no user, no domain
1331 desc--debug: no user, no domain
1332 desc--debug: no person
1332 desc--debug: no person
1333 desc--debug: other 1
1333 desc--debug: other 1
1334 other 2
1334 other 2
1335
1335
1336 other 3
1336 other 3
1337 desc--debug: line 1
1337 desc--debug: line 1
1338 line 2
1338 line 2
1339 file_adds: fourth third
1339 file_adds: fourth third
1340 file_adds: second
1340 file_adds: second
1341 file_adds:
1341 file_adds:
1342 file_adds: d
1342 file_adds: d
1343 file_adds:
1343 file_adds:
1344 file_adds:
1344 file_adds:
1345 file_adds: c
1345 file_adds: c
1346 file_adds: b
1346 file_adds: b
1347 file_adds: a
1347 file_adds: a
1348 file_adds--verbose: fourth third
1348 file_adds--verbose: fourth third
1349 file_adds--verbose: second
1349 file_adds--verbose: second
1350 file_adds--verbose:
1350 file_adds--verbose:
1351 file_adds--verbose: d
1351 file_adds--verbose: d
1352 file_adds--verbose:
1352 file_adds--verbose:
1353 file_adds--verbose:
1353 file_adds--verbose:
1354 file_adds--verbose: c
1354 file_adds--verbose: c
1355 file_adds--verbose: b
1355 file_adds--verbose: b
1356 file_adds--verbose: a
1356 file_adds--verbose: a
1357 file_adds--debug: fourth third
1357 file_adds--debug: fourth third
1358 file_adds--debug: second
1358 file_adds--debug: second
1359 file_adds--debug:
1359 file_adds--debug:
1360 file_adds--debug: d
1360 file_adds--debug: d
1361 file_adds--debug:
1361 file_adds--debug:
1362 file_adds--debug:
1362 file_adds--debug:
1363 file_adds--debug: c
1363 file_adds--debug: c
1364 file_adds--debug: b
1364 file_adds--debug: b
1365 file_adds--debug: a
1365 file_adds--debug: a
1366 file_dels: second
1366 file_dels: second
1367 file_dels:
1367 file_dels:
1368 file_dels:
1368 file_dels:
1369 file_dels:
1369 file_dels:
1370 file_dels:
1370 file_dels:
1371 file_dels:
1371 file_dels:
1372 file_dels:
1372 file_dels:
1373 file_dels:
1373 file_dels:
1374 file_dels:
1374 file_dels:
1375 file_dels--verbose: second
1375 file_dels--verbose: second
1376 file_dels--verbose:
1376 file_dels--verbose:
1377 file_dels--verbose:
1377 file_dels--verbose:
1378 file_dels--verbose:
1378 file_dels--verbose:
1379 file_dels--verbose:
1379 file_dels--verbose:
1380 file_dels--verbose:
1380 file_dels--verbose:
1381 file_dels--verbose:
1381 file_dels--verbose:
1382 file_dels--verbose:
1382 file_dels--verbose:
1383 file_dels--verbose:
1383 file_dels--verbose:
1384 file_dels--debug: second
1384 file_dels--debug: second
1385 file_dels--debug:
1385 file_dels--debug:
1386 file_dels--debug:
1386 file_dels--debug:
1387 file_dels--debug:
1387 file_dels--debug:
1388 file_dels--debug:
1388 file_dels--debug:
1389 file_dels--debug:
1389 file_dels--debug:
1390 file_dels--debug:
1390 file_dels--debug:
1391 file_dels--debug:
1391 file_dels--debug:
1392 file_dels--debug:
1392 file_dels--debug:
1393 file_mods:
1393 file_mods:
1394 file_mods:
1394 file_mods:
1395 file_mods:
1395 file_mods:
1396 file_mods:
1396 file_mods:
1397 file_mods:
1397 file_mods:
1398 file_mods: c
1398 file_mods: c
1399 file_mods:
1399 file_mods:
1400 file_mods:
1400 file_mods:
1401 file_mods:
1401 file_mods:
1402 file_mods--verbose:
1402 file_mods--verbose:
1403 file_mods--verbose:
1403 file_mods--verbose:
1404 file_mods--verbose:
1404 file_mods--verbose:
1405 file_mods--verbose:
1405 file_mods--verbose:
1406 file_mods--verbose:
1406 file_mods--verbose:
1407 file_mods--verbose: c
1407 file_mods--verbose: c
1408 file_mods--verbose:
1408 file_mods--verbose:
1409 file_mods--verbose:
1409 file_mods--verbose:
1410 file_mods--verbose:
1410 file_mods--verbose:
1411 file_mods--debug:
1411 file_mods--debug:
1412 file_mods--debug:
1412 file_mods--debug:
1413 file_mods--debug:
1413 file_mods--debug:
1414 file_mods--debug:
1414 file_mods--debug:
1415 file_mods--debug:
1415 file_mods--debug:
1416 file_mods--debug: c
1416 file_mods--debug: c
1417 file_mods--debug:
1417 file_mods--debug:
1418 file_mods--debug:
1418 file_mods--debug:
1419 file_mods--debug:
1419 file_mods--debug:
1420 file_copies: fourth (second)
1420 file_copies: fourth (second)
1421 file_copies:
1421 file_copies:
1422 file_copies:
1422 file_copies:
1423 file_copies:
1423 file_copies:
1424 file_copies:
1424 file_copies:
1425 file_copies:
1425 file_copies:
1426 file_copies:
1426 file_copies:
1427 file_copies:
1427 file_copies:
1428 file_copies:
1428 file_copies:
1429 file_copies--verbose: fourth (second)
1429 file_copies--verbose: fourth (second)
1430 file_copies--verbose:
1430 file_copies--verbose:
1431 file_copies--verbose:
1431 file_copies--verbose:
1432 file_copies--verbose:
1432 file_copies--verbose:
1433 file_copies--verbose:
1433 file_copies--verbose:
1434 file_copies--verbose:
1434 file_copies--verbose:
1435 file_copies--verbose:
1435 file_copies--verbose:
1436 file_copies--verbose:
1436 file_copies--verbose:
1437 file_copies--verbose:
1437 file_copies--verbose:
1438 file_copies--debug: fourth (second)
1438 file_copies--debug: fourth (second)
1439 file_copies--debug:
1439 file_copies--debug:
1440 file_copies--debug:
1440 file_copies--debug:
1441 file_copies--debug:
1441 file_copies--debug:
1442 file_copies--debug:
1442 file_copies--debug:
1443 file_copies--debug:
1443 file_copies--debug:
1444 file_copies--debug:
1444 file_copies--debug:
1445 file_copies--debug:
1445 file_copies--debug:
1446 file_copies--debug:
1446 file_copies--debug:
1447 file_copies_switch:
1447 file_copies_switch:
1448 file_copies_switch:
1448 file_copies_switch:
1449 file_copies_switch:
1449 file_copies_switch:
1450 file_copies_switch:
1450 file_copies_switch:
1451 file_copies_switch:
1451 file_copies_switch:
1452 file_copies_switch:
1452 file_copies_switch:
1453 file_copies_switch:
1453 file_copies_switch:
1454 file_copies_switch:
1454 file_copies_switch:
1455 file_copies_switch:
1455 file_copies_switch:
1456 file_copies_switch--verbose:
1456 file_copies_switch--verbose:
1457 file_copies_switch--verbose:
1457 file_copies_switch--verbose:
1458 file_copies_switch--verbose:
1458 file_copies_switch--verbose:
1459 file_copies_switch--verbose:
1459 file_copies_switch--verbose:
1460 file_copies_switch--verbose:
1460 file_copies_switch--verbose:
1461 file_copies_switch--verbose:
1461 file_copies_switch--verbose:
1462 file_copies_switch--verbose:
1462 file_copies_switch--verbose:
1463 file_copies_switch--verbose:
1463 file_copies_switch--verbose:
1464 file_copies_switch--verbose:
1464 file_copies_switch--verbose:
1465 file_copies_switch--debug:
1465 file_copies_switch--debug:
1466 file_copies_switch--debug:
1466 file_copies_switch--debug:
1467 file_copies_switch--debug:
1467 file_copies_switch--debug:
1468 file_copies_switch--debug:
1468 file_copies_switch--debug:
1469 file_copies_switch--debug:
1469 file_copies_switch--debug:
1470 file_copies_switch--debug:
1470 file_copies_switch--debug:
1471 file_copies_switch--debug:
1471 file_copies_switch--debug:
1472 file_copies_switch--debug:
1472 file_copies_switch--debug:
1473 file_copies_switch--debug:
1473 file_copies_switch--debug:
1474 files: fourth second third
1474 files: fourth second third
1475 files: second
1475 files: second
1476 files:
1476 files:
1477 files: d
1477 files: d
1478 files:
1478 files:
1479 files: c
1479 files: c
1480 files: c
1480 files: c
1481 files: b
1481 files: b
1482 files: a
1482 files: a
1483 files--verbose: fourth second third
1483 files--verbose: fourth second third
1484 files--verbose: second
1484 files--verbose: second
1485 files--verbose:
1485 files--verbose:
1486 files--verbose: d
1486 files--verbose: d
1487 files--verbose:
1487 files--verbose:
1488 files--verbose: c
1488 files--verbose: c
1489 files--verbose: c
1489 files--verbose: c
1490 files--verbose: b
1490 files--verbose: b
1491 files--verbose: a
1491 files--verbose: a
1492 files--debug: fourth second third
1492 files--debug: fourth second third
1493 files--debug: second
1493 files--debug: second
1494 files--debug:
1494 files--debug:
1495 files--debug: d
1495 files--debug: d
1496 files--debug:
1496 files--debug:
1497 files--debug: c
1497 files--debug: c
1498 files--debug: c
1498 files--debug: c
1499 files--debug: b
1499 files--debug: b
1500 files--debug: a
1500 files--debug: a
1501 manifest: 6:94961b75a2da
1501 manifest: 6:94961b75a2da
1502 manifest: 5:f2dbc354b94e
1502 manifest: 5:f2dbc354b94e
1503 manifest: 4:4dc3def4f9b4
1503 manifest: 4:4dc3def4f9b4
1504 manifest: 4:4dc3def4f9b4
1504 manifest: 4:4dc3def4f9b4
1505 manifest: 3:cb5a1327723b
1505 manifest: 3:cb5a1327723b
1506 manifest: 3:cb5a1327723b
1506 manifest: 3:cb5a1327723b
1507 manifest: 2:6e0e82995c35
1507 manifest: 2:6e0e82995c35
1508 manifest: 1:4e8d705b1e53
1508 manifest: 1:4e8d705b1e53
1509 manifest: 0:a0c8bcbbb45c
1509 manifest: 0:a0c8bcbbb45c
1510 manifest--verbose: 6:94961b75a2da
1510 manifest--verbose: 6:94961b75a2da
1511 manifest--verbose: 5:f2dbc354b94e
1511 manifest--verbose: 5:f2dbc354b94e
1512 manifest--verbose: 4:4dc3def4f9b4
1512 manifest--verbose: 4:4dc3def4f9b4
1513 manifest--verbose: 4:4dc3def4f9b4
1513 manifest--verbose: 4:4dc3def4f9b4
1514 manifest--verbose: 3:cb5a1327723b
1514 manifest--verbose: 3:cb5a1327723b
1515 manifest--verbose: 3:cb5a1327723b
1515 manifest--verbose: 3:cb5a1327723b
1516 manifest--verbose: 2:6e0e82995c35
1516 manifest--verbose: 2:6e0e82995c35
1517 manifest--verbose: 1:4e8d705b1e53
1517 manifest--verbose: 1:4e8d705b1e53
1518 manifest--verbose: 0:a0c8bcbbb45c
1518 manifest--verbose: 0:a0c8bcbbb45c
1519 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1519 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1520 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1520 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1521 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1521 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1522 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1522 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1523 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1523 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1524 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1524 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1525 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1525 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1526 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1526 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1527 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1527 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1528 node: 95c24699272ef57d062b8bccc32c878bf841784a
1528 node: 95c24699272ef57d062b8bccc32c878bf841784a
1529 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1529 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1530 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1530 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1531 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1531 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1532 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1532 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1533 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1533 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1534 node: 97054abb4ab824450e9164180baf491ae0078465
1534 node: 97054abb4ab824450e9164180baf491ae0078465
1535 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1535 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1536 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1536 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1537 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1537 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1538 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1538 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1539 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1539 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1540 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1540 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1541 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1541 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1542 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1542 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1543 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1543 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1544 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1544 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1545 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1545 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1546 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1546 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1547 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1547 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1548 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1548 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1549 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1549 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1550 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1550 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1551 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1551 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1552 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1552 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1553 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1553 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1554 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1554 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1555 parents:
1555 parents:
1556 parents: -1:000000000000
1556 parents: -1:000000000000
1557 parents: 5:13207e5a10d9 4:bbe44766e73d
1557 parents: 5:13207e5a10d9 4:bbe44766e73d
1558 parents: 3:10e46f2dcbf4
1558 parents: 3:10e46f2dcbf4
1559 parents:
1559 parents:
1560 parents:
1560 parents:
1561 parents:
1561 parents:
1562 parents:
1562 parents:
1563 parents:
1563 parents:
1564 parents--verbose:
1564 parents--verbose:
1565 parents--verbose: -1:000000000000
1565 parents--verbose: -1:000000000000
1566 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1566 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1567 parents--verbose: 3:10e46f2dcbf4
1567 parents--verbose: 3:10e46f2dcbf4
1568 parents--verbose:
1568 parents--verbose:
1569 parents--verbose:
1569 parents--verbose:
1570 parents--verbose:
1570 parents--verbose:
1571 parents--verbose:
1571 parents--verbose:
1572 parents--verbose:
1572 parents--verbose:
1573 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1573 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1574 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1574 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1575 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1575 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1576 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1576 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1577 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1577 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1578 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1578 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1579 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1579 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1580 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1580 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1581 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1581 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1582 rev: 8
1582 rev: 8
1583 rev: 7
1583 rev: 7
1584 rev: 6
1584 rev: 6
1585 rev: 5
1585 rev: 5
1586 rev: 4
1586 rev: 4
1587 rev: 3
1587 rev: 3
1588 rev: 2
1588 rev: 2
1589 rev: 1
1589 rev: 1
1590 rev: 0
1590 rev: 0
1591 rev--verbose: 8
1591 rev--verbose: 8
1592 rev--verbose: 7
1592 rev--verbose: 7
1593 rev--verbose: 6
1593 rev--verbose: 6
1594 rev--verbose: 5
1594 rev--verbose: 5
1595 rev--verbose: 4
1595 rev--verbose: 4
1596 rev--verbose: 3
1596 rev--verbose: 3
1597 rev--verbose: 2
1597 rev--verbose: 2
1598 rev--verbose: 1
1598 rev--verbose: 1
1599 rev--verbose: 0
1599 rev--verbose: 0
1600 rev--debug: 8
1600 rev--debug: 8
1601 rev--debug: 7
1601 rev--debug: 7
1602 rev--debug: 6
1602 rev--debug: 6
1603 rev--debug: 5
1603 rev--debug: 5
1604 rev--debug: 4
1604 rev--debug: 4
1605 rev--debug: 3
1605 rev--debug: 3
1606 rev--debug: 2
1606 rev--debug: 2
1607 rev--debug: 1
1607 rev--debug: 1
1608 rev--debug: 0
1608 rev--debug: 0
1609 tags: tip
1609 tags: tip
1610 tags:
1610 tags:
1611 tags:
1611 tags:
1612 tags:
1612 tags:
1613 tags:
1613 tags:
1614 tags:
1614 tags:
1615 tags:
1615 tags:
1616 tags:
1616 tags:
1617 tags:
1617 tags:
1618 tags--verbose: tip
1618 tags--verbose: tip
1619 tags--verbose:
1619 tags--verbose:
1620 tags--verbose:
1620 tags--verbose:
1621 tags--verbose:
1621 tags--verbose:
1622 tags--verbose:
1622 tags--verbose:
1623 tags--verbose:
1623 tags--verbose:
1624 tags--verbose:
1624 tags--verbose:
1625 tags--verbose:
1625 tags--verbose:
1626 tags--verbose:
1626 tags--verbose:
1627 tags--debug: tip
1627 tags--debug: tip
1628 tags--debug:
1628 tags--debug:
1629 tags--debug:
1629 tags--debug:
1630 tags--debug:
1630 tags--debug:
1631 tags--debug:
1631 tags--debug:
1632 tags--debug:
1632 tags--debug:
1633 tags--debug:
1633 tags--debug:
1634 tags--debug:
1634 tags--debug:
1635 tags--debug:
1635 tags--debug:
1636 diffstat: 3: +2/-1
1636 diffstat: 3: +2/-1
1637 diffstat: 1: +1/-0
1637 diffstat: 1: +1/-0
1638 diffstat: 0: +0/-0
1638 diffstat: 0: +0/-0
1639 diffstat: 1: +1/-0
1639 diffstat: 1: +1/-0
1640 diffstat: 0: +0/-0
1640 diffstat: 0: +0/-0
1641 diffstat: 1: +1/-0
1641 diffstat: 1: +1/-0
1642 diffstat: 1: +4/-0
1642 diffstat: 1: +4/-0
1643 diffstat: 1: +2/-0
1643 diffstat: 1: +2/-0
1644 diffstat: 1: +1/-0
1644 diffstat: 1: +1/-0
1645 diffstat--verbose: 3: +2/-1
1645 diffstat--verbose: 3: +2/-1
1646 diffstat--verbose: 1: +1/-0
1646 diffstat--verbose: 1: +1/-0
1647 diffstat--verbose: 0: +0/-0
1647 diffstat--verbose: 0: +0/-0
1648 diffstat--verbose: 1: +1/-0
1648 diffstat--verbose: 1: +1/-0
1649 diffstat--verbose: 0: +0/-0
1649 diffstat--verbose: 0: +0/-0
1650 diffstat--verbose: 1: +1/-0
1650 diffstat--verbose: 1: +1/-0
1651 diffstat--verbose: 1: +4/-0
1651 diffstat--verbose: 1: +4/-0
1652 diffstat--verbose: 1: +2/-0
1652 diffstat--verbose: 1: +2/-0
1653 diffstat--verbose: 1: +1/-0
1653 diffstat--verbose: 1: +1/-0
1654 diffstat--debug: 3: +2/-1
1654 diffstat--debug: 3: +2/-1
1655 diffstat--debug: 1: +1/-0
1655 diffstat--debug: 1: +1/-0
1656 diffstat--debug: 0: +0/-0
1656 diffstat--debug: 0: +0/-0
1657 diffstat--debug: 1: +1/-0
1657 diffstat--debug: 1: +1/-0
1658 diffstat--debug: 0: +0/-0
1658 diffstat--debug: 0: +0/-0
1659 diffstat--debug: 1: +1/-0
1659 diffstat--debug: 1: +1/-0
1660 diffstat--debug: 1: +4/-0
1660 diffstat--debug: 1: +4/-0
1661 diffstat--debug: 1: +2/-0
1661 diffstat--debug: 1: +2/-0
1662 diffstat--debug: 1: +1/-0
1662 diffstat--debug: 1: +1/-0
1663 extras: branch=default
1663 extras: branch=default
1664 extras: branch=default
1664 extras: branch=default
1665 extras: branch=default
1665 extras: branch=default
1666 extras: branch=default
1666 extras: branch=default
1667 extras: branch=foo
1667 extras: branch=foo
1668 extras: branch=default
1668 extras: branch=default
1669 extras: branch=default
1669 extras: branch=default
1670 extras: branch=default
1670 extras: branch=default
1671 extras: branch=default
1671 extras: branch=default
1672 extras--verbose: branch=default
1672 extras--verbose: branch=default
1673 extras--verbose: branch=default
1673 extras--verbose: branch=default
1674 extras--verbose: branch=default
1674 extras--verbose: branch=default
1675 extras--verbose: branch=default
1675 extras--verbose: branch=default
1676 extras--verbose: branch=foo
1676 extras--verbose: branch=foo
1677 extras--verbose: branch=default
1677 extras--verbose: branch=default
1678 extras--verbose: branch=default
1678 extras--verbose: branch=default
1679 extras--verbose: branch=default
1679 extras--verbose: branch=default
1680 extras--verbose: branch=default
1680 extras--verbose: branch=default
1681 extras--debug: branch=default
1681 extras--debug: branch=default
1682 extras--debug: branch=default
1682 extras--debug: branch=default
1683 extras--debug: branch=default
1683 extras--debug: branch=default
1684 extras--debug: branch=default
1684 extras--debug: branch=default
1685 extras--debug: branch=foo
1685 extras--debug: branch=foo
1686 extras--debug: branch=default
1686 extras--debug: branch=default
1687 extras--debug: branch=default
1687 extras--debug: branch=default
1688 extras--debug: branch=default
1688 extras--debug: branch=default
1689 extras--debug: branch=default
1689 extras--debug: branch=default
1690 p1rev: 7
1690 p1rev: 7
1691 p1rev: -1
1691 p1rev: -1
1692 p1rev: 5
1692 p1rev: 5
1693 p1rev: 3
1693 p1rev: 3
1694 p1rev: 3
1694 p1rev: 3
1695 p1rev: 2
1695 p1rev: 2
1696 p1rev: 1
1696 p1rev: 1
1697 p1rev: 0
1697 p1rev: 0
1698 p1rev: -1
1698 p1rev: -1
1699 p1rev--verbose: 7
1699 p1rev--verbose: 7
1700 p1rev--verbose: -1
1700 p1rev--verbose: -1
1701 p1rev--verbose: 5
1701 p1rev--verbose: 5
1702 p1rev--verbose: 3
1702 p1rev--verbose: 3
1703 p1rev--verbose: 3
1703 p1rev--verbose: 3
1704 p1rev--verbose: 2
1704 p1rev--verbose: 2
1705 p1rev--verbose: 1
1705 p1rev--verbose: 1
1706 p1rev--verbose: 0
1706 p1rev--verbose: 0
1707 p1rev--verbose: -1
1707 p1rev--verbose: -1
1708 p1rev--debug: 7
1708 p1rev--debug: 7
1709 p1rev--debug: -1
1709 p1rev--debug: -1
1710 p1rev--debug: 5
1710 p1rev--debug: 5
1711 p1rev--debug: 3
1711 p1rev--debug: 3
1712 p1rev--debug: 3
1712 p1rev--debug: 3
1713 p1rev--debug: 2
1713 p1rev--debug: 2
1714 p1rev--debug: 1
1714 p1rev--debug: 1
1715 p1rev--debug: 0
1715 p1rev--debug: 0
1716 p1rev--debug: -1
1716 p1rev--debug: -1
1717 p2rev: -1
1717 p2rev: -1
1718 p2rev: -1
1718 p2rev: -1
1719 p2rev: 4
1719 p2rev: 4
1720 p2rev: -1
1720 p2rev: -1
1721 p2rev: -1
1721 p2rev: -1
1722 p2rev: -1
1722 p2rev: -1
1723 p2rev: -1
1723 p2rev: -1
1724 p2rev: -1
1724 p2rev: -1
1725 p2rev: -1
1725 p2rev: -1
1726 p2rev--verbose: -1
1726 p2rev--verbose: -1
1727 p2rev--verbose: -1
1727 p2rev--verbose: -1
1728 p2rev--verbose: 4
1728 p2rev--verbose: 4
1729 p2rev--verbose: -1
1729 p2rev--verbose: -1
1730 p2rev--verbose: -1
1730 p2rev--verbose: -1
1731 p2rev--verbose: -1
1731 p2rev--verbose: -1
1732 p2rev--verbose: -1
1732 p2rev--verbose: -1
1733 p2rev--verbose: -1
1733 p2rev--verbose: -1
1734 p2rev--verbose: -1
1734 p2rev--verbose: -1
1735 p2rev--debug: -1
1735 p2rev--debug: -1
1736 p2rev--debug: -1
1736 p2rev--debug: -1
1737 p2rev--debug: 4
1737 p2rev--debug: 4
1738 p2rev--debug: -1
1738 p2rev--debug: -1
1739 p2rev--debug: -1
1739 p2rev--debug: -1
1740 p2rev--debug: -1
1740 p2rev--debug: -1
1741 p2rev--debug: -1
1741 p2rev--debug: -1
1742 p2rev--debug: -1
1742 p2rev--debug: -1
1743 p2rev--debug: -1
1743 p2rev--debug: -1
1744 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1744 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1745 p1node: 0000000000000000000000000000000000000000
1745 p1node: 0000000000000000000000000000000000000000
1746 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1746 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1747 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1747 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1748 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1748 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1749 p1node: 97054abb4ab824450e9164180baf491ae0078465
1749 p1node: 97054abb4ab824450e9164180baf491ae0078465
1750 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1750 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1751 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1751 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1752 p1node: 0000000000000000000000000000000000000000
1752 p1node: 0000000000000000000000000000000000000000
1753 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1753 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1754 p1node--verbose: 0000000000000000000000000000000000000000
1754 p1node--verbose: 0000000000000000000000000000000000000000
1755 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1755 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1756 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1756 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1757 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1757 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1758 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1758 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1759 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1759 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1760 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1760 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1761 p1node--verbose: 0000000000000000000000000000000000000000
1761 p1node--verbose: 0000000000000000000000000000000000000000
1762 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1762 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1763 p1node--debug: 0000000000000000000000000000000000000000
1763 p1node--debug: 0000000000000000000000000000000000000000
1764 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1764 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1765 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1765 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1766 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1766 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1767 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1767 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1768 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1768 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1769 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1769 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1770 p1node--debug: 0000000000000000000000000000000000000000
1770 p1node--debug: 0000000000000000000000000000000000000000
1771 p2node: 0000000000000000000000000000000000000000
1771 p2node: 0000000000000000000000000000000000000000
1772 p2node: 0000000000000000000000000000000000000000
1772 p2node: 0000000000000000000000000000000000000000
1773 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1773 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1774 p2node: 0000000000000000000000000000000000000000
1774 p2node: 0000000000000000000000000000000000000000
1775 p2node: 0000000000000000000000000000000000000000
1775 p2node: 0000000000000000000000000000000000000000
1776 p2node: 0000000000000000000000000000000000000000
1776 p2node: 0000000000000000000000000000000000000000
1777 p2node: 0000000000000000000000000000000000000000
1777 p2node: 0000000000000000000000000000000000000000
1778 p2node: 0000000000000000000000000000000000000000
1778 p2node: 0000000000000000000000000000000000000000
1779 p2node: 0000000000000000000000000000000000000000
1779 p2node: 0000000000000000000000000000000000000000
1780 p2node--verbose: 0000000000000000000000000000000000000000
1780 p2node--verbose: 0000000000000000000000000000000000000000
1781 p2node--verbose: 0000000000000000000000000000000000000000
1781 p2node--verbose: 0000000000000000000000000000000000000000
1782 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1782 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1783 p2node--verbose: 0000000000000000000000000000000000000000
1783 p2node--verbose: 0000000000000000000000000000000000000000
1784 p2node--verbose: 0000000000000000000000000000000000000000
1784 p2node--verbose: 0000000000000000000000000000000000000000
1785 p2node--verbose: 0000000000000000000000000000000000000000
1785 p2node--verbose: 0000000000000000000000000000000000000000
1786 p2node--verbose: 0000000000000000000000000000000000000000
1786 p2node--verbose: 0000000000000000000000000000000000000000
1787 p2node--verbose: 0000000000000000000000000000000000000000
1787 p2node--verbose: 0000000000000000000000000000000000000000
1788 p2node--verbose: 0000000000000000000000000000000000000000
1788 p2node--verbose: 0000000000000000000000000000000000000000
1789 p2node--debug: 0000000000000000000000000000000000000000
1789 p2node--debug: 0000000000000000000000000000000000000000
1790 p2node--debug: 0000000000000000000000000000000000000000
1790 p2node--debug: 0000000000000000000000000000000000000000
1791 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1791 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1792 p2node--debug: 0000000000000000000000000000000000000000
1792 p2node--debug: 0000000000000000000000000000000000000000
1793 p2node--debug: 0000000000000000000000000000000000000000
1793 p2node--debug: 0000000000000000000000000000000000000000
1794 p2node--debug: 0000000000000000000000000000000000000000
1794 p2node--debug: 0000000000000000000000000000000000000000
1795 p2node--debug: 0000000000000000000000000000000000000000
1795 p2node--debug: 0000000000000000000000000000000000000000
1796 p2node--debug: 0000000000000000000000000000000000000000
1796 p2node--debug: 0000000000000000000000000000000000000000
1797 p2node--debug: 0000000000000000000000000000000000000000
1797 p2node--debug: 0000000000000000000000000000000000000000
1798
1798
1799 Filters work:
1799 Filters work:
1800
1800
1801 $ hg log --template '{author|domain}\n'
1801 $ hg log --template '{author|domain}\n'
1802
1802
1803 hostname
1803 hostname
1804
1804
1805
1805
1806
1806
1807
1807
1808 place
1808 place
1809 place
1809 place
1810 hostname
1810 hostname
1811
1811
1812 $ hg log --template '{author|person}\n'
1812 $ hg log --template '{author|person}\n'
1813 test
1813 test
1814 User Name
1814 User Name
1815 person
1815 person
1816 person
1816 person
1817 person
1817 person
1818 person
1818 person
1819 other
1819 other
1820 A. N. Other
1820 A. N. Other
1821 User Name
1821 User Name
1822
1822
1823 $ hg log --template '{author|user}\n'
1823 $ hg log --template '{author|user}\n'
1824 test
1824 test
1825 user
1825 user
1826 person
1826 person
1827 person
1827 person
1828 person
1828 person
1829 person
1829 person
1830 other
1830 other
1831 other
1831 other
1832 user
1832 user
1833
1833
1834 $ hg log --template '{date|date}\n'
1834 $ hg log --template '{date|date}\n'
1835 Wed Jan 01 10:01:00 2020 +0000
1835 Wed Jan 01 10:01:00 2020 +0000
1836 Mon Jan 12 13:46:40 1970 +0000
1836 Mon Jan 12 13:46:40 1970 +0000
1837 Sun Jan 18 08:40:01 1970 +0000
1837 Sun Jan 18 08:40:01 1970 +0000
1838 Sun Jan 18 08:40:00 1970 +0000
1838 Sun Jan 18 08:40:00 1970 +0000
1839 Sat Jan 17 04:53:20 1970 +0000
1839 Sat Jan 17 04:53:20 1970 +0000
1840 Fri Jan 16 01:06:40 1970 +0000
1840 Fri Jan 16 01:06:40 1970 +0000
1841 Wed Jan 14 21:20:00 1970 +0000
1841 Wed Jan 14 21:20:00 1970 +0000
1842 Tue Jan 13 17:33:20 1970 +0000
1842 Tue Jan 13 17:33:20 1970 +0000
1843 Mon Jan 12 13:46:40 1970 +0000
1843 Mon Jan 12 13:46:40 1970 +0000
1844
1844
1845 $ hg log --template '{date|isodate}\n'
1845 $ hg log --template '{date|isodate}\n'
1846 2020-01-01 10:01 +0000
1846 2020-01-01 10:01 +0000
1847 1970-01-12 13:46 +0000
1847 1970-01-12 13:46 +0000
1848 1970-01-18 08:40 +0000
1848 1970-01-18 08:40 +0000
1849 1970-01-18 08:40 +0000
1849 1970-01-18 08:40 +0000
1850 1970-01-17 04:53 +0000
1850 1970-01-17 04:53 +0000
1851 1970-01-16 01:06 +0000
1851 1970-01-16 01:06 +0000
1852 1970-01-14 21:20 +0000
1852 1970-01-14 21:20 +0000
1853 1970-01-13 17:33 +0000
1853 1970-01-13 17:33 +0000
1854 1970-01-12 13:46 +0000
1854 1970-01-12 13:46 +0000
1855
1855
1856 $ hg log --template '{date|isodatesec}\n'
1856 $ hg log --template '{date|isodatesec}\n'
1857 2020-01-01 10:01:00 +0000
1857 2020-01-01 10:01:00 +0000
1858 1970-01-12 13:46:40 +0000
1858 1970-01-12 13:46:40 +0000
1859 1970-01-18 08:40:01 +0000
1859 1970-01-18 08:40:01 +0000
1860 1970-01-18 08:40:00 +0000
1860 1970-01-18 08:40:00 +0000
1861 1970-01-17 04:53:20 +0000
1861 1970-01-17 04:53:20 +0000
1862 1970-01-16 01:06:40 +0000
1862 1970-01-16 01:06:40 +0000
1863 1970-01-14 21:20:00 +0000
1863 1970-01-14 21:20:00 +0000
1864 1970-01-13 17:33:20 +0000
1864 1970-01-13 17:33:20 +0000
1865 1970-01-12 13:46:40 +0000
1865 1970-01-12 13:46:40 +0000
1866
1866
1867 $ hg log --template '{date|rfc822date}\n'
1867 $ hg log --template '{date|rfc822date}\n'
1868 Wed, 01 Jan 2020 10:01:00 +0000
1868 Wed, 01 Jan 2020 10:01:00 +0000
1869 Mon, 12 Jan 1970 13:46:40 +0000
1869 Mon, 12 Jan 1970 13:46:40 +0000
1870 Sun, 18 Jan 1970 08:40:01 +0000
1870 Sun, 18 Jan 1970 08:40:01 +0000
1871 Sun, 18 Jan 1970 08:40:00 +0000
1871 Sun, 18 Jan 1970 08:40:00 +0000
1872 Sat, 17 Jan 1970 04:53:20 +0000
1872 Sat, 17 Jan 1970 04:53:20 +0000
1873 Fri, 16 Jan 1970 01:06:40 +0000
1873 Fri, 16 Jan 1970 01:06:40 +0000
1874 Wed, 14 Jan 1970 21:20:00 +0000
1874 Wed, 14 Jan 1970 21:20:00 +0000
1875 Tue, 13 Jan 1970 17:33:20 +0000
1875 Tue, 13 Jan 1970 17:33:20 +0000
1876 Mon, 12 Jan 1970 13:46:40 +0000
1876 Mon, 12 Jan 1970 13:46:40 +0000
1877
1877
1878 $ hg log --template '{desc|firstline}\n'
1878 $ hg log --template '{desc|firstline}\n'
1879 third
1879 third
1880 second
1880 second
1881 merge
1881 merge
1882 new head
1882 new head
1883 new branch
1883 new branch
1884 no user, no domain
1884 no user, no domain
1885 no person
1885 no person
1886 other 1
1886 other 1
1887 line 1
1887 line 1
1888
1888
1889 $ hg log --template '{node|short}\n'
1889 $ hg log --template '{node|short}\n'
1890 95c24699272e
1890 95c24699272e
1891 29114dbae42b
1891 29114dbae42b
1892 d41e714fe50d
1892 d41e714fe50d
1893 13207e5a10d9
1893 13207e5a10d9
1894 bbe44766e73d
1894 bbe44766e73d
1895 10e46f2dcbf4
1895 10e46f2dcbf4
1896 97054abb4ab8
1896 97054abb4ab8
1897 b608e9d1a3f0
1897 b608e9d1a3f0
1898 1e4e1b8f71e0
1898 1e4e1b8f71e0
1899
1899
1900 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1900 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1901 <changeset author="test"/>
1901 <changeset author="test"/>
1902 <changeset author="User Name &lt;user@hostname&gt;"/>
1902 <changeset author="User Name &lt;user@hostname&gt;"/>
1903 <changeset author="person"/>
1903 <changeset author="person"/>
1904 <changeset author="person"/>
1904 <changeset author="person"/>
1905 <changeset author="person"/>
1905 <changeset author="person"/>
1906 <changeset author="person"/>
1906 <changeset author="person"/>
1907 <changeset author="other@place"/>
1907 <changeset author="other@place"/>
1908 <changeset author="A. N. Other &lt;other@place&gt;"/>
1908 <changeset author="A. N. Other &lt;other@place&gt;"/>
1909 <changeset author="User Name &lt;user@hostname&gt;"/>
1909 <changeset author="User Name &lt;user@hostname&gt;"/>
1910
1910
1911 $ hg log --template '{rev}: {children}\n'
1911 $ hg log --template '{rev}: {children}\n'
1912 8:
1912 8:
1913 7: 8:95c24699272e
1913 7: 8:95c24699272e
1914 6:
1914 6:
1915 5: 6:d41e714fe50d
1915 5: 6:d41e714fe50d
1916 4: 6:d41e714fe50d
1916 4: 6:d41e714fe50d
1917 3: 4:bbe44766e73d 5:13207e5a10d9
1917 3: 4:bbe44766e73d 5:13207e5a10d9
1918 2: 3:10e46f2dcbf4
1918 2: 3:10e46f2dcbf4
1919 1: 2:97054abb4ab8
1919 1: 2:97054abb4ab8
1920 0: 1:b608e9d1a3f0
1920 0: 1:b608e9d1a3f0
1921
1921
1922 Formatnode filter works:
1922 Formatnode filter works:
1923
1923
1924 $ hg -q log -r 0 --template '{node|formatnode}\n'
1924 $ hg -q log -r 0 --template '{node|formatnode}\n'
1925 1e4e1b8f71e0
1925 1e4e1b8f71e0
1926
1926
1927 $ hg log -r 0 --template '{node|formatnode}\n'
1927 $ hg log -r 0 --template '{node|formatnode}\n'
1928 1e4e1b8f71e0
1928 1e4e1b8f71e0
1929
1929
1930 $ hg -v log -r 0 --template '{node|formatnode}\n'
1930 $ hg -v log -r 0 --template '{node|formatnode}\n'
1931 1e4e1b8f71e0
1931 1e4e1b8f71e0
1932
1932
1933 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1933 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1934 1e4e1b8f71e05681d422154f5421e385fec3454f
1934 1e4e1b8f71e05681d422154f5421e385fec3454f
1935
1935
1936 Age filter:
1936 Age filter:
1937
1937
1938 $ hg init unstable-hash
1938 $ hg init unstable-hash
1939 $ cd unstable-hash
1939 $ cd unstable-hash
1940 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1940 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1941
1941
1942 >>> from datetime import datetime, timedelta
1942 >>> from datetime import datetime, timedelta
1943 >>> fp = open('a', 'w')
1943 >>> fp = open('a', 'w')
1944 >>> n = datetime.now() + timedelta(366 * 7)
1944 >>> n = datetime.now() + timedelta(366 * 7)
1945 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1945 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1946 >>> fp.close()
1946 >>> fp.close()
1947 $ hg add a
1947 $ hg add a
1948 $ hg commit -m future -d "`cat a`"
1948 $ hg commit -m future -d "`cat a`"
1949
1949
1950 $ hg log -l1 --template '{date|age}\n'
1950 $ hg log -l1 --template '{date|age}\n'
1951 7 years from now
1951 7 years from now
1952
1952
1953 $ cd ..
1953 $ cd ..
1954 $ rm -rf unstable-hash
1954 $ rm -rf unstable-hash
1955
1955
1956 Add a dummy commit to make up for the instability of the above:
1956 Add a dummy commit to make up for the instability of the above:
1957
1957
1958 $ echo a > a
1958 $ echo a > a
1959 $ hg add a
1959 $ hg add a
1960 $ hg ci -m future
1960 $ hg ci -m future
1961
1961
1962 Count filter:
1962 Count filter:
1963
1963
1964 $ hg log -l1 --template '{node|count} {node|short|count}\n'
1964 $ hg log -l1 --template '{node|count} {node|short|count}\n'
1965 40 12
1965 40 12
1966
1966
1967 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
1967 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
1968 0 1 4
1968 0 1 4
1969
1969
1970 $ hg log -G --template '{rev}: children: {children|count}, \
1970 $ hg log -G --template '{rev}: children: {children|count}, \
1971 > tags: {tags|count}, file_adds: {file_adds|count}, \
1971 > tags: {tags|count}, file_adds: {file_adds|count}, \
1972 > ancestors: {revset("ancestors(%s)", rev)|count}'
1972 > ancestors: {revset("ancestors(%s)", rev)|count}'
1973 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
1973 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
1974 |
1974 |
1975 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
1975 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
1976 |
1976 |
1977 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
1977 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
1978
1978
1979 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
1979 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
1980 |\
1980 |\
1981 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
1981 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
1982 | |
1982 | |
1983 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
1983 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
1984 |/
1984 |/
1985 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
1985 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
1986 |
1986 |
1987 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
1987 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
1988 |
1988 |
1989 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
1989 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
1990 |
1990 |
1991 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
1991 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
1992
1992
1993
1993
1994 Upper/lower filters:
1994 Upper/lower filters:
1995
1995
1996 $ hg log -r0 --template '{branch|upper}\n'
1996 $ hg log -r0 --template '{branch|upper}\n'
1997 DEFAULT
1997 DEFAULT
1998 $ hg log -r0 --template '{author|lower}\n'
1998 $ hg log -r0 --template '{author|lower}\n'
1999 user name <user@hostname>
1999 user name <user@hostname>
2000 $ hg log -r0 --template '{date|upper}\n'
2000 $ hg log -r0 --template '{date|upper}\n'
2001 abort: template filter 'upper' is not compatible with keyword 'date'
2001 abort: template filter 'upper' is not compatible with keyword 'date'
2002 [255]
2002 [255]
2003
2003
2004 Add a commit that does all possible modifications at once
2004 Add a commit that does all possible modifications at once
2005
2005
2006 $ echo modify >> third
2006 $ echo modify >> third
2007 $ touch b
2007 $ touch b
2008 $ hg add b
2008 $ hg add b
2009 $ hg mv fourth fifth
2009 $ hg mv fourth fifth
2010 $ hg rm a
2010 $ hg rm a
2011 $ hg ci -m "Modify, add, remove, rename"
2011 $ hg ci -m "Modify, add, remove, rename"
2012
2012
2013 Check the status template
2013 Check the status template
2014
2014
2015 $ cat <<EOF >> $HGRCPATH
2015 $ cat <<EOF >> $HGRCPATH
2016 > [extensions]
2016 > [extensions]
2017 > color=
2017 > color=
2018 > EOF
2018 > EOF
2019
2019
2020 $ hg log -T status -r 10
2020 $ hg log -T status -r 10
2021 changeset: 10:0f9759ec227a
2021 changeset: 10:0f9759ec227a
2022 tag: tip
2022 tag: tip
2023 user: test
2023 user: test
2024 date: Thu Jan 01 00:00:00 1970 +0000
2024 date: Thu Jan 01 00:00:00 1970 +0000
2025 summary: Modify, add, remove, rename
2025 summary: Modify, add, remove, rename
2026 files:
2026 files:
2027 M third
2027 M third
2028 A b
2028 A b
2029 A fifth
2029 A fifth
2030 R a
2030 R a
2031 R fourth
2031 R fourth
2032
2032
2033 $ hg log -T status -C -r 10
2033 $ hg log -T status -C -r 10
2034 changeset: 10:0f9759ec227a
2034 changeset: 10:0f9759ec227a
2035 tag: tip
2035 tag: tip
2036 user: test
2036 user: test
2037 date: Thu Jan 01 00:00:00 1970 +0000
2037 date: Thu Jan 01 00:00:00 1970 +0000
2038 summary: Modify, add, remove, rename
2038 summary: Modify, add, remove, rename
2039 files:
2039 files:
2040 M third
2040 M third
2041 A b
2041 A b
2042 A fifth
2042 A fifth
2043 fourth
2043 fourth
2044 R a
2044 R a
2045 R fourth
2045 R fourth
2046
2046
2047 $ hg log -T status -C -r 10 -v
2047 $ hg log -T status -C -r 10 -v
2048 changeset: 10:0f9759ec227a
2048 changeset: 10:0f9759ec227a
2049 tag: tip
2049 tag: tip
2050 user: test
2050 user: test
2051 date: Thu Jan 01 00:00:00 1970 +0000
2051 date: Thu Jan 01 00:00:00 1970 +0000
2052 description:
2052 description:
2053 Modify, add, remove, rename
2053 Modify, add, remove, rename
2054
2054
2055 files:
2055 files:
2056 M third
2056 M third
2057 A b
2057 A b
2058 A fifth
2058 A fifth
2059 fourth
2059 fourth
2060 R a
2060 R a
2061 R fourth
2061 R fourth
2062
2062
2063 $ hg log -T status -C -r 10 --debug
2063 $ hg log -T status -C -r 10 --debug
2064 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2064 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2065 tag: tip
2065 tag: tip
2066 phase: secret
2066 phase: secret
2067 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2067 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2068 parent: -1:0000000000000000000000000000000000000000
2068 parent: -1:0000000000000000000000000000000000000000
2069 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2069 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2070 user: test
2070 user: test
2071 date: Thu Jan 01 00:00:00 1970 +0000
2071 date: Thu Jan 01 00:00:00 1970 +0000
2072 extra: branch=default
2072 extra: branch=default
2073 description:
2073 description:
2074 Modify, add, remove, rename
2074 Modify, add, remove, rename
2075
2075
2076 files:
2076 files:
2077 M third
2077 M third
2078 A b
2078 A b
2079 A fifth
2079 A fifth
2080 fourth
2080 fourth
2081 R a
2081 R a
2082 R fourth
2082 R fourth
2083
2083
2084 $ hg log -T status -C -r 10 --quiet
2084 $ hg log -T status -C -r 10 --quiet
2085 10:0f9759ec227a
2085 10:0f9759ec227a
2086 $ hg --color=debug log -T status -r 10
2086 $ hg --color=debug log -T status -r 10
2087 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2087 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2088 [log.tag|tag: tip]
2088 [log.tag|tag: tip]
2089 [log.user|user: test]
2089 [log.user|user: test]
2090 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2090 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2091 [log.summary|summary: Modify, add, remove, rename]
2091 [log.summary|summary: Modify, add, remove, rename]
2092 [ui.note log.files|files:]
2092 [ui.note log.files|files:]
2093 [status.modified|M third]
2093 [status.modified|M third]
2094 [status.added|A b]
2094 [status.added|A b]
2095 [status.added|A fifth]
2095 [status.added|A fifth]
2096 [status.removed|R a]
2096 [status.removed|R a]
2097 [status.removed|R fourth]
2097 [status.removed|R fourth]
2098
2098
2099 $ hg --color=debug log -T status -C -r 10
2099 $ hg --color=debug log -T status -C -r 10
2100 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2100 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2101 [log.tag|tag: tip]
2101 [log.tag|tag: tip]
2102 [log.user|user: test]
2102 [log.user|user: test]
2103 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2103 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2104 [log.summary|summary: Modify, add, remove, rename]
2104 [log.summary|summary: Modify, add, remove, rename]
2105 [ui.note log.files|files:]
2105 [ui.note log.files|files:]
2106 [status.modified|M third]
2106 [status.modified|M third]
2107 [status.added|A b]
2107 [status.added|A b]
2108 [status.added|A fifth]
2108 [status.added|A fifth]
2109 [status.copied| fourth]
2109 [status.copied| fourth]
2110 [status.removed|R a]
2110 [status.removed|R a]
2111 [status.removed|R fourth]
2111 [status.removed|R fourth]
2112
2112
2113 $ hg --color=debug log -T status -C -r 10 -v
2113 $ hg --color=debug log -T status -C -r 10 -v
2114 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2114 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2115 [log.tag|tag: tip]
2115 [log.tag|tag: tip]
2116 [log.user|user: test]
2116 [log.user|user: test]
2117 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2117 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2118 [ui.note log.description|description:]
2118 [ui.note log.description|description:]
2119 [ui.note log.description|Modify, add, remove, rename]
2119 [ui.note log.description|Modify, add, remove, rename]
2120
2120
2121 [ui.note log.files|files:]
2121 [ui.note log.files|files:]
2122 [status.modified|M third]
2122 [status.modified|M third]
2123 [status.added|A b]
2123 [status.added|A b]
2124 [status.added|A fifth]
2124 [status.added|A fifth]
2125 [status.copied| fourth]
2125 [status.copied| fourth]
2126 [status.removed|R a]
2126 [status.removed|R a]
2127 [status.removed|R fourth]
2127 [status.removed|R fourth]
2128
2128
2129 $ hg --color=debug log -T status -C -r 10 --debug
2129 $ hg --color=debug log -T status -C -r 10 --debug
2130 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2130 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2131 [log.tag|tag: tip]
2131 [log.tag|tag: tip]
2132 [log.phase|phase: secret]
2132 [log.phase|phase: secret]
2133 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2133 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2134 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2134 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2135 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2135 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2136 [log.user|user: test]
2136 [log.user|user: test]
2137 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2137 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2138 [ui.debug log.extra|extra: branch=default]
2138 [ui.debug log.extra|extra: branch=default]
2139 [ui.note log.description|description:]
2139 [ui.note log.description|description:]
2140 [ui.note log.description|Modify, add, remove, rename]
2140 [ui.note log.description|Modify, add, remove, rename]
2141
2141
2142 [ui.note log.files|files:]
2142 [ui.note log.files|files:]
2143 [status.modified|M third]
2143 [status.modified|M third]
2144 [status.added|A b]
2144 [status.added|A b]
2145 [status.added|A fifth]
2145 [status.added|A fifth]
2146 [status.copied| fourth]
2146 [status.copied| fourth]
2147 [status.removed|R a]
2147 [status.removed|R a]
2148 [status.removed|R fourth]
2148 [status.removed|R fourth]
2149
2149
2150 $ hg --color=debug log -T status -C -r 10 --quiet
2150 $ hg --color=debug log -T status -C -r 10 --quiet
2151 [log.node|10:0f9759ec227a]
2151 [log.node|10:0f9759ec227a]
2152
2152
2153 Check the bisect template
2153 Check the bisect template
2154
2154
2155 $ hg bisect -g 1
2155 $ hg bisect -g 1
2156 $ hg bisect -b 3 --noupdate
2156 $ hg bisect -b 3 --noupdate
2157 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2157 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2158 $ hg log -T bisect -r 0:4
2158 $ hg log -T bisect -r 0:4
2159 changeset: 0:1e4e1b8f71e0
2159 changeset: 0:1e4e1b8f71e0
2160 bisect: good (implicit)
2160 bisect: good (implicit)
2161 user: User Name <user@hostname>
2161 user: User Name <user@hostname>
2162 date: Mon Jan 12 13:46:40 1970 +0000
2162 date: Mon Jan 12 13:46:40 1970 +0000
2163 summary: line 1
2163 summary: line 1
2164
2164
2165 changeset: 1:b608e9d1a3f0
2165 changeset: 1:b608e9d1a3f0
2166 bisect: good
2166 bisect: good
2167 user: A. N. Other <other@place>
2167 user: A. N. Other <other@place>
2168 date: Tue Jan 13 17:33:20 1970 +0000
2168 date: Tue Jan 13 17:33:20 1970 +0000
2169 summary: other 1
2169 summary: other 1
2170
2170
2171 changeset: 2:97054abb4ab8
2171 changeset: 2:97054abb4ab8
2172 bisect: untested
2172 bisect: untested
2173 user: other@place
2173 user: other@place
2174 date: Wed Jan 14 21:20:00 1970 +0000
2174 date: Wed Jan 14 21:20:00 1970 +0000
2175 summary: no person
2175 summary: no person
2176
2176
2177 changeset: 3:10e46f2dcbf4
2177 changeset: 3:10e46f2dcbf4
2178 bisect: bad
2178 bisect: bad
2179 user: person
2179 user: person
2180 date: Fri Jan 16 01:06:40 1970 +0000
2180 date: Fri Jan 16 01:06:40 1970 +0000
2181 summary: no user, no domain
2181 summary: no user, no domain
2182
2182
2183 changeset: 4:bbe44766e73d
2183 changeset: 4:bbe44766e73d
2184 bisect: bad (implicit)
2184 bisect: bad (implicit)
2185 branch: foo
2185 branch: foo
2186 user: person
2186 user: person
2187 date: Sat Jan 17 04:53:20 1970 +0000
2187 date: Sat Jan 17 04:53:20 1970 +0000
2188 summary: new branch
2188 summary: new branch
2189
2189
2190 $ hg log --debug -T bisect -r 0:4
2190 $ hg log --debug -T bisect -r 0:4
2191 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2191 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2192 bisect: good (implicit)
2192 bisect: good (implicit)
2193 phase: public
2193 phase: public
2194 parent: -1:0000000000000000000000000000000000000000
2194 parent: -1:0000000000000000000000000000000000000000
2195 parent: -1:0000000000000000000000000000000000000000
2195 parent: -1:0000000000000000000000000000000000000000
2196 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2196 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2197 user: User Name <user@hostname>
2197 user: User Name <user@hostname>
2198 date: Mon Jan 12 13:46:40 1970 +0000
2198 date: Mon Jan 12 13:46:40 1970 +0000
2199 files+: a
2199 files+: a
2200 extra: branch=default
2200 extra: branch=default
2201 description:
2201 description:
2202 line 1
2202 line 1
2203 line 2
2203 line 2
2204
2204
2205
2205
2206 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2206 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2207 bisect: good
2207 bisect: good
2208 phase: public
2208 phase: public
2209 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2209 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2210 parent: -1:0000000000000000000000000000000000000000
2210 parent: -1:0000000000000000000000000000000000000000
2211 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2211 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2212 user: A. N. Other <other@place>
2212 user: A. N. Other <other@place>
2213 date: Tue Jan 13 17:33:20 1970 +0000
2213 date: Tue Jan 13 17:33:20 1970 +0000
2214 files+: b
2214 files+: b
2215 extra: branch=default
2215 extra: branch=default
2216 description:
2216 description:
2217 other 1
2217 other 1
2218 other 2
2218 other 2
2219
2219
2220 other 3
2220 other 3
2221
2221
2222
2222
2223 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2223 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2224 bisect: untested
2224 bisect: untested
2225 phase: public
2225 phase: public
2226 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2226 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2227 parent: -1:0000000000000000000000000000000000000000
2227 parent: -1:0000000000000000000000000000000000000000
2228 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2228 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2229 user: other@place
2229 user: other@place
2230 date: Wed Jan 14 21:20:00 1970 +0000
2230 date: Wed Jan 14 21:20:00 1970 +0000
2231 files+: c
2231 files+: c
2232 extra: branch=default
2232 extra: branch=default
2233 description:
2233 description:
2234 no person
2234 no person
2235
2235
2236
2236
2237 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2237 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2238 bisect: bad
2238 bisect: bad
2239 phase: public
2239 phase: public
2240 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2240 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2241 parent: -1:0000000000000000000000000000000000000000
2241 parent: -1:0000000000000000000000000000000000000000
2242 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2242 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2243 user: person
2243 user: person
2244 date: Fri Jan 16 01:06:40 1970 +0000
2244 date: Fri Jan 16 01:06:40 1970 +0000
2245 files: c
2245 files: c
2246 extra: branch=default
2246 extra: branch=default
2247 description:
2247 description:
2248 no user, no domain
2248 no user, no domain
2249
2249
2250
2250
2251 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2251 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2252 bisect: bad (implicit)
2252 bisect: bad (implicit)
2253 branch: foo
2253 branch: foo
2254 phase: draft
2254 phase: draft
2255 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2255 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2256 parent: -1:0000000000000000000000000000000000000000
2256 parent: -1:0000000000000000000000000000000000000000
2257 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2257 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2258 user: person
2258 user: person
2259 date: Sat Jan 17 04:53:20 1970 +0000
2259 date: Sat Jan 17 04:53:20 1970 +0000
2260 extra: branch=foo
2260 extra: branch=foo
2261 description:
2261 description:
2262 new branch
2262 new branch
2263
2263
2264
2264
2265 $ hg log -v -T bisect -r 0:4
2265 $ hg log -v -T bisect -r 0:4
2266 changeset: 0:1e4e1b8f71e0
2266 changeset: 0:1e4e1b8f71e0
2267 bisect: good (implicit)
2267 bisect: good (implicit)
2268 user: User Name <user@hostname>
2268 user: User Name <user@hostname>
2269 date: Mon Jan 12 13:46:40 1970 +0000
2269 date: Mon Jan 12 13:46:40 1970 +0000
2270 files: a
2270 files: a
2271 description:
2271 description:
2272 line 1
2272 line 1
2273 line 2
2273 line 2
2274
2274
2275
2275
2276 changeset: 1:b608e9d1a3f0
2276 changeset: 1:b608e9d1a3f0
2277 bisect: good
2277 bisect: good
2278 user: A. N. Other <other@place>
2278 user: A. N. Other <other@place>
2279 date: Tue Jan 13 17:33:20 1970 +0000
2279 date: Tue Jan 13 17:33:20 1970 +0000
2280 files: b
2280 files: b
2281 description:
2281 description:
2282 other 1
2282 other 1
2283 other 2
2283 other 2
2284
2284
2285 other 3
2285 other 3
2286
2286
2287
2287
2288 changeset: 2:97054abb4ab8
2288 changeset: 2:97054abb4ab8
2289 bisect: untested
2289 bisect: untested
2290 user: other@place
2290 user: other@place
2291 date: Wed Jan 14 21:20:00 1970 +0000
2291 date: Wed Jan 14 21:20:00 1970 +0000
2292 files: c
2292 files: c
2293 description:
2293 description:
2294 no person
2294 no person
2295
2295
2296
2296
2297 changeset: 3:10e46f2dcbf4
2297 changeset: 3:10e46f2dcbf4
2298 bisect: bad
2298 bisect: bad
2299 user: person
2299 user: person
2300 date: Fri Jan 16 01:06:40 1970 +0000
2300 date: Fri Jan 16 01:06:40 1970 +0000
2301 files: c
2301 files: c
2302 description:
2302 description:
2303 no user, no domain
2303 no user, no domain
2304
2304
2305
2305
2306 changeset: 4:bbe44766e73d
2306 changeset: 4:bbe44766e73d
2307 bisect: bad (implicit)
2307 bisect: bad (implicit)
2308 branch: foo
2308 branch: foo
2309 user: person
2309 user: person
2310 date: Sat Jan 17 04:53:20 1970 +0000
2310 date: Sat Jan 17 04:53:20 1970 +0000
2311 description:
2311 description:
2312 new branch
2312 new branch
2313
2313
2314
2314
2315 $ hg --color=debug log -T bisect -r 0:4
2315 $ hg --color=debug log -T bisect -r 0:4
2316 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2316 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2317 [log.bisect bisect.good|bisect: good (implicit)]
2317 [log.bisect bisect.good|bisect: good (implicit)]
2318 [log.user|user: User Name <user@hostname>]
2318 [log.user|user: User Name <user@hostname>]
2319 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2319 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2320 [log.summary|summary: line 1]
2320 [log.summary|summary: line 1]
2321
2321
2322 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2322 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2323 [log.bisect bisect.good|bisect: good]
2323 [log.bisect bisect.good|bisect: good]
2324 [log.user|user: A. N. Other <other@place>]
2324 [log.user|user: A. N. Other <other@place>]
2325 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2325 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2326 [log.summary|summary: other 1]
2326 [log.summary|summary: other 1]
2327
2327
2328 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2328 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2329 [log.bisect bisect.untested|bisect: untested]
2329 [log.bisect bisect.untested|bisect: untested]
2330 [log.user|user: other@place]
2330 [log.user|user: other@place]
2331 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2331 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2332 [log.summary|summary: no person]
2332 [log.summary|summary: no person]
2333
2333
2334 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2334 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2335 [log.bisect bisect.bad|bisect: bad]
2335 [log.bisect bisect.bad|bisect: bad]
2336 [log.user|user: person]
2336 [log.user|user: person]
2337 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2337 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2338 [log.summary|summary: no user, no domain]
2338 [log.summary|summary: no user, no domain]
2339
2339
2340 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2340 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2341 [log.bisect bisect.bad|bisect: bad (implicit)]
2341 [log.bisect bisect.bad|bisect: bad (implicit)]
2342 [log.branch|branch: foo]
2342 [log.branch|branch: foo]
2343 [log.user|user: person]
2343 [log.user|user: person]
2344 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2344 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2345 [log.summary|summary: new branch]
2345 [log.summary|summary: new branch]
2346
2346
2347 $ hg --color=debug log --debug -T bisect -r 0:4
2347 $ hg --color=debug log --debug -T bisect -r 0:4
2348 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2348 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2349 [log.bisect bisect.good|bisect: good (implicit)]
2349 [log.bisect bisect.good|bisect: good (implicit)]
2350 [log.phase|phase: public]
2350 [log.phase|phase: public]
2351 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2351 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2352 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2352 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2353 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2353 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2354 [log.user|user: User Name <user@hostname>]
2354 [log.user|user: User Name <user@hostname>]
2355 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2355 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2356 [ui.debug log.files|files+: a]
2356 [ui.debug log.files|files+: a]
2357 [ui.debug log.extra|extra: branch=default]
2357 [ui.debug log.extra|extra: branch=default]
2358 [ui.note log.description|description:]
2358 [ui.note log.description|description:]
2359 [ui.note log.description|line 1
2359 [ui.note log.description|line 1
2360 line 2]
2360 line 2]
2361
2361
2362
2362
2363 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2363 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2364 [log.bisect bisect.good|bisect: good]
2364 [log.bisect bisect.good|bisect: good]
2365 [log.phase|phase: public]
2365 [log.phase|phase: public]
2366 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2366 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2367 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2367 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2368 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2368 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2369 [log.user|user: A. N. Other <other@place>]
2369 [log.user|user: A. N. Other <other@place>]
2370 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2370 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2371 [ui.debug log.files|files+: b]
2371 [ui.debug log.files|files+: b]
2372 [ui.debug log.extra|extra: branch=default]
2372 [ui.debug log.extra|extra: branch=default]
2373 [ui.note log.description|description:]
2373 [ui.note log.description|description:]
2374 [ui.note log.description|other 1
2374 [ui.note log.description|other 1
2375 other 2
2375 other 2
2376
2376
2377 other 3]
2377 other 3]
2378
2378
2379
2379
2380 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2380 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2381 [log.bisect bisect.untested|bisect: untested]
2381 [log.bisect bisect.untested|bisect: untested]
2382 [log.phase|phase: public]
2382 [log.phase|phase: public]
2383 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2383 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2384 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2384 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2385 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2385 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2386 [log.user|user: other@place]
2386 [log.user|user: other@place]
2387 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2387 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2388 [ui.debug log.files|files+: c]
2388 [ui.debug log.files|files+: c]
2389 [ui.debug log.extra|extra: branch=default]
2389 [ui.debug log.extra|extra: branch=default]
2390 [ui.note log.description|description:]
2390 [ui.note log.description|description:]
2391 [ui.note log.description|no person]
2391 [ui.note log.description|no person]
2392
2392
2393
2393
2394 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2394 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2395 [log.bisect bisect.bad|bisect: bad]
2395 [log.bisect bisect.bad|bisect: bad]
2396 [log.phase|phase: public]
2396 [log.phase|phase: public]
2397 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2397 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2398 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2398 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2399 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2399 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2400 [log.user|user: person]
2400 [log.user|user: person]
2401 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2401 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2402 [ui.debug log.files|files: c]
2402 [ui.debug log.files|files: c]
2403 [ui.debug log.extra|extra: branch=default]
2403 [ui.debug log.extra|extra: branch=default]
2404 [ui.note log.description|description:]
2404 [ui.note log.description|description:]
2405 [ui.note log.description|no user, no domain]
2405 [ui.note log.description|no user, no domain]
2406
2406
2407
2407
2408 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2408 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2409 [log.bisect bisect.bad|bisect: bad (implicit)]
2409 [log.bisect bisect.bad|bisect: bad (implicit)]
2410 [log.branch|branch: foo]
2410 [log.branch|branch: foo]
2411 [log.phase|phase: draft]
2411 [log.phase|phase: draft]
2412 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2412 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2413 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2413 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2414 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2414 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2415 [log.user|user: person]
2415 [log.user|user: person]
2416 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2416 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2417 [ui.debug log.extra|extra: branch=foo]
2417 [ui.debug log.extra|extra: branch=foo]
2418 [ui.note log.description|description:]
2418 [ui.note log.description|description:]
2419 [ui.note log.description|new branch]
2419 [ui.note log.description|new branch]
2420
2420
2421
2421
2422 $ hg --color=debug log -v -T bisect -r 0:4
2422 $ hg --color=debug log -v -T bisect -r 0:4
2423 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2423 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2424 [log.bisect bisect.good|bisect: good (implicit)]
2424 [log.bisect bisect.good|bisect: good (implicit)]
2425 [log.user|user: User Name <user@hostname>]
2425 [log.user|user: User Name <user@hostname>]
2426 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2426 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2427 [ui.note log.files|files: a]
2427 [ui.note log.files|files: a]
2428 [ui.note log.description|description:]
2428 [ui.note log.description|description:]
2429 [ui.note log.description|line 1
2429 [ui.note log.description|line 1
2430 line 2]
2430 line 2]
2431
2431
2432
2432
2433 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2433 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2434 [log.bisect bisect.good|bisect: good]
2434 [log.bisect bisect.good|bisect: good]
2435 [log.user|user: A. N. Other <other@place>]
2435 [log.user|user: A. N. Other <other@place>]
2436 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2436 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2437 [ui.note log.files|files: b]
2437 [ui.note log.files|files: b]
2438 [ui.note log.description|description:]
2438 [ui.note log.description|description:]
2439 [ui.note log.description|other 1
2439 [ui.note log.description|other 1
2440 other 2
2440 other 2
2441
2441
2442 other 3]
2442 other 3]
2443
2443
2444
2444
2445 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2445 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2446 [log.bisect bisect.untested|bisect: untested]
2446 [log.bisect bisect.untested|bisect: untested]
2447 [log.user|user: other@place]
2447 [log.user|user: other@place]
2448 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2448 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2449 [ui.note log.files|files: c]
2449 [ui.note log.files|files: c]
2450 [ui.note log.description|description:]
2450 [ui.note log.description|description:]
2451 [ui.note log.description|no person]
2451 [ui.note log.description|no person]
2452
2452
2453
2453
2454 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2454 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2455 [log.bisect bisect.bad|bisect: bad]
2455 [log.bisect bisect.bad|bisect: bad]
2456 [log.user|user: person]
2456 [log.user|user: person]
2457 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2457 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2458 [ui.note log.files|files: c]
2458 [ui.note log.files|files: c]
2459 [ui.note log.description|description:]
2459 [ui.note log.description|description:]
2460 [ui.note log.description|no user, no domain]
2460 [ui.note log.description|no user, no domain]
2461
2461
2462
2462
2463 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2463 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2464 [log.bisect bisect.bad|bisect: bad (implicit)]
2464 [log.bisect bisect.bad|bisect: bad (implicit)]
2465 [log.branch|branch: foo]
2465 [log.branch|branch: foo]
2466 [log.user|user: person]
2466 [log.user|user: person]
2467 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2467 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2468 [ui.note log.description|description:]
2468 [ui.note log.description|description:]
2469 [ui.note log.description|new branch]
2469 [ui.note log.description|new branch]
2470
2470
2471
2471
2472 $ hg bisect --reset
2472 $ hg bisect --reset
2473
2473
2474 Error on syntax:
2474 Error on syntax:
2475
2475
2476 $ echo 'x = "f' >> t
2476 $ echo 'x = "f' >> t
2477 $ hg log
2477 $ hg log
2478 abort: t:3: unmatched quotes
2478 abort: t:3: unmatched quotes
2479 [255]
2479 [255]
2480
2480
2481 $ hg log -T '{date'
2481 $ hg log -T '{date'
2482 hg: parse error at 1: unterminated template expansion
2482 hg: parse error at 1: unterminated template expansion
2483 [255]
2483 [255]
2484
2484
2485 Behind the scenes, this will throw TypeError
2485 Behind the scenes, this will throw TypeError
2486
2486
2487 $ hg log -l 3 --template '{date|obfuscate}\n'
2487 $ hg log -l 3 --template '{date|obfuscate}\n'
2488 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2488 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2489 [255]
2489 [255]
2490
2490
2491 Behind the scenes, this will throw a ValueError
2491 Behind the scenes, this will throw a ValueError
2492
2492
2493 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2493 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2494 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2494 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2495 [255]
2495 [255]
2496
2496
2497 Behind the scenes, this will throw AttributeError
2497 Behind the scenes, this will throw AttributeError
2498
2498
2499 $ hg log -l 3 --template 'line: {date|escape}\n'
2499 $ hg log -l 3 --template 'line: {date|escape}\n'
2500 abort: template filter 'escape' is not compatible with keyword 'date'
2500 abort: template filter 'escape' is not compatible with keyword 'date'
2501 [255]
2501 [255]
2502
2502
2503 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2503 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2504 hg: parse error: localdate expects a date information
2504 hg: parse error: localdate expects a date information
2505 [255]
2505 [255]
2506
2506
2507 Behind the scenes, this will throw ValueError
2507 Behind the scenes, this will throw ValueError
2508
2508
2509 $ hg tip --template '{author|email|date}\n'
2509 $ hg tip --template '{author|email|date}\n'
2510 hg: parse error: date expects a date information
2510 hg: parse error: date expects a date information
2511 [255]
2511 [255]
2512
2512
2513 Error in nested template:
2513 Error in nested template:
2514
2514
2515 $ hg log -T '{"date'
2515 $ hg log -T '{"date'
2516 hg: parse error at 2: unterminated string
2516 hg: parse error at 2: unterminated string
2517 [255]
2517 [255]
2518
2518
2519 $ hg log -T '{"foo{date|=}"}'
2519 $ hg log -T '{"foo{date|=}"}'
2520 hg: parse error at 11: syntax error
2520 hg: parse error at 11: syntax error
2521 [255]
2521 [255]
2522
2522
2523 Thrown an error if a template function doesn't exist
2523 Thrown an error if a template function doesn't exist
2524
2524
2525 $ hg tip --template '{foo()}\n'
2525 $ hg tip --template '{foo()}\n'
2526 hg: parse error: unknown function 'foo'
2526 hg: parse error: unknown function 'foo'
2527 [255]
2527 [255]
2528
2528
2529 Pass generator object created by template function to filter
2529 Pass generator object created by template function to filter
2530
2530
2531 $ hg log -l 1 --template '{if(author, author)|user}\n'
2531 $ hg log -l 1 --template '{if(author, author)|user}\n'
2532 test
2532 test
2533
2533
2534 Test diff function:
2534 Test diff function:
2535
2535
2536 $ hg diff -c 8
2536 $ hg diff -c 8
2537 diff -r 29114dbae42b -r 95c24699272e fourth
2537 diff -r 29114dbae42b -r 95c24699272e fourth
2538 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2538 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2539 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2539 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2540 @@ -0,0 +1,1 @@
2540 @@ -0,0 +1,1 @@
2541 +second
2541 +second
2542 diff -r 29114dbae42b -r 95c24699272e second
2542 diff -r 29114dbae42b -r 95c24699272e second
2543 --- a/second Mon Jan 12 13:46:40 1970 +0000
2543 --- a/second Mon Jan 12 13:46:40 1970 +0000
2544 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2544 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2545 @@ -1,1 +0,0 @@
2545 @@ -1,1 +0,0 @@
2546 -second
2546 -second
2547 diff -r 29114dbae42b -r 95c24699272e third
2547 diff -r 29114dbae42b -r 95c24699272e third
2548 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2548 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2549 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2549 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2550 @@ -0,0 +1,1 @@
2550 @@ -0,0 +1,1 @@
2551 +third
2551 +third
2552
2552
2553 $ hg log -r 8 -T "{diff()}"
2553 $ hg log -r 8 -T "{diff()}"
2554 diff -r 29114dbae42b -r 95c24699272e fourth
2554 diff -r 29114dbae42b -r 95c24699272e fourth
2555 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2555 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2556 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2556 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2557 @@ -0,0 +1,1 @@
2557 @@ -0,0 +1,1 @@
2558 +second
2558 +second
2559 diff -r 29114dbae42b -r 95c24699272e second
2559 diff -r 29114dbae42b -r 95c24699272e second
2560 --- a/second Mon Jan 12 13:46:40 1970 +0000
2560 --- a/second Mon Jan 12 13:46:40 1970 +0000
2561 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2561 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2562 @@ -1,1 +0,0 @@
2562 @@ -1,1 +0,0 @@
2563 -second
2563 -second
2564 diff -r 29114dbae42b -r 95c24699272e third
2564 diff -r 29114dbae42b -r 95c24699272e third
2565 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2565 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2566 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2566 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2567 @@ -0,0 +1,1 @@
2567 @@ -0,0 +1,1 @@
2568 +third
2568 +third
2569
2569
2570 $ hg log -r 8 -T "{diff('glob:f*')}"
2570 $ hg log -r 8 -T "{diff('glob:f*')}"
2571 diff -r 29114dbae42b -r 95c24699272e fourth
2571 diff -r 29114dbae42b -r 95c24699272e fourth
2572 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2572 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2573 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2573 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2574 @@ -0,0 +1,1 @@
2574 @@ -0,0 +1,1 @@
2575 +second
2575 +second
2576
2576
2577 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2577 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2578 diff -r 29114dbae42b -r 95c24699272e second
2578 diff -r 29114dbae42b -r 95c24699272e second
2579 --- a/second Mon Jan 12 13:46:40 1970 +0000
2579 --- a/second Mon Jan 12 13:46:40 1970 +0000
2580 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2580 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2581 @@ -1,1 +0,0 @@
2581 @@ -1,1 +0,0 @@
2582 -second
2582 -second
2583 diff -r 29114dbae42b -r 95c24699272e third
2583 diff -r 29114dbae42b -r 95c24699272e third
2584 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2584 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2585 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2585 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2586 @@ -0,0 +1,1 @@
2586 @@ -0,0 +1,1 @@
2587 +third
2587 +third
2588
2588
2589 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2589 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2590 diff -r 29114dbae42b -r 95c24699272e fourth
2590 diff -r 29114dbae42b -r 95c24699272e fourth
2591 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2591 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2592 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2592 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2593 @@ -0,0 +1,1 @@
2593 @@ -0,0 +1,1 @@
2594 +second
2594 +second
2595
2595
2596 $ cd ..
2596 $ cd ..
2597
2597
2598
2598
2599 latesttag:
2599 latesttag:
2600
2600
2601 $ hg init latesttag
2601 $ hg init latesttag
2602 $ cd latesttag
2602 $ cd latesttag
2603
2603
2604 $ echo a > file
2604 $ echo a > file
2605 $ hg ci -Am a -d '0 0'
2605 $ hg ci -Am a -d '0 0'
2606 adding file
2606 adding file
2607
2607
2608 $ echo b >> file
2608 $ echo b >> file
2609 $ hg ci -m b -d '1 0'
2609 $ hg ci -m b -d '1 0'
2610
2610
2611 $ echo c >> head1
2611 $ echo c >> head1
2612 $ hg ci -Am h1c -d '2 0'
2612 $ hg ci -Am h1c -d '2 0'
2613 adding head1
2613 adding head1
2614
2614
2615 $ hg update -q 1
2615 $ hg update -q 1
2616 $ echo d >> head2
2616 $ echo d >> head2
2617 $ hg ci -Am h2d -d '3 0'
2617 $ hg ci -Am h2d -d '3 0'
2618 adding head2
2618 adding head2
2619 created new head
2619 created new head
2620
2620
2621 $ echo e >> head2
2621 $ echo e >> head2
2622 $ hg ci -m h2e -d '4 0'
2622 $ hg ci -m h2e -d '4 0'
2623
2623
2624 $ hg merge -q
2624 $ hg merge -q
2625 $ hg ci -m merge -d '5 -3600'
2625 $ hg ci -m merge -d '5 -3600'
2626
2626
2627 No tag set:
2627 No tag set:
2628
2628
2629 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2629 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2630 5: null+5
2630 5: null+5
2631 4: null+4
2631 4: null+4
2632 3: null+3
2632 3: null+3
2633 2: null+3
2633 2: null+3
2634 1: null+2
2634 1: null+2
2635 0: null+1
2635 0: null+1
2636
2636
2637 One common tag: longest path wins:
2637 One common tag: longest path wins:
2638
2638
2639 $ hg tag -r 1 -m t1 -d '6 0' t1
2639 $ hg tag -r 1 -m t1 -d '6 0' t1
2640 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2640 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2641 6: t1+4
2641 6: t1+4
2642 5: t1+3
2642 5: t1+3
2643 4: t1+2
2643 4: t1+2
2644 3: t1+1
2644 3: t1+1
2645 2: t1+1
2645 2: t1+1
2646 1: t1+0
2646 1: t1+0
2647 0: null+1
2647 0: null+1
2648
2648
2649 One ancestor tag: more recent wins:
2649 One ancestor tag: more recent wins:
2650
2650
2651 $ hg tag -r 2 -m t2 -d '7 0' t2
2651 $ hg tag -r 2 -m t2 -d '7 0' t2
2652 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2652 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2653 7: t2+3
2653 7: t2+3
2654 6: t2+2
2654 6: t2+2
2655 5: t2+1
2655 5: t2+1
2656 4: t1+2
2656 4: t1+2
2657 3: t1+1
2657 3: t1+1
2658 2: t2+0
2658 2: t2+0
2659 1: t1+0
2659 1: t1+0
2660 0: null+1
2660 0: null+1
2661
2661
2662 Two branch tags: more recent wins:
2662 Two branch tags: more recent wins:
2663
2663
2664 $ hg tag -r 3 -m t3 -d '8 0' t3
2664 $ hg tag -r 3 -m t3 -d '8 0' t3
2665 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2665 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2666 8: t3+5
2666 8: t3+5
2667 7: t3+4
2667 7: t3+4
2668 6: t3+3
2668 6: t3+3
2669 5: t3+2
2669 5: t3+2
2670 4: t3+1
2670 4: t3+1
2671 3: t3+0
2671 3: t3+0
2672 2: t2+0
2672 2: t2+0
2673 1: t1+0
2673 1: t1+0
2674 0: null+1
2674 0: null+1
2675
2675
2676 Merged tag overrides:
2676 Merged tag overrides:
2677
2677
2678 $ hg tag -r 5 -m t5 -d '9 0' t5
2678 $ hg tag -r 5 -m t5 -d '9 0' t5
2679 $ hg tag -r 3 -m at3 -d '10 0' at3
2679 $ hg tag -r 3 -m at3 -d '10 0' at3
2680 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2680 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2681 10: t5+5
2681 10: t5+5
2682 9: t5+4
2682 9: t5+4
2683 8: t5+3
2683 8: t5+3
2684 7: t5+2
2684 7: t5+2
2685 6: t5+1
2685 6: t5+1
2686 5: t5+0
2686 5: t5+0
2687 4: at3:t3+1
2687 4: at3:t3+1
2688 3: at3:t3+0
2688 3: at3:t3+0
2689 2: t2+0
2689 2: t2+0
2690 1: t1+0
2690 1: t1+0
2691 0: null+1
2691 0: null+1
2692
2692
2693 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2693 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2694 10: t5+5,5
2694 10: t5+5,5
2695 9: t5+4,4
2695 9: t5+4,4
2696 8: t5+3,3
2696 8: t5+3,3
2697 7: t5+2,2
2697 7: t5+2,2
2698 6: t5+1,1
2698 6: t5+1,1
2699 5: t5+0,0
2699 5: t5+0,0
2700 4: at3+1,1 t3+1,1
2700 4: at3+1,1 t3+1,1
2701 3: at3+0,0 t3+0,0
2701 3: at3+0,0 t3+0,0
2702 2: t2+0,0
2702 2: t2+0,0
2703 1: t1+0,0
2703 1: t1+0,0
2704 0: null+1,1
2704 0: null+1,1
2705
2705
2706 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2706 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2707 10: t3, C: 8, D: 7
2707 10: t3, C: 8, D: 7
2708 9: t3, C: 7, D: 6
2708 9: t3, C: 7, D: 6
2709 8: t3, C: 6, D: 5
2709 8: t3, C: 6, D: 5
2710 7: t3, C: 5, D: 4
2710 7: t3, C: 5, D: 4
2711 6: t3, C: 4, D: 3
2711 6: t3, C: 4, D: 3
2712 5: t3, C: 3, D: 2
2712 5: t3, C: 3, D: 2
2713 4: t3, C: 1, D: 1
2713 4: t3, C: 1, D: 1
2714 3: t3, C: 0, D: 0
2714 3: t3, C: 0, D: 0
2715 2: t1, C: 1, D: 1
2715 2: t1, C: 1, D: 1
2716 1: t1, C: 0, D: 0
2716 1: t1, C: 0, D: 0
2717 0: null, C: 1, D: 1
2717 0: null, C: 1, D: 1
2718
2718
2719 $ cd ..
2719 $ cd ..
2720
2720
2721
2721
2722 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2722 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2723 if it is a relative path
2723 if it is a relative path
2724
2724
2725 $ mkdir -p home/styles
2725 $ mkdir -p home/styles
2726
2726
2727 $ cat > home/styles/teststyle <<EOF
2727 $ cat > home/styles/teststyle <<EOF
2728 > changeset = 'test {rev}:{node|short}\n'
2728 > changeset = 'test {rev}:{node|short}\n'
2729 > EOF
2729 > EOF
2730
2730
2731 $ HOME=`pwd`/home; export HOME
2731 $ HOME=`pwd`/home; export HOME
2732
2732
2733 $ cat > latesttag/.hg/hgrc <<EOF
2733 $ cat > latesttag/.hg/hgrc <<EOF
2734 > [ui]
2734 > [ui]
2735 > style = ~/styles/teststyle
2735 > style = ~/styles/teststyle
2736 > EOF
2736 > EOF
2737
2737
2738 $ hg -R latesttag tip
2738 $ hg -R latesttag tip
2739 test 10:9b4a630e5f5f
2739 test 10:9b4a630e5f5f
2740
2740
2741 Test recursive showlist template (issue1989):
2741 Test recursive showlist template (issue1989):
2742
2742
2743 $ cat > style1989 <<EOF
2743 $ cat > style1989 <<EOF
2744 > changeset = '{file_mods}{manifest}{extras}'
2744 > changeset = '{file_mods}{manifest}{extras}'
2745 > file_mod = 'M|{author|person}\n'
2745 > file_mod = 'M|{author|person}\n'
2746 > manifest = '{rev},{author}\n'
2746 > manifest = '{rev},{author}\n'
2747 > extra = '{key}: {author}\n'
2747 > extra = '{key}: {author}\n'
2748 > EOF
2748 > EOF
2749
2749
2750 $ hg -R latesttag log -r tip --style=style1989
2750 $ hg -R latesttag log -r tip --style=style1989
2751 M|test
2751 M|test
2752 10,test
2752 10,test
2753 branch: test
2753 branch: test
2754
2754
2755 Test new-style inline templating:
2755 Test new-style inline templating:
2756
2756
2757 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2757 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2758 modified files: .hgtags
2758 modified files: .hgtags
2759
2759
2760 Test the sub function of templating for expansion:
2760 Test the sub function of templating for expansion:
2761
2761
2762 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2762 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2763 xx
2763 xx
2764
2764
2765 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2765 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2766 hg: parse error: sub got an invalid pattern: [
2766 hg: parse error: sub got an invalid pattern: [
2767 [255]
2767 [255]
2768 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2768 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2769 hg: parse error: sub got an invalid replacement: \1
2769 hg: parse error: sub got an invalid replacement: \1
2770 [255]
2770 [255]
2771
2771
2772 Test the strip function with chars specified:
2772 Test the strip function with chars specified:
2773
2773
2774 $ hg log -R latesttag --template '{desc}\n'
2774 $ hg log -R latesttag --template '{desc}\n'
2775 at3
2775 at3
2776 t5
2776 t5
2777 t3
2777 t3
2778 t2
2778 t2
2779 t1
2779 t1
2780 merge
2780 merge
2781 h2e
2781 h2e
2782 h2d
2782 h2d
2783 h1c
2783 h1c
2784 b
2784 b
2785 a
2785 a
2786
2786
2787 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2787 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2788 at3
2788 at3
2789 5
2789 5
2790 3
2790 3
2791 2
2791 2
2792 1
2792 1
2793 merg
2793 merg
2794 h2
2794 h2
2795 h2d
2795 h2d
2796 h1c
2796 h1c
2797 b
2797 b
2798 a
2798 a
2799
2799
2800 Test date format:
2800 Test date format:
2801
2801
2802 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2802 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2803 date: 70 01 01 10 +0000
2803 date: 70 01 01 10 +0000
2804 date: 70 01 01 09 +0000
2804 date: 70 01 01 09 +0000
2805 date: 70 01 01 08 +0000
2805 date: 70 01 01 08 +0000
2806 date: 70 01 01 07 +0000
2806 date: 70 01 01 07 +0000
2807 date: 70 01 01 06 +0000
2807 date: 70 01 01 06 +0000
2808 date: 70 01 01 05 +0100
2808 date: 70 01 01 05 +0100
2809 date: 70 01 01 04 +0000
2809 date: 70 01 01 04 +0000
2810 date: 70 01 01 03 +0000
2810 date: 70 01 01 03 +0000
2811 date: 70 01 01 02 +0000
2811 date: 70 01 01 02 +0000
2812 date: 70 01 01 01 +0000
2812 date: 70 01 01 01 +0000
2813 date: 70 01 01 00 +0000
2813 date: 70 01 01 00 +0000
2814
2814
2815 Test invalid date:
2815 Test invalid date:
2816
2816
2817 $ hg log -R latesttag -T '{date(rev)}\n'
2817 $ hg log -R latesttag -T '{date(rev)}\n'
2818 hg: parse error: date expects a date information
2818 hg: parse error: date expects a date information
2819 [255]
2819 [255]
2820
2820
2821 Test integer literal:
2821 Test integer literal:
2822
2822
2823 $ hg log -Ra -r0 -T '{(0)}\n'
2823 $ hg log -Ra -r0 -T '{(0)}\n'
2824 0
2824 0
2825 $ hg log -Ra -r0 -T '{(123)}\n'
2825 $ hg log -Ra -r0 -T '{(123)}\n'
2826 123
2826 123
2827 $ hg log -Ra -r0 -T '{(-4)}\n'
2827 $ hg log -Ra -r0 -T '{(-4)}\n'
2828 -4
2828 -4
2829 $ hg log -Ra -r0 -T '{(-)}\n'
2829 $ hg log -Ra -r0 -T '{(-)}\n'
2830 hg: parse error at 2: integer literal without digits
2830 hg: parse error at 2: integer literal without digits
2831 [255]
2831 [255]
2832 $ hg log -Ra -r0 -T '{(-a)}\n'
2832 $ hg log -Ra -r0 -T '{(-a)}\n'
2833 hg: parse error at 2: integer literal without digits
2833 hg: parse error at 2: integer literal without digits
2834 [255]
2834 [255]
2835
2835
2836 top-level integer literal is interpreted as symbol (i.e. variable name):
2836 top-level integer literal is interpreted as symbol (i.e. variable name):
2837
2837
2838 $ hg log -Ra -r0 -T '{1}\n'
2838 $ hg log -Ra -r0 -T '{1}\n'
2839
2839
2840 $ hg log -Ra -r0 -T '{if("t", "{1}")}\n'
2840 $ hg log -Ra -r0 -T '{if("t", "{1}")}\n'
2841
2841
2842 $ hg log -Ra -r0 -T '{1|stringify}\n'
2842 $ hg log -Ra -r0 -T '{1|stringify}\n'
2843
2843
2844
2844
2845 unless explicit symbol is expected:
2845 unless explicit symbol is expected:
2846
2846
2847 $ hg log -Ra -r0 -T '{desc|1}\n'
2847 $ hg log -Ra -r0 -T '{desc|1}\n'
2848 hg: parse error: expected a symbol, got 'integer'
2848 hg: parse error: expected a symbol, got 'integer'
2849 [255]
2849 [255]
2850 $ hg log -Ra -r0 -T '{1()}\n'
2850 $ hg log -Ra -r0 -T '{1()}\n'
2851 hg: parse error: expected a symbol, got 'integer'
2851 hg: parse error: expected a symbol, got 'integer'
2852 [255]
2852 [255]
2853
2853
2854 Test string literal:
2854 Test string literal:
2855
2855
2856 $ hg log -Ra -r0 -T '{"string with no template fragment"}\n'
2856 $ hg log -Ra -r0 -T '{"string with no template fragment"}\n'
2857 string with no template fragment
2857 string with no template fragment
2858 $ hg log -Ra -r0 -T '{"template: {rev}"}\n'
2858 $ hg log -Ra -r0 -T '{"template: {rev}"}\n'
2859 template: 0
2859 template: 0
2860 $ hg log -Ra -r0 -T '{r"rawstring: {rev}"}\n'
2860 $ hg log -Ra -r0 -T '{r"rawstring: {rev}"}\n'
2861 rawstring: {rev}
2861 rawstring: {rev}
2862
2862
2863 because map operation requires template, raw string can't be used
2863 because map operation requires template, raw string can't be used
2864
2864
2865 $ hg log -Ra -r0 -T '{files % r"rawstring"}\n'
2865 $ hg log -Ra -r0 -T '{files % r"rawstring"}\n'
2866 hg: parse error: expected template specifier
2866 hg: parse error: expected template specifier
2867 [255]
2867 [255]
2868
2868
2869 Test string escaping:
2869 Test string escaping:
2870
2870
2871 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2871 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2872 >
2872 >
2873 <>\n<[>
2873 <>\n<[>
2874 <>\n<]>
2874 <>\n<]>
2875 <>\n<
2875 <>\n<
2876
2876
2877 $ hg log -R latesttag -r 0 \
2877 $ hg log -R latesttag -r 0 \
2878 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2878 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2879 >
2879 >
2880 <>\n<[>
2880 <>\n<[>
2881 <>\n<]>
2881 <>\n<]>
2882 <>\n<
2882 <>\n<
2883
2883
2884 $ hg log -R latesttag -r 0 -T esc \
2884 $ hg log -R latesttag -r 0 -T esc \
2885 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2885 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2886 >
2886 >
2887 <>\n<[>
2887 <>\n<[>
2888 <>\n<]>
2888 <>\n<]>
2889 <>\n<
2889 <>\n<
2890
2890
2891 $ cat <<'EOF' > esctmpl
2891 $ cat <<'EOF' > esctmpl
2892 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2892 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2893 > EOF
2893 > EOF
2894 $ hg log -R latesttag -r 0 --style ./esctmpl
2894 $ hg log -R latesttag -r 0 --style ./esctmpl
2895 >
2895 >
2896 <>\n<[>
2896 <>\n<[>
2897 <>\n<]>
2897 <>\n<]>
2898 <>\n<
2898 <>\n<
2899
2899
2900 Test string escaping of quotes:
2900 Test string escaping of quotes:
2901
2901
2902 $ hg log -Ra -r0 -T '{"\""}\n'
2902 $ hg log -Ra -r0 -T '{"\""}\n'
2903 "
2903 "
2904 $ hg log -Ra -r0 -T '{"\\\""}\n'
2904 $ hg log -Ra -r0 -T '{"\\\""}\n'
2905 \"
2905 \"
2906 $ hg log -Ra -r0 -T '{r"\""}\n'
2906 $ hg log -Ra -r0 -T '{r"\""}\n'
2907 \"
2907 \"
2908 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2908 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2909 \\\"
2909 \\\"
2910
2910
2911
2911
2912 $ hg log -Ra -r0 -T '{"\""}\n'
2912 $ hg log -Ra -r0 -T '{"\""}\n'
2913 "
2913 "
2914 $ hg log -Ra -r0 -T '{"\\\""}\n'
2914 $ hg log -Ra -r0 -T '{"\\\""}\n'
2915 \"
2915 \"
2916 $ hg log -Ra -r0 -T '{r"\""}\n'
2916 $ hg log -Ra -r0 -T '{r"\""}\n'
2917 \"
2917 \"
2918 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2918 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2919 \\\"
2919 \\\"
2920
2920
2921 Test exception in quoted template. single backslash before quotation mark is
2921 Test exception in quoted template. single backslash before quotation mark is
2922 stripped before parsing:
2922 stripped before parsing:
2923
2923
2924 $ cat <<'EOF' > escquotetmpl
2924 $ cat <<'EOF' > escquotetmpl
2925 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
2925 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
2926 > EOF
2926 > EOF
2927 $ cd latesttag
2927 $ cd latesttag
2928 $ hg log -r 2 --style ../escquotetmpl
2928 $ hg log -r 2 --style ../escquotetmpl
2929 " \" \" \\" head1
2929 " \" \" \\" head1
2930
2930
2931 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
2931 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
2932 valid
2932 valid
2933 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
2933 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
2934 valid
2934 valid
2935
2935
2936 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
2936 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
2937 _evalifliteral() templates (issue4733):
2937 _evalifliteral() templates (issue4733):
2938
2938
2939 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
2939 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
2940 "2
2940 "2
2941 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
2941 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
2942 "2
2942 "2
2943 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
2943 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
2944 "2
2944 "2
2945
2945
2946 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
2946 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
2947 \"
2947 \"
2948 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
2948 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
2949 \"
2949 \"
2950 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2950 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2951 \"
2951 \"
2952
2952
2953 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
2953 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
2954 \\\"
2954 \\\"
2955 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
2955 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
2956 \\\"
2956 \\\"
2957 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2957 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2958 \\\"
2958 \\\"
2959
2959
2960 escaped single quotes and errors:
2960 escaped single quotes and errors:
2961
2961
2962 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
2962 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
2963 foo
2963 foo
2964 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
2964 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
2965 foo
2965 foo
2966 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
2966 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
2967 hg: parse error at 21: unterminated string
2967 hg: parse error at 21: unterminated string
2968 [255]
2968 [255]
2969 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
2969 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
2970 hg: parse error: trailing \ in string
2970 hg: parse error: trailing \ in string
2971 [255]
2971 [255]
2972 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
2972 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
2973 hg: parse error: trailing \ in string
2973 hg: parse error: trailing \ in string
2974 [255]
2974 [255]
2975
2975
2976 $ cd ..
2976 $ cd ..
2977
2977
2978 Test leading backslashes:
2978 Test leading backslashes:
2979
2979
2980 $ cd latesttag
2980 $ cd latesttag
2981 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
2981 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
2982 {rev} {file}
2982 {rev} {file}
2983 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
2983 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
2984 \2 \head1
2984 \2 \head1
2985 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
2985 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
2986 \{rev} \{file}
2986 \{rev} \{file}
2987 $ cd ..
2987 $ cd ..
2988
2988
2989 Test leading backslashes in "if" expression (issue4714):
2989 Test leading backslashes in "if" expression (issue4714):
2990
2990
2991 $ cd latesttag
2991 $ cd latesttag
2992 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
2992 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
2993 {rev} \{rev}
2993 {rev} \{rev}
2994 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
2994 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
2995 \2 \\{rev}
2995 \2 \\{rev}
2996 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
2996 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
2997 \{rev} \\\{rev}
2997 \{rev} \\\{rev}
2998 $ cd ..
2998 $ cd ..
2999
2999
3000 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3000 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3001
3001
3002 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3002 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3003 \x6e
3003 \x6e
3004 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3004 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3005 \x5c\x786e
3005 \x5c\x786e
3006 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3006 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3007 \x6e
3007 \x6e
3008 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3008 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3009 \x5c\x786e
3009 \x5c\x786e
3010
3010
3011 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3011 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3012 \x6e
3012 \x6e
3013 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3013 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3014 \x5c\x786e
3014 \x5c\x786e
3015 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3015 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3016 \x6e
3016 \x6e
3017 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3017 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3018 \x5c\x786e
3018 \x5c\x786e
3019
3019
3020 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3020 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3021 fourth
3021 fourth
3022 second
3022 second
3023 third
3023 third
3024 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3024 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3025 fourth\nsecond\nthird
3025 fourth\nsecond\nthird
3026
3026
3027 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3027 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3028 <p>
3028 <p>
3029 1st
3029 1st
3030 </p>
3030 </p>
3031 <p>
3031 <p>
3032 2nd
3032 2nd
3033 </p>
3033 </p>
3034 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3034 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3035 <p>
3035 <p>
3036 1st\n\n2nd
3036 1st\n\n2nd
3037 </p>
3037 </p>
3038 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3038 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3039 1st
3039 1st
3040
3040
3041 2nd
3041 2nd
3042
3042
3043 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3043 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3044 o perso
3044 o perso
3045 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3045 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3046 no person
3046 no person
3047 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3047 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3048 o perso
3048 o perso
3049 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3049 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3050 no perso
3050 no perso
3051
3051
3052 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3052 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3053 -o perso-
3053 -o perso-
3054 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3054 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3055 no person
3055 no person
3056 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3056 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3057 \x2do perso\x2d
3057 \x2do perso\x2d
3058 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3058 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3059 -o perso-
3059 -o perso-
3060 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3060 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3061 \x2do perso\x6e
3061 \x2do perso\x6e
3062
3062
3063 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3063 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3064 fourth
3064 fourth
3065 second
3065 second
3066 third
3066 third
3067
3067
3068 Test string escaping in nested expression:
3068 Test string escaping in nested expression:
3069
3069
3070 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3070 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3071 fourth\x6esecond\x6ethird
3071 fourth\x6esecond\x6ethird
3072 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3072 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3073 fourth\x6esecond\x6ethird
3073 fourth\x6esecond\x6ethird
3074
3074
3075 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3075 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3076 fourth\x6esecond\x6ethird
3076 fourth\x6esecond\x6ethird
3077 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3077 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3078 fourth\x5c\x786esecond\x5c\x786ethird
3078 fourth\x5c\x786esecond\x5c\x786ethird
3079
3079
3080 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3080 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3081 3:\x6eo user, \x6eo domai\x6e
3081 3:\x6eo user, \x6eo domai\x6e
3082 4:\x5c\x786eew bra\x5c\x786ech
3082 4:\x5c\x786eew bra\x5c\x786ech
3083
3083
3084 Test quotes in nested expression are evaluated just like a $(command)
3084 Test quotes in nested expression are evaluated just like a $(command)
3085 substitution in POSIX shells:
3085 substitution in POSIX shells:
3086
3086
3087 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3087 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3088 8:95c24699272e
3088 8:95c24699272e
3089 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3089 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3090 {8} "95c24699272e"
3090 {8} "95c24699272e"
3091
3091
3092 Test recursive evaluation:
3092 Test recursive evaluation:
3093
3093
3094 $ hg init r
3094 $ hg init r
3095 $ cd r
3095 $ cd r
3096 $ echo a > a
3096 $ echo a > a
3097 $ hg ci -Am '{rev}'
3097 $ hg ci -Am '{rev}'
3098 adding a
3098 adding a
3099 $ hg log -r 0 --template '{if(rev, desc)}\n'
3099 $ hg log -r 0 --template '{if(rev, desc)}\n'
3100 {rev}
3100 {rev}
3101 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3101 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3102 test 0
3102 test 0
3103
3103
3104 $ hg branch -q 'text.{rev}'
3104 $ hg branch -q 'text.{rev}'
3105 $ echo aa >> aa
3105 $ echo aa >> aa
3106 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3106 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3107
3107
3108 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3108 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3109 {node|short}desc to
3109 {node|short}desc to
3110 text.{rev}be wrapped
3110 text.{rev}be wrapped
3111 text.{rev}desc to be
3111 text.{rev}desc to be
3112 text.{rev}wrapped (no-eol)
3112 text.{rev}wrapped (no-eol)
3113 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3113 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3114 bcc7ff960b8e:desc to
3114 bcc7ff960b8e:desc to
3115 text.1:be wrapped
3115 text.1:be wrapped
3116 text.1:desc to be
3116 text.1:desc to be
3117 text.1:wrapped (no-eol)
3117 text.1:wrapped (no-eol)
3118
3118
3119 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3119 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3120 {node|short} (no-eol)
3120 {node|short} (no-eol)
3121 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3121 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3122 bcc-ff---b-e (no-eol)
3122 bcc-ff---b-e (no-eol)
3123
3123
3124 $ cat >> .hg/hgrc <<EOF
3124 $ cat >> .hg/hgrc <<EOF
3125 > [extensions]
3125 > [extensions]
3126 > color=
3126 > color=
3127 > [color]
3127 > [color]
3128 > mode=ansi
3128 > mode=ansi
3129 > text.{rev} = red
3129 > text.{rev} = red
3130 > text.1 = green
3130 > text.1 = green
3131 > EOF
3131 > EOF
3132 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3132 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3133 \x1b[0;31mtext\x1b[0m (esc)
3133 \x1b[0;31mtext\x1b[0m (esc)
3134 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3134 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3135 \x1b[0;32mtext\x1b[0m (esc)
3135 \x1b[0;32mtext\x1b[0m (esc)
3136
3136
3137 Test branches inside if statement:
3137 Test branches inside if statement:
3138
3138
3139 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3139 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3140 no
3140 no
3141
3141
3142 Test get function:
3142 Test get function:
3143
3143
3144 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3144 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3145 default
3145 default
3146 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3146 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3147 hg: parse error: get() expects a dict as first argument
3147 hg: parse error: get() expects a dict as first argument
3148 [255]
3148 [255]
3149
3149
3150 Test localdate(date, tz) function:
3150 Test localdate(date, tz) function:
3151
3151
3152 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3152 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3153 1970-01-01 09:00 +0900
3153 1970-01-01 09:00 +0900
3154 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3154 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3155 1970-01-01 00:00 +0000
3155 1970-01-01 00:00 +0000
3156 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3156 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3157 1970-01-01 02:00 +0200
3157 1970-01-01 02:00 +0200
3158 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3158 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3159 1970-01-01 00:00 +0000
3159 1970-01-01 00:00 +0000
3160 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3160 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3161 1970-01-01 00:00 +0000
3161 1970-01-01 00:00 +0000
3162 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3162 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3163 hg: parse error: localdate expects a timezone
3163 hg: parse error: localdate expects a timezone
3164 [255]
3164 [255]
3165 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3165 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3166 hg: parse error: localdate expects a timezone
3166 hg: parse error: localdate expects a timezone
3167 [255]
3167 [255]
3168
3168
3169 Test shortest(node) function:
3169 Test shortest(node) function:
3170
3170
3171 $ echo b > b
3171 $ echo b > b
3172 $ hg ci -qAm b
3172 $ hg ci -qAm b
3173 $ hg log --template '{shortest(node)}\n'
3173 $ hg log --template '{shortest(node)}\n'
3174 e777
3174 e777
3175 bcc7
3175 bcc7
3176 f776
3176 f776
3177 $ hg log --template '{shortest(node, 10)}\n'
3177 $ hg log --template '{shortest(node, 10)}\n'
3178 e777603221
3178 e777603221
3179 bcc7ff960b
3179 bcc7ff960b
3180 f7769ec2ab
3180 f7769ec2ab
3181 $ hg log --template '{node|shortest}\n' -l1
3181 $ hg log --template '{node|shortest}\n' -l1
3182 e777
3182 e777
3183
3183
3184 Test pad function
3184 Test pad function
3185
3185
3186 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3186 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3187 2 test
3187 2 test
3188 1 {node|short}
3188 1 {node|short}
3189 0 test
3189 0 test
3190
3190
3191 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3191 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3192 2 test
3192 2 test
3193 1 {node|short}
3193 1 {node|short}
3194 0 test
3194 0 test
3195
3195
3196 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3196 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3197 2------------------- test
3197 2------------------- test
3198 1------------------- {node|short}
3198 1------------------- {node|short}
3199 0------------------- test
3199 0------------------- test
3200
3200
3201 Test template string in pad function
3201 Test template string in pad function
3202
3202
3203 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3203 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3204 {0} test
3204 {0} test
3205
3205
3206 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3206 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3207 \{rev} test
3207 \{rev} test
3208
3208
3209 Test ifcontains function
3209 Test ifcontains function
3210
3210
3211 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3211 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3212 2 is in the string
3212 2 is in the string
3213 1 is not
3213 1 is not
3214 0 is in the string
3214 0 is in the string
3215
3215
3216 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3216 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3217 2 did not add a
3217 2 did not add a
3218 1 did not add a
3218 1 did not add a
3219 0 added a
3219 0 added a
3220
3220
3221 Test revset function
3221 Test revset function
3222
3222
3223 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3223 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3224 2 current rev
3224 2 current rev
3225 1 not current rev
3225 1 not current rev
3226 0 not current rev
3226 0 not current rev
3227
3227
3228 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3228 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3229 2 match rev
3229 2 match rev
3230 1 match rev
3230 1 match rev
3231 0 not match rev
3231 0 not match rev
3232
3232
3233 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3233 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3234 2 Parents: 1
3234 2 Parents: 1
3235 1 Parents: 0
3235 1 Parents: 0
3236 0 Parents:
3236 0 Parents:
3237
3237
3238 $ cat >> .hg/hgrc <<EOF
3238 $ cat >> .hg/hgrc <<EOF
3239 > [revsetalias]
3239 > [revsetalias]
3240 > myparents(\$1) = parents(\$1)
3240 > myparents(\$1) = parents(\$1)
3241 > EOF
3241 > EOF
3242 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3242 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3243 2 Parents: 1
3243 2 Parents: 1
3244 1 Parents: 0
3244 1 Parents: 0
3245 0 Parents:
3245 0 Parents:
3246
3246
3247 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3247 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3248 Rev: 2
3248 Rev: 2
3249 Ancestor: 0
3249 Ancestor: 0
3250 Ancestor: 1
3250 Ancestor: 1
3251 Ancestor: 2
3251 Ancestor: 2
3252
3252
3253 Rev: 1
3253 Rev: 1
3254 Ancestor: 0
3254 Ancestor: 0
3255 Ancestor: 1
3255 Ancestor: 1
3256
3256
3257 Rev: 0
3257 Rev: 0
3258 Ancestor: 0
3258 Ancestor: 0
3259
3259
3260 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3260 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3261 2
3261 2
3262
3262
3263 a list template is evaluated for each item of revset
3263 a list template is evaluated for each item of revset
3264
3264
3265 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3265 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3266 2 p: 1:bcc7ff960b8e
3266 2 p: 1:bcc7ff960b8e
3267 1 p: 0:f7769ec2ab97
3267 1 p: 0:f7769ec2ab97
3268 0 p:
3268 0 p:
3269
3269
3270 therefore, 'revcache' should be recreated for each rev
3270 therefore, 'revcache' should be recreated for each rev
3271
3271
3272 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3272 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3273 2 aa b
3273 2 aa b
3274 p
3274 p
3275 1
3275 1
3276 p a
3276 p a
3277 0 a
3277 0 a
3278 p
3278 p
3279
3279
3280 Test active bookmark templating
3280 Test active bookmark templating
3281
3281
3282 $ hg book foo
3282 $ hg book foo
3283 $ hg book bar
3283 $ hg book bar
3284 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3284 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3285 2 bar* foo
3285 2 bar* foo
3286 1
3286 1
3287 0
3287 0
3288 $ hg log --template "{rev} {activebookmark}\n"
3288 $ hg log --template "{rev} {activebookmark}\n"
3289 2 bar
3289 2 bar
3290 1
3290 1
3291 0
3291 0
3292 $ hg bookmarks --inactive bar
3292 $ hg bookmarks --inactive bar
3293 $ hg log --template "{rev} {activebookmark}\n"
3293 $ hg log --template "{rev} {activebookmark}\n"
3294 2
3294 2
3295 1
3295 1
3296 0
3296 0
3297 $ hg book -r1 baz
3297 $ hg book -r1 baz
3298 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3298 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3299 2 bar foo
3299 2 bar foo
3300 1 baz
3300 1 baz
3301 0
3301 0
3302 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3302 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3303 2 t
3303 2 t
3304 1 f
3304 1 f
3305 0 f
3305 0 f
3306
3306
3307 Test stringify on sub expressions
3307 Test stringify on sub expressions
3308
3308
3309 $ cd ..
3309 $ cd ..
3310 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3310 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3311 fourth, second, third
3311 fourth, second, third
3312 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3312 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3313 abc
3313 abc
3314
3314
3315 Test splitlines
3315 Test splitlines
3316
3316
3317 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3317 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3318 @ foo Modify, add, remove, rename
3318 @ foo Modify, add, remove, rename
3319 |
3319 |
3320 o foo future
3320 o foo future
3321 |
3321 |
3322 o foo third
3322 o foo third
3323 |
3323 |
3324 o foo second
3324 o foo second
3325
3325
3326 o foo merge
3326 o foo merge
3327 |\
3327 |\
3328 | o foo new head
3328 | o foo new head
3329 | |
3329 | |
3330 o | foo new branch
3330 o | foo new branch
3331 |/
3331 |/
3332 o foo no user, no domain
3332 o foo no user, no domain
3333 |
3333 |
3334 o foo no person
3334 o foo no person
3335 |
3335 |
3336 o foo other 1
3336 o foo other 1
3337 | foo other 2
3337 | foo other 2
3338 | foo
3338 | foo
3339 | foo other 3
3339 | foo other 3
3340 o foo line 1
3340 o foo line 1
3341 foo line 2
3341 foo line 2
3342
3342
3343 Test startswith
3343 Test startswith
3344 $ hg log -Gv -R a --template "{startswith(desc)}"
3344 $ hg log -Gv -R a --template "{startswith(desc)}"
3345 hg: parse error: startswith expects two arguments
3345 hg: parse error: startswith expects two arguments
3346 [255]
3346 [255]
3347
3347
3348 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3348 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3349 @
3349 @
3350 |
3350 |
3351 o
3351 o
3352 |
3352 |
3353 o
3353 o
3354 |
3354 |
3355 o
3355 o
3356
3356
3357 o
3357 o
3358 |\
3358 |\
3359 | o
3359 | o
3360 | |
3360 | |
3361 o |
3361 o |
3362 |/
3362 |/
3363 o
3363 o
3364 |
3364 |
3365 o
3365 o
3366 |
3366 |
3367 o
3367 o
3368 |
3368 |
3369 o line 1
3369 o line 1
3370 line 2
3370 line 2
3371
3371
3372 Test bad template with better error message
3372 Test bad template with better error message
3373
3373
3374 $ hg log -Gv -R a --template '{desc|user()}'
3374 $ hg log -Gv -R a --template '{desc|user()}'
3375 hg: parse error: expected a symbol, got 'func'
3375 hg: parse error: expected a symbol, got 'func'
3376 [255]
3376 [255]
3377
3377
3378 Test word function (including index out of bounds graceful failure)
3378 Test word function (including index out of bounds graceful failure)
3379
3379
3380 $ hg log -Gv -R a --template "{word('1', desc)}"
3380 $ hg log -Gv -R a --template "{word('1', desc)}"
3381 @ add,
3381 @ add,
3382 |
3382 |
3383 o
3383 o
3384 |
3384 |
3385 o
3385 o
3386 |
3386 |
3387 o
3387 o
3388
3388
3389 o
3389 o
3390 |\
3390 |\
3391 | o head
3391 | o head
3392 | |
3392 | |
3393 o | branch
3393 o | branch
3394 |/
3394 |/
3395 o user,
3395 o user,
3396 |
3396 |
3397 o person
3397 o person
3398 |
3398 |
3399 o 1
3399 o 1
3400 |
3400 |
3401 o 1
3401 o 1
3402
3402
3403
3403
3404 Test word third parameter used as splitter
3404 Test word third parameter used as splitter
3405
3405
3406 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3406 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3407 @ M
3407 @ M
3408 |
3408 |
3409 o future
3409 o future
3410 |
3410 |
3411 o third
3411 o third
3412 |
3412 |
3413 o sec
3413 o sec
3414
3414
3415 o merge
3415 o merge
3416 |\
3416 |\
3417 | o new head
3417 | o new head
3418 | |
3418 | |
3419 o | new branch
3419 o | new branch
3420 |/
3420 |/
3421 o n
3421 o n
3422 |
3422 |
3423 o n
3423 o n
3424 |
3424 |
3425 o
3425 o
3426 |
3426 |
3427 o line 1
3427 o line 1
3428 line 2
3428 line 2
3429
3429
3430 Test word error messages for not enough and too many arguments
3430 Test word error messages for not enough and too many arguments
3431
3431
3432 $ hg log -Gv -R a --template "{word('0')}"
3432 $ hg log -Gv -R a --template "{word('0')}"
3433 hg: parse error: word expects two or three arguments, got 1
3433 hg: parse error: word expects two or three arguments, got 1
3434 [255]
3434 [255]
3435
3435
3436 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3436 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3437 hg: parse error: word expects two or three arguments, got 7
3437 hg: parse error: word expects two or three arguments, got 7
3438 [255]
3438 [255]
3439
3439
3440 Test word for integer literal
3440 Test word for integer literal
3441
3441
3442 $ hg log -R a --template "{word(2, desc)}\n" -r0
3442 $ hg log -R a --template "{word(2, desc)}\n" -r0
3443 line
3443 line
3444
3444
3445 Test word for invalid numbers
3445 Test word for invalid numbers
3446
3446
3447 $ hg log -Gv -R a --template "{word('a', desc)}"
3447 $ hg log -Gv -R a --template "{word('a', desc)}"
3448 hg: parse error: word expects an integer index
3448 hg: parse error: word expects an integer index
3449 [255]
3449 [255]
3450
3450
3451 Test word for out of range
3452
3453 $ hg log -R a --template "{word(10000, desc)}"
3454 $ hg log -R a --template "{word(-10000, desc)}"
3455
3451 Test indent and not adding to empty lines
3456 Test indent and not adding to empty lines
3452
3457
3453 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3458 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3454 -----
3459 -----
3455 > line 1
3460 > line 1
3456 >> line 2
3461 >> line 2
3457 -----
3462 -----
3458 > other 1
3463 > other 1
3459 >> other 2
3464 >> other 2
3460
3465
3461 >> other 3
3466 >> other 3
3462
3467
3463 Test with non-strings like dates
3468 Test with non-strings like dates
3464
3469
3465 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3470 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3466 1200000.00
3471 1200000.00
3467 1300000.00
3472 1300000.00
3468
3473
3469 Test broken string escapes:
3474 Test broken string escapes:
3470
3475
3471 $ hg log -T "bogus\\" -R a
3476 $ hg log -T "bogus\\" -R a
3472 hg: parse error: trailing \ in string
3477 hg: parse error: trailing \ in string
3473 [255]
3478 [255]
3474 $ hg log -T "\\xy" -R a
3479 $ hg log -T "\\xy" -R a
3475 hg: parse error: invalid \x escape
3480 hg: parse error: invalid \x escape
3476 [255]
3481 [255]
General Comments 0
You need to be logged in to leave comments. Login now