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