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