##// END OF EJS Templates
Reformat debugindex output
mpm@selenic.com -
r989:1b6eb272 default
parent child Browse files
Show More
@@ -1,1622 +1,1622
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005 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 demandload import demandload
9 9 demandload(globals(), "os re sys signal shutil")
10 10 demandload(globals(), "fancyopts ui hg util lock")
11 11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 12 demandload(globals(), "errno socket version struct atexit")
13 13
14 14 class UnknownCommand(Exception):
15 15 """Exception raised if command is not in the command table."""
16 16
17 17 def filterfiles(filters, files):
18 18 l = [x for x in files if x in filters]
19 19
20 20 for t in filters:
21 21 if t and t[-1] != "/":
22 22 t += "/"
23 23 l += [x for x in files if x.startswith(t)]
24 24 return l
25 25
26 26 def relpath(repo, args):
27 27 cwd = repo.getcwd()
28 28 if cwd:
29 29 return [util.normpath(os.path.join(cwd, x)) for x in args]
30 30 return args
31 31
32 32 def matchpats(repo, cwd, pats = [], opts = {}, head = ''):
33 33 return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
34 34 opts.get('exclude'), head)
35 35
36 36 def makewalk(repo, pats, opts, head = ''):
37 37 cwd = repo.getcwd()
38 38 files, matchfn = matchpats(repo, cwd, pats, opts, head)
39 39 exact = dict(zip(files, files))
40 40 def walk():
41 41 for src, fn in repo.walk(files = files, match = matchfn):
42 42 yield src, fn, util.pathto(cwd, fn), fn in exact
43 43 return files, matchfn, walk()
44 44
45 45 def walk(repo, pats, opts, head = ''):
46 46 files, matchfn, results = makewalk(repo, pats, opts, head)
47 47 for r in results: yield r
48 48
49 49 revrangesep = ':'
50 50
51 51 def revrange(ui, repo, revs, revlog=None):
52 52 if revlog is None:
53 53 revlog = repo.changelog
54 54 revcount = revlog.count()
55 55 def fix(val, defval):
56 56 if not val:
57 57 return defval
58 58 try:
59 59 num = int(val)
60 60 if str(num) != val:
61 61 raise ValueError
62 62 if num < 0:
63 63 num += revcount
64 64 if not (0 <= num < revcount):
65 65 raise ValueError
66 66 except ValueError:
67 67 try:
68 68 num = repo.changelog.rev(repo.lookup(val))
69 69 except KeyError:
70 70 try:
71 71 num = revlog.rev(revlog.lookup(val))
72 72 except KeyError:
73 73 raise util.Abort('invalid revision identifier %s', val)
74 74 return num
75 75 for spec in revs:
76 76 if spec.find(revrangesep) >= 0:
77 77 start, end = spec.split(revrangesep, 1)
78 78 start = fix(start, 0)
79 79 end = fix(end, revcount - 1)
80 80 if end > start:
81 81 end += 1
82 82 step = 1
83 83 else:
84 84 end -= 1
85 85 step = -1
86 86 for rev in xrange(start, end, step):
87 87 yield str(rev)
88 88 else:
89 89 yield spec
90 90
91 91 def make_filename(repo, r, pat, node=None,
92 92 total=None, seqno=None, revwidth=None):
93 93 node_expander = {
94 94 'H': lambda: hg.hex(node),
95 95 'R': lambda: str(r.rev(node)),
96 96 'h': lambda: hg.short(node),
97 97 }
98 98 expander = {
99 99 '%': lambda: '%',
100 100 'b': lambda: os.path.basename(repo.root),
101 101 }
102 102
103 103 try:
104 104 if node:
105 105 expander.update(node_expander)
106 106 if node and revwidth is not None:
107 107 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
108 108 if total is not None:
109 109 expander['N'] = lambda: str(total)
110 110 if seqno is not None:
111 111 expander['n'] = lambda: str(seqno)
112 112 if total is not None and seqno is not None:
113 113 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
114 114
115 115 newname = []
116 116 patlen = len(pat)
117 117 i = 0
118 118 while i < patlen:
119 119 c = pat[i]
120 120 if c == '%':
121 121 i += 1
122 122 c = pat[i]
123 123 c = expander[c]()
124 124 newname.append(c)
125 125 i += 1
126 126 return ''.join(newname)
127 127 except KeyError, inst:
128 128 raise util.Abort("invalid format spec '%%%s' in output file name",
129 129 inst.args[0])
130 130
131 131 def make_file(repo, r, pat, node=None,
132 132 total=None, seqno=None, revwidth=None, mode='wb'):
133 133 if not pat or pat == '-':
134 134 if 'w' in mode: return sys.stdout
135 135 else: return sys.stdin
136 136 if hasattr(pat, 'write') and 'w' in mode:
137 137 return pat
138 138 if hasattr(pat, 'read') and 'r' in mode:
139 139 return pat
140 140 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
141 141 mode)
142 142
143 143 def dodiff(fp, ui, repo, files=None, node1=None, node2=None, match=util.always, changes=None):
144 144 def date(c):
145 145 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
146 146
147 147 if not changes:
148 148 (c, a, d, u) = repo.changes(node1, node2, files, match = match)
149 149 else:
150 150 (c, a, d, u) = changes
151 151 if files:
152 152 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
153 153
154 154 if not c and not a and not d:
155 155 return
156 156
157 157 if node2:
158 158 change = repo.changelog.read(node2)
159 159 mmap2 = repo.manifest.read(change[0])
160 160 date2 = date(change)
161 161 def read(f):
162 162 return repo.file(f).read(mmap2[f])
163 163 else:
164 164 date2 = time.asctime()
165 165 if not node1:
166 166 node1 = repo.dirstate.parents()[0]
167 167 def read(f):
168 168 return repo.wfile(f).read()
169 169
170 170 if ui.quiet:
171 171 r = None
172 172 else:
173 173 hexfunc = ui.verbose and hg.hex or hg.short
174 174 r = [hexfunc(node) for node in [node1, node2] if node]
175 175
176 176 change = repo.changelog.read(node1)
177 177 mmap = repo.manifest.read(change[0])
178 178 date1 = date(change)
179 179
180 180 for f in c:
181 181 to = None
182 182 if f in mmap:
183 183 to = repo.file(f).read(mmap[f])
184 184 tn = read(f)
185 185 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
186 186 for f in a:
187 187 to = None
188 188 tn = read(f)
189 189 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
190 190 for f in d:
191 191 to = repo.file(f).read(mmap[f])
192 192 tn = None
193 193 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
194 194
195 195 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None):
196 196 """show a single changeset or file revision"""
197 197 changelog = repo.changelog
198 198 if filelog:
199 199 log = filelog
200 200 filerev = rev
201 201 node = filenode = filelog.node(filerev)
202 202 changerev = filelog.linkrev(filenode)
203 203 changenode = changenode or changelog.node(changerev)
204 204 else:
205 205 log = changelog
206 206 changerev = rev
207 207 if changenode is None:
208 208 changenode = changelog.node(changerev)
209 209 elif not changerev:
210 210 rev = changerev = changelog.rev(changenode)
211 211 node = changenode
212 212
213 213 if ui.quiet:
214 214 ui.write("%d:%s\n" % (rev, hg.short(node)))
215 215 return
216 216
217 217 changes = changelog.read(changenode)
218 218
219 219 t, tz = changes[2].split(' ')
220 220 # a conversion tool was sticking non-integer offsets into repos
221 221 try:
222 222 tz = int(tz)
223 223 except ValueError:
224 224 tz = 0
225 225 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
226 226
227 227 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
228 228 for p in log.parents(node)
229 229 if ui.debugflag or p != hg.nullid]
230 230 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
231 231 parents = []
232 232
233 233 if ui.verbose:
234 234 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
235 235 else:
236 236 ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode)))
237 237
238 238 for tag in repo.nodetags(changenode):
239 239 ui.status("tag: %s\n" % tag)
240 240 for parent in parents:
241 241 ui.write("parent: %d:%s\n" % parent)
242 242 if filelog:
243 243 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
244 244
245 245 if brinfo and changenode in brinfo:
246 246 br = brinfo[changenode]
247 247 ui.write("branch: %s\n" % " ".join(br))
248 248
249 249 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
250 250 hg.hex(changes[0])))
251 251 ui.status("user: %s\n" % changes[1])
252 252 ui.status("date: %s\n" % date)
253 253
254 254 if ui.debugflag:
255 255 files = repo.changes(changelog.parents(changenode)[0], changenode)
256 256 for key, value in zip(["files:", "files+:", "files-:"], files):
257 257 if value:
258 258 ui.note("%-12s %s\n" % (key, " ".join(value)))
259 259 else:
260 260 ui.note("files: %s\n" % " ".join(changes[3]))
261 261
262 262 description = changes[4].strip()
263 263 if description:
264 264 if ui.verbose:
265 265 ui.status("description:\n")
266 266 ui.status(description)
267 267 ui.status("\n\n")
268 268 else:
269 269 ui.status("summary: %s\n" % description.splitlines()[0])
270 270 ui.status("\n")
271 271
272 272 def show_version(ui):
273 273 """output version and copyright information"""
274 274 ui.write("Mercurial Distributed SCM (version %s)\n"
275 275 % version.get_version())
276 276 ui.status(
277 277 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
278 278 "This is free software; see the source for copying conditions. "
279 279 "There is NO\nwarranty; "
280 280 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
281 281 )
282 282
283 283 def help_(ui, cmd=None):
284 284 """show help for a given command or all commands"""
285 285 if cmd and cmd != 'shortlist':
286 286 key, i = find(cmd)
287 287 # synopsis
288 288 ui.write("%s\n\n" % i[2])
289 289
290 290 # description
291 291 doc = i[0].__doc__
292 292 if ui.quiet:
293 293 doc = doc.splitlines(0)[0]
294 294 ui.write("%s\n" % doc.rstrip())
295 295
296 296 # aliases
297 297 if not ui.quiet:
298 298 aliases = ', '.join(key.split('|')[1:])
299 299 if aliases:
300 300 ui.write("\naliases: %s\n" % aliases)
301 301
302 302 # options
303 303 if not ui.quiet and i[1]:
304 304 ui.write("\noptions:\n\n")
305 305 for s, l, d, c in i[1]:
306 306 opt = ' '
307 307 if s:
308 308 opt = opt + '-' + s + ' '
309 309 if l:
310 310 opt = opt + '--' + l + ' '
311 311 if d:
312 312 opt = opt + '(' + str(d) + ')'
313 313 ui.write(opt, "\n")
314 314 if c:
315 315 ui.write(' %s\n' % c)
316 316
317 317 else:
318 318 # program name
319 319 if ui.verbose:
320 320 show_version(ui)
321 321 else:
322 322 ui.status("Mercurial Distributed SCM\n")
323 323 ui.status('\n')
324 324
325 325 # list of commands
326 326 if cmd == "shortlist":
327 327 ui.status('basic commands (use "hg help" '
328 328 'for the full list or option "-v" for details):\n\n')
329 329 elif ui.verbose:
330 330 ui.status('list of commands:\n\n')
331 331 else:
332 332 ui.status('list of commands (use "hg help -v" '
333 333 'to show aliases and global options):\n\n')
334 334
335 335 h = {}
336 336 cmds = {}
337 337 for c, e in table.items():
338 338 f = c.split("|")[0]
339 339 if cmd == "shortlist" and not f.startswith("^"):
340 340 continue
341 341 f = f.lstrip("^")
342 342 if not ui.debugflag and f.startswith("debug"):
343 343 continue
344 344 d = ""
345 345 if e[0].__doc__:
346 346 d = e[0].__doc__.splitlines(0)[0].rstrip()
347 347 h[f] = d
348 348 cmds[f]=c.lstrip("^")
349 349
350 350 fns = h.keys()
351 351 fns.sort()
352 352 m = max(map(len, fns))
353 353 for f in fns:
354 354 if ui.verbose:
355 355 commands = cmds[f].replace("|",", ")
356 356 ui.write(" %s:\n %s\n"%(commands,h[f]))
357 357 else:
358 358 ui.write(' %-*s %s\n' % (m, f, h[f]))
359 359
360 360 # global options
361 361 if ui.verbose:
362 362 ui.write("\nglobal options:\n\n")
363 363 for s, l, d, c in globalopts:
364 364 opt = ' '
365 365 if s:
366 366 opt = opt + '-' + s + ' '
367 367 if l:
368 368 opt = opt + '--' + l + ' '
369 369 if d:
370 370 opt = opt + '(' + str(d) + ')'
371 371 ui.write(opt, "\n")
372 372 if c:
373 373 ui.write(' %s\n' % c)
374 374
375 375 # Commands start here, listed alphabetically
376 376
377 377 def add(ui, repo, *pats, **opts):
378 378 '''add the specified files on the next commit'''
379 379 names = []
380 380 for src, abs, rel, exact in walk(repo, pats, opts):
381 381 if exact:
382 382 names.append(abs)
383 383 elif repo.dirstate.state(abs) == '?':
384 384 ui.status('adding %s\n' % rel)
385 385 names.append(abs)
386 386 repo.add(names)
387 387
388 388 def addremove(ui, repo, *pats, **opts):
389 389 """add all new files, delete all missing files"""
390 390 add, remove = [], []
391 391 for src, abs, rel, exact in walk(repo, pats, opts):
392 392 if src == 'f' and repo.dirstate.state(abs) == '?':
393 393 add.append(abs)
394 394 if not exact: ui.status('adding ', rel, '\n')
395 395 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
396 396 remove.append(abs)
397 397 if not exact: ui.status('removing ', rel, '\n')
398 398 repo.add(add)
399 399 repo.remove(remove)
400 400
401 401 def annotate(ui, repo, *pats, **opts):
402 402 """show changeset information per file line"""
403 403 def getnode(rev):
404 404 return hg.short(repo.changelog.node(rev))
405 405
406 406 def getname(rev):
407 407 try:
408 408 return bcache[rev]
409 409 except KeyError:
410 410 cl = repo.changelog.read(repo.changelog.node(rev))
411 411 name = cl[1]
412 412 f = name.find('@')
413 413 if f >= 0:
414 414 name = name[:f]
415 415 f = name.find('<')
416 416 if f >= 0:
417 417 name = name[f+1:]
418 418 bcache[rev] = name
419 419 return name
420 420
421 421 if not pats:
422 422 raise util.Abort('at least one file name or pattern required')
423 423
424 424 bcache = {}
425 425 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
426 426 if not opts['user'] and not opts['changeset']:
427 427 opts['number'] = 1
428 428
429 429 if opts['rev']:
430 430 node = repo.changelog.lookup(opts['rev'])
431 431 else:
432 432 node = repo.dirstate.parents()[0]
433 433 change = repo.changelog.read(node)
434 434 mmap = repo.manifest.read(change[0])
435 435 for src, abs, rel, exact in walk(repo, pats, opts):
436 436 if abs not in mmap:
437 437 ui.warn("warning: %s is not in the repository!\n" % rel)
438 438 continue
439 439
440 440 lines = repo.file(abs).annotate(mmap[abs])
441 441 pieces = []
442 442
443 443 for o, f in opmap:
444 444 if opts[o]:
445 445 l = [f(n) for n, dummy in lines]
446 446 if l:
447 447 m = max(map(len, l))
448 448 pieces.append(["%*s" % (m, x) for x in l])
449 449
450 450 if pieces:
451 451 for p, l in zip(zip(*pieces), lines):
452 452 ui.write("%s: %s" % (" ".join(p), l[1]))
453 453
454 454 def cat(ui, repo, file1, rev=None, **opts):
455 455 """output the latest or given revision of a file"""
456 456 r = repo.file(relpath(repo, [file1])[0])
457 457 if rev:
458 458 try:
459 459 # assume all revision numbers are for changesets
460 460 n = repo.lookup(rev)
461 461 change = repo.changelog.read(n)
462 462 m = repo.manifest.read(change[0])
463 463 n = m[relpath(repo, [file1])[0]]
464 464 except hg.RepoError, KeyError:
465 465 n = r.lookup(rev)
466 466 else:
467 467 n = r.tip()
468 468 fp = make_file(repo, r, opts['output'], node=n)
469 469 fp.write(r.read(n))
470 470
471 471 def clone(ui, source, dest=None, **opts):
472 472 """make a copy of an existing repository"""
473 473 if dest is None:
474 474 dest = os.path.basename(os.path.normpath(source))
475 475
476 476 if os.path.exists(dest):
477 477 ui.warn("abort: destination '%s' already exists\n" % dest)
478 478 return 1
479 479
480 480 dest = os.path.realpath(dest)
481 481
482 482 class Dircleanup:
483 483 def __init__(self, dir_):
484 484 self.rmtree = shutil.rmtree
485 485 self.dir_ = dir_
486 486 os.mkdir(dir_)
487 487 def close(self):
488 488 self.dir_ = None
489 489 def __del__(self):
490 490 if self.dir_:
491 491 self.rmtree(self.dir_, True)
492 492
493 493 if opts['ssh']:
494 494 ui.setconfig("ui", "ssh", opts['ssh'])
495 495 if opts['remotecmd']:
496 496 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
497 497
498 498 d = Dircleanup(dest)
499 499 source = ui.expandpath(source)
500 500 abspath = source
501 501 other = hg.repository(ui, source)
502 502
503 503 if other.dev() != -1:
504 504 abspath = os.path.abspath(source)
505 505 copyfile = (os.stat(dest).st_dev == other.dev()
506 506 and getattr(os, 'link', None) or shutil.copy2)
507 507 if copyfile is not shutil.copy2:
508 508 ui.note("cloning by hardlink\n")
509 509 # we use a lock here because because we're not nicely ordered
510 510 l = lock.lock(os.path.join(source, ".hg", "lock"))
511 511
512 512 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
513 513 copyfile)
514 514 try:
515 515 os.unlink(os.path.join(dest, ".hg", "dirstate"))
516 516 except OSError:
517 517 pass
518 518
519 519 repo = hg.repository(ui, dest)
520 520
521 521 else:
522 522 repo = hg.repository(ui, dest, create=1)
523 523 repo.pull(other)
524 524
525 525 f = repo.opener("hgrc", "w")
526 526 f.write("[paths]\n")
527 527 f.write("default = %s\n" % abspath)
528 528
529 529 if not opts['noupdate']:
530 530 update(ui, repo)
531 531
532 532 d.close()
533 533
534 534 def commit(ui, repo, *pats, **opts):
535 535 """commit the specified files or all outstanding changes"""
536 536 if opts['text']:
537 537 ui.warn("Warning: -t and --text is deprecated,"
538 538 " please use -m or --message instead.\n")
539 539 message = opts['message'] or opts['text']
540 540 logfile = opts['logfile']
541 541 if not message and logfile:
542 542 try:
543 543 if logfile == '-':
544 544 message = sys.stdin.read()
545 545 else:
546 546 message = open(logfile).read()
547 547 except IOError, why:
548 548 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
549 549
550 550 if opts['addremove']:
551 551 addremove(ui, repo, *pats, **opts)
552 552 cwd = repo.getcwd()
553 553 if not pats and cwd:
554 554 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
555 555 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
556 556 fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
557 557 if pats:
558 558 c, a, d, u = repo.changes(files = fns, match = match)
559 559 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
560 560 else:
561 561 files = []
562 562 repo.commit(files, message, opts['user'], opts['date'], match)
563 563
564 564 def copy(ui, repo, source, dest):
565 565 """mark a file as copied or renamed for the next commit"""
566 566 return repo.copy(*relpath(repo, (source, dest)))
567 567
568 568 def debugcheckstate(ui, repo):
569 569 """validate the correctness of the current dirstate"""
570 570 parent1, parent2 = repo.dirstate.parents()
571 571 repo.dirstate.read()
572 572 dc = repo.dirstate.map
573 573 keys = dc.keys()
574 574 keys.sort()
575 575 m1n = repo.changelog.read(parent1)[0]
576 576 m2n = repo.changelog.read(parent2)[0]
577 577 m1 = repo.manifest.read(m1n)
578 578 m2 = repo.manifest.read(m2n)
579 579 errors = 0
580 580 for f in dc:
581 581 state = repo.dirstate.state(f)
582 582 if state in "nr" and f not in m1:
583 583 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
584 584 errors += 1
585 585 if state in "a" and f in m1:
586 586 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
587 587 errors += 1
588 588 if state in "m" and f not in m1 and f not in m2:
589 589 ui.warn("%s in state %s, but not in either manifest\n" %
590 590 (f, state))
591 591 errors += 1
592 592 for f in m1:
593 593 state = repo.dirstate.state(f)
594 594 if state not in "nrm":
595 595 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
596 596 errors += 1
597 597 if errors:
598 598 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
599 599
600 600 def debugstate(ui, repo):
601 601 """show the contents of the current dirstate"""
602 602 repo.dirstate.read()
603 603 dc = repo.dirstate.map
604 604 keys = dc.keys()
605 605 keys.sort()
606 606 for file_ in keys:
607 607 ui.write("%c %3o %10d %s %s\n"
608 608 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
609 609 time.strftime("%x %X",
610 610 time.localtime(dc[file_][3])), file_))
611 611
612 612 def debugindex(ui, file_):
613 613 """dump the contents of an index file"""
614 614 r = hg.revlog(hg.opener(""), file_, "")
615 615 ui.write(" rev offset length base linkrev" +
616 " p1 p2 nodeid\n")
616 " nodeid p1 p2\n")
617 617 for i in range(r.count()):
618 618 e = r.index[i]
619 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
619 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
620 620 i, e[0], e[1], e[2], e[3],
621 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
621 hg.short(e[6]), hg.short(e[4]), hg.short(e[5])))
622 622
623 623 def debugindexdot(ui, file_):
624 624 """dump an index DAG as a .dot file"""
625 625 r = hg.revlog(hg.opener(""), file_, "")
626 626 ui.write("digraph G {\n")
627 627 for i in range(r.count()):
628 628 e = r.index[i]
629 629 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
630 630 if e[5] != hg.nullid:
631 631 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
632 632 ui.write("}\n")
633 633
634 634 def debugwalk(ui, repo, *pats, **opts):
635 635 items = list(walk(repo, pats, opts))
636 636 if not items: return
637 637 fmt = '%%s %%-%ds %%-%ds %%s' % (
638 638 max([len(abs) for (src, abs, rel, exact) in items]),
639 639 max([len(rel) for (src, abs, rel, exact) in items]))
640 640 exactly = {True: 'exact', False: ''}
641 641 for src, abs, rel, exact in items:
642 642 print fmt % (src, abs, rel, exactly[exact])
643 643
644 644 def diff(ui, repo, *pats, **opts):
645 645 """diff working directory (or selected files)"""
646 646 revs = []
647 647 if opts['rev']:
648 648 revs = map(lambda x: repo.lookup(x), opts['rev'])
649 649
650 650 if len(revs) > 2:
651 651 raise util.Abort("too many revisions to diff")
652 652
653 653 files = []
654 654 match = util.always
655 655 if pats:
656 656 roots, match, results = makewalk(repo, pats, opts)
657 657 for src, abs, rel, exact in results:
658 658 files.append(abs)
659 659 dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
660 660
661 661 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
662 662 node = repo.lookup(changeset)
663 663 prev, other = repo.changelog.parents(node)
664 664 change = repo.changelog.read(node)
665 665
666 666 fp = make_file(repo, repo.changelog, opts['output'],
667 667 node=node, total=total, seqno=seqno,
668 668 revwidth=revwidth)
669 669 if fp != sys.stdout:
670 670 ui.note("%s\n" % fp.name)
671 671
672 672 fp.write("# HG changeset patch\n")
673 673 fp.write("# User %s\n" % change[1])
674 674 fp.write("# Node ID %s\n" % hg.hex(node))
675 675 fp.write("# Parent %s\n" % hg.hex(prev))
676 676 if other != hg.nullid:
677 677 fp.write("# Parent %s\n" % hg.hex(other))
678 678 fp.write(change[4].rstrip())
679 679 fp.write("\n\n")
680 680
681 681 dodiff(fp, ui, repo, None, prev, node)
682 682 if fp != sys.stdout: fp.close()
683 683
684 684 def export(ui, repo, *changesets, **opts):
685 685 """dump the header and diffs for one or more changesets"""
686 686 if not changesets:
687 687 raise util.Abort("export requires at least one changeset")
688 688 seqno = 0
689 689 revs = list(revrange(ui, repo, changesets))
690 690 total = len(revs)
691 691 revwidth = max(len(revs[0]), len(revs[-1]))
692 692 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
693 693 for cset in revs:
694 694 seqno += 1
695 695 doexport(ui, repo, cset, seqno, total, revwidth, opts)
696 696
697 697 def forget(ui, repo, *pats, **opts):
698 698 """don't add the specified files on the next commit"""
699 699 forget = []
700 700 for src, abs, rel, exact in walk(repo, pats, opts):
701 701 if repo.dirstate.state(abs) == 'a':
702 702 forget.append(abs)
703 703 if not exact: ui.status('forgetting ', rel, '\n')
704 704 repo.forget(forget)
705 705
706 706 def heads(ui, repo, **opts):
707 707 """show current repository heads"""
708 708 heads = repo.changelog.heads()
709 709 br = None
710 710 if opts['branches']:
711 711 br = repo.branchlookup(heads)
712 712 for n in repo.changelog.heads():
713 713 show_changeset(ui, repo, changenode=n, brinfo=br)
714 714
715 715 def identify(ui, repo):
716 716 """print information about the working copy"""
717 717 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
718 718 if not parents:
719 719 ui.write("unknown\n")
720 720 return
721 721
722 722 hexfunc = ui.verbose and hg.hex or hg.short
723 723 (c, a, d, u) = repo.changes()
724 724 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
725 725 (c or a or d) and "+" or "")]
726 726
727 727 if not ui.quiet:
728 728 # multiple tags for a single parent separated by '/'
729 729 parenttags = ['/'.join(tags)
730 730 for tags in map(repo.nodetags, parents) if tags]
731 731 # tags for multiple parents separated by ' + '
732 732 if parenttags:
733 733 output.append(' + '.join(parenttags))
734 734
735 735 ui.write("%s\n" % ' '.join(output))
736 736
737 737 def import_(ui, repo, patch1, *patches, **opts):
738 738 """import an ordered set of patches"""
739 739 patches = (patch1,) + patches
740 740
741 741 if not opts['force']:
742 742 (c, a, d, u) = repo.changes()
743 743 if c or a or d:
744 744 ui.warn("abort: outstanding uncommitted changes!\n")
745 745 return 1
746 746
747 747 d = opts["base"]
748 748 strip = opts["strip"]
749 749
750 750 for patch in patches:
751 751 ui.status("applying %s\n" % patch)
752 752 pf = os.path.join(d, patch)
753 753
754 754 message = []
755 755 user = None
756 756 hgpatch = False
757 757 for line in file(pf):
758 758 line = line.rstrip()
759 759 if line.startswith("--- ") or line.startswith("diff -r"):
760 760 break
761 761 elif hgpatch:
762 762 # parse values when importing the result of an hg export
763 763 if line.startswith("# User "):
764 764 user = line[7:]
765 765 ui.debug('User: %s\n' % user)
766 766 elif not line.startswith("# ") and line:
767 767 message.append(line)
768 768 hgpatch = False
769 769 elif line == '# HG changeset patch':
770 770 hgpatch = True
771 771 message = [] # We may have collected garbage
772 772 else:
773 773 message.append(line)
774 774
775 775 # make sure message isn't empty
776 776 if not message:
777 777 message = "imported patch %s\n" % patch
778 778 else:
779 779 message = "%s\n" % '\n'.join(message)
780 780 ui.debug('message:\n%s\n' % message)
781 781
782 782 f = os.popen("patch -p%d < '%s'" % (strip, pf))
783 783 files = []
784 784 for l in f.read().splitlines():
785 785 l.rstrip('\r\n');
786 786 ui.status("%s\n" % l)
787 787 if l.startswith('patching file '):
788 788 pf = l[14:]
789 789 if pf not in files:
790 790 files.append(pf)
791 791 patcherr = f.close()
792 792 if patcherr:
793 793 raise util.Abort("patch failed")
794 794
795 795 if len(files) > 0:
796 796 addremove(ui, repo, *files)
797 797 repo.commit(files, message, user)
798 798
799 799 def incoming(ui, repo, source="default"):
800 800 """show new changesets found in source"""
801 801 source = ui.expandpath(source)
802 802 other = hg.repository(ui, source)
803 803 if not other.local():
804 804 ui.warn("abort: incoming doesn't work for remote"
805 805 + " repositories yet, sorry!\n")
806 806 return 1
807 807 o = repo.findincoming(other)
808 808 if not o:
809 809 return
810 810 o = other.newer(o)
811 811 o.reverse()
812 812 for n in o:
813 813 show_changeset(ui, other, changenode=n)
814 814
815 815 def init(ui, dest="."):
816 816 """create a new repository in the given directory"""
817 817 if not os.path.exists(dest):
818 818 os.mkdir(dest)
819 819 hg.repository(ui, dest, create=1)
820 820
821 821 def locate(ui, repo, *pats, **opts):
822 822 """locate files matching specific patterns"""
823 823 end = '\n'
824 824 if opts['print0']: end = '\0'
825 825
826 826 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
827 827 if repo.dirstate.state(abs) == '?': continue
828 828 if opts['fullpath']:
829 829 ui.write(os.path.join(repo.root, abs), end)
830 830 else:
831 831 ui.write(rel, end)
832 832
833 833 def log(ui, repo, f=None, **opts):
834 834 """show the revision history of the repository or a single file"""
835 835 if f:
836 836 files = relpath(repo, [f])
837 837 filelog = repo.file(files[0])
838 838 log = filelog
839 839 lookup = filelog.lookup
840 840 else:
841 841 files = None
842 842 filelog = None
843 843 log = repo.changelog
844 844 lookup = repo.lookup
845 845 revlist = []
846 846 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
847 847 while revs:
848 848 if len(revs) == 1:
849 849 revlist.append(revs.pop(0))
850 850 else:
851 851 a = revs.pop(0)
852 852 b = revs.pop(0)
853 853 off = a > b and -1 or 1
854 854 revlist.extend(range(a, b + off, off))
855 855
856 856 for i in revlist or range(log.count() - 1, -1, -1):
857 857 show_changeset(ui, repo, filelog=filelog, rev=i)
858 858 if opts['patch']:
859 859 if filelog:
860 860 filenode = filelog.node(i)
861 861 i = filelog.linkrev(filenode)
862 862 changenode = repo.changelog.node(i)
863 863 prev, other = repo.changelog.parents(changenode)
864 864 dodiff(sys.stdout, ui, repo, files, prev, changenode)
865 865 ui.write("\n\n")
866 866
867 867 def manifest(ui, repo, rev=None):
868 868 """output the latest or given revision of the project manifest"""
869 869 if rev:
870 870 try:
871 871 # assume all revision numbers are for changesets
872 872 n = repo.lookup(rev)
873 873 change = repo.changelog.read(n)
874 874 n = change[0]
875 875 except hg.RepoError:
876 876 n = repo.manifest.lookup(rev)
877 877 else:
878 878 n = repo.manifest.tip()
879 879 m = repo.manifest.read(n)
880 880 mf = repo.manifest.readflags(n)
881 881 files = m.keys()
882 882 files.sort()
883 883
884 884 for f in files:
885 885 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
886 886
887 887 def outgoing(ui, repo, dest="default-push"):
888 888 """show changesets not found in destination"""
889 889 dest = ui.expandpath(dest)
890 890 other = hg.repository(ui, dest)
891 891 o = repo.findoutgoing(other)
892 892 o = repo.newer(o)
893 893 o.reverse()
894 894 for n in o:
895 895 show_changeset(ui, repo, changenode=n)
896 896
897 897 def parents(ui, repo, rev=None):
898 898 """show the parents of the working dir or revision"""
899 899 if rev:
900 900 p = repo.changelog.parents(repo.lookup(rev))
901 901 else:
902 902 p = repo.dirstate.parents()
903 903
904 904 for n in p:
905 905 if n != hg.nullid:
906 906 show_changeset(ui, repo, changenode=n)
907 907
908 908 def paths(ui, search = None):
909 909 """show definition of symbolic path names"""
910 910 try:
911 911 repo = hg.repository(ui=ui)
912 912 except:
913 913 pass
914 914
915 915 if search:
916 916 for name, path in ui.configitems("paths"):
917 917 if name == search:
918 918 ui.write("%s\n" % path)
919 919 return
920 920 ui.warn("not found!\n")
921 921 return 1
922 922 else:
923 923 for name, path in ui.configitems("paths"):
924 924 ui.write("%s = %s\n" % (name, path))
925 925
926 926 def pull(ui, repo, source="default", **opts):
927 927 """pull changes from the specified source"""
928 928 source = ui.expandpath(source)
929 929 ui.status('pulling from %s\n' % (source))
930 930
931 931 if opts['ssh']:
932 932 ui.setconfig("ui", "ssh", opts['ssh'])
933 933 if opts['remotecmd']:
934 934 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
935 935
936 936 other = hg.repository(ui, source)
937 937 r = repo.pull(other)
938 938 if not r:
939 939 if opts['update']:
940 940 return update(ui, repo)
941 941 else:
942 942 ui.status("(run 'hg update' to get a working copy)\n")
943 943
944 944 return r
945 945
946 946 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
947 947 """push changes to the specified destination"""
948 948 dest = ui.expandpath(dest)
949 949 ui.status('pushing to %s\n' % (dest))
950 950
951 951 if ssh:
952 952 ui.setconfig("ui", "ssh", ssh)
953 953 if remotecmd:
954 954 ui.setconfig("ui", "remotecmd", remotecmd)
955 955
956 956 other = hg.repository(ui, dest)
957 957 r = repo.push(other, force)
958 958 return r
959 959
960 960 def rawcommit(ui, repo, *flist, **rc):
961 961 "raw commit interface"
962 962 if rc['text']:
963 963 ui.warn("Warning: -t and --text is deprecated,"
964 964 " please use -m or --message instead.\n")
965 965 message = rc['message'] or rc['text']
966 966 if not message and rc['logfile']:
967 967 try:
968 968 message = open(rc['logfile']).read()
969 969 except IOError:
970 970 pass
971 971 if not message and not rc['logfile']:
972 972 ui.warn("abort: missing commit message\n")
973 973 return 1
974 974
975 975 files = relpath(repo, list(flist))
976 976 if rc['files']:
977 977 files += open(rc['files']).read().splitlines()
978 978
979 979 rc['parent'] = map(repo.lookup, rc['parent'])
980 980
981 981 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
982 982
983 983 def recover(ui, repo):
984 984 """roll back an interrupted transaction"""
985 985 repo.recover()
986 986
987 987 def remove(ui, repo, file1, *files):
988 988 """remove the specified files on the next commit"""
989 989 repo.remove(relpath(repo, (file1,) + files))
990 990
991 991 def revert(ui, repo, *names, **opts):
992 992 """revert modified files or dirs back to their unmodified states"""
993 993 node = opts['rev'] and repo.lookup(opts['rev']) or \
994 994 repo.dirstate.parents()[0]
995 995 root = os.path.realpath(repo.root)
996 996
997 997 def trimpath(p):
998 998 p = os.path.realpath(p)
999 999 if p.startswith(root):
1000 1000 rest = p[len(root):]
1001 1001 if not rest:
1002 1002 return rest
1003 1003 if p.startswith(os.sep):
1004 1004 return rest[1:]
1005 1005 return p
1006 1006
1007 1007 relnames = map(trimpath, names or [os.getcwd()])
1008 1008 chosen = {}
1009 1009
1010 1010 def choose(name):
1011 1011 def body(name):
1012 1012 for r in relnames:
1013 1013 if not name.startswith(r):
1014 1014 continue
1015 1015 rest = name[len(r):]
1016 1016 if not rest:
1017 1017 return r, True
1018 1018 depth = rest.count(os.sep)
1019 1019 if not r:
1020 1020 if depth == 0 or not opts['nonrecursive']:
1021 1021 return r, True
1022 1022 elif rest[0] == os.sep:
1023 1023 if depth == 1 or not opts['nonrecursive']:
1024 1024 return r, True
1025 1025 return None, False
1026 1026 relname, ret = body(name)
1027 1027 if ret:
1028 1028 chosen[relname] = 1
1029 1029 return ret
1030 1030
1031 1031 r = repo.update(node, False, True, choose, False)
1032 1032 for n in relnames:
1033 1033 if n not in chosen:
1034 1034 ui.warn('error: no matches for %s\n' % n)
1035 1035 r = 1
1036 1036 sys.stdout.flush()
1037 1037 return r
1038 1038
1039 1039 def root(ui, repo):
1040 1040 """print the root (top) of the current working dir"""
1041 1041 ui.write(repo.root + "\n")
1042 1042
1043 1043 def serve(ui, repo, **opts):
1044 1044 """export the repository via HTTP"""
1045 1045
1046 1046 if opts["stdio"]:
1047 1047 fin, fout = sys.stdin, sys.stdout
1048 1048 sys.stdout = sys.stderr
1049 1049
1050 1050 def getarg():
1051 1051 argline = fin.readline()[:-1]
1052 1052 arg, l = argline.split()
1053 1053 val = fin.read(int(l))
1054 1054 return arg, val
1055 1055 def respond(v):
1056 1056 fout.write("%d\n" % len(v))
1057 1057 fout.write(v)
1058 1058 fout.flush()
1059 1059
1060 1060 lock = None
1061 1061
1062 1062 while 1:
1063 1063 cmd = fin.readline()[:-1]
1064 1064 if cmd == '':
1065 1065 return
1066 1066 if cmd == "heads":
1067 1067 h = repo.heads()
1068 1068 respond(" ".join(map(hg.hex, h)) + "\n")
1069 1069 if cmd == "lock":
1070 1070 lock = repo.lock()
1071 1071 respond("")
1072 1072 if cmd == "unlock":
1073 1073 if lock:
1074 1074 lock.release()
1075 1075 lock = None
1076 1076 respond("")
1077 1077 elif cmd == "branches":
1078 1078 arg, nodes = getarg()
1079 1079 nodes = map(hg.bin, nodes.split(" "))
1080 1080 r = []
1081 1081 for b in repo.branches(nodes):
1082 1082 r.append(" ".join(map(hg.hex, b)) + "\n")
1083 1083 respond("".join(r))
1084 1084 elif cmd == "between":
1085 1085 arg, pairs = getarg()
1086 1086 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1087 1087 r = []
1088 1088 for b in repo.between(pairs):
1089 1089 r.append(" ".join(map(hg.hex, b)) + "\n")
1090 1090 respond("".join(r))
1091 1091 elif cmd == "changegroup":
1092 1092 nodes = []
1093 1093 arg, roots = getarg()
1094 1094 nodes = map(hg.bin, roots.split(" "))
1095 1095
1096 1096 cg = repo.changegroup(nodes)
1097 1097 while 1:
1098 1098 d = cg.read(4096)
1099 1099 if not d:
1100 1100 break
1101 1101 fout.write(d)
1102 1102
1103 1103 fout.flush()
1104 1104
1105 1105 elif cmd == "addchangegroup":
1106 1106 if not lock:
1107 1107 respond("not locked")
1108 1108 continue
1109 1109 respond("")
1110 1110
1111 1111 r = repo.addchangegroup(fin)
1112 1112 respond("")
1113 1113
1114 1114 optlist = "name templates style address port ipv6 accesslog errorlog"
1115 1115 for o in optlist.split():
1116 1116 if opts[o]:
1117 1117 ui.setconfig("web", o, opts[o])
1118 1118
1119 1119 httpd = hgweb.create_server(repo)
1120 1120
1121 1121 if ui.verbose:
1122 1122 addr, port = httpd.socket.getsockname()
1123 1123 if addr == '0.0.0.0':
1124 1124 addr = socket.gethostname()
1125 1125 else:
1126 1126 try:
1127 1127 addr = socket.gethostbyaddr(addr)[0]
1128 1128 except socket.error:
1129 1129 pass
1130 1130 if port != 80:
1131 1131 ui.status('listening at http://%s:%d/\n' % (addr, port))
1132 1132 else:
1133 1133 ui.status('listening at http://%s/\n' % addr)
1134 1134 httpd.serve_forever()
1135 1135
1136 1136 def status(ui, repo, *pats, **opts):
1137 1137 '''show changed files in the working directory
1138 1138
1139 1139 M = modified
1140 1140 A = added
1141 1141 R = removed
1142 1142 ? = not tracked
1143 1143 '''
1144 1144
1145 1145 cwd = repo.getcwd()
1146 1146 files, matchfn = matchpats(repo, cwd, pats, opts)
1147 1147 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1148 1148 for n in repo.changes(files=files, match=matchfn)]
1149 1149
1150 1150 changetypes = [('modified', 'M', c),
1151 1151 ('added', 'A', a),
1152 1152 ('removed', 'R', d),
1153 1153 ('unknown', '?', u)]
1154 1154
1155 1155 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1156 1156 or changetypes):
1157 1157 for f in changes:
1158 1158 ui.write("%s %s\n" % (char, f))
1159 1159
1160 1160 def tag(ui, repo, name, rev=None, **opts):
1161 1161 """add a tag for the current tip or a given revision"""
1162 1162 if opts['text']:
1163 1163 ui.warn("Warning: -t and --text is deprecated,"
1164 1164 " please use -m or --message instead.\n")
1165 1165 if name == "tip":
1166 1166 ui.warn("abort: 'tip' is a reserved name!\n")
1167 1167 return -1
1168 1168 if rev:
1169 1169 r = hg.hex(repo.lookup(rev))
1170 1170 else:
1171 1171 r = hg.hex(repo.changelog.tip())
1172 1172
1173 1173 if name.find(revrangesep) >= 0:
1174 1174 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1175 1175 return -1
1176 1176
1177 1177 if opts['local']:
1178 1178 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1179 1179 return
1180 1180
1181 1181 (c, a, d, u) = repo.changes()
1182 1182 for x in (c, a, d, u):
1183 1183 if ".hgtags" in x:
1184 1184 ui.warn("abort: working copy of .hgtags is changed!\n")
1185 1185 ui.status("(please commit .hgtags manually)\n")
1186 1186 return -1
1187 1187
1188 1188 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1189 1189 if repo.dirstate.state(".hgtags") == '?':
1190 1190 repo.add([".hgtags"])
1191 1191
1192 1192 message = (opts['message'] or opts['text'] or
1193 1193 "Added tag %s for changeset %s" % (name, r))
1194 1194 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1195 1195
1196 1196 def tags(ui, repo):
1197 1197 """list repository tags"""
1198 1198
1199 1199 l = repo.tagslist()
1200 1200 l.reverse()
1201 1201 for t, n in l:
1202 1202 try:
1203 1203 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1204 1204 except KeyError:
1205 1205 r = " ?:?"
1206 1206 ui.write("%-30s %s\n" % (t, r))
1207 1207
1208 1208 def tip(ui, repo):
1209 1209 """show the tip revision"""
1210 1210 n = repo.changelog.tip()
1211 1211 show_changeset(ui, repo, changenode=n)
1212 1212
1213 1213 def undo(ui, repo):
1214 1214 """undo the last commit or pull
1215 1215
1216 1216 Roll back the last pull or commit transaction on the
1217 1217 repository, restoring the project to its earlier state.
1218 1218
1219 1219 This command should be used with care. There is only one level of
1220 1220 undo and there is no redo.
1221 1221
1222 1222 This command is not intended for use on public repositories. Once
1223 1223 a change is visible for pull by other users, undoing it locally is
1224 1224 ineffective.
1225 1225 """
1226 1226 repo.undo()
1227 1227
1228 1228 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1229 1229 '''update or merge working directory
1230 1230
1231 1231 If there are no outstanding changes in the working directory and
1232 1232 there is a linear relationship between the current version and the
1233 1233 requested version, the result is the requested version.
1234 1234
1235 1235 Otherwise the result is a merge between the contents of the
1236 1236 current working directory and the requested version. Files that
1237 1237 changed between either parent are marked as changed for the next
1238 1238 commit and a commit must be performed before any further updates
1239 1239 are allowed.
1240 1240 '''
1241 1241 if branch:
1242 1242 br = repo.branchlookup(branch=branch)
1243 1243 found = []
1244 1244 for x in br:
1245 1245 if branch in br[x]:
1246 1246 found.append(x)
1247 1247 if len(found) > 1:
1248 1248 ui.warn("Found multiple heads for %s\n" % branch)
1249 1249 for x in found:
1250 1250 show_changeset(ui, repo, changenode=x, brinfo=br)
1251 1251 return 1
1252 1252 if len(found) == 1:
1253 1253 node = found[0]
1254 1254 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1255 1255 else:
1256 1256 ui.warn("branch %s not found\n" % (branch))
1257 1257 return 1
1258 1258 else:
1259 1259 node = node and repo.lookup(node) or repo.changelog.tip()
1260 1260 return repo.update(node, allow=merge, force=clean)
1261 1261
1262 1262 def verify(ui, repo):
1263 1263 """verify the integrity of the repository"""
1264 1264 return repo.verify()
1265 1265
1266 1266 # Command options and aliases are listed here, alphabetically
1267 1267
1268 1268 table = {
1269 1269 "^add":
1270 1270 (add,
1271 1271 [('I', 'include', [], 'include path in search'),
1272 1272 ('X', 'exclude', [], 'exclude path from search')],
1273 1273 "hg add [OPTION]... [FILE]..."),
1274 1274 "addremove":
1275 1275 (addremove,
1276 1276 [('I', 'include', [], 'include path in search'),
1277 1277 ('X', 'exclude', [], 'exclude path from search')],
1278 1278 "hg addremove [OPTION]... [FILE]..."),
1279 1279 "^annotate":
1280 1280 (annotate,
1281 1281 [('r', 'rev', '', 'revision'),
1282 1282 ('u', 'user', None, 'show user'),
1283 1283 ('n', 'number', None, 'show revision number'),
1284 1284 ('c', 'changeset', None, 'show changeset'),
1285 1285 ('I', 'include', [], 'include path in search'),
1286 1286 ('X', 'exclude', [], 'exclude path from search')],
1287 1287 'hg annotate [OPTION]... FILE...'),
1288 1288 "cat":
1289 1289 (cat,
1290 1290 [('o', 'output', "", 'output to file')],
1291 1291 'hg cat [-o OUTFILE] FILE [REV]'),
1292 1292 "^clone":
1293 1293 (clone,
1294 1294 [('U', 'noupdate', None, 'skip update after cloning'),
1295 1295 ('e', 'ssh', "", 'ssh command'),
1296 1296 ('', 'remotecmd', "", 'remote hg command')],
1297 1297 'hg clone [OPTIONS] SOURCE [DEST]'),
1298 1298 "^commit|ci":
1299 1299 (commit,
1300 1300 [('A', 'addremove', None, 'run add/remove during commit'),
1301 1301 ('I', 'include', [], 'include path in search'),
1302 1302 ('X', 'exclude', [], 'exclude path from search'),
1303 1303 ('m', 'message', "", 'commit message'),
1304 1304 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1305 1305 ('l', 'logfile', "", 'commit message file'),
1306 1306 ('d', 'date', "", 'date code'),
1307 1307 ('u', 'user', "", 'user')],
1308 1308 'hg commit [OPTION]... [FILE]...'),
1309 1309 "copy": (copy, [], 'hg copy SOURCE DEST'),
1310 1310 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1311 1311 "debugstate": (debugstate, [], 'debugstate'),
1312 1312 "debugindex": (debugindex, [], 'debugindex FILE'),
1313 1313 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1314 1314 "debugwalk":
1315 1315 (debugwalk,
1316 1316 [('I', 'include', [], 'include path in search'),
1317 1317 ('X', 'exclude', [], 'exclude path from search')],
1318 1318 'debugwalk [OPTION]... [FILE]...'),
1319 1319 "^diff":
1320 1320 (diff,
1321 1321 [('r', 'rev', [], 'revision'),
1322 1322 ('I', 'include', [], 'include path in search'),
1323 1323 ('X', 'exclude', [], 'exclude path from search')],
1324 1324 'hg diff [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1325 1325 "^export":
1326 1326 (export,
1327 1327 [('o', 'output', "", 'output to file')],
1328 1328 "hg export [-o OUTFILE] REV..."),
1329 1329 "forget":
1330 1330 (forget,
1331 1331 [('I', 'include', [], 'include path in search'),
1332 1332 ('X', 'exclude', [], 'exclude path from search')],
1333 1333 "hg forget [OPTION]... FILE..."),
1334 1334 "heads":
1335 1335 (heads,
1336 1336 [('b', 'branches', None, 'find branch info')],
1337 1337 'hg [-b] heads'),
1338 1338 "help": (help_, [], 'hg help [COMMAND]'),
1339 1339 "identify|id": (identify, [], 'hg identify'),
1340 1340 "import|patch":
1341 1341 (import_,
1342 1342 [('p', 'strip', 1, 'path strip'),
1343 1343 ('f', 'force', None, 'skip check for outstanding changes'),
1344 1344 ('b', 'base', "", 'base path')],
1345 1345 "hg import [-p NUM] [-b BASE] PATCH..."),
1346 1346 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1347 1347 "^init": (init, [], 'hg init [DEST]'),
1348 1348 "locate":
1349 1349 (locate,
1350 1350 [('r', 'rev', '', 'revision'),
1351 1351 ('0', 'print0', None, 'end records with NUL'),
1352 1352 ('f', 'fullpath', None, 'print complete paths'),
1353 1353 ('I', 'include', [], 'include path in search'),
1354 1354 ('X', 'exclude', [], 'exclude path from search')],
1355 1355 'hg locate [OPTION]... [PATTERN]...'),
1356 1356 "^log|history":
1357 1357 (log,
1358 1358 [('r', 'rev', [], 'revision'),
1359 1359 ('p', 'patch', None, 'show patch')],
1360 1360 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1361 1361 "manifest": (manifest, [], 'hg manifest [REV]'),
1362 1362 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1363 1363 "parents": (parents, [], 'hg parents [REV]'),
1364 1364 "paths": (paths, [], 'hg paths [NAME]'),
1365 1365 "^pull":
1366 1366 (pull,
1367 1367 [('u', 'update', None, 'update working directory'),
1368 1368 ('e', 'ssh', "", 'ssh command'),
1369 1369 ('', 'remotecmd', "", 'remote hg command')],
1370 1370 'hg pull [OPTIONS] [SOURCE]'),
1371 1371 "^push":
1372 1372 (push,
1373 1373 [('f', 'force', None, 'force push'),
1374 1374 ('e', 'ssh', "", 'ssh command'),
1375 1375 ('', 'remotecmd', "", 'remote hg command')],
1376 1376 'hg push [-f] [DEST]'),
1377 1377 "rawcommit":
1378 1378 (rawcommit,
1379 1379 [('p', 'parent', [], 'parent'),
1380 1380 ('d', 'date', "", 'date code'),
1381 1381 ('u', 'user', "", 'user'),
1382 1382 ('F', 'files', "", 'file list'),
1383 1383 ('m', 'message', "", 'commit message'),
1384 1384 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1385 1385 ('l', 'logfile', "", 'commit message file')],
1386 1386 'hg rawcommit [OPTION]... [FILE]...'),
1387 1387 "recover": (recover, [], "hg recover"),
1388 1388 "^remove|rm": (remove, [], "hg remove FILE..."),
1389 1389 "^revert":
1390 1390 (revert,
1391 1391 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1392 1392 ("r", "rev", "", "revision")],
1393 1393 "hg revert [-n] [-r REV] [NAME]..."),
1394 1394 "root": (root, [], "hg root"),
1395 1395 "^serve":
1396 1396 (serve,
1397 1397 [('A', 'accesslog', '', 'access log file'),
1398 1398 ('E', 'errorlog', '', 'error log file'),
1399 1399 ('p', 'port', 0, 'listen port'),
1400 1400 ('a', 'address', '', 'interface address'),
1401 1401 ('n', 'name', "", 'repository name'),
1402 1402 ('', 'stdio', None, 'for remote clients'),
1403 1403 ('t', 'templates', "", 'template directory'),
1404 1404 ('', 'style', "", 'template style'),
1405 1405 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1406 1406 "hg serve [OPTION]..."),
1407 1407 "^status":
1408 1408 (status,
1409 1409 [('m', 'modified', None, 'show only modified files'),
1410 1410 ('a', 'added', None, 'show only added files'),
1411 1411 ('r', 'removed', None, 'show only removed files'),
1412 1412 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1413 1413 ('I', 'include', [], 'include path in search'),
1414 1414 ('X', 'exclude', [], 'exclude path from search')],
1415 1415 "hg status [OPTION]... [FILE]..."),
1416 1416 "tag":
1417 1417 (tag,
1418 1418 [('l', 'local', None, 'make the tag local'),
1419 1419 ('m', 'message', "", 'commit message'),
1420 1420 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1421 1421 ('d', 'date', "", 'date code'),
1422 1422 ('u', 'user', "", 'user')],
1423 1423 'hg tag [OPTION]... NAME [REV]'),
1424 1424 "tags": (tags, [], 'hg tags'),
1425 1425 "tip": (tip, [], 'hg tip'),
1426 1426 "undo": (undo, [], 'hg undo'),
1427 1427 "^update|up|checkout|co":
1428 1428 (update,
1429 1429 [('b', 'branch', "", 'checkout the head of a specific branch'),
1430 1430 ('m', 'merge', None, 'allow merging of conflicts'),
1431 1431 ('C', 'clean', None, 'overwrite locally modified files')],
1432 1432 'hg update [-b TAG] [-m] [-C] [REV]'),
1433 1433 "verify": (verify, [], 'hg verify'),
1434 1434 "version": (show_version, [], 'hg version'),
1435 1435 }
1436 1436
1437 1437 globalopts = [('v', 'verbose', None, 'verbose mode'),
1438 1438 ('', 'debug', None, 'debug mode'),
1439 1439 ('q', 'quiet', None, 'quiet mode'),
1440 1440 ('', 'profile', None, 'profile'),
1441 1441 ('', 'cwd', '', 'change working directory'),
1442 1442 ('R', 'repository', "", 'repository root directory'),
1443 1443 ('', 'traceback', None, 'print traceback on exception'),
1444 1444 ('y', 'noninteractive', None, 'run non-interactively'),
1445 1445 ('', 'version', None, 'output version information and exit'),
1446 1446 ('', 'time', None, 'time how long the command takes'),
1447 1447 ]
1448 1448
1449 1449 norepo = "clone init version help debugindex debugindexdot paths"
1450 1450
1451 1451 def find(cmd):
1452 1452 for e in table.keys():
1453 1453 if re.match("(%s)$" % e, cmd):
1454 1454 return e, table[e]
1455 1455
1456 1456 raise UnknownCommand(cmd)
1457 1457
1458 1458 class SignalInterrupt(Exception):
1459 1459 """Exception raised on SIGTERM and SIGHUP."""
1460 1460
1461 1461 def catchterm(*args):
1462 1462 raise SignalInterrupt
1463 1463
1464 1464 def run():
1465 1465 sys.exit(dispatch(sys.argv[1:]))
1466 1466
1467 1467 class ParseError(Exception):
1468 1468 """Exception raised on errors in parsing the command line."""
1469 1469
1470 1470 def parse(args):
1471 1471 options = {}
1472 1472 cmdoptions = {}
1473 1473
1474 1474 try:
1475 1475 args = fancyopts.fancyopts(args, globalopts, options)
1476 1476 except fancyopts.getopt.GetoptError, inst:
1477 1477 raise ParseError(None, inst)
1478 1478
1479 1479 if options["version"]:
1480 1480 return ("version", show_version, [], options, cmdoptions)
1481 1481 elif not args:
1482 1482 return ("help", help_, ["shortlist"], options, cmdoptions)
1483 1483 else:
1484 1484 cmd, args = args[0], args[1:]
1485 1485
1486 1486 i = find(cmd)[1]
1487 1487
1488 1488 # combine global options into local
1489 1489 c = list(i[1])
1490 1490 for o in globalopts:
1491 1491 c.append((o[0], o[1], options[o[1]], o[3]))
1492 1492
1493 1493 try:
1494 1494 args = fancyopts.fancyopts(args, c, cmdoptions)
1495 1495 except fancyopts.getopt.GetoptError, inst:
1496 1496 raise ParseError(cmd, inst)
1497 1497
1498 1498 # separate global options back out
1499 1499 for o in globalopts:
1500 1500 n = o[1]
1501 1501 options[n] = cmdoptions[n]
1502 1502 del cmdoptions[n]
1503 1503
1504 1504 return (cmd, i[0], args, options, cmdoptions)
1505 1505
1506 1506 def dispatch(args):
1507 1507 signal.signal(signal.SIGTERM, catchterm)
1508 1508 try:
1509 1509 signal.signal(signal.SIGHUP, catchterm)
1510 1510 except AttributeError:
1511 1511 pass
1512 1512
1513 1513 try:
1514 1514 cmd, func, args, options, cmdoptions = parse(args)
1515 1515 except ParseError, inst:
1516 1516 u = ui.ui()
1517 1517 if inst.args[0]:
1518 1518 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1519 1519 help_(u, inst.args[0])
1520 1520 else:
1521 1521 u.warn("hg: %s\n" % inst.args[1])
1522 1522 help_(u, 'shortlist')
1523 1523 sys.exit(-1)
1524 1524 except UnknownCommand, inst:
1525 1525 u = ui.ui()
1526 1526 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1527 1527 help_(u, 'shortlist')
1528 1528 sys.exit(1)
1529 1529
1530 1530 if options['cwd']:
1531 1531 try:
1532 1532 os.chdir(options['cwd'])
1533 1533 except OSError, inst:
1534 1534 u = ui.ui()
1535 1535 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1536 1536 sys.exit(1)
1537 1537
1538 1538 if options["time"]:
1539 1539 def get_times():
1540 1540 t = os.times()
1541 1541 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1542 1542 t = (t[0], t[1], t[2], t[3], time.clock())
1543 1543 return t
1544 1544 s = get_times()
1545 1545 def print_time():
1546 1546 t = get_times()
1547 1547 u = ui.ui()
1548 1548 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1549 1549 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1550 1550 atexit.register(print_time)
1551 1551
1552 1552 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1553 1553 not options["noninteractive"])
1554 1554
1555 1555 try:
1556 1556 try:
1557 1557 if cmd not in norepo.split():
1558 1558 path = options["repository"] or ""
1559 1559 repo = hg.repository(ui=u, path=path)
1560 1560 d = lambda: func(u, repo, *args, **cmdoptions)
1561 1561 else:
1562 1562 d = lambda: func(u, *args, **cmdoptions)
1563 1563
1564 1564 if options['profile']:
1565 1565 import hotshot, hotshot.stats
1566 1566 prof = hotshot.Profile("hg.prof")
1567 1567 r = prof.runcall(d)
1568 1568 prof.close()
1569 1569 stats = hotshot.stats.load("hg.prof")
1570 1570 stats.strip_dirs()
1571 1571 stats.sort_stats('time', 'calls')
1572 1572 stats.print_stats(40)
1573 1573 return r
1574 1574 else:
1575 1575 return d()
1576 1576 except:
1577 1577 if options['traceback']:
1578 1578 traceback.print_exc()
1579 1579 raise
1580 1580 except hg.RepoError, inst:
1581 1581 u.warn("abort: ", inst, "!\n")
1582 1582 except SignalInterrupt:
1583 1583 u.warn("killed!\n")
1584 1584 except KeyboardInterrupt:
1585 1585 try:
1586 1586 u.warn("interrupted!\n")
1587 1587 except IOError, inst:
1588 1588 if inst.errno == errno.EPIPE:
1589 1589 if u.debugflag:
1590 1590 u.warn("\nbroken pipe\n")
1591 1591 else:
1592 1592 raise
1593 1593 except IOError, inst:
1594 1594 if hasattr(inst, "code"):
1595 1595 u.warn("abort: %s\n" % inst)
1596 1596 elif hasattr(inst, "reason"):
1597 1597 u.warn("abort: error: %s\n" % inst.reason[1])
1598 1598 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1599 1599 if u.debugflag: u.warn("broken pipe\n")
1600 1600 else:
1601 1601 raise
1602 1602 except OSError, inst:
1603 1603 if hasattr(inst, "filename"):
1604 1604 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1605 1605 else:
1606 1606 u.warn("abort: %s\n" % inst.strerror)
1607 1607 except util.Abort, inst:
1608 1608 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1609 1609 sys.exit(1)
1610 1610 except TypeError, inst:
1611 1611 # was this an argument error?
1612 1612 tb = traceback.extract_tb(sys.exc_info()[2])
1613 1613 if len(tb) > 2: # no
1614 1614 raise
1615 1615 u.debug(inst, "\n")
1616 1616 u.warn("%s: invalid arguments\n" % cmd)
1617 1617 help_(u, cmd)
1618 1618 except UnknownCommand, inst:
1619 1619 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1620 1620 help_(u, 'shortlist')
1621 1621
1622 1622 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now