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