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