##// END OF EJS Templates
hg addremove: take optional files list...
mpm@selenic.com -
r353:dda243bb default
parent child Browse files
Show More
@@ -1,733 +1,746 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 import os, re, sys, signal
9 9 import fancyopts, ui, hg
10 10 from demandload import *
11 11 demandload(globals(), "mdiff time hgweb traceback random signal")
12 12
13 13 class UnknownCommand(Exception): pass
14 14
15 15 def filterfiles(filters, files):
16 16 l = [ x for x in files if x in filters ]
17 17
18 18 for t in filters:
19 19 if t and t[-1] != os.sep: t += os.sep
20 20 l += [ x for x in files if x.startswith(t) ]
21 21 return l
22 22
23 23 def relfilter(repo, files):
24 24 if os.getcwd() != repo.root:
25 25 p = os.getcwd()[len(repo.root) + 1: ]
26 26 return filterfiles([p], files)
27 27 return files
28 28
29 29 def relpath(repo, args):
30 30 if os.getcwd() != repo.root:
31 31 p = os.getcwd()[len(repo.root) + 1: ]
32 32 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
33 33 return args
34 34
35 35 def dodiff(repo, path, files = None, node1 = None, node2 = None):
36 36 def date(c):
37 37 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
38 38
39 39 if node2:
40 40 change = repo.changelog.read(node2)
41 41 mmap2 = repo.manifest.read(change[0])
42 42 (c, a, d) = repo.diffrevs(node1, node2)
43 43 def read(f): return repo.file(f).read(mmap2[f])
44 44 date2 = date(change)
45 45 else:
46 46 date2 = time.asctime()
47 47 (c, a, d, u) = repo.diffdir(path, node1)
48 48 if not node1:
49 49 node1 = repo.dirstate.parents()[0]
50 50 def read(f): return file(os.path.join(repo.root, f)).read()
51 51
52 52 change = repo.changelog.read(node1)
53 53 mmap = repo.manifest.read(change[0])
54 54 date1 = date(change)
55 55
56 56 if files:
57 57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
58 58
59 59 for f in c:
60 60 to = None
61 61 if f in mmap:
62 62 to = repo.file(f).read(mmap[f])
63 63 tn = read(f)
64 64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
65 65 for f in a:
66 66 to = None
67 67 tn = read(f)
68 68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
69 69 for f in d:
70 70 to = repo.file(f).read(mmap[f])
71 71 tn = None
72 72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
73 73
74 74 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
75 75 """show a single changeset or file revision"""
76 76 changelog = repo.changelog
77 77 if filelog:
78 78 log = filelog
79 79 filerev = rev
80 80 node = filenode = filelog.node(filerev)
81 81 changerev = filelog.linkrev(filenode)
82 82 changenode = changenode or changelog.node(changerev)
83 83 else:
84 84 log = changelog
85 85 changerev = rev
86 86 if changenode is None:
87 87 changenode = changelog.node(changerev)
88 88 elif not changerev:
89 89 rev = changerev = changelog.rev(changenode)
90 90 node = changenode
91 91
92 92 if ui.quiet:
93 93 ui.write("%d:%s\n" % (rev, hg.hex(node)))
94 94 return
95 95
96 96 changes = changelog.read(changenode)
97 97
98 98 parents = [(log.rev(parent), hg.hex(parent))
99 99 for parent in log.parents(node)
100 100 if ui.debugflag or parent != hg.nullid]
101 101 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
102 102 parents = []
103 103
104 104 if filelog:
105 105 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
106 106 for parent in parents:
107 107 ui.write("parent: %d:%s\n" % parent)
108 108 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
109 109 else:
110 110 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
111 111 for parent in parents:
112 112 ui.write("parent: %d:%s\n" % parent)
113 113 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
114 114 hg.hex(changes[0])))
115 115 ui.status("user: %s\n" % changes[1])
116 116 ui.status("date: %s\n" % time.asctime(
117 117 time.localtime(float(changes[2].split(' ')[0]))))
118 118 ui.note("files: %s\n" % " ".join(changes[3]))
119 119 description = changes[4].strip()
120 120 if description:
121 121 if ui.verbose:
122 122 ui.status("description:\n")
123 123 ui.status(description)
124 124 ui.status("\n\n")
125 125 else:
126 126 ui.status("summary: %s\n" % description.splitlines()[0])
127 127 ui.status("\n")
128 128
129 129 def help(ui, cmd=None):
130 130 '''show help for a given command or all commands'''
131 131 if cmd:
132 132 try:
133 133 i = find(cmd)
134 134 ui.write("%s\n\n" % i[2])
135 135
136 136 if i[1]:
137 137 for s, l, d, c in i[1]:
138 138 opt=' '
139 139 if s: opt = opt + '-' + s + ' '
140 140 if l: opt = opt + '--' + l + ' '
141 141 if d: opt = opt + '(' + str(d) + ')'
142 142 ui.write(opt, "\n")
143 143 if c: ui.write(' %s\n' % c)
144 144 ui.write("\n")
145 145
146 146 ui.write(i[0].__doc__, "\n")
147 147 except UnknownCommand:
148 148 ui.warn("hg: unknown command %s\n" % cmd)
149 149 sys.exit(0)
150 150 else:
151 151 ui.status('hg commands:\n\n')
152 152
153 153 h = {}
154 154 for e in table.values():
155 155 f = e[0]
156 156 if f.__name__.startswith("debug"): continue
157 157 d = ""
158 158 if f.__doc__:
159 159 d = f.__doc__.splitlines(0)[0].rstrip()
160 160 h[f.__name__] = d
161 161
162 162 fns = h.keys()
163 163 fns.sort()
164 164 m = max(map(len, fns))
165 165 for f in fns:
166 166 ui.status(' %-*s %s\n' % (m, f, h[f]))
167 167
168 168 # Commands start here, listed alphabetically
169 169
170 170 def add(ui, repo, file, *files):
171 171 '''add the specified files on the next commit'''
172 172 repo.add(relpath(repo, (file,) + files))
173 173
174 def addremove(ui, repo):
174 def addremove(ui, repo, *files):
175 175 """add all new files, delete all missing files"""
176 (c, a, d, u) = repo.diffdir(repo.root)
176 if files:
177 files = relpath(repo, files)
178 d = []
179 u = []
180 for f in files:
181 p = repo.wjoin(f)
182 s = repo.dirstate.state(f)
183 isfile = os.path.isfile(p)
184 if s != 'r' and not isfile:
185 d.append(f)
186 elif s not in 'nmai' and isfile:
187 u.append(f)
188 else:
189 (c, a, d, u) = repo.diffdir(repo.root)
177 190 repo.add(u)
178 191 repo.remove(d)
179 192
180 193 def annotate(u, repo, file, *files, **ops):
181 194 """show changeset information per file line"""
182 195 def getnode(rev):
183 196 return hg.short(repo.changelog.node(rev))
184 197
185 198 def getname(rev):
186 199 try:
187 200 return bcache[rev]
188 201 except KeyError:
189 202 cl = repo.changelog.read(repo.changelog.node(rev))
190 203 name = cl[1]
191 204 f = name.find('@')
192 205 if f >= 0:
193 206 name = name[:f]
194 207 bcache[rev] = name
195 208 return name
196 209
197 210 bcache = {}
198 211 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
199 212 if not ops['user'] and not ops['changeset']:
200 213 ops['number'] = 1
201 214
202 215 node = repo.dirstate.parents()[0]
203 216 if ops['revision']:
204 217 node = repo.changelog.lookup(ops['revision'])
205 218 change = repo.changelog.read(node)
206 219 mmap = repo.manifest.read(change[0])
207 220 maxuserlen = 0
208 221 maxchangelen = 0
209 222 for f in relpath(repo, (file,) + files):
210 223 lines = repo.file(f).annotate(mmap[f])
211 224 pieces = []
212 225
213 226 for o, f in opmap:
214 227 if ops[o]:
215 228 l = [ f(n) for n,t in lines ]
216 229 m = max(map(len, l))
217 230 pieces.append([ "%*s" % (m, x) for x in l])
218 231
219 232 for p,l in zip(zip(*pieces), lines):
220 233 u.write(" ".join(p) + ": " + l[1])
221 234
222 235 def cat(ui, repo, file, rev = []):
223 236 """output the latest or given revision of a file"""
224 237 r = repo.file(relpath(repo, [file])[0])
225 238 n = r.tip()
226 239 if rev: n = r.lookup(rev)
227 240 sys.stdout.write(r.read(n))
228 241
229 242 def commit(ui, repo, *files, **opts):
230 243 """commit the specified files or all outstanding changes"""
231 244 text = opts['text']
232 245 if not text and opts['logfile']:
233 246 try: text = open(opts['logfile']).read()
234 247 except IOError: pass
235 248
236 249 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
237 250
238 251 def debugaddchangegroup(ui, repo):
239 252 data = sys.stdin.read()
240 253 repo.addchangegroup(data)
241 254
242 255 def debugchangegroup(ui, repo, roots):
243 256 newer = repo.newer(map(repo.lookup, roots))
244 257 for chunk in repo.changegroup(newer):
245 258 sys.stdout.write(chunk)
246 259
247 260 def debugindex(ui, file):
248 261 r = hg.revlog(open, file, "")
249 262 print " rev offset length base linkrev"+\
250 263 " p1 p2 nodeid"
251 264 for i in range(r.count()):
252 265 e = r.index[i]
253 266 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
254 267 i, e[0], e[1], e[2], e[3],
255 268 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
256 269
257 270 def debugindexdot(ui, file):
258 271 r = hg.revlog(open, file, "")
259 272 print "digraph G {"
260 273 for i in range(r.count()):
261 274 e = r.index[i]
262 275 print "\t%d -> %d" % (r.rev(e[4]), i)
263 276 if e[5] != hg.nullid:
264 277 print "\t%d -> %d" % (r.rev(e[5]), i)
265 278 print "}"
266 279
267 280 def diff(ui, repo, *files, **opts):
268 281 """diff working directory (or selected files)"""
269 282 revs = []
270 283 if opts['rev']:
271 284 revs = map(lambda x: repo.lookup(x), opts['rev'])
272 285
273 286 if len(revs) > 2:
274 287 self.ui.warn("too many revisions to diff\n")
275 288 sys.exit(1)
276 289
277 290 if files:
278 291 files = relpath(repo, files)
279 292 else:
280 293 files = relpath(repo, [""])
281 294
282 295 dodiff(repo, os.getcwd(), files, *revs)
283 296
284 297 def export(ui, repo, changeset):
285 298 """dump the changeset header and diffs for a revision"""
286 299 node = repo.lookup(changeset)
287 300 prev, other = repo.changelog.parents(node)
288 301 change = repo.changelog.read(node)
289 302 print "# HG changeset patch"
290 303 print "# User %s" % change[1]
291 304 print "# Node ID %s" % hg.hex(node)
292 305 print "# Parent %s" % hg.hex(prev)
293 306 print
294 307 if other != hg.nullid:
295 308 print "# Parent %s" % hg.hex(other)
296 309 print change[4].rstrip()
297 310 print
298 311
299 312 dodiff(repo, "", None, prev, node)
300 313
301 314 def forget(ui, repo, file, *files):
302 315 """don't add the specified files on the next commit"""
303 316 repo.forget(relpath(repo, (file,) + files))
304 317
305 318 def heads(ui, repo):
306 319 """show current repository heads"""
307 320 for n in repo.changelog.heads():
308 321 show_changeset(ui, repo, changenode=n)
309 322
310 323 def history(ui, repo):
311 324 """show the changelog history"""
312 325 for i in range(repo.changelog.count() - 1, -1, -1):
313 326 show_changeset(ui, repo, rev=i)
314 327
315 328 def identify(ui, repo):
316 329 """print information about the working copy"""
317 330 (c, a, d, u) = repo.diffdir(repo.root)
318 331 mflag = (c or a or d or u) and "+" or ""
319 332 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
320 333 if not parents:
321 334 ui.write("unknown\n")
322 335 return
323 336
324 337 tstring = ''
325 338 if not ui.quiet:
326 339 tags = sum(map(repo.nodetags, parents), [])
327 340 tstring = " " + ' + '.join(tags)
328 341
329 342 hexfunc = ui.verbose and hg.hex or hg.short
330 343 pstring = '+'.join([hexfunc(parent) for parent in parents])
331 344 ui.write("%s%s%s\n" % (pstring, mflag, tstring))
332 345
333 346 def init(ui, source=None):
334 347 """create a new repository or copy an existing one"""
335 348
336 349 if source:
337 350 paths = {}
338 351 for name, path in ui.configitems("paths"):
339 352 paths[name] = path
340 353
341 354 if source in paths: source = paths[source]
342 355
343 356 link = 0
344 357 if not source.startswith("http://"):
345 358 d1 = os.stat(os.getcwd()).st_dev
346 359 d2 = os.stat(source).st_dev
347 360 if d1 == d2: link = 1
348 361
349 362 if link:
350 363 ui.debug("copying by hardlink\n")
351 364 os.system("cp -al %s/.hg .hg" % source)
352 365 try:
353 366 os.remove(".hg/dirstate")
354 367 except: pass
355 368
356 369 repo = hg.repository(ui, ".")
357 370
358 371 else:
359 372 repo = hg.repository(ui, ".", create=1)
360 373 other = hg.repository(ui, source)
361 374 cg = repo.getchangegroup(other)
362 375 repo.addchangegroup(cg)
363 376 else:
364 377 repo = hg.repository(ui, ".", create=1)
365 378
366 379 f = repo.opener("hgrc", "w")
367 380 f.write("[paths]\n")
368 381 f.write("default = %s\n" % source)
369 382
370 383 def log(ui, repo, f):
371 384 """show the revision history of a single file"""
372 385 f = relpath(repo, [f])[0]
373 386
374 387 r = repo.file(f)
375 388 for i in range(r.count() - 1, -1, -1):
376 389 show_changeset(ui, repo, filelog=r, rev=i)
377 390
378 391 def manifest(ui, repo, rev = []):
379 392 """output the latest or given revision of the project manifest"""
380 393 n = repo.manifest.tip()
381 394 if rev:
382 395 n = repo.manifest.lookup(rev)
383 396 m = repo.manifest.read(n)
384 397 mf = repo.manifest.readflags(n)
385 398 files = m.keys()
386 399 files.sort()
387 400
388 401 for f in files:
389 402 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
390 403
391 404 def parents(ui, repo, node = None):
392 405 '''show the parents of the current working dir'''
393 406 if node:
394 407 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
395 408 else:
396 409 p = repo.dirstate.parents()
397 410
398 411 for n in p:
399 412 if n != hg.nullid:
400 413 show_changeset(ui, repo, changenode=n)
401 414
402 415 def patch(ui, repo, patch1, *patches, **opts):
403 416 """import an ordered set of patches"""
404 417 try:
405 418 import psyco
406 419 psyco.full()
407 420 except:
408 421 pass
409 422
410 423 patches = (patch1,) + patches
411 424
412 425 d = opts["base"]
413 426 strip = opts["strip"]
414 427 quiet = opts["quiet"] and "> /dev/null" or ""
415 428
416 429 for patch in patches:
417 430 ui.status("applying %s\n" % patch)
418 431 pf = os.path.join(d, patch)
419 432
420 433 text = ""
421 434 for l in file(pf):
422 435 if l[:4] == "--- ": break
423 436 text += l
424 437
425 438 # make sure text isn't empty
426 439 if not text: text = "imported patch %s\n" % patch
427 440
428 441 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
429 442 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
430 443 f.close()
431 444
432 445 if files:
433 446 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
434 447 raise "patch failed!"
435 448 repo.commit(files, text)
436 449
437 450 def pull(ui, repo, source="default"):
438 451 """pull changes from the specified source"""
439 452 paths = {}
440 453 for name, path in ui.configitems("paths"):
441 454 paths[name] = path
442 455
443 456 if source in paths: source = paths[source]
444 457
445 458 other = hg.repository(ui, source)
446 459 cg = repo.getchangegroup(other)
447 460 repo.addchangegroup(cg)
448 461
449 462 def push(ui, repo, dest):
450 463 """push changes to the specified destination"""
451 464 paths = {}
452 465 for name, path in ui.configitems("paths"):
453 466 paths[name] = path
454 467
455 468 if dest in paths: dest = paths[dest]
456 469
457 470 if not dest.startswith("ssh://"):
458 471 ui.warn("abort: can only push to ssh:// destinations currently\n")
459 472 return 1
460 473
461 474 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
462 475 if not m:
463 476 ui.warn("abort: couldn't parse destination %s\n" % dest)
464 477 return 1
465 478
466 479 user, host, port, path = map(m.group, (2, 3, 5, 7))
467 480 host = user and ("%s@%s" % (user, host)) or host
468 481 port = port and (" -p %s") % port or ""
469 482 path = path or ""
470 483
471 484 sport = random.randrange(30000, 60000)
472 485 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
473 486 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
474 487
475 488 child = os.fork()
476 489 if not child:
477 490 sys.stdout = file("/dev/null", "w")
478 491 sys.stderr = sys.stdout
479 492 hgweb.server(repo.root, "pull", "", "localhost", sport)
480 493 else:
481 494 r = os.system(cmd)
482 495 os.kill(child, signal.SIGTERM)
483 496 return r
484 497
485 498 def rawcommit(ui, repo, flist, **rc):
486 499 "raw commit interface"
487 500
488 501 text = rc['text']
489 502 if not text and rc['logfile']:
490 503 try: text = open(rc['logfile']).read()
491 504 except IOError: pass
492 505 if not text and not rc['logfile']:
493 506 print "missing commit text"
494 507 return 1
495 508
496 509 files = relpath(repo, flist)
497 510 if rc['files']:
498 511 files += open(rc['files']).read().splitlines()
499 512
500 513 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
501 514
502 515 def recover(ui, repo):
503 516 """roll back an interrupted transaction"""
504 517 repo.recover()
505 518
506 519 def remove(ui, repo, file, *files):
507 520 """remove the specified files on the next commit"""
508 521 repo.remove(relpath(repo, (file,) + files))
509 522
510 523 def serve(ui, repo, **opts):
511 524 """export the repository via HTTP"""
512 525 hgweb.server(repo.root, opts["name"], opts["templates"],
513 526 opts["address"], opts["port"])
514 527
515 528 def status(ui, repo):
516 529 '''show changed files in the working directory
517 530
518 531 C = changed
519 532 A = added
520 533 R = removed
521 534 ? = not tracked'''
522 535
523 536 (c, a, d, u) = repo.diffdir(os.getcwd())
524 537 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
525 538
526 539 for f in c: print "C", f
527 540 for f in a: print "A", f
528 541 for f in d: print "R", f
529 542 for f in u: print "?", f
530 543
531 544 def tags(ui, repo):
532 545 """list repository tags"""
533 546
534 547 l = repo.tagslist()
535 548 l.reverse()
536 549 for t,n in l:
537 550 try:
538 551 r = repo.changelog.rev(n)
539 552 except KeyError:
540 553 r = "?"
541 554 print "%-30s %5d:%s" % (t, repo.changelog.rev(n), hg.hex(n))
542 555
543 556 def tip(ui, repo):
544 557 """show the tip revision"""
545 558 n = repo.changelog.tip()
546 559 show_changeset(ui, repo, changenode=n)
547 560
548 561 def undo(ui, repo):
549 562 """undo the last transaction"""
550 563 repo.undo()
551 564
552 565 def update(ui, repo, node=None, merge=False, clean=False):
553 566 '''update or merge working directory
554 567
555 568 If there are no outstanding changes in the working directory and
556 569 there is a linear relationship between the current version and the
557 570 requested version, the result is the requested version.
558 571
559 572 Otherwise the result is a merge between the contents of the
560 573 current working directory and the requested version. Files that
561 574 changed between either parent are marked as changed for the next
562 575 commit and a commit must be performed before any further updates
563 576 are allowed.
564 577 '''
565 578 node = node and repo.lookup(node) or repo.changelog.tip()
566 579 return repo.update(node, allow=merge, force=clean)
567 580
568 581 def verify(ui, repo):
569 582 """verify the integrity of the repository"""
570 583 return repo.verify()
571 584
572 585 # Command options and aliases are listed here, alphabetically
573 586
574 587 table = {
575 588 "add": (add, [], "hg add [files]"),
576 "addremove": (addremove, [], "hg addremove"),
589 "addremove": (addremove, [], "hg addremove [files]"),
577 590 "ann|annotate": (annotate,
578 591 [('r', 'revision', '', 'revision'),
579 592 ('u', 'user', None, 'show user'),
580 593 ('n', 'number', None, 'show revision number'),
581 594 ('c', 'changeset', None, 'show changeset')],
582 595 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
583 596 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
584 597 "commit|ci": (commit,
585 598 [('t', 'text', "", 'commit text'),
586 599 ('l', 'logfile', "", 'commit text file'),
587 600 ('d', 'date', "", 'data'),
588 601 ('u', 'user', "", 'user')],
589 602 'hg commit [files]'),
590 603 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
591 604 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
592 605 "debugindex": (debugindex, [], 'debugindex <file>'),
593 606 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
594 607 "diff": (diff, [('r', 'rev', [], 'revision')],
595 608 'hg diff [-r A] [-r B] [files]'),
596 609 "export": (export, [], "hg export <changeset>"),
597 610 "forget": (forget, [], "hg forget [files]"),
598 611 "heads": (heads, [], 'hg heads'),
599 612 "history": (history, [], 'hg history'),
600 613 "help": (help, [], 'hg help [command]'),
601 614 "identify|id": (identify, [], 'hg identify'),
602 615 "init": (init, [], 'hg init [url]'),
603 616 "log": (log, [], 'hg log <file>'),
604 617 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
605 618 "parents": (parents, [], 'hg parents [node]'),
606 619 "patch|import": (patch,
607 620 [('p', 'strip', 1, 'path strip'),
608 621 ('b', 'base', "", 'base path'),
609 622 ('q', 'quiet', "", 'silence diff')],
610 623 "hg import [options] patches"),
611 624 "pull|merge": (pull, [], 'hg pull [source]'),
612 625 "push": (push, [], 'hg push <destination>'),
613 626 "rawcommit": (rawcommit,
614 627 [('p', 'parent', [], 'parent'),
615 628 ('d', 'date', "", 'data'),
616 629 ('u', 'user', "", 'user'),
617 630 ('F', 'files', "", 'file list'),
618 631 ('t', 'text', "", 'commit text'),
619 632 ('l', 'logfile', "", 'commit text file')],
620 633 'hg rawcommit [options] [files]'),
621 634 "recover": (recover, [], "hg recover"),
622 635 "remove": (remove, [], "hg remove [files]"),
623 636 "serve": (serve, [('p', 'port', 8000, 'listen port'),
624 637 ('a', 'address', '', 'interface address'),
625 638 ('n', 'name', os.getcwd(), 'repository name'),
626 639 ('t', 'templates', "", 'template map')],
627 640 "hg serve [options]"),
628 641 "status": (status, [], 'hg status'),
629 642 "tags": (tags, [], 'hg tags'),
630 643 "tip": (tip, [], 'hg tip'),
631 644 "undo": (undo, [], 'hg undo'),
632 645 "update|up|checkout|co|resolve": (update,
633 646 [('m', 'merge', None,
634 647 'allow merging of conflicts'),
635 648 ('C', 'clean', None,
636 649 'overwrite locally modified files')],
637 650 'hg update [options] [node]'),
638 651 "verify": (verify, [], 'hg verify'),
639 652 }
640 653
641 654 norepo = "init branch help debugindex debugindexdot"
642 655
643 656 def find(cmd):
644 657 i = None
645 658 for e in table.keys():
646 659 if re.match("(%s)$" % e, cmd):
647 660 return table[e]
648 661
649 662 raise UnknownCommand(cmd)
650 663
651 664 class SignalInterrupt(Exception): pass
652 665
653 666 def catchterm(*args):
654 667 raise SignalInterrupt
655 668
656 669 def run():
657 670 sys.exit(dispatch(sys.argv[1:]))
658 671
659 672 def dispatch(args):
660 673 options = {}
661 674 opts = [('v', 'verbose', None, 'verbose'),
662 675 ('d', 'debug', None, 'debug'),
663 676 ('q', 'quiet', None, 'quiet'),
664 677 ('p', 'profile', None, 'profile'),
665 678 ('y', 'noninteractive', None, 'run non-interactively'),
666 679 ]
667 680
668 681 args = fancyopts.fancyopts(args, opts, options,
669 682 'hg [options] <command> [options] [files]')
670 683
671 684 if not args:
672 685 cmd = "help"
673 686 else:
674 687 cmd, args = args[0], args[1:]
675 688
676 689 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
677 690 not options["noninteractive"])
678 691
679 692 try:
680 693 i = find(cmd)
681 694 except UnknownCommand:
682 695 u.warn("hg: unknown command '%s'\n" % cmd)
683 696 help(u)
684 697 sys.exit(1)
685 698
686 699 signal.signal(signal.SIGTERM, catchterm)
687 700
688 701 cmdoptions = {}
689 702 try:
690 703 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
691 704 except fancyopts.getopt.GetoptError, inst:
692 705 u.warn("hg %s: %s\n" % (cmd, inst))
693 706 help(u, cmd)
694 707 sys.exit(-1)
695 708
696 709 if cmd not in norepo.split():
697 710 repo = hg.repository(ui = u)
698 711 d = lambda: i[0](u, repo, *args, **cmdoptions)
699 712 else:
700 713 d = lambda: i[0](u, *args, **cmdoptions)
701 714
702 715 try:
703 716 if options['profile']:
704 717 import hotshot, hotshot.stats
705 718 prof = hotshot.Profile("hg.prof")
706 719 r = prof.runcall(d)
707 720 prof.close()
708 721 stats = hotshot.stats.load("hg.prof")
709 722 stats.strip_dirs()
710 723 stats.sort_stats('time', 'calls')
711 724 stats.print_stats(40)
712 725 return r
713 726 else:
714 727 return d()
715 728 except SignalInterrupt:
716 729 u.warn("killed!\n")
717 730 except KeyboardInterrupt:
718 731 u.warn("interrupted!\n")
719 732 except IOError, inst:
720 733 if inst.errno == 32:
721 734 u.warn("broken pipe\n")
722 735 else:
723 736 raise
724 737 except TypeError, inst:
725 738 # was this an argument error?
726 739 tb = traceback.extract_tb(sys.exc_info()[2])
727 740 if len(tb) > 2: # no
728 741 raise
729 742 u.debug(inst, "\n")
730 743 u.warn("%s: invalid arguments\n" % i[0].__name__)
731 744 help(u, cmd)
732 745 sys.exit(-1)
733 746
General Comments 0
You need to be logged in to leave comments. Login now