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