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