changeset 1584 | b3e94785ab69 |
parent 1582 | 63799b01985c |
child 1586 | 5c5aaaa9ab6f |
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) |