comparison mercurial/commands.py @ 5124:06154aff2b1a

merge with -stable
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Wed, 08 Aug 2007 23:00:01 +0200
parents f94dbc6c7eaf c80af96943aa
children 13d23d66a6cd
comparison
equal deleted inserted replaced
5123:f94dbc6c7eaf 5124:06154aff2b1a
6 # of the GNU General Public License, incorporated herein by reference. 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 import demandimport; demandimport.enable() 8 import demandimport; demandimport.enable()
9 from node import * 9 from node import *
10 from i18n import _ 10 from i18n import _
11 import bisect, os, re, sys, urllib, shlex, stat 11 import os, re, sys, urllib
12 import ui, hg, util, revlog, bundlerepo, extensions 12 import ui, hg, util, revlog, bundlerepo, extensions
13 import difflib, patch, time, help, mdiff, tempfile 13 import difflib, patch, time, help, mdiff, tempfile
14 import errno, version, socket 14 import errno, version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver 15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16 16
31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): 31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
32 if exact: 32 if exact:
33 if ui.verbose: 33 if ui.verbose:
34 ui.status(_('adding %s\n') % rel) 34 ui.status(_('adding %s\n') % rel)
35 names.append(abs) 35 names.append(abs)
36 elif repo.dirstate.state(abs) == '?': 36 elif abs not in repo.dirstate:
37 ui.status(_('adding %s\n') % rel) 37 ui.status(_('adding %s\n') % rel)
38 names.append(abs) 38 names.append(abs)
39 if not opts.get('dry_run'): 39 if not opts.get('dry_run'):
40 repo.add(names) 40 repo.add(names)
41 41
71 71
72 Without the -a option, annotate will avoid processing files it 72 Without the -a option, annotate will avoid processing files it
73 detects as binary. With -a, annotate will generate an annotation 73 detects as binary. With -a, annotate will generate an annotation
74 anyway, probably with undesirable results. 74 anyway, probably with undesirable results.
75 """ 75 """
76 getdate = util.cachefunc(lambda x: util.datestr(x.date())) 76 getdate = util.cachefunc(lambda x: util.datestr(x[0].date()))
77 77
78 if not pats: 78 if not pats:
79 raise util.Abort(_('at least one file name or pattern required')) 79 raise util.Abort(_('at least one file name or pattern required'))
80 80
81 opmap = [['user', lambda x: ui.shortuser(x.user())], 81 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
82 ['number', lambda x: str(x.rev())], 82 ('number', lambda x: str(x[0].rev())),
83 ['changeset', lambda x: short(x.node())], 83 ('changeset', lambda x: short(x[0].node())),
84 ['date', getdate], ['follow', lambda x: x.path()]] 84 ('date', getdate),
85 ('follow', lambda x: x[0].path()),
86 ]
87
85 if (not opts['user'] and not opts['changeset'] and not opts['date'] 88 if (not opts['user'] and not opts['changeset'] and not opts['date']
86 and not opts['follow']): 89 and not opts['follow']):
87 opts['number'] = 1 90 opts['number'] = 1
91
92 linenumber = opts.get('line_number') is not None
93 if (linenumber and (not opts['changeset']) and (not opts['number'])):
94 raise util.Abort(_('at least one of -n/-c is required for -l'))
95
96 funcmap = [func for op, func in opmap if opts.get(op)]
97 if linenumber:
98 lastfunc = funcmap[-1]
99 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
88 100
89 ctx = repo.changectx(opts['rev']) 101 ctx = repo.changectx(opts['rev'])
90 102
91 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, 103 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
92 node=ctx.node()): 104 node=ctx.node()):
93 fctx = ctx.filectx(abs) 105 fctx = ctx.filectx(abs)
94 if not opts['text'] and util.binary(fctx.data()): 106 if not opts['text'] and util.binary(fctx.data()):
95 ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) 107 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
96 continue 108 continue
97 109
98 lines = fctx.annotate(follow=opts.get('follow')) 110 lines = fctx.annotate(follow=opts.get('follow'),
111 linenumber=linenumber)
99 pieces = [] 112 pieces = []
100 113
101 for o, f in opmap: 114 for f in funcmap:
102 if opts[o]: 115 l = [f(n) for n, dummy in lines]
103 l = [f(n) for n, dummy in lines] 116 if l:
104 if l: 117 m = max(map(len, l))
105 m = max(map(len, l)) 118 pieces.append(["%*s" % (m, x) for x in l])
106 pieces.append(["%*s" % (m, x) for x in l])
107 119
108 if pieces: 120 if pieces:
109 for p, l in zip(zip(*pieces), lines): 121 for p, l in zip(zip(*pieces), lines):
110 ui.write("%s: %s" % (" ".join(p), l[1])) 122 ui.write("%s: %s" % (" ".join(p), l[1]))
111 123
414 will be committed. 426 will be committed.
415 427
416 If no commit message is specified, the editor configured in your hgrc 428 If no commit message is specified, the editor configured in your hgrc
417 or in the EDITOR environment variable is started to enter a message. 429 or in the EDITOR environment variable is started to enter a message.
418 """ 430 """
419 message = cmdutil.logmessage(opts) 431 def commitfunc(ui, repo, files, message, match, opts):
420 432 return repo.commit(files, message, opts['user'], opts['date'], match,
421 if opts['addremove']: 433 force_editor=opts.get('force_editor'))
422 cmdutil.addremove(repo, pats, opts) 434 cmdutil.commit(ui, repo, commitfunc, pats, opts)
423 fns, match, anypats = cmdutil.matchpats(repo, pats, opts) 435
424 if pats: 436 def docopy(ui, repo, pats, opts):
425 status = repo.status(files=fns, match=match)
426 modified, added, removed, deleted, unknown = status[:5]
427 files = modified + added + removed
428 slist = None
429 for f in fns:
430 if f == '.':
431 continue
432 if f not in files:
433 rf = repo.wjoin(f)
434 try:
435 mode = os.lstat(rf)[stat.ST_MODE]
436 except OSError:
437 raise util.Abort(_("file %s not found!") % rf)
438 if stat.S_ISDIR(mode):
439 name = f + '/'
440 if slist is None:
441 slist = list(files)
442 slist.sort()
443 i = bisect.bisect(slist, name)
444 if i >= len(slist) or not slist[i].startswith(name):
445 raise util.Abort(_("no match under directory %s!")
446 % rf)
447 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
448 raise util.Abort(_("can't commit %s: "
449 "unsupported file type!") % rf)
450 elif repo.dirstate.state(f) == '?':
451 raise util.Abort(_("file %s not tracked!") % rf)
452 else:
453 files = []
454 try:
455 repo.commit(files, message, opts['user'], opts['date'], match,
456 force_editor=opts.get('force_editor'))
457 except ValueError, inst:
458 raise util.Abort(str(inst))
459
460 def docopy(ui, repo, pats, opts, wlock):
461 # called with the repo lock held 437 # called with the repo lock held
462 # 438 #
463 # hgsep => pathname that uses "/" to separate directories 439 # hgsep => pathname that uses "/" to separate directories
464 # ossep => pathname that uses os.sep to separate directories 440 # ossep => pathname that uses os.sep to separate directories
465 cwd = repo.getcwd() 441 cwd = repo.getcwd()
471 # rel: ossep 447 # rel: ossep
472 # return: hgsep 448 # return: hgsep
473 def okaytocopy(abs, rel, exact): 449 def okaytocopy(abs, rel, exact):
474 reasons = {'?': _('is not managed'), 450 reasons = {'?': _('is not managed'),
475 'r': _('has been marked for remove')} 451 'r': _('has been marked for remove')}
476 state = repo.dirstate.state(abs) 452 state = repo.dirstate[abs]
477 reason = reasons.get(state) 453 reason = reasons.get(state)
478 if reason: 454 if reason:
479 if exact: 455 if exact:
480 ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) 456 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
481 else: 457 else:
499 ui.warn(_('%s: not overwriting - %s collides with %s\n') % 475 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
500 (reltarget, repo.pathto(abssrc, cwd), 476 (reltarget, repo.pathto(abssrc, cwd),
501 repo.pathto(prevsrc, cwd))) 477 repo.pathto(prevsrc, cwd)))
502 return 478 return
503 if (not opts['after'] and os.path.exists(target) or 479 if (not opts['after'] and os.path.exists(target) or
504 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'): 480 opts['after'] and repo.dirstate[abstarget] in 'mn'):
505 if not opts['force']: 481 if not opts['force']:
506 ui.warn(_('%s: not overwriting - file exists\n') % 482 ui.warn(_('%s: not overwriting - file exists\n') %
507 reltarget) 483 reltarget)
508 return 484 return
509 if not opts['after'] and not opts.get('dry_run'): 485 if not opts['after'] and not opts.get('dry_run'):
514 else: 490 else:
515 targetdir = os.path.dirname(target) or '.' 491 targetdir = os.path.dirname(target) or '.'
516 if not os.path.isdir(targetdir) and not opts.get('dry_run'): 492 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
517 os.makedirs(targetdir) 493 os.makedirs(targetdir)
518 try: 494 try:
519 restore = repo.dirstate.state(abstarget) == 'r' 495 restore = repo.dirstate[abstarget] == 'r'
520 if restore and not opts.get('dry_run'): 496 if restore and not opts.get('dry_run'):
521 repo.undelete([abstarget], wlock) 497 repo.undelete([abstarget])
522 try: 498 try:
523 if not opts.get('dry_run'): 499 if not opts.get('dry_run'):
524 util.copyfile(src, target) 500 util.copyfile(src, target)
525 restore = False 501 restore = False
526 finally: 502 finally:
527 if restore: 503 if restore:
528 repo.remove([abstarget], wlock=wlock) 504 repo.remove([abstarget])
529 except IOError, inst: 505 except IOError, inst:
530 if inst.errno == errno.ENOENT: 506 if inst.errno == errno.ENOENT:
531 ui.warn(_('%s: deleted in working copy\n') % relsrc) 507 ui.warn(_('%s: deleted in working copy\n') % relsrc)
532 else: 508 else:
533 ui.warn(_('%s: cannot copy - %s\n') % 509 ui.warn(_('%s: cannot copy - %s\n') %
536 return 512 return
537 if ui.verbose or not exact: 513 if ui.verbose or not exact:
538 ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) 514 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
539 targets[abstarget] = abssrc 515 targets[abstarget] = abssrc
540 if abstarget != origsrc: 516 if abstarget != origsrc:
541 if repo.dirstate.state(origsrc) == 'a': 517 if repo.dirstate[origsrc] == 'a':
542 if not ui.quiet: 518 if not ui.quiet:
543 ui.warn(_("%s has not been committed yet, so no copy " 519 ui.warn(_("%s has not been committed yet, so no copy "
544 "data will be stored for %s.\n") 520 "data will be stored for %s.\n")
545 % (repo.pathto(origsrc, cwd), reltarget)) 521 % (repo.pathto(origsrc, cwd), reltarget))
546 if abstarget not in repo.dirstate and not opts.get('dry_run'): 522 if abstarget not in repo.dirstate and not opts.get('dry_run'):
547 repo.add([abstarget], wlock) 523 repo.add([abstarget])
548 elif not opts.get('dry_run'): 524 elif not opts.get('dry_run'):
549 repo.copy(origsrc, abstarget, wlock) 525 repo.copy(origsrc, abstarget)
550 copied.append((abssrc, relsrc, exact)) 526 copied.append((abssrc, relsrc, exact))
551 527
552 # pat: ossep 528 # pat: ossep
553 # dest ossep 529 # dest ossep
554 # srcs: list of (hgsep, hgsep, ossep, bool) 530 # srcs: list of (hgsep, hgsep, ossep, bool)
664 operation is recorded, but no copying is performed. 640 operation is recorded, but no copying is performed.
665 641
666 This command takes effect in the next commit. To undo a copy 642 This command takes effect in the next commit. To undo a copy
667 before that, see hg revert. 643 before that, see hg revert.
668 """ 644 """
669 wlock = repo.wlock(0) 645 wlock = repo.wlock(False)
670 errs, copied = docopy(ui, repo, pats, opts, wlock) 646 try:
647 errs, copied = docopy(ui, repo, pats, opts)
648 finally:
649 del wlock
671 return errs 650 return errs
672 651
673 def debugancestor(ui, index, rev1, rev2): 652 def debugancestor(ui, index, rev1, rev2):
674 """find the ancestor revision of two revisions in a given index""" 653 """find the ancestor revision of two revisions in a given index"""
675 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index) 654 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
702 if rev == "": 681 if rev == "":
703 rev = repo.changelog.tip() 682 rev = repo.changelog.tip()
704 ctx = repo.changectx(rev) 683 ctx = repo.changectx(rev)
705 files = ctx.manifest() 684 files = ctx.manifest()
706 wlock = repo.wlock() 685 wlock = repo.wlock()
707 repo.dirstate.rebuild(rev, files) 686 try:
687 repo.dirstate.rebuild(rev, files)
688 finally:
689 del wlock
708 690
709 def debugcheckstate(ui, repo): 691 def debugcheckstate(ui, repo):
710 """validate the correctness of the current dirstate""" 692 """validate the correctness of the current dirstate"""
711 parent1, parent2 = repo.dirstate.parents() 693 parent1, parent2 = repo.dirstate.parents()
712 dc = repo.dirstate
713 m1 = repo.changectx(parent1).manifest() 694 m1 = repo.changectx(parent1).manifest()
714 m2 = repo.changectx(parent2).manifest() 695 m2 = repo.changectx(parent2).manifest()
715 errors = 0 696 errors = 0
716 for f in dc: 697 for f in repo.dirstate:
717 state = repo.dirstate.state(f) 698 state = repo.dirstate[f]
718 if state in "nr" and f not in m1: 699 if state in "nr" and f not in m1:
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state)) 700 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
720 errors += 1 701 errors += 1
721 if state in "a" and f in m1: 702 if state in "a" and f in m1:
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state)) 703 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
724 if state in "m" and f not in m1 and f not in m2: 705 if state in "m" and f not in m1 and f not in m2:
725 ui.warn(_("%s in state %s, but not in either manifest\n") % 706 ui.warn(_("%s in state %s, but not in either manifest\n") %
726 (f, state)) 707 (f, state))
727 errors += 1 708 errors += 1
728 for f in m1: 709 for f in m1:
729 state = repo.dirstate.state(f) 710 state = repo.dirstate[f]
730 if state not in "nrm": 711 if state not in "nrm":
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state)) 712 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
732 errors += 1 713 errors += 1
733 if errors: 714 if errors:
734 error = _(".hg/dirstate inconsistent with current parent's manifest") 715 error = _(".hg/dirstate inconsistent with current parent's manifest")
772 753
773 wlock = repo.wlock() 754 wlock = repo.wlock()
774 try: 755 try:
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2)) 756 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
776 finally: 757 finally:
777 wlock.release() 758 del wlock
778 759
779 def debugstate(ui, repo): 760 def debugstate(ui, repo):
780 """show the contents of the current dirstate""" 761 """show the contents of the current dirstate"""
781 dc = repo.dirstate 762 dc = repo.dirstate._map
782 for file_ in dc: 763 k = dc.keys()
764 k.sort()
765 for file_ in k:
783 if dc[file_][3] == -1: 766 if dc[file_][3] == -1:
784 # Pad or slice to locale representation 767 # Pad or slice to locale representation
785 locale_len = len(time.strftime("%x %X", time.localtime(0))) 768 locale_len = len(time.strftime("%x %X", time.localtime(0)))
786 timestr = 'unset' 769 timestr = 'unset'
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr)) 770 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
839 822
840 def debuginstall(ui): 823 def debuginstall(ui):
841 '''test Mercurial installation''' 824 '''test Mercurial installation'''
842 825
843 def writetemp(contents): 826 def writetemp(contents):
844 (fd, name) = tempfile.mkstemp() 827 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
845 f = os.fdopen(fd, "wb") 828 f = os.fdopen(fd, "wb")
846 f.write(contents) 829 f.write(contents)
847 f.close() 830 f.close()
848 return name 831 return name
849 832
1570 if opts.get('exact') or not opts['force']: 1553 if opts.get('exact') or not opts['force']:
1571 cmdutil.bail_if_changed(repo) 1554 cmdutil.bail_if_changed(repo)
1572 1555
1573 d = opts["base"] 1556 d = opts["base"]
1574 strip = opts["strip"] 1557 strip = opts["strip"]
1575 1558 wlock = lock = None
1576 wlock = repo.wlock() 1559 try:
1577 lock = repo.lock() 1560 wlock = repo.wlock()
1578 1561 lock = repo.lock()
1579 for p in patches: 1562 for p in patches:
1580 pf = os.path.join(d, p) 1563 pf = os.path.join(d, p)
1581 1564
1582 if pf == '-': 1565 if pf == '-':
1583 ui.status(_("applying patch from stdin\n")) 1566 ui.status(_("applying patch from stdin\n"))
1584 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin) 1567 data = patch.extract(ui, sys.stdin)
1585 else:
1586 ui.status(_("applying %s\n") % p)
1587 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1588
1589 if tmpname is None:
1590 raise util.Abort(_('no diffs found'))
1591
1592 try:
1593 cmdline_message = cmdutil.logmessage(opts)
1594 if cmdline_message:
1595 # pickup the cmdline msg
1596 message = cmdline_message
1597 elif message:
1598 # pickup the patch msg
1599 message = message.strip()
1600 else: 1568 else:
1601 # launch the editor 1569 ui.status(_("applying %s\n") % p)
1602 message = None 1570 data = patch.extract(ui, file(pf, 'rb'))
1603 ui.debug(_('message:\n%s\n') % message) 1571
1604 1572 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1605 wp = repo.workingctx().parents() 1573
1606 if opts.get('exact'): 1574 if tmpname is None:
1607 if not nodeid or not p1: 1575 raise util.Abort(_('no diffs found'))
1608 raise util.Abort(_('not a mercurial patch')) 1576
1609 p1 = repo.lookup(p1) 1577 try:
1610 p2 = repo.lookup(p2 or hex(nullid)) 1578 cmdline_message = cmdutil.logmessage(opts)
1611 1579 if cmdline_message:
1612 if p1 != wp[0].node(): 1580 # pickup the cmdline msg
1613 hg.clean(repo, p1, wlock=wlock) 1581 message = cmdline_message
1614 repo.dirstate.setparents(p1, p2) 1582 elif message:
1615 elif p2: 1583 # pickup the patch msg
1584 message = message.strip()
1585 else:
1586 # launch the editor
1587 message = None
1588 ui.debug(_('message:\n%s\n') % message)
1589
1590 wp = repo.workingctx().parents()
1591 if opts.get('exact'):
1592 if not nodeid or not p1:
1593 raise util.Abort(_('not a mercurial patch'))
1594 p1 = repo.lookup(p1)
1595 p2 = repo.lookup(p2 or hex(nullid))
1596
1597 if p1 != wp[0].node():
1598 hg.clean(repo, p1)
1599 repo.dirstate.setparents(p1, p2)
1600 elif p2:
1601 try:
1602 p1 = repo.lookup(p1)
1603 p2 = repo.lookup(p2)
1604 if p1 == wp[0].node():
1605 repo.dirstate.setparents(p1, p2)
1606 except hg.RepoError:
1607 pass
1608 if opts.get('exact') or opts.get('import_branch'):
1609 repo.dirstate.setbranch(branch or 'default')
1610
1611 files = {}
1616 try: 1612 try:
1617 p1 = repo.lookup(p1) 1613 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1618 p2 = repo.lookup(p2) 1614 files=files)
1619 if p1 == wp[0].node(): 1615 finally:
1620 repo.dirstate.setparents(p1, p2) 1616 files = patch.updatedir(ui, repo, files)
1621 except hg.RepoError: 1617 n = repo.commit(files, message, user, date)
1622 pass 1618 if opts.get('exact'):
1623 if opts.get('exact') or opts.get('import_branch'): 1619 if hex(n) != nodeid:
1624 repo.dirstate.setbranch(branch or 'default') 1620 repo.rollback()
1625 1621 raise util.Abort(_('patch is damaged' +
1626 files = {} 1622 ' or loses information'))
1627 try:
1628 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1629 files=files)
1630 finally: 1623 finally:
1631 files = patch.updatedir(ui, repo, files, wlock=wlock) 1624 os.unlink(tmpname)
1632 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock) 1625 finally:
1633 if opts.get('exact'): 1626 del lock, wlock
1634 if hex(n) != nodeid:
1635 repo.rollback(wlock=wlock, lock=lock)
1636 raise util.Abort(_('patch is damaged or loses information'))
1637 finally:
1638 os.unlink(tmpname)
1639 1627
1640 def incoming(ui, repo, source="default", **opts): 1628 def incoming(ui, repo, source="default", **opts):
1641 """show new changesets found in source 1629 """show new changesets found in source
1642 1630
1643 Show new changesets found in the specified path/URL or the default 1631 Show new changesets found in the specified path/URL or the default
1748 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, 1736 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1749 badmatch=util.always, 1737 badmatch=util.always,
1750 default='relglob'): 1738 default='relglob'):
1751 if src == 'b': 1739 if src == 'b':
1752 continue 1740 continue
1753 if not node and repo.dirstate.state(abs) == '?': 1741 if not node and abs not in repo.dirstate:
1754 continue 1742 continue
1755 if opts['fullpath']: 1743 if opts['fullpath']:
1756 ui.write(os.path.join(repo.root, abs), end) 1744 ui.write(os.path.join(repo.root, abs), end)
1757 else: 1745 else:
1758 ui.write(((pats and rel) or abs), end) 1746 ui.write(((pats and rel) or abs), end)
2186 To undo a remove before that, see hg revert. 2174 To undo a remove before that, see hg revert.
2187 2175
2188 Modified files and added files are not removed by default. To 2176 Modified files and added files are not removed by default. To
2189 remove them, use the -f/--force option. 2177 remove them, use the -f/--force option.
2190 """ 2178 """
2191 names = []
2192 if not opts['after'] and not pats: 2179 if not opts['after'] and not pats:
2193 raise util.Abort(_('no files specified')) 2180 raise util.Abort(_('no files specified'))
2194 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) 2181 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2195 exact = dict.fromkeys(files) 2182 exact = dict.fromkeys(files)
2196 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5] 2183 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2203 elif abs in added: 2190 elif abs in added:
2204 if opts['force']: 2191 if opts['force']:
2205 forget.append(abs) 2192 forget.append(abs)
2206 continue 2193 continue
2207 reason = _('has been marked for add (use -f to force removal)') 2194 reason = _('has been marked for add (use -f to force removal)')
2208 elif repo.dirstate.state(abs) == '?': 2195 elif abs not in repo.dirstate:
2209 reason = _('is not managed') 2196 reason = _('is not managed')
2210 elif opts['after'] and not exact and abs not in deleted: 2197 elif opts['after'] and not exact and abs not in deleted:
2211 continue 2198 continue
2212 elif abs in removed: 2199 elif abs in removed:
2213 continue 2200 continue
2233 operation is recorded, but no copying is performed. 2220 operation is recorded, but no copying is performed.
2234 2221
2235 This command takes effect in the next commit. To undo a rename 2222 This command takes effect in the next commit. To undo a rename
2236 before that, see hg revert. 2223 before that, see hg revert.
2237 """ 2224 """
2238 wlock = repo.wlock(0) 2225 wlock = repo.wlock(False)
2239 errs, copied = docopy(ui, repo, pats, opts, wlock) 2226 try:
2240 names = [] 2227 errs, copied = docopy(ui, repo, pats, opts)
2241 for abs, rel, exact in copied: 2228 names = []
2242 if ui.verbose or not exact: 2229 for abs, rel, exact in copied:
2243 ui.status(_('removing %s\n') % rel) 2230 if ui.verbose or not exact:
2244 names.append(abs) 2231 ui.status(_('removing %s\n') % rel)
2245 if not opts.get('dry_run'): 2232 names.append(abs)
2246 repo.remove(names, True, wlock=wlock) 2233 if not opts.get('dry_run'):
2247 return errs 2234 repo.remove(names, True)
2235 return errs
2236 finally:
2237 del wlock
2248 2238
2249 def revert(ui, repo, *pats, **opts): 2239 def revert(ui, repo, *pats, **opts):
2250 """revert files or dirs to their states as of some revision 2240 """revert files or dirs to their states as of some revision
2251 2241
2252 With no revision specified, revert the named files or directories 2242 With no revision specified, revert the named files or directories
2296 if node == parent: 2286 if node == parent:
2297 pmf = mf 2287 pmf = mf
2298 else: 2288 else:
2299 pmf = None 2289 pmf = None
2300 2290
2301 wlock = repo.wlock()
2302
2303 # need all matching names in dirstate and manifest of target rev, 2291 # need all matching names in dirstate and manifest of target rev,
2304 # so have to walk both. do not print errors if files exist in one 2292 # so have to walk both. do not print errors if files exist in one
2305 # but not other. 2293 # but not other.
2306 2294
2307 names = {} 2295 names = {}
2308 target_only = {} 2296 target_only = {}
2309 2297
2310 # walk dirstate. 2298 wlock = repo.wlock()
2311 2299 try:
2312 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, 2300 # walk dirstate.
2313 badmatch=mf.has_key): 2301 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2314 names[abs] = (rel, exact) 2302 badmatch=mf.has_key):
2315 if src == 'b': 2303 names[abs] = (rel, exact)
2304 if src == 'b':
2305 target_only[abs] = True
2306
2307 # walk target manifest.
2308
2309 def badmatch(path):
2310 if path in names:
2311 return True
2312 path_ = path + '/'
2313 for f in names:
2314 if f.startswith(path_):
2315 return True
2316 return False
2317
2318 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2319 badmatch=badmatch):
2320 if abs in names or src == 'b':
2321 continue
2322 names[abs] = (rel, exact)
2316 target_only[abs] = True 2323 target_only[abs] = True
2317 2324
2318 # walk target manifest. 2325 changes = repo.status(match=names.has_key)[:5]
2319 2326 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2320 def badmatch(path): 2327
2321 if path in names: 2328 revert = ([], _('reverting %s\n'))
2322 return True 2329 add = ([], _('adding %s\n'))
2323 path_ = path + '/' 2330 remove = ([], _('removing %s\n'))
2324 for f in names: 2331 forget = ([], _('forgetting %s\n'))
2325 if f.startswith(path_): 2332 undelete = ([], _('undeleting %s\n'))
2326 return True 2333 update = {}
2327 return False 2334
2328 2335 disptable = (
2329 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, 2336 # dispatch table:
2330 badmatch=badmatch): 2337 # file state
2331 if abs in names or src == 'b': 2338 # action if in target manifest
2332 continue 2339 # action if not in target manifest
2333 names[abs] = (rel, exact) 2340 # make backup if in target manifest
2334 target_only[abs] = True 2341 # make backup if not in target manifest
2335 2342 (modified, revert, remove, True, True),
2336 changes = repo.status(match=names.has_key, wlock=wlock)[:5] 2343 (added, revert, forget, True, False),
2337 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) 2344 (removed, undelete, None, False, False),
2338 2345 (deleted, revert, remove, False, False),
2339 revert = ([], _('reverting %s\n')) 2346 (unknown, add, None, True, False),
2340 add = ([], _('adding %s\n')) 2347 (target_only, add, None, False, False),
2341 remove = ([], _('removing %s\n')) 2348 )
2342 forget = ([], _('forgetting %s\n')) 2349
2343 undelete = ([], _('undeleting %s\n')) 2350 entries = names.items()
2344 update = {} 2351 entries.sort()
2345 2352
2346 disptable = ( 2353 for abs, (rel, exact) in entries:
2347 # dispatch table: 2354 mfentry = mf.get(abs)
2348 # file state 2355 target = repo.wjoin(abs)
2349 # action if in target manifest 2356 def handle(xlist, dobackup):
2350 # action if not in target manifest 2357 xlist[0].append(abs)
2351 # make backup if in target manifest 2358 update[abs] = 1
2352 # make backup if not in target manifest 2359 if dobackup and not opts['no_backup'] and util.lexists(target):
2353 (modified, revert, remove, True, True), 2360 bakname = "%s.orig" % rel
2354 (added, revert, forget, True, False), 2361 ui.note(_('saving current version of %s as %s\n') %
2355 (removed, undelete, None, False, False), 2362 (rel, bakname))
2356 (deleted, revert, remove, False, False), 2363 if not opts.get('dry_run'):
2357 (unknown, add, None, True, False), 2364 util.copyfile(target, bakname)
2358 (target_only, add, None, False, False), 2365 if ui.verbose or not exact:
2359 ) 2366 ui.status(xlist[1] % rel)
2360 2367 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2361 entries = names.items() 2368 if abs not in table: continue
2362 entries.sort() 2369 # file has changed in dirstate
2363 2370 if mfentry:
2364 for abs, (rel, exact) in entries: 2371 handle(hitlist, backuphit)
2365 mfentry = mf.get(abs) 2372 elif misslist is not None:
2366 target = repo.wjoin(abs) 2373 handle(misslist, backupmiss)
2367 def handle(xlist, dobackup): 2374 else:
2368 xlist[0].append(abs) 2375 if exact: ui.warn(_('file not managed: %s\n') % rel)
2369 update[abs] = 1 2376 break
2370 if dobackup and not opts['no_backup'] and util.lexists(target):
2371 bakname = "%s.orig" % rel
2372 ui.note(_('saving current version of %s as %s\n') %
2373 (rel, bakname))
2374 if not opts.get('dry_run'):
2375 util.copyfile(target, bakname)
2376 if ui.verbose or not exact:
2377 ui.status(xlist[1] % rel)
2378 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2379 if abs not in table: continue
2380 # file has changed in dirstate
2381 if mfentry:
2382 handle(hitlist, backuphit)
2383 elif misslist is not None:
2384 handle(misslist, backupmiss)
2385 else: 2377 else:
2386 if exact: ui.warn(_('file not managed: %s\n') % rel) 2378 # file has not changed in dirstate
2387 break 2379 if node == parent:
2388 else: 2380 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2389 # file has not changed in dirstate 2381 continue
2390 if node == parent: 2382 if pmf is None:
2391 if exact: ui.warn(_('no changes needed to %s\n') % rel) 2383 # only need parent manifest in this unlikely case,
2392 continue 2384 # so do not read by default
2393 if pmf is None: 2385 pmf = repo.changectx(parent).manifest()
2394 # only need parent manifest in this unlikely case, 2386 if abs in pmf:
2395 # so do not read by default 2387 if mfentry:
2396 pmf = repo.changectx(parent).manifest() 2388 # if version of file is same in parent and target
2397 if abs in pmf: 2389 # manifests, do nothing
2398 if mfentry: 2390 if pmf[abs] != mfentry:
2399 # if version of file is same in parent and target 2391 handle(revert, False)
2400 # manifests, do nothing 2392 else:
2401 if pmf[abs] != mfentry: 2393 handle(remove, False)
2402 handle(revert, False) 2394
2403 else: 2395 if not opts.get('dry_run'):
2404 handle(remove, False) 2396 for f in forget[0]:
2405 2397 repo.dirstate.forget(f)
2406 if not opts.get('dry_run'): 2398 r = hg.revert(repo, node, update.has_key)
2407 repo.dirstate.forget(forget[0]) 2399 for f in add[0]:
2408 r = hg.revert(repo, node, update.has_key, wlock) 2400 repo.dirstate.add(f)
2409 repo.dirstate.update(add[0], 'a') 2401 for f in undelete[0]:
2410 repo.dirstate.update(undelete[0], 'n') 2402 repo.dirstate.normal(f)
2411 repo.dirstate.update(remove[0], 'r') 2403 for f in remove[0]:
2412 return r 2404 repo.dirstate.remove(f)
2405 return r
2406 finally:
2407 del wlock
2413 2408
2414 def rollback(ui, repo): 2409 def rollback(ui, repo):
2415 """roll back the last transaction in this repository 2410 """roll back the last transaction in this repository
2416 2411
2417 Roll back the last transaction in this repository, restoring the 2412 Roll back the last transaction in this repository, restoring the
2465 s = sshserver.sshserver(ui, repo) 2460 s = sshserver.sshserver(ui, repo)
2466 s.serve_forever() 2461 s.serve_forever()
2467 2462
2468 parentui = ui.parentui or ui 2463 parentui = ui.parentui or ui
2469 optlist = ("name templates style address port ipv6" 2464 optlist = ("name templates style address port ipv6"
2470 " accesslog errorlog webdir_conf") 2465 " accesslog errorlog webdir_conf certificate")
2471 for o in optlist.split(): 2466 for o in optlist.split():
2472 if opts[o]: 2467 if opts[o]:
2473 parentui.setconfig("web", o, str(opts[o])) 2468 parentui.setconfig("web", o, str(opts[o]))
2474 if (repo is not None) and (repo.ui != parentui): 2469 if (repo is not None) and (repo.ui != parentui):
2475 repo.ui.setconfig("web", o, str(opts[o])) 2470 repo.ui.setconfig("web", o, str(opts[o]))
2648 2643
2649 Apply one or more compressed changegroup files generated by the 2644 Apply one or more compressed changegroup files generated by the
2650 bundle command. 2645 bundle command.
2651 """ 2646 """
2652 fnames = (fname1,) + fnames 2647 fnames = (fname1,) + fnames
2653 result = None
2654 for fname in fnames: 2648 for fname in fnames:
2655 if os.path.exists(fname): 2649 if os.path.exists(fname):
2656 f = open(fname, "rb") 2650 f = open(fname, "rb")
2657 else: 2651 else:
2658 f = urllib.urlopen(fname) 2652 f = urllib.urlopen(fname)
2755 commitopts = [ 2749 commitopts = [
2756 ('m', 'message', '', _('use <text> as commit message')), 2750 ('m', 'message', '', _('use <text> as commit message')),
2757 ('l', 'logfile', '', _('read commit message from <file>')), 2751 ('l', 'logfile', '', _('read commit message from <file>')),
2758 ] 2752 ]
2759 2753
2754 commitopts2 = [
2755 ('d', 'date', '', _('record datecode as commit date')),
2756 ('u', 'user', '', _('record user as committer')),
2757 ]
2758
2760 table = { 2759 table = {
2761 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')), 2760 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2762 "addremove": 2761 "addremove":
2763 (addremove, 2762 (addremove,
2764 [('s', 'similarity', '', 2763 [('s', 'similarity', '',
2772 ('a', 'text', None, _('treat all files as text')), 2771 ('a', 'text', None, _('treat all files as text')),
2773 ('u', 'user', None, _('list the author')), 2772 ('u', 'user', None, _('list the author')),
2774 ('d', 'date', None, _('list the date')), 2773 ('d', 'date', None, _('list the date')),
2775 ('n', 'number', None, _('list the revision number (default)')), 2774 ('n', 'number', None, _('list the revision number (default)')),
2776 ('c', 'changeset', None, _('list the changeset')), 2775 ('c', 'changeset', None, _('list the changeset')),
2776 ('l', 'line-number', None,
2777 _('show line number at the first appearance'))
2777 ] + walkopts, 2778 ] + walkopts,
2778 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')), 2779 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2779 "archive": 2780 "archive":
2780 (archive, 2781 (archive,
2781 [('', 'no-decode', None, _('do not pass files through decoders')), 2782 [('', 'no-decode', None, _('do not pass files through decoders')),
2782 ('p', 'prefix', '', _('directory prefix for files in archive')), 2783 ('p', 'prefix', '', _('directory prefix for files in archive')),
2783 ('r', 'rev', '', _('revision to distribute')), 2784 ('r', 'rev', '', _('revision to distribute')),
2786 _('hg archive [OPTION]... DEST')), 2787 _('hg archive [OPTION]... DEST')),
2787 "backout": 2788 "backout":
2788 (backout, 2789 (backout,
2789 [('', 'merge', None, 2790 [('', 'merge', None,
2790 _('merge with old dirstate parent after backout')), 2791 _('merge with old dirstate parent after backout')),
2791 ('d', 'date', '', _('record datecode as commit date')),
2792 ('', 'parent', '', _('parent to choose when backing out merge')), 2792 ('', 'parent', '', _('parent to choose when backing out merge')),
2793 ('u', 'user', '', _('record user as committer')),
2794 ('r', 'rev', '', _('revision to backout')), 2793 ('r', 'rev', '', _('revision to backout')),
2795 ] + walkopts + commitopts, 2794 ] + walkopts + commitopts + commitopts2,
2796 _('hg backout [OPTION]... [-r] REV')), 2795 _('hg backout [OPTION]... [-r] REV')),
2797 "branch": 2796 "branch":
2798 (branch, 2797 (branch,
2799 [('f', 'force', None, 2798 [('f', 'force', None,
2800 _('set branch name even if it shadows an existing branch'))], 2799 _('set branch name even if it shadows an existing branch'))],
2832 _('hg clone [OPTION]... SOURCE [DEST]')), 2831 _('hg clone [OPTION]... SOURCE [DEST]')),
2833 "^commit|ci": 2832 "^commit|ci":
2834 (commit, 2833 (commit,
2835 [('A', 'addremove', None, 2834 [('A', 'addremove', None,
2836 _('mark new/missing files as added/removed before committing')), 2835 _('mark new/missing files as added/removed before committing')),
2837 ('d', 'date', '', _('record datecode as commit date')), 2836 ] + walkopts + commitopts + commitopts2,
2838 ('u', 'user', '', _('record user as commiter')),
2839 ] + walkopts + commitopts,
2840 _('hg commit [OPTION]... [FILE]...')), 2837 _('hg commit [OPTION]... [FILE]...')),
2841 "copy|cp": 2838 "copy|cp":
2842 (copy, 2839 (copy,
2843 [('A', 'after', None, _('record a copy that has already occurred')), 2840 [('A', 'after', None, _('record a copy that has already occurred')),
2844 ('f', 'force', None, 2841 ('f', 'force', None,
3024 ] + remoteopts, 3021 ] + remoteopts,
3025 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')), 3022 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3026 "debugrawcommit|rawcommit": 3023 "debugrawcommit|rawcommit":
3027 (rawcommit, 3024 (rawcommit,
3028 [('p', 'parent', [], _('parent')), 3025 [('p', 'parent', [], _('parent')),
3029 ('d', 'date', '', _('date code')),
3030 ('u', 'user', '', _('user')),
3031 ('F', 'files', '', _('file list')) 3026 ('F', 'files', '', _('file list'))
3032 ] + commitopts, 3027 ] + commitopts + commitopts2,
3033 _('hg debugrawcommit [OPTION]... [FILE]...')), 3028 _('hg debugrawcommit [OPTION]... [FILE]...')),
3034 "recover": (recover, [], _('hg recover')), 3029 "recover": (recover, [], _('hg recover')),
3035 "^remove|rm": 3030 "^remove|rm":
3036 (remove, 3031 (remove,
3037 [('A', 'after', None, _('record remove that has already occurred')), 3032 [('A', 'after', None, _('record remove that has already occurred')),
3073 ' (serve more than one repo)')), 3068 ' (serve more than one repo)')),
3074 ('', 'pid-file', '', _('name of file to write process ID to')), 3069 ('', 'pid-file', '', _('name of file to write process ID to')),
3075 ('', 'stdio', None, _('for remote clients')), 3070 ('', 'stdio', None, _('for remote clients')),
3076 ('t', 'templates', '', _('web templates to use')), 3071 ('t', 'templates', '', _('web templates to use')),
3077 ('', 'style', '', _('template style to use')), 3072 ('', 'style', '', _('template style to use')),
3078 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))], 3073 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3074 ('', 'certificate', '', _('SSL certificate file'))],
3079 _('hg serve [OPTION]...')), 3075 _('hg serve [OPTION]...')),
3080 "^status|st": 3076 "^status|st":
3081 (status, 3077 (status,
3082 [('A', 'all', None, _('show status of all files')), 3078 [('A', 'all', None, _('show status of all files')),
3083 ('m', 'modified', None, _('show only modified files')), 3079 ('m', 'modified', None, _('show only modified files')),
3096 _('hg status [OPTION]... [FILE]...')), 3092 _('hg status [OPTION]... [FILE]...')),
3097 "tag": 3093 "tag":
3098 (tag, 3094 (tag,
3099 [('f', 'force', None, _('replace existing tag')), 3095 [('f', 'force', None, _('replace existing tag')),
3100 ('l', 'local', None, _('make the tag local')), 3096 ('l', 'local', None, _('make the tag local')),
3101 ('m', 'message', '', _('message for tag commit log entry')),
3102 ('d', 'date', '', _('record datecode as commit date')),
3103 ('u', 'user', '', _('record user as commiter')),
3104 ('r', 'rev', '', _('revision to tag')), 3097 ('r', 'rev', '', _('revision to tag')),
3105 ('', 'remove', None, _('remove a tag'))], 3098 ('', 'remove', None, _('remove a tag')),
3099 # -l/--local is already there, commitopts cannot be used
3100 ('m', 'message', '', _('use <text> as commit message')),
3101 ] + commitopts2,
3106 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')), 3102 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3107 "tags": (tags, [], _('hg tags')), 3103 "tags": (tags, [], _('hg tags')),
3108 "tip": 3104 "tip":
3109 (tip, 3105 (tip,
3110 [('', 'style', '', _('display using template map file')), 3106 [('', 'style', '', _('display using template map file')),
3124 _('hg update [-C] [-d DATE] [[-r] REV]')), 3120 _('hg update [-C] [-d DATE] [[-r] REV]')),
3125 "verify": (verify, [], _('hg verify')), 3121 "verify": (verify, [], _('hg verify')),
3126 "version": (version_, [], _('hg version')), 3122 "version": (version_, [], _('hg version')),
3127 } 3123 }
3128 3124
3125 extensions.commandtable = table
3126
3129 norepo = ("clone init version help debugancestor debugcomplete debugdata" 3127 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3130 " debugindex debugindexdot debugdate debuginstall") 3128 " debugindex debugindexdot debugdate debuginstall")
3131 optionalrepo = ("paths serve showconfig") 3129 optionalrepo = ("paths serve showconfig")
3132 3130
3133 def dispatch(args): 3131 def dispatch(args):