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