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