##// END OF EJS Templates
Make log --follow without a file list follow a single head....
Brendan Cully -
r2782:21e571c2 default
parent child Browse files
Show More
@@ -1,3617 +1,3659 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 from node import *
10 10 from i18n import gettext as _
11 11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 13 demandload(globals(), "fnmatch mdiff random signal tempfile time")
14 14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 15 demandload(globals(), "archival cStringIO changegroup email.Parser")
16 16 demandload(globals(), "hgweb.server sshserver")
17 17
18 18 class UnknownCommand(Exception):
19 19 """Exception raised if command is not in the command table."""
20 20 class AmbiguousCommand(Exception):
21 21 """Exception raised if command shortcut matches more than one command."""
22 22
23 23 def bail_if_changed(repo):
24 24 modified, added, removed, deleted, unknown = repo.changes()
25 25 if modified or added or removed or deleted:
26 26 raise util.Abort(_("outstanding uncommitted changes"))
27 27
28 28 def filterfiles(filters, files):
29 29 l = [x for x in files if x in filters]
30 30
31 31 for t in filters:
32 32 if t and t[-1] != "/":
33 33 t += "/"
34 34 l += [x for x in files if x.startswith(t)]
35 35 return l
36 36
37 37 def relpath(repo, args):
38 38 cwd = repo.getcwd()
39 39 if cwd:
40 40 return [util.normpath(os.path.join(cwd, x)) for x in args]
41 41 return args
42 42
43 43 def logmessage(**opts):
44 44 """ get the log message according to -m and -l option """
45 45 message = opts['message']
46 46 logfile = opts['logfile']
47 47
48 48 if message and logfile:
49 49 raise util.Abort(_('options --message and --logfile are mutually '
50 50 'exclusive'))
51 51 if not message and logfile:
52 52 try:
53 53 if logfile == '-':
54 54 message = sys.stdin.read()
55 55 else:
56 56 message = open(logfile).read()
57 57 except IOError, inst:
58 58 raise util.Abort(_("can't read commit message '%s': %s") %
59 59 (logfile, inst.strerror))
60 60 return message
61 61
62 62 def matchpats(repo, pats=[], opts={}, head=''):
63 63 cwd = repo.getcwd()
64 64 if not pats and cwd:
65 65 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
66 66 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
67 67 cwd = ''
68 68 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
69 69 opts.get('exclude'), head)
70 70
71 71 def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
72 72 files, matchfn, anypats = matchpats(repo, pats, opts, head)
73 73 exact = dict(zip(files, files))
74 74 def walk():
75 75 for src, fn in repo.walk(node=node, files=files, match=matchfn,
76 76 badmatch=badmatch):
77 77 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
78 78 return files, matchfn, walk()
79 79
80 80 def walk(repo, pats, opts, node=None, head='', badmatch=None):
81 81 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
82 82 for r in results:
83 83 yield r
84 84
85 85 def walkchangerevs(ui, repo, pats, opts):
86 86 '''Iterate over files and the revs they changed in.
87 87
88 88 Callers most commonly need to iterate backwards over the history
89 89 it is interested in. Doing so has awful (quadratic-looking)
90 90 performance, so we use iterators in a "windowed" way.
91 91
92 92 We walk a window of revisions in the desired order. Within the
93 93 window, we first walk forwards to gather data, then in the desired
94 94 order (usually backwards) to display it.
95 95
96 96 This function returns an (iterator, getchange, matchfn) tuple. The
97 97 getchange function returns the changelog entry for a numeric
98 98 revision. The iterator yields 3-tuples. They will be of one of
99 99 the following forms:
100 100
101 101 "window", incrementing, lastrev: stepping through a window,
102 102 positive if walking forwards through revs, last rev in the
103 103 sequence iterated over - use to reset state for the current window
104 104
105 105 "add", rev, fns: out-of-order traversal of the given file names
106 106 fns, which changed during revision rev - use to gather data for
107 107 possible display
108 108
109 109 "iter", rev, None: in-order traversal of the revs earlier iterated
110 110 over with "add" - use to display data'''
111 111
112 112 def increasing_windows(start, end, windowsize=8, sizelimit=512):
113 113 if start < end:
114 114 while start < end:
115 115 yield start, min(windowsize, end-start)
116 116 start += windowsize
117 117 if windowsize < sizelimit:
118 118 windowsize *= 2
119 119 else:
120 120 while start > end:
121 121 yield start, min(windowsize, start-end-1)
122 122 start -= windowsize
123 123 if windowsize < sizelimit:
124 124 windowsize *= 2
125 125
126 126
127 127 files, matchfn, anypats = matchpats(repo, pats, opts)
128 128 follow = opts.get('follow')
129 129
130 130 if repo.changelog.count() == 0:
131 131 return [], False, matchfn
132 132
133 133 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
134 134 wanted = {}
135 135 slowpath = anypats
136 136 fncache = {}
137 137
138 138 chcache = {}
139 139 def getchange(rev):
140 140 ch = chcache.get(rev)
141 141 if ch is None:
142 142 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
143 143 return ch
144 144
145 145 if not slowpath and not files:
146 146 # No files, no patterns. Display all revs.
147 147 wanted = dict(zip(revs, revs))
148 148 copies = []
149 149 if not slowpath:
150 150 # Only files, no patterns. Check the history of each file.
151 151 def filerevgen(filelog, node):
152 152 cl_count = repo.changelog.count()
153 153 if node is None:
154 154 last = filelog.count() - 1
155 155 else:
156 156 last = filelog.rev(node)
157 157 for i, window in increasing_windows(last, -1):
158 158 revs = []
159 159 for j in xrange(i - window, i + 1):
160 160 n = filelog.node(j)
161 161 revs.append((filelog.linkrev(n),
162 162 follow and filelog.renamed(n)))
163 163 revs.reverse()
164 164 for rev in revs:
165 165 # only yield rev for which we have the changelog, it can
166 166 # happen while doing "hg log" during a pull or commit
167 167 if rev[0] < cl_count:
168 168 yield rev
169 169 def iterfiles():
170 170 for filename in files:
171 171 yield filename, None
172 172 for filename_node in copies:
173 173 yield filename_node
174 174 minrev, maxrev = min(revs), max(revs)
175 175 for file_, node in iterfiles():
176 176 filelog = repo.file(file_)
177 177 # A zero count may be a directory or deleted file, so
178 178 # try to find matching entries on the slow path.
179 179 if filelog.count() == 0:
180 180 slowpath = True
181 181 break
182 182 for rev, copied in filerevgen(filelog, node):
183 183 if rev <= maxrev:
184 184 if rev < minrev:
185 185 break
186 186 fncache.setdefault(rev, [])
187 187 fncache[rev].append(file_)
188 188 wanted[rev] = 1
189 189 if follow and copied:
190 190 copies.append(copied)
191 191 if slowpath:
192 192 if follow:
193 193 raise util.Abort(_('can only follow copies/renames for explicit '
194 194 'file names'))
195 195
196 196 # The slow path checks files modified in every changeset.
197 197 def changerevgen():
198 198 for i, window in increasing_windows(repo.changelog.count()-1, -1):
199 199 for j in xrange(i - window, i + 1):
200 200 yield j, getchange(j)[3]
201 201
202 202 for rev, changefiles in changerevgen():
203 203 matches = filter(matchfn, changefiles)
204 204 if matches:
205 205 fncache[rev] = matches
206 206 wanted[rev] = 1
207 207
208 208 def iterate():
209 class followfilter:
210 def __init__(self):
211 self.startrev = -1
212 self.roots = []
213
214 def match(self, rev):
215 def realparents(rev):
216 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
217
218 if self.startrev == -1:
219 self.startrev = rev
220 return True
221
222 if rev > self.startrev:
223 # forward: all descendants
224 if not self.roots:
225 self.roots.append(self.startrev)
226 for parent in realparents(rev):
227 if parent in self.roots:
228 self.roots.append(rev)
229 return True
230 else:
231 # backwards: all parents
232 if not self.roots:
233 self.roots.extend(realparents(self.startrev))
234 if rev in self.roots:
235 self.roots.remove(rev)
236 self.roots.extend(realparents(rev))
237 return True
238
239 return False
240
241 if follow and not files:
242 ff = followfilter()
243 def want(rev):
244 if rev not in wanted:
245 return False
246 return ff.match(rev)
247 else:
248 def want(rev):
249 return rev in wanted
250
209 251 for i, window in increasing_windows(0, len(revs)):
210 252 yield 'window', revs[0] < revs[-1], revs[-1]
211 nrevs = [rev for rev in revs[i:i+window]
212 if rev in wanted]
253 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
213 254 srevs = list(nrevs)
214 255 srevs.sort()
215 256 for rev in srevs:
216 257 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
217 258 yield 'add', rev, fns
218 259 for rev in nrevs:
219 260 yield 'iter', rev, None
220 261 return iterate(), getchange, matchfn
221 262
222 263 revrangesep = ':'
223 264
224 265 def revfix(repo, val, defval):
225 266 '''turn user-level id of changeset into rev number.
226 267 user-level id can be tag, changeset, rev number, or negative rev
227 268 number relative to number of revs (-1 is tip, etc).'''
228 269 if not val:
229 270 return defval
230 271 try:
231 272 num = int(val)
232 273 if str(num) != val:
233 274 raise ValueError
234 275 if num < 0:
235 276 num += repo.changelog.count()
236 277 if num < 0:
237 278 num = 0
238 279 elif num >= repo.changelog.count():
239 280 raise ValueError
240 281 except ValueError:
241 282 try:
242 283 num = repo.changelog.rev(repo.lookup(val))
243 284 except KeyError:
244 285 raise util.Abort(_('invalid revision identifier %s'), val)
245 286 return num
246 287
247 288 def revpair(ui, repo, revs):
248 289 '''return pair of nodes, given list of revisions. second item can
249 290 be None, meaning use working dir.'''
250 291 if not revs:
251 292 return repo.dirstate.parents()[0], None
252 293 end = None
253 294 if len(revs) == 1:
254 295 start = revs[0]
255 296 if revrangesep in start:
256 297 start, end = start.split(revrangesep, 1)
257 298 start = revfix(repo, start, 0)
258 299 end = revfix(repo, end, repo.changelog.count() - 1)
259 300 else:
260 301 start = revfix(repo, start, None)
261 302 elif len(revs) == 2:
262 303 if revrangesep in revs[0] or revrangesep in revs[1]:
263 304 raise util.Abort(_('too many revisions specified'))
264 305 start = revfix(repo, revs[0], None)
265 306 end = revfix(repo, revs[1], None)
266 307 else:
267 308 raise util.Abort(_('too many revisions specified'))
268 309 if end is not None: end = repo.lookup(str(end))
269 310 return repo.lookup(str(start)), end
270 311
271 312 def revrange(ui, repo, revs):
272 313 """Yield revision as strings from a list of revision specifications."""
273 314 seen = {}
274 315 for spec in revs:
275 316 if revrangesep in spec:
276 317 start, end = spec.split(revrangesep, 1)
277 318 start = revfix(repo, start, 0)
278 319 end = revfix(repo, end, repo.changelog.count() - 1)
279 320 step = start > end and -1 or 1
280 321 for rev in xrange(start, end+step, step):
281 322 if rev in seen:
282 323 continue
283 324 seen[rev] = 1
284 325 yield str(rev)
285 326 else:
286 327 rev = revfix(repo, spec, None)
287 328 if rev in seen:
288 329 continue
289 330 seen[rev] = 1
290 331 yield str(rev)
291 332
292 333 def make_filename(repo, pat, node,
293 334 total=None, seqno=None, revwidth=None, pathname=None):
294 335 node_expander = {
295 336 'H': lambda: hex(node),
296 337 'R': lambda: str(repo.changelog.rev(node)),
297 338 'h': lambda: short(node),
298 339 }
299 340 expander = {
300 341 '%': lambda: '%',
301 342 'b': lambda: os.path.basename(repo.root),
302 343 }
303 344
304 345 try:
305 346 if node:
306 347 expander.update(node_expander)
307 348 if node and revwidth is not None:
308 349 expander['r'] = (lambda:
309 350 str(repo.changelog.rev(node)).zfill(revwidth))
310 351 if total is not None:
311 352 expander['N'] = lambda: str(total)
312 353 if seqno is not None:
313 354 expander['n'] = lambda: str(seqno)
314 355 if total is not None and seqno is not None:
315 356 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
316 357 if pathname is not None:
317 358 expander['s'] = lambda: os.path.basename(pathname)
318 359 expander['d'] = lambda: os.path.dirname(pathname) or '.'
319 360 expander['p'] = lambda: pathname
320 361
321 362 newname = []
322 363 patlen = len(pat)
323 364 i = 0
324 365 while i < patlen:
325 366 c = pat[i]
326 367 if c == '%':
327 368 i += 1
328 369 c = pat[i]
329 370 c = expander[c]()
330 371 newname.append(c)
331 372 i += 1
332 373 return ''.join(newname)
333 374 except KeyError, inst:
334 375 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
335 376 inst.args[0])
336 377
337 378 def make_file(repo, pat, node=None,
338 379 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
339 380 if not pat or pat == '-':
340 381 return 'w' in mode and sys.stdout or sys.stdin
341 382 if hasattr(pat, 'write') and 'w' in mode:
342 383 return pat
343 384 if hasattr(pat, 'read') and 'r' in mode:
344 385 return pat
345 386 return open(make_filename(repo, pat, node, total, seqno, revwidth,
346 387 pathname),
347 388 mode)
348 389
349 390 def write_bundle(cg, filename=None, compress=True):
350 391 """Write a bundle file and return its filename.
351 392
352 393 Existing files will not be overwritten.
353 394 If no filename is specified, a temporary file is created.
354 395 bz2 compression can be turned off.
355 396 The bundle file will be deleted in case of errors.
356 397 """
357 398 class nocompress(object):
358 399 def compress(self, x):
359 400 return x
360 401 def flush(self):
361 402 return ""
362 403
363 404 fh = None
364 405 cleanup = None
365 406 try:
366 407 if filename:
367 408 if os.path.exists(filename):
368 409 raise util.Abort(_("file '%s' already exists"), filename)
369 410 fh = open(filename, "wb")
370 411 else:
371 412 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
372 413 fh = os.fdopen(fd, "wb")
373 414 cleanup = filename
374 415
375 416 if compress:
376 417 fh.write("HG10")
377 418 z = bz2.BZ2Compressor(9)
378 419 else:
379 420 fh.write("HG10UN")
380 421 z = nocompress()
381 422 # parse the changegroup data, otherwise we will block
382 423 # in case of sshrepo because we don't know the end of the stream
383 424
384 425 # an empty chunkiter is the end of the changegroup
385 426 empty = False
386 427 while not empty:
387 428 empty = True
388 429 for chunk in changegroup.chunkiter(cg):
389 430 empty = False
390 431 fh.write(z.compress(changegroup.genchunk(chunk)))
391 432 fh.write(z.compress(changegroup.closechunk()))
392 433 fh.write(z.flush())
393 434 cleanup = None
394 435 return filename
395 436 finally:
396 437 if fh is not None:
397 438 fh.close()
398 439 if cleanup is not None:
399 440 os.unlink(cleanup)
400 441
401 442 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
402 443 changes=None, text=False, opts={}):
403 444 if not node1:
404 445 node1 = repo.dirstate.parents()[0]
405 446 # reading the data for node1 early allows it to play nicely
406 447 # with repo.changes and the revlog cache.
407 448 change = repo.changelog.read(node1)
408 449 mmap = repo.manifest.read(change[0])
409 450 date1 = util.datestr(change[2])
410 451
411 452 if not changes:
412 453 changes = repo.changes(node1, node2, files, match=match)
413 454 modified, added, removed, deleted, unknown = changes
414 455 if files:
415 456 modified, added, removed = map(lambda x: filterfiles(files, x),
416 457 (modified, added, removed))
417 458
418 459 if not modified and not added and not removed:
419 460 return
420 461
421 462 if node2:
422 463 change = repo.changelog.read(node2)
423 464 mmap2 = repo.manifest.read(change[0])
424 465 _date2 = util.datestr(change[2])
425 466 def date2(f):
426 467 return _date2
427 468 def read(f):
428 469 return repo.file(f).read(mmap2[f])
429 470 else:
430 471 tz = util.makedate()[1]
431 472 _date2 = util.datestr()
432 473 def date2(f):
433 474 try:
434 475 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
435 476 except OSError, err:
436 477 if err.errno != errno.ENOENT: raise
437 478 return _date2
438 479 def read(f):
439 480 return repo.wread(f)
440 481
441 482 if ui.quiet:
442 483 r = None
443 484 else:
444 485 hexfunc = ui.verbose and hex or short
445 486 r = [hexfunc(node) for node in [node1, node2] if node]
446 487
447 488 diffopts = ui.diffopts()
448 489 showfunc = opts.get('show_function') or diffopts['showfunc']
449 490 ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
450 491 ignorewsamount = opts.get('ignore_space_change') or \
451 492 diffopts['ignorewsamount']
452 493 ignoreblanklines = opts.get('ignore_blank_lines') or \
453 494 diffopts['ignoreblanklines']
454 495
455 496 all = modified + added + removed
456 497 all.sort()
457 498 for f in all:
458 499 to = None
459 500 tn = None
460 501 if f in mmap:
461 502 to = repo.file(f).read(mmap[f])
462 503 if f not in removed:
463 504 tn = read(f)
464 505 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
465 506 showfunc=showfunc, ignorews=ignorews,
466 507 ignorewsamount=ignorewsamount,
467 508 ignoreblanklines=ignoreblanklines))
468 509
469 510 def trimuser(ui, name, rev, revcache):
470 511 """trim the name of the user who committed a change"""
471 512 user = revcache.get(rev)
472 513 if user is None:
473 514 user = revcache[rev] = ui.shortuser(name)
474 515 return user
475 516
476 517 class changeset_printer(object):
477 518 '''show changeset information when templating not requested.'''
478 519
479 520 def __init__(self, ui, repo):
480 521 self.ui = ui
481 522 self.repo = repo
482 523
483 524 def show(self, rev=0, changenode=None, brinfo=None):
484 525 '''show a single changeset or file revision'''
485 526 log = self.repo.changelog
486 527 if changenode is None:
487 528 changenode = log.node(rev)
488 529 elif not rev:
489 530 rev = log.rev(changenode)
490 531
491 532 if self.ui.quiet:
492 533 self.ui.write("%d:%s\n" % (rev, short(changenode)))
493 534 return
494 535
495 536 changes = log.read(changenode)
496 537 date = util.datestr(changes[2])
497 538
498 539 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
499 540 for p in log.parents(changenode)
500 541 if self.ui.debugflag or p != nullid]
501 542 if (not self.ui.debugflag and len(parents) == 1 and
502 543 parents[0][0] == rev-1):
503 544 parents = []
504 545
505 546 if self.ui.verbose:
506 547 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
507 548 else:
508 549 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
509 550
510 551 for tag in self.repo.nodetags(changenode):
511 552 self.ui.status(_("tag: %s\n") % tag)
512 553 for parent in parents:
513 554 self.ui.write(_("parent: %d:%s\n") % parent)
514 555
515 556 if brinfo and changenode in brinfo:
516 557 br = brinfo[changenode]
517 558 self.ui.write(_("branch: %s\n") % " ".join(br))
518 559
519 560 self.ui.debug(_("manifest: %d:%s\n") %
520 561 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
521 562 self.ui.status(_("user: %s\n") % changes[1])
522 563 self.ui.status(_("date: %s\n") % date)
523 564
524 565 if self.ui.debugflag:
525 566 files = self.repo.changes(log.parents(changenode)[0], changenode)
526 567 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
527 568 files):
528 569 if value:
529 570 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
530 571 else:
531 572 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
532 573
533 574 description = changes[4].strip()
534 575 if description:
535 576 if self.ui.verbose:
536 577 self.ui.status(_("description:\n"))
537 578 self.ui.status(description)
538 579 self.ui.status("\n\n")
539 580 else:
540 581 self.ui.status(_("summary: %s\n") %
541 582 description.splitlines()[0])
542 583 self.ui.status("\n")
543 584
544 585 def show_changeset(ui, repo, opts):
545 586 '''show one changeset. uses template or regular display. caller
546 587 can pass in 'style' and 'template' options in opts.'''
547 588
548 589 tmpl = opts.get('template')
549 590 if tmpl:
550 591 tmpl = templater.parsestring(tmpl, quoted=False)
551 592 else:
552 593 tmpl = ui.config('ui', 'logtemplate')
553 594 if tmpl: tmpl = templater.parsestring(tmpl)
554 595 mapfile = opts.get('style') or ui.config('ui', 'style')
555 596 if tmpl or mapfile:
556 597 if mapfile:
557 598 if not os.path.isfile(mapfile):
558 599 mapname = templater.templatepath('map-cmdline.' + mapfile)
559 600 if not mapname: mapname = templater.templatepath(mapfile)
560 601 if mapname: mapfile = mapname
561 602 try:
562 603 t = templater.changeset_templater(ui, repo, mapfile)
563 604 except SyntaxError, inst:
564 605 raise util.Abort(inst.args[0])
565 606 if tmpl: t.use_template(tmpl)
566 607 return t
567 608 return changeset_printer(ui, repo)
568 609
569 610 def setremoteconfig(ui, opts):
570 611 "copy remote options to ui tree"
571 612 if opts.get('ssh'):
572 613 ui.setconfig("ui", "ssh", opts['ssh'])
573 614 if opts.get('remotecmd'):
574 615 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
575 616
576 617 def show_version(ui):
577 618 """output version and copyright information"""
578 619 ui.write(_("Mercurial Distributed SCM (version %s)\n")
579 620 % version.get_version())
580 621 ui.status(_(
581 622 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
582 623 "This is free software; see the source for copying conditions. "
583 624 "There is NO\nwarranty; "
584 625 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
585 626 ))
586 627
587 628 def help_(ui, name=None, with_version=False):
588 629 """show help for a command, extension, or list of commands
589 630
590 631 With no arguments, print a list of commands and short help.
591 632
592 633 Given a command name, print help for that command.
593 634
594 635 Given an extension name, print help for that extension, and the
595 636 commands it provides."""
596 637 option_lists = []
597 638
598 639 def helpcmd(name):
599 640 if with_version:
600 641 show_version(ui)
601 642 ui.write('\n')
602 643 aliases, i = findcmd(name)
603 644 # synopsis
604 645 ui.write("%s\n\n" % i[2])
605 646
606 647 # description
607 648 doc = i[0].__doc__
608 649 if not doc:
609 650 doc = _("(No help text available)")
610 651 if ui.quiet:
611 652 doc = doc.splitlines(0)[0]
612 653 ui.write("%s\n" % doc.rstrip())
613 654
614 655 if not ui.quiet:
615 656 # aliases
616 657 if len(aliases) > 1:
617 658 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
618 659
619 660 # options
620 661 if i[1]:
621 662 option_lists.append(("options", i[1]))
622 663
623 664 def helplist(select=None):
624 665 h = {}
625 666 cmds = {}
626 667 for c, e in table.items():
627 668 f = c.split("|", 1)[0]
628 669 if select and not select(f):
629 670 continue
630 671 if name == "shortlist" and not f.startswith("^"):
631 672 continue
632 673 f = f.lstrip("^")
633 674 if not ui.debugflag and f.startswith("debug"):
634 675 continue
635 676 doc = e[0].__doc__
636 677 if not doc:
637 678 doc = _("(No help text available)")
638 679 h[f] = doc.splitlines(0)[0].rstrip()
639 680 cmds[f] = c.lstrip("^")
640 681
641 682 fns = h.keys()
642 683 fns.sort()
643 684 m = max(map(len, fns))
644 685 for f in fns:
645 686 if ui.verbose:
646 687 commands = cmds[f].replace("|",", ")
647 688 ui.write(" %s:\n %s\n"%(commands, h[f]))
648 689 else:
649 690 ui.write(' %-*s %s\n' % (m, f, h[f]))
650 691
651 692 def helpext(name):
652 693 try:
653 694 mod = findext(name)
654 695 except KeyError:
655 696 raise UnknownCommand(name)
656 697
657 698 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
658 699 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
659 700 for d in doc[1:]:
660 701 ui.write(d, '\n')
661 702
662 703 ui.status('\n')
663 704 if ui.verbose:
664 705 ui.status(_('list of commands:\n\n'))
665 706 else:
666 707 ui.status(_('list of commands (use "hg help -v %s" '
667 708 'to show aliases and global options):\n\n') % name)
668 709
669 710 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
670 711 helplist(modcmds.has_key)
671 712
672 713 if name and name != 'shortlist':
673 714 try:
674 715 helpcmd(name)
675 716 except UnknownCommand:
676 717 helpext(name)
677 718
678 719 else:
679 720 # program name
680 721 if ui.verbose or with_version:
681 722 show_version(ui)
682 723 else:
683 724 ui.status(_("Mercurial Distributed SCM\n"))
684 725 ui.status('\n')
685 726
686 727 # list of commands
687 728 if name == "shortlist":
688 729 ui.status(_('basic commands (use "hg help" '
689 730 'for the full list or option "-v" for details):\n\n'))
690 731 elif ui.verbose:
691 732 ui.status(_('list of commands:\n\n'))
692 733 else:
693 734 ui.status(_('list of commands (use "hg help -v" '
694 735 'to show aliases and global options):\n\n'))
695 736
696 737 helplist()
697 738
698 739 # global options
699 740 if ui.verbose:
700 741 option_lists.append(("global options", globalopts))
701 742
702 743 # list all option lists
703 744 opt_output = []
704 745 for title, options in option_lists:
705 746 opt_output.append(("\n%s:\n" % title, None))
706 747 for shortopt, longopt, default, desc in options:
707 748 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
708 749 longopt and " --%s" % longopt),
709 750 "%s%s" % (desc,
710 751 default
711 752 and _(" (default: %s)") % default
712 753 or "")))
713 754
714 755 if opt_output:
715 756 opts_len = max([len(line[0]) for line in opt_output if line[1]])
716 757 for first, second in opt_output:
717 758 if second:
718 759 ui.write(" %-*s %s\n" % (opts_len, first, second))
719 760 else:
720 761 ui.write("%s\n" % first)
721 762
722 763 # Commands start here, listed alphabetically
723 764
724 765 def add(ui, repo, *pats, **opts):
725 766 """add the specified files on the next commit
726 767
727 768 Schedule files to be version controlled and added to the repository.
728 769
729 770 The files will be added to the repository at the next commit.
730 771
731 772 If no names are given, add all files in the repository.
732 773 """
733 774
734 775 names = []
735 776 for src, abs, rel, exact in walk(repo, pats, opts):
736 777 if exact:
737 778 if ui.verbose:
738 779 ui.status(_('adding %s\n') % rel)
739 780 names.append(abs)
740 781 elif repo.dirstate.state(abs) == '?':
741 782 ui.status(_('adding %s\n') % rel)
742 783 names.append(abs)
743 784 if not opts.get('dry_run'):
744 785 repo.add(names)
745 786
746 787 def addremove(ui, repo, *pats, **opts):
747 788 """add all new files, delete all missing files (DEPRECATED)
748 789
749 790 (DEPRECATED)
750 791 Add all new files and remove all missing files from the repository.
751 792
752 793 New files are ignored if they match any of the patterns in .hgignore. As
753 794 with add, these changes take effect at the next commit.
754 795
755 796 This command is now deprecated and will be removed in a future
756 797 release. Please use add and remove --after instead.
757 798 """
758 799 ui.warn(_('(the addremove command is deprecated; use add and remove '
759 800 '--after instead)\n'))
760 801 return addremove_lock(ui, repo, pats, opts)
761 802
762 803 def addremove_lock(ui, repo, pats, opts, wlock=None):
763 804 add, remove = [], []
764 805 for src, abs, rel, exact in walk(repo, pats, opts):
765 806 if src == 'f' and repo.dirstate.state(abs) == '?':
766 807 add.append(abs)
767 808 if ui.verbose or not exact:
768 809 ui.status(_('adding %s\n') % ((pats and rel) or abs))
769 810 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
770 811 remove.append(abs)
771 812 if ui.verbose or not exact:
772 813 ui.status(_('removing %s\n') % ((pats and rel) or abs))
773 814 if not opts.get('dry_run'):
774 815 repo.add(add, wlock=wlock)
775 816 repo.remove(remove, wlock=wlock)
776 817
777 818 def annotate(ui, repo, *pats, **opts):
778 819 """show changeset information per file line
779 820
780 821 List changes in files, showing the revision id responsible for each line
781 822
782 823 This command is useful to discover who did a change or when a change took
783 824 place.
784 825
785 826 Without the -a option, annotate will avoid processing files it
786 827 detects as binary. With -a, annotate will generate an annotation
787 828 anyway, probably with undesirable results.
788 829 """
789 830 def getnode(rev):
790 831 return short(repo.changelog.node(rev))
791 832
792 833 ucache = {}
793 834 def getname(rev):
794 835 try:
795 836 return ucache[rev]
796 837 except:
797 838 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
798 839 ucache[rev] = u
799 840 return u
800 841
801 842 dcache = {}
802 843 def getdate(rev):
803 844 datestr = dcache.get(rev)
804 845 if datestr is None:
805 846 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
806 847 return datestr
807 848
808 849 if not pats:
809 850 raise util.Abort(_('at least one file name or pattern required'))
810 851
811 852 opmap = [['user', getname], ['number', str], ['changeset', getnode],
812 853 ['date', getdate]]
813 854 if not opts['user'] and not opts['changeset'] and not opts['date']:
814 855 opts['number'] = 1
815 856
816 857 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
817 858
818 859 for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
819 860 fctx = ctx.filectx(abs)
820 861 if not opts['text'] and util.binary(fctx.data()):
821 862 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
822 863 continue
823 864
824 865 lines = fctx.annotate()
825 866 pieces = []
826 867
827 868 for o, f in opmap:
828 869 if opts[o]:
829 870 l = [f(n) for n, dummy in lines]
830 871 if l:
831 872 m = max(map(len, l))
832 873 pieces.append(["%*s" % (m, x) for x in l])
833 874
834 875 if pieces:
835 876 for p, l in zip(zip(*pieces), lines):
836 877 ui.write("%s: %s" % (" ".join(p), l[1]))
837 878
838 879 def archive(ui, repo, dest, **opts):
839 880 '''create unversioned archive of a repository revision
840 881
841 882 By default, the revision used is the parent of the working
842 883 directory; use "-r" to specify a different revision.
843 884
844 885 To specify the type of archive to create, use "-t". Valid
845 886 types are:
846 887
847 888 "files" (default): a directory full of files
848 889 "tar": tar archive, uncompressed
849 890 "tbz2": tar archive, compressed using bzip2
850 891 "tgz": tar archive, compressed using gzip
851 892 "uzip": zip archive, uncompressed
852 893 "zip": zip archive, compressed using deflate
853 894
854 895 The exact name of the destination archive or directory is given
855 896 using a format string; see "hg help export" for details.
856 897
857 898 Each member added to an archive file has a directory prefix
858 899 prepended. Use "-p" to specify a format string for the prefix.
859 900 The default is the basename of the archive, with suffixes removed.
860 901 '''
861 902
862 903 if opts['rev']:
863 904 node = repo.lookup(opts['rev'])
864 905 else:
865 906 node, p2 = repo.dirstate.parents()
866 907 if p2 != nullid:
867 908 raise util.Abort(_('uncommitted merge - please provide a '
868 909 'specific revision'))
869 910
870 911 dest = make_filename(repo, dest, node)
871 912 if os.path.realpath(dest) == repo.root:
872 913 raise util.Abort(_('repository root cannot be destination'))
873 914 dummy, matchfn, dummy = matchpats(repo, [], opts)
874 915 kind = opts.get('type') or 'files'
875 916 prefix = opts['prefix']
876 917 if dest == '-':
877 918 if kind == 'files':
878 919 raise util.Abort(_('cannot archive plain files to stdout'))
879 920 dest = sys.stdout
880 921 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
881 922 prefix = make_filename(repo, prefix, node)
882 923 archival.archive(repo, dest, node, kind, not opts['no_decode'],
883 924 matchfn, prefix)
884 925
885 926 def backout(ui, repo, rev, **opts):
886 927 '''reverse effect of earlier changeset
887 928
888 929 Commit the backed out changes as a new changeset. The new
889 930 changeset is a child of the backed out changeset.
890 931
891 932 If you back out a changeset other than the tip, a new head is
892 933 created. This head is the parent of the working directory. If
893 934 you back out an old changeset, your working directory will appear
894 935 old after the backout. You should merge the backout changeset
895 936 with another head.
896 937
897 938 The --merge option remembers the parent of the working directory
898 939 before starting the backout, then merges the new head with that
899 940 changeset afterwards. This saves you from doing the merge by
900 941 hand. The result of this merge is not committed, as for a normal
901 942 merge.'''
902 943
903 944 bail_if_changed(repo)
904 945 op1, op2 = repo.dirstate.parents()
905 946 if op2 != nullid:
906 947 raise util.Abort(_('outstanding uncommitted merge'))
907 948 node = repo.lookup(rev)
908 949 p1, p2 = repo.changelog.parents(node)
909 950 if p1 == nullid:
910 951 raise util.Abort(_('cannot back out a change with no parents'))
911 952 if p2 != nullid:
912 953 if not opts['parent']:
913 954 raise util.Abort(_('cannot back out a merge changeset without '
914 955 '--parent'))
915 956 p = repo.lookup(opts['parent'])
916 957 if p not in (p1, p2):
917 958 raise util.Abort(_('%s is not a parent of %s' %
918 959 (short(p), short(node))))
919 960 parent = p
920 961 else:
921 962 if opts['parent']:
922 963 raise util.Abort(_('cannot use --parent on non-merge changeset'))
923 964 parent = p1
924 965 repo.update(node, force=True, show_stats=False)
925 966 revert_opts = opts.copy()
926 967 revert_opts['rev'] = hex(parent)
927 968 revert(ui, repo, **revert_opts)
928 969 commit_opts = opts.copy()
929 970 commit_opts['addremove'] = False
930 971 if not commit_opts['message'] and not commit_opts['logfile']:
931 972 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
932 973 commit_opts['force_editor'] = True
933 974 commit(ui, repo, **commit_opts)
934 975 def nice(node):
935 976 return '%d:%s' % (repo.changelog.rev(node), short(node))
936 977 ui.status(_('changeset %s backs out changeset %s\n') %
937 978 (nice(repo.changelog.tip()), nice(node)))
938 979 if op1 != node:
939 980 if opts['merge']:
940 981 ui.status(_('merging with changeset %s\n') % nice(op1))
941 982 doupdate(ui, repo, hex(op1), **opts)
942 983 else:
943 984 ui.status(_('the backout changeset is a new head - '
944 985 'do not forget to merge\n'))
945 986 ui.status(_('(use "backout --merge" '
946 987 'if you want to auto-merge)\n'))
947 988
948 989 def bundle(ui, repo, fname, dest=None, **opts):
949 990 """create a changegroup file
950 991
951 992 Generate a compressed changegroup file collecting all changesets
952 993 not found in the other repository.
953 994
954 995 This file can then be transferred using conventional means and
955 996 applied to another repository with the unbundle command. This is
956 997 useful when native push and pull are not available or when
957 998 exporting an entire repository is undesirable. The standard file
958 999 extension is ".hg".
959 1000
960 1001 Unlike import/export, this exactly preserves all changeset
961 1002 contents including permissions, rename data, and revision history.
962 1003 """
963 1004 dest = ui.expandpath(dest or 'default-push', dest or 'default')
964 1005 other = hg.repository(ui, dest)
965 1006 o = repo.findoutgoing(other, force=opts['force'])
966 1007 cg = repo.changegroup(o, 'bundle')
967 1008 write_bundle(cg, fname)
968 1009
969 1010 def cat(ui, repo, file1, *pats, **opts):
970 1011 """output the latest or given revisions of files
971 1012
972 1013 Print the specified files as they were at the given revision.
973 1014 If no revision is given then the tip is used.
974 1015
975 1016 Output may be to a file, in which case the name of the file is
976 1017 given using a format string. The formatting rules are the same as
977 1018 for the export command, with the following additions:
978 1019
979 1020 %s basename of file being printed
980 1021 %d dirname of file being printed, or '.' if in repo root
981 1022 %p root-relative path name of file being printed
982 1023 """
983 1024 ctx = repo.changectx(opts['rev'] or "-1")
984 1025 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
985 1026 fp = make_file(repo, opts['output'], ctx.node(), pathname=abs)
986 1027 fp.write(ctx.filectx(abs).data())
987 1028
988 1029 def clone(ui, source, dest=None, **opts):
989 1030 """make a copy of an existing repository
990 1031
991 1032 Create a copy of an existing repository in a new directory.
992 1033
993 1034 If no destination directory name is specified, it defaults to the
994 1035 basename of the source.
995 1036
996 1037 The location of the source is added to the new repository's
997 1038 .hg/hgrc file, as the default to be used for future pulls.
998 1039
999 1040 For efficiency, hardlinks are used for cloning whenever the source
1000 1041 and destination are on the same filesystem (note this applies only
1001 1042 to the repository data, not to the checked out files). Some
1002 1043 filesystems, such as AFS, implement hardlinking incorrectly, but
1003 1044 do not report errors. In these cases, use the --pull option to
1004 1045 avoid hardlinking.
1005 1046
1006 1047 You can safely clone repositories and checked out files using full
1007 1048 hardlinks with
1008 1049
1009 1050 $ cp -al REPO REPOCLONE
1010 1051
1011 1052 which is the fastest way to clone. However, the operation is not
1012 1053 atomic (making sure REPO is not modified during the operation is
1013 1054 up to you) and you have to make sure your editor breaks hardlinks
1014 1055 (Emacs and most Linux Kernel tools do so).
1015 1056
1016 1057 If you use the -r option to clone up to a specific revision, no
1017 1058 subsequent revisions will be present in the cloned repository.
1018 1059 This option implies --pull, even on local repositories.
1019 1060
1020 1061 See pull for valid source format details.
1021 1062
1022 1063 It is possible to specify an ssh:// URL as the destination, but no
1023 1064 .hg/hgrc will be created on the remote side. Look at the help text
1024 1065 for the pull command for important details about ssh:// URLs.
1025 1066 """
1026 1067 setremoteconfig(ui, opts)
1027 1068 hg.clone(ui, ui.expandpath(source), dest,
1028 1069 pull=opts['pull'],
1029 1070 stream=opts['uncompressed'],
1030 1071 rev=opts['rev'],
1031 1072 update=not opts['noupdate'])
1032 1073
1033 1074 def commit(ui, repo, *pats, **opts):
1034 1075 """commit the specified files or all outstanding changes
1035 1076
1036 1077 Commit changes to the given files into the repository.
1037 1078
1038 1079 If a list of files is omitted, all changes reported by "hg status"
1039 1080 will be committed.
1040 1081
1041 1082 If no commit message is specified, the editor configured in your hgrc
1042 1083 or in the EDITOR environment variable is started to enter a message.
1043 1084 """
1044 1085 message = logmessage(**opts)
1045 1086
1046 1087 if opts['addremove']:
1047 1088 addremove_lock(ui, repo, pats, opts)
1048 1089 fns, match, anypats = matchpats(repo, pats, opts)
1049 1090 if pats:
1050 1091 modified, added, removed, deleted, unknown = (
1051 1092 repo.changes(files=fns, match=match))
1052 1093 files = modified + added + removed
1053 1094 else:
1054 1095 files = []
1055 1096 try:
1056 1097 repo.commit(files, message, opts['user'], opts['date'], match,
1057 1098 force_editor=opts.get('force_editor'))
1058 1099 except ValueError, inst:
1059 1100 raise util.Abort(str(inst))
1060 1101
1061 1102 def docopy(ui, repo, pats, opts, wlock):
1062 1103 # called with the repo lock held
1063 1104 cwd = repo.getcwd()
1064 1105 errors = 0
1065 1106 copied = []
1066 1107 targets = {}
1067 1108
1068 1109 def okaytocopy(abs, rel, exact):
1069 1110 reasons = {'?': _('is not managed'),
1070 1111 'a': _('has been marked for add'),
1071 1112 'r': _('has been marked for remove')}
1072 1113 state = repo.dirstate.state(abs)
1073 1114 reason = reasons.get(state)
1074 1115 if reason:
1075 1116 if state == 'a':
1076 1117 origsrc = repo.dirstate.copied(abs)
1077 1118 if origsrc is not None:
1078 1119 return origsrc
1079 1120 if exact:
1080 1121 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
1081 1122 else:
1082 1123 return abs
1083 1124
1084 1125 def copy(origsrc, abssrc, relsrc, target, exact):
1085 1126 abstarget = util.canonpath(repo.root, cwd, target)
1086 1127 reltarget = util.pathto(cwd, abstarget)
1087 1128 prevsrc = targets.get(abstarget)
1088 1129 if prevsrc is not None:
1089 1130 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
1090 1131 (reltarget, abssrc, prevsrc))
1091 1132 return
1092 1133 if (not opts['after'] and os.path.exists(reltarget) or
1093 1134 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
1094 1135 if not opts['force']:
1095 1136 ui.warn(_('%s: not overwriting - file exists\n') %
1096 1137 reltarget)
1097 1138 return
1098 1139 if not opts['after'] and not opts.get('dry_run'):
1099 1140 os.unlink(reltarget)
1100 1141 if opts['after']:
1101 1142 if not os.path.exists(reltarget):
1102 1143 return
1103 1144 else:
1104 1145 targetdir = os.path.dirname(reltarget) or '.'
1105 1146 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
1106 1147 os.makedirs(targetdir)
1107 1148 try:
1108 1149 restore = repo.dirstate.state(abstarget) == 'r'
1109 1150 if restore and not opts.get('dry_run'):
1110 1151 repo.undelete([abstarget], wlock)
1111 1152 try:
1112 1153 if not opts.get('dry_run'):
1113 1154 shutil.copyfile(relsrc, reltarget)
1114 1155 shutil.copymode(relsrc, reltarget)
1115 1156 restore = False
1116 1157 finally:
1117 1158 if restore:
1118 1159 repo.remove([abstarget], wlock)
1119 1160 except shutil.Error, inst:
1120 1161 raise util.Abort(str(inst))
1121 1162 except IOError, inst:
1122 1163 if inst.errno == errno.ENOENT:
1123 1164 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1124 1165 else:
1125 1166 ui.warn(_('%s: cannot copy - %s\n') %
1126 1167 (relsrc, inst.strerror))
1127 1168 errors += 1
1128 1169 return
1129 1170 if ui.verbose or not exact:
1130 1171 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1131 1172 targets[abstarget] = abssrc
1132 1173 if abstarget != origsrc and not opts.get('dry_run'):
1133 1174 repo.copy(origsrc, abstarget, wlock)
1134 1175 copied.append((abssrc, relsrc, exact))
1135 1176
1136 1177 def targetpathfn(pat, dest, srcs):
1137 1178 if os.path.isdir(pat):
1138 1179 abspfx = util.canonpath(repo.root, cwd, pat)
1139 1180 if destdirexists:
1140 1181 striplen = len(os.path.split(abspfx)[0])
1141 1182 else:
1142 1183 striplen = len(abspfx)
1143 1184 if striplen:
1144 1185 striplen += len(os.sep)
1145 1186 res = lambda p: os.path.join(dest, p[striplen:])
1146 1187 elif destdirexists:
1147 1188 res = lambda p: os.path.join(dest, os.path.basename(p))
1148 1189 else:
1149 1190 res = lambda p: dest
1150 1191 return res
1151 1192
1152 1193 def targetpathafterfn(pat, dest, srcs):
1153 1194 if util.patkind(pat, None)[0]:
1154 1195 # a mercurial pattern
1155 1196 res = lambda p: os.path.join(dest, os.path.basename(p))
1156 1197 else:
1157 1198 abspfx = util.canonpath(repo.root, cwd, pat)
1158 1199 if len(abspfx) < len(srcs[0][0]):
1159 1200 # A directory. Either the target path contains the last
1160 1201 # component of the source path or it does not.
1161 1202 def evalpath(striplen):
1162 1203 score = 0
1163 1204 for s in srcs:
1164 1205 t = os.path.join(dest, s[0][striplen:])
1165 1206 if os.path.exists(t):
1166 1207 score += 1
1167 1208 return score
1168 1209
1169 1210 striplen = len(abspfx)
1170 1211 if striplen:
1171 1212 striplen += len(os.sep)
1172 1213 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1173 1214 score = evalpath(striplen)
1174 1215 striplen1 = len(os.path.split(abspfx)[0])
1175 1216 if striplen1:
1176 1217 striplen1 += len(os.sep)
1177 1218 if evalpath(striplen1) > score:
1178 1219 striplen = striplen1
1179 1220 res = lambda p: os.path.join(dest, p[striplen:])
1180 1221 else:
1181 1222 # a file
1182 1223 if destdirexists:
1183 1224 res = lambda p: os.path.join(dest, os.path.basename(p))
1184 1225 else:
1185 1226 res = lambda p: dest
1186 1227 return res
1187 1228
1188 1229
1189 1230 pats = list(pats)
1190 1231 if not pats:
1191 1232 raise util.Abort(_('no source or destination specified'))
1192 1233 if len(pats) == 1:
1193 1234 raise util.Abort(_('no destination specified'))
1194 1235 dest = pats.pop()
1195 1236 destdirexists = os.path.isdir(dest)
1196 1237 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1197 1238 raise util.Abort(_('with multiple sources, destination must be an '
1198 1239 'existing directory'))
1199 1240 if opts['after']:
1200 1241 tfn = targetpathafterfn
1201 1242 else:
1202 1243 tfn = targetpathfn
1203 1244 copylist = []
1204 1245 for pat in pats:
1205 1246 srcs = []
1206 1247 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
1207 1248 origsrc = okaytocopy(abssrc, relsrc, exact)
1208 1249 if origsrc:
1209 1250 srcs.append((origsrc, abssrc, relsrc, exact))
1210 1251 if not srcs:
1211 1252 continue
1212 1253 copylist.append((tfn(pat, dest, srcs), srcs))
1213 1254 if not copylist:
1214 1255 raise util.Abort(_('no files to copy'))
1215 1256
1216 1257 for targetpath, srcs in copylist:
1217 1258 for origsrc, abssrc, relsrc, exact in srcs:
1218 1259 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1219 1260
1220 1261 if errors:
1221 1262 ui.warn(_('(consider using --after)\n'))
1222 1263 return errors, copied
1223 1264
1224 1265 def copy(ui, repo, *pats, **opts):
1225 1266 """mark files as copied for the next commit
1226 1267
1227 1268 Mark dest as having copies of source files. If dest is a
1228 1269 directory, copies are put in that directory. If dest is a file,
1229 1270 there can only be one source.
1230 1271
1231 1272 By default, this command copies the contents of files as they
1232 1273 stand in the working directory. If invoked with --after, the
1233 1274 operation is recorded, but no copying is performed.
1234 1275
1235 1276 This command takes effect in the next commit.
1236 1277
1237 1278 NOTE: This command should be treated as experimental. While it
1238 1279 should properly record copied files, this information is not yet
1239 1280 fully used by merge, nor fully reported by log.
1240 1281 """
1241 1282 wlock = repo.wlock(0)
1242 1283 errs, copied = docopy(ui, repo, pats, opts, wlock)
1243 1284 return errs
1244 1285
1245 1286 def debugancestor(ui, index, rev1, rev2):
1246 1287 """find the ancestor revision of two revisions in a given index"""
1247 1288 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1248 1289 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1249 1290 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1250 1291
1251 1292 def debugcomplete(ui, cmd='', **opts):
1252 1293 """returns the completion list associated with the given command"""
1253 1294
1254 1295 if opts['options']:
1255 1296 options = []
1256 1297 otables = [globalopts]
1257 1298 if cmd:
1258 1299 aliases, entry = findcmd(cmd)
1259 1300 otables.append(entry[1])
1260 1301 for t in otables:
1261 1302 for o in t:
1262 1303 if o[0]:
1263 1304 options.append('-%s' % o[0])
1264 1305 options.append('--%s' % o[1])
1265 1306 ui.write("%s\n" % "\n".join(options))
1266 1307 return
1267 1308
1268 1309 clist = findpossible(cmd).keys()
1269 1310 clist.sort()
1270 1311 ui.write("%s\n" % "\n".join(clist))
1271 1312
1272 1313 def debugrebuildstate(ui, repo, rev=None):
1273 1314 """rebuild the dirstate as it would look like for the given revision"""
1274 1315 if not rev:
1275 1316 rev = repo.changelog.tip()
1276 1317 else:
1277 1318 rev = repo.lookup(rev)
1278 1319 change = repo.changelog.read(rev)
1279 1320 n = change[0]
1280 1321 files = repo.manifest.readflags(n)
1281 1322 wlock = repo.wlock()
1282 1323 repo.dirstate.rebuild(rev, files.iteritems())
1283 1324
1284 1325 def debugcheckstate(ui, repo):
1285 1326 """validate the correctness of the current dirstate"""
1286 1327 parent1, parent2 = repo.dirstate.parents()
1287 1328 repo.dirstate.read()
1288 1329 dc = repo.dirstate.map
1289 1330 keys = dc.keys()
1290 1331 keys.sort()
1291 1332 m1n = repo.changelog.read(parent1)[0]
1292 1333 m2n = repo.changelog.read(parent2)[0]
1293 1334 m1 = repo.manifest.read(m1n)
1294 1335 m2 = repo.manifest.read(m2n)
1295 1336 errors = 0
1296 1337 for f in dc:
1297 1338 state = repo.dirstate.state(f)
1298 1339 if state in "nr" and f not in m1:
1299 1340 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1300 1341 errors += 1
1301 1342 if state in "a" and f in m1:
1302 1343 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1303 1344 errors += 1
1304 1345 if state in "m" and f not in m1 and f not in m2:
1305 1346 ui.warn(_("%s in state %s, but not in either manifest\n") %
1306 1347 (f, state))
1307 1348 errors += 1
1308 1349 for f in m1:
1309 1350 state = repo.dirstate.state(f)
1310 1351 if state not in "nrm":
1311 1352 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1312 1353 errors += 1
1313 1354 if errors:
1314 1355 error = _(".hg/dirstate inconsistent with current parent's manifest")
1315 1356 raise util.Abort(error)
1316 1357
1317 1358 def debugconfig(ui, repo, *values):
1318 1359 """show combined config settings from all hgrc files
1319 1360
1320 1361 With no args, print names and values of all config items.
1321 1362
1322 1363 With one arg of the form section.name, print just the value of
1323 1364 that config item.
1324 1365
1325 1366 With multiple args, print names and values of all config items
1326 1367 with matching section names."""
1327 1368
1328 1369 if values:
1329 1370 if len([v for v in values if '.' in v]) > 1:
1330 1371 raise util.Abort(_('only one config item permitted'))
1331 1372 for section, name, value in ui.walkconfig():
1332 1373 sectname = section + '.' + name
1333 1374 if values:
1334 1375 for v in values:
1335 1376 if v == section:
1336 1377 ui.write('%s=%s\n' % (sectname, value))
1337 1378 elif v == sectname:
1338 1379 ui.write(value, '\n')
1339 1380 else:
1340 1381 ui.write('%s=%s\n' % (sectname, value))
1341 1382
1342 1383 def debugsetparents(ui, repo, rev1, rev2=None):
1343 1384 """manually set the parents of the current working directory
1344 1385
1345 1386 This is useful for writing repository conversion tools, but should
1346 1387 be used with care.
1347 1388 """
1348 1389
1349 1390 if not rev2:
1350 1391 rev2 = hex(nullid)
1351 1392
1352 1393 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1353 1394
1354 1395 def debugstate(ui, repo):
1355 1396 """show the contents of the current dirstate"""
1356 1397 repo.dirstate.read()
1357 1398 dc = repo.dirstate.map
1358 1399 keys = dc.keys()
1359 1400 keys.sort()
1360 1401 for file_ in keys:
1361 1402 ui.write("%c %3o %10d %s %s\n"
1362 1403 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1363 1404 time.strftime("%x %X",
1364 1405 time.localtime(dc[file_][3])), file_))
1365 1406 for f in repo.dirstate.copies:
1366 1407 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1367 1408
1368 1409 def debugdata(ui, file_, rev):
1369 1410 """dump the contents of an data file revision"""
1370 1411 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1371 1412 file_[:-2] + ".i", file_, 0)
1372 1413 try:
1373 1414 ui.write(r.revision(r.lookup(rev)))
1374 1415 except KeyError:
1375 1416 raise util.Abort(_('invalid revision identifier %s'), rev)
1376 1417
1377 1418 def debugindex(ui, file_):
1378 1419 """dump the contents of an index file"""
1379 1420 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1380 1421 ui.write(" rev offset length base linkrev" +
1381 1422 " nodeid p1 p2\n")
1382 1423 for i in range(r.count()):
1383 1424 node = r.node(i)
1384 1425 pp = r.parents(node)
1385 1426 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1386 1427 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1387 1428 short(node), short(pp[0]), short(pp[1])))
1388 1429
1389 1430 def debugindexdot(ui, file_):
1390 1431 """dump an index DAG as a .dot file"""
1391 1432 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1392 1433 ui.write("digraph G {\n")
1393 1434 for i in range(r.count()):
1394 1435 node = r.node(i)
1395 1436 pp = r.parents(node)
1396 1437 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1397 1438 if pp[1] != nullid:
1398 1439 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1399 1440 ui.write("}\n")
1400 1441
1401 1442 def debugrename(ui, repo, file, rev=None):
1402 1443 """dump rename information"""
1403 1444 r = repo.file(relpath(repo, [file])[0])
1404 1445 if rev:
1405 1446 try:
1406 1447 # assume all revision numbers are for changesets
1407 1448 n = repo.lookup(rev)
1408 1449 change = repo.changelog.read(n)
1409 1450 m = repo.manifest.read(change[0])
1410 1451 n = m[relpath(repo, [file])[0]]
1411 1452 except (hg.RepoError, KeyError):
1412 1453 n = r.lookup(rev)
1413 1454 else:
1414 1455 n = r.tip()
1415 1456 m = r.renamed(n)
1416 1457 if m:
1417 1458 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1418 1459 else:
1419 1460 ui.write(_("not renamed\n"))
1420 1461
1421 1462 def debugwalk(ui, repo, *pats, **opts):
1422 1463 """show how files match on given patterns"""
1423 1464 items = list(walk(repo, pats, opts))
1424 1465 if not items:
1425 1466 return
1426 1467 fmt = '%%s %%-%ds %%-%ds %%s' % (
1427 1468 max([len(abs) for (src, abs, rel, exact) in items]),
1428 1469 max([len(rel) for (src, abs, rel, exact) in items]))
1429 1470 for src, abs, rel, exact in items:
1430 1471 line = fmt % (src, abs, rel, exact and 'exact' or '')
1431 1472 ui.write("%s\n" % line.rstrip())
1432 1473
1433 1474 def diff(ui, repo, *pats, **opts):
1434 1475 """diff repository (or selected files)
1435 1476
1436 1477 Show differences between revisions for the specified files.
1437 1478
1438 1479 Differences between files are shown using the unified diff format.
1439 1480
1440 1481 When two revision arguments are given, then changes are shown
1441 1482 between those revisions. If only one revision is specified then
1442 1483 that revision is compared to the working directory, and, when no
1443 1484 revisions are specified, the working directory files are compared
1444 1485 to its parent.
1445 1486
1446 1487 Without the -a option, diff will avoid generating diffs of files
1447 1488 it detects as binary. With -a, diff will generate a diff anyway,
1448 1489 probably with undesirable results.
1449 1490 """
1450 1491 node1, node2 = revpair(ui, repo, opts['rev'])
1451 1492
1452 1493 fns, matchfn, anypats = matchpats(repo, pats, opts)
1453 1494
1454 1495 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1455 1496 text=opts['text'], opts=opts)
1456 1497
1457 1498 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1458 1499 node = repo.lookup(changeset)
1459 1500 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1460 1501 if opts['switch_parent']:
1461 1502 parents.reverse()
1462 1503 prev = (parents and parents[0]) or nullid
1463 1504 change = repo.changelog.read(node)
1464 1505
1465 1506 fp = make_file(repo, opts['output'], node, total=total, seqno=seqno,
1466 1507 revwidth=revwidth)
1467 1508 if fp != sys.stdout:
1468 1509 ui.note("%s\n" % fp.name)
1469 1510
1470 1511 fp.write("# HG changeset patch\n")
1471 1512 fp.write("# User %s\n" % change[1])
1472 1513 fp.write("# Date %d %d\n" % change[2])
1473 1514 fp.write("# Node ID %s\n" % hex(node))
1474 1515 fp.write("# Parent %s\n" % hex(prev))
1475 1516 if len(parents) > 1:
1476 1517 fp.write("# Parent %s\n" % hex(parents[1]))
1477 1518 fp.write(change[4].rstrip())
1478 1519 fp.write("\n\n")
1479 1520
1480 1521 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1481 1522 if fp != sys.stdout:
1482 1523 fp.close()
1483 1524
1484 1525 def export(ui, repo, *changesets, **opts):
1485 1526 """dump the header and diffs for one or more changesets
1486 1527
1487 1528 Print the changeset header and diffs for one or more revisions.
1488 1529
1489 1530 The information shown in the changeset header is: author,
1490 1531 changeset hash, parent and commit comment.
1491 1532
1492 1533 Output may be to a file, in which case the name of the file is
1493 1534 given using a format string. The formatting rules are as follows:
1494 1535
1495 1536 %% literal "%" character
1496 1537 %H changeset hash (40 bytes of hexadecimal)
1497 1538 %N number of patches being generated
1498 1539 %R changeset revision number
1499 1540 %b basename of the exporting repository
1500 1541 %h short-form changeset hash (12 bytes of hexadecimal)
1501 1542 %n zero-padded sequence number, starting at 1
1502 1543 %r zero-padded changeset revision number
1503 1544
1504 1545 Without the -a option, export will avoid generating diffs of files
1505 1546 it detects as binary. With -a, export will generate a diff anyway,
1506 1547 probably with undesirable results.
1507 1548
1508 1549 With the --switch-parent option, the diff will be against the second
1509 1550 parent. It can be useful to review a merge.
1510 1551 """
1511 1552 if not changesets:
1512 1553 raise util.Abort(_("export requires at least one changeset"))
1513 1554 seqno = 0
1514 1555 revs = list(revrange(ui, repo, changesets))
1515 1556 total = len(revs)
1516 1557 revwidth = max(map(len, revs))
1517 1558 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1518 1559 ui.note(msg)
1519 1560 for cset in revs:
1520 1561 seqno += 1
1521 1562 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1522 1563
1523 1564 def forget(ui, repo, *pats, **opts):
1524 1565 """don't add the specified files on the next commit (DEPRECATED)
1525 1566
1526 1567 (DEPRECATED)
1527 1568 Undo an 'hg add' scheduled for the next commit.
1528 1569
1529 1570 This command is now deprecated and will be removed in a future
1530 1571 release. Please use revert instead.
1531 1572 """
1532 1573 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1533 1574 forget = []
1534 1575 for src, abs, rel, exact in walk(repo, pats, opts):
1535 1576 if repo.dirstate.state(abs) == 'a':
1536 1577 forget.append(abs)
1537 1578 if ui.verbose or not exact:
1538 1579 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1539 1580 repo.forget(forget)
1540 1581
1541 1582 def grep(ui, repo, pattern, *pats, **opts):
1542 1583 """search for a pattern in specified files and revisions
1543 1584
1544 1585 Search revisions of files for a regular expression.
1545 1586
1546 1587 This command behaves differently than Unix grep. It only accepts
1547 1588 Python/Perl regexps. It searches repository history, not the
1548 1589 working directory. It always prints the revision number in which
1549 1590 a match appears.
1550 1591
1551 1592 By default, grep only prints output for the first revision of a
1552 1593 file in which it finds a match. To get it to print every revision
1553 1594 that contains a change in match status ("-" for a match that
1554 1595 becomes a non-match, or "+" for a non-match that becomes a match),
1555 1596 use the --all flag.
1556 1597 """
1557 1598 reflags = 0
1558 1599 if opts['ignore_case']:
1559 1600 reflags |= re.I
1560 1601 regexp = re.compile(pattern, reflags)
1561 1602 sep, eol = ':', '\n'
1562 1603 if opts['print0']:
1563 1604 sep = eol = '\0'
1564 1605
1565 1606 fcache = {}
1566 1607 def getfile(fn):
1567 1608 if fn not in fcache:
1568 1609 fcache[fn] = repo.file(fn)
1569 1610 return fcache[fn]
1570 1611
1571 1612 def matchlines(body):
1572 1613 begin = 0
1573 1614 linenum = 0
1574 1615 while True:
1575 1616 match = regexp.search(body, begin)
1576 1617 if not match:
1577 1618 break
1578 1619 mstart, mend = match.span()
1579 1620 linenum += body.count('\n', begin, mstart) + 1
1580 1621 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1581 1622 lend = body.find('\n', mend)
1582 1623 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1583 1624 begin = lend + 1
1584 1625
1585 1626 class linestate(object):
1586 1627 def __init__(self, line, linenum, colstart, colend):
1587 1628 self.line = line
1588 1629 self.linenum = linenum
1589 1630 self.colstart = colstart
1590 1631 self.colend = colend
1591 1632 def __eq__(self, other):
1592 1633 return self.line == other.line
1593 1634 def __hash__(self):
1594 1635 return hash(self.line)
1595 1636
1596 1637 matches = {}
1597 1638 def grepbody(fn, rev, body):
1598 1639 matches[rev].setdefault(fn, {})
1599 1640 m = matches[rev][fn]
1600 1641 for lnum, cstart, cend, line in matchlines(body):
1601 1642 s = linestate(line, lnum, cstart, cend)
1602 1643 m[s] = s
1603 1644
1604 1645 # FIXME: prev isn't used, why ?
1605 1646 prev = {}
1606 1647 ucache = {}
1607 1648 def display(fn, rev, states, prevstates):
1608 1649 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1609 1650 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1610 1651 counts = {'-': 0, '+': 0}
1611 1652 filerevmatches = {}
1612 1653 for l in diff:
1613 1654 if incrementing or not opts['all']:
1614 1655 change = ((l in prevstates) and '-') or '+'
1615 1656 r = rev
1616 1657 else:
1617 1658 change = ((l in states) and '-') or '+'
1618 1659 r = prev[fn]
1619 1660 cols = [fn, str(rev)]
1620 1661 if opts['line_number']:
1621 1662 cols.append(str(l.linenum))
1622 1663 if opts['all']:
1623 1664 cols.append(change)
1624 1665 if opts['user']:
1625 1666 cols.append(trimuser(ui, getchange(rev)[1], rev,
1626 1667 ucache))
1627 1668 if opts['files_with_matches']:
1628 1669 c = (fn, rev)
1629 1670 if c in filerevmatches:
1630 1671 continue
1631 1672 filerevmatches[c] = 1
1632 1673 else:
1633 1674 cols.append(l.line)
1634 1675 ui.write(sep.join(cols), eol)
1635 1676 counts[change] += 1
1636 1677 return counts['+'], counts['-']
1637 1678
1638 1679 fstate = {}
1639 1680 skip = {}
1640 1681 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1641 1682 count = 0
1642 1683 incrementing = False
1643 1684 for st, rev, fns in changeiter:
1644 1685 if st == 'window':
1645 1686 incrementing = rev
1646 1687 matches.clear()
1647 1688 elif st == 'add':
1648 1689 change = repo.changelog.read(repo.lookup(str(rev)))
1649 1690 mf = repo.manifest.read(change[0])
1650 1691 matches[rev] = {}
1651 1692 for fn in fns:
1652 1693 if fn in skip:
1653 1694 continue
1654 1695 fstate.setdefault(fn, {})
1655 1696 try:
1656 1697 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1657 1698 except KeyError:
1658 1699 pass
1659 1700 elif st == 'iter':
1660 1701 states = matches[rev].items()
1661 1702 states.sort()
1662 1703 for fn, m in states:
1663 1704 if fn in skip:
1664 1705 continue
1665 1706 if incrementing or not opts['all'] or fstate[fn]:
1666 1707 pos, neg = display(fn, rev, m, fstate[fn])
1667 1708 count += pos + neg
1668 1709 if pos and not opts['all']:
1669 1710 skip[fn] = True
1670 1711 fstate[fn] = m
1671 1712 prev[fn] = rev
1672 1713
1673 1714 if not incrementing:
1674 1715 fstate = fstate.items()
1675 1716 fstate.sort()
1676 1717 for fn, state in fstate:
1677 1718 if fn in skip:
1678 1719 continue
1679 1720 display(fn, rev, {}, state)
1680 1721 return (count == 0 and 1) or 0
1681 1722
1682 1723 def heads(ui, repo, **opts):
1683 1724 """show current repository heads
1684 1725
1685 1726 Show all repository head changesets.
1686 1727
1687 1728 Repository "heads" are changesets that don't have children
1688 1729 changesets. They are where development generally takes place and
1689 1730 are the usual targets for update and merge operations.
1690 1731 """
1691 1732 if opts['rev']:
1692 1733 heads = repo.heads(repo.lookup(opts['rev']))
1693 1734 else:
1694 1735 heads = repo.heads()
1695 1736 br = None
1696 1737 if opts['branches']:
1697 1738 br = repo.branchlookup(heads)
1698 1739 displayer = show_changeset(ui, repo, opts)
1699 1740 for n in heads:
1700 1741 displayer.show(changenode=n, brinfo=br)
1701 1742
1702 1743 def identify(ui, repo):
1703 1744 """print information about the working copy
1704 1745
1705 1746 Print a short summary of the current state of the repo.
1706 1747
1707 1748 This summary identifies the repository state using one or two parent
1708 1749 hash identifiers, followed by a "+" if there are uncommitted changes
1709 1750 in the working directory, followed by a list of tags for this revision.
1710 1751 """
1711 1752 parents = [p for p in repo.dirstate.parents() if p != nullid]
1712 1753 if not parents:
1713 1754 ui.write(_("unknown\n"))
1714 1755 return
1715 1756
1716 1757 hexfunc = ui.verbose and hex or short
1717 1758 modified, added, removed, deleted, unknown = repo.changes()
1718 1759 output = ["%s%s" %
1719 1760 ('+'.join([hexfunc(parent) for parent in parents]),
1720 1761 (modified or added or removed or deleted) and "+" or "")]
1721 1762
1722 1763 if not ui.quiet:
1723 1764 # multiple tags for a single parent separated by '/'
1724 1765 parenttags = ['/'.join(tags)
1725 1766 for tags in map(repo.nodetags, parents) if tags]
1726 1767 # tags for multiple parents separated by ' + '
1727 1768 if parenttags:
1728 1769 output.append(' + '.join(parenttags))
1729 1770
1730 1771 ui.write("%s\n" % ' '.join(output))
1731 1772
1732 1773 def import_(ui, repo, patch1, *patches, **opts):
1733 1774 """import an ordered set of patches
1734 1775
1735 1776 Import a list of patches and commit them individually.
1736 1777
1737 1778 If there are outstanding changes in the working directory, import
1738 1779 will abort unless given the -f flag.
1739 1780
1740 1781 You can import a patch straight from a mail message. Even patches
1741 1782 as attachments work (body part must be type text/plain or
1742 1783 text/x-patch to be used). From and Subject headers of email
1743 1784 message are used as default committer and commit message. All
1744 1785 text/plain body parts before first diff are added to commit
1745 1786 message.
1746 1787
1747 1788 If imported patch was generated by hg export, user and description
1748 1789 from patch override values from message headers and body. Values
1749 1790 given on command line with -m and -u override these.
1750 1791
1751 1792 To read a patch from standard input, use patch name "-".
1752 1793 """
1753 1794 patches = (patch1,) + patches
1754 1795
1755 1796 if not opts['force']:
1756 1797 bail_if_changed(repo)
1757 1798
1758 1799 d = opts["base"]
1759 1800 strip = opts["strip"]
1760 1801
1761 1802 mailre = re.compile(r'(?:From |[\w-]+:)')
1762 1803
1763 1804 # attempt to detect the start of a patch
1764 1805 # (this heuristic is borrowed from quilt)
1765 1806 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1766 1807 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1767 1808 '(---|\*\*\*)[ \t])', re.MULTILINE)
1768 1809
1769 1810 for patch in patches:
1770 1811 pf = os.path.join(d, patch)
1771 1812
1772 1813 message = None
1773 1814 user = None
1774 1815 date = None
1775 1816 hgpatch = False
1776 1817
1777 1818 p = email.Parser.Parser()
1778 1819 if pf == '-':
1779 1820 msg = p.parse(sys.stdin)
1780 1821 ui.status(_("applying patch from stdin\n"))
1781 1822 else:
1782 1823 msg = p.parse(file(pf))
1783 1824 ui.status(_("applying %s\n") % patch)
1784 1825
1785 1826 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
1786 1827 tmpfp = os.fdopen(fd, 'w')
1787 1828 try:
1788 1829 message = msg['Subject']
1789 1830 if message:
1790 1831 message = message.replace('\n\t', ' ')
1791 1832 ui.debug('Subject: %s\n' % message)
1792 1833 user = msg['From']
1793 1834 if user:
1794 1835 ui.debug('From: %s\n' % user)
1795 1836 diffs_seen = 0
1796 1837 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
1797 1838 for part in msg.walk():
1798 1839 content_type = part.get_content_type()
1799 1840 ui.debug('Content-Type: %s\n' % content_type)
1800 1841 if content_type not in ok_types:
1801 1842 continue
1802 1843 payload = part.get_payload(decode=True)
1803 1844 m = diffre.search(payload)
1804 1845 if m:
1805 1846 ui.debug(_('found patch at byte %d\n') % m.start(0))
1806 1847 diffs_seen += 1
1807 1848 hgpatch = False
1808 1849 fp = cStringIO.StringIO()
1809 1850 if message:
1810 1851 fp.write(message)
1811 1852 fp.write('\n')
1812 1853 for line in payload[:m.start(0)].splitlines():
1813 1854 if line.startswith('# HG changeset patch'):
1814 1855 ui.debug(_('patch generated by hg export\n'))
1815 1856 hgpatch = True
1816 1857 # drop earlier commit message content
1817 1858 fp.seek(0)
1818 1859 fp.truncate()
1819 1860 elif hgpatch:
1820 1861 if line.startswith('# User '):
1821 1862 user = line[7:]
1822 1863 ui.debug('From: %s\n' % user)
1823 1864 elif line.startswith("# Date "):
1824 1865 date = line[7:]
1825 1866 if not line.startswith('# '):
1826 1867 fp.write(line)
1827 1868 fp.write('\n')
1828 1869 message = fp.getvalue()
1829 1870 if tmpfp:
1830 1871 tmpfp.write(payload)
1831 1872 if not payload.endswith('\n'):
1832 1873 tmpfp.write('\n')
1833 1874 elif not diffs_seen and message and content_type == 'text/plain':
1834 1875 message += '\n' + payload
1835 1876
1836 1877 if opts['message']:
1837 1878 # pickup the cmdline msg
1838 1879 message = opts['message']
1839 1880 elif message:
1840 1881 # pickup the patch msg
1841 1882 message = message.strip()
1842 1883 else:
1843 1884 # launch the editor
1844 1885 message = None
1845 1886 ui.debug(_('message:\n%s\n') % message)
1846 1887
1847 1888 tmpfp.close()
1848 1889 if not diffs_seen:
1849 1890 raise util.Abort(_('no diffs found'))
1850 1891
1851 1892 files = util.patch(strip, tmpname, ui, cwd=repo.root)
1852 1893 if len(files) > 0:
1853 1894 cfiles = files
1854 1895 cwd = repo.getcwd()
1855 1896 if cwd:
1856 1897 cfiles = [util.pathto(cwd, f) for f in files]
1857 1898 addremove_lock(ui, repo, cfiles, {})
1858 1899 repo.commit(files, message, user, date)
1859 1900 finally:
1860 1901 os.unlink(tmpname)
1861 1902
1862 1903 def incoming(ui, repo, source="default", **opts):
1863 1904 """show new changesets found in source
1864 1905
1865 1906 Show new changesets found in the specified path/URL or the default
1866 1907 pull location. These are the changesets that would be pulled if a pull
1867 1908 was requested.
1868 1909
1869 1910 For remote repository, using --bundle avoids downloading the changesets
1870 1911 twice if the incoming is followed by a pull.
1871 1912
1872 1913 See pull for valid source format details.
1873 1914 """
1874 1915 source = ui.expandpath(source)
1875 1916 setremoteconfig(ui, opts)
1876 1917
1877 1918 other = hg.repository(ui, source)
1878 1919 incoming = repo.findincoming(other, force=opts["force"])
1879 1920 if not incoming:
1880 1921 ui.status(_("no changes found\n"))
1881 1922 return
1882 1923
1883 1924 cleanup = None
1884 1925 try:
1885 1926 fname = opts["bundle"]
1886 1927 if fname or not other.local():
1887 1928 # create a bundle (uncompressed if other repo is not local)
1888 1929 cg = other.changegroup(incoming, "incoming")
1889 1930 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1890 1931 # keep written bundle?
1891 1932 if opts["bundle"]:
1892 1933 cleanup = None
1893 1934 if not other.local():
1894 1935 # use the created uncompressed bundlerepo
1895 1936 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1896 1937
1897 1938 revs = None
1898 1939 if opts['rev']:
1899 1940 revs = [other.lookup(rev) for rev in opts['rev']]
1900 1941 o = other.changelog.nodesbetween(incoming, revs)[0]
1901 1942 if opts['newest_first']:
1902 1943 o.reverse()
1903 1944 displayer = show_changeset(ui, other, opts)
1904 1945 for n in o:
1905 1946 parents = [p for p in other.changelog.parents(n) if p != nullid]
1906 1947 if opts['no_merges'] and len(parents) == 2:
1907 1948 continue
1908 1949 displayer.show(changenode=n)
1909 1950 if opts['patch']:
1910 1951 prev = (parents and parents[0]) or nullid
1911 1952 dodiff(ui, ui, other, prev, n)
1912 1953 ui.write("\n")
1913 1954 finally:
1914 1955 if hasattr(other, 'close'):
1915 1956 other.close()
1916 1957 if cleanup:
1917 1958 os.unlink(cleanup)
1918 1959
1919 1960 def init(ui, dest=".", **opts):
1920 1961 """create a new repository in the given directory
1921 1962
1922 1963 Initialize a new repository in the given directory. If the given
1923 1964 directory does not exist, it is created.
1924 1965
1925 1966 If no directory is given, the current directory is used.
1926 1967
1927 1968 It is possible to specify an ssh:// URL as the destination.
1928 1969 Look at the help text for the pull command for important details
1929 1970 about ssh:// URLs.
1930 1971 """
1931 1972 setremoteconfig(ui, opts)
1932 1973 hg.repository(ui, dest, create=1)
1933 1974
1934 1975 def locate(ui, repo, *pats, **opts):
1935 1976 """locate files matching specific patterns
1936 1977
1937 1978 Print all files under Mercurial control whose names match the
1938 1979 given patterns.
1939 1980
1940 1981 This command searches the current directory and its
1941 1982 subdirectories. To search an entire repository, move to the root
1942 1983 of the repository.
1943 1984
1944 1985 If no patterns are given to match, this command prints all file
1945 1986 names.
1946 1987
1947 1988 If you want to feed the output of this command into the "xargs"
1948 1989 command, use the "-0" option to both this command and "xargs".
1949 1990 This will avoid the problem of "xargs" treating single filenames
1950 1991 that contain white space as multiple filenames.
1951 1992 """
1952 1993 end = opts['print0'] and '\0' or '\n'
1953 1994 rev = opts['rev']
1954 1995 if rev:
1955 1996 node = repo.lookup(rev)
1956 1997 else:
1957 1998 node = None
1958 1999
1959 2000 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1960 2001 head='(?:.*/|)'):
1961 2002 if not node and repo.dirstate.state(abs) == '?':
1962 2003 continue
1963 2004 if opts['fullpath']:
1964 2005 ui.write(os.path.join(repo.root, abs), end)
1965 2006 else:
1966 2007 ui.write(((pats and rel) or abs), end)
1967 2008
1968 2009 def log(ui, repo, *pats, **opts):
1969 2010 """show revision history of entire repository or files
1970 2011
1971 2012 Print the revision history of the specified files or the entire
1972 2013 project.
1973 2014
1974 2015 File history is shown without following rename or copy history of
1975 files. Use -f/--follow to follow history across renames and
1976 copies.
2016 files. Use -f/--follow with a file name to follow history across
2017 renames and copies. --follow without a file name will only show
2018 ancestors or descendants of the starting revision.
1977 2019
1978 2020 By default this command outputs: changeset id and hash, tags,
1979 2021 non-trivial parents, user, date and time, and a summary for each
1980 2022 commit. When the -v/--verbose switch is used, the list of changed
1981 2023 files and full commit message is shown.
1982 2024 """
1983 2025 class dui(object):
1984 2026 # Implement and delegate some ui protocol. Save hunks of
1985 2027 # output for later display in the desired order.
1986 2028 def __init__(self, ui):
1987 2029 self.ui = ui
1988 2030 self.hunk = {}
1989 2031 self.header = {}
1990 2032 def bump(self, rev):
1991 2033 self.rev = rev
1992 2034 self.hunk[rev] = []
1993 2035 self.header[rev] = []
1994 2036 def note(self, *args):
1995 2037 if self.verbose:
1996 2038 self.write(*args)
1997 2039 def status(self, *args):
1998 2040 if not self.quiet:
1999 2041 self.write(*args)
2000 2042 def write(self, *args):
2001 2043 self.hunk[self.rev].append(args)
2002 2044 def write_header(self, *args):
2003 2045 self.header[self.rev].append(args)
2004 2046 def debug(self, *args):
2005 2047 if self.debugflag:
2006 2048 self.write(*args)
2007 2049 def __getattr__(self, key):
2008 2050 return getattr(self.ui, key)
2009 2051
2010 2052 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
2011 2053
2012 2054 if opts['limit']:
2013 2055 try:
2014 2056 limit = int(opts['limit'])
2015 2057 except ValueError:
2016 2058 raise util.Abort(_('limit must be a positive integer'))
2017 2059 if limit <= 0: raise util.Abort(_('limit must be positive'))
2018 2060 else:
2019 2061 limit = sys.maxint
2020 2062 count = 0
2021 2063
2022 2064 displayer = show_changeset(ui, repo, opts)
2023 2065 for st, rev, fns in changeiter:
2024 2066 if st == 'window':
2025 2067 du = dui(ui)
2026 2068 displayer.ui = du
2027 2069 elif st == 'add':
2028 2070 du.bump(rev)
2029 2071 changenode = repo.changelog.node(rev)
2030 2072 parents = [p for p in repo.changelog.parents(changenode)
2031 2073 if p != nullid]
2032 2074 if opts['no_merges'] and len(parents) == 2:
2033 2075 continue
2034 2076 if opts['only_merges'] and len(parents) != 2:
2035 2077 continue
2036 2078
2037 2079 if opts['keyword']:
2038 2080 changes = getchange(rev)
2039 2081 miss = 0
2040 2082 for k in [kw.lower() for kw in opts['keyword']]:
2041 2083 if not (k in changes[1].lower() or
2042 2084 k in changes[4].lower() or
2043 2085 k in " ".join(changes[3][:20]).lower()):
2044 2086 miss = 1
2045 2087 break
2046 2088 if miss:
2047 2089 continue
2048 2090
2049 2091 br = None
2050 2092 if opts['branches']:
2051 2093 br = repo.branchlookup([repo.changelog.node(rev)])
2052 2094
2053 2095 displayer.show(rev, brinfo=br)
2054 2096 if opts['patch']:
2055 2097 prev = (parents and parents[0]) or nullid
2056 2098 dodiff(du, du, repo, prev, changenode, match=matchfn)
2057 2099 du.write("\n\n")
2058 2100 elif st == 'iter':
2059 2101 if count == limit: break
2060 2102 if du.header[rev]:
2061 2103 for args in du.header[rev]:
2062 2104 ui.write_header(*args)
2063 2105 if du.hunk[rev]:
2064 2106 count += 1
2065 2107 for args in du.hunk[rev]:
2066 2108 ui.write(*args)
2067 2109
2068 2110 def manifest(ui, repo, rev=None):
2069 2111 """output the latest or given revision of the project manifest
2070 2112
2071 2113 Print a list of version controlled files for the given revision.
2072 2114
2073 2115 The manifest is the list of files being version controlled. If no revision
2074 2116 is given then the tip is used.
2075 2117 """
2076 2118 if rev:
2077 2119 try:
2078 2120 # assume all revision numbers are for changesets
2079 2121 n = repo.lookup(rev)
2080 2122 change = repo.changelog.read(n)
2081 2123 n = change[0]
2082 2124 except hg.RepoError:
2083 2125 n = repo.manifest.lookup(rev)
2084 2126 else:
2085 2127 n = repo.manifest.tip()
2086 2128 m = repo.manifest.read(n)
2087 2129 mf = repo.manifest.readflags(n)
2088 2130 files = m.keys()
2089 2131 files.sort()
2090 2132
2091 2133 for f in files:
2092 2134 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
2093 2135
2094 2136 def merge(ui, repo, node=None, **opts):
2095 2137 """Merge working directory with another revision
2096 2138
2097 2139 Merge the contents of the current working directory and the
2098 2140 requested revision. Files that changed between either parent are
2099 2141 marked as changed for the next commit and a commit must be
2100 2142 performed before any further updates are allowed.
2101 2143 """
2102 2144 return doupdate(ui, repo, node=node, merge=True, **opts)
2103 2145
2104 2146 def outgoing(ui, repo, dest=None, **opts):
2105 2147 """show changesets not found in destination
2106 2148
2107 2149 Show changesets not found in the specified destination repository or
2108 2150 the default push location. These are the changesets that would be pushed
2109 2151 if a push was requested.
2110 2152
2111 2153 See pull for valid destination format details.
2112 2154 """
2113 2155 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2114 2156 setremoteconfig(ui, opts)
2115 2157 revs = None
2116 2158 if opts['rev']:
2117 2159 revs = [repo.lookup(rev) for rev in opts['rev']]
2118 2160
2119 2161 other = hg.repository(ui, dest)
2120 2162 o = repo.findoutgoing(other, force=opts['force'])
2121 2163 if not o:
2122 2164 ui.status(_("no changes found\n"))
2123 2165 return
2124 2166 o = repo.changelog.nodesbetween(o, revs)[0]
2125 2167 if opts['newest_first']:
2126 2168 o.reverse()
2127 2169 displayer = show_changeset(ui, repo, opts)
2128 2170 for n in o:
2129 2171 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2130 2172 if opts['no_merges'] and len(parents) == 2:
2131 2173 continue
2132 2174 displayer.show(changenode=n)
2133 2175 if opts['patch']:
2134 2176 prev = (parents and parents[0]) or nullid
2135 2177 dodiff(ui, ui, repo, prev, n)
2136 2178 ui.write("\n")
2137 2179
2138 2180 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
2139 2181 """show the parents of the working dir or revision
2140 2182
2141 2183 Print the working directory's parent revisions.
2142 2184 """
2143 2185 # legacy
2144 2186 if file_ and not rev:
2145 2187 try:
2146 2188 rev = repo.lookup(file_)
2147 2189 file_ = None
2148 2190 except hg.RepoError:
2149 2191 pass
2150 2192 else:
2151 2193 ui.warn(_("'hg parent REV' is deprecated, "
2152 2194 "please use 'hg parents -r REV instead\n"))
2153 2195
2154 2196 if rev:
2155 2197 if file_:
2156 2198 ctx = repo.filectx(file_, changeid=rev)
2157 2199 else:
2158 2200 ctx = repo.changectx(rev)
2159 2201 p = [cp.node() for cp in ctx.parents()]
2160 2202 else:
2161 2203 p = repo.dirstate.parents()
2162 2204
2163 2205 br = None
2164 2206 if branches is not None:
2165 2207 br = repo.branchlookup(p)
2166 2208 displayer = show_changeset(ui, repo, opts)
2167 2209 for n in p:
2168 2210 if n != nullid:
2169 2211 displayer.show(changenode=n, brinfo=br)
2170 2212
2171 2213 def paths(ui, repo, search=None):
2172 2214 """show definition of symbolic path names
2173 2215
2174 2216 Show definition of symbolic path name NAME. If no name is given, show
2175 2217 definition of available names.
2176 2218
2177 2219 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2178 2220 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2179 2221 """
2180 2222 if search:
2181 2223 for name, path in ui.configitems("paths"):
2182 2224 if name == search:
2183 2225 ui.write("%s\n" % path)
2184 2226 return
2185 2227 ui.warn(_("not found!\n"))
2186 2228 return 1
2187 2229 else:
2188 2230 for name, path in ui.configitems("paths"):
2189 2231 ui.write("%s = %s\n" % (name, path))
2190 2232
2191 2233 def postincoming(ui, repo, modheads, optupdate):
2192 2234 if modheads == 0:
2193 2235 return
2194 2236 if optupdate:
2195 2237 if modheads == 1:
2196 2238 return doupdate(ui, repo)
2197 2239 else:
2198 2240 ui.status(_("not updating, since new heads added\n"))
2199 2241 if modheads > 1:
2200 2242 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2201 2243 else:
2202 2244 ui.status(_("(run 'hg update' to get a working copy)\n"))
2203 2245
2204 2246 def pull(ui, repo, source="default", **opts):
2205 2247 """pull changes from the specified source
2206 2248
2207 2249 Pull changes from a remote repository to a local one.
2208 2250
2209 2251 This finds all changes from the repository at the specified path
2210 2252 or URL and adds them to the local repository. By default, this
2211 2253 does not update the copy of the project in the working directory.
2212 2254
2213 2255 Valid URLs are of the form:
2214 2256
2215 2257 local/filesystem/path
2216 2258 http://[user@]host[:port]/[path]
2217 2259 https://[user@]host[:port]/[path]
2218 2260 ssh://[user@]host[:port]/[path]
2219 2261
2220 2262 Some notes about using SSH with Mercurial:
2221 2263 - SSH requires an accessible shell account on the destination machine
2222 2264 and a copy of hg in the remote path or specified with as remotecmd.
2223 2265 - path is relative to the remote user's home directory by default.
2224 2266 Use an extra slash at the start of a path to specify an absolute path:
2225 2267 ssh://example.com//tmp/repository
2226 2268 - Mercurial doesn't use its own compression via SSH; the right thing
2227 2269 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2228 2270 Host *.mylocalnetwork.example.com
2229 2271 Compression off
2230 2272 Host *
2231 2273 Compression on
2232 2274 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2233 2275 with the --ssh command line option.
2234 2276 """
2235 2277 source = ui.expandpath(source)
2236 2278 setremoteconfig(ui, opts)
2237 2279
2238 2280 other = hg.repository(ui, source)
2239 2281 ui.status(_('pulling from %s\n') % (source))
2240 2282 revs = None
2241 2283 if opts['rev'] and not other.local():
2242 2284 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2243 2285 elif opts['rev']:
2244 2286 revs = [other.lookup(rev) for rev in opts['rev']]
2245 2287 modheads = repo.pull(other, heads=revs, force=opts['force'])
2246 2288 return postincoming(ui, repo, modheads, opts['update'])
2247 2289
2248 2290 def push(ui, repo, dest=None, **opts):
2249 2291 """push changes to the specified destination
2250 2292
2251 2293 Push changes from the local repository to the given destination.
2252 2294
2253 2295 This is the symmetrical operation for pull. It helps to move
2254 2296 changes from the current repository to a different one. If the
2255 2297 destination is local this is identical to a pull in that directory
2256 2298 from the current one.
2257 2299
2258 2300 By default, push will refuse to run if it detects the result would
2259 2301 increase the number of remote heads. This generally indicates the
2260 2302 the client has forgotten to sync and merge before pushing.
2261 2303
2262 2304 Valid URLs are of the form:
2263 2305
2264 2306 local/filesystem/path
2265 2307 ssh://[user@]host[:port]/[path]
2266 2308
2267 2309 Look at the help text for the pull command for important details
2268 2310 about ssh:// URLs.
2269 2311
2270 2312 Pushing to http:// and https:// URLs is possible, too, if this
2271 2313 feature is enabled on the remote Mercurial server.
2272 2314 """
2273 2315 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2274 2316 setremoteconfig(ui, opts)
2275 2317
2276 2318 other = hg.repository(ui, dest)
2277 2319 ui.status('pushing to %s\n' % (dest))
2278 2320 revs = None
2279 2321 if opts['rev']:
2280 2322 revs = [repo.lookup(rev) for rev in opts['rev']]
2281 2323 r = repo.push(other, opts['force'], revs=revs)
2282 2324 return r == 0
2283 2325
2284 2326 def rawcommit(ui, repo, *flist, **rc):
2285 2327 """raw commit interface (DEPRECATED)
2286 2328
2287 2329 (DEPRECATED)
2288 2330 Lowlevel commit, for use in helper scripts.
2289 2331
2290 2332 This command is not intended to be used by normal users, as it is
2291 2333 primarily useful for importing from other SCMs.
2292 2334
2293 2335 This command is now deprecated and will be removed in a future
2294 2336 release, please use debugsetparents and commit instead.
2295 2337 """
2296 2338
2297 2339 ui.warn(_("(the rawcommit command is deprecated)\n"))
2298 2340
2299 2341 message = rc['message']
2300 2342 if not message and rc['logfile']:
2301 2343 try:
2302 2344 message = open(rc['logfile']).read()
2303 2345 except IOError:
2304 2346 pass
2305 2347 if not message and not rc['logfile']:
2306 2348 raise util.Abort(_("missing commit message"))
2307 2349
2308 2350 files = relpath(repo, list(flist))
2309 2351 if rc['files']:
2310 2352 files += open(rc['files']).read().splitlines()
2311 2353
2312 2354 rc['parent'] = map(repo.lookup, rc['parent'])
2313 2355
2314 2356 try:
2315 2357 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2316 2358 except ValueError, inst:
2317 2359 raise util.Abort(str(inst))
2318 2360
2319 2361 def recover(ui, repo):
2320 2362 """roll back an interrupted transaction
2321 2363
2322 2364 Recover from an interrupted commit or pull.
2323 2365
2324 2366 This command tries to fix the repository status after an interrupted
2325 2367 operation. It should only be necessary when Mercurial suggests it.
2326 2368 """
2327 2369 if repo.recover():
2328 2370 return repo.verify()
2329 2371 return 1
2330 2372
2331 2373 def remove(ui, repo, *pats, **opts):
2332 2374 """remove the specified files on the next commit
2333 2375
2334 2376 Schedule the indicated files for removal from the repository.
2335 2377
2336 2378 This command schedules the files to be removed at the next commit.
2337 2379 This only removes files from the current branch, not from the
2338 2380 entire project history. If the files still exist in the working
2339 2381 directory, they will be deleted from it. If invoked with --after,
2340 2382 files that have been manually deleted are marked as removed.
2341 2383
2342 2384 Modified files and added files are not removed by default. To
2343 2385 remove them, use the -f/--force option.
2344 2386 """
2345 2387 names = []
2346 2388 if not opts['after'] and not pats:
2347 2389 raise util.Abort(_('no files specified'))
2348 2390 files, matchfn, anypats = matchpats(repo, pats, opts)
2349 2391 exact = dict.fromkeys(files)
2350 2392 mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn))
2351 2393 modified, added, removed, deleted, unknown = mardu
2352 2394 remove, forget = [], []
2353 2395 for src, abs, rel, exact in walk(repo, pats, opts):
2354 2396 reason = None
2355 2397 if abs not in deleted and opts['after']:
2356 2398 reason = _('is still present')
2357 2399 elif abs in modified and not opts['force']:
2358 2400 reason = _('is modified (use -f to force removal)')
2359 2401 elif abs in added:
2360 2402 if opts['force']:
2361 2403 forget.append(abs)
2362 2404 continue
2363 2405 reason = _('has been marked for add (use -f to force removal)')
2364 2406 elif abs in unknown:
2365 2407 reason = _('is not managed')
2366 2408 elif abs in removed:
2367 2409 continue
2368 2410 if reason:
2369 2411 if exact:
2370 2412 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2371 2413 else:
2372 2414 if ui.verbose or not exact:
2373 2415 ui.status(_('removing %s\n') % rel)
2374 2416 remove.append(abs)
2375 2417 repo.forget(forget)
2376 2418 repo.remove(remove, unlink=not opts['after'])
2377 2419
2378 2420 def rename(ui, repo, *pats, **opts):
2379 2421 """rename files; equivalent of copy + remove
2380 2422
2381 2423 Mark dest as copies of sources; mark sources for deletion. If
2382 2424 dest is a directory, copies are put in that directory. If dest is
2383 2425 a file, there can only be one source.
2384 2426
2385 2427 By default, this command copies the contents of files as they
2386 2428 stand in the working directory. If invoked with --after, the
2387 2429 operation is recorded, but no copying is performed.
2388 2430
2389 2431 This command takes effect in the next commit.
2390 2432
2391 2433 NOTE: This command should be treated as experimental. While it
2392 2434 should properly record rename files, this information is not yet
2393 2435 fully used by merge, nor fully reported by log.
2394 2436 """
2395 2437 wlock = repo.wlock(0)
2396 2438 errs, copied = docopy(ui, repo, pats, opts, wlock)
2397 2439 names = []
2398 2440 for abs, rel, exact in copied:
2399 2441 if ui.verbose or not exact:
2400 2442 ui.status(_('removing %s\n') % rel)
2401 2443 names.append(abs)
2402 2444 if not opts.get('dry_run'):
2403 2445 repo.remove(names, True, wlock)
2404 2446 return errs
2405 2447
2406 2448 def revert(ui, repo, *pats, **opts):
2407 2449 """revert files or dirs to their states as of some revision
2408 2450
2409 2451 With no revision specified, revert the named files or directories
2410 2452 to the contents they had in the parent of the working directory.
2411 2453 This restores the contents of the affected files to an unmodified
2412 2454 state. If the working directory has two parents, you must
2413 2455 explicitly specify the revision to revert to.
2414 2456
2415 2457 Modified files are saved with a .orig suffix before reverting.
2416 2458 To disable these backups, use --no-backup.
2417 2459
2418 2460 Using the -r option, revert the given files or directories to
2419 2461 their contents as of a specific revision. This can be helpful to"roll
2420 2462 back" some or all of a change that should not have been committed.
2421 2463
2422 2464 Revert modifies the working directory. It does not commit any
2423 2465 changes, or change the parent of the working directory. If you
2424 2466 revert to a revision other than the parent of the working
2425 2467 directory, the reverted files will thus appear modified
2426 2468 afterwards.
2427 2469
2428 2470 If a file has been deleted, it is recreated. If the executable
2429 2471 mode of a file was changed, it is reset.
2430 2472
2431 2473 If names are given, all files matching the names are reverted.
2432 2474
2433 2475 If no arguments are given, all files in the repository are reverted.
2434 2476 """
2435 2477 parent, p2 = repo.dirstate.parents()
2436 2478 if opts['rev']:
2437 2479 node = repo.lookup(opts['rev'])
2438 2480 elif p2 != nullid:
2439 2481 raise util.Abort(_('working dir has two parents; '
2440 2482 'you must specify the revision to revert to'))
2441 2483 else:
2442 2484 node = parent
2443 2485 mf = repo.manifest.read(repo.changelog.read(node)[0])
2444 2486 if node == parent:
2445 2487 pmf = mf
2446 2488 else:
2447 2489 pmf = None
2448 2490
2449 2491 wlock = repo.wlock()
2450 2492
2451 2493 # need all matching names in dirstate and manifest of target rev,
2452 2494 # so have to walk both. do not print errors if files exist in one
2453 2495 # but not other.
2454 2496
2455 2497 names = {}
2456 2498 target_only = {}
2457 2499
2458 2500 # walk dirstate.
2459 2501
2460 2502 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
2461 2503 names[abs] = (rel, exact)
2462 2504 if src == 'b':
2463 2505 target_only[abs] = True
2464 2506
2465 2507 # walk target manifest.
2466 2508
2467 2509 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
2468 2510 badmatch=names.has_key):
2469 2511 if abs in names: continue
2470 2512 names[abs] = (rel, exact)
2471 2513 target_only[abs] = True
2472 2514
2473 2515 changes = repo.changes(match=names.has_key, wlock=wlock)
2474 2516 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2475 2517
2476 2518 revert = ([], _('reverting %s\n'))
2477 2519 add = ([], _('adding %s\n'))
2478 2520 remove = ([], _('removing %s\n'))
2479 2521 forget = ([], _('forgetting %s\n'))
2480 2522 undelete = ([], _('undeleting %s\n'))
2481 2523 update = {}
2482 2524
2483 2525 disptable = (
2484 2526 # dispatch table:
2485 2527 # file state
2486 2528 # action if in target manifest
2487 2529 # action if not in target manifest
2488 2530 # make backup if in target manifest
2489 2531 # make backup if not in target manifest
2490 2532 (modified, revert, remove, True, True),
2491 2533 (added, revert, forget, True, False),
2492 2534 (removed, undelete, None, False, False),
2493 2535 (deleted, revert, remove, False, False),
2494 2536 (unknown, add, None, True, False),
2495 2537 (target_only, add, None, False, False),
2496 2538 )
2497 2539
2498 2540 entries = names.items()
2499 2541 entries.sort()
2500 2542
2501 2543 for abs, (rel, exact) in entries:
2502 2544 mfentry = mf.get(abs)
2503 2545 def handle(xlist, dobackup):
2504 2546 xlist[0].append(abs)
2505 2547 update[abs] = 1
2506 2548 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2507 2549 bakname = "%s.orig" % rel
2508 2550 ui.note(_('saving current version of %s as %s\n') %
2509 2551 (rel, bakname))
2510 2552 if not opts.get('dry_run'):
2511 2553 shutil.copyfile(rel, bakname)
2512 2554 shutil.copymode(rel, bakname)
2513 2555 if ui.verbose or not exact:
2514 2556 ui.status(xlist[1] % rel)
2515 2557 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2516 2558 if abs not in table: continue
2517 2559 # file has changed in dirstate
2518 2560 if mfentry:
2519 2561 handle(hitlist, backuphit)
2520 2562 elif misslist is not None:
2521 2563 handle(misslist, backupmiss)
2522 2564 else:
2523 2565 if exact: ui.warn(_('file not managed: %s\n' % rel))
2524 2566 break
2525 2567 else:
2526 2568 # file has not changed in dirstate
2527 2569 if node == parent:
2528 2570 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2529 2571 continue
2530 2572 if pmf is None:
2531 2573 # only need parent manifest in this unlikely case,
2532 2574 # so do not read by default
2533 2575 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2534 2576 if abs in pmf:
2535 2577 if mfentry:
2536 2578 # if version of file is same in parent and target
2537 2579 # manifests, do nothing
2538 2580 if pmf[abs] != mfentry:
2539 2581 handle(revert, False)
2540 2582 else:
2541 2583 handle(remove, False)
2542 2584
2543 2585 if not opts.get('dry_run'):
2544 2586 repo.dirstate.forget(forget[0])
2545 2587 r = repo.update(node, False, True, update.has_key, False, wlock=wlock,
2546 2588 show_stats=False)
2547 2589 repo.dirstate.update(add[0], 'a')
2548 2590 repo.dirstate.update(undelete[0], 'n')
2549 2591 repo.dirstate.update(remove[0], 'r')
2550 2592 return r
2551 2593
2552 2594 def rollback(ui, repo):
2553 2595 """roll back the last transaction in this repository
2554 2596
2555 2597 Roll back the last transaction in this repository, restoring the
2556 2598 project to its state prior to the transaction.
2557 2599
2558 2600 Transactions are used to encapsulate the effects of all commands
2559 2601 that create new changesets or propagate existing changesets into a
2560 2602 repository. For example, the following commands are transactional,
2561 2603 and their effects can be rolled back:
2562 2604
2563 2605 commit
2564 2606 import
2565 2607 pull
2566 2608 push (with this repository as destination)
2567 2609 unbundle
2568 2610
2569 2611 This command should be used with care. There is only one level of
2570 2612 rollback, and there is no way to undo a rollback.
2571 2613
2572 2614 This command is not intended for use on public repositories. Once
2573 2615 changes are visible for pull by other users, rolling a transaction
2574 2616 back locally is ineffective (someone else may already have pulled
2575 2617 the changes). Furthermore, a race is possible with readers of the
2576 2618 repository; for example an in-progress pull from the repository
2577 2619 may fail if a rollback is performed.
2578 2620 """
2579 2621 repo.rollback()
2580 2622
2581 2623 def root(ui, repo):
2582 2624 """print the root (top) of the current working dir
2583 2625
2584 2626 Print the root directory of the current repository.
2585 2627 """
2586 2628 ui.write(repo.root + "\n")
2587 2629
2588 2630 def serve(ui, repo, **opts):
2589 2631 """export the repository via HTTP
2590 2632
2591 2633 Start a local HTTP repository browser and pull server.
2592 2634
2593 2635 By default, the server logs accesses to stdout and errors to
2594 2636 stderr. Use the "-A" and "-E" options to log to files.
2595 2637 """
2596 2638
2597 2639 if opts["stdio"]:
2598 2640 if repo is None:
2599 2641 raise hg.RepoError(_('no repo found'))
2600 2642 s = sshserver.sshserver(ui, repo)
2601 2643 s.serve_forever()
2602 2644
2603 2645 optlist = ("name templates style address port ipv6"
2604 2646 " accesslog errorlog webdir_conf")
2605 2647 for o in optlist.split():
2606 2648 if opts[o]:
2607 2649 ui.setconfig("web", o, opts[o])
2608 2650
2609 2651 if repo is None and not ui.config("web", "webdir_conf"):
2610 2652 raise hg.RepoError(_('no repo found'))
2611 2653
2612 2654 if opts['daemon'] and not opts['daemon_pipefds']:
2613 2655 rfd, wfd = os.pipe()
2614 2656 args = sys.argv[:]
2615 2657 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2616 2658 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2617 2659 args[0], args)
2618 2660 os.close(wfd)
2619 2661 os.read(rfd, 1)
2620 2662 os._exit(0)
2621 2663
2622 2664 try:
2623 2665 httpd = hgweb.server.create_server(ui, repo)
2624 2666 except socket.error, inst:
2625 2667 raise util.Abort(_('cannot start server: ') + inst.args[1])
2626 2668
2627 2669 if ui.verbose:
2628 2670 addr, port = httpd.socket.getsockname()
2629 2671 if addr == '0.0.0.0':
2630 2672 addr = socket.gethostname()
2631 2673 else:
2632 2674 try:
2633 2675 addr = socket.gethostbyaddr(addr)[0]
2634 2676 except socket.error:
2635 2677 pass
2636 2678 if port != 80:
2637 2679 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2638 2680 else:
2639 2681 ui.status(_('listening at http://%s/\n') % addr)
2640 2682
2641 2683 if opts['pid_file']:
2642 2684 fp = open(opts['pid_file'], 'w')
2643 2685 fp.write(str(os.getpid()) + '\n')
2644 2686 fp.close()
2645 2687
2646 2688 if opts['daemon_pipefds']:
2647 2689 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2648 2690 os.close(rfd)
2649 2691 os.write(wfd, 'y')
2650 2692 os.close(wfd)
2651 2693 sys.stdout.flush()
2652 2694 sys.stderr.flush()
2653 2695 fd = os.open(util.nulldev, os.O_RDWR)
2654 2696 if fd != 0: os.dup2(fd, 0)
2655 2697 if fd != 1: os.dup2(fd, 1)
2656 2698 if fd != 2: os.dup2(fd, 2)
2657 2699 if fd not in (0, 1, 2): os.close(fd)
2658 2700
2659 2701 httpd.serve_forever()
2660 2702
2661 2703 def status(ui, repo, *pats, **opts):
2662 2704 """show changed files in the working directory
2663 2705
2664 2706 Show status of files in the repository. If names are given, only
2665 2707 files that match are shown. Files that are clean or ignored, are
2666 2708 not listed unless -c (clean), -i (ignored) or -A is given.
2667 2709
2668 2710 The codes used to show the status of files are:
2669 2711 M = modified
2670 2712 A = added
2671 2713 R = removed
2672 2714 C = clean
2673 2715 ! = deleted, but still tracked
2674 2716 ? = not tracked
2675 2717 I = ignored (not shown by default)
2676 2718 = the previous added file was copied from here
2677 2719 """
2678 2720
2679 2721 all = opts['all']
2680 2722
2681 2723 files, matchfn, anypats = matchpats(repo, pats, opts)
2682 2724 cwd = (pats and repo.getcwd()) or ''
2683 2725 modified, added, removed, deleted, unknown, ignored, clean = [
2684 2726 [util.pathto(cwd, x) for x in n]
2685 2727 for n in repo.status(files=files, match=matchfn,
2686 2728 list_ignored=all or opts['ignored'],
2687 2729 list_clean=all or opts['clean'])]
2688 2730
2689 2731 changetypes = (('modified', 'M', modified),
2690 2732 ('added', 'A', added),
2691 2733 ('removed', 'R', removed),
2692 2734 ('deleted', '!', deleted),
2693 2735 ('unknown', '?', unknown),
2694 2736 ('ignored', 'I', ignored))
2695 2737
2696 2738 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2697 2739
2698 2740 end = opts['print0'] and '\0' or '\n'
2699 2741
2700 2742 for opt, char, changes in ([ct for ct in explicit_changetypes
2701 2743 if all or opts[ct[0]]]
2702 2744 or changetypes):
2703 2745 if opts['no_status']:
2704 2746 format = "%%s%s" % end
2705 2747 else:
2706 2748 format = "%s %%s%s" % (char, end)
2707 2749
2708 2750 for f in changes:
2709 2751 ui.write(format % f)
2710 2752 if ((all or opts.get('copies')) and not opts.get('no_status')
2711 2753 and opt == 'added' and repo.dirstate.copies.has_key(f)):
2712 2754 ui.write(' %s%s' % (repo.dirstate.copies[f], end))
2713 2755
2714 2756 def tag(ui, repo, name, rev_=None, **opts):
2715 2757 """add a tag for the current tip or a given revision
2716 2758
2717 2759 Name a particular revision using <name>.
2718 2760
2719 2761 Tags are used to name particular revisions of the repository and are
2720 2762 very useful to compare different revision, to go back to significant
2721 2763 earlier versions or to mark branch points as releases, etc.
2722 2764
2723 2765 If no revision is given, the parent of the working directory is used.
2724 2766
2725 2767 To facilitate version control, distribution, and merging of tags,
2726 2768 they are stored as a file named ".hgtags" which is managed
2727 2769 similarly to other project files and can be hand-edited if
2728 2770 necessary. The file '.hg/localtags' is used for local tags (not
2729 2771 shared among repositories).
2730 2772 """
2731 2773 if name == "tip":
2732 2774 raise util.Abort(_("the name 'tip' is reserved"))
2733 2775 if rev_ is not None:
2734 2776 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2735 2777 "please use 'hg tag [-r REV] NAME' instead\n"))
2736 2778 if opts['rev']:
2737 2779 raise util.Abort(_("use only one form to specify the revision"))
2738 2780 if opts['rev']:
2739 2781 rev_ = opts['rev']
2740 2782 if rev_:
2741 2783 r = hex(repo.lookup(rev_))
2742 2784 else:
2743 2785 p1, p2 = repo.dirstate.parents()
2744 2786 if p1 == nullid:
2745 2787 raise util.Abort(_('no revision to tag'))
2746 2788 if p2 != nullid:
2747 2789 raise util.Abort(_('outstanding uncommitted merges'))
2748 2790 r = hex(p1)
2749 2791
2750 2792 repo.tag(name, r, opts['local'], opts['message'], opts['user'],
2751 2793 opts['date'])
2752 2794
2753 2795 def tags(ui, repo):
2754 2796 """list repository tags
2755 2797
2756 2798 List the repository tags.
2757 2799
2758 2800 This lists both regular and local tags.
2759 2801 """
2760 2802
2761 2803 l = repo.tagslist()
2762 2804 l.reverse()
2763 2805 for t, n in l:
2764 2806 try:
2765 2807 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2766 2808 except KeyError:
2767 2809 r = " ?:?"
2768 2810 if ui.quiet:
2769 2811 ui.write("%s\n" % t)
2770 2812 else:
2771 2813 ui.write("%-30s %s\n" % (t, r))
2772 2814
2773 2815 def tip(ui, repo, **opts):
2774 2816 """show the tip revision
2775 2817
2776 2818 Show the tip revision.
2777 2819 """
2778 2820 n = repo.changelog.tip()
2779 2821 br = None
2780 2822 if opts['branches']:
2781 2823 br = repo.branchlookup([n])
2782 2824 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2783 2825 if opts['patch']:
2784 2826 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2785 2827
2786 2828 def unbundle(ui, repo, fname, **opts):
2787 2829 """apply a changegroup file
2788 2830
2789 2831 Apply a compressed changegroup file generated by the bundle
2790 2832 command.
2791 2833 """
2792 2834 f = urllib.urlopen(fname)
2793 2835
2794 2836 header = f.read(6)
2795 2837 if not header.startswith("HG"):
2796 2838 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2797 2839 elif not header.startswith("HG10"):
2798 2840 raise util.Abort(_("%s: unknown bundle version") % fname)
2799 2841 elif header == "HG10BZ":
2800 2842 def generator(f):
2801 2843 zd = bz2.BZ2Decompressor()
2802 2844 zd.decompress("BZ")
2803 2845 for chunk in f:
2804 2846 yield zd.decompress(chunk)
2805 2847 elif header == "HG10UN":
2806 2848 def generator(f):
2807 2849 for chunk in f:
2808 2850 yield chunk
2809 2851 else:
2810 2852 raise util.Abort(_("%s: unknown bundle compression type")
2811 2853 % fname)
2812 2854 gen = generator(util.filechunkiter(f, 4096))
2813 2855 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2814 2856 'bundle:' + fname)
2815 2857 return postincoming(ui, repo, modheads, opts['update'])
2816 2858
2817 2859 def undo(ui, repo):
2818 2860 """undo the last commit or pull (DEPRECATED)
2819 2861
2820 2862 (DEPRECATED)
2821 2863 This command is now deprecated and will be removed in a future
2822 2864 release. Please use the rollback command instead. For usage
2823 2865 instructions, see the rollback command.
2824 2866 """
2825 2867 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2826 2868 repo.rollback()
2827 2869
2828 2870 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2829 2871 branch=None, **opts):
2830 2872 """update or merge working directory
2831 2873
2832 2874 Update the working directory to the specified revision.
2833 2875
2834 2876 If there are no outstanding changes in the working directory and
2835 2877 there is a linear relationship between the current version and the
2836 2878 requested version, the result is the requested version.
2837 2879
2838 2880 To merge the working directory with another revision, use the
2839 2881 merge command.
2840 2882
2841 2883 By default, update will refuse to run if doing so would require
2842 2884 merging or discarding local changes.
2843 2885 """
2844 2886 if merge:
2845 2887 ui.warn(_('(the -m/--merge option is deprecated; '
2846 2888 'use the merge command instead)\n'))
2847 2889 return doupdate(ui, repo, node, merge, clean, force, branch, **opts)
2848 2890
2849 2891 def doupdate(ui, repo, node=None, merge=False, clean=False, force=None,
2850 2892 branch=None, **opts):
2851 2893 if branch:
2852 2894 br = repo.branchlookup(branch=branch)
2853 2895 found = []
2854 2896 for x in br:
2855 2897 if branch in br[x]:
2856 2898 found.append(x)
2857 2899 if len(found) > 1:
2858 2900 ui.warn(_("Found multiple heads for %s\n") % branch)
2859 2901 for x in found:
2860 2902 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br)
2861 2903 return 1
2862 2904 if len(found) == 1:
2863 2905 node = found[0]
2864 2906 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2865 2907 else:
2866 2908 ui.warn(_("branch %s not found\n") % (branch))
2867 2909 return 1
2868 2910 else:
2869 2911 node = node and repo.lookup(node) or repo.changelog.tip()
2870 2912 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2871 2913
2872 2914 def verify(ui, repo):
2873 2915 """verify the integrity of the repository
2874 2916
2875 2917 Verify the integrity of the current repository.
2876 2918
2877 2919 This will perform an extensive check of the repository's
2878 2920 integrity, validating the hashes and checksums of each entry in
2879 2921 the changelog, manifest, and tracked files, as well as the
2880 2922 integrity of their crosslinks and indices.
2881 2923 """
2882 2924 return repo.verify()
2883 2925
2884 2926 # Command options and aliases are listed here, alphabetically
2885 2927
2886 2928 table = {
2887 2929 "^add":
2888 2930 (add,
2889 2931 [('I', 'include', [], _('include names matching the given patterns')),
2890 2932 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2891 2933 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2892 2934 _('hg add [OPTION]... [FILE]...')),
2893 2935 "debugaddremove|addremove":
2894 2936 (addremove,
2895 2937 [('I', 'include', [], _('include names matching the given patterns')),
2896 2938 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2897 2939 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2898 2940 _('hg addremove [OPTION]... [FILE]...')),
2899 2941 "^annotate":
2900 2942 (annotate,
2901 2943 [('r', 'rev', '', _('annotate the specified revision')),
2902 2944 ('a', 'text', None, _('treat all files as text')),
2903 2945 ('u', 'user', None, _('list the author')),
2904 2946 ('d', 'date', None, _('list the date')),
2905 2947 ('n', 'number', None, _('list the revision number (default)')),
2906 2948 ('c', 'changeset', None, _('list the changeset')),
2907 2949 ('I', 'include', [], _('include names matching the given patterns')),
2908 2950 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2909 2951 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2910 2952 "archive":
2911 2953 (archive,
2912 2954 [('', 'no-decode', None, _('do not pass files through decoders')),
2913 2955 ('p', 'prefix', '', _('directory prefix for files in archive')),
2914 2956 ('r', 'rev', '', _('revision to distribute')),
2915 2957 ('t', 'type', '', _('type of distribution to create')),
2916 2958 ('I', 'include', [], _('include names matching the given patterns')),
2917 2959 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2918 2960 _('hg archive [OPTION]... DEST')),
2919 2961 "backout":
2920 2962 (backout,
2921 2963 [('', 'merge', None,
2922 2964 _('merge with old dirstate parent after backout')),
2923 2965 ('m', 'message', '', _('use <text> as commit message')),
2924 2966 ('l', 'logfile', '', _('read commit message from <file>')),
2925 2967 ('d', 'date', '', _('record datecode as commit date')),
2926 2968 ('', 'parent', '', _('parent to choose when backing out merge')),
2927 2969 ('u', 'user', '', _('record user as committer')),
2928 2970 ('I', 'include', [], _('include names matching the given patterns')),
2929 2971 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2930 2972 _('hg backout [OPTION]... REV')),
2931 2973 "bundle":
2932 2974 (bundle,
2933 2975 [('f', 'force', None,
2934 2976 _('run even when remote repository is unrelated'))],
2935 2977 _('hg bundle FILE DEST')),
2936 2978 "cat":
2937 2979 (cat,
2938 2980 [('o', 'output', '', _('print output to file with formatted name')),
2939 2981 ('r', 'rev', '', _('print the given revision')),
2940 2982 ('I', 'include', [], _('include names matching the given patterns')),
2941 2983 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2942 2984 _('hg cat [OPTION]... FILE...')),
2943 2985 "^clone":
2944 2986 (clone,
2945 2987 [('U', 'noupdate', None, _('do not update the new working directory')),
2946 2988 ('r', 'rev', [],
2947 2989 _('a changeset you would like to have after cloning')),
2948 2990 ('', 'pull', None, _('use pull protocol to copy metadata')),
2949 2991 ('', 'uncompressed', None,
2950 2992 _('use uncompressed transfer (fast over LAN)')),
2951 2993 ('e', 'ssh', '', _('specify ssh command to use')),
2952 2994 ('', 'remotecmd', '',
2953 2995 _('specify hg command to run on the remote side'))],
2954 2996 _('hg clone [OPTION]... SOURCE [DEST]')),
2955 2997 "^commit|ci":
2956 2998 (commit,
2957 2999 [('A', 'addremove', None,
2958 3000 _('mark new/missing files as added/removed before committing')),
2959 3001 ('m', 'message', '', _('use <text> as commit message')),
2960 3002 ('l', 'logfile', '', _('read the commit message from <file>')),
2961 3003 ('d', 'date', '', _('record datecode as commit date')),
2962 3004 ('u', 'user', '', _('record user as commiter')),
2963 3005 ('I', 'include', [], _('include names matching the given patterns')),
2964 3006 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2965 3007 _('hg commit [OPTION]... [FILE]...')),
2966 3008 "copy|cp":
2967 3009 (copy,
2968 3010 [('A', 'after', None, _('record a copy that has already occurred')),
2969 3011 ('f', 'force', None,
2970 3012 _('forcibly copy over an existing managed file')),
2971 3013 ('I', 'include', [], _('include names matching the given patterns')),
2972 3014 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2973 3015 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2974 3016 _('hg copy [OPTION]... [SOURCE]... DEST')),
2975 3017 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2976 3018 "debugcomplete":
2977 3019 (debugcomplete,
2978 3020 [('o', 'options', None, _('show the command options'))],
2979 3021 _('debugcomplete [-o] CMD')),
2980 3022 "debugrebuildstate":
2981 3023 (debugrebuildstate,
2982 3024 [('r', 'rev', '', _('revision to rebuild to'))],
2983 3025 _('debugrebuildstate [-r REV] [REV]')),
2984 3026 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2985 3027 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2986 3028 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2987 3029 "debugstate": (debugstate, [], _('debugstate')),
2988 3030 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2989 3031 "debugindex": (debugindex, [], _('debugindex FILE')),
2990 3032 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2991 3033 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2992 3034 "debugwalk":
2993 3035 (debugwalk,
2994 3036 [('I', 'include', [], _('include names matching the given patterns')),
2995 3037 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2996 3038 _('debugwalk [OPTION]... [FILE]...')),
2997 3039 "^diff":
2998 3040 (diff,
2999 3041 [('r', 'rev', [], _('revision')),
3000 3042 ('a', 'text', None, _('treat all files as text')),
3001 3043 ('p', 'show-function', None,
3002 3044 _('show which function each change is in')),
3003 3045 ('w', 'ignore-all-space', None,
3004 3046 _('ignore white space when comparing lines')),
3005 3047 ('b', 'ignore-space-change', None,
3006 3048 _('ignore changes in the amount of white space')),
3007 3049 ('B', 'ignore-blank-lines', None,
3008 3050 _('ignore changes whose lines are all blank')),
3009 3051 ('I', 'include', [], _('include names matching the given patterns')),
3010 3052 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3011 3053 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
3012 3054 "^export":
3013 3055 (export,
3014 3056 [('o', 'output', '', _('print output to file with formatted name')),
3015 3057 ('a', 'text', None, _('treat all files as text')),
3016 3058 ('', 'switch-parent', None, _('diff against the second parent'))],
3017 3059 _('hg export [-a] [-o OUTFILESPEC] REV...')),
3018 3060 "debugforget|forget":
3019 3061 (forget,
3020 3062 [('I', 'include', [], _('include names matching the given patterns')),
3021 3063 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3022 3064 _('hg forget [OPTION]... FILE...')),
3023 3065 "grep":
3024 3066 (grep,
3025 3067 [('0', 'print0', None, _('end fields with NUL')),
3026 3068 ('', 'all', None, _('print all revisions that match')),
3027 3069 ('i', 'ignore-case', None, _('ignore case when matching')),
3028 3070 ('l', 'files-with-matches', None,
3029 3071 _('print only filenames and revs that match')),
3030 3072 ('n', 'line-number', None, _('print matching line numbers')),
3031 3073 ('r', 'rev', [], _('search in given revision range')),
3032 3074 ('u', 'user', None, _('print user who committed change')),
3033 3075 ('I', 'include', [], _('include names matching the given patterns')),
3034 3076 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3035 3077 _('hg grep [OPTION]... PATTERN [FILE]...')),
3036 3078 "heads":
3037 3079 (heads,
3038 3080 [('b', 'branches', None, _('show branches')),
3039 3081 ('', 'style', '', _('display using template map file')),
3040 3082 ('r', 'rev', '', _('show only heads which are descendants of rev')),
3041 3083 ('', 'template', '', _('display with template'))],
3042 3084 _('hg heads [-b] [-r <rev>]')),
3043 3085 "help": (help_, [], _('hg help [COMMAND]')),
3044 3086 "identify|id": (identify, [], _('hg identify')),
3045 3087 "import|patch":
3046 3088 (import_,
3047 3089 [('p', 'strip', 1,
3048 3090 _('directory strip option for patch. This has the same\n'
3049 3091 'meaning as the corresponding patch option')),
3050 3092 ('m', 'message', '', _('use <text> as commit message')),
3051 3093 ('b', 'base', '', _('base path')),
3052 3094 ('f', 'force', None,
3053 3095 _('skip check for outstanding uncommitted changes'))],
3054 3096 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
3055 3097 "incoming|in": (incoming,
3056 3098 [('M', 'no-merges', None, _('do not show merges')),
3057 3099 ('f', 'force', None,
3058 3100 _('run even when remote repository is unrelated')),
3059 3101 ('', 'style', '', _('display using template map file')),
3060 3102 ('n', 'newest-first', None, _('show newest record first')),
3061 3103 ('', 'bundle', '', _('file to store the bundles into')),
3062 3104 ('p', 'patch', None, _('show patch')),
3063 3105 ('r', 'rev', [], _('a specific revision you would like to pull')),
3064 3106 ('', 'template', '', _('display with template')),
3065 3107 ('e', 'ssh', '', _('specify ssh command to use')),
3066 3108 ('', 'remotecmd', '',
3067 3109 _('specify hg command to run on the remote side'))],
3068 3110 _('hg incoming [-p] [-n] [-M] [-r REV]...'
3069 3111 ' [--bundle FILENAME] [SOURCE]')),
3070 3112 "^init":
3071 3113 (init,
3072 3114 [('e', 'ssh', '', _('specify ssh command to use')),
3073 3115 ('', 'remotecmd', '',
3074 3116 _('specify hg command to run on the remote side'))],
3075 3117 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
3076 3118 "locate":
3077 3119 (locate,
3078 3120 [('r', 'rev', '', _('search the repository as it stood at rev')),
3079 3121 ('0', 'print0', None,
3080 3122 _('end filenames with NUL, for use with xargs')),
3081 3123 ('f', 'fullpath', None,
3082 3124 _('print complete paths from the filesystem root')),
3083 3125 ('I', 'include', [], _('include names matching the given patterns')),
3084 3126 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3085 3127 _('hg locate [OPTION]... [PATTERN]...')),
3086 3128 "^log|history":
3087 3129 (log,
3088 3130 [('b', 'branches', None, _('show branches')),
3089 3131 ('f', 'follow', None,
3090 _('follow file history across copies and renames')),
3132 _('follow changeset history, or file history across copies and renames')),
3091 3133 ('k', 'keyword', [], _('search for a keyword')),
3092 3134 ('l', 'limit', '', _('limit number of changes displayed')),
3093 3135 ('r', 'rev', [], _('show the specified revision or range')),
3094 3136 ('M', 'no-merges', None, _('do not show merges')),
3095 3137 ('', 'style', '', _('display using template map file')),
3096 3138 ('m', 'only-merges', None, _('show only merges')),
3097 3139 ('p', 'patch', None, _('show patch')),
3098 3140 ('', 'template', '', _('display with template')),
3099 3141 ('I', 'include', [], _('include names matching the given patterns')),
3100 3142 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3101 3143 _('hg log [OPTION]... [FILE]')),
3102 3144 "manifest": (manifest, [], _('hg manifest [REV]')),
3103 3145 "merge":
3104 3146 (merge,
3105 3147 [('b', 'branch', '', _('merge with head of a specific branch')),
3106 3148 ('f', 'force', None, _('force a merge with outstanding changes'))],
3107 3149 _('hg merge [-b TAG] [-f] [REV]')),
3108 3150 "outgoing|out": (outgoing,
3109 3151 [('M', 'no-merges', None, _('do not show merges')),
3110 3152 ('f', 'force', None,
3111 3153 _('run even when remote repository is unrelated')),
3112 3154 ('p', 'patch', None, _('show patch')),
3113 3155 ('', 'style', '', _('display using template map file')),
3114 3156 ('r', 'rev', [], _('a specific revision you would like to push')),
3115 3157 ('n', 'newest-first', None, _('show newest record first')),
3116 3158 ('', 'template', '', _('display with template')),
3117 3159 ('e', 'ssh', '', _('specify ssh command to use')),
3118 3160 ('', 'remotecmd', '',
3119 3161 _('specify hg command to run on the remote side'))],
3120 3162 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
3121 3163 "^parents":
3122 3164 (parents,
3123 3165 [('b', 'branches', None, _('show branches')),
3124 3166 ('r', 'rev', '', _('show parents from the specified rev')),
3125 3167 ('', 'style', '', _('display using template map file')),
3126 3168 ('', 'template', '', _('display with template'))],
3127 3169 _('hg parents [-b] [-r REV] [FILE]')),
3128 3170 "paths": (paths, [], _('hg paths [NAME]')),
3129 3171 "^pull":
3130 3172 (pull,
3131 3173 [('u', 'update', None,
3132 3174 _('update the working directory to tip after pull')),
3133 3175 ('e', 'ssh', '', _('specify ssh command to use')),
3134 3176 ('f', 'force', None,
3135 3177 _('run even when remote repository is unrelated')),
3136 3178 ('r', 'rev', [], _('a specific revision you would like to pull')),
3137 3179 ('', 'remotecmd', '',
3138 3180 _('specify hg command to run on the remote side'))],
3139 3181 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
3140 3182 "^push":
3141 3183 (push,
3142 3184 [('f', 'force', None, _('force push')),
3143 3185 ('e', 'ssh', '', _('specify ssh command to use')),
3144 3186 ('r', 'rev', [], _('a specific revision you would like to push')),
3145 3187 ('', 'remotecmd', '',
3146 3188 _('specify hg command to run on the remote side'))],
3147 3189 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
3148 3190 "debugrawcommit|rawcommit":
3149 3191 (rawcommit,
3150 3192 [('p', 'parent', [], _('parent')),
3151 3193 ('d', 'date', '', _('date code')),
3152 3194 ('u', 'user', '', _('user')),
3153 3195 ('F', 'files', '', _('file list')),
3154 3196 ('m', 'message', '', _('commit message')),
3155 3197 ('l', 'logfile', '', _('commit message file'))],
3156 3198 _('hg debugrawcommit [OPTION]... [FILE]...')),
3157 3199 "recover": (recover, [], _('hg recover')),
3158 3200 "^remove|rm":
3159 3201 (remove,
3160 3202 [('A', 'after', None, _('record remove that has already occurred')),
3161 3203 ('f', 'force', None, _('remove file even if modified')),
3162 3204 ('I', 'include', [], _('include names matching the given patterns')),
3163 3205 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3164 3206 _('hg remove [OPTION]... FILE...')),
3165 3207 "rename|mv":
3166 3208 (rename,
3167 3209 [('A', 'after', None, _('record a rename that has already occurred')),
3168 3210 ('f', 'force', None,
3169 3211 _('forcibly copy over an existing managed file')),
3170 3212 ('I', 'include', [], _('include names matching the given patterns')),
3171 3213 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3172 3214 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3173 3215 _('hg rename [OPTION]... SOURCE... DEST')),
3174 3216 "^revert":
3175 3217 (revert,
3176 3218 [('r', 'rev', '', _('revision to revert to')),
3177 3219 ('', 'no-backup', None, _('do not save backup copies of files')),
3178 3220 ('I', 'include', [], _('include names matching given patterns')),
3179 3221 ('X', 'exclude', [], _('exclude names matching given patterns')),
3180 3222 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3181 3223 _('hg revert [-r REV] [NAME]...')),
3182 3224 "rollback": (rollback, [], _('hg rollback')),
3183 3225 "root": (root, [], _('hg root')),
3184 3226 "^serve":
3185 3227 (serve,
3186 3228 [('A', 'accesslog', '', _('name of access log file to write to')),
3187 3229 ('d', 'daemon', None, _('run server in background')),
3188 3230 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3189 3231 ('E', 'errorlog', '', _('name of error log file to write to')),
3190 3232 ('p', 'port', 0, _('port to use (default: 8000)')),
3191 3233 ('a', 'address', '', _('address to use')),
3192 3234 ('n', 'name', '',
3193 3235 _('name to show in web pages (default: working dir)')),
3194 3236 ('', 'webdir-conf', '', _('name of the webdir config file'
3195 3237 ' (serve more than one repo)')),
3196 3238 ('', 'pid-file', '', _('name of file to write process ID to')),
3197 3239 ('', 'stdio', None, _('for remote clients')),
3198 3240 ('t', 'templates', '', _('web templates to use')),
3199 3241 ('', 'style', '', _('template style to use')),
3200 3242 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3201 3243 _('hg serve [OPTION]...')),
3202 3244 "^status|st":
3203 3245 (status,
3204 3246 [('A', 'all', None, _('show status of all files')),
3205 3247 ('m', 'modified', None, _('show only modified files')),
3206 3248 ('a', 'added', None, _('show only added files')),
3207 3249 ('r', 'removed', None, _('show only removed files')),
3208 3250 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3209 3251 ('c', 'clean', None, _('show only files without changes')),
3210 3252 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3211 3253 ('i', 'ignored', None, _('show ignored files')),
3212 3254 ('n', 'no-status', None, _('hide status prefix')),
3213 3255 ('C', 'copies', None, _('show source of copied files')),
3214 3256 ('0', 'print0', None,
3215 3257 _('end filenames with NUL, for use with xargs')),
3216 3258 ('I', 'include', [], _('include names matching the given patterns')),
3217 3259 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3218 3260 _('hg status [OPTION]... [FILE]...')),
3219 3261 "tag":
3220 3262 (tag,
3221 3263 [('l', 'local', None, _('make the tag local')),
3222 3264 ('m', 'message', '', _('message for tag commit log entry')),
3223 3265 ('d', 'date', '', _('record datecode as commit date')),
3224 3266 ('u', 'user', '', _('record user as commiter')),
3225 3267 ('r', 'rev', '', _('revision to tag'))],
3226 3268 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3227 3269 "tags": (tags, [], _('hg tags')),
3228 3270 "tip":
3229 3271 (tip,
3230 3272 [('b', 'branches', None, _('show branches')),
3231 3273 ('', 'style', '', _('display using template map file')),
3232 3274 ('p', 'patch', None, _('show patch')),
3233 3275 ('', 'template', '', _('display with template'))],
3234 3276 _('hg tip [-b] [-p]')),
3235 3277 "unbundle":
3236 3278 (unbundle,
3237 3279 [('u', 'update', None,
3238 3280 _('update the working directory to tip after unbundle'))],
3239 3281 _('hg unbundle [-u] FILE')),
3240 3282 "debugundo|undo": (undo, [], _('hg undo')),
3241 3283 "^update|up|checkout|co":
3242 3284 (update,
3243 3285 [('b', 'branch', '', _('checkout the head of a specific branch')),
3244 3286 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3245 3287 ('C', 'clean', None, _('overwrite locally modified files')),
3246 3288 ('f', 'force', None, _('force a merge with outstanding changes'))],
3247 3289 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3248 3290 "verify": (verify, [], _('hg verify')),
3249 3291 "version": (show_version, [], _('hg version')),
3250 3292 }
3251 3293
3252 3294 globalopts = [
3253 3295 ('R', 'repository', '',
3254 3296 _('repository root directory or symbolic path name')),
3255 3297 ('', 'cwd', '', _('change working directory')),
3256 3298 ('y', 'noninteractive', None,
3257 3299 _('do not prompt, assume \'yes\' for any required answers')),
3258 3300 ('q', 'quiet', None, _('suppress output')),
3259 3301 ('v', 'verbose', None, _('enable additional output')),
3260 3302 ('', 'config', [], _('set/override config option')),
3261 3303 ('', 'debug', None, _('enable debugging output')),
3262 3304 ('', 'debugger', None, _('start debugger')),
3263 3305 ('', 'lsprof', None, _('print improved command execution profile')),
3264 3306 ('', 'traceback', None, _('print traceback on exception')),
3265 3307 ('', 'time', None, _('time how long the command takes')),
3266 3308 ('', 'profile', None, _('print command execution profile')),
3267 3309 ('', 'version', None, _('output version information and exit')),
3268 3310 ('h', 'help', None, _('display help and exit')),
3269 3311 ]
3270 3312
3271 3313 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3272 3314 " debugindex debugindexdot")
3273 3315 optionalrepo = ("paths serve debugconfig")
3274 3316
3275 3317 def findpossible(cmd):
3276 3318 """
3277 3319 Return cmd -> (aliases, command table entry)
3278 3320 for each matching command.
3279 3321 Return debug commands (or their aliases) only if no normal command matches.
3280 3322 """
3281 3323 choice = {}
3282 3324 debugchoice = {}
3283 3325 for e in table.keys():
3284 3326 aliases = e.lstrip("^").split("|")
3285 3327 found = None
3286 3328 if cmd in aliases:
3287 3329 found = cmd
3288 3330 else:
3289 3331 for a in aliases:
3290 3332 if a.startswith(cmd):
3291 3333 found = a
3292 3334 break
3293 3335 if found is not None:
3294 3336 if aliases[0].startswith("debug"):
3295 3337 debugchoice[found] = (aliases, table[e])
3296 3338 else:
3297 3339 choice[found] = (aliases, table[e])
3298 3340
3299 3341 if not choice and debugchoice:
3300 3342 choice = debugchoice
3301 3343
3302 3344 return choice
3303 3345
3304 3346 def findcmd(cmd):
3305 3347 """Return (aliases, command table entry) for command string."""
3306 3348 choice = findpossible(cmd)
3307 3349
3308 3350 if choice.has_key(cmd):
3309 3351 return choice[cmd]
3310 3352
3311 3353 if len(choice) > 1:
3312 3354 clist = choice.keys()
3313 3355 clist.sort()
3314 3356 raise AmbiguousCommand(cmd, clist)
3315 3357
3316 3358 if choice:
3317 3359 return choice.values()[0]
3318 3360
3319 3361 raise UnknownCommand(cmd)
3320 3362
3321 3363 def catchterm(*args):
3322 3364 raise util.SignalInterrupt
3323 3365
3324 3366 def run():
3325 3367 sys.exit(dispatch(sys.argv[1:]))
3326 3368
3327 3369 class ParseError(Exception):
3328 3370 """Exception raised on errors in parsing the command line."""
3329 3371
3330 3372 def parse(ui, args):
3331 3373 options = {}
3332 3374 cmdoptions = {}
3333 3375
3334 3376 try:
3335 3377 args = fancyopts.fancyopts(args, globalopts, options)
3336 3378 except fancyopts.getopt.GetoptError, inst:
3337 3379 raise ParseError(None, inst)
3338 3380
3339 3381 if args:
3340 3382 cmd, args = args[0], args[1:]
3341 3383 aliases, i = findcmd(cmd)
3342 3384 cmd = aliases[0]
3343 3385 defaults = ui.config("defaults", cmd)
3344 3386 if defaults:
3345 3387 args = defaults.split() + args
3346 3388 c = list(i[1])
3347 3389 else:
3348 3390 cmd = None
3349 3391 c = []
3350 3392
3351 3393 # combine global options into local
3352 3394 for o in globalopts:
3353 3395 c.append((o[0], o[1], options[o[1]], o[3]))
3354 3396
3355 3397 try:
3356 3398 args = fancyopts.fancyopts(args, c, cmdoptions)
3357 3399 except fancyopts.getopt.GetoptError, inst:
3358 3400 raise ParseError(cmd, inst)
3359 3401
3360 3402 # separate global options back out
3361 3403 for o in globalopts:
3362 3404 n = o[1]
3363 3405 options[n] = cmdoptions[n]
3364 3406 del cmdoptions[n]
3365 3407
3366 3408 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3367 3409
3368 3410 external = {}
3369 3411
3370 3412 def findext(name):
3371 3413 '''return module with given extension name'''
3372 3414 try:
3373 3415 return sys.modules[external[name]]
3374 3416 except KeyError:
3375 3417 for k, v in external.iteritems():
3376 3418 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3377 3419 return sys.modules[v]
3378 3420 raise KeyError(name)
3379 3421
3380 3422 def dispatch(args):
3381 3423 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3382 3424 num = getattr(signal, name, None)
3383 3425 if num: signal.signal(num, catchterm)
3384 3426
3385 3427 try:
3386 3428 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3387 3429 except util.Abort, inst:
3388 3430 sys.stderr.write(_("abort: %s\n") % inst)
3389 3431 return -1
3390 3432
3391 3433 for ext_name, load_from_name in u.extensions():
3392 3434 try:
3393 3435 if load_from_name:
3394 3436 # the module will be loaded in sys.modules
3395 3437 # choose an unique name so that it doesn't
3396 3438 # conflicts with other modules
3397 3439 module_name = "hgext_%s" % ext_name.replace('.', '_')
3398 3440 mod = imp.load_source(module_name, load_from_name)
3399 3441 else:
3400 3442 def importh(name):
3401 3443 mod = __import__(name)
3402 3444 components = name.split('.')
3403 3445 for comp in components[1:]:
3404 3446 mod = getattr(mod, comp)
3405 3447 return mod
3406 3448 try:
3407 3449 mod = importh("hgext.%s" % ext_name)
3408 3450 except ImportError:
3409 3451 mod = importh(ext_name)
3410 3452 external[ext_name] = mod.__name__
3411 3453 except (util.SignalInterrupt, KeyboardInterrupt):
3412 3454 raise
3413 3455 except Exception, inst:
3414 3456 u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst))
3415 3457 if u.print_exc():
3416 3458 return 1
3417 3459
3418 3460 for name in external.itervalues():
3419 3461 mod = sys.modules[name]
3420 3462 uisetup = getattr(mod, 'uisetup', None)
3421 3463 if uisetup:
3422 3464 uisetup(u)
3423 3465 cmdtable = getattr(mod, 'cmdtable', {})
3424 3466 for t in cmdtable:
3425 3467 if t in table:
3426 3468 u.warn(_("module %s overrides %s\n") % (name, t))
3427 3469 table.update(cmdtable)
3428 3470
3429 3471 try:
3430 3472 cmd, func, args, options, cmdoptions = parse(u, args)
3431 3473 if options["time"]:
3432 3474 def get_times():
3433 3475 t = os.times()
3434 3476 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3435 3477 t = (t[0], t[1], t[2], t[3], time.clock())
3436 3478 return t
3437 3479 s = get_times()
3438 3480 def print_time():
3439 3481 t = get_times()
3440 3482 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3441 3483 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3442 3484 atexit.register(print_time)
3443 3485
3444 3486 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3445 3487 not options["noninteractive"], options["traceback"],
3446 3488 options["config"])
3447 3489
3448 3490 # enter the debugger before command execution
3449 3491 if options['debugger']:
3450 3492 pdb.set_trace()
3451 3493
3452 3494 try:
3453 3495 if options['cwd']:
3454 3496 try:
3455 3497 os.chdir(options['cwd'])
3456 3498 except OSError, inst:
3457 3499 raise util.Abort('%s: %s' %
3458 3500 (options['cwd'], inst.strerror))
3459 3501
3460 3502 path = u.expandpath(options["repository"]) or ""
3461 3503 repo = path and hg.repository(u, path=path) or None
3462 3504
3463 3505 if options['help']:
3464 3506 return help_(u, cmd, options['version'])
3465 3507 elif options['version']:
3466 3508 return show_version(u)
3467 3509 elif not cmd:
3468 3510 return help_(u, 'shortlist')
3469 3511
3470 3512 if cmd not in norepo.split():
3471 3513 try:
3472 3514 if not repo:
3473 3515 repo = hg.repository(u, path=path)
3474 3516 u = repo.ui
3475 3517 for name in external.itervalues():
3476 3518 mod = sys.modules[name]
3477 3519 if hasattr(mod, 'reposetup'):
3478 3520 mod.reposetup(u, repo)
3479 3521 except hg.RepoError:
3480 3522 if cmd not in optionalrepo.split():
3481 3523 raise
3482 3524 d = lambda: func(u, repo, *args, **cmdoptions)
3483 3525 else:
3484 3526 d = lambda: func(u, *args, **cmdoptions)
3485 3527
3486 3528 # reupdate the options, repo/.hg/hgrc may have changed them
3487 3529 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3488 3530 not options["noninteractive"], options["traceback"],
3489 3531 options["config"])
3490 3532
3491 3533 try:
3492 3534 if options['profile']:
3493 3535 import hotshot, hotshot.stats
3494 3536 prof = hotshot.Profile("hg.prof")
3495 3537 try:
3496 3538 try:
3497 3539 return prof.runcall(d)
3498 3540 except:
3499 3541 try:
3500 3542 u.warn(_('exception raised - generating '
3501 3543 'profile anyway\n'))
3502 3544 except:
3503 3545 pass
3504 3546 raise
3505 3547 finally:
3506 3548 prof.close()
3507 3549 stats = hotshot.stats.load("hg.prof")
3508 3550 stats.strip_dirs()
3509 3551 stats.sort_stats('time', 'calls')
3510 3552 stats.print_stats(40)
3511 3553 elif options['lsprof']:
3512 3554 try:
3513 3555 from mercurial import lsprof
3514 3556 except ImportError:
3515 3557 raise util.Abort(_(
3516 3558 'lsprof not available - install from '
3517 3559 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3518 3560 p = lsprof.Profiler()
3519 3561 p.enable(subcalls=True)
3520 3562 try:
3521 3563 return d()
3522 3564 finally:
3523 3565 p.disable()
3524 3566 stats = lsprof.Stats(p.getstats())
3525 3567 stats.sort()
3526 3568 stats.pprint(top=10, file=sys.stderr, climit=5)
3527 3569 else:
3528 3570 return d()
3529 3571 finally:
3530 3572 u.flush()
3531 3573 except:
3532 3574 # enter the debugger when we hit an exception
3533 3575 if options['debugger']:
3534 3576 pdb.post_mortem(sys.exc_info()[2])
3535 3577 u.print_exc()
3536 3578 raise
3537 3579 except ParseError, inst:
3538 3580 if inst.args[0]:
3539 3581 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3540 3582 help_(u, inst.args[0])
3541 3583 else:
3542 3584 u.warn(_("hg: %s\n") % inst.args[1])
3543 3585 help_(u, 'shortlist')
3544 3586 except AmbiguousCommand, inst:
3545 3587 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3546 3588 (inst.args[0], " ".join(inst.args[1])))
3547 3589 except UnknownCommand, inst:
3548 3590 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3549 3591 help_(u, 'shortlist')
3550 3592 except hg.RepoError, inst:
3551 3593 u.warn(_("abort: %s!\n") % inst)
3552 3594 except lock.LockHeld, inst:
3553 3595 if inst.errno == errno.ETIMEDOUT:
3554 3596 reason = _('timed out waiting for lock held by %s') % inst.locker
3555 3597 else:
3556 3598 reason = _('lock held by %s') % inst.locker
3557 3599 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3558 3600 except lock.LockUnavailable, inst:
3559 3601 u.warn(_("abort: could not lock %s: %s\n") %
3560 3602 (inst.desc or inst.filename, inst.strerror))
3561 3603 except revlog.RevlogError, inst:
3562 3604 u.warn(_("abort: "), inst, "!\n")
3563 3605 except util.SignalInterrupt:
3564 3606 u.warn(_("killed!\n"))
3565 3607 except KeyboardInterrupt:
3566 3608 try:
3567 3609 u.warn(_("interrupted!\n"))
3568 3610 except IOError, inst:
3569 3611 if inst.errno == errno.EPIPE:
3570 3612 if u.debugflag:
3571 3613 u.warn(_("\nbroken pipe\n"))
3572 3614 else:
3573 3615 raise
3574 3616 except IOError, inst:
3575 3617 if hasattr(inst, "code"):
3576 3618 u.warn(_("abort: %s\n") % inst)
3577 3619 elif hasattr(inst, "reason"):
3578 3620 u.warn(_("abort: error: %s\n") % inst.reason[1])
3579 3621 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3580 3622 if u.debugflag:
3581 3623 u.warn(_("broken pipe\n"))
3582 3624 elif getattr(inst, "strerror", None):
3583 3625 if getattr(inst, "filename", None):
3584 3626 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
3585 3627 else:
3586 3628 u.warn(_("abort: %s\n") % inst.strerror)
3587 3629 else:
3588 3630 raise
3589 3631 except OSError, inst:
3590 3632 if hasattr(inst, "filename"):
3591 3633 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3592 3634 else:
3593 3635 u.warn(_("abort: %s\n") % inst.strerror)
3594 3636 except util.Abort, inst:
3595 3637 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
3596 3638 except TypeError, inst:
3597 3639 # was this an argument error?
3598 3640 tb = traceback.extract_tb(sys.exc_info()[2])
3599 3641 if len(tb) > 2: # no
3600 3642 raise
3601 3643 u.debug(inst, "\n")
3602 3644 u.warn(_("%s: invalid arguments\n") % cmd)
3603 3645 help_(u, cmd)
3604 3646 except SystemExit, inst:
3605 3647 # Commands shouldn't sys.exit directly, but give a return code.
3606 3648 # Just in case catch this and and pass exit code to caller.
3607 3649 return inst.code
3608 3650 except:
3609 3651 u.warn(_("** unknown exception encountered, details follow\n"))
3610 3652 u.warn(_("** report bug details to "
3611 3653 "http://www.selenic.com/mercurial/bts\n"))
3612 3654 u.warn(_("** or mercurial@selenic.com\n"))
3613 3655 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3614 3656 % version.get_version())
3615 3657 raise
3616 3658
3617 3659 return -1
General Comments 0
You need to be logged in to leave comments. Login now