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