##// END OF EJS Templates
cmdutil: make "files" list all files, add "file_mods" for modified files
Patrick Mezard -
r5550:db6633f1 default
parent child Browse files
Show More
@@ -1,949 +1,945 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 575 files = []
576 576 def getfiles():
577 577 if not files:
578 578 files[:] = self.repo.status(
579 579 log.parents(changenode)[0], changenode)[:3]
580 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.
584 if self.ui.debugflag:
585 def showfiles(**args):
586 return showlist('file', getfiles()[0], **args)
587 else:
588 581 def showfiles(**args):
589 582 return showlist('file', changes[3], **args)
583 def showmods(**args):
584 return showlist('file_mod', getfiles()[0], **args)
590 585 def showadds(**args):
591 586 return showlist('file_add', getfiles()[1], **args)
592 587 def showdels(**args):
593 588 return showlist('file_del', getfiles()[2], **args)
594 589 def showmanifest(**args):
595 590 args = args.copy()
596 591 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
597 592 node=hex(changes[0])))
598 593 return self.t('manifest', **args)
599 594
600 595 defprops = {
601 596 'author': changes[1],
602 597 'branches': showbranches,
603 598 'date': changes[2],
604 599 'desc': changes[4].strip(),
605 600 'file_adds': showadds,
606 601 'file_dels': showdels,
602 'file_mods': showmods,
607 603 'files': showfiles,
608 604 'file_copies': showcopies,
609 605 'manifest': showmanifest,
610 606 'node': hex(changenode),
611 607 'parents': showparents,
612 608 'rev': rev,
613 609 'tags': showtags,
614 610 'extras': showextras,
615 611 }
616 612 props = props.copy()
617 613 props.update(defprops)
618 614
619 615 try:
620 616 if self.ui.debugflag and 'header_debug' in self.t:
621 617 key = 'header_debug'
622 618 elif self.ui.quiet and 'header_quiet' in self.t:
623 619 key = 'header_quiet'
624 620 elif self.ui.verbose and 'header_verbose' in self.t:
625 621 key = 'header_verbose'
626 622 elif 'header' in self.t:
627 623 key = 'header'
628 624 else:
629 625 key = ''
630 626 if key:
631 627 h = templater.stringify(self.t(key, **props))
632 628 if self.buffered:
633 629 self.header[rev] = h
634 630 else:
635 631 self.ui.write(h)
636 632 if self.ui.debugflag and 'changeset_debug' in self.t:
637 633 key = 'changeset_debug'
638 634 elif self.ui.quiet and 'changeset_quiet' in self.t:
639 635 key = 'changeset_quiet'
640 636 elif self.ui.verbose and 'changeset_verbose' in self.t:
641 637 key = 'changeset_verbose'
642 638 else:
643 639 key = 'changeset'
644 640 self.ui.write(templater.stringify(self.t(key, **props)))
645 641 self.showpatch(changenode)
646 642 except KeyError, inst:
647 643 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
648 644 inst.args[0]))
649 645 except SyntaxError, inst:
650 646 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
651 647
652 648 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
653 649 """show one changeset using template or regular display.
654 650
655 651 Display format will be the first non-empty hit of:
656 652 1. option 'template'
657 653 2. option 'style'
658 654 3. [ui] setting 'logtemplate'
659 655 4. [ui] setting 'style'
660 656 If all of these values are either the unset or the empty string,
661 657 regular display via changeset_printer() is done.
662 658 """
663 659 # options
664 660 patch = False
665 661 if opts.get('patch'):
666 662 patch = matchfn or util.always
667 663
668 664 tmpl = opts.get('template')
669 665 mapfile = None
670 666 if tmpl:
671 667 tmpl = templater.parsestring(tmpl, quoted=False)
672 668 else:
673 669 mapfile = opts.get('style')
674 670 # ui settings
675 671 if not mapfile:
676 672 tmpl = ui.config('ui', 'logtemplate')
677 673 if tmpl:
678 674 tmpl = templater.parsestring(tmpl)
679 675 else:
680 676 mapfile = ui.config('ui', 'style')
681 677
682 678 if tmpl or mapfile:
683 679 if mapfile:
684 680 if not os.path.split(mapfile)[0]:
685 681 mapname = (templater.templatepath('map-cmdline.' + mapfile)
686 682 or templater.templatepath(mapfile))
687 683 if mapname: mapfile = mapname
688 684 try:
689 685 t = changeset_templater(ui, repo, patch, mapfile, buffered)
690 686 except SyntaxError, inst:
691 687 raise util.Abort(inst.args[0])
692 688 if tmpl: t.use_template(tmpl)
693 689 return t
694 690 return changeset_printer(ui, repo, patch, buffered)
695 691
696 692 def finddate(ui, repo, date):
697 693 """Find the tipmost changeset that matches the given date spec"""
698 694 df = util.matchdate(date + " to " + date)
699 695 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
700 696 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
701 697 results = {}
702 698 for st, rev, fns in changeiter:
703 699 if st == 'add':
704 700 d = get(rev)[2]
705 701 if df(d[0]):
706 702 results[rev] = d
707 703 elif st == 'iter':
708 704 if rev in results:
709 705 ui.status("Found revision %s from %s\n" %
710 706 (rev, util.datestr(results[rev])))
711 707 return str(rev)
712 708
713 709 raise util.Abort(_("revision matching date not found"))
714 710
715 711 def walkchangerevs(ui, repo, pats, change, opts):
716 712 '''Iterate over files and the revs they changed in.
717 713
718 714 Callers most commonly need to iterate backwards over the history
719 715 it is interested in. Doing so has awful (quadratic-looking)
720 716 performance, so we use iterators in a "windowed" way.
721 717
722 718 We walk a window of revisions in the desired order. Within the
723 719 window, we first walk forwards to gather data, then in the desired
724 720 order (usually backwards) to display it.
725 721
726 722 This function returns an (iterator, matchfn) tuple. The iterator
727 723 yields 3-tuples. They will be of one of the following forms:
728 724
729 725 "window", incrementing, lastrev: stepping through a window,
730 726 positive if walking forwards through revs, last rev in the
731 727 sequence iterated over - use to reset state for the current window
732 728
733 729 "add", rev, fns: out-of-order traversal of the given file names
734 730 fns, which changed during revision rev - use to gather data for
735 731 possible display
736 732
737 733 "iter", rev, None: in-order traversal of the revs earlier iterated
738 734 over with "add" - use to display data'''
739 735
740 736 def increasing_windows(start, end, windowsize=8, sizelimit=512):
741 737 if start < end:
742 738 while start < end:
743 739 yield start, min(windowsize, end-start)
744 740 start += windowsize
745 741 if windowsize < sizelimit:
746 742 windowsize *= 2
747 743 else:
748 744 while start > end:
749 745 yield start, min(windowsize, start-end-1)
750 746 start -= windowsize
751 747 if windowsize < sizelimit:
752 748 windowsize *= 2
753 749
754 750 files, matchfn, anypats = matchpats(repo, pats, opts)
755 751 follow = opts.get('follow') or opts.get('follow_first')
756 752
757 753 if repo.changelog.count() == 0:
758 754 return [], matchfn
759 755
760 756 if follow:
761 757 defrange = '%s:0' % repo.changectx().rev()
762 758 else:
763 759 defrange = 'tip:0'
764 760 revs = revrange(repo, opts['rev'] or [defrange])
765 761 wanted = {}
766 762 slowpath = anypats or opts.get('removed')
767 763 fncache = {}
768 764
769 765 if not slowpath and not files:
770 766 # No files, no patterns. Display all revs.
771 767 wanted = dict.fromkeys(revs)
772 768 copies = []
773 769 if not slowpath:
774 770 # Only files, no patterns. Check the history of each file.
775 771 def filerevgen(filelog, node):
776 772 cl_count = repo.changelog.count()
777 773 if node is None:
778 774 last = filelog.count() - 1
779 775 else:
780 776 last = filelog.rev(node)
781 777 for i, window in increasing_windows(last, nullrev):
782 778 revs = []
783 779 for j in xrange(i - window, i + 1):
784 780 n = filelog.node(j)
785 781 revs.append((filelog.linkrev(n),
786 782 follow and filelog.renamed(n)))
787 783 revs.reverse()
788 784 for rev in revs:
789 785 # only yield rev for which we have the changelog, it can
790 786 # happen while doing "hg log" during a pull or commit
791 787 if rev[0] < cl_count:
792 788 yield rev
793 789 def iterfiles():
794 790 for filename in files:
795 791 yield filename, None
796 792 for filename_node in copies:
797 793 yield filename_node
798 794 minrev, maxrev = min(revs), max(revs)
799 795 for file_, node in iterfiles():
800 796 filelog = repo.file(file_)
801 797 # A zero count may be a directory or deleted file, so
802 798 # try to find matching entries on the slow path.
803 799 if filelog.count() == 0:
804 800 slowpath = True
805 801 break
806 802 for rev, copied in filerevgen(filelog, node):
807 803 if rev <= maxrev:
808 804 if rev < minrev:
809 805 break
810 806 fncache.setdefault(rev, [])
811 807 fncache[rev].append(file_)
812 808 wanted[rev] = 1
813 809 if follow and copied:
814 810 copies.append(copied)
815 811 if slowpath:
816 812 if follow:
817 813 raise util.Abort(_('can only follow copies/renames for explicit '
818 814 'file names'))
819 815
820 816 # The slow path checks files modified in every changeset.
821 817 def changerevgen():
822 818 for i, window in increasing_windows(repo.changelog.count()-1,
823 819 nullrev):
824 820 for j in xrange(i - window, i + 1):
825 821 yield j, change(j)[3]
826 822
827 823 for rev, changefiles in changerevgen():
828 824 matches = filter(matchfn, changefiles)
829 825 if matches:
830 826 fncache[rev] = matches
831 827 wanted[rev] = 1
832 828
833 829 class followfilter:
834 830 def __init__(self, onlyfirst=False):
835 831 self.startrev = nullrev
836 832 self.roots = []
837 833 self.onlyfirst = onlyfirst
838 834
839 835 def match(self, rev):
840 836 def realparents(rev):
841 837 if self.onlyfirst:
842 838 return repo.changelog.parentrevs(rev)[0:1]
843 839 else:
844 840 return filter(lambda x: x != nullrev,
845 841 repo.changelog.parentrevs(rev))
846 842
847 843 if self.startrev == nullrev:
848 844 self.startrev = rev
849 845 return True
850 846
851 847 if rev > self.startrev:
852 848 # forward: all descendants
853 849 if not self.roots:
854 850 self.roots.append(self.startrev)
855 851 for parent in realparents(rev):
856 852 if parent in self.roots:
857 853 self.roots.append(rev)
858 854 return True
859 855 else:
860 856 # backwards: all parents
861 857 if not self.roots:
862 858 self.roots.extend(realparents(self.startrev))
863 859 if rev in self.roots:
864 860 self.roots.remove(rev)
865 861 self.roots.extend(realparents(rev))
866 862 return True
867 863
868 864 return False
869 865
870 866 # it might be worthwhile to do this in the iterator if the rev range
871 867 # is descending and the prune args are all within that range
872 868 for rev in opts.get('prune', ()):
873 869 rev = repo.changelog.rev(repo.lookup(rev))
874 870 ff = followfilter()
875 871 stop = min(revs[0], revs[-1])
876 872 for x in xrange(rev, stop-1, -1):
877 873 if ff.match(x) and x in wanted:
878 874 del wanted[x]
879 875
880 876 def iterate():
881 877 if follow and not files:
882 878 ff = followfilter(onlyfirst=opts.get('follow_first'))
883 879 def want(rev):
884 880 if ff.match(rev) and rev in wanted:
885 881 return True
886 882 return False
887 883 else:
888 884 def want(rev):
889 885 return rev in wanted
890 886
891 887 for i, window in increasing_windows(0, len(revs)):
892 888 yield 'window', revs[0] < revs[-1], revs[-1]
893 889 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
894 890 srevs = list(nrevs)
895 891 srevs.sort()
896 892 for rev in srevs:
897 893 fns = fncache.get(rev)
898 894 if not fns:
899 895 def fns_generator():
900 896 for f in change(rev)[3]:
901 897 if matchfn(f):
902 898 yield f
903 899 fns = fns_generator()
904 900 yield 'add', rev, fns
905 901 for rev in nrevs:
906 902 yield 'iter', rev, None
907 903 return iterate(), matchfn
908 904
909 905 def commit(ui, repo, commitfunc, pats, opts):
910 906 '''commit the specified files or all outstanding changes'''
911 907 message = logmessage(opts)
912 908
913 909 if opts['addremove']:
914 910 addremove(repo, pats, opts)
915 911 fns, match, anypats = matchpats(repo, pats, opts)
916 912 if pats:
917 913 status = repo.status(files=fns, match=match)
918 914 modified, added, removed, deleted, unknown = status[:5]
919 915 files = modified + added + removed
920 916 slist = None
921 917 for f in fns:
922 918 if f == '.':
923 919 continue
924 920 if f not in files:
925 921 rf = repo.wjoin(f)
926 922 try:
927 923 mode = os.lstat(rf)[stat.ST_MODE]
928 924 except OSError:
929 925 raise util.Abort(_("file %s not found!") % rf)
930 926 if stat.S_ISDIR(mode):
931 927 name = f + '/'
932 928 if slist is None:
933 929 slist = list(files)
934 930 slist.sort()
935 931 i = bisect.bisect(slist, name)
936 932 if i >= len(slist) or not slist[i].startswith(name):
937 933 raise util.Abort(_("no match under directory %s!")
938 934 % rf)
939 935 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
940 936 raise util.Abort(_("can't commit %s: "
941 937 "unsupported file type!") % rf)
942 938 elif f not in repo.dirstate:
943 939 raise util.Abort(_("file %s not tracked!") % rf)
944 940 else:
945 941 files = []
946 942 try:
947 943 return commitfunc(ui, repo, files, message, match, opts)
948 944 except ValueError, inst:
949 945 raise util.Abort(str(inst))
@@ -1,21 +1,24 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 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 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'
4 changeset_debug = 'changeset: {rev}:{node}\n{branches}{tags}{parents}{manifest}user: {author}\ndate: {date|date}\n{file_mods}{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 start_file_mods = 'files: '
9 file_mod = ' {file_mod}'
10 end_file_mods = '\n'
8 11 start_file_adds = 'files+: '
9 12 file_add = ' {file_add}'
10 13 end_file_adds = '\n'
11 14 start_file_dels = 'files-: '
12 15 file_del = ' {file_del}'
13 16 end_file_dels = '\n'
14 17 start_file_copies = 'copies: '
15 18 file_copy = ' {name} ({source})'
16 19 end_file_copies = '\n'
17 20 parent = 'parent: {rev}:{node|formatnode}\n'
18 21 manifest = 'manifest: {rev}:{node}\n'
19 22 branch = 'branch: {branch}\n'
20 23 tag = 'tag: {tag}\n'
21 24 extra = 'extra: {key}={value|stringescape}\n'
@@ -1,124 +1,124 b''
1 1 #!/bin/sh
2 2
3 3 hg init a
4 4 cd a
5 5 echo a > a
6 6 hg add a
7 7 echo line 1 > b
8 8 echo line 2 >> b
9 9 hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
10 10 hg add b
11 11 echo other 1 > c
12 12 echo other 2 >> c
13 13 echo >> c
14 14 echo other 3 >> c
15 15 hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
16 16 hg add c
17 17 hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 18 echo c >> c
19 19 hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20 20 echo foo > .hg/branch
21 21 hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 22 hg co -q 3
23 23 echo other 4 >> d
24 24 hg add d
25 25 hg commit -m 'new head' -d '1500000 0' -u 'person'
26 26 hg merge -q
27 27 hg commit -m 'merge' -d '1500001 0' -u 'person'
28 28 # second branch starting at nullrev
29 29 hg update null
30 30 echo second > second
31 31 hg add second
32 32 hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
33 33
34 34 # make sure user/global hgrc does not affect tests
35 35 echo '[ui]' > .hg/hgrc
36 36 echo 'logtemplate =' >> .hg/hgrc
37 37 echo 'style =' >> .hg/hgrc
38 38
39 39 echo '# default style is like normal output'
40 40 echo '# normal'
41 41 hg log > log.out
42 42 hg log --style default > style.out
43 43 diff log.out style.out
44 44 echo '# verbose'
45 45 hg log -v > log.out
46 46 hg log -v --style default > style.out
47 47 diff log.out style.out
48 48 echo '# debug'
49 49 hg log --debug > log.out
50 50 hg log --debug --style default > style.out
51 51 diff log.out style.out
52 52
53 53 echo '# revision with no copies (used to print a traceback)'
54 54 hg tip -v --template '\n'
55 55
56 56 echo '# compact style works'
57 57 hg log --style compact
58 58 hg log -v --style compact
59 59 hg log --debug --style compact
60 60
61 61 echo '# error if style not readable'
62 62 touch q
63 63 chmod 0 q
64 64 hg log --style ./q
65 65
66 66 echo '# error if no style'
67 67 hg log --style notexist
68 68
69 69 echo '# error if style missing key'
70 70 echo 'q = q' > t
71 71 hg log --style ./t
72 72
73 73 echo '# error if include fails'
74 74 echo 'changeset = q' >> t
75 75 hg log --style ./t
76 76
77 77 echo '# include works'
78 78 rm q
79 79 echo '{rev}' > q
80 80 hg log --style ./t
81 81
82 82 echo '# ui.style works'
83 83 echo '[ui]' > .hg/hgrc
84 84 echo 'style = t' >> .hg/hgrc
85 85 hg log
86 86
87 87 echo '# issue338'
88 88 hg log --style=changelog > changelog
89 89 cat changelog
90 90
91 91 echo "# keys work"
92 for key in author branches date desc file_adds file_dels files \
93 manifest node parents rev tags; do
92 for key in author branches date desc file_adds file_dels file_mods \
93 files manifest node parents rev tags; do
94 94 for mode in '' --verbose --debug; do
95 95 hg log $mode --template "$key$mode: {$key}\n"
96 96 done
97 97 done
98 98
99 99 echo '# filters work'
100 100 hg log --template '{author|domain}\n'
101 101 hg log --template '{author|person}\n'
102 102 hg log --template '{author|user}\n'
103 103 hg log --template '{date|age}\n' > /dev/null || exit 1
104 104 hg log --template '{date|date}\n'
105 105 hg log --template '{date|isodate}\n'
106 106 hg log --template '{date|rfc822date}\n'
107 107 hg log --template '{desc|firstline}\n'
108 108 hg log --template '{node|short}\n'
109 109
110 110 echo '# formatnode filter works'
111 111 echo '# quiet'
112 112 hg -q log -r 0 --template '#node|formatnode#\n'
113 113 echo '# normal'
114 114 hg log -r 0 --template '#node|formatnode#\n'
115 115 echo '# verbose'
116 116 hg -v log -r 0 --template '#node|formatnode#\n'
117 117 echo '# debug'
118 118 hg --debug log -r 0 --template '#node|formatnode#\n'
119 119
120 120 echo '# error on syntax'
121 121 echo 'x = "f' >> t
122 122 hg log
123 123
124 124 echo '# done'
@@ -1,531 +1,555 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 263 file_adds: second
264 264 file_adds:
265 265 file_adds: d
266 266 file_adds:
267 267 file_adds:
268 268 file_adds: c
269 269 file_adds: b
270 270 file_adds: a
271 271 file_adds--verbose: second
272 272 file_adds--verbose:
273 273 file_adds--verbose: d
274 274 file_adds--verbose:
275 275 file_adds--verbose:
276 276 file_adds--verbose: c
277 277 file_adds--verbose: b
278 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 file_mods:
312 file_mods:
313 file_mods:
314 file_mods:
315 file_mods: c
316 file_mods:
317 file_mods:
318 file_mods:
319 file_mods--verbose:
320 file_mods--verbose:
321 file_mods--verbose:
322 file_mods--verbose:
323 file_mods--verbose: c
324 file_mods--verbose:
325 file_mods--verbose:
326 file_mods--verbose:
327 file_mods--debug:
328 file_mods--debug:
329 file_mods--debug:
330 file_mods--debug:
331 file_mods--debug: c
332 file_mods--debug:
333 file_mods--debug:
334 file_mods--debug:
311 335 files: second
312 336 files:
313 337 files: d
314 338 files:
315 339 files: c
316 340 files: c
317 341 files: b
318 342 files: a
319 343 files--verbose: second
320 344 files--verbose:
321 345 files--verbose: d
322 346 files--verbose:
323 347 files--verbose: c
324 348 files--verbose: c
325 349 files--verbose: b
326 350 files--verbose: a
327 files--debug:
351 files--debug: second
328 352 files--debug:
329 files--debug:
353 files--debug: d
330 354 files--debug:
331 355 files--debug: c
332 files--debug:
333 files--debug:
334 files--debug:
356 files--debug: c
357 files--debug: b
358 files--debug: a
335 359 manifest: 7:f2dbc354b94e
336 360 manifest: 6:91015e9dbdd7
337 361 manifest: 5:4dc3def4f9b4
338 362 manifest: 4:90ae8dda64e1
339 363 manifest: 3:cb5a1327723b
340 364 manifest: 2:6e0e82995c35
341 365 manifest: 1:4e8d705b1e53
342 366 manifest: 0:a0c8bcbbb45c
343 367 manifest--verbose: 7:f2dbc354b94e
344 368 manifest--verbose: 6:91015e9dbdd7
345 369 manifest--verbose: 5:4dc3def4f9b4
346 370 manifest--verbose: 4:90ae8dda64e1
347 371 manifest--verbose: 3:cb5a1327723b
348 372 manifest--verbose: 2:6e0e82995c35
349 373 manifest--verbose: 1:4e8d705b1e53
350 374 manifest--verbose: 0:a0c8bcbbb45c
351 375 manifest--debug: 7:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
352 376 manifest--debug: 6:91015e9dbdd76a6791085d12b0a0ec7fcd22ffbf
353 377 manifest--debug: 5:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
354 378 manifest--debug: 4:90ae8dda64e1a876c792bccb9af66284f6018363
355 379 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
356 380 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
357 381 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
358 382 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
359 383 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
360 384 node: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
361 385 node: 13207e5a10d9fd28ec424934298e176197f2c67f
362 386 node: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
363 387 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
364 388 node: 97054abb4ab824450e9164180baf491ae0078465
365 389 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
366 390 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
367 391 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
368 392 node--verbose: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
369 393 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
370 394 node--verbose: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
371 395 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
372 396 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
373 397 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
374 398 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
375 399 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
376 400 node--debug: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
377 401 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
378 402 node--debug: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
379 403 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
380 404 node--debug: 97054abb4ab824450e9164180baf491ae0078465
381 405 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
382 406 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
383 407 parents: -1:000000000000
384 408 parents: 5:13207e5a10d9 4:32a18f097fcc
385 409 parents: 3:10e46f2dcbf4
386 410 parents:
387 411 parents:
388 412 parents:
389 413 parents:
390 414 parents:
391 415 parents--verbose: -1:000000000000
392 416 parents--verbose: 5:13207e5a10d9 4:32a18f097fcc
393 417 parents--verbose: 3:10e46f2dcbf4
394 418 parents--verbose:
395 419 parents--verbose:
396 420 parents--verbose:
397 421 parents--verbose:
398 422 parents--verbose:
399 423 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
400 424 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:32a18f097fcccf76ef282f62f8a85b3adf8d13c4
401 425 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
402 426 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
403 427 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
404 428 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
405 429 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
406 430 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
407 431 rev: 7
408 432 rev: 6
409 433 rev: 5
410 434 rev: 4
411 435 rev: 3
412 436 rev: 2
413 437 rev: 1
414 438 rev: 0
415 439 rev--verbose: 7
416 440 rev--verbose: 6
417 441 rev--verbose: 5
418 442 rev--verbose: 4
419 443 rev--verbose: 3
420 444 rev--verbose: 2
421 445 rev--verbose: 1
422 446 rev--verbose: 0
423 447 rev--debug: 7
424 448 rev--debug: 6
425 449 rev--debug: 5
426 450 rev--debug: 4
427 451 rev--debug: 3
428 452 rev--debug: 2
429 453 rev--debug: 1
430 454 rev--debug: 0
431 455 tags: tip
432 456 tags:
433 457 tags:
434 458 tags:
435 459 tags:
436 460 tags:
437 461 tags:
438 462 tags:
439 463 tags--verbose: tip
440 464 tags--verbose:
441 465 tags--verbose:
442 466 tags--verbose:
443 467 tags--verbose:
444 468 tags--verbose:
445 469 tags--verbose:
446 470 tags--verbose:
447 471 tags--debug: tip
448 472 tags--debug:
449 473 tags--debug:
450 474 tags--debug:
451 475 tags--debug:
452 476 tags--debug:
453 477 tags--debug:
454 478 tags--debug:
455 479 # filters work
456 480 hostname
457 481
458 482
459 483
460 484
461 485 place
462 486 place
463 487 hostname
464 488 User Name
465 489 person
466 490 person
467 491 person
468 492 person
469 493 other
470 494 A. N. Other
471 495 User Name
472 496 user
473 497 person
474 498 person
475 499 person
476 500 person
477 501 other
478 502 other
479 503 user
480 504 Mon Jan 12 13:46:40 1970 +0000
481 505 Sun Jan 18 08:40:01 1970 +0000
482 506 Sun Jan 18 08:40:00 1970 +0000
483 507 Sat Jan 17 04:53:20 1970 +0000
484 508 Fri Jan 16 01:06:40 1970 +0000
485 509 Wed Jan 14 21:20:00 1970 +0000
486 510 Tue Jan 13 17:33:20 1970 +0000
487 511 Mon Jan 12 13:46:40 1970 +0000
488 512 1970-01-12 13:46 +0000
489 513 1970-01-18 08:40 +0000
490 514 1970-01-18 08:40 +0000
491 515 1970-01-17 04:53 +0000
492 516 1970-01-16 01:06 +0000
493 517 1970-01-14 21:20 +0000
494 518 1970-01-13 17:33 +0000
495 519 1970-01-12 13:46 +0000
496 520 Mon, 12 Jan 1970 13:46:40 +0000
497 521 Sun, 18 Jan 1970 08:40:01 +0000
498 522 Sun, 18 Jan 1970 08:40:00 +0000
499 523 Sat, 17 Jan 1970 04:53:20 +0000
500 524 Fri, 16 Jan 1970 01:06:40 +0000
501 525 Wed, 14 Jan 1970 21:20:00 +0000
502 526 Tue, 13 Jan 1970 17:33:20 +0000
503 527 Mon, 12 Jan 1970 13:46:40 +0000
504 528 second
505 529 merge
506 530 new head
507 531 new branch
508 532 no user, no domain
509 533 no person
510 534 other 1
511 535 line 1
512 536 29114dbae42b
513 537 c7b487c6c50e
514 538 13207e5a10d9
515 539 32a18f097fcc
516 540 10e46f2dcbf4
517 541 97054abb4ab8
518 542 b608e9d1a3f0
519 543 1e4e1b8f71e0
520 544 # formatnode filter works
521 545 # quiet
522 546 1e4e1b8f71e0
523 547 # normal
524 548 1e4e1b8f71e0
525 549 # verbose
526 550 1e4e1b8f71e0
527 551 # debug
528 552 1e4e1b8f71e05681d422154f5421e385fec3454f
529 553 # error on syntax
530 554 abort: t:3: unmatched quotes
531 555 # done
General Comments 0
You need to be logged in to leave comments. Login now