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