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