Mercurial > hg > mercurial-crew-with-dirclash
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) |