##// END OF EJS Templates
Catch SIGHUP...
Matt Mackall -
r641:27f53edc default
parent child Browse files
Show More
@@ -1,1279 +1,1280 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 from demandload import *
9 9 demandload(globals(), "os re sys signal")
10 10 demandload(globals(), "fancyopts ui hg util")
11 11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 12 demandload(globals(), "errno socket version struct")
13 13
14 14 class UnknownCommand(Exception): pass
15 15
16 16 def filterfiles(filters, files):
17 17 l = [ x for x in files if x in filters ]
18 18
19 19 for t in filters:
20 20 if t and t[-1] != "/": t += "/"
21 21 l += [ x for x in files if x.startswith(t) ]
22 22 return l
23 23
24 24 def relfilter(repo, files):
25 25 cwd = repo.getcwd()
26 26 if cwd:
27 27 return filterfiles([util.pconvert(cwd)], files)
28 28 return files
29 29
30 30 def relpath(repo, args):
31 31 cwd = repo.getcwd()
32 32 if cwd:
33 33 return [ util.pconvert(os.path.normpath(os.path.join(cwd, x))) for x in args ]
34 34 return args
35 35
36 36 revrangesep = ':'
37 37
38 38 def revrange(ui, repo, revs = [], revlog = None):
39 39 if revlog is None:
40 40 revlog = repo.changelog
41 41 revcount = revlog.count()
42 42 def fix(val, defval):
43 43 if not val: return defval
44 44 try:
45 45 num = int(val)
46 46 if str(num) != val: raise ValueError
47 47 if num < 0: num += revcount
48 48 if not (0 <= num < revcount):
49 49 raise ValueError
50 50 except ValueError:
51 51 try:
52 52 num = repo.changelog.rev(repo.lookup(val))
53 53 except KeyError:
54 54 try:
55 55 num = revlog.rev(revlog.lookup(val))
56 56 except KeyError:
57 57 ui.warn('abort: invalid revision identifier %s\n' % val)
58 58 sys.exit(1)
59 59 return num
60 60 for spec in revs:
61 61 if spec.find(revrangesep) >= 0:
62 62 start, end = spec.split(revrangesep, 1)
63 63 start = fix(start, 0)
64 64 end = fix(end, revcount - 1)
65 65 if end > start:
66 66 end += 1
67 67 step = 1
68 68 else:
69 69 end -= 1
70 70 step = -1
71 71 for rev in xrange(start, end, step):
72 72 yield str(rev)
73 73 else:
74 74 yield spec
75 75
76 76 def make_filename(repo, r, pat, node=None,
77 77 total=None, seqno=None, revwidth=None):
78 78 node_expander = {
79 79 'H': lambda: hg.hex(node),
80 80 'R': lambda: str(r.rev(node)),
81 81 'h': lambda: hg.short(node),
82 82 }
83 83 expander = {
84 84 '%': lambda: '%',
85 85 'b': lambda: os.path.basename(repo.root),
86 86 }
87 87
88 88 if node: expander.update(node_expander)
89 89 if node and revwidth is not None:
90 90 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
91 91 if total is not None: expander['N'] = lambda: str(total)
92 92 if seqno is not None: expander['n'] = lambda: str(seqno)
93 93 if total is not None and seqno is not None:
94 94 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
95 95
96 96 newname = []
97 97 patlen = len(pat)
98 98 i = 0
99 99 while i < patlen:
100 100 c = pat[i]
101 101 if c == '%':
102 102 i += 1
103 103 c = pat[i]
104 104 c = expander[c]()
105 105 newname.append(c)
106 106 i += 1
107 107 return ''.join(newname)
108 108
109 109 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
110 110 def date(c):
111 111 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
112 112
113 113 (c, a, d, u) = repo.changes(node1, node2, files)
114 114 if files:
115 115 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
116 116
117 117 if not c and not a and not d:
118 118 return
119 119
120 120 if node2:
121 121 change = repo.changelog.read(node2)
122 122 mmap2 = repo.manifest.read(change[0])
123 123 def read(f): return repo.file(f).read(mmap2[f])
124 124 date2 = date(change)
125 125 else:
126 126 date2 = time.asctime()
127 127 if not node1:
128 128 node1 = repo.dirstate.parents()[0]
129 129 def read(f): return repo.wfile(f).read()
130 130
131 131 if ui.quiet:
132 132 r = None
133 133 else:
134 134 hexfunc = ui.verbose and hg.hex or hg.short
135 135 r = [hexfunc(node) for node in [node1, node2] if node]
136 136
137 137 change = repo.changelog.read(node1)
138 138 mmap = repo.manifest.read(change[0])
139 139 date1 = date(change)
140 140
141 141 for f in c:
142 142 to = None
143 143 if f in mmap:
144 144 to = repo.file(f).read(mmap[f])
145 145 tn = read(f)
146 146 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
147 147 for f in a:
148 148 to = None
149 149 tn = read(f)
150 150 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
151 151 for f in d:
152 152 to = repo.file(f).read(mmap[f])
153 153 tn = None
154 154 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
155 155
156 156 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
157 157 """show a single changeset or file revision"""
158 158 changelog = repo.changelog
159 159 if filelog:
160 160 log = filelog
161 161 filerev = rev
162 162 node = filenode = filelog.node(filerev)
163 163 changerev = filelog.linkrev(filenode)
164 164 changenode = changenode or changelog.node(changerev)
165 165 else:
166 166 log = changelog
167 167 changerev = rev
168 168 if changenode is None:
169 169 changenode = changelog.node(changerev)
170 170 elif not changerev:
171 171 rev = changerev = changelog.rev(changenode)
172 172 node = changenode
173 173
174 174 if ui.quiet:
175 175 ui.write("%d:%s\n" % (rev, hg.hex(node)))
176 176 return
177 177
178 178 changes = changelog.read(changenode)
179 179
180 180 parents = [(log.rev(parent), hg.hex(parent))
181 181 for parent in log.parents(node)
182 182 if ui.debugflag or parent != hg.nullid]
183 183 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
184 184 parents = []
185 185
186 186 if filelog:
187 187 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
188 188 for parent in parents:
189 189 ui.write("parent: %d:%s\n" % parent)
190 190 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
191 191 else:
192 192 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
193 193 for tag in repo.nodetags(changenode):
194 194 ui.status("tag: %s\n" % tag)
195 195 for parent in parents:
196 196 ui.write("parent: %d:%s\n" % parent)
197 197 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
198 198 hg.hex(changes[0])))
199 199 ui.status("user: %s\n" % changes[1])
200 200 ui.status("date: %s\n" % time.asctime(
201 201 time.localtime(float(changes[2].split(' ')[0]))))
202 202 if ui.debugflag:
203 203 files = repo.changes(changelog.parents(changenode)[0], changenode)
204 204 for key, value in zip(["files:", "files+:", "files-:"], files):
205 205 if value:
206 206 ui.note("%-12s %s\n" % (key, " ".join(value)))
207 207 else:
208 208 ui.note("files: %s\n" % " ".join(changes[3]))
209 209 description = changes[4].strip()
210 210 if description:
211 211 if ui.verbose:
212 212 ui.status("description:\n")
213 213 ui.status(description)
214 214 ui.status("\n\n")
215 215 else:
216 216 ui.status("summary: %s\n" % description.splitlines()[0])
217 217 ui.status("\n")
218 218
219 219 def show_version(ui):
220 220 """output version and copyright information"""
221 221 ui.write("Mercurial version %s\n" % version.get_version())
222 222 ui.status(
223 223 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
224 224 "This is free software; see the source for copying conditions. "
225 225 "There is NO\nwarranty; "
226 226 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
227 227 )
228 228
229 229 def help(ui, cmd=None):
230 230 '''show help for a given command or all commands'''
231 231 if cmd:
232 232 try:
233 233 i = find(cmd)
234 234 ui.write("%s\n\n" % i[2])
235 235
236 236 if i[1]:
237 237 for s, l, d, c in i[1]:
238 238 opt=' '
239 239 if s: opt = opt + '-' + s + ' '
240 240 if l: opt = opt + '--' + l + ' '
241 241 if d: opt = opt + '(' + str(d) + ')'
242 242 ui.write(opt, "\n")
243 243 if c: ui.write(' %s\n' % c)
244 244 ui.write("\n")
245 245
246 246 ui.write(i[0].__doc__, "\n")
247 247 except UnknownCommand:
248 248 ui.warn("hg: unknown command %s\n" % cmd)
249 249 sys.exit(0)
250 250 else:
251 251 if ui.verbose:
252 252 show_version(ui)
253 253 ui.write('\n')
254 254 if ui.verbose:
255 255 ui.write('hg commands:\n\n')
256 256 else:
257 257 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
258 258
259 259 h = {}
260 260 for c, e in table.items():
261 261 f = c.split("|")[0]
262 262 if not ui.verbose and not f.startswith("^"):
263 263 continue
264 264 if not ui.debugflag and f.startswith("debug"):
265 265 continue
266 266 f = f.lstrip("^")
267 267 d = ""
268 268 if e[0].__doc__:
269 269 d = e[0].__doc__.splitlines(0)[0].rstrip()
270 270 h[f] = d
271 271
272 272 fns = h.keys()
273 273 fns.sort()
274 274 m = max(map(len, fns))
275 275 for f in fns:
276 276 ui.write(' %-*s %s\n' % (m, f, h[f]))
277 277
278 278 # Commands start here, listed alphabetically
279 279
280 280 def add(ui, repo, file, *files):
281 281 '''add the specified files on the next commit'''
282 282 repo.add(relpath(repo, (file,) + files))
283 283
284 284 def addremove(ui, repo, *files):
285 285 """add all new files, delete all missing files"""
286 286 if files:
287 287 files = relpath(repo, files)
288 288 d = []
289 289 u = []
290 290 for f in files:
291 291 p = repo.wjoin(f)
292 292 s = repo.dirstate.state(f)
293 293 isfile = os.path.isfile(p)
294 294 if s != 'r' and not isfile:
295 295 d.append(f)
296 296 elif s not in 'nmai' and isfile:
297 297 u.append(f)
298 298 else:
299 299 (c, a, d, u) = repo.changes(None, None)
300 300 repo.add(u)
301 301 repo.remove(d)
302 302
303 303 def annotate(u, repo, file, *files, **ops):
304 304 """show changeset information per file line"""
305 305 def getnode(rev):
306 306 return hg.short(repo.changelog.node(rev))
307 307
308 308 def getname(rev):
309 309 try:
310 310 return bcache[rev]
311 311 except KeyError:
312 312 cl = repo.changelog.read(repo.changelog.node(rev))
313 313 name = cl[1]
314 314 f = name.find('@')
315 315 if f >= 0:
316 316 name = name[:f]
317 317 f = name.find('<')
318 318 if f >= 0:
319 319 name = name[f+1:]
320 320 bcache[rev] = name
321 321 return name
322 322
323 323 bcache = {}
324 324 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
325 325 if not ops['user'] and not ops['changeset']:
326 326 ops['number'] = 1
327 327
328 328 node = repo.dirstate.parents()[0]
329 329 if ops['revision']:
330 330 node = repo.changelog.lookup(ops['revision'])
331 331 change = repo.changelog.read(node)
332 332 mmap = repo.manifest.read(change[0])
333 333 for f in relpath(repo, (file,) + files):
334 334 lines = repo.file(f).annotate(mmap[f])
335 335 pieces = []
336 336
337 337 for o, f in opmap:
338 338 if ops[o]:
339 339 l = [ f(n) for n,t in lines ]
340 340 m = max(map(len, l))
341 341 pieces.append([ "%*s" % (m, x) for x in l])
342 342
343 343 for p,l in zip(zip(*pieces), lines):
344 344 u.write(" ".join(p) + ": " + l[1])
345 345
346 346 def cat(ui, repo, file, rev = [], **opts):
347 347 """output the latest or given revision of a file"""
348 348 r = repo.file(relpath(repo, [file])[0])
349 349 n = r.tip()
350 350 if rev: n = r.lookup(rev)
351 351 if opts['output'] and opts['output'] != '-':
352 352 try:
353 353 outname = make_filename(repo, r, opts['output'], node=n)
354 354 fp = open(outname, 'wb')
355 355 except KeyError, inst:
356 356 ui.warn("error: invlaid format spec '%%%s' in output file name\n" %
357 357 inst.args[0])
358 358 sys.exit(1);
359 359 else:
360 360 fp = sys.stdout
361 361 fp.write(r.read(n))
362 362
363 363 def clone(ui, source, dest = None, **opts):
364 364 """make a copy of an existing repository"""
365 365 if dest is None:
366 366 dest = os.path.basename(os.path.normpath(source))
367 367
368 368 if os.path.exists(dest):
369 369 ui.warn("abort: destination '%s' already exists\n" % dest)
370 370 return 1
371 371
372 372 class dircleanup:
373 373 def __init__(self, dir):
374 374 import shutil
375 375 self.rmtree = shutil.rmtree
376 376 self.dir = dir
377 377 os.mkdir(dir)
378 378 def close(self):
379 379 self.dir = None
380 380 def __del__(self):
381 381 if self.dir:
382 382 self.rmtree(self.dir, True)
383 383
384 384 d = dircleanup(dest)
385 385 link = 0
386 386 abspath = source
387 387 source = ui.expandpath(source)
388 388 other = hg.repository(ui, source)
389 389
390 390 if other.dev() != -1 and os.stat(dest).st_dev == other.dev():
391 391 ui.status("cloning by hardlink\n")
392 392 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
393 393 try:
394 394 os.remove(os.path.join(dest, ".hg", "dirstate"))
395 395 except: pass
396 396
397 397 repo = hg.repository(ui, dest)
398 398
399 399 else:
400 400 repo = hg.repository(ui, dest, create=1)
401 401 repo.pull(other)
402 402
403 403 f = repo.opener("hgrc", "w")
404 404 f.write("[paths]\n")
405 405 f.write("default = %s\n" % abspath)
406 406
407 407 if not opts['noupdate']:
408 408 update(ui, repo)
409 409
410 410 d.close()
411 411
412 412 def commit(ui, repo, *files, **opts):
413 413 """commit the specified files or all outstanding changes"""
414 414 text = opts['text']
415 415 if not text and opts['logfile']:
416 416 try: text = open(opts['logfile']).read()
417 417 except IOError: pass
418 418
419 419 if opts['addremove']:
420 420 addremove(ui, repo, *files)
421 421 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
422 422
423 423 def copy(ui, repo, source, dest):
424 424 """mark a file as copied or renamed for the next commit"""
425 425 return repo.copy(*relpath(repo, (source, dest)))
426 426
427 427 def debugcheckstate(ui, repo):
428 428 """validate the correctness of the current dirstate"""
429 429 parent1, parent2 = repo.dirstate.parents()
430 430 repo.dirstate.read()
431 431 dc = repo.dirstate.map
432 432 keys = dc.keys()
433 433 keys.sort()
434 434 m1n = repo.changelog.read(parent1)[0]
435 435 m2n = repo.changelog.read(parent2)[0]
436 436 m1 = repo.manifest.read(m1n)
437 437 m2 = repo.manifest.read(m2n)
438 438 errors = 0
439 439 for f in dc:
440 440 state = repo.dirstate.state(f)
441 441 if state in "nr" and f not in m1:
442 442 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
443 443 errors += 1
444 444 if state in "a" and f in m1:
445 445 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
446 446 errors += 1
447 447 if state in "m" and f not in m1 and f not in m2:
448 448 ui.warn("%s in state %s, but not in either manifest\n" %
449 449 (f, state))
450 450 errors += 1
451 451 for f in m1:
452 452 state = repo.dirstate.state(f)
453 453 if state not in "nrm":
454 454 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
455 455 errors += 1
456 456 if errors:
457 457 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
458 458 sys.exit(1)
459 459
460 460 def debugstate(ui, repo):
461 461 """show the contents of the current dirstate"""
462 462 repo.dirstate.read()
463 463 dc = repo.dirstate.map
464 464 keys = dc.keys()
465 465 keys.sort()
466 466 for file in keys:
467 467 ui.write("%c %s\n" % (dc[file][0], file))
468 468
469 469 def debugindex(ui, file):
470 470 """dump the contents of an index file"""
471 471 r = hg.revlog(hg.opener(""), file, "")
472 472 ui.write(" rev offset length base linkrev" +
473 473 " p1 p2 nodeid\n")
474 474 for i in range(r.count()):
475 475 e = r.index[i]
476 476 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
477 477 i, e[0], e[1], e[2], e[3],
478 478 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
479 479
480 480 def debugindexdot(ui, file):
481 481 """dump an index DAG as a .dot file"""
482 482 r = hg.revlog(hg.opener(""), file, "")
483 483 ui.write("digraph G {\n")
484 484 for i in range(r.count()):
485 485 e = r.index[i]
486 486 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
487 487 if e[5] != hg.nullid:
488 488 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
489 489 ui.write("}\n")
490 490
491 491 def diff(ui, repo, *files, **opts):
492 492 """diff working directory (or selected files)"""
493 493 revs = []
494 494 if opts['rev']:
495 495 revs = map(lambda x: repo.lookup(x), opts['rev'])
496 496
497 497 if len(revs) > 2:
498 498 ui.warn("too many revisions to diff\n")
499 499 sys.exit(1)
500 500
501 501 if files:
502 502 files = relpath(repo, files)
503 503 else:
504 504 files = relpath(repo, [""])
505 505
506 506 dodiff(sys.stdout, ui, repo, files, *revs)
507 507
508 508 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
509 509 node = repo.lookup(changeset)
510 510 prev, other = repo.changelog.parents(node)
511 511 change = repo.changelog.read(node)
512 512
513 513 if opts['output'] and opts['output'] != '-':
514 514 try:
515 515 outname = make_filename(repo, repo.changelog, opts['output'],
516 516 node=node, total=total, seqno=seqno,
517 517 revwidth=revwidth)
518 518 fp = open(outname, 'wb')
519 519 except KeyError, inst:
520 520 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
521 521 inst.args[0])
522 522 sys.exit(1)
523 523 else:
524 524 fp = sys.stdout
525 525
526 526 fp.write("# HG changeset patch\n")
527 527 fp.write("# User %s\n" % change[1])
528 528 fp.write("# Node ID %s\n" % hg.hex(node))
529 529 fp.write("# Parent %s\n" % hg.hex(prev))
530 530 if other != hg.nullid:
531 531 fp.write("# Parent %s\n" % hg.hex(other))
532 532 fp.write(change[4].rstrip())
533 533 fp.write("\n\n")
534 534
535 535 dodiff(fp, ui, repo, None, prev, node)
536 536
537 537 def export(ui, repo, *changesets, **opts):
538 538 """dump the header and diffs for one or more changesets"""
539 539 if not changesets:
540 540 ui.warn("error: export requires at least one changeset\n")
541 541 sys.exit(1)
542 542 seqno = 0
543 543 revs = list(revrange(ui, repo, changesets))
544 544 total = len(revs)
545 545 revwidth = max(len(revs[0]), len(revs[-1]))
546 546 for cset in revs:
547 547 seqno += 1
548 548 doexport(ui, repo, cset, seqno, total, revwidth, opts)
549 549
550 550 def forget(ui, repo, file, *files):
551 551 """don't add the specified files on the next commit"""
552 552 repo.forget(relpath(repo, (file,) + files))
553 553
554 554 def heads(ui, repo):
555 555 """show current repository heads"""
556 556 for n in repo.changelog.heads():
557 557 show_changeset(ui, repo, changenode=n)
558 558
559 559 def identify(ui, repo):
560 560 """print information about the working copy"""
561 561 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
562 562 if not parents:
563 563 ui.write("unknown\n")
564 564 return
565 565
566 566 hexfunc = ui.verbose and hg.hex or hg.short
567 567 (c, a, d, u) = repo.changes(None, None)
568 568 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
569 569 (c or a or d) and "+" or "")]
570 570
571 571 if not ui.quiet:
572 572 # multiple tags for a single parent separated by '/'
573 573 parenttags = ['/'.join(tags)
574 574 for tags in map(repo.nodetags, parents) if tags]
575 575 # tags for multiple parents separated by ' + '
576 576 output.append(' + '.join(parenttags))
577 577
578 578 ui.write("%s\n" % ' '.join(output))
579 579
580 580 def import_(ui, repo, patch1, *patches, **opts):
581 581 """import an ordered set of patches"""
582 582 try:
583 583 import psyco
584 584 psyco.full()
585 585 except:
586 586 pass
587 587
588 588 patches = (patch1,) + patches
589 589
590 590 d = opts["base"]
591 591 strip = opts["strip"]
592 592
593 593 for patch in patches:
594 594 ui.status("applying %s\n" % patch)
595 595 pf = os.path.join(d, patch)
596 596
597 597 text = ""
598 598 for l in file(pf):
599 599 if l.startswith("--- ") or l.startswith("diff -r"): break
600 600 text += l
601 601
602 602 # parse values that exist when importing the result of an hg export
603 603 hgpatch = user = snippet = None
604 604 ui.debug('text:\n')
605 605 for t in text.splitlines():
606 606 ui.debug(t,'\n')
607 607 if t == '# HG changeset patch' or hgpatch == True:
608 608 hgpatch = True
609 609 if t[:7] == "# User ":
610 610 user = t[7:]
611 611 ui.debug('User: %s\n' % user)
612 612 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
613 613 if snippet: text = snippet + '\n' + text
614 614 ui.debug('text:\n%s\n' % text)
615 615
616 616 # make sure text isn't empty
617 617 if not text: text = "imported patch %s\n" % patch
618 618
619 619 f = os.popen("patch -p%d < %s" % (strip, pf))
620 620 files = []
621 621 for l in f.read().splitlines():
622 622 l.rstrip('\r\n');
623 623 ui.status("%s\n" % l)
624 624 if l[:14] == 'patching file ':
625 625 pf = l[14:]
626 626 if pf not in files:
627 627 files.append(pf)
628 628 patcherr = f.close()
629 629 if patcherr:
630 630 sys.stderr.write("patch failed")
631 631 sys.exit(1)
632 632
633 633 if len(files) > 0:
634 634 addremove(ui, repo, *files)
635 635 repo.commit(files, text, user)
636 636
637 637 def init(ui, source=None):
638 638 """create a new repository in the current directory"""
639 639
640 640 if source:
641 641 ui.warn("no longer supported: use \"hg clone\" instead\n")
642 642 sys.exit(1)
643 643 repo = hg.repository(ui, ".", create=1)
644 644
645 645 def locate(ui, repo, *pats, **opts):
646 646 """locate files matching specific patterns"""
647 647 if [p for p in pats if os.sep in p]:
648 648 ui.warn("error: patterns may not contain '%s'\n" % os.sep)
649 649 ui.warn("use '-i <dir>' instead\n")
650 650 sys.exit(1)
651 651 def compile(pats, head = '^', tail = os.sep, on_empty = True):
652 652 if not pats:
653 653 class c:
654 654 def match(self, x): return on_empty
655 655 return c()
656 656 regexp = r'%s(?:%s)%s' % (
657 657 head,
658 658 '|'.join([fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
659 659 for p in pats]),
660 660 tail)
661 661 return re.compile(regexp)
662 662 exclude = compile(opts['exclude'], on_empty = False)
663 663 include = compile(opts['include'])
664 664 pat = compile([os.path.normcase(p) for p in pats], head = '', tail = '$')
665 665 end = '\n'
666 666 if opts['print0']: end = '\0'
667 667 if opts['rev']: node = repo.manifest.lookup(opts['rev'])
668 668 else: node = repo.manifest.tip()
669 669 manifest = repo.manifest.read(node)
670 670 cwd = repo.getcwd()
671 671 cwd_plus = cwd and (cwd + os.sep)
672 672 found = []
673 673 for f in manifest:
674 674 f = os.path.normcase(f)
675 675 if exclude.match(f) or not(include.match(f) and
676 676 f.startswith(cwd_plus) and
677 677 pat.match(os.path.basename(f))): continue
678 678 if opts['fullpath']: f = os.path.join(repo.root, f)
679 679 elif cwd: f = f[len(cwd_plus):]
680 680 found.append(f)
681 681 found.sort()
682 682 for f in found: ui.write(f, end)
683 683
684 684 def log(ui, repo, f=None, **opts):
685 685 """show the revision history of the repository or a single file"""
686 686 if f:
687 687 files = relpath(repo, [f])
688 688 filelog = repo.file(files[0])
689 689 log = filelog
690 690 lookup = filelog.lookup
691 691 else:
692 692 files = None
693 693 filelog = None
694 694 log = repo.changelog
695 695 lookup = repo.lookup
696 696 revlist = []
697 697 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
698 698 while revs:
699 699 if len(revs) == 1:
700 700 revlist.append(revs.pop(0))
701 701 else:
702 702 a = revs.pop(0)
703 703 b = revs.pop(0)
704 704 off = a > b and -1 or 1
705 705 revlist.extend(range(a, b + off, off))
706 706
707 707 for i in revlist or range(log.count() - 1, -1, -1):
708 708 show_changeset(ui, repo, filelog=filelog, rev=i)
709 709 if opts['patch']:
710 710 if filelog:
711 711 filenode = filelog.node(i)
712 712 i = filelog.linkrev(filenode)
713 713 changenode = repo.changelog.node(i)
714 714 prev, other = repo.changelog.parents(changenode)
715 715 dodiff(sys.stdout, ui, repo, files, prev, changenode)
716 716 ui.write("\n")
717 717 ui.write("\n")
718 718
719 719 def manifest(ui, repo, rev = []):
720 720 """output the latest or given revision of the project manifest"""
721 721 n = repo.manifest.tip()
722 722 if rev:
723 723 n = repo.manifest.lookup(rev)
724 724 m = repo.manifest.read(n)
725 725 mf = repo.manifest.readflags(n)
726 726 files = m.keys()
727 727 files.sort()
728 728
729 729 for f in files:
730 730 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
731 731
732 732 def parents(ui, repo, node = None):
733 733 '''show the parents of the current working dir'''
734 734 if node:
735 735 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
736 736 else:
737 737 p = repo.dirstate.parents()
738 738
739 739 for n in p:
740 740 if n != hg.nullid:
741 741 show_changeset(ui, repo, changenode=n)
742 742
743 743 def pull(ui, repo, source="default", **opts):
744 744 """pull changes from the specified source"""
745 745 source = ui.expandpath(source)
746 746 ui.status('pulling from %s\n' % (source))
747 747
748 748 other = hg.repository(ui, source)
749 749 r = repo.pull(other)
750 750 if not r:
751 751 if opts['update']:
752 752 return update(ui, repo)
753 753 else:
754 754 ui.status("(run 'hg update' to get a working copy)\n")
755 755
756 756 return r
757 757
758 758 def push(ui, repo, dest="default-push"):
759 759 """push changes to the specified destination"""
760 760 dest = ui.expandpath(dest)
761 761 ui.status('pushing to %s\n' % (dest))
762 762
763 763 other = hg.repository(ui, dest)
764 764 r = repo.push(other)
765 765 return r
766 766
767 767 def rawcommit(ui, repo, *flist, **rc):
768 768 "raw commit interface"
769 769
770 770 text = rc['text']
771 771 if not text and rc['logfile']:
772 772 try: text = open(rc['logfile']).read()
773 773 except IOError: pass
774 774 if not text and not rc['logfile']:
775 775 ui.warn("abort: missing commit text\n")
776 776 return 1
777 777
778 778 files = relpath(repo, list(flist))
779 779 if rc['files']:
780 780 files += open(rc['files']).read().splitlines()
781 781
782 782 rc['parent'] = map(repo.lookup, rc['parent'])
783 783
784 784 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
785 785
786 786 def recover(ui, repo):
787 787 """roll back an interrupted transaction"""
788 788 repo.recover()
789 789
790 790 def remove(ui, repo, file, *files):
791 791 """remove the specified files on the next commit"""
792 792 repo.remove(relpath(repo, (file,) + files))
793 793
794 794 def revert(ui, repo, *names, **opts):
795 795 """revert modified files or dirs back to their unmodified states"""
796 796 node = opts['rev'] and repo.lookup(opts['rev']) or \
797 797 repo.dirstate.parents()[0]
798 798 root = os.path.realpath(repo.root)
799 799
800 800 def trimpath(p):
801 801 p = os.path.realpath(p)
802 802 if p.startswith(root):
803 803 rest = p[len(root):]
804 804 if not rest:
805 805 return rest
806 806 if p.startswith(os.sep):
807 807 return rest[1:]
808 808 return p
809 809
810 810 relnames = map(trimpath, names or [os.getcwd()])
811 811 chosen = {}
812 812
813 813 def choose(name):
814 814 def body(name):
815 815 for r in relnames:
816 816 if not name.startswith(r): continue
817 817 rest = name[len(r):]
818 818 if not rest: return r, True
819 819 depth = rest.count(os.sep)
820 820 if not r:
821 821 if depth == 0 or not opts['nonrecursive']: return r, True
822 822 elif rest[0] == os.sep:
823 823 if depth == 1 or not opts['nonrecursive']: return r, True
824 824 return None, False
825 825 relname, ret = body(name)
826 826 if ret:
827 827 chosen[relname] = 1
828 828 return ret
829 829
830 830 r = repo.update(node, False, True, choose, False)
831 831 for n in relnames:
832 832 if n not in chosen:
833 833 ui.warn('error: no matches for %s\n' % n)
834 834 r = 1
835 835 sys.stdout.flush()
836 836 return r
837 837
838 838 def root(ui, repo):
839 839 """print the root (top) of the current working dir"""
840 840 ui.write(repo.root + "\n")
841 841
842 842 def serve(ui, repo, **opts):
843 843 """export the repository via HTTP"""
844 844
845 845 if opts["stdio"]:
846 846 fin, fout = sys.stdin, sys.stdout
847 847 sys.stdout = sys.stderr
848 848
849 849 def getarg():
850 850 argline = fin.readline()[:-1]
851 851 arg, l = argline.split()
852 852 val = fin.read(int(l))
853 853 return arg, val
854 854 def respond(v):
855 855 fout.write("%d\n" % len(v))
856 856 fout.write(v)
857 857 fout.flush()
858 858
859 859 lock = None
860 860
861 861 while 1:
862 862 cmd = fin.readline()[:-1]
863 863 if cmd == '':
864 864 return
865 865 if cmd == "heads":
866 866 h = repo.heads()
867 867 respond(" ".join(map(hg.hex, h)) + "\n")
868 868 if cmd == "lock":
869 869 lock = repo.lock()
870 870 respond("")
871 871 if cmd == "unlock":
872 872 if lock: lock.release()
873 873 lock = None
874 874 respond("")
875 875 elif cmd == "branches":
876 876 arg, nodes = getarg()
877 877 nodes = map(hg.bin, nodes.split(" "))
878 878 r = []
879 879 for b in repo.branches(nodes):
880 880 r.append(" ".join(map(hg.hex, b)) + "\n")
881 881 respond("".join(r))
882 882 elif cmd == "between":
883 883 arg, pairs = getarg()
884 884 pairs = [ map(hg.bin, p.split("-")) for p in pairs.split(" ") ]
885 885 r = []
886 886 for b in repo.between(pairs):
887 887 r.append(" ".join(map(hg.hex, b)) + "\n")
888 888 respond("".join(r))
889 889 elif cmd == "changegroup":
890 890 nodes = []
891 891 arg, roots = getarg()
892 892 nodes = map(hg.bin, roots.split(" "))
893 893
894 894 cg = repo.changegroup(nodes)
895 895 while 1:
896 896 d = cg.read(4096)
897 897 if not d: break
898 898 fout.write(d)
899 899
900 900 out.flush()
901 901
902 902 elif cmd == "addchangegroup":
903 903 if not lock:
904 904 respond("not locked")
905 905 continue
906 906 respond("")
907 907
908 908 r = repo.addchangegroup(fin)
909 909 respond("")
910 910
911 911 def openlog(opt, default):
912 912 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
913 913 else: return default
914 914
915 915 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
916 916 opts["address"], opts["port"],
917 917 openlog('accesslog', sys.stdout),
918 918 openlog('errorlog', sys.stderr))
919 919 if ui.verbose:
920 920 addr, port = httpd.socket.getsockname()
921 921 if addr == '0.0.0.0':
922 922 addr = socket.gethostname()
923 923 else:
924 924 try:
925 925 addr = socket.gethostbyaddr(addr)[0]
926 926 except: pass
927 927 if port != 80:
928 928 ui.status('listening at http://%s:%d/\n' % (addr, port))
929 929 else:
930 930 ui.status('listening at http://%s/\n' % addr)
931 931 httpd.serve_forever()
932 932
933 933 def status(ui, repo):
934 934 '''show changed files in the working directory
935 935
936 936 C = changed
937 937 A = added
938 938 R = removed
939 939 ? = not tracked'''
940 940
941 941 (c, a, d, u) = repo.changes(None, None)
942 942 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
943 943
944 944 for f in c: ui.write("C ", f, "\n")
945 945 for f in a: ui.write("A ", f, "\n")
946 946 for f in d: ui.write("R ", f, "\n")
947 947 for f in u: ui.write("? ", f, "\n")
948 948
949 949 def tag(ui, repo, name, rev = None, **opts):
950 950 """add a tag for the current tip or a given revision"""
951 951
952 952 if name == "tip":
953 953 ui.warn("abort: 'tip' is a reserved name!\n")
954 954 return -1
955 955 if rev:
956 956 r = hg.hex(repo.lookup(rev))
957 957 else:
958 958 r = hg.hex(repo.changelog.tip())
959 959
960 960 if name.find(revrangesep) >= 0:
961 961 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
962 962 return -1
963 963
964 964 if opts['local']:
965 965 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
966 966 return
967 967
968 968 (c, a, d, u) = repo.changes(None, None)
969 969 for x in (c, a, d, u):
970 970 if ".hgtags" in x:
971 971 ui.warn("abort: working copy of .hgtags is changed!\n")
972 972 ui.status("(please commit .hgtags manually)\n")
973 973 return -1
974 974
975 975 add = 0
976 976 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
977 977 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
978 978 if add: repo.add([".hgtags"])
979 979
980 980 if not opts['text']:
981 981 opts['text'] = "Added tag %s for changeset %s" % (name, r)
982 982
983 983 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
984 984
985 985 def tags(ui, repo):
986 986 """list repository tags"""
987 987
988 988 l = repo.tagslist()
989 989 l.reverse()
990 990 for t, n in l:
991 991 try:
992 992 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
993 993 except KeyError:
994 994 r = " ?:?"
995 995 ui.write("%-30s %s\n" % (t, r))
996 996
997 997 def tip(ui, repo):
998 998 """show the tip revision"""
999 999 n = repo.changelog.tip()
1000 1000 show_changeset(ui, repo, changenode=n)
1001 1001
1002 1002 def undo(ui, repo):
1003 1003 """undo the last commit or pull
1004 1004
1005 1005 Roll back the last pull or commit transaction on the
1006 1006 repository, restoring the project to its earlier state.
1007 1007
1008 1008 This command should be used with care. There is only one level of
1009 1009 undo and there is no redo.
1010 1010
1011 1011 This command is not intended for use on public repositories. Once
1012 1012 a change is visible for pull by other users, undoing it locally is
1013 1013 ineffective.
1014 1014 """
1015 1015 repo.undo()
1016 1016
1017 1017 def update(ui, repo, node=None, merge=False, clean=False):
1018 1018 '''update or merge working directory
1019 1019
1020 1020 If there are no outstanding changes in the working directory and
1021 1021 there is a linear relationship between the current version and the
1022 1022 requested version, the result is the requested version.
1023 1023
1024 1024 Otherwise the result is a merge between the contents of the
1025 1025 current working directory and the requested version. Files that
1026 1026 changed between either parent are marked as changed for the next
1027 1027 commit and a commit must be performed before any further updates
1028 1028 are allowed.
1029 1029 '''
1030 1030 node = node and repo.lookup(node) or repo.changelog.tip()
1031 1031 return repo.update(node, allow=merge, force=clean)
1032 1032
1033 1033 def verify(ui, repo):
1034 1034 """verify the integrity of the repository"""
1035 1035 return repo.verify()
1036 1036
1037 1037 # Command options and aliases are listed here, alphabetically
1038 1038
1039 1039 table = {
1040 1040 "^add": (add, [], "hg add [files]"),
1041 1041 "addremove": (addremove, [], "hg addremove [files]"),
1042 1042 "^annotate": (annotate,
1043 1043 [('r', 'revision', '', 'revision'),
1044 1044 ('u', 'user', None, 'show user'),
1045 1045 ('n', 'number', None, 'show revision number'),
1046 1046 ('c', 'changeset', None, 'show changeset')],
1047 1047 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
1048 1048 "cat": (cat, [('o', 'output', "", 'output to file')], 'hg cat [-o outfile] file> [rev]'),
1049 1049 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
1050 1050 'hg clone [options] <source> [dest]'),
1051 1051 "^commit|ci": (commit,
1052 1052 [('t', 'text', "", 'commit text'),
1053 1053 ('A', 'addremove', None, 'run add/remove during commit'),
1054 1054 ('l', 'logfile', "", 'commit text file'),
1055 1055 ('d', 'date', "", 'date code'),
1056 1056 ('u', 'user', "", 'user')],
1057 1057 'hg commit [files]'),
1058 1058 "copy": (copy, [], 'hg copy <source> <dest>'),
1059 1059 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1060 1060 "debugstate": (debugstate, [], 'debugstate'),
1061 1061 "debugindex": (debugindex, [], 'debugindex <file>'),
1062 1062 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
1063 1063 "^diff": (diff, [('r', 'rev', [], 'revision')],
1064 1064 'hg diff [-r A] [-r B] [files]'),
1065 1065 "^export": (export, [('o', 'output', "", 'output to file')],
1066 1066 "hg export [-o file] <changeset> ..."),
1067 1067 "forget": (forget, [], "hg forget [files]"),
1068 1068 "heads": (heads, [], 'hg heads'),
1069 1069 "help": (help, [], 'hg help [command]'),
1070 1070 "identify|id": (identify, [], 'hg identify'),
1071 1071 "import|patch": (import_,
1072 1072 [('p', 'strip', 1, 'path strip'),
1073 1073 ('b', 'base', "", 'base path')],
1074 1074 "hg import [options] <patches>"),
1075 1075 "^init": (init, [], 'hg init'),
1076 1076 "locate": (locate,
1077 1077 [('0', 'print0', None, 'end records with NUL'),
1078 1078 ('f', 'fullpath', None, 'print complete paths'),
1079 1079 ('i', 'include', [], 'include path in search'),
1080 1080 ('r', 'rev', '', 'revision'),
1081 1081 ('x', 'exclude', [], 'exclude path from search')],
1082 1082 'hg locate [options] [files]'),
1083 1083 "^log|history": (log,
1084 1084 [('r', 'rev', [], 'revision'),
1085 1085 ('p', 'patch', None, 'show patch')],
1086 1086 'hg log [-r A] [-r B] [-p] [file]'),
1087 1087 "manifest": (manifest, [], 'hg manifest [rev]'),
1088 1088 "parents": (parents, [], 'hg parents [node]'),
1089 1089 "^pull": (pull,
1090 1090 [('u', 'update', None, 'update working directory')],
1091 1091 'hg pull [options] [source]'),
1092 1092 "^push": (push, [], 'hg push <destination>'),
1093 1093 "rawcommit": (rawcommit,
1094 1094 [('p', 'parent', [], 'parent'),
1095 1095 ('d', 'date', "", 'date code'),
1096 1096 ('u', 'user', "", 'user'),
1097 1097 ('F', 'files', "", 'file list'),
1098 1098 ('t', 'text', "", 'commit text'),
1099 1099 ('l', 'logfile', "", 'commit text file')],
1100 1100 'hg rawcommit [options] [files]'),
1101 1101 "recover": (recover, [], "hg recover"),
1102 1102 "^remove|rm": (remove, [], "hg remove [files]"),
1103 1103 "^revert": (revert,
1104 1104 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1105 1105 ("r", "rev", "", "revision")],
1106 1106 "hg revert [files|dirs]"),
1107 1107 "root": (root, [], "hg root"),
1108 1108 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1109 1109 ('E', 'errorlog', '', 'error log file'),
1110 1110 ('p', 'port', 8000, 'listen port'),
1111 1111 ('a', 'address', '', 'interface address'),
1112 1112 ('n', 'name', os.getcwd(), 'repository name'),
1113 1113 ('', 'stdio', None, 'for remote clients'),
1114 1114 ('t', 'templates', "", 'template map')],
1115 1115 "hg serve [options]"),
1116 1116 "^status": (status, [], 'hg status'),
1117 1117 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1118 1118 ('t', 'text', "", 'commit text'),
1119 1119 ('d', 'date', "", 'date code'),
1120 1120 ('u', 'user', "", 'user')],
1121 1121 'hg tag [options] <name> [rev]'),
1122 1122 "tags": (tags, [], 'hg tags'),
1123 1123 "tip": (tip, [], 'hg tip'),
1124 1124 "undo": (undo, [], 'hg undo'),
1125 1125 "^update|up|checkout|co":
1126 1126 (update,
1127 1127 [('m', 'merge', None, 'allow merging of conflicts'),
1128 1128 ('C', 'clean', None, 'overwrite locally modified files')],
1129 1129 'hg update [options] [node]'),
1130 1130 "verify": (verify, [], 'hg verify'),
1131 1131 "version": (show_version, [], 'hg version'),
1132 1132 }
1133 1133
1134 1134 globalopts = [('v', 'verbose', None, 'verbose'),
1135 1135 ('', 'debug', None, 'debug'),
1136 1136 ('q', 'quiet', None, 'quiet'),
1137 1137 ('', 'profile', None, 'profile'),
1138 1138 ('R', 'repository', "", 'repository root directory'),
1139 1139 ('', 'traceback', None, 'print traceback on exception'),
1140 1140 ('y', 'noninteractive', None, 'run non-interactively'),
1141 1141 ('', 'version', None, 'output version information and exit'),
1142 1142 ]
1143 1143
1144 1144 norepo = "clone init version help debugindex debugindexdot"
1145 1145
1146 1146 def find(cmd):
1147 1147 for e in table.keys():
1148 1148 if re.match("(%s)$" % e, cmd):
1149 1149 return table[e]
1150 1150
1151 1151 raise UnknownCommand(cmd)
1152 1152
1153 1153 class SignalInterrupt(Exception): pass
1154 1154
1155 1155 def catchterm(*args):
1156 1156 raise SignalInterrupt
1157 1157
1158 1158 def run():
1159 1159 sys.exit(dispatch(sys.argv[1:]))
1160 1160
1161 1161 class ParseError(Exception): pass
1162 1162
1163 1163 def parse(args):
1164 1164 options = {}
1165 1165 cmdoptions = {}
1166 1166
1167 1167 try:
1168 1168 args = fancyopts.fancyopts(args, globalopts, options)
1169 1169 except fancyopts.getopt.GetoptError, inst:
1170 1170 raise ParseError(None, inst)
1171 1171
1172 1172 if options["version"]:
1173 1173 return ("version", show_version, [], options, cmdoptions)
1174 1174 elif not args:
1175 1175 return ("help", help, [], options, cmdoptions)
1176 1176 else:
1177 1177 cmd, args = args[0], args[1:]
1178 1178
1179 1179 i = find(cmd)
1180 1180
1181 1181 # combine global options into local
1182 1182 c = list(i[1])
1183 1183 l = len(c)
1184 1184 for o in globalopts:
1185 1185 c.append((o[0], o[1], options[o[1]], o[3]))
1186 1186
1187 1187 try:
1188 1188 args = fancyopts.fancyopts(args, c, cmdoptions)
1189 1189 except fancyopts.getopt.GetoptError, inst:
1190 1190 raise ParseError(cmd, inst)
1191 1191
1192 1192 # separate global options back out
1193 1193 for o in globalopts:
1194 1194 n = o[1]
1195 1195 options[n] = cmdoptions[n]
1196 1196 del cmdoptions[n]
1197 1197
1198 1198 return (cmd, i[0], args, options, cmdoptions)
1199 1199
1200 1200 def dispatch(args):
1201 1201 signal.signal(signal.SIGTERM, catchterm)
1202 signal.signal(signal.SIGHUP, catchterm)
1202 1203
1203 1204 try:
1204 1205 cmd, func, args, options, cmdoptions = parse(args)
1205 1206 except ParseError, inst:
1206 1207 u = ui.ui()
1207 1208 if inst.args[0]:
1208 1209 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1209 1210 help(u, inst.args[0])
1210 1211 else:
1211 1212 u.warn("hg: %s\n" % inst.args[1])
1212 1213 help(u)
1213 1214 sys.exit(-1)
1214 1215 except UnknownCommand, inst:
1215 1216 u = ui.ui()
1216 1217 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1217 1218 help(u)
1218 1219 sys.exit(1)
1219 1220
1220 1221 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1221 1222 not options["noninteractive"])
1222 1223
1223 1224 try:
1224 1225 try:
1225 1226 if cmd not in norepo.split():
1226 1227 path = options["repository"] or ""
1227 1228 repo = hg.repository(ui=u, path=path)
1228 1229 d = lambda: func(u, repo, *args, **cmdoptions)
1229 1230 else:
1230 1231 d = lambda: func(u, *args, **cmdoptions)
1231 1232
1232 1233 if options['profile']:
1233 1234 import hotshot, hotshot.stats
1234 1235 prof = hotshot.Profile("hg.prof")
1235 1236 r = prof.runcall(d)
1236 1237 prof.close()
1237 1238 stats = hotshot.stats.load("hg.prof")
1238 1239 stats.strip_dirs()
1239 1240 stats.sort_stats('time', 'calls')
1240 1241 stats.print_stats(40)
1241 1242 return r
1242 1243 else:
1243 1244 return d()
1244 1245 except:
1245 1246 if options['traceback']:
1246 1247 traceback.print_exc()
1247 1248 raise
1248 1249 except util.CommandError, inst:
1249 1250 u.warn("abort: %s\n" % inst.args)
1250 1251 except hg.RepoError, inst:
1251 1252 u.warn("abort: ", inst, "!\n")
1252 1253 except SignalInterrupt:
1253 1254 u.warn("killed!\n")
1254 1255 except KeyboardInterrupt:
1255 1256 u.warn("interrupted!\n")
1256 1257 except IOError, inst:
1257 1258 if hasattr(inst, "code"):
1258 1259 u.warn("abort: %s\n" % inst)
1259 1260 elif hasattr(inst, "reason"):
1260 1261 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1261 1262 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1262 1263 u.warn("broken pipe\n")
1263 1264 else:
1264 1265 raise
1265 1266 except OSError, inst:
1266 1267 if hasattr(inst, "filename"):
1267 1268 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1268 1269 else:
1269 1270 u.warn("abort: %s\n" % inst.strerror)
1270 1271 except TypeError, inst:
1271 1272 # was this an argument error?
1272 1273 tb = traceback.extract_tb(sys.exc_info()[2])
1273 1274 if len(tb) > 2: # no
1274 1275 raise
1275 1276 u.debug(inst, "\n")
1276 1277 u.warn("%s: invalid arguments\n" % cmd)
1277 1278 help(u, cmd)
1278 1279
1279 1280 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now