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