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