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