##// END OF EJS Templates
Show tags in hg history etc....
Thomas Arendsen Hein -
r387:c07c6fb2 default
parent child Browse files
Show More
@@ -1,762 +1,764 b''
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 import os, re, sys, signal
9 9 import fancyopts, ui, hg
10 10 from demandload import *
11 11 demandload(globals(), "mdiff time hgweb traceback random signal errno")
12 12
13 13 class UnknownCommand(Exception): pass
14 14
15 15 def filterfiles(filters, files):
16 16 l = [ x for x in files if x in filters ]
17 17
18 18 for t in filters:
19 19 if t and t[-1] != os.sep: t += os.sep
20 20 l += [ x for x in files if x.startswith(t) ]
21 21 return l
22 22
23 23 def relfilter(repo, files):
24 24 if os.getcwd() != repo.root:
25 25 p = os.getcwd()[len(repo.root) + 1: ]
26 26 return filterfiles([p], files)
27 27 return files
28 28
29 29 def relpath(repo, args):
30 30 if os.getcwd() != repo.root:
31 31 p = os.getcwd()[len(repo.root) + 1: ]
32 32 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
33 33 return args
34 34
35 35 def dodiff(repo, path, files = None, node1 = None, node2 = None):
36 36 def date(c):
37 37 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
38 38
39 39 if node2:
40 40 change = repo.changelog.read(node2)
41 41 mmap2 = repo.manifest.read(change[0])
42 42 (c, a, d) = repo.diffrevs(node1, node2)
43 43 def read(f): return repo.file(f).read(mmap2[f])
44 44 date2 = date(change)
45 45 else:
46 46 date2 = time.asctime()
47 47 (c, a, d, u) = repo.diffdir(path, node1)
48 48 if not node1:
49 49 node1 = repo.dirstate.parents()[0]
50 50 def read(f): return file(os.path.join(repo.root, f)).read()
51 51
52 52 change = repo.changelog.read(node1)
53 53 mmap = repo.manifest.read(change[0])
54 54 date1 = date(change)
55 55
56 56 if files:
57 57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
58 58
59 59 for f in c:
60 60 to = None
61 61 if f in mmap:
62 62 to = repo.file(f).read(mmap[f])
63 63 tn = read(f)
64 64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
65 65 for f in a:
66 66 to = None
67 67 tn = read(f)
68 68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
69 69 for f in d:
70 70 to = repo.file(f).read(mmap[f])
71 71 tn = None
72 72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
73 73
74 74 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
75 75 """show a single changeset or file revision"""
76 76 changelog = repo.changelog
77 77 if filelog:
78 78 log = filelog
79 79 filerev = rev
80 80 node = filenode = filelog.node(filerev)
81 81 changerev = filelog.linkrev(filenode)
82 82 changenode = changenode or changelog.node(changerev)
83 83 else:
84 84 log = changelog
85 85 changerev = rev
86 86 if changenode is None:
87 87 changenode = changelog.node(changerev)
88 88 elif not changerev:
89 89 rev = changerev = changelog.rev(changenode)
90 90 node = changenode
91 91
92 92 if ui.quiet:
93 93 ui.write("%d:%s\n" % (rev, hg.hex(node)))
94 94 return
95 95
96 96 changes = changelog.read(changenode)
97 97
98 98 parents = [(log.rev(parent), hg.hex(parent))
99 99 for parent in log.parents(node)
100 100 if ui.debugflag or parent != hg.nullid]
101 101 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
102 102 parents = []
103 103
104 104 if filelog:
105 105 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
106 106 for parent in parents:
107 107 ui.write("parent: %d:%s\n" % parent)
108 108 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
109 109 else:
110 110 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
111 for tag in repo.nodetags(changenode):
112 ui.status("tag: %s\n" % tag)
111 113 for parent in parents:
112 114 ui.write("parent: %d:%s\n" % parent)
113 115 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
114 116 hg.hex(changes[0])))
115 117 ui.status("user: %s\n" % changes[1])
116 118 ui.status("date: %s\n" % time.asctime(
117 119 time.localtime(float(changes[2].split(' ')[0]))))
118 120 ui.note("files: %s\n" % " ".join(changes[3]))
119 121 description = changes[4].strip()
120 122 if description:
121 123 if ui.verbose:
122 124 ui.status("description:\n")
123 125 ui.status(description)
124 126 ui.status("\n")
125 127 else:
126 128 ui.status("summary: %s\n" % description.splitlines()[0])
127 129 ui.status("\n")
128 130
129 131 def help(ui, cmd=None):
130 132 '''show help for a given command or all commands'''
131 133 if cmd:
132 134 try:
133 135 i = find(cmd)
134 136 ui.write("%s\n\n" % i[2])
135 137
136 138 if i[1]:
137 139 for s, l, d, c in i[1]:
138 140 opt=' '
139 141 if s: opt = opt + '-' + s + ' '
140 142 if l: opt = opt + '--' + l + ' '
141 143 if d: opt = opt + '(' + str(d) + ')'
142 144 ui.write(opt, "\n")
143 145 if c: ui.write(' %s\n' % c)
144 146 ui.write("\n")
145 147
146 148 ui.write(i[0].__doc__, "\n")
147 149 except UnknownCommand:
148 150 ui.warn("hg: unknown command %s\n" % cmd)
149 151 sys.exit(0)
150 152 else:
151 153 ui.status('hg commands:\n\n')
152 154
153 155 h = {}
154 156 for e in table.values():
155 157 f = e[0]
156 158 if f.__name__.startswith("debug"): continue
157 159 d = ""
158 160 if f.__doc__:
159 161 d = f.__doc__.splitlines(0)[0].rstrip()
160 162 h[f.__name__] = d
161 163
162 164 fns = h.keys()
163 165 fns.sort()
164 166 m = max(map(len, fns))
165 167 for f in fns:
166 168 ui.status(' %-*s %s\n' % (m, f, h[f]))
167 169
168 170 # Commands start here, listed alphabetically
169 171
170 172 def add(ui, repo, file, *files):
171 173 '''add the specified files on the next commit'''
172 174 repo.add(relpath(repo, (file,) + files))
173 175
174 176 def addremove(ui, repo, *files):
175 177 """add all new files, delete all missing files"""
176 178 if files:
177 179 files = relpath(repo, files)
178 180 d = []
179 181 u = []
180 182 for f in files:
181 183 p = repo.wjoin(f)
182 184 s = repo.dirstate.state(f)
183 185 isfile = os.path.isfile(p)
184 186 if s != 'r' and not isfile:
185 187 d.append(f)
186 188 elif s not in 'nmai' and isfile:
187 189 u.append(f)
188 190 else:
189 191 (c, a, d, u) = repo.diffdir(repo.root)
190 192 repo.add(u)
191 193 repo.remove(d)
192 194
193 195 def annotate(u, repo, file, *files, **ops):
194 196 """show changeset information per file line"""
195 197 def getnode(rev):
196 198 return hg.short(repo.changelog.node(rev))
197 199
198 200 def getname(rev):
199 201 try:
200 202 return bcache[rev]
201 203 except KeyError:
202 204 cl = repo.changelog.read(repo.changelog.node(rev))
203 205 name = cl[1]
204 206 f = name.find('@')
205 207 if f >= 0:
206 208 name = name[:f]
207 209 bcache[rev] = name
208 210 return name
209 211
210 212 bcache = {}
211 213 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
212 214 if not ops['user'] and not ops['changeset']:
213 215 ops['number'] = 1
214 216
215 217 node = repo.dirstate.parents()[0]
216 218 if ops['revision']:
217 219 node = repo.changelog.lookup(ops['revision'])
218 220 change = repo.changelog.read(node)
219 221 mmap = repo.manifest.read(change[0])
220 222 maxuserlen = 0
221 223 maxchangelen = 0
222 224 for f in relpath(repo, (file,) + files):
223 225 lines = repo.file(f).annotate(mmap[f])
224 226 pieces = []
225 227
226 228 for o, f in opmap:
227 229 if ops[o]:
228 230 l = [ f(n) for n,t in lines ]
229 231 m = max(map(len, l))
230 232 pieces.append([ "%*s" % (m, x) for x in l])
231 233
232 234 for p,l in zip(zip(*pieces), lines):
233 235 u.write(" ".join(p) + ": " + l[1])
234 236
235 237 def cat(ui, repo, file, rev = []):
236 238 """output the latest or given revision of a file"""
237 239 r = repo.file(relpath(repo, [file])[0])
238 240 n = r.tip()
239 241 if rev: n = r.lookup(rev)
240 242 sys.stdout.write(r.read(n))
241 243
242 244 def commit(ui, repo, *files, **opts):
243 245 """commit the specified files or all outstanding changes"""
244 246 text = opts['text']
245 247 if not text and opts['logfile']:
246 248 try: text = open(opts['logfile']).read()
247 249 except IOError: pass
248 250
249 251 if opts['addremove']:
250 252 addremove(ui, repo, *files)
251 253 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
252 254
253 255 def copy(ui, repo, source, dest):
254 256 """mark a file as copied or renamed for the next commit"""
255 257 return repo.copy(*relpath(repo, (source, dest)))
256 258
257 259 def debugaddchangegroup(ui, repo):
258 260 data = sys.stdin.read()
259 261 repo.addchangegroup(data)
260 262
261 263 def debugchangegroup(ui, repo, roots):
262 264 newer = repo.newer(map(repo.lookup, roots))
263 265 for chunk in repo.changegroup(newer):
264 266 sys.stdout.write(chunk)
265 267
266 268 def debugindex(ui, file):
267 269 r = hg.revlog(open, file, "")
268 270 print " rev offset length base linkrev"+\
269 271 " p1 p2 nodeid"
270 272 for i in range(r.count()):
271 273 e = r.index[i]
272 274 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
273 275 i, e[0], e[1], e[2], e[3],
274 276 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
275 277
276 278 def debugindexdot(ui, file):
277 279 r = hg.revlog(open, file, "")
278 280 print "digraph G {"
279 281 for i in range(r.count()):
280 282 e = r.index[i]
281 283 print "\t%d -> %d" % (r.rev(e[4]), i)
282 284 if e[5] != hg.nullid:
283 285 print "\t%d -> %d" % (r.rev(e[5]), i)
284 286 print "}"
285 287
286 288 def diff(ui, repo, *files, **opts):
287 289 """diff working directory (or selected files)"""
288 290 revs = []
289 291 if opts['rev']:
290 292 revs = map(lambda x: repo.lookup(x), opts['rev'])
291 293
292 294 if len(revs) > 2:
293 295 self.ui.warn("too many revisions to diff\n")
294 296 sys.exit(1)
295 297
296 298 if files:
297 299 files = relpath(repo, files)
298 300 else:
299 301 files = relpath(repo, [""])
300 302
301 303 dodiff(repo, os.getcwd(), files, *revs)
302 304
303 305 def export(ui, repo, changeset):
304 306 """dump the changeset header and diffs for a revision"""
305 307 node = repo.lookup(changeset)
306 308 prev, other = repo.changelog.parents(node)
307 309 change = repo.changelog.read(node)
308 310 print "# HG changeset patch"
309 311 print "# User %s" % change[1]
310 312 print "# Node ID %s" % hg.hex(node)
311 313 print "# Parent %s" % hg.hex(prev)
312 314 print
313 315 if other != hg.nullid:
314 316 print "# Parent %s" % hg.hex(other)
315 317 print change[4].rstrip()
316 318 print
317 319
318 320 dodiff(repo, "", None, prev, node)
319 321
320 322 def forget(ui, repo, file, *files):
321 323 """don't add the specified files on the next commit"""
322 324 repo.forget(relpath(repo, (file,) + files))
323 325
324 326 def heads(ui, repo):
325 327 """show current repository heads"""
326 328 for n in repo.changelog.heads():
327 329 show_changeset(ui, repo, changenode=n)
328 330
329 331 def history(ui, repo):
330 332 """show the changelog history"""
331 333 for i in range(repo.changelog.count() - 1, -1, -1):
332 334 show_changeset(ui, repo, rev=i)
333 335
334 336 def identify(ui, repo):
335 337 """print information about the working copy"""
336 338 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
337 339 if not parents:
338 340 ui.write("unknown\n")
339 341 return
340 342
341 343 hexfunc = ui.verbose and hg.hex or hg.short
342 344 (c, a, d, u) = repo.diffdir(repo.root)
343 345 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
344 346 (c or a or d) and "+" or "")]
345 347
346 348 if not ui.quiet:
347 349 # multiple tags for a single parent separated by '/'
348 350 parenttags = ['/'.join(tags)
349 351 for tags in map(repo.nodetags, parents) if tags]
350 352 # tags for multiple parents separated by ' + '
351 353 output.append(' + '.join(parenttags))
352 354
353 355 ui.write("%s\n" % ' '.join(output))
354 356
355 357 def init(ui, source=None):
356 358 """create a new repository or copy an existing one"""
357 359
358 360 if source:
359 361 paths = {}
360 362 for name, path in ui.configitems("paths"):
361 363 paths[name] = path
362 364
363 365 if source in paths: source = paths[source]
364 366
365 367 link = 0
366 368 if not source.startswith("http://"):
367 369 d1 = os.stat(os.getcwd()).st_dev
368 370 d2 = os.stat(source).st_dev
369 371 if d1 == d2: link = 1
370 372
371 373 if link:
372 374 ui.debug("copying by hardlink\n")
373 375 os.system("cp -al %s/.hg .hg" % source)
374 376 try:
375 377 os.remove(".hg/dirstate")
376 378 except: pass
377 379
378 380 repo = hg.repository(ui, ".")
379 381
380 382 else:
381 383 repo = hg.repository(ui, ".", create=1)
382 384 other = hg.repository(ui, source)
383 385 cg = repo.getchangegroup(other)
384 386 repo.addchangegroup(cg)
385 387 else:
386 388 repo = hg.repository(ui, ".", create=1)
387 389
388 390 f = repo.opener("hgrc", "w")
389 391 f.write("[paths]\n")
390 392 f.write("default = %s\n" % source)
391 393
392 394 def log(ui, repo, f):
393 395 """show the revision history of a single file"""
394 396 f = relpath(repo, [f])[0]
395 397
396 398 r = repo.file(f)
397 399 for i in range(r.count() - 1, -1, -1):
398 400 show_changeset(ui, repo, filelog=r, rev=i)
399 401
400 402 def manifest(ui, repo, rev = []):
401 403 """output the latest or given revision of the project manifest"""
402 404 n = repo.manifest.tip()
403 405 if rev:
404 406 n = repo.manifest.lookup(rev)
405 407 m = repo.manifest.read(n)
406 408 mf = repo.manifest.readflags(n)
407 409 files = m.keys()
408 410 files.sort()
409 411
410 412 for f in files:
411 413 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
412 414
413 415 def parents(ui, repo, node = None):
414 416 '''show the parents of the current working dir'''
415 417 if node:
416 418 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
417 419 else:
418 420 p = repo.dirstate.parents()
419 421
420 422 for n in p:
421 423 if n != hg.nullid:
422 424 show_changeset(ui, repo, changenode=n)
423 425
424 426 def patch(ui, repo, patch1, *patches, **opts):
425 427 """import an ordered set of patches"""
426 428 try:
427 429 import psyco
428 430 psyco.full()
429 431 except:
430 432 pass
431 433
432 434 patches = (patch1,) + patches
433 435
434 436 d = opts["base"]
435 437 strip = opts["strip"]
436 438 quiet = opts["quiet"] and "> /dev/null" or ""
437 439
438 440 for patch in patches:
439 441 ui.status("applying %s\n" % patch)
440 442 pf = os.path.join(d, patch)
441 443
442 444 text = ""
443 445 for l in file(pf):
444 446 if l[:4] == "--- ": break
445 447 text += l
446 448
447 449 # make sure text isn't empty
448 450 if not text: text = "imported patch %s\n" % patch
449 451
450 452 f = os.popen("patch -p%d < %s" % (strip, pf))
451 453 files = []
452 454 for l in f.read().splitlines():
453 455 l.rstrip('\r\n');
454 456 if not quiet:
455 457 print l
456 458 if l[:14] == 'patching file ':
457 459 files.append(l[14:])
458 460 f.close()
459 461
460 462 if len(files) > 0:
461 463 addremove(ui, repo, *files)
462 464 repo.commit(files, text)
463 465
464 466 def pull(ui, repo, source="default"):
465 467 """pull changes from the specified source"""
466 468 paths = {}
467 469 for name, path in ui.configitems("paths"):
468 470 paths[name] = path
469 471
470 472 if source in paths: source = paths[source]
471 473
472 474 other = hg.repository(ui, source)
473 475 cg = repo.getchangegroup(other)
474 476 repo.addchangegroup(cg)
475 477
476 478 def push(ui, repo, dest="default-push"):
477 479 """push changes to the specified destination"""
478 480 paths = {}
479 481 for name, path in ui.configitems("paths"):
480 482 paths[name] = path
481 483
482 484 if dest in paths: dest = paths[dest]
483 485
484 486 if not dest.startswith("ssh://"):
485 487 ui.warn("abort: can only push to ssh:// destinations currently\n")
486 488 return 1
487 489
488 490 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
489 491 if not m:
490 492 ui.warn("abort: couldn't parse destination %s\n" % dest)
491 493 return 1
492 494
493 495 user, host, port, path = map(m.group, (2, 3, 5, 7))
494 496 host = user and ("%s@%s" % (user, host)) or host
495 497 port = port and (" -p %s") % port or ""
496 498 path = path or ""
497 499
498 500 sport = random.randrange(30000, 60000)
499 501 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
500 502 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
501 503
502 504 child = os.fork()
503 505 if not child:
504 506 sys.stdout = file("/dev/null", "w")
505 507 sys.stderr = sys.stdout
506 508 hgweb.server(repo.root, "pull", "", "localhost", sport)
507 509 else:
508 510 r = os.system(cmd)
509 511 os.kill(child, signal.SIGTERM)
510 512 return r
511 513
512 514 def rawcommit(ui, repo, flist, **rc):
513 515 "raw commit interface"
514 516
515 517 text = rc['text']
516 518 if not text and rc['logfile']:
517 519 try: text = open(rc['logfile']).read()
518 520 except IOError: pass
519 521 if not text and not rc['logfile']:
520 522 print "missing commit text"
521 523 return 1
522 524
523 525 files = relpath(repo, flist)
524 526 if rc['files']:
525 527 files += open(rc['files']).read().splitlines()
526 528
527 529 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
528 530
529 531 def recover(ui, repo):
530 532 """roll back an interrupted transaction"""
531 533 repo.recover()
532 534
533 535 def remove(ui, repo, file, *files):
534 536 """remove the specified files on the next commit"""
535 537 repo.remove(relpath(repo, (file,) + files))
536 538
537 539 def serve(ui, repo, **opts):
538 540 """export the repository via HTTP"""
539 541 hgweb.server(repo.root, opts["name"], opts["templates"],
540 542 opts["address"], opts["port"])
541 543
542 544 def status(ui, repo):
543 545 '''show changed files in the working directory
544 546
545 547 C = changed
546 548 A = added
547 549 R = removed
548 550 ? = not tracked'''
549 551
550 552 (c, a, d, u) = repo.diffdir(os.getcwd())
551 553 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
552 554
553 555 for f in c: print "C", f
554 556 for f in a: print "A", f
555 557 for f in d: print "R", f
556 558 for f in u: print "?", f
557 559
558 560 def tags(ui, repo):
559 561 """list repository tags"""
560 562
561 563 l = repo.tagslist()
562 564 l.reverse()
563 565 for t,n in l:
564 566 try:
565 567 r = repo.changelog.rev(n)
566 568 except KeyError:
567 569 r = "?"
568 570 print "%-30s %5d:%s" % (t, repo.changelog.rev(n), hg.hex(n))
569 571
570 572 def tip(ui, repo):
571 573 """show the tip revision"""
572 574 n = repo.changelog.tip()
573 575 show_changeset(ui, repo, changenode=n)
574 576
575 577 def undo(ui, repo):
576 578 """undo the last transaction"""
577 579 repo.undo()
578 580
579 581 def update(ui, repo, node=None, merge=False, clean=False):
580 582 '''update or merge working directory
581 583
582 584 If there are no outstanding changes in the working directory and
583 585 there is a linear relationship between the current version and the
584 586 requested version, the result is the requested version.
585 587
586 588 Otherwise the result is a merge between the contents of the
587 589 current working directory and the requested version. Files that
588 590 changed between either parent are marked as changed for the next
589 591 commit and a commit must be performed before any further updates
590 592 are allowed.
591 593 '''
592 594 node = node and repo.lookup(node) or repo.changelog.tip()
593 595 return repo.update(node, allow=merge, force=clean)
594 596
595 597 def verify(ui, repo):
596 598 """verify the integrity of the repository"""
597 599 return repo.verify()
598 600
599 601 # Command options and aliases are listed here, alphabetically
600 602
601 603 table = {
602 604 "add": (add, [], "hg add [files]"),
603 605 "addremove": (addremove, [], "hg addremove [files]"),
604 606 "ann|annotate": (annotate,
605 607 [('r', 'revision', '', 'revision'),
606 608 ('u', 'user', None, 'show user'),
607 609 ('n', 'number', None, 'show revision number'),
608 610 ('c', 'changeset', None, 'show changeset')],
609 611 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
610 612 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
611 613 "commit|ci": (commit,
612 614 [('t', 'text', "", 'commit text'),
613 615 ('A', 'addremove', None, 'run add/remove during commit'),
614 616 ('l', 'logfile', "", 'commit text file'),
615 617 ('d', 'date', "", 'data'),
616 618 ('u', 'user', "", 'user')],
617 619 'hg commit [files]'),
618 620 "copy": (copy, [], 'hg copy <source> <dest>'),
619 621 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
620 622 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
621 623 "debugindex": (debugindex, [], 'debugindex <file>'),
622 624 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
623 625 "diff": (diff, [('r', 'rev', [], 'revision')],
624 626 'hg diff [-r A] [-r B] [files]'),
625 627 "export": (export, [], "hg export <changeset>"),
626 628 "forget": (forget, [], "hg forget [files]"),
627 629 "heads": (heads, [], 'hg heads'),
628 630 "history": (history, [], 'hg history'),
629 631 "help": (help, [], 'hg help [command]'),
630 632 "identify|id": (identify, [], 'hg identify'),
631 633 "init": (init, [], 'hg init [url]'),
632 634 "log": (log, [], 'hg log <file>'),
633 635 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
634 636 "parents": (parents, [], 'hg parents [node]'),
635 637 "patch|import": (patch,
636 638 [('p', 'strip', 1, 'path strip'),
637 639 ('b', 'base', "", 'base path'),
638 640 ('q', 'quiet', "", 'silence diff')],
639 641 "hg import [options] patches"),
640 642 "pull|merge": (pull, [], 'hg pull [source]'),
641 643 "push": (push, [], 'hg push <destination>'),
642 644 "rawcommit": (rawcommit,
643 645 [('p', 'parent', [], 'parent'),
644 646 ('d', 'date', "", 'data'),
645 647 ('u', 'user', "", 'user'),
646 648 ('F', 'files', "", 'file list'),
647 649 ('t', 'text', "", 'commit text'),
648 650 ('l', 'logfile', "", 'commit text file')],
649 651 'hg rawcommit [options] [files]'),
650 652 "recover": (recover, [], "hg recover"),
651 653 "remove": (remove, [], "hg remove [files]"),
652 654 "serve": (serve, [('p', 'port', 8000, 'listen port'),
653 655 ('a', 'address', '', 'interface address'),
654 656 ('n', 'name', os.getcwd(), 'repository name'),
655 657 ('t', 'templates', "", 'template map')],
656 658 "hg serve [options]"),
657 659 "status": (status, [], 'hg status'),
658 660 "tags": (tags, [], 'hg tags'),
659 661 "tip": (tip, [], 'hg tip'),
660 662 "undo": (undo, [], 'hg undo'),
661 663 "update|up|checkout|co|resolve": (update,
662 664 [('m', 'merge', None,
663 665 'allow merging of conflicts'),
664 666 ('C', 'clean', None,
665 667 'overwrite locally modified files')],
666 668 'hg update [options] [node]'),
667 669 "verify": (verify, [], 'hg verify'),
668 670 }
669 671
670 672 norepo = "init branch help debugindex debugindexdot"
671 673
672 674 def find(cmd):
673 675 i = None
674 676 for e in table.keys():
675 677 if re.match("(%s)$" % e, cmd):
676 678 return table[e]
677 679
678 680 raise UnknownCommand(cmd)
679 681
680 682 class SignalInterrupt(Exception): pass
681 683
682 684 def catchterm(*args):
683 685 raise SignalInterrupt
684 686
685 687 def run():
686 688 sys.exit(dispatch(sys.argv[1:]))
687 689
688 690 def dispatch(args):
689 691 options = {}
690 692 opts = [('v', 'verbose', None, 'verbose'),
691 693 ('d', 'debug', None, 'debug'),
692 694 ('q', 'quiet', None, 'quiet'),
693 695 ('p', 'profile', None, 'profile'),
694 696 ('y', 'noninteractive', None, 'run non-interactively'),
695 697 ]
696 698
697 699 args = fancyopts.fancyopts(args, opts, options,
698 700 'hg [options] <command> [options] [files]')
699 701
700 702 if not args:
701 703 cmd = "help"
702 704 else:
703 705 cmd, args = args[0], args[1:]
704 706
705 707 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
706 708 not options["noninteractive"])
707 709
708 710 try:
709 711 i = find(cmd)
710 712 except UnknownCommand:
711 713 u.warn("hg: unknown command '%s'\n" % cmd)
712 714 help(u)
713 715 sys.exit(1)
714 716
715 717 signal.signal(signal.SIGTERM, catchterm)
716 718
717 719 cmdoptions = {}
718 720 try:
719 721 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
720 722 except fancyopts.getopt.GetoptError, inst:
721 723 u.warn("hg %s: %s\n" % (cmd, inst))
722 724 help(u, cmd)
723 725 sys.exit(-1)
724 726
725 727 if cmd not in norepo.split():
726 728 repo = hg.repository(ui = u)
727 729 d = lambda: i[0](u, repo, *args, **cmdoptions)
728 730 else:
729 731 d = lambda: i[0](u, *args, **cmdoptions)
730 732
731 733 try:
732 734 if options['profile']:
733 735 import hotshot, hotshot.stats
734 736 prof = hotshot.Profile("hg.prof")
735 737 r = prof.runcall(d)
736 738 prof.close()
737 739 stats = hotshot.stats.load("hg.prof")
738 740 stats.strip_dirs()
739 741 stats.sort_stats('time', 'calls')
740 742 stats.print_stats(40)
741 743 return r
742 744 else:
743 745 return d()
744 746 except SignalInterrupt:
745 747 u.warn("killed!\n")
746 748 except KeyboardInterrupt:
747 749 u.warn("interrupted!\n")
748 750 except IOError, inst:
749 751 if inst.errno == errno.EPIPE:
750 752 u.warn("broken pipe\n")
751 753 else:
752 754 raise
753 755 except TypeError, inst:
754 756 # was this an argument error?
755 757 tb = traceback.extract_tb(sys.exc_info()[2])
756 758 if len(tb) > 2: # no
757 759 raise
758 760 u.debug(inst, "\n")
759 761 u.warn("%s: invalid arguments\n" % i[0].__name__)
760 762 help(u, cmd)
761 763 sys.exit(-1)
762 764
General Comments 0
You need to be logged in to leave comments. Login now