##// END OF EJS Templates
cmdutil: always expose "files_add", "files_del" and "manifest" templater properties
Patrick Mezard -
r5545:5a124ce4 default
parent child Browse files
Show More
@@ -1,944 +1,949 b''
1 1 # cmdutil.py - help for command processing in mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import *
9 9 from i18n import _
10 10 import os, sys, bisect, stat
11 11 import mdiff, bdiff, util, templater, patch
12 12
13 13 revrangesep = ':'
14 14
15 15 class UnknownCommand(Exception):
16 16 """Exception raised if command is not in the command table."""
17 17 class AmbiguousCommand(Exception):
18 18 """Exception raised if command shortcut matches more than one command."""
19 19
20 20 def findpossible(ui, cmd, table):
21 21 """
22 22 Return cmd -> (aliases, command table entry)
23 23 for each matching command.
24 24 Return debug commands (or their aliases) only if no normal command matches.
25 25 """
26 26 choice = {}
27 27 debugchoice = {}
28 28 for e in table.keys():
29 29 aliases = e.lstrip("^").split("|")
30 30 found = None
31 31 if cmd in aliases:
32 32 found = cmd
33 33 elif not ui.config("ui", "strict"):
34 34 for a in aliases:
35 35 if a.startswith(cmd):
36 36 found = a
37 37 break
38 38 if found is not None:
39 39 if aliases[0].startswith("debug") or found.startswith("debug"):
40 40 debugchoice[found] = (aliases, table[e])
41 41 else:
42 42 choice[found] = (aliases, table[e])
43 43
44 44 if not choice and debugchoice:
45 45 choice = debugchoice
46 46
47 47 return choice
48 48
49 49 def findcmd(ui, cmd, table):
50 50 """Return (aliases, command table entry) for command string."""
51 51 choice = findpossible(ui, cmd, table)
52 52
53 53 if choice.has_key(cmd):
54 54 return choice[cmd]
55 55
56 56 if len(choice) > 1:
57 57 clist = choice.keys()
58 58 clist.sort()
59 59 raise AmbiguousCommand(cmd, clist)
60 60
61 61 if choice:
62 62 return choice.values()[0]
63 63
64 64 raise UnknownCommand(cmd)
65 65
66 66 def bail_if_changed(repo):
67 67 modified, added, removed, deleted = repo.status()[:4]
68 68 if modified or added or removed or deleted:
69 69 raise util.Abort(_("outstanding uncommitted changes"))
70 70
71 71 def logmessage(opts):
72 72 """ get the log message according to -m and -l option """
73 73 message = opts['message']
74 74 logfile = opts['logfile']
75 75
76 76 if message and logfile:
77 77 raise util.Abort(_('options --message and --logfile are mutually '
78 78 'exclusive'))
79 79 if not message and logfile:
80 80 try:
81 81 if logfile == '-':
82 82 message = sys.stdin.read()
83 83 else:
84 84 message = open(logfile).read()
85 85 except IOError, inst:
86 86 raise util.Abort(_("can't read commit message '%s': %s") %
87 87 (logfile, inst.strerror))
88 88 return message
89 89
90 90 def setremoteconfig(ui, opts):
91 91 "copy remote options to ui tree"
92 92 if opts.get('ssh'):
93 93 ui.setconfig("ui", "ssh", opts['ssh'])
94 94 if opts.get('remotecmd'):
95 95 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
96 96
97 97 def revpair(repo, revs):
98 98 '''return pair of nodes, given list of revisions. second item can
99 99 be None, meaning use working dir.'''
100 100
101 101 def revfix(repo, val, defval):
102 102 if not val and val != 0 and defval is not None:
103 103 val = defval
104 104 return repo.lookup(val)
105 105
106 106 if not revs:
107 107 return repo.dirstate.parents()[0], None
108 108 end = None
109 109 if len(revs) == 1:
110 110 if revrangesep in revs[0]:
111 111 start, end = revs[0].split(revrangesep, 1)
112 112 start = revfix(repo, start, 0)
113 113 end = revfix(repo, end, repo.changelog.count() - 1)
114 114 else:
115 115 start = revfix(repo, revs[0], None)
116 116 elif len(revs) == 2:
117 117 if revrangesep in revs[0] or revrangesep in revs[1]:
118 118 raise util.Abort(_('too many revisions specified'))
119 119 start = revfix(repo, revs[0], None)
120 120 end = revfix(repo, revs[1], None)
121 121 else:
122 122 raise util.Abort(_('too many revisions specified'))
123 123 return start, end
124 124
125 125 def revrange(repo, revs):
126 126 """Yield revision as strings from a list of revision specifications."""
127 127
128 128 def revfix(repo, val, defval):
129 129 if not val and val != 0 and defval is not None:
130 130 return defval
131 131 return repo.changelog.rev(repo.lookup(val))
132 132
133 133 seen, l = {}, []
134 134 for spec in revs:
135 135 if revrangesep in spec:
136 136 start, end = spec.split(revrangesep, 1)
137 137 start = revfix(repo, start, 0)
138 138 end = revfix(repo, end, repo.changelog.count() - 1)
139 139 step = start > end and -1 or 1
140 140 for rev in xrange(start, end+step, step):
141 141 if rev in seen:
142 142 continue
143 143 seen[rev] = 1
144 144 l.append(rev)
145 145 else:
146 146 rev = revfix(repo, spec, None)
147 147 if rev in seen:
148 148 continue
149 149 seen[rev] = 1
150 150 l.append(rev)
151 151
152 152 return l
153 153
154 154 def make_filename(repo, pat, node,
155 155 total=None, seqno=None, revwidth=None, pathname=None):
156 156 node_expander = {
157 157 'H': lambda: hex(node),
158 158 'R': lambda: str(repo.changelog.rev(node)),
159 159 'h': lambda: short(node),
160 160 }
161 161 expander = {
162 162 '%': lambda: '%',
163 163 'b': lambda: os.path.basename(repo.root),
164 164 }
165 165
166 166 try:
167 167 if node:
168 168 expander.update(node_expander)
169 169 if node:
170 170 expander['r'] = (lambda:
171 171 str(repo.changelog.rev(node)).zfill(revwidth or 0))
172 172 if total is not None:
173 173 expander['N'] = lambda: str(total)
174 174 if seqno is not None:
175 175 expander['n'] = lambda: str(seqno)
176 176 if total is not None and seqno is not None:
177 177 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
178 178 if pathname is not None:
179 179 expander['s'] = lambda: os.path.basename(pathname)
180 180 expander['d'] = lambda: os.path.dirname(pathname) or '.'
181 181 expander['p'] = lambda: pathname
182 182
183 183 newname = []
184 184 patlen = len(pat)
185 185 i = 0
186 186 while i < patlen:
187 187 c = pat[i]
188 188 if c == '%':
189 189 i += 1
190 190 c = pat[i]
191 191 c = expander[c]()
192 192 newname.append(c)
193 193 i += 1
194 194 return ''.join(newname)
195 195 except KeyError, inst:
196 196 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
197 197 inst.args[0])
198 198
199 199 def make_file(repo, pat, node=None,
200 200 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
201 201 if not pat or pat == '-':
202 202 return 'w' in mode and sys.stdout or sys.stdin
203 203 if hasattr(pat, 'write') and 'w' in mode:
204 204 return pat
205 205 if hasattr(pat, 'read') and 'r' in mode:
206 206 return pat
207 207 return open(make_filename(repo, pat, node, total, seqno, revwidth,
208 208 pathname),
209 209 mode)
210 210
211 211 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
212 212 cwd = repo.getcwd()
213 213 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
214 214 opts.get('exclude'), globbed=globbed,
215 215 default=default)
216 216
217 217 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
218 218 default=None):
219 219 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
220 220 default=default)
221 221 exact = dict.fromkeys(files)
222 222 cwd = repo.getcwd()
223 223 for src, fn in repo.walk(node=node, files=files, match=matchfn,
224 224 badmatch=badmatch):
225 225 yield src, fn, repo.pathto(fn, cwd), fn in exact
226 226
227 227 def findrenames(repo, added=None, removed=None, threshold=0.5):
228 228 '''find renamed files -- yields (before, after, score) tuples'''
229 229 if added is None or removed is None:
230 230 added, removed = repo.status()[1:3]
231 231 ctx = repo.changectx()
232 232 for a in added:
233 233 aa = repo.wread(a)
234 234 bestname, bestscore = None, threshold
235 235 for r in removed:
236 236 rr = ctx.filectx(r).data()
237 237
238 238 # bdiff.blocks() returns blocks of matching lines
239 239 # count the number of bytes in each
240 240 equal = 0
241 241 alines = mdiff.splitnewlines(aa)
242 242 matches = bdiff.blocks(aa, rr)
243 243 for x1,x2,y1,y2 in matches:
244 244 for line in alines[x1:x2]:
245 245 equal += len(line)
246 246
247 247 lengths = len(aa) + len(rr)
248 248 if lengths:
249 249 myscore = equal*2.0 / lengths
250 250 if myscore >= bestscore:
251 251 bestname, bestscore = r, myscore
252 252 if bestname:
253 253 yield bestname, a, bestscore
254 254
255 255 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
256 256 if dry_run is None:
257 257 dry_run = opts.get('dry_run')
258 258 if similarity is None:
259 259 similarity = float(opts.get('similarity') or 0)
260 260 add, remove = [], []
261 261 mapping = {}
262 262 for src, abs, rel, exact in walk(repo, pats, opts):
263 263 target = repo.wjoin(abs)
264 264 if src == 'f' and abs not in repo.dirstate:
265 265 add.append(abs)
266 266 mapping[abs] = rel, exact
267 267 if repo.ui.verbose or not exact:
268 268 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
269 269 if repo.dirstate[abs] != 'r' and (not util.lexists(target)
270 270 or (os.path.isdir(target) and not os.path.islink(target))):
271 271 remove.append(abs)
272 272 mapping[abs] = rel, exact
273 273 if repo.ui.verbose or not exact:
274 274 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
275 275 if not dry_run:
276 276 repo.remove(remove)
277 277 repo.add(add)
278 278 if similarity > 0:
279 279 for old, new, score in findrenames(repo, add, remove, similarity):
280 280 oldrel, oldexact = mapping[old]
281 281 newrel, newexact = mapping[new]
282 282 if repo.ui.verbose or not oldexact or not newexact:
283 283 repo.ui.status(_('recording removal of %s as rename to %s '
284 284 '(%d%% similar)\n') %
285 285 (oldrel, newrel, score * 100))
286 286 if not dry_run:
287 287 repo.copy(old, new)
288 288
289 289 def service(opts, parentfn=None, initfn=None, runfn=None):
290 290 '''Run a command as a service.'''
291 291
292 292 if opts['daemon'] and not opts['daemon_pipefds']:
293 293 rfd, wfd = os.pipe()
294 294 args = sys.argv[:]
295 295 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
296 296 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
297 297 args[0], args)
298 298 os.close(wfd)
299 299 os.read(rfd, 1)
300 300 if parentfn:
301 301 return parentfn(pid)
302 302 else:
303 303 os._exit(0)
304 304
305 305 if initfn:
306 306 initfn()
307 307
308 308 if opts['pid_file']:
309 309 fp = open(opts['pid_file'], 'w')
310 310 fp.write(str(os.getpid()) + '\n')
311 311 fp.close()
312 312
313 313 if opts['daemon_pipefds']:
314 314 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
315 315 os.close(rfd)
316 316 try:
317 317 os.setsid()
318 318 except AttributeError:
319 319 pass
320 320 os.write(wfd, 'y')
321 321 os.close(wfd)
322 322 sys.stdout.flush()
323 323 sys.stderr.flush()
324 324 fd = os.open(util.nulldev, os.O_RDWR)
325 325 if fd != 0: os.dup2(fd, 0)
326 326 if fd != 1: os.dup2(fd, 1)
327 327 if fd != 2: os.dup2(fd, 2)
328 328 if fd not in (0, 1, 2): os.close(fd)
329 329
330 330 if runfn:
331 331 return runfn()
332 332
333 333 class changeset_printer(object):
334 334 '''show changeset information when templating not requested.'''
335 335
336 336 def __init__(self, ui, repo, patch, buffered):
337 337 self.ui = ui
338 338 self.repo = repo
339 339 self.buffered = buffered
340 340 self.patch = patch
341 341 self.header = {}
342 342 self.hunk = {}
343 343 self.lastheader = None
344 344
345 345 def flush(self, rev):
346 346 if rev in self.header:
347 347 h = self.header[rev]
348 348 if h != self.lastheader:
349 349 self.lastheader = h
350 350 self.ui.write(h)
351 351 del self.header[rev]
352 352 if rev in self.hunk:
353 353 self.ui.write(self.hunk[rev])
354 354 del self.hunk[rev]
355 355 return 1
356 356 return 0
357 357
358 358 def show(self, rev=0, changenode=None, copies=(), **props):
359 359 if self.buffered:
360 360 self.ui.pushbuffer()
361 361 self._show(rev, changenode, copies, props)
362 362 self.hunk[rev] = self.ui.popbuffer()
363 363 else:
364 364 self._show(rev, changenode, copies, props)
365 365
366 366 def _show(self, rev, changenode, copies, props):
367 367 '''show a single changeset or file revision'''
368 368 log = self.repo.changelog
369 369 if changenode is None:
370 370 changenode = log.node(rev)
371 371 elif not rev:
372 372 rev = log.rev(changenode)
373 373
374 374 if self.ui.quiet:
375 375 self.ui.write("%d:%s\n" % (rev, short(changenode)))
376 376 return
377 377
378 378 changes = log.read(changenode)
379 379 date = util.datestr(changes[2])
380 380 extra = changes[5]
381 381 branch = extra.get("branch")
382 382
383 383 hexfunc = self.ui.debugflag and hex or short
384 384
385 385 parents = [(p, hexfunc(log.node(p)))
386 386 for p in self._meaningful_parentrevs(log, rev)]
387 387
388 388 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
389 389
390 390 # don't show the default branch name
391 391 if branch != 'default':
392 392 branch = util.tolocal(branch)
393 393 self.ui.write(_("branch: %s\n") % branch)
394 394 for tag in self.repo.nodetags(changenode):
395 395 self.ui.write(_("tag: %s\n") % tag)
396 396 for parent in parents:
397 397 self.ui.write(_("parent: %d:%s\n") % parent)
398 398
399 399 if self.ui.debugflag:
400 400 self.ui.write(_("manifest: %d:%s\n") %
401 401 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
402 402 self.ui.write(_("user: %s\n") % changes[1])
403 403 self.ui.write(_("date: %s\n") % date)
404 404
405 405 if self.ui.debugflag:
406 406 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
407 407 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
408 408 files):
409 409 if value:
410 410 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
411 411 elif changes[3] and self.ui.verbose:
412 412 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
413 413 if copies and self.ui.verbose:
414 414 copies = ['%s (%s)' % c for c in copies]
415 415 self.ui.write(_("copies: %s\n") % ' '.join(copies))
416 416
417 417 if extra and self.ui.debugflag:
418 418 extraitems = extra.items()
419 419 extraitems.sort()
420 420 for key, value in extraitems:
421 421 self.ui.write(_("extra: %s=%s\n")
422 422 % (key, value.encode('string_escape')))
423 423
424 424 description = changes[4].strip()
425 425 if description:
426 426 if self.ui.verbose:
427 427 self.ui.write(_("description:\n"))
428 428 self.ui.write(description)
429 429 self.ui.write("\n\n")
430 430 else:
431 431 self.ui.write(_("summary: %s\n") %
432 432 description.splitlines()[0])
433 433 self.ui.write("\n")
434 434
435 435 self.showpatch(changenode)
436 436
437 437 def showpatch(self, node):
438 438 if self.patch:
439 439 prev = self.repo.changelog.parents(node)[0]
440 440 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui,
441 441 opts=patch.diffopts(self.ui))
442 442 self.ui.write("\n")
443 443
444 444 def _meaningful_parentrevs(self, log, rev):
445 445 """Return list of meaningful (or all if debug) parentrevs for rev.
446 446
447 447 For merges (two non-nullrev revisions) both parents are meaningful.
448 448 Otherwise the first parent revision is considered meaningful if it
449 449 is not the preceding revision.
450 450 """
451 451 parents = log.parentrevs(rev)
452 452 if not self.ui.debugflag and parents[1] == nullrev:
453 453 if parents[0] >= rev - 1:
454 454 parents = []
455 455 else:
456 456 parents = [parents[0]]
457 457 return parents
458 458
459 459
460 460 class changeset_templater(changeset_printer):
461 461 '''format changeset information.'''
462 462
463 463 def __init__(self, ui, repo, patch, mapfile, buffered):
464 464 changeset_printer.__init__(self, ui, repo, patch, buffered)
465 465 filters = templater.common_filters.copy()
466 466 filters['formatnode'] = (ui.debugflag and (lambda x: x)
467 467 or (lambda x: x[:12]))
468 468 self.t = templater.templater(mapfile, filters,
469 469 cache={
470 470 'parent': '{rev}:{node|formatnode} ',
471 471 'manifest': '{rev}:{node|formatnode}',
472 472 'filecopy': '{name} ({source})'})
473 473
474 474 def use_template(self, t):
475 475 '''set template string to use'''
476 476 self.t.cache['changeset'] = t
477 477
478 478 def _show(self, rev, changenode, copies, props):
479 479 '''show a single changeset or file revision'''
480 480 log = self.repo.changelog
481 481 if changenode is None:
482 482 changenode = log.node(rev)
483 483 elif not rev:
484 484 rev = log.rev(changenode)
485 485
486 486 changes = log.read(changenode)
487 487
488 488 def showlist(name, values, plural=None, **args):
489 489 '''expand set of values.
490 490 name is name of key in template map.
491 491 values is list of strings or dicts.
492 492 plural is plural of name, if not simply name + 's'.
493 493
494 494 expansion works like this, given name 'foo'.
495 495
496 496 if values is empty, expand 'no_foos'.
497 497
498 498 if 'foo' not in template map, return values as a string,
499 499 joined by space.
500 500
501 501 expand 'start_foos'.
502 502
503 503 for each value, expand 'foo'. if 'last_foo' in template
504 504 map, expand it instead of 'foo' for last key.
505 505
506 506 expand 'end_foos'.
507 507 '''
508 508 if plural: names = plural
509 509 else: names = name + 's'
510 510 if not values:
511 511 noname = 'no_' + names
512 512 if noname in self.t:
513 513 yield self.t(noname, **args)
514 514 return
515 515 if name not in self.t:
516 516 if isinstance(values[0], str):
517 517 yield ' '.join(values)
518 518 else:
519 519 for v in values:
520 520 yield dict(v, **args)
521 521 return
522 522 startname = 'start_' + names
523 523 if startname in self.t:
524 524 yield self.t(startname, **args)
525 525 vargs = args.copy()
526 526 def one(v, tag=name):
527 527 try:
528 528 vargs.update(v)
529 529 except (AttributeError, ValueError):
530 530 try:
531 531 for a, b in v:
532 532 vargs[a] = b
533 533 except ValueError:
534 534 vargs[name] = v
535 535 return self.t(tag, **vargs)
536 536 lastname = 'last_' + name
537 537 if lastname in self.t:
538 538 last = values.pop()
539 539 else:
540 540 last = None
541 541 for v in values:
542 542 yield one(v)
543 543 if last is not None:
544 544 yield one(last, tag=lastname)
545 545 endname = 'end_' + names
546 546 if endname in self.t:
547 547 yield self.t(endname, **args)
548 548
549 549 def showbranches(**args):
550 550 branch = changes[5].get("branch")
551 551 if branch != 'default':
552 552 branch = util.tolocal(branch)
553 553 return showlist('branch', [branch], plural='branches', **args)
554 554
555 555 def showparents(**args):
556 556 parents = [[('rev', p), ('node', hex(log.node(p)))]
557 557 for p in self._meaningful_parentrevs(log, rev)]
558 558 return showlist('parent', parents, **args)
559 559
560 560 def showtags(**args):
561 561 return showlist('tag', self.repo.nodetags(changenode), **args)
562 562
563 563 def showextras(**args):
564 564 extras = changes[5].items()
565 565 extras.sort()
566 566 for key, value in extras:
567 567 args = args.copy()
568 568 args.update(dict(key=key, value=value))
569 569 yield self.t('extra', **args)
570 570
571 571 def showcopies(**args):
572 572 c = [{'name': x[0], 'source': x[1]} for x in copies]
573 573 return showlist('file_copy', c, plural='file_copies', **args)
574
574
575 files = []
576 def getfiles():
577 if not files:
578 files[:] = self.repo.status(
579 log.parents(changenode)[0], changenode)[:3]
580 return files
581 # XXX: "files" means "modified files" in debug, "all changed
582 # files" otherwise. This should be fixed and a "file_mods" be
583 # introduced instead.
575 584 if self.ui.debugflag:
576 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
577 585 def showfiles(**args):
578 return showlist('file', files[0], **args)
579 def showadds(**args):
580 return showlist('file_add', files[1], **args)
581 def showdels(**args):
582 return showlist('file_del', files[2], **args)
583 def showmanifest(**args):
584 args = args.copy()
585 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
586 node=hex(changes[0])))
587 return self.t('manifest', **args)
586 return showlist('file', getfiles()[0], **args)
588 587 else:
589 588 def showfiles(**args):
590 589 return showlist('file', changes[3], **args)
591 showadds = ''
592 showdels = ''
593 showmanifest = ''
590 def showadds(**args):
591 return showlist('file_add', getfiles()[1], **args)
592 def showdels(**args):
593 return showlist('file_del', getfiles()[2], **args)
594 def showmanifest(**args):
595 args = args.copy()
596 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
597 node=hex(changes[0])))
598 return self.t('manifest', **args)
594 599
595 600 defprops = {
596 601 'author': changes[1],
597 602 'branches': showbranches,
598 603 'date': changes[2],
599 604 'desc': changes[4].strip(),
600 605 'file_adds': showadds,
601 606 'file_dels': showdels,
602 607 'files': showfiles,
603 608 'file_copies': showcopies,
604 609 'manifest': showmanifest,
605 610 'node': hex(changenode),
606 611 'parents': showparents,
607 612 'rev': rev,
608 613 'tags': showtags,
609 614 'extras': showextras,
610 615 }
611 616 props = props.copy()
612 617 props.update(defprops)
613 618
614 619 try:
615 620 if self.ui.debugflag and 'header_debug' in self.t:
616 621 key = 'header_debug'
617 622 elif self.ui.quiet and 'header_quiet' in self.t:
618 623 key = 'header_quiet'
619 624 elif self.ui.verbose and 'header_verbose' in self.t:
620 625 key = 'header_verbose'
621 626 elif 'header' in self.t:
622 627 key = 'header'
623 628 else:
624 629 key = ''
625 630 if key:
626 631 h = templater.stringify(self.t(key, **props))
627 632 if self.buffered:
628 633 self.header[rev] = h
629 634 else:
630 635 self.ui.write(h)
631 636 if self.ui.debugflag and 'changeset_debug' in self.t:
632 637 key = 'changeset_debug'
633 638 elif self.ui.quiet and 'changeset_quiet' in self.t:
634 639 key = 'changeset_quiet'
635 640 elif self.ui.verbose and 'changeset_verbose' in self.t:
636 641 key = 'changeset_verbose'
637 642 else:
638 643 key = 'changeset'
639 644 self.ui.write(templater.stringify(self.t(key, **props)))
640 645 self.showpatch(changenode)
641 646 except KeyError, inst:
642 647 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
643 648 inst.args[0]))
644 649 except SyntaxError, inst:
645 650 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
646 651
647 652 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
648 653 """show one changeset using template or regular display.
649 654
650 655 Display format will be the first non-empty hit of:
651 656 1. option 'template'
652 657 2. option 'style'
653 658 3. [ui] setting 'logtemplate'
654 659 4. [ui] setting 'style'
655 660 If all of these values are either the unset or the empty string,
656 661 regular display via changeset_printer() is done.
657 662 """
658 663 # options
659 664 patch = False
660 665 if opts.get('patch'):
661 666 patch = matchfn or util.always
662 667
663 668 tmpl = opts.get('template')
664 669 mapfile = None
665 670 if tmpl:
666 671 tmpl = templater.parsestring(tmpl, quoted=False)
667 672 else:
668 673 mapfile = opts.get('style')
669 674 # ui settings
670 675 if not mapfile:
671 676 tmpl = ui.config('ui', 'logtemplate')
672 677 if tmpl:
673 678 tmpl = templater.parsestring(tmpl)
674 679 else:
675 680 mapfile = ui.config('ui', 'style')
676 681
677 682 if tmpl or mapfile:
678 683 if mapfile:
679 684 if not os.path.split(mapfile)[0]:
680 685 mapname = (templater.templatepath('map-cmdline.' + mapfile)
681 686 or templater.templatepath(mapfile))
682 687 if mapname: mapfile = mapname
683 688 try:
684 689 t = changeset_templater(ui, repo, patch, mapfile, buffered)
685 690 except SyntaxError, inst:
686 691 raise util.Abort(inst.args[0])
687 692 if tmpl: t.use_template(tmpl)
688 693 return t
689 694 return changeset_printer(ui, repo, patch, buffered)
690 695
691 696 def finddate(ui, repo, date):
692 697 """Find the tipmost changeset that matches the given date spec"""
693 698 df = util.matchdate(date + " to " + date)
694 699 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
695 700 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
696 701 results = {}
697 702 for st, rev, fns in changeiter:
698 703 if st == 'add':
699 704 d = get(rev)[2]
700 705 if df(d[0]):
701 706 results[rev] = d
702 707 elif st == 'iter':
703 708 if rev in results:
704 709 ui.status("Found revision %s from %s\n" %
705 710 (rev, util.datestr(results[rev])))
706 711 return str(rev)
707 712
708 713 raise util.Abort(_("revision matching date not found"))
709 714
710 715 def walkchangerevs(ui, repo, pats, change, opts):
711 716 '''Iterate over files and the revs they changed in.
712 717
713 718 Callers most commonly need to iterate backwards over the history
714 719 it is interested in. Doing so has awful (quadratic-looking)
715 720 performance, so we use iterators in a "windowed" way.
716 721
717 722 We walk a window of revisions in the desired order. Within the
718 723 window, we first walk forwards to gather data, then in the desired
719 724 order (usually backwards) to display it.
720 725
721 726 This function returns an (iterator, matchfn) tuple. The iterator
722 727 yields 3-tuples. They will be of one of the following forms:
723 728
724 729 "window", incrementing, lastrev: stepping through a window,
725 730 positive if walking forwards through revs, last rev in the
726 731 sequence iterated over - use to reset state for the current window
727 732
728 733 "add", rev, fns: out-of-order traversal of the given file names
729 734 fns, which changed during revision rev - use to gather data for
730 735 possible display
731 736
732 737 "iter", rev, None: in-order traversal of the revs earlier iterated
733 738 over with "add" - use to display data'''
734 739
735 740 def increasing_windows(start, end, windowsize=8, sizelimit=512):
736 741 if start < end:
737 742 while start < end:
738 743 yield start, min(windowsize, end-start)
739 744 start += windowsize
740 745 if windowsize < sizelimit:
741 746 windowsize *= 2
742 747 else:
743 748 while start > end:
744 749 yield start, min(windowsize, start-end-1)
745 750 start -= windowsize
746 751 if windowsize < sizelimit:
747 752 windowsize *= 2
748 753
749 754 files, matchfn, anypats = matchpats(repo, pats, opts)
750 755 follow = opts.get('follow') or opts.get('follow_first')
751 756
752 757 if repo.changelog.count() == 0:
753 758 return [], matchfn
754 759
755 760 if follow:
756 761 defrange = '%s:0' % repo.changectx().rev()
757 762 else:
758 763 defrange = 'tip:0'
759 764 revs = revrange(repo, opts['rev'] or [defrange])
760 765 wanted = {}
761 766 slowpath = anypats or opts.get('removed')
762 767 fncache = {}
763 768
764 769 if not slowpath and not files:
765 770 # No files, no patterns. Display all revs.
766 771 wanted = dict.fromkeys(revs)
767 772 copies = []
768 773 if not slowpath:
769 774 # Only files, no patterns. Check the history of each file.
770 775 def filerevgen(filelog, node):
771 776 cl_count = repo.changelog.count()
772 777 if node is None:
773 778 last = filelog.count() - 1
774 779 else:
775 780 last = filelog.rev(node)
776 781 for i, window in increasing_windows(last, nullrev):
777 782 revs = []
778 783 for j in xrange(i - window, i + 1):
779 784 n = filelog.node(j)
780 785 revs.append((filelog.linkrev(n),
781 786 follow and filelog.renamed(n)))
782 787 revs.reverse()
783 788 for rev in revs:
784 789 # only yield rev for which we have the changelog, it can
785 790 # happen while doing "hg log" during a pull or commit
786 791 if rev[0] < cl_count:
787 792 yield rev
788 793 def iterfiles():
789 794 for filename in files:
790 795 yield filename, None
791 796 for filename_node in copies:
792 797 yield filename_node
793 798 minrev, maxrev = min(revs), max(revs)
794 799 for file_, node in iterfiles():
795 800 filelog = repo.file(file_)
796 801 # A zero count may be a directory or deleted file, so
797 802 # try to find matching entries on the slow path.
798 803 if filelog.count() == 0:
799 804 slowpath = True
800 805 break
801 806 for rev, copied in filerevgen(filelog, node):
802 807 if rev <= maxrev:
803 808 if rev < minrev:
804 809 break
805 810 fncache.setdefault(rev, [])
806 811 fncache[rev].append(file_)
807 812 wanted[rev] = 1
808 813 if follow and copied:
809 814 copies.append(copied)
810 815 if slowpath:
811 816 if follow:
812 817 raise util.Abort(_('can only follow copies/renames for explicit '
813 818 'file names'))
814 819
815 820 # The slow path checks files modified in every changeset.
816 821 def changerevgen():
817 822 for i, window in increasing_windows(repo.changelog.count()-1,
818 823 nullrev):
819 824 for j in xrange(i - window, i + 1):
820 825 yield j, change(j)[3]
821 826
822 827 for rev, changefiles in changerevgen():
823 828 matches = filter(matchfn, changefiles)
824 829 if matches:
825 830 fncache[rev] = matches
826 831 wanted[rev] = 1
827 832
828 833 class followfilter:
829 834 def __init__(self, onlyfirst=False):
830 835 self.startrev = nullrev
831 836 self.roots = []
832 837 self.onlyfirst = onlyfirst
833 838
834 839 def match(self, rev):
835 840 def realparents(rev):
836 841 if self.onlyfirst:
837 842 return repo.changelog.parentrevs(rev)[0:1]
838 843 else:
839 844 return filter(lambda x: x != nullrev,
840 845 repo.changelog.parentrevs(rev))
841 846
842 847 if self.startrev == nullrev:
843 848 self.startrev = rev
844 849 return True
845 850
846 851 if rev > self.startrev:
847 852 # forward: all descendants
848 853 if not self.roots:
849 854 self.roots.append(self.startrev)
850 855 for parent in realparents(rev):
851 856 if parent in self.roots:
852 857 self.roots.append(rev)
853 858 return True
854 859 else:
855 860 # backwards: all parents
856 861 if not self.roots:
857 862 self.roots.extend(realparents(self.startrev))
858 863 if rev in self.roots:
859 864 self.roots.remove(rev)
860 865 self.roots.extend(realparents(rev))
861 866 return True
862 867
863 868 return False
864 869
865 870 # it might be worthwhile to do this in the iterator if the rev range
866 871 # is descending and the prune args are all within that range
867 872 for rev in opts.get('prune', ()):
868 873 rev = repo.changelog.rev(repo.lookup(rev))
869 874 ff = followfilter()
870 875 stop = min(revs[0], revs[-1])
871 876 for x in xrange(rev, stop-1, -1):
872 877 if ff.match(x) and x in wanted:
873 878 del wanted[x]
874 879
875 880 def iterate():
876 881 if follow and not files:
877 882 ff = followfilter(onlyfirst=opts.get('follow_first'))
878 883 def want(rev):
879 884 if ff.match(rev) and rev in wanted:
880 885 return True
881 886 return False
882 887 else:
883 888 def want(rev):
884 889 return rev in wanted
885 890
886 891 for i, window in increasing_windows(0, len(revs)):
887 892 yield 'window', revs[0] < revs[-1], revs[-1]
888 893 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
889 894 srevs = list(nrevs)
890 895 srevs.sort()
891 896 for rev in srevs:
892 897 fns = fncache.get(rev)
893 898 if not fns:
894 899 def fns_generator():
895 900 for f in change(rev)[3]:
896 901 if matchfn(f):
897 902 yield f
898 903 fns = fns_generator()
899 904 yield 'add', rev, fns
900 905 for rev in nrevs:
901 906 yield 'iter', rev, None
902 907 return iterate(), matchfn
903 908
904 909 def commit(ui, repo, commitfunc, pats, opts):
905 910 '''commit the specified files or all outstanding changes'''
906 911 message = logmessage(opts)
907 912
908 913 if opts['addremove']:
909 914 addremove(repo, pats, opts)
910 915 fns, match, anypats = matchpats(repo, pats, opts)
911 916 if pats:
912 917 status = repo.status(files=fns, match=match)
913 918 modified, added, removed, deleted, unknown = status[:5]
914 919 files = modified + added + removed
915 920 slist = None
916 921 for f in fns:
917 922 if f == '.':
918 923 continue
919 924 if f not in files:
920 925 rf = repo.wjoin(f)
921 926 try:
922 927 mode = os.lstat(rf)[stat.ST_MODE]
923 928 except OSError:
924 929 raise util.Abort(_("file %s not found!") % rf)
925 930 if stat.S_ISDIR(mode):
926 931 name = f + '/'
927 932 if slist is None:
928 933 slist = list(files)
929 934 slist.sort()
930 935 i = bisect.bisect(slist, name)
931 936 if i >= len(slist) or not slist[i].startswith(name):
932 937 raise util.Abort(_("no match under directory %s!")
933 938 % rf)
934 939 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
935 940 raise util.Abort(_("can't commit %s: "
936 941 "unsupported file type!") % rf)
937 942 elif f not in repo.dirstate:
938 943 raise util.Abort(_("file %s not tracked!") % rf)
939 944 else:
940 945 files = []
941 946 try:
942 947 return commitfunc(ui, repo, files, message, match, opts)
943 948 except ValueError, inst:
944 949 raise util.Abort(str(inst))
@@ -1,21 +1,21 b''
1 1 changeset = 'changeset: {rev}:{node|short}\n{branches}{tags}{parents}user: {author}\ndate: {date|date}\nsummary: {desc|firstline}\n\n'
2 2 changeset_quiet = '{rev}:{node|short}\n'
3 changeset_verbose = 'changeset: {rev}:{node|short}\n{branches}{tags}{parents}{manifest}user: {author}\ndate: {date|date}\n{files}{file_adds}{file_dels}{file_copies}description:\n{desc|strip}\n\n\n'
3 changeset_verbose = 'changeset: {rev}:{node|short}\n{branches}{tags}{parents}user: {author}\ndate: {date|date}\n{files}{file_copies}description:\n{desc|strip}\n\n\n'
4 4 changeset_debug = 'changeset: {rev}:{node}\n{branches}{tags}{parents}{manifest}user: {author}\ndate: {date|date}\n{files}{file_adds}{file_dels}{file_copies}{extras}description:\n{desc|strip}\n\n\n'
5 5 start_files = 'files: '
6 6 file = ' {file}'
7 7 end_files = '\n'
8 8 start_file_adds = 'files+: '
9 9 file_add = ' {file_add}'
10 10 end_file_adds = '\n'
11 11 start_file_dels = 'files-: '
12 12 file_del = ' {file_del}'
13 13 end_file_dels = '\n'
14 14 start_file_copies = 'copies: '
15 15 file_copy = ' {name} ({source})'
16 16 end_file_copies = '\n'
17 17 parent = 'parent: {rev}:{node|formatnode}\n'
18 18 manifest = 'manifest: {rev}:{node}\n'
19 19 branch = 'branch: {branch}\n'
20 20 tag = 'tag: {tag}\n'
21 21 extra = 'extra: {key}={value|stringescape}\n'
@@ -1,531 +1,531 b''
1 1 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
2 2 # default style is like normal output
3 3 # normal
4 4 # verbose
5 5 # debug
6 6 # revision with no copies (used to print a traceback)
7 7
8 8 # compact style works
9 9 7[tip]:-1 29114dbae42b 1970-01-12 13:46 +0000 user
10 10 second
11 11
12 12 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
13 13 merge
14 14
15 15 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
16 16 new head
17 17
18 18 4 32a18f097fcc 1970-01-17 04:53 +0000 person
19 19 new branch
20 20
21 21 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
22 22 no user, no domain
23 23
24 24 2 97054abb4ab8 1970-01-14 21:20 +0000 other
25 25 no person
26 26
27 27 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
28 28 other 1
29 29
30 30 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
31 31 line 1
32 32
33 33 7[tip]:-1 29114dbae42b 1970-01-12 13:46 +0000 user
34 34 second
35 35
36 36 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
37 37 merge
38 38
39 39 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
40 40 new head
41 41
42 42 4 32a18f097fcc 1970-01-17 04:53 +0000 person
43 43 new branch
44 44
45 45 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
46 46 no user, no domain
47 47
48 48 2 97054abb4ab8 1970-01-14 21:20 +0000 other
49 49 no person
50 50
51 51 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
52 52 other 1
53 53
54 54 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
55 55 line 1
56 56
57 57 7[tip]:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 user
58 58 second
59 59
60 60 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
61 61 merge
62 62
63 63 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
64 64 new head
65 65
66 66 4:3,-1 32a18f097fcc 1970-01-17 04:53 +0000 person
67 67 new branch
68 68
69 69 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
70 70 no user, no domain
71 71
72 72 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other
73 73 no person
74 74
75 75 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
76 76 other 1
77 77
78 78 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
79 79 line 1
80 80
81 81 # error if style not readable
82 82 abort: Permission denied: ./q
83 83 # error if no style
84 84 abort: No such file or directory: notexist
85 85 # error if style missing key
86 86 abort: ./t: no key named 'changeset'
87 87 # error if include fails
88 88 abort: template file ./q: Permission denied
89 89 # include works
90 90 7
91 91 6
92 92 5
93 93 4
94 94 3
95 95 2
96 96 1
97 97 0
98 98 # ui.style works
99 99 7
100 100 6
101 101 5
102 102 4
103 103 3
104 104 2
105 105 1
106 106 0
107 107 # issue338
108 108 1970-01-12 User Name <user@hostname>
109 109
110 110 * second:
111 111 second
112 112 [29114dbae42b] [tip]
113 113
114 114 1970-01-18 person <person>
115 115
116 116 * merge
117 117 [c7b487c6c50e]
118 118
119 119 * d:
120 120 new head
121 121 [13207e5a10d9]
122 122
123 123 1970-01-17 person <person>
124 124
125 125 * new branch
126 126 [32a18f097fcc]
127 127
128 128 1970-01-16 person <person>
129 129
130 130 * c:
131 131 no user, no domain
132 132 [10e46f2dcbf4]
133 133
134 134 1970-01-14 other <other@place>
135 135
136 136 * c:
137 137 no person
138 138 [97054abb4ab8]
139 139
140 140 1970-01-13 A. N. Other <other@place>
141 141
142 142 * b:
143 143 other 1 other 2
144 144
145 145 other 3
146 146 [b608e9d1a3f0]
147 147
148 148 1970-01-12 User Name <user@hostname>
149 149
150 150 * a:
151 151 line 1 line 2
152 152 [1e4e1b8f71e0]
153 153
154 154 # keys work
155 155 author: User Name <user@hostname>
156 156 author: person
157 157 author: person
158 158 author: person
159 159 author: person
160 160 author: other@place
161 161 author: A. N. Other <other@place>
162 162 author: User Name <user@hostname>
163 163 author--verbose: User Name <user@hostname>
164 164 author--verbose: person
165 165 author--verbose: person
166 166 author--verbose: person
167 167 author--verbose: person
168 168 author--verbose: other@place
169 169 author--verbose: A. N. Other <other@place>
170 170 author--verbose: User Name <user@hostname>
171 171 author--debug: User Name <user@hostname>
172 172 author--debug: person
173 173 author--debug: person
174 174 author--debug: person
175 175 author--debug: person
176 176 author--debug: other@place
177 177 author--debug: A. N. Other <other@place>
178 178 author--debug: User Name <user@hostname>
179 179 branches:
180 180 branches:
181 181 branches:
182 182 branches: foo
183 183 branches:
184 184 branches:
185 185 branches:
186 186 branches:
187 187 branches--verbose:
188 188 branches--verbose:
189 189 branches--verbose:
190 190 branches--verbose: foo
191 191 branches--verbose:
192 192 branches--verbose:
193 193 branches--verbose:
194 194 branches--verbose:
195 195 branches--debug:
196 196 branches--debug:
197 197 branches--debug:
198 198 branches--debug: foo
199 199 branches--debug:
200 200 branches--debug:
201 201 branches--debug:
202 202 branches--debug:
203 203 date: 1000000.00
204 204 date: 1500001.00
205 205 date: 1500000.00
206 206 date: 1400000.00
207 207 date: 1300000.00
208 208 date: 1200000.00
209 209 date: 1100000.00
210 210 date: 1000000.00
211 211 date--verbose: 1000000.00
212 212 date--verbose: 1500001.00
213 213 date--verbose: 1500000.00
214 214 date--verbose: 1400000.00
215 215 date--verbose: 1300000.00
216 216 date--verbose: 1200000.00
217 217 date--verbose: 1100000.00
218 218 date--verbose: 1000000.00
219 219 date--debug: 1000000.00
220 220 date--debug: 1500001.00
221 221 date--debug: 1500000.00
222 222 date--debug: 1400000.00
223 223 date--debug: 1300000.00
224 224 date--debug: 1200000.00
225 225 date--debug: 1100000.00
226 226 date--debug: 1000000.00
227 227 desc: second
228 228 desc: merge
229 229 desc: new head
230 230 desc: new branch
231 231 desc: no user, no domain
232 232 desc: no person
233 233 desc: other 1
234 234 other 2
235 235
236 236 other 3
237 237 desc: line 1
238 238 line 2
239 239 desc--verbose: second
240 240 desc--verbose: merge
241 241 desc--verbose: new head
242 242 desc--verbose: new branch
243 243 desc--verbose: no user, no domain
244 244 desc--verbose: no person
245 245 desc--verbose: other 1
246 246 other 2
247 247
248 248 other 3
249 249 desc--verbose: line 1
250 250 line 2
251 251 desc--debug: second
252 252 desc--debug: merge
253 253 desc--debug: new head
254 254 desc--debug: new branch
255 255 desc--debug: no user, no domain
256 256 desc--debug: no person
257 257 desc--debug: other 1
258 258 other 2
259 259
260 260 other 3
261 261 desc--debug: line 1
262 262 line 2
263 file_adds:
264 file_adds:
263 file_adds: second
265 264 file_adds:
266 file_adds:
267 file_adds:
268 file_adds:
265 file_adds: d
269 266 file_adds:
270 267 file_adds:
268 file_adds: c
269 file_adds: b
270 file_adds: a
271 file_adds--verbose: second
271 272 file_adds--verbose:
272 file_adds--verbose:
273 file_adds--verbose: d
273 274 file_adds--verbose:
274 275 file_adds--verbose:
275 file_adds--verbose:
276 file_adds--verbose:
277 file_adds--verbose:
278 file_adds--verbose:
276 file_adds--verbose: c
277 file_adds--verbose: b
278 file_adds--verbose: a
279 279 file_adds--debug: second
280 280 file_adds--debug:
281 281 file_adds--debug: d
282 282 file_adds--debug:
283 283 file_adds--debug:
284 284 file_adds--debug: c
285 285 file_adds--debug: b
286 286 file_adds--debug: a
287 287 file_dels:
288 288 file_dels:
289 289 file_dels:
290 290 file_dels:
291 291 file_dels:
292 292 file_dels:
293 293 file_dels:
294 294 file_dels:
295 295 file_dels--verbose:
296 296 file_dels--verbose:
297 297 file_dels--verbose:
298 298 file_dels--verbose:
299 299 file_dels--verbose:
300 300 file_dels--verbose:
301 301 file_dels--verbose:
302 302 file_dels--verbose:
303 303 file_dels--debug:
304 304 file_dels--debug:
305 305 file_dels--debug:
306 306 file_dels--debug:
307 307 file_dels--debug:
308 308 file_dels--debug:
309 309 file_dels--debug:
310 310 file_dels--debug:
311 311 files: second
312 312 files:
313 313 files: d
314 314 files:
315 315 files: c
316 316 files: c
317 317 files: b
318 318 files: a
319 319 files--verbose: second
320 320 files--verbose:
321 321 files--verbose: d
322 322 files--verbose:
323 323 files--verbose: c
324 324 files--verbose: c
325 325 files--verbose: b
326 326 files--verbose: a
327 327 files--debug:
328 328 files--debug:
329 329 files--debug:
330 330 files--debug:
331 331 files--debug: c
332 332 files--debug:
333 333 files--debug:
334 334 files--debug:
335 manifest:
336 manifest:
337 manifest:
338 manifest:
339 manifest:
340 manifest:
341 manifest:
342 manifest:
343 manifest--verbose:
344 manifest--verbose:
345 manifest--verbose:
346 manifest--verbose:
347 manifest--verbose:
348 manifest--verbose:
349 manifest--verbose:
350 manifest--verbose:
335 manifest: 7:f2dbc354b94e
336 manifest: 6:91015e9dbdd7
337 manifest: 5:4dc3def4f9b4
338 manifest: 4:90ae8dda64e1
339 manifest: 3:cb5a1327723b
340 manifest: 2:6e0e82995c35
341 manifest: 1:4e8d705b1e53
342 manifest: 0:a0c8bcbbb45c
343 manifest--verbose: 7:f2dbc354b94e
344 manifest--verbose: 6:91015e9dbdd7
345 manifest--verbose: 5:4dc3def4f9b4
346 manifest--verbose: 4:90ae8dda64e1
347 manifest--verbose: 3:cb5a1327723b
348 manifest--verbose: 2:6e0e82995c35
349 manifest--verbose: 1:4e8d705b1e53
350 manifest--verbose: 0:a0c8bcbbb45c
351 351 manifest--debug: 7:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
352 352 manifest--debug: 6:91015e9dbdd76a6791085d12b0a0ec7fcd22ffbf
353 353 manifest--debug: 5:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
354 354 manifest--debug: 4:90ae8dda64e1a876c792bccb9af66284f6018363
355 355 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
356 356 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
357 357 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
358 358 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
359 359 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
360 360 node: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
361 361 node: 13207e5a10d9fd28ec424934298e176197f2c67f
362 362 node: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
363 363 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
364 364 node: 97054abb4ab824450e9164180baf491ae0078465
365 365 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
366 366 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
367 367 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
368 368 node--verbose: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
369 369 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
370 370 node--verbose: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
371 371 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
372 372 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
373 373 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
374 374 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
375 375 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
376 376 node--debug: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
377 377 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
378 378 node--debug: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
379 379 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
380 380 node--debug: 97054abb4ab824450e9164180baf491ae0078465
381 381 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
382 382 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
383 383 parents: -1:000000000000
384 384 parents: 5:13207e5a10d9 4:32a18f097fcc
385 385 parents: 3:10e46f2dcbf4
386 386 parents:
387 387 parents:
388 388 parents:
389 389 parents:
390 390 parents:
391 391 parents--verbose: -1:000000000000
392 392 parents--verbose: 5:13207e5a10d9 4:32a18f097fcc
393 393 parents--verbose: 3:10e46f2dcbf4
394 394 parents--verbose:
395 395 parents--verbose:
396 396 parents--verbose:
397 397 parents--verbose:
398 398 parents--verbose:
399 399 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
400 400 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:32a18f097fcccf76ef282f62f8a85b3adf8d13c4
401 401 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
402 402 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
403 403 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
404 404 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
405 405 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
406 406 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
407 407 rev: 7
408 408 rev: 6
409 409 rev: 5
410 410 rev: 4
411 411 rev: 3
412 412 rev: 2
413 413 rev: 1
414 414 rev: 0
415 415 rev--verbose: 7
416 416 rev--verbose: 6
417 417 rev--verbose: 5
418 418 rev--verbose: 4
419 419 rev--verbose: 3
420 420 rev--verbose: 2
421 421 rev--verbose: 1
422 422 rev--verbose: 0
423 423 rev--debug: 7
424 424 rev--debug: 6
425 425 rev--debug: 5
426 426 rev--debug: 4
427 427 rev--debug: 3
428 428 rev--debug: 2
429 429 rev--debug: 1
430 430 rev--debug: 0
431 431 tags: tip
432 432 tags:
433 433 tags:
434 434 tags:
435 435 tags:
436 436 tags:
437 437 tags:
438 438 tags:
439 439 tags--verbose: tip
440 440 tags--verbose:
441 441 tags--verbose:
442 442 tags--verbose:
443 443 tags--verbose:
444 444 tags--verbose:
445 445 tags--verbose:
446 446 tags--verbose:
447 447 tags--debug: tip
448 448 tags--debug:
449 449 tags--debug:
450 450 tags--debug:
451 451 tags--debug:
452 452 tags--debug:
453 453 tags--debug:
454 454 tags--debug:
455 455 # filters work
456 456 hostname
457 457
458 458
459 459
460 460
461 461 place
462 462 place
463 463 hostname
464 464 User Name
465 465 person
466 466 person
467 467 person
468 468 person
469 469 other
470 470 A. N. Other
471 471 User Name
472 472 user
473 473 person
474 474 person
475 475 person
476 476 person
477 477 other
478 478 other
479 479 user
480 480 Mon Jan 12 13:46:40 1970 +0000
481 481 Sun Jan 18 08:40:01 1970 +0000
482 482 Sun Jan 18 08:40:00 1970 +0000
483 483 Sat Jan 17 04:53:20 1970 +0000
484 484 Fri Jan 16 01:06:40 1970 +0000
485 485 Wed Jan 14 21:20:00 1970 +0000
486 486 Tue Jan 13 17:33:20 1970 +0000
487 487 Mon Jan 12 13:46:40 1970 +0000
488 488 1970-01-12 13:46 +0000
489 489 1970-01-18 08:40 +0000
490 490 1970-01-18 08:40 +0000
491 491 1970-01-17 04:53 +0000
492 492 1970-01-16 01:06 +0000
493 493 1970-01-14 21:20 +0000
494 494 1970-01-13 17:33 +0000
495 495 1970-01-12 13:46 +0000
496 496 Mon, 12 Jan 1970 13:46:40 +0000
497 497 Sun, 18 Jan 1970 08:40:01 +0000
498 498 Sun, 18 Jan 1970 08:40:00 +0000
499 499 Sat, 17 Jan 1970 04:53:20 +0000
500 500 Fri, 16 Jan 1970 01:06:40 +0000
501 501 Wed, 14 Jan 1970 21:20:00 +0000
502 502 Tue, 13 Jan 1970 17:33:20 +0000
503 503 Mon, 12 Jan 1970 13:46:40 +0000
504 504 second
505 505 merge
506 506 new head
507 507 new branch
508 508 no user, no domain
509 509 no person
510 510 other 1
511 511 line 1
512 512 29114dbae42b
513 513 c7b487c6c50e
514 514 13207e5a10d9
515 515 32a18f097fcc
516 516 10e46f2dcbf4
517 517 97054abb4ab8
518 518 b608e9d1a3f0
519 519 1e4e1b8f71e0
520 520 # formatnode filter works
521 521 # quiet
522 522 1e4e1b8f71e0
523 523 # normal
524 524 1e4e1b8f71e0
525 525 # verbose
526 526 1e4e1b8f71e0
527 527 # debug
528 528 1e4e1b8f71e05681d422154f5421e385fec3454f
529 529 # error on syntax
530 530 abort: t:3: unmatched quotes
531 531 # done
General Comments 0
You need to be logged in to leave comments. Login now