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