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