##// END OF EJS Templates
On importing the result of 'hg export', parse while reading and drop headers....
Thomas Arendsen Hein -
r701:80ed193e default
parent child Browse files
Show More
@@ -1,1354 +1,1355 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 text = ""
618 for l in file(pf):
619 if l.startswith("--- ") or l.startswith("diff -r"):
617 text = []
618 user = None
619 hgpatch = False
620 for line in file(pf):
621 line = line.rstrip()
622 if line.startswith("--- ") or line.startswith("diff -r"):
620 623 break
621 text += l
622
623 # parse values that exist when importing the result of an hg export
624 hgpatch = user = snippet = None
625 ui.debug('text:\n')
626 for t in text.splitlines():
627 ui.debug(t, '\n')
628 if t == '# HG changeset patch' or hgpatch:
624 elif hgpatch:
625 # parse values when importing the result of an hg export
626 if line.startswith("# User "):
627 user = line[7:]
628 ui.debug('User: %s\n' % user)
629 elif not line.startswith("# ") and line:
630 text.append(line)
631 hgpatch = False
632 elif line == '# HG changeset patch':
629 633 hgpatch = True
630 if t.startswith("# User "):
631 user = t[7:]
632 ui.debug('User: %s\n' % user)
633 if not t.startswith("# ") and t.strip() and not snippet:
634 snippet = t
635 if snippet:
636 text = snippet + '\n' + text
637 ui.debug('text:\n%s\n' % text)
634 else:
635 text.append(line)
638 636
639 637 # make sure text isn't empty
640 638 if not text:
641 639 text = "imported patch %s\n" % patch
640 else:
641 text = "%s\n" % '\n'.join(text)
642 ui.debug('text:\n%s\n' % text)
642 643
643 644 f = os.popen("patch -p%d < %s" % (strip, pf))
644 645 files = []
645 646 for l in f.read().splitlines():
646 647 l.rstrip('\r\n');
647 648 ui.status("%s\n" % l)
648 649 if l.startswith('patching file '):
649 650 pf = l[14:]
650 651 if pf not in files:
651 652 files.append(pf)
652 653 patcherr = f.close()
653 654 if patcherr:
654 655 sys.stderr.write("patch failed")
655 656 sys.exit(1)
656 657
657 658 if len(files) > 0:
658 659 addremove(ui, repo, *files)
659 660 repo.commit(files, text, user)
660 661
661 662 def init(ui, source=None):
662 663 """create a new repository in the current directory"""
663 664
664 665 if source:
665 666 ui.warn("no longer supported: use \"hg clone\" instead\n")
666 667 sys.exit(1)
667 668 hg.repository(ui, ".", create=1)
668 669
669 670 def locate(ui, repo, *pats, **opts):
670 671 """locate files matching specific patterns"""
671 672 if [p for p in pats if os.sep in p]:
672 673 ui.warn("error: patterns may not contain '%s'\n" % os.sep)
673 674 ui.warn("use '-i <dir>' instead\n")
674 675 sys.exit(1)
675 676 def compile(pats, head='^', tail=os.sep, on_empty=True):
676 677 if not pats:
677 678 class c:
678 679 def match(self, x):
679 680 return on_empty
680 681 return c()
681 682 fnpats = [fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
682 683 for p in pats]
683 684 regexp = r'%s(?:%s)%s' % (head, '|'.join(fnpats), tail)
684 685 return re.compile(regexp)
685 686 exclude = compile(opts['exclude'], on_empty=False)
686 687 include = compile(opts['include'])
687 688 pat = compile(pats, head='', tail='$')
688 689 end = opts['print0'] and '\0' or '\n'
689 690 if opts['rev']:
690 691 node = repo.manifest.lookup(opts['rev'])
691 692 else:
692 693 node = repo.manifest.tip()
693 694 manifest = repo.manifest.read(node)
694 695 cwd = repo.getcwd()
695 696 cwd_plus = cwd and (cwd + os.sep)
696 697 found = []
697 698 for f in manifest:
698 699 f = os.path.normcase(f)
699 700 if exclude.match(f) or not(include.match(f) and
700 701 f.startswith(cwd_plus) and
701 702 pat.match(os.path.basename(f))):
702 703 continue
703 704 if opts['fullpath']:
704 705 f = os.path.join(repo.root, f)
705 706 elif cwd:
706 707 f = f[len(cwd_plus):]
707 708 found.append(f)
708 709 found.sort()
709 710 for f in found:
710 711 ui.write(f, end)
711 712
712 713 def log(ui, repo, f=None, **opts):
713 714 """show the revision history of the repository or a single file"""
714 715 if f:
715 716 files = relpath(repo, [f])
716 717 filelog = repo.file(files[0])
717 718 log = filelog
718 719 lookup = filelog.lookup
719 720 else:
720 721 files = None
721 722 filelog = None
722 723 log = repo.changelog
723 724 lookup = repo.lookup
724 725 revlist = []
725 726 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
726 727 while revs:
727 728 if len(revs) == 1:
728 729 revlist.append(revs.pop(0))
729 730 else:
730 731 a = revs.pop(0)
731 732 b = revs.pop(0)
732 733 off = a > b and -1 or 1
733 734 revlist.extend(range(a, b + off, off))
734 735
735 736 for i in revlist or range(log.count() - 1, -1, -1):
736 737 show_changeset(ui, repo, filelog=filelog, rev=i)
737 738 if opts['patch']:
738 739 if filelog:
739 740 filenode = filelog.node(i)
740 741 i = filelog.linkrev(filenode)
741 742 changenode = repo.changelog.node(i)
742 743 prev, other = repo.changelog.parents(changenode)
743 744 dodiff(sys.stdout, ui, repo, files, prev, changenode)
744 745 ui.write("\n\n")
745 746
746 747 def manifest(ui, repo, rev=None):
747 748 """output the latest or given revision of the project manifest"""
748 749 if rev:
749 750 try:
750 751 # assume all revision numbers are for changesets
751 752 n = repo.lookup(rev)
752 753 change = repo.changelog.read(n)
753 754 n = change[0]
754 755 except hg.RepoError:
755 756 n = repo.manifest.lookup(rev)
756 757 else:
757 758 n = repo.manifest.tip()
758 759 m = repo.manifest.read(n)
759 760 mf = repo.manifest.readflags(n)
760 761 files = m.keys()
761 762 files.sort()
762 763
763 764 for f in files:
764 765 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
765 766
766 767 def parents(ui, repo, node=None):
767 768 '''show the parents of the current working dir'''
768 769 if node:
769 770 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
770 771 else:
771 772 p = repo.dirstate.parents()
772 773
773 774 for n in p:
774 775 if n != hg.nullid:
775 776 show_changeset(ui, repo, changenode=n)
776 777
777 778 def pull(ui, repo, source="default", **opts):
778 779 """pull changes from the specified source"""
779 780 source = ui.expandpath(source)
780 781 ui.status('pulling from %s\n' % (source))
781 782
782 783 other = hg.repository(ui, source)
783 784 r = repo.pull(other)
784 785 if not r:
785 786 if opts['update']:
786 787 return update(ui, repo)
787 788 else:
788 789 ui.status("(run 'hg update' to get a working copy)\n")
789 790
790 791 return r
791 792
792 793 def push(ui, repo, dest="default-push"):
793 794 """push changes to the specified destination"""
794 795 dest = ui.expandpath(dest)
795 796 ui.status('pushing to %s\n' % (dest))
796 797
797 798 other = hg.repository(ui, dest)
798 799 r = repo.push(other)
799 800 return r
800 801
801 802 def rawcommit(ui, repo, *flist, **rc):
802 803 "raw commit interface"
803 804
804 805 text = rc['text']
805 806 if not text and rc['logfile']:
806 807 try:
807 808 text = open(rc['logfile']).read()
808 809 except IOError:
809 810 pass
810 811 if not text and not rc['logfile']:
811 812 ui.warn("abort: missing commit text\n")
812 813 return 1
813 814
814 815 files = relpath(repo, list(flist))
815 816 if rc['files']:
816 817 files += open(rc['files']).read().splitlines()
817 818
818 819 rc['parent'] = map(repo.lookup, rc['parent'])
819 820
820 821 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
821 822
822 823 def recover(ui, repo):
823 824 """roll back an interrupted transaction"""
824 825 repo.recover()
825 826
826 827 def remove(ui, repo, file1, *files):
827 828 """remove the specified files on the next commit"""
828 829 repo.remove(relpath(repo, (file1,) + files))
829 830
830 831 def revert(ui, repo, *names, **opts):
831 832 """revert modified files or dirs back to their unmodified states"""
832 833 node = opts['rev'] and repo.lookup(opts['rev']) or \
833 834 repo.dirstate.parents()[0]
834 835 root = os.path.realpath(repo.root)
835 836
836 837 def trimpath(p):
837 838 p = os.path.realpath(p)
838 839 if p.startswith(root):
839 840 rest = p[len(root):]
840 841 if not rest:
841 842 return rest
842 843 if p.startswith(os.sep):
843 844 return rest[1:]
844 845 return p
845 846
846 847 relnames = map(trimpath, names or [os.getcwd()])
847 848 chosen = {}
848 849
849 850 def choose(name):
850 851 def body(name):
851 852 for r in relnames:
852 853 if not name.startswith(r):
853 854 continue
854 855 rest = name[len(r):]
855 856 if not rest:
856 857 return r, True
857 858 depth = rest.count(os.sep)
858 859 if not r:
859 860 if depth == 0 or not opts['nonrecursive']:
860 861 return r, True
861 862 elif rest[0] == os.sep:
862 863 if depth == 1 or not opts['nonrecursive']:
863 864 return r, True
864 865 return None, False
865 866 relname, ret = body(name)
866 867 if ret:
867 868 chosen[relname] = 1
868 869 return ret
869 870
870 871 r = repo.update(node, False, True, choose, False)
871 872 for n in relnames:
872 873 if n not in chosen:
873 874 ui.warn('error: no matches for %s\n' % n)
874 875 r = 1
875 876 sys.stdout.flush()
876 877 return r
877 878
878 879 def root(ui, repo):
879 880 """print the root (top) of the current working dir"""
880 881 ui.write(repo.root + "\n")
881 882
882 883 def serve(ui, repo, **opts):
883 884 """export the repository via HTTP"""
884 885
885 886 if opts["stdio"]:
886 887 fin, fout = sys.stdin, sys.stdout
887 888 sys.stdout = sys.stderr
888 889
889 890 def getarg():
890 891 argline = fin.readline()[:-1]
891 892 arg, l = argline.split()
892 893 val = fin.read(int(l))
893 894 return arg, val
894 895 def respond(v):
895 896 fout.write("%d\n" % len(v))
896 897 fout.write(v)
897 898 fout.flush()
898 899
899 900 lock = None
900 901
901 902 while 1:
902 903 cmd = fin.readline()[:-1]
903 904 if cmd == '':
904 905 return
905 906 if cmd == "heads":
906 907 h = repo.heads()
907 908 respond(" ".join(map(hg.hex, h)) + "\n")
908 909 if cmd == "lock":
909 910 lock = repo.lock()
910 911 respond("")
911 912 if cmd == "unlock":
912 913 if lock:
913 914 lock.release()
914 915 lock = None
915 916 respond("")
916 917 elif cmd == "branches":
917 918 arg, nodes = getarg()
918 919 nodes = map(hg.bin, nodes.split(" "))
919 920 r = []
920 921 for b in repo.branches(nodes):
921 922 r.append(" ".join(map(hg.hex, b)) + "\n")
922 923 respond("".join(r))
923 924 elif cmd == "between":
924 925 arg, pairs = getarg()
925 926 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
926 927 r = []
927 928 for b in repo.between(pairs):
928 929 r.append(" ".join(map(hg.hex, b)) + "\n")
929 930 respond("".join(r))
930 931 elif cmd == "changegroup":
931 932 nodes = []
932 933 arg, roots = getarg()
933 934 nodes = map(hg.bin, roots.split(" "))
934 935
935 936 cg = repo.changegroup(nodes)
936 937 while 1:
937 938 d = cg.read(4096)
938 939 if not d:
939 940 break
940 941 fout.write(d)
941 942
942 943 fout.flush()
943 944
944 945 elif cmd == "addchangegroup":
945 946 if not lock:
946 947 respond("not locked")
947 948 continue
948 949 respond("")
949 950
950 951 r = repo.addchangegroup(fin)
951 952 respond("")
952 953
953 954 def openlog(opt, default):
954 955 if opts[opt] and opts[opt] != '-':
955 956 return open(opts[opt], 'w')
956 957 else:
957 958 return default
958 959
959 960 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
960 961 opts["address"], opts["port"],
961 962 openlog('accesslog', sys.stdout),
962 963 openlog('errorlog', sys.stderr))
963 964 if ui.verbose:
964 965 addr, port = httpd.socket.getsockname()
965 966 if addr == '0.0.0.0':
966 967 addr = socket.gethostname()
967 968 else:
968 969 try:
969 970 addr = socket.gethostbyaddr(addr)[0]
970 971 except socket.error:
971 972 pass
972 973 if port != 80:
973 974 ui.status('listening at http://%s:%d/\n' % (addr, port))
974 975 else:
975 976 ui.status('listening at http://%s/\n' % addr)
976 977 httpd.serve_forever()
977 978
978 979 def status(ui, repo):
979 980 '''show changed files in the working directory
980 981
981 982 C = changed
982 983 A = added
983 984 R = removed
984 985 ? = not tracked'''
985 986
986 987 (c, a, d, u) = repo.changes(None, None)
987 988 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
988 989
989 990 for f in c:
990 991 ui.write("C ", f, "\n")
991 992 for f in a:
992 993 ui.write("A ", f, "\n")
993 994 for f in d:
994 995 ui.write("R ", f, "\n")
995 996 for f in u:
996 997 ui.write("? ", f, "\n")
997 998
998 999 def tag(ui, repo, name, rev=None, **opts):
999 1000 """add a tag for the current tip or a given revision"""
1000 1001
1001 1002 if name == "tip":
1002 1003 ui.warn("abort: 'tip' is a reserved name!\n")
1003 1004 return -1
1004 1005 if rev:
1005 1006 r = hg.hex(repo.lookup(rev))
1006 1007 else:
1007 1008 r = hg.hex(repo.changelog.tip())
1008 1009
1009 1010 if name.find(revrangesep) >= 0:
1010 1011 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1011 1012 return -1
1012 1013
1013 1014 if opts['local']:
1014 1015 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1015 1016 return
1016 1017
1017 1018 (c, a, d, u) = repo.changes(None, None)
1018 1019 for x in (c, a, d, u):
1019 1020 if ".hgtags" in x:
1020 1021 ui.warn("abort: working copy of .hgtags is changed!\n")
1021 1022 ui.status("(please commit .hgtags manually)\n")
1022 1023 return -1
1023 1024
1024 1025 add = not os.path.exists(repo.wjoin(".hgtags"))
1025 1026 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1026 1027 if add:
1027 1028 repo.add([".hgtags"])
1028 1029
1029 1030 if not opts['text']:
1030 1031 opts['text'] = "Added tag %s for changeset %s" % (name, r)
1031 1032
1032 1033 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
1033 1034
1034 1035 def tags(ui, repo):
1035 1036 """list repository tags"""
1036 1037
1037 1038 l = repo.tagslist()
1038 1039 l.reverse()
1039 1040 for t, n in l:
1040 1041 try:
1041 1042 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1042 1043 except KeyError:
1043 1044 r = " ?:?"
1044 1045 ui.write("%-30s %s\n" % (t, r))
1045 1046
1046 1047 def tip(ui, repo):
1047 1048 """show the tip revision"""
1048 1049 n = repo.changelog.tip()
1049 1050 show_changeset(ui, repo, changenode=n)
1050 1051
1051 1052 def undo(ui, repo):
1052 1053 """undo the last commit or pull
1053 1054
1054 1055 Roll back the last pull or commit transaction on the
1055 1056 repository, restoring the project to its earlier state.
1056 1057
1057 1058 This command should be used with care. There is only one level of
1058 1059 undo and there is no redo.
1059 1060
1060 1061 This command is not intended for use on public repositories. Once
1061 1062 a change is visible for pull by other users, undoing it locally is
1062 1063 ineffective.
1063 1064 """
1064 1065 repo.undo()
1065 1066
1066 1067 def update(ui, repo, node=None, merge=False, clean=False):
1067 1068 '''update or merge working directory
1068 1069
1069 1070 If there are no outstanding changes in the working directory and
1070 1071 there is a linear relationship between the current version and the
1071 1072 requested version, the result is the requested version.
1072 1073
1073 1074 Otherwise the result is a merge between the contents of the
1074 1075 current working directory and the requested version. Files that
1075 1076 changed between either parent are marked as changed for the next
1076 1077 commit and a commit must be performed before any further updates
1077 1078 are allowed.
1078 1079 '''
1079 1080 node = node and repo.lookup(node) or repo.changelog.tip()
1080 1081 return repo.update(node, allow=merge, force=clean)
1081 1082
1082 1083 def verify(ui, repo):
1083 1084 """verify the integrity of the repository"""
1084 1085 return repo.verify()
1085 1086
1086 1087 # Command options and aliases are listed here, alphabetically
1087 1088
1088 1089 table = {
1089 1090 "^add": (add, [], "hg add [files]"),
1090 1091 "addremove": (addremove, [], "hg addremove [files]"),
1091 1092 "^annotate":
1092 1093 (annotate,
1093 1094 [('r', 'revision', '', 'revision'),
1094 1095 ('u', 'user', None, 'show user'),
1095 1096 ('n', 'number', None, 'show revision number'),
1096 1097 ('c', 'changeset', None, 'show changeset')],
1097 1098 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
1098 1099 "cat":
1099 1100 (cat,
1100 1101 [('o', 'output', "", 'output to file')],
1101 1102 'hg cat [-o outfile] <file> [rev]'),
1102 1103 "^clone":
1103 1104 (clone,
1104 1105 [('U', 'noupdate', None, 'skip update after cloning')],
1105 1106 'hg clone [options] <source> [dest]'),
1106 1107 "^commit|ci":
1107 1108 (commit,
1108 1109 [('t', 'text', "", 'commit text'),
1109 1110 ('A', 'addremove', None, 'run add/remove during commit'),
1110 1111 ('l', 'logfile', "", 'commit text file'),
1111 1112 ('d', 'date', "", 'date code'),
1112 1113 ('u', 'user', "", 'user')],
1113 1114 'hg commit [files]'),
1114 1115 "copy": (copy, [], 'hg copy <source> <dest>'),
1115 1116 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1116 1117 "debugstate": (debugstate, [], 'debugstate'),
1117 1118 "debugindex": (debugindex, [], 'debugindex <file>'),
1118 1119 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
1119 1120 "^diff":
1120 1121 (diff,
1121 1122 [('r', 'rev', [], 'revision')],
1122 1123 'hg diff [-r A] [-r B] [files]'),
1123 1124 "^export":
1124 1125 (export,
1125 1126 [('o', 'output', "", 'output to file')],
1126 1127 "hg export [-o file] <changeset> ..."),
1127 1128 "forget": (forget, [], "hg forget [files]"),
1128 1129 "heads": (heads, [], 'hg heads'),
1129 1130 "help": (help_, [], 'hg help [command]'),
1130 1131 "identify|id": (identify, [], 'hg identify'),
1131 1132 "import|patch":
1132 1133 (import_,
1133 1134 [('p', 'strip', 1, 'path strip'),
1134 1135 ('b', 'base', "", 'base path')],
1135 1136 "hg import [options] <patches>"),
1136 1137 "^init": (init, [], 'hg init'),
1137 1138 "locate":
1138 1139 (locate,
1139 1140 [('0', 'print0', None, 'end records with NUL'),
1140 1141 ('f', 'fullpath', None, 'print complete paths'),
1141 1142 ('i', 'include', [], 'include path in search'),
1142 1143 ('r', 'rev', '', 'revision'),
1143 1144 ('x', 'exclude', [], 'exclude path from search')],
1144 1145 'hg locate [options] [files]'),
1145 1146 "^log|history":
1146 1147 (log,
1147 1148 [('r', 'rev', [], 'revision'),
1148 1149 ('p', 'patch', None, 'show patch')],
1149 1150 'hg log [-r A] [-r B] [-p] [file]'),
1150 1151 "manifest": (manifest, [], 'hg manifest [rev]'),
1151 1152 "parents": (parents, [], 'hg parents [node]'),
1152 1153 "^pull":
1153 1154 (pull,
1154 1155 [('u', 'update', None, 'update working directory')],
1155 1156 'hg pull [options] [source]'),
1156 1157 "^push": (push, [], 'hg push <destination>'),
1157 1158 "rawcommit":
1158 1159 (rawcommit,
1159 1160 [('p', 'parent', [], 'parent'),
1160 1161 ('d', 'date', "", 'date code'),
1161 1162 ('u', 'user', "", 'user'),
1162 1163 ('F', 'files', "", 'file list'),
1163 1164 ('t', 'text', "", 'commit text'),
1164 1165 ('l', 'logfile', "", 'commit text file')],
1165 1166 'hg rawcommit [options] [files]'),
1166 1167 "recover": (recover, [], "hg recover"),
1167 1168 "^remove|rm": (remove, [], "hg remove [files]"),
1168 1169 "^revert":
1169 1170 (revert,
1170 1171 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1171 1172 ("r", "rev", "", "revision")],
1172 1173 "hg revert [files|dirs]"),
1173 1174 "root": (root, [], "hg root"),
1174 1175 "^serve":
1175 1176 (serve,
1176 1177 [('A', 'accesslog', '', 'access log file'),
1177 1178 ('E', 'errorlog', '', 'error log file'),
1178 1179 ('p', 'port', 8000, 'listen port'),
1179 1180 ('a', 'address', '', 'interface address'),
1180 1181 ('n', 'name', os.getcwd(), 'repository name'),
1181 1182 ('', 'stdio', None, 'for remote clients'),
1182 1183 ('t', 'templates', "", 'template map')],
1183 1184 "hg serve [options]"),
1184 1185 "^status": (status, [], 'hg status'),
1185 1186 "tag":
1186 1187 (tag,
1187 1188 [('l', 'local', None, 'make the tag local'),
1188 1189 ('t', 'text', "", 'commit text'),
1189 1190 ('d', 'date', "", 'date code'),
1190 1191 ('u', 'user', "", 'user')],
1191 1192 'hg tag [options] <name> [rev]'),
1192 1193 "tags": (tags, [], 'hg tags'),
1193 1194 "tip": (tip, [], 'hg tip'),
1194 1195 "undo": (undo, [], 'hg undo'),
1195 1196 "^update|up|checkout|co":
1196 1197 (update,
1197 1198 [('m', 'merge', None, 'allow merging of conflicts'),
1198 1199 ('C', 'clean', None, 'overwrite locally modified files')],
1199 1200 'hg update [options] [node]'),
1200 1201 "verify": (verify, [], 'hg verify'),
1201 1202 "version": (show_version, [], 'hg version'),
1202 1203 }
1203 1204
1204 1205 globalopts = [('v', 'verbose', None, 'verbose'),
1205 1206 ('', 'debug', None, 'debug'),
1206 1207 ('q', 'quiet', None, 'quiet'),
1207 1208 ('', 'profile', None, 'profile'),
1208 1209 ('R', 'repository', "", 'repository root directory'),
1209 1210 ('', 'traceback', None, 'print traceback on exception'),
1210 1211 ('y', 'noninteractive', None, 'run non-interactively'),
1211 1212 ('', 'version', None, 'output version information and exit'),
1212 1213 ]
1213 1214
1214 1215 norepo = "clone init version help debugindex debugindexdot"
1215 1216
1216 1217 def find(cmd):
1217 1218 for e in table.keys():
1218 1219 if re.match("(%s)$" % e, cmd):
1219 1220 return table[e]
1220 1221
1221 1222 raise UnknownCommand(cmd)
1222 1223
1223 1224 class SignalInterrupt(Exception):
1224 1225 """Exception raised on SIGTERM and SIGHUP."""
1225 1226
1226 1227 def catchterm(*args):
1227 1228 raise SignalInterrupt
1228 1229
1229 1230 def run():
1230 1231 sys.exit(dispatch(sys.argv[1:]))
1231 1232
1232 1233 class ParseError(Exception):
1233 1234 """Exception raised on errors in parsing the command line."""
1234 1235
1235 1236 def parse(args):
1236 1237 options = {}
1237 1238 cmdoptions = {}
1238 1239
1239 1240 try:
1240 1241 args = fancyopts.fancyopts(args, globalopts, options)
1241 1242 except fancyopts.getopt.GetoptError, inst:
1242 1243 raise ParseError(None, inst)
1243 1244
1244 1245 if options["version"]:
1245 1246 return ("version", show_version, [], options, cmdoptions)
1246 1247 elif not args:
1247 1248 return ("help", help_, [], options, cmdoptions)
1248 1249 else:
1249 1250 cmd, args = args[0], args[1:]
1250 1251
1251 1252 i = find(cmd)
1252 1253
1253 1254 # combine global options into local
1254 1255 c = list(i[1])
1255 1256 for o in globalopts:
1256 1257 c.append((o[0], o[1], options[o[1]], o[3]))
1257 1258
1258 1259 try:
1259 1260 args = fancyopts.fancyopts(args, c, cmdoptions)
1260 1261 except fancyopts.getopt.GetoptError, inst:
1261 1262 raise ParseError(cmd, inst)
1262 1263
1263 1264 # separate global options back out
1264 1265 for o in globalopts:
1265 1266 n = o[1]
1266 1267 options[n] = cmdoptions[n]
1267 1268 del cmdoptions[n]
1268 1269
1269 1270 return (cmd, i[0], args, options, cmdoptions)
1270 1271
1271 1272 def dispatch(args):
1272 1273 signal.signal(signal.SIGTERM, catchterm)
1273 1274 try:
1274 1275 signal.signal(signal.SIGHUP, catchterm)
1275 1276 except AttributeError:
1276 1277 pass
1277 1278
1278 1279 try:
1279 1280 cmd, func, args, options, cmdoptions = parse(args)
1280 1281 except ParseError, inst:
1281 1282 u = ui.ui()
1282 1283 if inst.args[0]:
1283 1284 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1284 1285 help_(u, inst.args[0])
1285 1286 else:
1286 1287 u.warn("hg: %s\n" % inst.args[1])
1287 1288 help_(u)
1288 1289 sys.exit(-1)
1289 1290 except UnknownCommand, inst:
1290 1291 u = ui.ui()
1291 1292 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1292 1293 help_(u)
1293 1294 sys.exit(1)
1294 1295
1295 1296 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1296 1297 not options["noninteractive"])
1297 1298
1298 1299 try:
1299 1300 try:
1300 1301 if cmd not in norepo.split():
1301 1302 path = options["repository"] or ""
1302 1303 repo = hg.repository(ui=u, path=path)
1303 1304 d = lambda: func(u, repo, *args, **cmdoptions)
1304 1305 else:
1305 1306 d = lambda: func(u, *args, **cmdoptions)
1306 1307
1307 1308 if options['profile']:
1308 1309 import hotshot, hotshot.stats
1309 1310 prof = hotshot.Profile("hg.prof")
1310 1311 r = prof.runcall(d)
1311 1312 prof.close()
1312 1313 stats = hotshot.stats.load("hg.prof")
1313 1314 stats.strip_dirs()
1314 1315 stats.sort_stats('time', 'calls')
1315 1316 stats.print_stats(40)
1316 1317 return r
1317 1318 else:
1318 1319 return d()
1319 1320 except:
1320 1321 if options['traceback']:
1321 1322 traceback.print_exc()
1322 1323 raise
1323 1324 except util.CommandError, inst:
1324 1325 u.warn("abort: %s\n" % inst.args)
1325 1326 except hg.RepoError, inst:
1326 1327 u.warn("abort: ", inst, "!\n")
1327 1328 except SignalInterrupt:
1328 1329 u.warn("killed!\n")
1329 1330 except KeyboardInterrupt:
1330 1331 u.warn("interrupted!\n")
1331 1332 except IOError, inst:
1332 1333 if hasattr(inst, "code"):
1333 1334 u.warn("abort: %s\n" % inst)
1334 1335 elif hasattr(inst, "reason"):
1335 1336 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1336 1337 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1337 1338 u.warn("broken pipe\n")
1338 1339 else:
1339 1340 raise
1340 1341 except OSError, inst:
1341 1342 if hasattr(inst, "filename"):
1342 1343 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1343 1344 else:
1344 1345 u.warn("abort: %s\n" % inst.strerror)
1345 1346 except TypeError, inst:
1346 1347 # was this an argument error?
1347 1348 tb = traceback.extract_tb(sys.exc_info()[2])
1348 1349 if len(tb) > 2: # no
1349 1350 raise
1350 1351 u.debug(inst, "\n")
1351 1352 u.warn("%s: invalid arguments\n" % cmd)
1352 1353 help_(u, cmd)
1353 1354
1354 1355 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now