##// END OF EJS Templates
commands: report http exceptions nicely...
mpm@selenic.com -
r395:fbe88349 default
parent child Browse files
Show More
@@ -0,0 +1,34 b''
1 #!/bin/bash
2
3 mkdir copy
4 cd copy
5 hg init http://localhost:20059/
6 hg verify
7 hg co
8 cat foo
9 hg manifest
10
11 cat > dumb.py <<EOF
12 import BaseHTTPServer, SimpleHTTPServer, signal
13
14 def run(server_class=BaseHTTPServer.HTTPServer,
15 handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
16 server_address = ('localhost', 20059)
17 httpd = server_class(server_address, handler_class)
18 httpd.serve_forever()
19
20 signal.signal(signal.SIGTERM, lambda x: sys.exit(0))
21 run()
22 EOF
23
24 python dumb.py 2>/dev/null &
25
26 mkdir copy2
27 cd copy2
28 hg init http://localhost:20059/foo
29 hg verify
30 hg co
31 cat foo
32 hg manifest
33
34 kill %1
@@ -0,0 +1,22 b''
1 requesting all changes
2 adding changesets
3 abort: error 111: Connection refused
4 transaction abort!
5 rollback completed
6 checking changesets
7 checking manifests
8 crosschecking files in changesets and manifests
9 checking files
10 0 files, 0 changesets, 0 total revisions
11 cat: foo: No such file or directory
12 requesting all changes
13 adding changesets
14 abort: HTTP Error 404: File not found
15 transaction abort!
16 rollback completed
17 checking changesets
18 checking manifests
19 crosschecking files in changesets and manifests
20 checking files
21 0 files, 0 changesets, 0 total revisions
22 cat: foo: No such file or directory
@@ -1,768 +1,772 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 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 391
392 392 if opts['update']:
393 393 update(ui, repo)
394 394 else:
395 395 repo = hg.repository(ui, ".", create=1)
396 396
397 397 def log(ui, repo, f):
398 398 """show the revision history of a single file"""
399 399 f = relpath(repo, [f])[0]
400 400
401 401 r = repo.file(f)
402 402 for i in range(r.count() - 1, -1, -1):
403 403 show_changeset(ui, repo, filelog=r, rev=i)
404 404
405 405 def manifest(ui, repo, rev = []):
406 406 """output the latest or given revision of the project manifest"""
407 407 n = repo.manifest.tip()
408 408 if rev:
409 409 n = repo.manifest.lookup(rev)
410 410 m = repo.manifest.read(n)
411 411 mf = repo.manifest.readflags(n)
412 412 files = m.keys()
413 413 files.sort()
414 414
415 415 for f in files:
416 416 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
417 417
418 418 def parents(ui, repo, node = None):
419 419 '''show the parents of the current working dir'''
420 420 if node:
421 421 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
422 422 else:
423 423 p = repo.dirstate.parents()
424 424
425 425 for n in p:
426 426 if n != hg.nullid:
427 427 show_changeset(ui, repo, changenode=n)
428 428
429 429 def patch(ui, repo, patch1, *patches, **opts):
430 430 """import an ordered set of patches"""
431 431 try:
432 432 import psyco
433 433 psyco.full()
434 434 except:
435 435 pass
436 436
437 437 patches = (patch1,) + patches
438 438
439 439 d = opts["base"]
440 440 strip = opts["strip"]
441 441 quiet = opts["quiet"] and "> /dev/null" or ""
442 442
443 443 for patch in patches:
444 444 ui.status("applying %s\n" % patch)
445 445 pf = os.path.join(d, patch)
446 446
447 447 text = ""
448 448 for l in file(pf):
449 449 if l[:4] == "--- ": break
450 450 text += l
451 451
452 452 # make sure text isn't empty
453 453 if not text: text = "imported patch %s\n" % patch
454 454
455 455 f = os.popen("patch -p%d < %s" % (strip, pf))
456 456 files = []
457 457 for l in f.read().splitlines():
458 458 l.rstrip('\r\n');
459 459 if not quiet:
460 460 print l
461 461 if l[:14] == 'patching file ':
462 462 files.append(l[14:])
463 463 f.close()
464 464
465 465 if len(files) > 0:
466 466 addremove(ui, repo, *files)
467 467 repo.commit(files, text)
468 468
469 469 def pull(ui, repo, source="default"):
470 470 """pull changes from the specified source"""
471 471 paths = {}
472 472 for name, path in ui.configitems("paths"):
473 473 paths[name] = path
474 474
475 475 if source in paths: source = paths[source]
476 476
477 477 other = hg.repository(ui, source)
478 478 cg = repo.getchangegroup(other)
479 479 repo.addchangegroup(cg)
480 480
481 481 def push(ui, repo, dest="default-push"):
482 482 """push changes to the specified destination"""
483 483 paths = {}
484 484 for name, path in ui.configitems("paths"):
485 485 paths[name] = path
486 486
487 487 if dest in paths: dest = paths[dest]
488 488
489 489 if not dest.startswith("ssh://"):
490 490 ui.warn("abort: can only push to ssh:// destinations currently\n")
491 491 return 1
492 492
493 493 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
494 494 if not m:
495 495 ui.warn("abort: couldn't parse destination %s\n" % dest)
496 496 return 1
497 497
498 498 user, host, port, path = map(m.group, (2, 3, 5, 7))
499 499 host = user and ("%s@%s" % (user, host)) or host
500 500 port = port and (" -p %s") % port or ""
501 501 path = path or ""
502 502
503 503 sport = random.randrange(30000, 60000)
504 504 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
505 505 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
506 506
507 507 child = os.fork()
508 508 if not child:
509 509 sys.stdout = file("/dev/null", "w")
510 510 sys.stderr = sys.stdout
511 511 hgweb.server(repo.root, "pull", "", "localhost", sport)
512 512 else:
513 513 r = os.system(cmd)
514 514 os.kill(child, signal.SIGTERM)
515 515 return r
516 516
517 517 def rawcommit(ui, repo, flist, **rc):
518 518 "raw commit interface"
519 519
520 520 text = rc['text']
521 521 if not text and rc['logfile']:
522 522 try: text = open(rc['logfile']).read()
523 523 except IOError: pass
524 524 if not text and not rc['logfile']:
525 525 print "missing commit text"
526 526 return 1
527 527
528 528 files = relpath(repo, flist)
529 529 if rc['files']:
530 530 files += open(rc['files']).read().splitlines()
531 531
532 532 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
533 533
534 534 def recover(ui, repo):
535 535 """roll back an interrupted transaction"""
536 536 repo.recover()
537 537
538 538 def remove(ui, repo, file, *files):
539 539 """remove the specified files on the next commit"""
540 540 repo.remove(relpath(repo, (file,) + files))
541 541
542 542 def serve(ui, repo, **opts):
543 543 """export the repository via HTTP"""
544 544 hgweb.server(repo.root, opts["name"], opts["templates"],
545 545 opts["address"], opts["port"])
546 546
547 547 def status(ui, repo):
548 548 '''show changed files in the working directory
549 549
550 550 C = changed
551 551 A = added
552 552 R = removed
553 553 ? = not tracked'''
554 554
555 555 (c, a, d, u) = repo.diffdir(os.getcwd())
556 556 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
557 557
558 558 for f in c: print "C", f
559 559 for f in a: print "A", f
560 560 for f in d: print "R", f
561 561 for f in u: print "?", f
562 562
563 563 def tags(ui, repo):
564 564 """list repository tags"""
565 565
566 566 l = repo.tagslist()
567 567 l.reverse()
568 568 for t,n in l:
569 569 try:
570 570 r = repo.changelog.rev(n)
571 571 except KeyError:
572 572 r = "?"
573 573 print "%-30s %5d:%s" % (t, repo.changelog.rev(n), hg.hex(n))
574 574
575 575 def tip(ui, repo):
576 576 """show the tip revision"""
577 577 n = repo.changelog.tip()
578 578 show_changeset(ui, repo, changenode=n)
579 579
580 580 def undo(ui, repo):
581 581 """undo the last transaction"""
582 582 repo.undo()
583 583
584 584 def update(ui, repo, node=None, merge=False, clean=False):
585 585 '''update or merge working directory
586 586
587 587 If there are no outstanding changes in the working directory and
588 588 there is a linear relationship between the current version and the
589 589 requested version, the result is the requested version.
590 590
591 591 Otherwise the result is a merge between the contents of the
592 592 current working directory and the requested version. Files that
593 593 changed between either parent are marked as changed for the next
594 594 commit and a commit must be performed before any further updates
595 595 are allowed.
596 596 '''
597 597 node = node and repo.lookup(node) or repo.changelog.tip()
598 598 return repo.update(node, allow=merge, force=clean)
599 599
600 600 def verify(ui, repo):
601 601 """verify the integrity of the repository"""
602 602 return repo.verify()
603 603
604 604 # Command options and aliases are listed here, alphabetically
605 605
606 606 table = {
607 607 "add": (add, [], "hg add [files]"),
608 608 "addremove": (addremove, [], "hg addremove [files]"),
609 609 "ann|annotate": (annotate,
610 610 [('r', 'revision', '', 'revision'),
611 611 ('u', 'user', None, 'show user'),
612 612 ('n', 'number', None, 'show revision number'),
613 613 ('c', 'changeset', None, 'show changeset')],
614 614 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
615 615 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
616 616 "commit|ci": (commit,
617 617 [('t', 'text', "", 'commit text'),
618 618 ('A', 'addremove', None, 'run add/remove during commit'),
619 619 ('l', 'logfile', "", 'commit text file'),
620 620 ('d', 'date', "", 'data'),
621 621 ('u', 'user', "", 'user')],
622 622 'hg commit [files]'),
623 623 "copy": (copy, [], 'hg copy <source> <dest>'),
624 624 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
625 625 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
626 626 "debugindex": (debugindex, [], 'debugindex <file>'),
627 627 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
628 628 "diff": (diff, [('r', 'rev', [], 'revision')],
629 629 'hg diff [-r A] [-r B] [files]'),
630 630 "export": (export, [], "hg export <changeset>"),
631 631 "forget": (forget, [], "hg forget [files]"),
632 632 "heads": (heads, [], 'hg heads'),
633 633 "history": (history, [], 'hg history'),
634 634 "help": (help, [], 'hg help [command]'),
635 635 "identify|id": (identify, [], 'hg identify'),
636 636 "init": (init, [('u', 'update', None, 'update after init')],
637 637 'hg init [options] [url]'),
638 638 "log": (log, [], 'hg log <file>'),
639 639 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
640 640 "parents": (parents, [], 'hg parents [node]'),
641 641 "patch|import": (patch,
642 642 [('p', 'strip', 1, 'path strip'),
643 643 ('b', 'base', "", 'base path'),
644 644 ('q', 'quiet', "", 'silence diff')],
645 645 "hg import [options] patches"),
646 646 "pull|merge": (pull, [], 'hg pull [source]'),
647 647 "push": (push, [], 'hg push <destination>'),
648 648 "rawcommit": (rawcommit,
649 649 [('p', 'parent', [], 'parent'),
650 650 ('d', 'date', "", 'data'),
651 651 ('u', 'user', "", 'user'),
652 652 ('F', 'files', "", 'file list'),
653 653 ('t', 'text', "", 'commit text'),
654 654 ('l', 'logfile', "", 'commit text file')],
655 655 'hg rawcommit [options] [files]'),
656 656 "recover": (recover, [], "hg recover"),
657 657 "remove": (remove, [], "hg remove [files]"),
658 658 "serve": (serve, [('p', 'port', 8000, 'listen port'),
659 659 ('a', 'address', '', 'interface address'),
660 660 ('n', 'name', os.getcwd(), 'repository name'),
661 661 ('t', 'templates', "", 'template map')],
662 662 "hg serve [options]"),
663 663 "status": (status, [], 'hg status'),
664 664 "tags": (tags, [], 'hg tags'),
665 665 "tip": (tip, [], 'hg tip'),
666 666 "undo": (undo, [], 'hg undo'),
667 667 "update|up|checkout|co|resolve": (update,
668 668 [('m', 'merge', None,
669 669 'allow merging of conflicts'),
670 670 ('C', 'clean', None,
671 671 'overwrite locally modified files')],
672 672 'hg update [options] [node]'),
673 673 "verify": (verify, [], 'hg verify'),
674 674 }
675 675
676 676 norepo = "init branch help debugindex debugindexdot"
677 677
678 678 def find(cmd):
679 679 i = None
680 680 for e in table.keys():
681 681 if re.match("(%s)$" % e, cmd):
682 682 return table[e]
683 683
684 684 raise UnknownCommand(cmd)
685 685
686 686 class SignalInterrupt(Exception): pass
687 687
688 688 def catchterm(*args):
689 689 raise SignalInterrupt
690 690
691 691 def run():
692 692 sys.exit(dispatch(sys.argv[1:]))
693 693
694 694 def dispatch(args):
695 695 options = {}
696 696 opts = [('v', 'verbose', None, 'verbose'),
697 697 ('d', 'debug', None, 'debug'),
698 698 ('q', 'quiet', None, 'quiet'),
699 699 ('p', 'profile', None, 'profile'),
700 700 ('y', 'noninteractive', None, 'run non-interactively'),
701 701 ]
702 702
703 703 args = fancyopts.fancyopts(args, opts, options,
704 704 'hg [options] <command> [options] [files]')
705 705
706 706 if not args:
707 707 cmd = "help"
708 708 else:
709 709 cmd, args = args[0], args[1:]
710 710
711 711 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
712 712 not options["noninteractive"])
713 713
714 714 try:
715 715 i = find(cmd)
716 716 except UnknownCommand:
717 717 u.warn("hg: unknown command '%s'\n" % cmd)
718 718 help(u)
719 719 sys.exit(1)
720 720
721 721 signal.signal(signal.SIGTERM, catchterm)
722 722
723 723 cmdoptions = {}
724 724 try:
725 725 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
726 726 except fancyopts.getopt.GetoptError, inst:
727 727 u.warn("hg %s: %s\n" % (cmd, inst))
728 728 help(u, cmd)
729 729 sys.exit(-1)
730 730
731 731 if cmd not in norepo.split():
732 732 repo = hg.repository(ui = u)
733 733 d = lambda: i[0](u, repo, *args, **cmdoptions)
734 734 else:
735 735 d = lambda: i[0](u, *args, **cmdoptions)
736 736
737 737 try:
738 738 if options['profile']:
739 739 import hotshot, hotshot.stats
740 740 prof = hotshot.Profile("hg.prof")
741 741 r = prof.runcall(d)
742 742 prof.close()
743 743 stats = hotshot.stats.load("hg.prof")
744 744 stats.strip_dirs()
745 745 stats.sort_stats('time', 'calls')
746 746 stats.print_stats(40)
747 747 return r
748 748 else:
749 749 return d()
750 750 except SignalInterrupt:
751 751 u.warn("killed!\n")
752 752 except KeyboardInterrupt:
753 753 u.warn("interrupted!\n")
754 754 except IOError, inst:
755 if inst.errno == errno.EPIPE:
755 if hasattr(inst, "code"):
756 u.warn("abort: %s\n" % inst)
757 elif hasattr(inst, "reason"):
758 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
759 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
756 760 u.warn("broken pipe\n")
757 761 else:
758 762 raise
759 763 except TypeError, inst:
760 764 # was this an argument error?
761 765 tb = traceback.extract_tb(sys.exc_info()[2])
762 766 if len(tb) > 2: # no
763 767 raise
764 768 u.debug(inst, "\n")
765 769 u.warn("%s: invalid arguments\n" % i[0].__name__)
766 770 help(u, cmd)
767 771 sys.exit(-1)
768 772
General Comments 0
You need to be logged in to leave comments. Login now