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