comparison mercurial/commands.py @ 1584:b3e94785ab69

merge with crew
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Sun, 11 Dec 2005 15:38:42 -0800
parents 63799b01985c
children 5c5aaaa9ab6f
comparison
equal deleted inserted replaced
1583:32a4e6802864 1584:b3e94785ab69
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback") 13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
14 demandload(globals(), "errno socket version struct atexit sets bz2") 14 demandload(globals(), "errno socket version struct atexit sets bz2")
15 15
16 class UnknownCommand(Exception): 16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table.""" 17 """Exception raised if command is not in the command table."""
18 class AmbiguousCommand(Exception):
19 """Exception raised if command shortcut matches more than one command."""
18 20
19 def filterfiles(filters, files): 21 def filterfiles(filters, files):
20 l = [x for x in files if x in filters] 22 l = [x for x in files if x in filters]
21 23
22 for t in filters: 24 for t in filters:
29 cwd = repo.getcwd() 31 cwd = repo.getcwd()
30 if cwd: 32 if cwd:
31 return [util.normpath(os.path.join(cwd, x)) for x in args] 33 return [util.normpath(os.path.join(cwd, x)) for x in args]
32 return args 34 return args
33 35
34 def matchpats(repo, cwd, pats=[], opts={}, head=''): 36 def matchpats(repo, pats=[], opts={}, head=''):
37 cwd = repo.getcwd()
38 if not pats and cwd:
39 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
40 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
41 cwd = ''
35 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), 42 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
36 opts.get('exclude'), head) 43 opts.get('exclude'), head) + (cwd,)
37 44
38 def makewalk(repo, pats, opts, head=''): 45 def makewalk(repo, pats, opts, node=None, head=''):
39 cwd = repo.getcwd() 46 files, matchfn, anypats, cwd = matchpats(repo, pats, opts, head)
40 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
41 exact = dict(zip(files, files)) 47 exact = dict(zip(files, files))
42 def walk(): 48 def walk():
43 for src, fn in repo.walk(files=files, match=matchfn): 49 for src, fn in repo.walk(node=node, files=files, match=matchfn):
44 yield src, fn, util.pathto(cwd, fn), fn in exact 50 yield src, fn, util.pathto(cwd, fn), fn in exact
45 return files, matchfn, walk() 51 return files, matchfn, walk()
46 52
47 def walk(repo, pats, opts, head=''): 53 def walk(repo, pats, opts, node=None, head=''):
48 files, matchfn, results = makewalk(repo, pats, opts, head) 54 files, matchfn, results = makewalk(repo, pats, opts, node, head)
49 for r in results: 55 for r in results:
50 yield r 56 yield r
51 57
52 def walkchangerevs(ui, repo, cwd, pats, opts): 58 def walkchangerevs(ui, repo, pats, opts):
53 '''Iterate over files and the revs they changed in. 59 '''Iterate over files and the revs they changed in.
54 60
55 Callers most commonly need to iterate backwards over the history 61 Callers most commonly need to iterate backwards over the history
56 it is interested in. Doing so has awful (quadratic-looking) 62 it is interested in. Doing so has awful (quadratic-looking)
57 performance, so we use iterators in a "windowed" way. 63 performance, so we use iterators in a "windowed" way.
77 over with "add" - use to display data''' 83 over with "add" - use to display data'''
78 84
79 if repo.changelog.count() == 0: 85 if repo.changelog.count() == 0:
80 return [], False 86 return [], False
81 87
82 cwd = repo.getcwd() 88 files, matchfn, anypats, cwd = matchpats(repo, pats, opts)
83 if not pats and cwd:
84 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
85 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
86 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
87 pats, opts)
88 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0'])) 89 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
89 wanted = {} 90 wanted = {}
90 slowpath = anypats 91 slowpath = anypats
91 window = 300 92 window = 300
92 fncache = {} 93 fncache = {}
385 option_lists = [] 386 option_lists = []
386 if cmd and cmd != 'shortlist': 387 if cmd and cmd != 'shortlist':
387 if with_version: 388 if with_version:
388 show_version(ui) 389 show_version(ui)
389 ui.write('\n') 390 ui.write('\n')
390 key, i = find(cmd) 391 aliases, i = find(cmd)
391 # synopsis 392 # synopsis
392 ui.write("%s\n\n" % i[2]) 393 ui.write("%s\n\n" % i[2])
393 394
394 # description 395 # description
395 doc = i[0].__doc__ 396 doc = i[0].__doc__
397 doc = doc.splitlines(0)[0] 398 doc = doc.splitlines(0)[0]
398 ui.write("%s\n" % doc.rstrip()) 399 ui.write("%s\n" % doc.rstrip())
399 400
400 if not ui.quiet: 401 if not ui.quiet:
401 # aliases 402 # aliases
402 aliases = ', '.join(key.split('|')[1:]) 403 if len(aliases) > 1:
403 if aliases: 404 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
404 ui.write(_("\naliases: %s\n") % aliases)
405 405
406 # options 406 # options
407 if i[1]: 407 if i[1]:
408 option_lists.append(("options", i[1])) 408 option_lists.append(("options", i[1]))
409 409
480 480
481 Schedule files to be version controlled and added to the repository. 481 Schedule files to be version controlled and added to the repository.
482 482
483 The files will be added to the repository at the next commit. 483 The files will be added to the repository at the next commit.
484 484
485 If no names are given, add all files in the current directory and 485 If no names are given, add all files in the repository.
486 its subdirectories.
487 """ 486 """
488 487
489 names = [] 488 names = []
490 for src, abs, rel, exact in walk(repo, pats, opts): 489 for src, abs, rel, exact in walk(repo, pats, opts):
491 if exact: 490 if exact:
535 ucache = {} 534 ucache = {}
536 def getname(rev): 535 def getname(rev):
537 cl = repo.changelog.read(repo.changelog.node(rev)) 536 cl = repo.changelog.read(repo.changelog.node(rev))
538 return trimuser(ui, cl[1], rev, ucache) 537 return trimuser(ui, cl[1], rev, ucache)
539 538
539 dcache = {}
540 def getdate(rev):
541 datestr = dcache.get(rev)
542 if datestr is None:
543 cl = repo.changelog.read(repo.changelog.node(rev))
544 datestr = dcache[rev] = util.datestr(cl[2])
545 return datestr
546
540 if not pats: 547 if not pats:
541 raise util.Abort(_('at least one file name or pattern required')) 548 raise util.Abort(_('at least one file name or pattern required'))
542 549
543 opmap = [['user', getname], ['number', str], ['changeset', getnode]] 550 opmap = [['user', getname], ['number', str], ['changeset', getnode],
544 if not opts['user'] and not opts['changeset']: 551 ['date', getdate]]
552 if not opts['user'] and not opts['changeset'] and not opts['date']:
545 opts['number'] = 1 553 opts['number'] = 1
546 554
547 if opts['rev']: 555 if opts['rev']:
548 node = repo.changelog.lookup(opts['rev']) 556 node = repo.changelog.lookup(opts['rev'])
549 else: 557 else:
622 %s basename of file being printed 630 %s basename of file being printed
623 %d dirname of file being printed, or '.' if in repo root 631 %d dirname of file being printed, or '.' if in repo root
624 %p root-relative path name of file being printed 632 %p root-relative path name of file being printed
625 """ 633 """
626 mf = {} 634 mf = {}
627 if opts['rev']: 635 rev = opts['rev']
628 change = repo.changelog.read(repo.lookup(opts['rev'])) 636 if rev:
629 mf = repo.manifest.read(change[0]) 637 node = repo.lookup(rev)
630 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts): 638 else:
639 node = repo.changelog.tip()
640 change = repo.changelog.read(node)
641 mf = repo.manifest.read(change[0])
642 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, node):
631 r = repo.file(abs) 643 r = repo.file(abs)
632 if opts['rev']: 644 n = mf[abs]
633 try:
634 n = mf[abs]
635 except (hg.RepoError, KeyError):
636 try:
637 n = r.lookup(rev)
638 except KeyError, inst:
639 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
640 else:
641 n = r.tip()
642 fp = make_file(repo, r, opts['output'], node=n, pathname=abs) 645 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
643 fp.write(r.read(n)) 646 fp.write(r.read(n))
644 647
645 def clone(ui, source, dest=None, **opts): 648 def clone(ui, source, dest=None, **opts):
646 """make a copy of an existing repository 649 """make a copy of an existing repository
665 if os.path.exists(dest): 668 if os.path.exists(dest):
666 raise util.Abort(_("destination '%s' already exists"), dest) 669 raise util.Abort(_("destination '%s' already exists"), dest)
667 670
668 dest = os.path.realpath(dest) 671 dest = os.path.realpath(dest)
669 672
670 class Dircleanup: 673 class Dircleanup(object):
671 def __init__(self, dir_): 674 def __init__(self, dir_):
672 self.rmtree = shutil.rmtree 675 self.rmtree = shutil.rmtree
673 self.dir_ = dir_ 676 self.dir_ = dir_
674 os.mkdir(dir_) 677 os.mkdir(dir_)
675 def close(self): 678 def close(self):
733 repo.pull(other, heads = revs) 736 repo.pull(other, heads = revs)
734 737
735 f = repo.opener("hgrc", "w", text=True) 738 f = repo.opener("hgrc", "w", text=True)
736 f.write("[paths]\n") 739 f.write("[paths]\n")
737 f.write("default = %s\n" % abspath) 740 f.write("default = %s\n" % abspath)
741 f.close()
738 742
739 if not opts['noupdate']: 743 if not opts['noupdate']:
740 update(ui, repo) 744 update(ui, repo)
741 745
742 d.close() 746 d.close()
745 """commit the specified files or all outstanding changes 749 """commit the specified files or all outstanding changes
746 750
747 Commit changes to the given files into the repository. 751 Commit changes to the given files into the repository.
748 752
749 If a list of files is omitted, all changes reported by "hg status" 753 If a list of files is omitted, all changes reported by "hg status"
750 from the root of the repository will be commited. 754 will be commited.
751 755
752 The HGEDITOR or EDITOR environment variables are used to start an 756 The HGEDITOR or EDITOR environment variables are used to start an
753 editor to add a commit comment. 757 editor to add a commit comment.
754 """ 758 """
755 message = opts['message'] 759 message = opts['message']
768 raise util.Abort(_("can't read commit message '%s': %s") % 772 raise util.Abort(_("can't read commit message '%s': %s") %
769 (logfile, inst.strerror)) 773 (logfile, inst.strerror))
770 774
771 if opts['addremove']: 775 if opts['addremove']:
772 addremove(ui, repo, *pats, **opts) 776 addremove(ui, repo, *pats, **opts)
773 cwd = repo.getcwd() 777 fns, match, anypats, cwd = matchpats(repo, pats, opts)
774 if not pats and cwd:
775 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
776 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
777 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
778 pats, opts)
779 if pats: 778 if pats:
780 c, a, d, u = repo.changes(files=fns, match=match) 779 c, a, d, u = repo.changes(files=fns, match=match)
781 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r'] 780 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
782 else: 781 else:
783 files = [] 782 files = []
785 repo.commit(files, message, opts['user'], opts['date'], match) 784 repo.commit(files, message, opts['user'], opts['date'], match)
786 except ValueError, inst: 785 except ValueError, inst:
787 raise util.Abort(str(inst)) 786 raise util.Abort(str(inst))
788 787
789 def docopy(ui, repo, pats, opts): 788 def docopy(ui, repo, pats, opts):
790 if not pats: 789 cwd = repo.getcwd()
791 raise util.Abort(_('no source or destination specified')) 790 errors = 0
792 elif len(pats) == 1: 791 copied = []
793 raise util.Abort(_('no destination specified')) 792 targets = {}
794 pats = list(pats)
795 dest = pats.pop()
796 sources = []
797 dir2dir = len(pats) == 1 and os.path.isdir(pats[0])
798 793
799 def okaytocopy(abs, rel, exact): 794 def okaytocopy(abs, rel, exact):
800 reasons = {'?': _('is not managed'), 795 reasons = {'?': _('is not managed'),
801 'a': _('has been marked for add')} 796 'a': _('has been marked for add')}
802 reason = reasons.get(repo.dirstate.state(abs)) 797 reason = reasons.get(repo.dirstate.state(abs))
803 if reason: 798 if reason:
804 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) 799 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
805 else: 800 else:
806 return True 801 return True
807 802
808 for src, abs, rel, exact in walk(repo, pats, opts): 803 def copy(abssrc, relsrc, target, exact):
809 if okaytocopy(abs, rel, exact): 804 abstarget = util.canonpath(repo.root, cwd, target)
810 sources.append((abs, rel, exact)) 805 reltarget = util.pathto(cwd, abstarget)
811 if not sources: 806 prevsrc = targets.get(abstarget)
812 raise util.Abort(_('no files to copy')) 807 if prevsrc is not None:
813 808 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
814 cwd = repo.getcwd() 809 (reltarget, abssrc, prevsrc))
815 absdest = util.canonpath(repo.root, cwd, dest) 810 return
816 reldest = util.pathto(cwd, absdest) 811 if (not opts['after'] and os.path.exists(reltarget) or
817 if os.path.exists(reldest): 812 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
818 destisfile = not os.path.isdir(reldest) 813 if not opts['force']:
819 else: 814 ui.warn(_('%s: not overwriting - file exists\n') %
820 destisfile = not dir2dir and (len(sources) == 1 815 reltarget)
821 or repo.dirstate.state(absdest) != '?') 816 return
822 817 if not opts['after']:
823 if destisfile and len(sources) > 1: 818 os.unlink(reltarget)
824 raise util.Abort(_('with multiple sources, destination must be a ' 819 if opts['after']:
825 'directory')) 820 if not os.path.exists(reltarget):
826 821 return
827 srcpfxlen = 0
828 if dir2dir:
829 srcpfx = util.pathto(cwd, util.canonpath(repo.root, cwd, pats[0]))
830 if os.path.exists(reldest):
831 srcpfx = os.path.split(srcpfx)[0]
832 if srcpfx:
833 srcpfx += os.sep
834 srcpfxlen = len(srcpfx)
835
836 errs, copied = 0, []
837 for abs, rel, exact in sources:
838 if destisfile:
839 mydest = reldest
840 elif dir2dir:
841 mydest = os.path.join(dest, rel[srcpfxlen:])
842 else: 822 else:
843 mydest = os.path.join(dest, os.path.basename(rel)) 823 targetdir = os.path.dirname(reltarget) or '.'
844 myabsdest = util.canonpath(repo.root, cwd, mydest) 824 if not os.path.isdir(targetdir):
845 myreldest = util.pathto(cwd, myabsdest) 825 os.makedirs(targetdir)
846 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
847 ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
848 continue
849 mydestdir = os.path.dirname(myreldest) or '.'
850 if not opts['after']:
851 try: 826 try:
852 if dir2dir: os.makedirs(mydestdir) 827 shutil.copyfile(relsrc, reltarget)
853 elif not destisfile: os.mkdir(mydestdir) 828 shutil.copymode(relsrc, reltarget)
854 except OSError, inst:
855 if inst.errno != errno.EEXIST: raise
856 if ui.verbose or not exact:
857 ui.status(_('copying %s to %s\n') % (rel, myreldest))
858 if not opts['after']:
859 try:
860 shutil.copyfile(rel, myreldest)
861 shutil.copymode(rel, myreldest)
862 except shutil.Error, inst: 829 except shutil.Error, inst:
863 raise util.Abort(str(inst)) 830 raise util.Abort(str(inst))
864 except IOError, inst: 831 except IOError, inst:
865 if inst.errno == errno.ENOENT: 832 if inst.errno == errno.ENOENT:
866 ui.warn(_('%s: deleted in working copy\n') % rel) 833 ui.warn(_('%s: deleted in working copy\n') % relsrc)
867 else: 834 else:
868 ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror)) 835 ui.warn(_('%s: cannot copy - %s\n') %
869 errs += 1 836 (relsrc, inst.strerror))
870 continue 837 errors += 1
871 repo.copy(abs, myabsdest) 838 return
872 copied.append((abs, rel, exact)) 839 if ui.verbose or not exact:
873 if errs: 840 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
841 targets[abstarget] = abssrc
842 repo.copy(abssrc, abstarget)
843 copied.append((abssrc, relsrc, exact))
844
845 def targetpathfn(pat, dest, srcs):
846 if os.path.isdir(pat):
847 if pat.endswith(os.sep):
848 pat = pat[:-len(os.sep)]
849 if destdirexists:
850 striplen = len(os.path.split(pat)[0])
851 else:
852 striplen = len(pat)
853 if striplen:
854 striplen += len(os.sep)
855 res = lambda p: os.path.join(dest, p[striplen:])
856 elif destdirexists:
857 res = lambda p: os.path.join(dest, os.path.basename(p))
858 else:
859 res = lambda p: dest
860 return res
861
862 def targetpathafterfn(pat, dest, srcs):
863 if util.patkind(pat, None)[0]:
864 # a mercurial pattern
865 res = lambda p: os.path.join(dest, os.path.basename(p))
866 elif len(util.canonpath(repo.root, cwd, pat)) < len(srcs[0][0]):
867 # A directory. Either the target path contains the last
868 # component of the source path or it does not.
869 def evalpath(striplen):
870 score = 0
871 for s in srcs:
872 t = os.path.join(dest, s[1][striplen:])
873 if os.path.exists(t):
874 score += 1
875 return score
876
877 if pat.endswith(os.sep):
878 pat = pat[:-len(os.sep)]
879 striplen = len(pat) + len(os.sep)
880 if os.path.isdir(os.path.join(dest, os.path.split(pat)[1])):
881 score = evalpath(striplen)
882 striplen1 = len(os.path.split(pat)[0])
883 if striplen1:
884 striplen1 += len(os.sep)
885 if evalpath(striplen1) > score:
886 striplen = striplen1
887 res = lambda p: os.path.join(dest, p[striplen:])
888 else:
889 # a file
890 if destdirexists:
891 res = lambda p: os.path.join(dest, os.path.basename(p))
892 else:
893 res = lambda p: dest
894 return res
895
896
897 pats = list(pats)
898 if not pats:
899 raise util.Abort(_('no source or destination specified'))
900 if len(pats) == 1:
901 raise util.Abort(_('no destination specified'))
902 dest = pats.pop()
903 destdirexists = os.path.isdir(dest)
904 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
905 raise util.Abort(_('with multiple sources, destination must be an '
906 'existing directory'))
907 if opts['after']:
908 tfn = targetpathafterfn
909 else:
910 tfn = targetpathfn
911 copylist = []
912 for pat in pats:
913 srcs = []
914 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
915 if okaytocopy(abssrc, relsrc, exact):
916 srcs.append((abssrc, relsrc, exact))
917 if not srcs:
918 continue
919 copylist.append((tfn(pat, dest, srcs), srcs))
920 if not copylist:
921 raise util.Abort(_('no files to copy'))
922
923 for targetpath, srcs in copylist:
924 for abssrc, relsrc, exact in srcs:
925 copy(abssrc, relsrc, targetpath(relsrc), exact)
926
927 if errors:
874 ui.warn(_('(consider using --after)\n')) 928 ui.warn(_('(consider using --after)\n'))
875 return errs, copied 929 return errors, copied
876 930
877 def copy(ui, repo, *pats, **opts): 931 def copy(ui, repo, *pats, **opts):
878 """mark files as copied for the next commit 932 """mark files as copied for the next commit
879 933
880 Mark dest as having copies of source files. If dest is a 934 Mark dest as having copies of source files. If dest is a
1005 # assume all revision numbers are for changesets 1059 # assume all revision numbers are for changesets
1006 n = repo.lookup(rev) 1060 n = repo.lookup(rev)
1007 change = repo.changelog.read(n) 1061 change = repo.changelog.read(n)
1008 m = repo.manifest.read(change[0]) 1062 m = repo.manifest.read(change[0])
1009 n = m[relpath(repo, [file])[0]] 1063 n = m[relpath(repo, [file])[0]]
1010 except hg.RepoError, KeyError: 1064 except (hg.RepoError, KeyError):
1011 n = r.lookup(rev) 1065 n = r.lookup(rev)
1012 else: 1066 else:
1013 n = r.tip() 1067 n = r.tip()
1014 m = r.renamed(n) 1068 m = r.renamed(n)
1015 if m: 1069 if m:
1028 for src, abs, rel, exact in items: 1082 for src, abs, rel, exact in items:
1029 line = fmt % (src, abs, rel, exact and 'exact' or '') 1083 line = fmt % (src, abs, rel, exact and 'exact' or '')
1030 ui.write("%s\n" % line.rstrip()) 1084 ui.write("%s\n" % line.rstrip())
1031 1085
1032 def diff(ui, repo, *pats, **opts): 1086 def diff(ui, repo, *pats, **opts):
1033 """diff working directory (or selected files) 1087 """diff repository (or selected files)
1034 1088
1035 Show differences between revisions for the specified files. 1089 Show differences between revisions for the specified files.
1036 1090
1037 Differences between files are shown using the unified diff format. 1091 Differences between files are shown using the unified diff format.
1038 1092
1054 if len(revs) > 1: 1108 if len(revs) > 1:
1055 node2 = revs[1] 1109 node2 = revs[1]
1056 if len(revs) > 2: 1110 if len(revs) > 2:
1057 raise util.Abort(_("too many revisions to diff")) 1111 raise util.Abort(_("too many revisions to diff"))
1058 1112
1059 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts) 1113 fns, matchfn, anypats, cwd = matchpats(repo, pats, opts)
1060 1114
1061 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn, 1115 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1062 text=opts['text']) 1116 text=opts['text'])
1063 1117
1064 def doexport(ui, repo, changeset, seqno, total, revwidth, opts): 1118 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1175 lstart = body.rfind('\n', begin, mstart) + 1 or begin 1229 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1176 lend = body.find('\n', mend) 1230 lend = body.find('\n', mend)
1177 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend] 1231 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1178 begin = lend + 1 1232 begin = lend + 1
1179 1233
1180 class linestate: 1234 class linestate(object):
1181 def __init__(self, line, linenum, colstart, colend): 1235 def __init__(self, line, linenum, colstart, colend):
1182 self.line = line 1236 self.line = line
1183 self.linenum = linenum 1237 self.linenum = linenum
1184 self.colstart = colstart 1238 self.colstart = colstart
1185 self.colend = colend 1239 self.colend = colend
1225 counts[change] += 1 1279 counts[change] += 1
1226 return counts['+'], counts['-'] 1280 return counts['+'], counts['-']
1227 1281
1228 fstate = {} 1282 fstate = {}
1229 skip = {} 1283 skip = {}
1230 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts) 1284 changeiter, getchange = walkchangerevs(ui, repo, pats, opts)
1231 count = 0 1285 count = 0
1232 incrementing = False 1286 incrementing = False
1233 for st, rev, fns in changeiter: 1287 for st, rev, fns in changeiter:
1234 if st == 'window': 1288 if st == 'window':
1235 incrementing = rev 1289 incrementing = rev
1273 1327
1274 Repository "heads" are changesets that don't have children 1328 Repository "heads" are changesets that don't have children
1275 changesets. They are where development generally takes place and 1329 changesets. They are where development generally takes place and
1276 are the usual targets for update and merge operations. 1330 are the usual targets for update and merge operations.
1277 """ 1331 """
1278 heads = repo.changelog.heads() 1332 if opts['rev']:
1333 heads = repo.heads(repo.lookup(opts['rev']))
1334 else:
1335 heads = repo.heads()
1279 br = None 1336 br = None
1280 if opts['branches']: 1337 if opts['branches']:
1281 br = repo.branchlookup(heads) 1338 br = repo.branchlookup(heads)
1282 for n in repo.changelog.heads(): 1339 for n in heads:
1283 show_changeset(ui, repo, changenode=n, brinfo=br) 1340 show_changeset(ui, repo, changenode=n, brinfo=br)
1284 1341
1285 def identify(ui, repo): 1342 def identify(ui, repo):
1286 """print information about the working copy 1343 """print information about the working copy
1287 1344
1459 """show revision history of entire repository or files 1516 """show revision history of entire repository or files
1460 1517
1461 Print the revision history of the specified files or the entire project. 1518 Print the revision history of the specified files or the entire project.
1462 1519
1463 By default this command outputs: changeset id and hash, tags, 1520 By default this command outputs: changeset id and hash, tags,
1464 parents, user, date and time, and a summary for each commit. The 1521 non-trivial parents, user, date and time, and a summary for each
1465 -v switch adds some more detail, such as changed files, manifest 1522 commit. When the -v/--verbose switch is used, the list of changed
1466 hashes or message signatures. 1523 files and full commit message is shown.
1467 """ 1524 """
1468 class dui: 1525 class dui(object):
1469 # Implement and delegate some ui protocol. Save hunks of 1526 # Implement and delegate some ui protocol. Save hunks of
1470 # output for later display in the desired order. 1527 # output for later display in the desired order.
1471 def __init__(self, ui): 1528 def __init__(self, ui):
1472 self.ui = ui 1529 self.ui = ui
1473 self.hunk = {} 1530 self.hunk = {}
1485 def debug(self, *args): 1542 def debug(self, *args):
1486 if self.debugflag: 1543 if self.debugflag:
1487 self.write(*args) 1544 self.write(*args)
1488 def __getattr__(self, key): 1545 def __getattr__(self, key):
1489 return getattr(self.ui, key) 1546 return getattr(self.ui, key)
1490 cwd = repo.getcwd() 1547 changeiter, getchange = walkchangerevs(ui, repo, pats, opts)
1491 if not pats and cwd:
1492 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1493 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1494 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1495 pats, opts)
1496 for st, rev, fns in changeiter: 1548 for st, rev, fns in changeiter:
1497 if st == 'window': 1549 if st == 'window':
1498 du = dui(ui) 1550 du = dui(ui)
1499 elif st == 'add': 1551 elif st == 'add':
1500 du.bump(rev) 1552 du.bump(rev)
1731 Recover from an interrupted commit or pull. 1783 Recover from an interrupted commit or pull.
1732 1784
1733 This command tries to fix the repository status after an interrupted 1785 This command tries to fix the repository status after an interrupted
1734 operation. It should only be necessary when Mercurial suggests it. 1786 operation. It should only be necessary when Mercurial suggests it.
1735 """ 1787 """
1736 repo.recover() 1788 if repo.recover():
1789 return repo.verify()
1790 return False
1737 1791
1738 def remove(ui, repo, pat, *pats, **opts): 1792 def remove(ui, repo, pat, *pats, **opts):
1739 """remove the specified files on the next commit 1793 """remove the specified files on the next commit
1740 1794
1741 Schedule the indicated files for removal from the repository. 1795 Schedule the indicated files for removal from the repository.
1797 If a file has been deleted, it is recreated. If the executable 1851 If a file has been deleted, it is recreated. If the executable
1798 mode of a file was changed, it is reset. 1852 mode of a file was changed, it is reset.
1799 1853
1800 If names are given, all files matching the names are reverted. 1854 If names are given, all files matching the names are reverted.
1801 1855
1802 If no names are given, all files in the current directory and 1856 If no arguments are given, all files in the repository are reverted.
1803 its subdirectories are reverted.
1804 """ 1857 """
1805 node = opts['rev'] and repo.lookup(opts['rev']) or \ 1858 node = opts['rev'] and repo.lookup(opts['rev']) or \
1806 repo.dirstate.parents()[0] 1859 repo.dirstate.parents()[0]
1807 1860
1808 files, choose, anypats = matchpats(repo, repo.getcwd(), pats, opts) 1861 files, choose, anypats, cwd = matchpats(repo, pats, opts)
1809 (c, a, d, u) = repo.changes(match=choose) 1862 (c, a, d, u) = repo.changes(match=choose)
1810 repo.forget(a) 1863 repo.forget(a)
1811 repo.undelete(d) 1864 repo.undelete(d)
1812 1865
1813 return repo.update(node, False, True, choose, False) 1866 return repo.update(node, False, True, choose, False)
1926 httpd.serve_forever() 1979 httpd.serve_forever()
1927 1980
1928 def status(ui, repo, *pats, **opts): 1981 def status(ui, repo, *pats, **opts):
1929 """show changed files in the working directory 1982 """show changed files in the working directory
1930 1983
1931 Show changed files in the working directory. If no names are 1984 Show changed files in the repository. If names are
1932 given, all files are shown. Otherwise, only files matching the 1985 given, only files that match are shown.
1933 given names are shown.
1934 1986
1935 The codes used to show the status of files are: 1987 The codes used to show the status of files are:
1936 M = modified 1988 M = modified
1937 A = added 1989 A = added
1938 R = removed 1990 R = removed
1939 ? = not tracked 1991 ? = not tracked
1940 """ 1992 """
1941 1993
1942 cwd = repo.getcwd() 1994 files, matchfn, anypats, cwd = matchpats(repo, pats, opts)
1943 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1944 (c, a, d, u) = [[util.pathto(cwd, x) for x in n] 1995 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1945 for n in repo.changes(files=files, match=matchfn)] 1996 for n in repo.changes(files=files, match=matchfn)]
1946 1997
1947 changetypes = [(_('modified'), 'M', c), 1998 changetypes = [(_('modified'), 'M', c),
1948 (_('added'), 'A', a), 1999 (_('added'), 'A', a),
1984 if rev: 2035 if rev:
1985 r = hex(repo.lookup(rev)) 2036 r = hex(repo.lookup(rev))
1986 else: 2037 else:
1987 r = hex(repo.changelog.tip()) 2038 r = hex(repo.changelog.tip())
1988 2039
1989 if name.find(revrangesep) >= 0: 2040 disallowed = (revrangesep, '\r', '\n')
1990 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep) 2041 for c in disallowed:
2042 if name.find(c) >= 0:
2043 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
1991 2044
1992 if opts['local']: 2045 if opts['local']:
1993 repo.opener("localtags", "a").write("%s %s\n" % (r, name)) 2046 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1994 return 2047 return
1995 2048
2136 "^annotate": 2189 "^annotate":
2137 (annotate, 2190 (annotate,
2138 [('r', 'rev', '', _('annotate the specified revision')), 2191 [('r', 'rev', '', _('annotate the specified revision')),
2139 ('a', 'text', None, _('treat all files as text')), 2192 ('a', 'text', None, _('treat all files as text')),
2140 ('u', 'user', None, _('list the author')), 2193 ('u', 'user', None, _('list the author')),
2194 ('d', 'date', None, _('list the date')),
2141 ('n', 'number', None, _('list the revision number (default)')), 2195 ('n', 'number', None, _('list the revision number (default)')),
2142 ('c', 'changeset', None, _('list the changeset')), 2196 ('c', 'changeset', None, _('list the changeset')),
2143 ('I', 'include', [], _('include names matching the given patterns')), 2197 ('I', 'include', [], _('include names matching the given patterns')),
2144 ('X', 'exclude', [], _('exclude names matching the given patterns'))], 2198 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2145 _('hg annotate [OPTION]... FILE...')), 2199 _('hg annotate [OPTION]... FILE...')),
2221 ('r', 'rev', [], _('search in given revision range')), 2275 ('r', 'rev', [], _('search in given revision range')),
2222 ('u', 'user', None, _('print user who committed change'))], 2276 ('u', 'user', None, _('print user who committed change'))],
2223 "hg grep [OPTION]... PATTERN [FILE]..."), 2277 "hg grep [OPTION]... PATTERN [FILE]..."),
2224 "heads": 2278 "heads":
2225 (heads, 2279 (heads,
2226 [('b', 'branches', None, _('find branch info'))], 2280 [('b', 'branches', None, _('find branch info')),
2227 _('hg heads [-b]')), 2281 ('r', 'rev', "", _('show only heads which are descendants of rev'))],
2282 _('hg heads [-b] [-r <rev>]')),
2228 "help": (help_, [], _('hg help [COMMAND]')), 2283 "help": (help_, [], _('hg help [COMMAND]')),
2229 "identify|id": (identify, [], _('hg identify')), 2284 "identify|id": (identify, [], _('hg identify')),
2230 "import|patch": 2285 "import|patch":
2231 (import_, 2286 (import_,
2232 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') + 2287 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2372 2427
2373 norepo = ("clone init version help debugancestor debugconfig debugdata" 2428 norepo = ("clone init version help debugancestor debugconfig debugdata"
2374 " debugindex debugindexdot paths") 2429 " debugindex debugindexdot paths")
2375 2430
2376 def find(cmd): 2431 def find(cmd):
2377 choice = [] 2432 """Return (aliases, command table entry) for command string."""
2433 choice = None
2378 for e in table.keys(): 2434 for e in table.keys():
2379 aliases = e.lstrip("^").split("|") 2435 aliases = e.lstrip("^").split("|")
2380 if cmd in aliases: 2436 if cmd in aliases:
2381 return e, table[e] 2437 return aliases, table[e]
2382 for a in aliases: 2438 for a in aliases:
2383 if a.startswith(cmd): 2439 if a.startswith(cmd):
2384 choice.append(e) 2440 if choice:
2385 if len(choice) == 1: 2441 raise AmbiguousCommand(cmd)
2386 e = choice[0] 2442 else:
2387 return e, table[e] 2443 choice = aliases, table[e]
2444 break
2445 if choice:
2446 return choice
2388 2447
2389 raise UnknownCommand(cmd) 2448 raise UnknownCommand(cmd)
2390 2449
2391 class SignalInterrupt(Exception): 2450 class SignalInterrupt(Exception):
2392 """Exception raised on SIGTERM and SIGHUP.""" 2451 """Exception raised on SIGTERM and SIGHUP."""
2409 except fancyopts.getopt.GetoptError, inst: 2468 except fancyopts.getopt.GetoptError, inst:
2410 raise ParseError(None, inst) 2469 raise ParseError(None, inst)
2411 2470
2412 if args: 2471 if args:
2413 cmd, args = args[0], args[1:] 2472 cmd, args = args[0], args[1:]
2473 aliases, i = find(cmd)
2474 cmd = aliases[0]
2414 defaults = ui.config("defaults", cmd) 2475 defaults = ui.config("defaults", cmd)
2415 if defaults: 2476 if defaults:
2416 # reparse with command defaults added 2477 args = defaults.split() + args
2417 args = [cmd] + defaults.split() + args
2418 try:
2419 args = fancyopts.fancyopts(args, globalopts, options)
2420 except fancyopts.getopt.GetoptError, inst:
2421 raise ParseError(None, inst)
2422
2423 cmd, args = args[0], args[1:]
2424
2425 i = find(cmd)[1]
2426 c = list(i[1]) 2478 c = list(i[1])
2427 else: 2479 else:
2428 cmd = None 2480 cmd = None
2429 c = [] 2481 c = []
2430 2482
2458 sys.stderr.write(_("abort: %s\n") % inst) 2510 sys.stderr.write(_("abort: %s\n") % inst)
2459 sys.exit(1) 2511 sys.exit(1)
2460 2512
2461 external = [] 2513 external = []
2462 for x in u.extensions(): 2514 for x in u.extensions():
2463 def on_exception(Exception, inst): 2515 def on_exception(exc, inst):
2464 u.warn(_("*** failed to import extension %s\n") % x[1]) 2516 u.warn(_("*** failed to import extension %s\n") % x[1])
2465 u.warn("%s\n" % inst) 2517 u.warn("%s\n" % inst)
2466 if "--traceback" in sys.argv[1:]: 2518 if "--traceback" in sys.argv[1:]:
2467 traceback.print_exc() 2519 traceback.print_exc()
2468 if x[1]: 2520 if x[1]:
2500 help_(u, inst.args[0]) 2552 help_(u, inst.args[0])
2501 else: 2553 else:
2502 u.warn(_("hg: %s\n") % inst.args[1]) 2554 u.warn(_("hg: %s\n") % inst.args[1])
2503 help_(u, 'shortlist') 2555 help_(u, 'shortlist')
2504 sys.exit(-1) 2556 sys.exit(-1)
2557 except AmbiguousCommand, inst:
2558 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2559 sys.exit(1)
2505 except UnknownCommand, inst: 2560 except UnknownCommand, inst:
2506 u.warn(_("hg: unknown command '%s'\n") % inst.args[0]) 2561 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2507 help_(u, 'shortlist') 2562 help_(u, 'shortlist')
2508 sys.exit(1) 2563 sys.exit(1)
2509 2564
2618 if len(tb) > 2: # no 2673 if len(tb) > 2: # no
2619 raise 2674 raise
2620 u.debug(inst, "\n") 2675 u.debug(inst, "\n")
2621 u.warn(_("%s: invalid arguments\n") % cmd) 2676 u.warn(_("%s: invalid arguments\n") % cmd)
2622 help_(u, cmd) 2677 help_(u, cmd)
2678 except AmbiguousCommand, inst:
2679 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2680 help_(u, 'shortlist')
2623 except UnknownCommand, inst: 2681 except UnknownCommand, inst:
2624 u.warn(_("hg: unknown command '%s'\n") % inst.args[0]) 2682 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2625 help_(u, 'shortlist') 2683 help_(u, 'shortlist')
2626 except SystemExit: 2684 except SystemExit:
2627 # don't catch this in the catch-all below 2685 # don't catch this in the catch-all below
2628 raise 2686 raise
2629 except: 2687 except:
2630 u.warn(_("** unknown exception encountered, details follow\n")) 2688 u.warn(_("** unknown exception encountered, details follow\n"))
2631 u.warn(_("** report bug details to mercurial@selenic.com\n")) 2689 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2690 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2691 % version.get_version())
2632 raise 2692 raise
2633 2693
2634 sys.exit(-1) 2694 sys.exit(-1)