##// END OF EJS Templates
Use try/finally pattern to cleanup locks and transactions
Matt Mackall -
r4915:97b734fb default
parent child Browse files
Show More
@@ -19,7 +19,7 b" def fetch(ui, repo, source='default', **"
19 merged, and the result of the merge is committed. Otherwise, the
19 merged, and the result of the merge is committed. Otherwise, the
20 working directory is updated.'''
20 working directory is updated.'''
21
21
22 def postincoming(other, modheads):
22 def postincoming(other, modheads, lock, wlock):
23 if modheads == 0:
23 if modheads == 0:
24 return 0
24 return 0
25 if modheads == 1:
25 if modheads == 1:
@@ -50,7 +50,7 b" def fetch(ui, repo, source='default', **"
50 ui.status(_('new changeset %d:%s merges remote changes '
50 ui.status(_('new changeset %d:%s merges remote changes '
51 'with local\n') % (repo.changelog.rev(n),
51 'with local\n') % (repo.changelog.rev(n),
52 short(n)))
52 short(n)))
53 def pull():
53 def pull(lock, wlock):
54 cmdutil.setremoteconfig(ui, opts)
54 cmdutil.setremoteconfig(ui, opts)
55
55
56 other = hg.repository(ui, ui.expandpath(source))
56 other = hg.repository(ui, ui.expandpath(source))
@@ -61,7 +61,7 b" def fetch(ui, repo, source='default', **"
61 elif opts['rev']:
61 elif opts['rev']:
62 revs = [other.lookup(rev) for rev in opts['rev']]
62 revs = [other.lookup(rev) for rev in opts['rev']]
63 modheads = repo.pull(other, heads=revs, lock=lock)
63 modheads = repo.pull(other, heads=revs, lock=lock)
64 return postincoming(other, modheads)
64 return postincoming(other, modheads, lock, wlock)
65
65
66 parent, p2 = repo.dirstate.parents()
66 parent, p2 = repo.dirstate.parents()
67 if parent != repo.changelog.tip():
67 if parent != repo.changelog.tip():
@@ -69,19 +69,19 b" def fetch(ui, repo, source='default', **"
69 '(use "hg update" to check out tip)'))
69 '(use "hg update" to check out tip)'))
70 if p2 != nullid:
70 if p2 != nullid:
71 raise util.Abort(_('outstanding uncommitted merge'))
71 raise util.Abort(_('outstanding uncommitted merge'))
72 wlock = repo.wlock()
72 wlock = lock = None
73 lock = repo.lock()
74 try:
73 try:
74 wlock = repo.wlock()
75 lock = repo.lock()
75 mod, add, rem = repo.status(wlock=wlock)[:3]
76 mod, add, rem = repo.status(wlock=wlock)[:3]
76 if mod or add or rem:
77 if mod or add or rem:
77 raise util.Abort(_('outstanding uncommitted changes'))
78 raise util.Abort(_('outstanding uncommitted changes'))
78 if len(repo.heads()) > 1:
79 if len(repo.heads()) > 1:
79 raise util.Abort(_('multiple heads in this repository '
80 raise util.Abort(_('multiple heads in this repository '
80 '(use "hg heads" and "hg merge" to merge)'))
81 '(use "hg heads" and "hg merge" to merge)'))
81 return pull()
82 return pull(lock, wlock)
82 finally:
83 finally:
83 lock.release()
84 del lock, wlock
84 wlock.release()
85
85
86 cmdtable = {
86 cmdtable = {
87 'fetch':
87 'fetch':
This diff has been collapsed as it changes many lines, (721 lines changed) Show them Hide them
@@ -439,24 +439,28 b' class queue:'
439 def apply(self, repo, series, list=False, update_status=True,
439 def apply(self, repo, series, list=False, update_status=True,
440 strict=False, patchdir=None, merge=None, wlock=None,
440 strict=False, patchdir=None, merge=None, wlock=None,
441 all_files={}):
441 all_files={}):
442 if not wlock:
442 lock = tr = None
443 wlock = repo.wlock()
444 lock = repo.lock()
445 tr = repo.transaction()
446 try:
443 try:
447 ret = self._apply(tr, repo, series, list, update_status,
444 if not wlock:
448 strict, patchdir, merge, wlock,
445 wlock = repo.wlock()
449 lock=lock, all_files=all_files)
446 lock = repo.lock()
450 tr.close()
447 tr = repo.transaction()
451 self.save_dirty()
452 return ret
453 except:
454 try:
448 try:
455 tr.abort()
449 ret = self._apply(tr, repo, series, list, update_status,
456 finally:
450 strict, patchdir, merge, wlock,
457 repo.invalidate()
451 lock=lock, all_files=all_files)
458 repo.dirstate.invalidate()
452 tr.close()
459 raise
453 self.save_dirty()
454 return ret
455 except:
456 try:
457 tr.abort()
458 finally:
459 repo.invalidate()
460 repo.dirstate.invalidate()
461 raise
462 finally:
463 del lock, wlock, tr
460
464
461 def _apply(self, tr, repo, series, list=False, update_status=True,
465 def _apply(self, tr, repo, series, list=False, update_status=True,
462 strict=False, patchdir=None, merge=None, wlock=None,
466 strict=False, patchdir=None, merge=None, wlock=None,
@@ -616,44 +620,51 b' class queue:'
616 commitfiles = m + a + r
620 commitfiles = m + a + r
617 self.check_toppatch(repo)
621 self.check_toppatch(repo)
618 wlock = repo.wlock()
622 wlock = repo.wlock()
619 insert = self.full_series_end()
623 try:
620 if msg:
624 insert = self.full_series_end()
621 n = repo.commit(commitfiles, msg, force=True, wlock=wlock)
625 if msg:
622 else:
626 n = repo.commit(commitfiles, msg, force=True, wlock=wlock)
623 n = repo.commit(commitfiles,
627 else:
624 "[mq]: %s" % patch, force=True, wlock=wlock)
628 n = repo.commit(commitfiles,
625 if n == None:
629 "[mq]: %s" % patch, force=True, wlock=wlock)
626 raise util.Abort(_("repo commit failed"))
630 if n == None:
627 self.full_series[insert:insert] = [patch]
631 raise util.Abort(_("repo commit failed"))
628 self.applied.append(statusentry(revlog.hex(n), patch))
632 self.full_series[insert:insert] = [patch]
629 self.parse_series()
633 self.applied.append(statusentry(revlog.hex(n), patch))
630 self.series_dirty = 1
634 self.parse_series()
631 self.applied_dirty = 1
635 self.series_dirty = 1
632 p = self.opener(patch, "w")
636 self.applied_dirty = 1
633 if msg:
637 p = self.opener(patch, "w")
634 msg = msg + "\n"
638 if msg:
635 p.write(msg)
639 msg = msg + "\n"
636 p.close()
640 p.write(msg)
637 wlock = None
641 p.close()
638 r = self.qrepo()
642 wlock = None
639 if r: r.add([patch])
643 r = self.qrepo()
640 if commitfiles:
644 if r: r.add([patch])
641 self.refresh(repo, short=True)
645 if commitfiles:
642 self.removeundo(repo)
646 self.refresh(repo, short=True)
647 self.removeundo(repo)
648 finally:
649 del wlock
643
650
644 def strip(self, repo, rev, update=True, backup="all", wlock=None):
651 def strip(self, repo, rev, update=True, backup="all", wlock=None):
645 if not wlock:
652 lock = None
646 wlock = repo.wlock()
653 try:
647 lock = repo.lock()
654 if not wlock:
655 wlock = repo.wlock()
656 lock = repo.lock()
648
657
649 if update:
658 if update:
650 self.check_localchanges(repo, refresh=False)
659 self.check_localchanges(repo, refresh=False)
651 urev = self.qparents(repo, rev)
660 urev = self.qparents(repo, rev)
652 hg.clean(repo, urev, wlock=wlock)
661 hg.clean(repo, urev, wlock=wlock)
653 repo.dirstate.write()
662 repo.dirstate.write()
654
663
655 self.removeundo(repo)
664 self.removeundo(repo)
656 repair.strip(self.ui, repo, rev, backup)
665 repair.strip(self.ui, repo, rev, backup)
666 finally:
667 del lock, wlock
657
668
658 def isapplied(self, patch):
669 def isapplied(self, patch):
659 """returns (index, rev, patch)"""
670 """returns (index, rev, patch)"""
@@ -740,69 +751,74 b' class queue:'
740 mergeq=None, wlock=None):
751 mergeq=None, wlock=None):
741 if not wlock:
752 if not wlock:
742 wlock = repo.wlock()
753 wlock = repo.wlock()
743 patch = self.lookup(patch)
754 try:
744 # Suppose our series file is: A B C and the current 'top' patch is B.
755 patch = self.lookup(patch)
745 # qpush C should be performed (moving forward)
756 # Suppose our series file is: A B C and the current 'top'
746 # qpush B is a NOP (no change)
757 # patch is B. qpush C should be performed (moving forward)
747 # qpush A is an error (can't go backwards with qpush)
758 # qpush B is a NOP (no change) qpush A is an error (can't
748 if patch:
759 # go backwards with qpush)
749 info = self.isapplied(patch)
760 if patch:
750 if info:
761 info = self.isapplied(patch)
751 if info[0] < len(self.applied) - 1:
762 if info:
752 raise util.Abort(_("cannot push to a previous patch: %s") %
763 if info[0] < len(self.applied) - 1:
753 patch)
764 raise util.Abort(
754 if info[0] < len(self.series) - 1:
765 _("cannot push to a previous patch: %s") % patch)
755 self.ui.warn(_('qpush: %s is already at the top\n') % patch)
766 if info[0] < len(self.series) - 1:
756 else:
767 self.ui.warn(
757 self.ui.warn(_('all patches are currently applied\n'))
768 _('qpush: %s is already at the top\n') % patch)
758 return
769 else:
770 self.ui.warn(_('all patches are currently applied\n'))
771 return
759
772
760 # Following the above example, starting at 'top' of B:
773 # Following the above example, starting at 'top' of B:
761 # qpush should be performed (pushes C), but a subsequent qpush without
774 # qpush should be performed (pushes C), but a subsequent
762 # an argument is an error (nothing to apply). This allows a loop
775 # qpush without an argument is an error (nothing to
763 # of "...while hg qpush..." to work as it detects an error when done
776 # apply). This allows a loop of "...while hg qpush..." to
764 if self.series_end() == len(self.series):
777 # work as it detects an error when done
765 self.ui.warn(_('patch series already fully applied\n'))
778 if self.series_end() == len(self.series):
766 return 1
779 self.ui.warn(_('patch series already fully applied\n'))
767 if not force:
780 return 1
768 self.check_localchanges(repo)
781 if not force:
782 self.check_localchanges(repo)
769
783
770 self.applied_dirty = 1;
784 self.applied_dirty = 1;
771 start = self.series_end()
785 start = self.series_end()
772 if start > 0:
786 if start > 0:
773 self.check_toppatch(repo)
787 self.check_toppatch(repo)
774 if not patch:
788 if not patch:
775 patch = self.series[start]
789 patch = self.series[start]
776 end = start + 1
790 end = start + 1
777 else:
778 end = self.series.index(patch, start) + 1
779 s = self.series[start:end]
780 all_files = {}
781 try:
782 if mergeq:
783 ret = self.mergepatch(repo, mergeq, s, wlock)
784 else:
791 else:
785 ret = self.apply(repo, s, list, wlock=wlock,
792 end = self.series.index(patch, start) + 1
786 all_files=all_files)
793 s = self.series[start:end]
787 except:
794 all_files = {}
788 self.ui.warn(_('cleaning up working directory...'))
795 try:
789 node = repo.dirstate.parents()[0]
796 if mergeq:
790 hg.revert(repo, node, None, wlock)
797 ret = self.mergepatch(repo, mergeq, s, wlock)
791 unknown = repo.status(wlock=wlock)[4]
798 else:
792 # only remove unknown files that we know we touched or
799 ret = self.apply(repo, s, list, wlock=wlock,
793 # created while patching
800 all_files=all_files)
794 for f in unknown:
801 except:
795 if f in all_files:
802 self.ui.warn(_('cleaning up working directory...'))
796 util.unlink(repo.wjoin(f))
803 node = repo.dirstate.parents()[0]
797 self.ui.warn(_('done\n'))
804 hg.revert(repo, node, None, wlock)
798 raise
805 unknown = repo.status(wlock=wlock)[4]
799 top = self.applied[-1].name
806 # only remove unknown files that we know we touched or
800 if ret[0]:
807 # created while patching
801 self.ui.write("Errors during apply, please fix and refresh %s\n" %
808 for f in unknown:
802 top)
809 if f in all_files:
803 else:
810 util.unlink(repo.wjoin(f))
804 self.ui.write("Now at: %s\n" % top)
811 self.ui.warn(_('done\n'))
805 return ret[0]
812 raise
813 top = self.applied[-1].name
814 if ret[0]:
815 self.ui.write(
816 "Errors during apply, please fix and refresh %s\n" % top)
817 else:
818 self.ui.write("Now at: %s\n" % top)
819 return ret[0]
820 finally:
821 del wlock
806
822
807 def pop(self, repo, patch=None, force=False, update=True, all=False,
823 def pop(self, repo, patch=None, force=False, update=True, all=False,
808 wlock=None):
824 wlock=None):
@@ -812,82 +828,85 b' class queue:'
812
828
813 if not wlock:
829 if not wlock:
814 wlock = repo.wlock()
830 wlock = repo.wlock()
815 if patch:
831 try:
816 # index, rev, patch
832 if patch:
817 info = self.isapplied(patch)
833 # index, rev, patch
818 if not info:
834 info = self.isapplied(patch)
819 patch = self.lookup(patch)
835 if not info:
820 info = self.isapplied(patch)
836 patch = self.lookup(patch)
821 if not info:
837 info = self.isapplied(patch)
822 raise util.Abort(_("patch %s is not applied") % patch)
838 if not info:
839 raise util.Abort(_("patch %s is not applied") % patch)
823
840
824 if len(self.applied) == 0:
841 if len(self.applied) == 0:
825 # Allow qpop -a to work repeatedly,
842 # Allow qpop -a to work repeatedly,
826 # but not qpop without an argument
843 # but not qpop without an argument
827 self.ui.warn(_("no patches applied\n"))
844 self.ui.warn(_("no patches applied\n"))
828 return not all
845 return not all
829
846
830 if not update:
847 if not update:
831 parents = repo.dirstate.parents()
848 parents = repo.dirstate.parents()
832 rr = [ revlog.bin(x.rev) for x in self.applied ]
849 rr = [ revlog.bin(x.rev) for x in self.applied ]
833 for p in parents:
850 for p in parents:
834 if p in rr:
851 if p in rr:
835 self.ui.warn("qpop: forcing dirstate update\n")
852 self.ui.warn("qpop: forcing dirstate update\n")
836 update = True
853 update = True
837
854
838 if not force and update:
855 if not force and update:
839 self.check_localchanges(repo)
856 self.check_localchanges(repo)
840
857
841 self.applied_dirty = 1;
858 self.applied_dirty = 1;
842 end = len(self.applied)
859 end = len(self.applied)
843 if not patch:
860 if not patch:
844 if all:
861 if all:
845 popi = 0
862 popi = 0
863 else:
864 popi = len(self.applied) - 1
846 else:
865 else:
847 popi = len(self.applied) - 1
866 popi = info[0] + 1
848 else:
867 if popi >= end:
849 popi = info[0] + 1
868 self.ui.warn("qpop: %s is already at the top\n" % patch)
850 if popi >= end:
869 return
851 self.ui.warn("qpop: %s is already at the top\n" % patch)
870 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
852 return
853 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
854
871
855 start = info[0]
872 start = info[0]
856 rev = revlog.bin(info[1])
873 rev = revlog.bin(info[1])
857
874
858 # we know there are no local changes, so we can make a simplified
875 # we know there are no local changes, so we can make a simplified
859 # form of hg.update.
876 # form of hg.update.
860 if update:
877 if update:
861 top = self.check_toppatch(repo)
878 top = self.check_toppatch(repo)
862 qp = self.qparents(repo, rev)
879 qp = self.qparents(repo, rev)
863 changes = repo.changelog.read(qp)
880 changes = repo.changelog.read(qp)
864 mmap = repo.manifest.read(changes[0])
881 mmap = repo.manifest.read(changes[0])
865 m, a, r, d, u = repo.status(qp, top)[:5]
882 m, a, r, d, u = repo.status(qp, top)[:5]
866 if d:
883 if d:
867 raise util.Abort("deletions found between repo revs")
884 raise util.Abort("deletions found between repo revs")
868 for f in m:
885 for f in m:
869 getfile(f, mmap[f])
886 getfile(f, mmap[f])
870 for f in r:
887 for f in r:
871 getfile(f, mmap[f])
888 getfile(f, mmap[f])
872 util.set_exec(repo.wjoin(f), mmap.execf(f))
889 util.set_exec(repo.wjoin(f), mmap.execf(f))
873 for f in m + r:
890 for f in m + r:
874 repo.dirstate.normal(f)
891 repo.dirstate.normal(f)
875 for f in a:
892 for f in a:
876 try:
893 try:
877 os.unlink(repo.wjoin(f))
894 os.unlink(repo.wjoin(f))
878 except OSError, e:
895 except OSError, e:
879 if e.errno != errno.ENOENT:
896 if e.errno != errno.ENOENT:
880 raise
897 raise
881 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
898 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
882 except: pass
899 except: pass
883 repo.dirstate.forget(f)
900 repo.dirstate.forget(f)
884 repo.dirstate.setparents(qp, revlog.nullid)
901 repo.dirstate.setparents(qp, revlog.nullid)
885 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
902 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
886 del self.applied[start:end]
903 del self.applied[start:end]
887 if len(self.applied):
904 if len(self.applied):
888 self.ui.write("Now at: %s\n" % self.applied[-1].name)
905 self.ui.write("Now at: %s\n" % self.applied[-1].name)
889 else:
906 else:
890 self.ui.write("Patch queue now empty\n")
907 self.ui.write("Patch queue now empty\n")
908 finally:
909 del wlock
891
910
892 def diff(self, repo, pats, opts):
911 def diff(self, repo, pats, opts):
893 top = self.check_toppatch(repo)
912 top = self.check_toppatch(repo)
@@ -904,179 +923,184 b' class queue:'
904 self.ui.write("No patches applied\n")
923 self.ui.write("No patches applied\n")
905 return 1
924 return 1
906 wlock = repo.wlock()
925 wlock = repo.wlock()
907 self.check_toppatch(repo)
926 try:
908 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
927 self.check_toppatch(repo)
909 top = revlog.bin(top)
928 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
910 cparents = repo.changelog.parents(top)
929 top = revlog.bin(top)
911 patchparent = self.qparents(repo, top)
930 cparents = repo.changelog.parents(top)
912 message, comments, user, date, patchfound = self.readheaders(patchfn)
931 patchparent = self.qparents(repo, top)
913
932 message, comments, user, date, patchfound = self.readheaders(patchfn)
914 patchf = self.opener(patchfn, 'r+')
915
916 # if the patch was a git patch, refresh it as a git patch
917 for line in patchf:
918 if line.startswith('diff --git'):
919 self.diffopts().git = True
920 break
921 patchf.seek(0)
922 patchf.truncate()
923
933
924 msg = opts.get('msg', '').rstrip()
934 patchf = self.opener(patchfn, 'r+')
925 if msg:
935
926 if comments:
936 # if the patch was a git patch, refresh it as a git patch
927 # Remove existing message.
937 for line in patchf:
928 ci = 0
938 if line.startswith('diff --git'):
929 subj = None
939 self.diffopts().git = True
930 for mi in xrange(len(message)):
940 break
931 if comments[ci].lower().startswith('subject: '):
941 patchf.seek(0)
932 subj = comments[ci][9:]
942 patchf.truncate()
933 while message[mi] != comments[ci] and message[mi] != subj:
934 ci += 1
935 del comments[ci]
936 comments.append(msg)
937 if comments:
938 comments = "\n".join(comments) + '\n\n'
939 patchf.write(comments)
940
943
941 if opts.get('git'):
944 msg = opts.get('msg', '').rstrip()
942 self.diffopts().git = True
945 if msg:
943 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
946 if comments:
944 tip = repo.changelog.tip()
947 # Remove existing message.
945 if top == tip:
948 ci = 0
946 # if the top of our patch queue is also the tip, there is an
949 subj = None
947 # optimization here. We update the dirstate in place and strip
950 for mi in xrange(len(message)):
948 # off the tip commit. Then just commit the current directory
951 if comments[ci].lower().startswith('subject: '):
949 # tree. We can also send repo.commit the list of files
952 subj = comments[ci][9:]
950 # changed to speed up the diff
953 while message[mi] != comments[ci] and message[mi] != subj:
951 #
954 ci += 1
952 # in short mode, we only diff the files included in the
955 del comments[ci]
953 # patch already
956 comments.append(msg)
954 #
957 if comments:
955 # this should really read:
958 comments = "\n".join(comments) + '\n\n'
956 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
959 patchf.write(comments)
957 # but we do it backwards to take advantage of manifest/chlog
958 # caching against the next repo.status call
959 #
960 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
961 changes = repo.changelog.read(tip)
962 man = repo.manifest.read(changes[0])
963 aaa = aa[:]
964 if opts.get('short'):
965 filelist = mm + aa + dd
966 match = dict.fromkeys(filelist).__contains__
967 else:
968 filelist = None
969 match = util.always
970 m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
971
960
972 # we might end up with files that were added between tip and
961 if opts.get('git'):
973 # the dirstate parent, but then changed in the local dirstate.
962 self.diffopts().git = True
974 # in this case, we want them to only show up in the added section
963 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
975 for x in m:
964 tip = repo.changelog.tip()
976 if x not in aa:
965 if top == tip:
977 mm.append(x)
966 # if the top of our patch queue is also the tip, there is an
978 # we might end up with files added by the local dirstate that
967 # optimization here. We update the dirstate in place and strip
979 # were deleted by the patch. In this case, they should only
968 # off the tip commit. Then just commit the current directory
980 # show up in the changed section.
969 # tree. We can also send repo.commit the list of files
981 for x in a:
970 # changed to speed up the diff
982 if x in dd:
971 #
983 del dd[dd.index(x)]
972 # in short mode, we only diff the files included in the
984 mm.append(x)
973 # patch already
974 #
975 # this should really read:
976 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
977 # but we do it backwards to take advantage of manifest/chlog
978 # caching against the next repo.status call
979 #
980 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
981 changes = repo.changelog.read(tip)
982 man = repo.manifest.read(changes[0])
983 aaa = aa[:]
984 if opts.get('short'):
985 filelist = mm + aa + dd
986 match = dict.fromkeys(filelist).__contains__
985 else:
987 else:
986 aa.append(x)
988 filelist = None
987 # make sure any files deleted in the local dirstate
989 match = util.always
988 # are not in the add or change column of the patch
990 m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
989 forget = []
990 for x in d + r:
991 if x in aa:
992 del aa[aa.index(x)]
993 forget.append(x)
994 continue
995 elif x in mm:
996 del mm[mm.index(x)]
997 dd.append(x)
998
991
999 m = util.unique(mm)
992 # we might end up with files that were added between
1000 r = util.unique(dd)
993 # tip and the dirstate parent, but then changed in the
1001 a = util.unique(aa)
994 # local dirstate. in this case, we want them to only
1002 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
995 # show up in the added section
1003 filelist = util.unique(c[0] + c[1] + c[2])
996 for x in m:
1004 patch.diff(repo, patchparent, files=filelist, match=matchfn,
997 if x not in aa:
1005 fp=patchf, changes=c, opts=self.diffopts())
998 mm.append(x)
1006 patchf.close()
999 # we might end up with files added by the local dirstate that
1000 # were deleted by the patch. In this case, they should only
1001 # show up in the changed section.
1002 for x in a:
1003 if x in dd:
1004 del dd[dd.index(x)]
1005 mm.append(x)
1006 else:
1007 aa.append(x)
1008 # make sure any files deleted in the local dirstate
1009 # are not in the add or change column of the patch
1010 forget = []
1011 for x in d + r:
1012 if x in aa:
1013 del aa[aa.index(x)]
1014 forget.append(x)
1015 continue
1016 elif x in mm:
1017 del mm[mm.index(x)]
1018 dd.append(x)
1019
1020 m = util.unique(mm)
1021 r = util.unique(dd)
1022 a = util.unique(aa)
1023 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1024 filelist = util.unique(c[0] + c[1] + c[2])
1025 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1026 fp=patchf, changes=c, opts=self.diffopts())
1027 patchf.close()
1007
1028
1008 repo.dirstate.setparents(*cparents)
1029 repo.dirstate.setparents(*cparents)
1009 copies = {}
1030 copies = {}
1010 for dst in a:
1031 for dst in a:
1011 src = repo.dirstate.copied(dst)
1032 src = repo.dirstate.copied(dst)
1012 if src is None:
1033 if src is None:
1013 continue
1034 continue
1014 copies.setdefault(src, []).append(dst)
1035 copies.setdefault(src, []).append(dst)
1015 repo.dirstate.add(dst)
1036 repo.dirstate.add(dst)
1016 # remember the copies between patchparent and tip
1037 # remember the copies between patchparent and tip
1017 # this may be slow, so don't do it if we're not tracking copies
1038 # this may be slow, so don't do it if we're not tracking copies
1018 if self.diffopts().git:
1039 if self.diffopts().git:
1019 for dst in aaa:
1040 for dst in aaa:
1020 f = repo.file(dst)
1041 f = repo.file(dst)
1021 src = f.renamed(man[dst])
1042 src = f.renamed(man[dst])
1022 if src:
1043 if src:
1023 copies[src[0]] = copies.get(dst, [])
1044 copies[src[0]] = copies.get(dst, [])
1024 if dst in a:
1045 if dst in a:
1025 copies[src[0]].append(dst)
1046 copies[src[0]].append(dst)
1026 # we can't copy a file created by the patch itself
1047 # we can't copy a file created by the patch itself
1027 if dst in copies:
1048 if dst in copies:
1028 del copies[dst]
1049 del copies[dst]
1029 for src, dsts in copies.iteritems():
1050 for src, dsts in copies.iteritems():
1030 for dst in dsts:
1051 for dst in dsts:
1031 repo.dirstate.copy(src, dst)
1052 repo.dirstate.copy(src, dst)
1032 for f in r:
1053 for f in r:
1033 repo.dirstate.remove(f)
1054 repo.dirstate.remove(f)
1034 # if the patch excludes a modified file, mark that file with mtime=0
1055 # if the patch excludes a modified file, mark that
1035 # so status can see it.
1056 # file with mtime=0 so status can see it.
1036 mm = []
1057 mm = []
1037 for i in xrange(len(m)-1, -1, -1):
1058 for i in xrange(len(m)-1, -1, -1):
1038 if not matchfn(m[i]):
1059 if not matchfn(m[i]):
1039 mm.append(m[i])
1060 mm.append(m[i])
1040 del m[i]
1061 del m[i]
1041 for f in m:
1062 for f in m:
1042 repo.dirstate.normal(f)
1063 repo.dirstate.normal(f)
1043 for f in mm:
1064 for f in mm:
1044 repo.dirstate.normaldirty(f)
1065 repo.dirstate.normaldirty(f)
1045 for f in forget:
1066 for f in forget:
1046 repo.dirstate.forget(f)
1067 repo.dirstate.forget(f)
1047
1068
1048 if not msg:
1069 if not msg:
1049 if not message:
1070 if not message:
1050 message = "[mq]: %s\n" % patchfn
1071 message = "[mq]: %s\n" % patchfn
1072 else:
1073 message = "\n".join(message)
1051 else:
1074 else:
1052 message = "\n".join(message)
1075 message = msg
1053 else:
1054 message = msg
1055
1076
1056 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1077 self.strip(repo, top, update=False,
1057 n = repo.commit(filelist, message, changes[1], match=matchfn,
1078 backup='strip', wlock=wlock)
1058 force=1, wlock=wlock)
1079 n = repo.commit(filelist, message, changes[1], match=matchfn,
1059 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1080 force=1, wlock=wlock)
1060 self.applied_dirty = 1
1081 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1061 self.removeundo(repo)
1082 self.applied_dirty = 1
1062 else:
1083 self.removeundo(repo)
1063 self.printdiff(repo, patchparent, fp=patchf)
1084 else:
1064 patchf.close()
1085 self.printdiff(repo, patchparent, fp=patchf)
1065 added = repo.status()[1]
1086 patchf.close()
1066 for a in added:
1087 added = repo.status()[1]
1067 f = repo.wjoin(a)
1088 for a in added:
1068 try:
1089 f = repo.wjoin(a)
1069 os.unlink(f)
1090 try:
1070 except OSError, e:
1091 os.unlink(f)
1071 if e.errno != errno.ENOENT:
1092 except OSError, e:
1072 raise
1093 if e.errno != errno.ENOENT:
1073 try: os.removedirs(os.path.dirname(f))
1094 raise
1074 except: pass
1095 try: os.removedirs(os.path.dirname(f))
1075 # forget the file copies in the dirstate
1096 except: pass
1076 # push should readd the files later on
1097 # forget the file copies in the dirstate
1077 repo.dirstate.forget(a)
1098 # push should readd the files later on
1078 self.pop(repo, force=True, wlock=wlock)
1099 repo.dirstate.forget(a)
1079 self.push(repo, force=True, wlock=wlock)
1100 self.pop(repo, force=True, wlock=wlock)
1101 self.push(repo, force=True, wlock=wlock)
1102 finally:
1103 del wlock
1080
1104
1081 def init(self, repo, create=False):
1105 def init(self, repo, create=False):
1082 if not create and os.path.isdir(self.path):
1106 if not create and os.path.isdir(self.path):
@@ -1872,10 +1896,13 b' def rename(ui, repo, patch, name=None, *'
1872 r = q.qrepo()
1896 r = q.qrepo()
1873 if r:
1897 if r:
1874 wlock = r.wlock()
1898 wlock = r.wlock()
1875 if r.dirstate[name] == 'r':
1899 try:
1876 r.undelete([name], wlock)
1900 if r.dirstate[name] == 'r':
1877 r.copy(patch, name, wlock)
1901 r.undelete([name], wlock)
1878 r.remove([patch], False, wlock)
1902 r.copy(patch, name, wlock)
1903 r.remove([patch], False, wlock)
1904 finally:
1905 del wlock
1879
1906
1880 q.save_dirty()
1907 q.save_dirty()
1881
1908
@@ -96,9 +96,10 b' class transplanter:'
96 diffopts = patch.diffopts(self.ui, opts)
96 diffopts = patch.diffopts(self.ui, opts)
97 diffopts.git = True
97 diffopts.git = True
98
98
99 wlock = repo.wlock()
99 lock = wlock = None
100 lock = repo.lock()
101 try:
100 try:
101 wlock = repo.wlock()
102 lock = repo.lock()
102 for rev in revs:
103 for rev in revs:
103 node = revmap[rev]
104 node = revmap[rev]
104 revstr = '%s:%s' % (rev, revlog.short(node))
105 revstr = '%s:%s' % (rev, revlog.short(node))
@@ -166,6 +167,7 b' class transplanter:'
166 finally:
167 finally:
167 self.saveseries(revmap, merges)
168 self.saveseries(revmap, merges)
168 self.transplants.write()
169 self.transplants.write()
170 del lock, wlock
169
171
170 def filter(self, filter, changelog, patchfile):
172 def filter(self, filter, changelog, patchfile):
171 '''arbitrarily rewrite changeset before applying it'''
173 '''arbitrarily rewrite changeset before applying it'''
@@ -272,20 +274,25 b' class transplanter:'
272
274
273 extra = {'transplant_source': node}
275 extra = {'transplant_source': node}
274 wlock = repo.wlock()
276 wlock = repo.wlock()
275 p1, p2 = repo.dirstate.parents()
277 try:
276 if p1 != parents[0]:
278 p1, p2 = repo.dirstate.parents()
277 raise util.Abort(_('working dir not at transplant parent %s') %
279 if p1 != parents[0]:
278 revlog.hex(parents[0]))
280 raise util.Abort(
279 if merge:
281 _('working dir not at transplant parent %s') %
280 repo.dirstate.setparents(p1, parents[1])
282 revlog.hex(parents[0]))
281 n = repo.commit(None, message, user, date, wlock=wlock, extra=extra)
283 if merge:
282 if not n:
284 repo.dirstate.setparents(p1, parents[1])
283 raise util.Abort(_('commit failed'))
285 n = repo.commit(None, message, user, date, wlock=wlock,
284 if not merge:
286 extra=extra)
285 self.transplants.set(n, node)
287 if not n:
286 self.unlog()
288 raise util.Abort(_('commit failed'))
289 if not merge:
290 self.transplants.set(n, node)
291 self.unlog()
287
292
288 return n, node
293 return n, node
294 finally:
295 del wlock
289
296
290 def readseries(self):
297 def readseries(self):
291 nodes = []
298 nodes = []
@@ -676,7 +676,10 b' def copy(ui, repo, *pats, **opts):'
676 before that, see hg revert.
676 before that, see hg revert.
677 """
677 """
678 wlock = repo.wlock(False)
678 wlock = repo.wlock(False)
679 errs, copied = docopy(ui, repo, pats, opts, wlock)
679 try:
680 errs, copied = docopy(ui, repo, pats, opts, wlock)
681 finally:
682 del wlock
680 return errs
683 return errs
681
684
682 def debugancestor(ui, index, rev1, rev2):
685 def debugancestor(ui, index, rev1, rev2):
@@ -713,7 +716,10 b' def debugrebuildstate(ui, repo, rev=""):'
713 ctx = repo.changectx(rev)
716 ctx = repo.changectx(rev)
714 files = ctx.manifest()
717 files = ctx.manifest()
715 wlock = repo.wlock()
718 wlock = repo.wlock()
716 repo.dirstate.rebuild(rev, files)
719 try:
720 repo.dirstate.rebuild(rev, files)
721 finally:
722 del wlock
717
723
718 def debugcheckstate(ui, repo):
724 def debugcheckstate(ui, repo):
719 """validate the correctness of the current dirstate"""
725 """validate the correctness of the current dirstate"""
@@ -782,7 +788,7 b' def debugsetparents(ui, repo, rev1, rev2'
782 try:
788 try:
783 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
789 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
784 finally:
790 finally:
785 wlock.release()
791 del wlock
786
792
787 def debugstate(ui, repo):
793 def debugstate(ui, repo):
788 """show the contents of the current dirstate"""
794 """show the contents of the current dirstate"""
@@ -1581,70 +1587,76 b' def import_(ui, repo, patch1, *patches, '
1581
1587
1582 d = opts["base"]
1588 d = opts["base"]
1583 strip = opts["strip"]
1589 strip = opts["strip"]
1584
1590 wlock = lock = None
1585 wlock = repo.wlock()
1591 try:
1586 lock = repo.lock()
1592 wlock = repo.wlock()
1587
1593 lock = repo.lock()
1588 for p in patches:
1594 for p in patches:
1589 pf = os.path.join(d, p)
1595 pf = os.path.join(d, p)
1590
1596
1591 if pf == '-':
1597 if pf == '-':
1592 ui.status(_("applying patch from stdin\n"))
1598 ui.status(_("applying patch from stdin\n"))
1593 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1599 data = patch.extract(ui, sys.stdin)
1594 else:
1595 ui.status(_("applying %s\n") % p)
1596 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1597
1598 if tmpname is None:
1599 raise util.Abort(_('no diffs found'))
1600
1601 try:
1602 cmdline_message = cmdutil.logmessage(opts)
1603 if cmdline_message:
1604 # pickup the cmdline msg
1605 message = cmdline_message
1606 elif message:
1607 # pickup the patch msg
1608 message = message.strip()
1609 else:
1600 else:
1610 # launch the editor
1601 ui.status(_("applying %s\n") % p)
1611 message = None
1602 data = patch.extract(ui, file(pf, 'rb'))
1612 ui.debug(_('message:\n%s\n') % message)
1603
1613
1604 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1614 wp = repo.workingctx().parents()
1605
1615 if opts.get('exact'):
1606 if tmpname is None:
1616 if not nodeid or not p1:
1607 raise util.Abort(_('no diffs found'))
1617 raise util.Abort(_('not a mercurial patch'))
1608
1618 p1 = repo.lookup(p1)
1609 try:
1619 p2 = repo.lookup(p2 or hex(nullid))
1610 cmdline_message = cmdutil.logmessage(opts)
1620
1611 if cmdline_message:
1621 if p1 != wp[0].node():
1612 # pickup the cmdline msg
1622 hg.clean(repo, p1, wlock=wlock)
1613 message = cmdline_message
1623 repo.dirstate.setparents(p1, p2)
1614 elif message:
1624 elif p2:
1615 # pickup the patch msg
1625 try:
1616 message = message.strip()
1617 else:
1618 # launch the editor
1619 message = None
1620 ui.debug(_('message:\n%s\n') % message)
1621
1622 wp = repo.workingctx().parents()
1623 if opts.get('exact'):
1624 if not nodeid or not p1:
1625 raise util.Abort(_('not a mercurial patch'))
1626 p1 = repo.lookup(p1)
1626 p1 = repo.lookup(p1)
1627 p2 = repo.lookup(p2)
1627 p2 = repo.lookup(p2 or hex(nullid))
1628 if p1 == wp[0].node():
1628
1629 repo.dirstate.setparents(p1, p2)
1629 if p1 != wp[0].node():
1630 except hg.RepoError:
1630 hg.clean(repo, p1, wlock=wlock)
1631 pass
1631 repo.dirstate.setparents(p1, p2)
1632 if opts.get('exact') or opts.get('import_branch'):
1632 elif p2:
1633 repo.dirstate.setbranch(branch or 'default')
1633 try:
1634
1634 p1 = repo.lookup(p1)
1635 files = {}
1635 p2 = repo.lookup(p2)
1636 try:
1636 if p1 == wp[0].node():
1637 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1637 repo.dirstate.setparents(p1, p2)
1638 files=files)
1638 except hg.RepoError:
1639 pass
1640 if opts.get('exact') or opts.get('import_branch'):
1641 repo.dirstate.setbranch(branch or 'default')
1642
1643 files = {}
1644 try:
1645 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1646 files=files)
1647 finally:
1648 files = patch.updatedir(ui, repo, files, wlock=wlock)
1649 n = repo.commit(files, message, user, date, wlock=wlock,
1650 lock=lock)
1651 if opts.get('exact'):
1652 if hex(n) != nodeid:
1653 repo.rollback(wlock=wlock, lock=lock)
1654 raise util.Abort(_('patch is damaged' +
1655 ' or loses information'))
1639 finally:
1656 finally:
1640 files = patch.updatedir(ui, repo, files, wlock=wlock)
1657 os.unlink(tmpname)
1641 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1658 finally:
1642 if opts.get('exact'):
1659 del wlock, lock
1643 if hex(n) != nodeid:
1644 repo.rollback(wlock=wlock, lock=lock)
1645 raise util.Abort(_('patch is damaged or loses information'))
1646 finally:
1647 os.unlink(tmpname)
1648
1660
1649 def incoming(ui, repo, source="default", **opts):
1661 def incoming(ui, repo, source="default", **opts):
1650 """show new changesets found in source
1662 """show new changesets found in source
@@ -2248,15 +2260,18 b' def rename(ui, repo, *pats, **opts):'
2248 before that, see hg revert.
2260 before that, see hg revert.
2249 """
2261 """
2250 wlock = repo.wlock(False)
2262 wlock = repo.wlock(False)
2251 errs, copied = docopy(ui, repo, pats, opts, wlock)
2263 try:
2252 names = []
2264 errs, copied = docopy(ui, repo, pats, opts, wlock)
2253 for abs, rel, exact in copied:
2265 names = []
2254 if ui.verbose or not exact:
2266 for abs, rel, exact in copied:
2255 ui.status(_('removing %s\n') % rel)
2267 if ui.verbose or not exact:
2256 names.append(abs)
2268 ui.status(_('removing %s\n') % rel)
2257 if not opts.get('dry_run'):
2269 names.append(abs)
2258 repo.remove(names, True, wlock=wlock)
2270 if not opts.get('dry_run'):
2259 return errs
2271 repo.remove(names, True, wlock=wlock)
2272 return errs
2273 finally:
2274 del wlock
2260
2275
2261 def revert(ui, repo, *pats, **opts):
2276 def revert(ui, repo, *pats, **opts):
2262 """revert files or dirs to their states as of some revision
2277 """revert files or dirs to their states as of some revision
@@ -2310,8 +2325,6 b' def revert(ui, repo, *pats, **opts):'
2310 else:
2325 else:
2311 pmf = None
2326 pmf = None
2312
2327
2313 wlock = repo.wlock()
2314
2315 # need all matching names in dirstate and manifest of target rev,
2328 # need all matching names in dirstate and manifest of target rev,
2316 # so have to walk both. do not print errors if files exist in one
2329 # so have to walk both. do not print errors if files exist in one
2317 # but not other.
2330 # but not other.
@@ -2319,113 +2332,116 b' def revert(ui, repo, *pats, **opts):'
2319 names = {}
2332 names = {}
2320 target_only = {}
2333 target_only = {}
2321
2334
2322 # walk dirstate.
2335 wlock = repo.wlock()
2323
2336 try:
2324 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2337 # walk dirstate.
2325 badmatch=mf.has_key):
2338 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2326 names[abs] = (rel, exact)
2339 badmatch=mf.has_key):
2327 if src == 'b':
2340 names[abs] = (rel, exact)
2328 target_only[abs] = True
2341 if src == 'b':
2329
2342 target_only[abs] = True
2330 # walk target manifest.
2343
2331
2344 # walk target manifest.
2332 def badmatch(path):
2345
2333 if path in names:
2346 def badmatch(path):
2334 return True
2347 if path in names:
2335 path_ = path + '/'
2336 for f in names:
2337 if f.startswith(path_):
2338 return True
2348 return True
2339 return False
2349 path_ = path + '/'
2340
2350 for f in names:
2341 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2351 if f.startswith(path_):
2342 badmatch=badmatch):
2352 return True
2343 if abs in names or src == 'b':
2353 return False
2344 continue
2354
2345 names[abs] = (rel, exact)
2355 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2346 target_only[abs] = True
2356 badmatch=badmatch):
2347
2357 if abs in names or src == 'b':
2348 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2358 continue
2349 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2359 names[abs] = (rel, exact)
2350
2360 target_only[abs] = True
2351 revert = ([], _('reverting %s\n'))
2361
2352 add = ([], _('adding %s\n'))
2362 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2353 remove = ([], _('removing %s\n'))
2363 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2354 forget = ([], _('forgetting %s\n'))
2364
2355 undelete = ([], _('undeleting %s\n'))
2365 revert = ([], _('reverting %s\n'))
2356 update = {}
2366 add = ([], _('adding %s\n'))
2357
2367 remove = ([], _('removing %s\n'))
2358 disptable = (
2368 forget = ([], _('forgetting %s\n'))
2359 # dispatch table:
2369 undelete = ([], _('undeleting %s\n'))
2360 # file state
2370 update = {}
2361 # action if in target manifest
2371
2362 # action if not in target manifest
2372 disptable = (
2363 # make backup if in target manifest
2373 # dispatch table:
2364 # make backup if not in target manifest
2374 # file state
2365 (modified, revert, remove, True, True),
2375 # action if in target manifest
2366 (added, revert, forget, True, False),
2376 # action if not in target manifest
2367 (removed, undelete, None, False, False),
2377 # make backup if in target manifest
2368 (deleted, revert, remove, False, False),
2378 # make backup if not in target manifest
2369 (unknown, add, None, True, False),
2379 (modified, revert, remove, True, True),
2370 (target_only, add, None, False, False),
2380 (added, revert, forget, True, False),
2371 )
2381 (removed, undelete, None, False, False),
2372
2382 (deleted, revert, remove, False, False),
2373 entries = names.items()
2383 (unknown, add, None, True, False),
2374 entries.sort()
2384 (target_only, add, None, False, False),
2375
2385 )
2376 for abs, (rel, exact) in entries:
2386
2377 mfentry = mf.get(abs)
2387 entries = names.items()
2378 target = repo.wjoin(abs)
2388 entries.sort()
2379 def handle(xlist, dobackup):
2389
2380 xlist[0].append(abs)
2390 for abs, (rel, exact) in entries:
2381 update[abs] = 1
2391 mfentry = mf.get(abs)
2382 if dobackup and not opts['no_backup'] and util.lexists(target):
2392 target = repo.wjoin(abs)
2383 bakname = "%s.orig" % rel
2393 def handle(xlist, dobackup):
2384 ui.note(_('saving current version of %s as %s\n') %
2394 xlist[0].append(abs)
2385 (rel, bakname))
2395 update[abs] = 1
2386 if not opts.get('dry_run'):
2396 if dobackup and not opts['no_backup'] and util.lexists(target):
2387 util.copyfile(target, bakname)
2397 bakname = "%s.orig" % rel
2388 if ui.verbose or not exact:
2398 ui.note(_('saving current version of %s as %s\n') %
2389 ui.status(xlist[1] % rel)
2399 (rel, bakname))
2390 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2400 if not opts.get('dry_run'):
2391 if abs not in table: continue
2401 util.copyfile(target, bakname)
2392 # file has changed in dirstate
2402 if ui.verbose or not exact:
2393 if mfentry:
2403 ui.status(xlist[1] % rel)
2394 handle(hitlist, backuphit)
2404 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2395 elif misslist is not None:
2405 if abs not in table: continue
2396 handle(misslist, backupmiss)
2406 # file has changed in dirstate
2407 if mfentry:
2408 handle(hitlist, backuphit)
2409 elif misslist is not None:
2410 handle(misslist, backupmiss)
2411 else:
2412 if exact: ui.warn(_('file not managed: %s\n') % rel)
2413 break
2397 else:
2414 else:
2398 if exact: ui.warn(_('file not managed: %s\n') % rel)
2415 # file has not changed in dirstate
2399 break
2416 if node == parent:
2400 else:
2417 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2401 # file has not changed in dirstate
2418 continue
2402 if node == parent:
2419 if pmf is None:
2403 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2420 # only need parent manifest in this unlikely case,
2404 continue
2421 # so do not read by default
2405 if pmf is None:
2422 pmf = repo.changectx(parent).manifest()
2406 # only need parent manifest in this unlikely case,
2423 if abs in pmf:
2407 # so do not read by default
2424 if mfentry:
2408 pmf = repo.changectx(parent).manifest()
2425 # if version of file is same in parent and target
2409 if abs in pmf:
2426 # manifests, do nothing
2410 if mfentry:
2427 if pmf[abs] != mfentry:
2411 # if version of file is same in parent and target
2428 handle(revert, False)
2412 # manifests, do nothing
2429 else:
2413 if pmf[abs] != mfentry:
2430 handle(remove, False)
2414 handle(revert, False)
2431
2415 else:
2432 if not opts.get('dry_run'):
2416 handle(remove, False)
2433 for f in forget[0]:
2417
2434 repo.dirstate.forget(f)
2418 if not opts.get('dry_run'):
2435 r = hg.revert(repo, node, update.has_key, wlock)
2419 for f in forget[0]:
2436 for f in add[0]:
2420 repo.dirstate.forget(f)
2437 repo.dirstate.add(f)
2421 r = hg.revert(repo, node, update.has_key, wlock)
2438 for f in undelete[0]:
2422 for f in add[0]:
2439 repo.dirstate.normal(f)
2423 repo.dirstate.add(f)
2440 for f in remove[0]:
2424 for f in undelete[0]:
2441 repo.dirstate.remove(f)
2425 repo.dirstate.normal(f)
2442 return r
2426 for f in remove[0]:
2443 finally:
2427 repo.dirstate.remove(f)
2444 del wlock
2428 return r
2429
2445
2430 def rollback(ui, repo):
2446 def rollback(ui, repo):
2431 """roll back the last transaction in this repository
2447 """roll back the last transaction in this repository
@@ -130,103 +130,99 b' def clone(ui, source, dest=None, pull=Fa'
130 if self.dir_:
130 if self.dir_:
131 self.rmtree(self.dir_, True)
131 self.rmtree(self.dir_, True)
132
132
133 dir_cleanup = None
133 src_lock = dest_lock = dir_cleanup = None
134 if islocal(dest):
134 try:
135 dir_cleanup = DirCleanup(dest)
135 if islocal(dest):
136 dir_cleanup = DirCleanup(dest)
136
137
137 abspath = origsource
138 abspath = origsource
138 copy = False
139 copy = False
139 if src_repo.local() and islocal(dest):
140 if src_repo.local() and islocal(dest):
140 abspath = os.path.abspath(origsource)
141 abspath = os.path.abspath(origsource)
141 copy = not pull and not rev
142 copy = not pull and not rev
142
143
143 src_lock, dest_lock = None, None
144 if copy:
144 if copy:
145 try:
145 try:
146 # we use a lock here because if we race with commit, we
146 # we use a lock here because if we race with commit, we
147 # can end up with extra data in the cloned revlogs that's
147 # can end up with extra data in the cloned revlogs that's
148 # not pointed to by changesets, thus causing verify to
148 # not pointed to by changesets, thus causing verify to
149 # fail
149 # fail
150 src_lock = src_repo.lock()
150 src_lock = src_repo.lock()
151 except lock.LockException:
151 except lock.LockException:
152 copy = False
152 copy = False
153
153
154 if copy:
154 if copy:
155 def force_copy(src, dst):
155 def force_copy(src, dst):
156 try:
156 try:
157 util.copyfiles(src, dst)
157 util.copyfiles(src, dst)
158 except OSError, inst:
158 except OSError, inst:
159 if inst.errno != errno.ENOENT:
159 if inst.errno != errno.ENOENT:
160 raise
160 raise
161
161
162 src_store = os.path.realpath(src_repo.spath)
162 src_store = os.path.realpath(src_repo.spath)
163 if not os.path.exists(dest):
163 if not os.path.exists(dest):
164 os.mkdir(dest)
164 os.mkdir(dest)
165 dest_path = os.path.realpath(os.path.join(dest, ".hg"))
165 dest_path = os.path.realpath(os.path.join(dest, ".hg"))
166 os.mkdir(dest_path)
166 os.mkdir(dest_path)
167 if src_repo.spath != src_repo.path:
167 if src_repo.spath != src_repo.path:
168 dest_store = os.path.join(dest_path, "store")
168 dest_store = os.path.join(dest_path, "store")
169 os.mkdir(dest_store)
169 os.mkdir(dest_store)
170 else:
170 else:
171 dest_store = dest_path
171 dest_store = dest_path
172 # copy the requires file
172 # copy the requires file
173 force_copy(src_repo.join("requires"),
173 force_copy(src_repo.join("requires"),
174 os.path.join(dest_path, "requires"))
174 os.path.join(dest_path, "requires"))
175 # we lock here to avoid premature writing to the target
175 # we lock here to avoid premature writing to the target
176 dest_lock = lock.lock(os.path.join(dest_store, "lock"))
176 dest_lock = lock.lock(os.path.join(dest_store, "lock"))
177
177
178 files = ("data",
178 files = ("data",
179 "00manifest.d", "00manifest.i",
179 "00manifest.d", "00manifest.i",
180 "00changelog.d", "00changelog.i")
180 "00changelog.d", "00changelog.i")
181 for f in files:
181 for f in files:
182 src = os.path.join(src_store, f)
182 src = os.path.join(src_store, f)
183 dst = os.path.join(dest_store, f)
183 dst = os.path.join(dest_store, f)
184 force_copy(src, dst)
184 force_copy(src, dst)
185
186 # we need to re-init the repo after manually copying the data
187 # into it
188 dest_repo = repository(ui, dest)
189
190 else:
191 dest_repo = repository(ui, dest, create=True)
185
192
186 # we need to re-init the repo after manually copying the data
193 revs = None
187 # into it
194 if rev:
188 dest_repo = repository(ui, dest)
195 if 'lookup' not in src_repo.capabilities:
189
196 raise util.Abort(_("src repository does not support revision "
190 else:
197 "lookup and so doesn't support clone by "
191 dest_repo = repository(ui, dest, create=True)
198 "revision"))
199 revs = [src_repo.lookup(r) for r in rev]
192
200
193 revs = None
201 if dest_repo.local():
194 if rev:
202 dest_repo.clone(src_repo, heads=revs, stream=stream)
195 if 'lookup' not in src_repo.capabilities:
203 elif src_repo.local():
196 raise util.Abort(_("src repository does not support revision "
204 src_repo.push(dest_repo, revs=revs)
197 "lookup and so doesn't support clone by "
205 else:
198 "revision"))
206 raise util.Abort(_("clone from remote to remote not supported"))
199 revs = [src_repo.lookup(r) for r in rev]
200
207
201 if dest_repo.local():
208 if dest_repo.local():
202 dest_repo.clone(src_repo, heads=revs, stream=stream)
209 fp = dest_repo.opener("hgrc", "w", text=True)
203 elif src_repo.local():
210 fp.write("[paths]\n")
204 src_repo.push(dest_repo, revs=revs)
211 fp.write("default = %s\n" % abspath)
205 else:
212 fp.close()
206 raise util.Abort(_("clone from remote to remote not supported"))
207
208 if src_lock:
209 src_lock.release()
210
213
211 if dest_repo.local():
214 if update:
212 fp = dest_repo.opener("hgrc", "w", text=True)
215 try:
213 fp.write("[paths]\n")
216 checkout = dest_repo.lookup("default")
214 fp.write("default = %s\n" % abspath)
217 except:
215 fp.close()
218 checkout = dest_repo.changelog.tip()
216
219 _update(dest_repo, checkout)
217 if dest_lock:
220 if dir_cleanup:
218 dest_lock.release()
221 dir_cleanup.close()
219
222
220 if update:
223 return src_repo, dest_repo
221 try:
224 finally:
222 checkout = dest_repo.lookup("default")
225 del src_lock, dest_lock, dir_cleanup
223 except:
224 checkout = dest_repo.changelog.tip()
225 _update(dest_repo, checkout)
226 if dir_cleanup:
227 dir_cleanup.close()
228
229 return src_repo, dest_repo
230
226
231 def _showstats(repo, stats):
227 def _showstats(repo, stats):
232 stats = ((stats[0], _("updated")),
228 stats = ((stats[0], _("updated")),
@@ -1168,7 +1168,7 b' class hgweb(object):'
1168 req.write('%d\n' % ret)
1168 req.write('%d\n' % ret)
1169 req.write(val)
1169 req.write(val)
1170 finally:
1170 finally:
1171 lock.release()
1171 del lock
1172 except (OSError, IOError), inst:
1172 except (OSError, IOError), inst:
1173 req.write('0\n')
1173 req.write('0\n')
1174 filename = getattr(inst, 'filename', '')
1174 filename = getattr(inst, 'filename', '')
This diff has been collapsed as it changes many lines, (628 lines changed) Show them Hide them
@@ -516,28 +516,34 b' class localrepository(repo.repository):'
516
516
517 def recover(self):
517 def recover(self):
518 l = self.lock()
518 l = self.lock()
519 if os.path.exists(self.sjoin("journal")):
519 try:
520 self.ui.status(_("rolling back interrupted transaction\n"))
520 if os.path.exists(self.sjoin("journal")):
521 transaction.rollback(self.sopener, self.sjoin("journal"))
521 self.ui.status(_("rolling back interrupted transaction\n"))
522 self.invalidate()
522 transaction.rollback(self.sopener, self.sjoin("journal"))
523 return True
523 self.invalidate()
524 else:
524 return True
525 self.ui.warn(_("no interrupted transaction available\n"))
525 else:
526 return False
526 self.ui.warn(_("no interrupted transaction available\n"))
527 return False
528 finally:
529 del l
527
530
528 def rollback(self, wlock=None, lock=None):
531 def rollback(self, wlock=None, lock=None):
529 if not wlock:
532 try:
530 wlock = self.wlock()
533 if not wlock:
531 if not lock:
534 wlock = self.wlock()
532 lock = self.lock()
535 if not lock:
533 if os.path.exists(self.sjoin("undo")):
536 lock = self.lock()
534 self.ui.status(_("rolling back last transaction\n"))
537 if os.path.exists(self.sjoin("undo")):
535 transaction.rollback(self.sopener, self.sjoin("undo"))
538 self.ui.status(_("rolling back last transaction\n"))
536 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
539 transaction.rollback(self.sopener, self.sjoin("undo"))
537 self.invalidate()
540 util.rename(self.join("undo.dirstate"), self.join("dirstate"))
538 self.dirstate.invalidate()
541 self.invalidate()
539 else:
542 self.dirstate.invalidate()
540 self.ui.warn(_("no rollback information available\n"))
543 else:
544 self.ui.warn(_("no rollback information available\n"))
545 finally:
546 del wlock, lock
541
547
542 def invalidate(self):
548 def invalidate(self):
543 for a in "changelog manifest".split():
549 for a in "changelog manifest".split():
@@ -639,164 +645,169 b' class localrepository(repo.repository):'
639 def commit(self, files=None, text="", user=None, date=None,
645 def commit(self, files=None, text="", user=None, date=None,
640 match=util.always, force=False, lock=None, wlock=None,
646 match=util.always, force=False, lock=None, wlock=None,
641 force_editor=False, p1=None, p2=None, extra={}):
647 force_editor=False, p1=None, p2=None, extra={}):
642
648 tr = None
643 commit = []
649 try:
644 remove = []
650 commit = []
645 changed = []
651 remove = []
646 use_dirstate = (p1 is None) # not rawcommit
652 changed = []
647 extra = extra.copy()
653 use_dirstate = (p1 is None) # not rawcommit
654 extra = extra.copy()
648
655
649 if use_dirstate:
656 if use_dirstate:
650 if files:
657 if files:
651 for f in files:
658 for f in files:
652 s = self.dirstate[f]
659 s = self.dirstate[f]
653 if s in 'nma':
660 if s in 'nma':
654 commit.append(f)
661 commit.append(f)
655 elif s == 'r':
662 elif s == 'r':
656 remove.append(f)
663 remove.append(f)
657 else:
664 else:
658 self.ui.warn(_("%s not tracked!\n") % f)
665 self.ui.warn(_("%s not tracked!\n") % f)
666 else:
667 changes = self.status(match=match)[:5]
668 modified, added, removed, deleted, unknown = changes
669 commit = modified + added
670 remove = removed
659 else:
671 else:
660 changes = self.status(match=match)[:5]
672 commit = files
661 modified, added, removed, deleted, unknown = changes
662 commit = modified + added
663 remove = removed
664 else:
665 commit = files
666
673
667 if use_dirstate:
674 if use_dirstate:
668 p1, p2 = self.dirstate.parents()
675 p1, p2 = self.dirstate.parents()
669 update_dirstate = True
676 update_dirstate = True
670 else:
677 else:
671 p1, p2 = p1, p2 or nullid
678 p1, p2 = p1, p2 or nullid
672 update_dirstate = (self.dirstate.parents()[0] == p1)
679 update_dirstate = (self.dirstate.parents()[0] == p1)
673
680
674 c1 = self.changelog.read(p1)
681 c1 = self.changelog.read(p1)
675 c2 = self.changelog.read(p2)
682 c2 = self.changelog.read(p2)
676 m1 = self.manifest.read(c1[0]).copy()
683 m1 = self.manifest.read(c1[0]).copy()
677 m2 = self.manifest.read(c2[0])
684 m2 = self.manifest.read(c2[0])
678
685
679 if use_dirstate:
686 if use_dirstate:
680 branchname = self.workingctx().branch()
687 branchname = self.workingctx().branch()
681 try:
688 try:
682 branchname = branchname.decode('UTF-8').encode('UTF-8')
689 branchname = branchname.decode('UTF-8').encode('UTF-8')
683 except UnicodeDecodeError:
690 except UnicodeDecodeError:
684 raise util.Abort(_('branch name not in UTF-8!'))
691 raise util.Abort(_('branch name not in UTF-8!'))
685 else:
692 else:
686 branchname = ""
693 branchname = ""
687
694
688 if use_dirstate:
695 if use_dirstate:
689 oldname = c1[5].get("branch") # stored in UTF-8
696 oldname = c1[5].get("branch") # stored in UTF-8
690 if (not commit and not remove and not force and p2 == nullid
697 if (not commit and not remove and not force and p2 == nullid
691 and branchname == oldname):
698 and branchname == oldname):
692 self.ui.status(_("nothing changed\n"))
699 self.ui.status(_("nothing changed\n"))
693 return None
700 return None
694
701
695 xp1 = hex(p1)
702 xp1 = hex(p1)
696 if p2 == nullid: xp2 = ''
703 if p2 == nullid: xp2 = ''
697 else: xp2 = hex(p2)
704 else: xp2 = hex(p2)
698
705
699 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
706 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
700
707
701 if not wlock:
708 if not wlock:
702 wlock = self.wlock()
709 wlock = self.wlock()
703 if not lock:
710 if not lock:
704 lock = self.lock()
711 lock = self.lock()
705 tr = self.transaction()
712 tr = self.transaction()
706
713
707 # check in files
714 # check in files
708 new = {}
715 new = {}
709 linkrev = self.changelog.count()
716 linkrev = self.changelog.count()
710 commit.sort()
717 commit.sort()
711 is_exec = util.execfunc(self.root, m1.execf)
718 is_exec = util.execfunc(self.root, m1.execf)
712 is_link = util.linkfunc(self.root, m1.linkf)
719 is_link = util.linkfunc(self.root, m1.linkf)
713 for f in commit:
720 for f in commit:
714 self.ui.note(f + "\n")
721 self.ui.note(f + "\n")
715 try:
722 try:
716 new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
723 new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
717 new_exec = is_exec(f)
724 new_exec = is_exec(f)
718 new_link = is_link(f)
725 new_link = is_link(f)
719 if not changed or changed[-1] != f:
726 if not changed or changed[-1] != f:
720 # mention the file in the changelog if some flag changed,
727 # mention the file in the changelog if some
721 # even if there was no content change.
728 # flag changed, even if there was no content
722 old_exec = m1.execf(f)
729 # change.
723 old_link = m1.linkf(f)
730 old_exec = m1.execf(f)
724 if old_exec != new_exec or old_link != new_link:
731 old_link = m1.linkf(f)
725 changed.append(f)
732 if old_exec != new_exec or old_link != new_link:
726 m1.set(f, new_exec, new_link)
733 changed.append(f)
727 except (OSError, IOError):
734 m1.set(f, new_exec, new_link)
728 if use_dirstate:
735 except (OSError, IOError):
729 self.ui.warn(_("trouble committing %s!\n") % f)
736 if use_dirstate:
730 raise
737 self.ui.warn(_("trouble committing %s!\n") % f)
731 else:
738 raise
732 remove.append(f)
739 else:
740 remove.append(f)
733
741
734 # update manifest
742 # update manifest
735 m1.update(new)
743 m1.update(new)
736 remove.sort()
744 remove.sort()
737 removed = []
745 removed = []
738
746
739 for f in remove:
747 for f in remove:
740 if f in m1:
748 if f in m1:
741 del m1[f]
749 del m1[f]
742 removed.append(f)
750 removed.append(f)
743 elif f in m2:
751 elif f in m2:
744 removed.append(f)
752 removed.append(f)
745 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, removed))
753 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
754 (new, removed))
746
755
747 # add changeset
756 # add changeset
748 new = new.keys()
757 new = new.keys()
749 new.sort()
758 new.sort()
750
759
751 user = user or self.ui.username()
760 user = user or self.ui.username()
752 if not text or force_editor:
761 if not text or force_editor:
753 edittext = []
762 edittext = []
754 if text:
763 if text:
755 edittext.append(text)
764 edittext.append(text)
756 edittext.append("")
765 edittext.append("")
757 edittext.append("HG: user: %s" % user)
766 edittext.append("HG: user: %s" % user)
758 if p2 != nullid:
767 if p2 != nullid:
759 edittext.append("HG: branch merge")
768 edittext.append("HG: branch merge")
760 if branchname:
769 if branchname:
761 edittext.append("HG: branch %s" % util.tolocal(branchname))
770 edittext.append("HG: branch %s" % util.tolocal(branchname))
762 edittext.extend(["HG: changed %s" % f for f in changed])
771 edittext.extend(["HG: changed %s" % f for f in changed])
763 edittext.extend(["HG: removed %s" % f for f in removed])
772 edittext.extend(["HG: removed %s" % f for f in removed])
764 if not changed and not remove:
773 if not changed and not remove:
765 edittext.append("HG: no files changed")
774 edittext.append("HG: no files changed")
766 edittext.append("")
775 edittext.append("")
767 # run editor in the repository root
776 # run editor in the repository root
768 olddir = os.getcwd()
777 olddir = os.getcwd()
769 os.chdir(self.root)
778 os.chdir(self.root)
770 text = self.ui.edit("\n".join(edittext), user)
779 text = self.ui.edit("\n".join(edittext), user)
771 os.chdir(olddir)
780 os.chdir(olddir)
772
781
773 lines = [line.rstrip() for line in text.rstrip().splitlines()]
782 lines = [line.rstrip() for line in text.rstrip().splitlines()]
774 while lines and not lines[0]:
783 while lines and not lines[0]:
775 del lines[0]
784 del lines[0]
776 if not lines:
785 if not lines:
777 return None
786 return None
778 text = '\n'.join(lines)
787 text = '\n'.join(lines)
779 if branchname:
788 if branchname:
780 extra["branch"] = branchname
789 extra["branch"] = branchname
781 n = self.changelog.add(mn, changed + removed, text, tr, p1, p2,
790 n = self.changelog.add(mn, changed + removed, text, tr, p1, p2,
782 user, date, extra)
791 user, date, extra)
783 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
792 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
784 parent2=xp2)
793 parent2=xp2)
785 tr.close()
794 tr.close()
786
795
787 if self.branchcache and "branch" in extra:
796 if self.branchcache and "branch" in extra:
788 self.branchcache[util.tolocal(extra["branch"])] = n
797 self.branchcache[util.tolocal(extra["branch"])] = n
789
798
790 if use_dirstate or update_dirstate:
799 if use_dirstate or update_dirstate:
791 self.dirstate.setparents(n)
800 self.dirstate.setparents(n)
792 if use_dirstate:
801 if use_dirstate:
793 for f in new:
802 for f in new:
794 self.dirstate.normal(f)
803 self.dirstate.normal(f)
795 for f in removed:
804 for f in removed:
796 self.dirstate.forget(f)
805 self.dirstate.forget(f)
797
806
798 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
807 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
799 return n
808 return n
809 finally:
810 del lock, wlock, tr
800
811
801 def walk(self, node=None, files=[], match=util.always, badmatch=None):
812 def walk(self, node=None, files=[], match=util.always, badmatch=None):
802 '''
813 '''
@@ -895,18 +906,18 b' class localrepository(repo.repository):'
895
906
896 # update dirstate for files that are actually clean
907 # update dirstate for files that are actually clean
897 if fixup:
908 if fixup:
898 cleanup = False
909 fixlock = wlock
899 if not wlock:
910 try:
900 try:
911 if not fixlock:
901 wlock = self.wlock(False)
912 try:
902 cleanup = True
913 fixlock = self.wlock(False)
903 except lock.LockException:
914 except lock.LockException:
904 pass
915 pass
905 if wlock:
916 if fixlock:
906 for f in fixup:
917 for f in fixup:
907 self.dirstate.normal(f)
918 self.dirstate.normal(f)
908 if cleanup:
919 finally:
909 wlock.release()
920 del fixlock
910 else:
921 else:
911 # we are comparing working dir against non-parent
922 # we are comparing working dir against non-parent
912 # generate a pseudo-manifest for the working dir
923 # generate a pseudo-manifest for the working dir
@@ -954,84 +965,99 b' class localrepository(repo.repository):'
954 return (modified, added, removed, deleted, unknown, ignored, clean)
965 return (modified, added, removed, deleted, unknown, ignored, clean)
955
966
956 def add(self, list, wlock=None):
967 def add(self, list, wlock=None):
957 if not wlock:
968 try:
958 wlock = self.wlock()
969 if not wlock:
959 for f in list:
970 wlock = self.wlock()
960 p = self.wjoin(f)
971 for f in list:
961 try:
972 p = self.wjoin(f)
962 st = os.lstat(p)
973 try:
963 except:
974 st = os.lstat(p)
964 self.ui.warn(_("%s does not exist!\n") % f)
975 except:
965 continue
976 self.ui.warn(_("%s does not exist!\n") % f)
966 if st.st_size > 10000000:
977 continue
967 self.ui.warn(_("%s: files over 10MB may cause memory and"
978 if st.st_size > 10000000:
968 " performance problems\n"
979 self.ui.warn(_("%s: files over 10MB may cause memory and"
969 "(use 'hg revert %s' to unadd the file)\n")
980 " performance problems\n"
970 % (f, f))
981 "(use 'hg revert %s' to unadd the file)\n")
971 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
982 % (f, f))
972 self.ui.warn(_("%s not added: only files and symlinks "
983 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
973 "supported currently\n") % f)
984 self.ui.warn(_("%s not added: only files and symlinks "
974 elif self.dirstate[f] in 'an':
985 "supported currently\n") % f)
975 self.ui.warn(_("%s already tracked!\n") % f)
986 elif self.dirstate[f] in 'an':
976 else:
987 self.ui.warn(_("%s already tracked!\n") % f)
977 self.dirstate.add(f)
988 else:
989 self.dirstate.add(f)
990 finally:
991 del wlock
978
992
979 def forget(self, list, wlock=None):
993 def forget(self, list, wlock=None):
980 if not wlock:
994 try:
981 wlock = self.wlock()
995 if not wlock:
982 for f in list:
996 wlock = self.wlock()
983 if self.dirstate[f] != 'a':
997 for f in list:
984 self.ui.warn(_("%s not added!\n") % f)
998 if self.dirstate[f] != 'a':
985 else:
999 self.ui.warn(_("%s not added!\n") % f)
986 self.dirstate.forget(f)
1000 else:
1001 self.dirstate.forget(f)
1002 finally:
1003 del wlock
987
1004
988 def remove(self, list, unlink=False, wlock=None):
1005 def remove(self, list, unlink=False, wlock=None):
989 if unlink:
1006 try:
1007 if unlink:
1008 for f in list:
1009 try:
1010 util.unlink(self.wjoin(f))
1011 except OSError, inst:
1012 if inst.errno != errno.ENOENT:
1013 raise
1014 if not wlock:
1015 wlock = self.wlock()
990 for f in list:
1016 for f in list:
991 try:
1017 if unlink and os.path.exists(self.wjoin(f)):
992 util.unlink(self.wjoin(f))
1018 self.ui.warn(_("%s still exists!\n") % f)
993 except OSError, inst:
1019 elif self.dirstate[f] == 'a':
994 if inst.errno != errno.ENOENT:
1020 self.dirstate.forget(f)
995 raise
1021 elif f not in self.dirstate:
996 if not wlock:
1022 self.ui.warn(_("%s not tracked!\n") % f)
997 wlock = self.wlock()
1023 else:
998 for f in list:
1024 self.dirstate.remove(f)
999 if unlink and os.path.exists(self.wjoin(f)):
1025 finally:
1000 self.ui.warn(_("%s still exists!\n") % f)
1026 del wlock
1001 elif self.dirstate[f] == 'a':
1002 self.dirstate.forget(f)
1003 elif f not in self.dirstate:
1004 self.ui.warn(_("%s not tracked!\n") % f)
1005 else:
1006 self.dirstate.remove(f)
1007
1027
1008 def undelete(self, list, wlock=None):
1028 def undelete(self, list, wlock=None):
1009 p = self.dirstate.parents()[0]
1029 try:
1010 mn = self.changelog.read(p)[0]
1030 p = self.dirstate.parents()[0]
1011 m = self.manifest.read(mn)
1031 mn = self.changelog.read(p)[0]
1012 if not wlock:
1032 m = self.manifest.read(mn)
1013 wlock = self.wlock()
1033 if not wlock:
1014 for f in list:
1034 wlock = self.wlock()
1015 if self.dirstate[f] != 'r':
1035 for f in list:
1016 self.ui.warn("%s not removed!\n" % f)
1036 if self.dirstate[f] != 'r':
1017 else:
1037 self.ui.warn("%s not removed!\n" % f)
1018 t = self.file(f).read(m[f])
1038 else:
1019 self.wwrite(f, t, m.flags(f))
1039 t = self.file(f).read(m[f])
1020 self.dirstate.normal(f)
1040 self.wwrite(f, t, m.flags(f))
1041 self.dirstate.normal(f)
1042 finally:
1043 del wlock
1021
1044
1022 def copy(self, source, dest, wlock=None):
1045 def copy(self, source, dest, wlock=None):
1023 p = self.wjoin(dest)
1046 try:
1024 if not (os.path.exists(p) or os.path.islink(p)):
1047 p = self.wjoin(dest)
1025 self.ui.warn(_("%s does not exist!\n") % dest)
1048 if not (os.path.exists(p) or os.path.islink(p)):
1026 elif not (os.path.isfile(p) or os.path.islink(p)):
1049 self.ui.warn(_("%s does not exist!\n") % dest)
1027 self.ui.warn(_("copy failed: %s is not a file or a "
1050 elif not (os.path.isfile(p) or os.path.islink(p)):
1028 "symbolic link\n") % dest)
1051 self.ui.warn(_("copy failed: %s is not a file or a "
1029 else:
1052 "symbolic link\n") % dest)
1030 if not wlock:
1053 else:
1031 wlock = self.wlock()
1054 if not wlock:
1032 if dest not in self.dirstate:
1055 wlock = self.wlock()
1033 self.dirstate.add(dest)
1056 if dest not in self.dirstate:
1034 self.dirstate.copy(source, dest)
1057 self.dirstate.add(dest)
1058 self.dirstate.copy(source, dest)
1059 finally:
1060 del wlock
1035
1061
1036 def heads(self, start=None):
1062 def heads(self, start=None):
1037 heads = self.changelog.heads(start)
1063 heads = self.changelog.heads(start)
@@ -1309,12 +1335,9 b' class localrepository(repo.repository):'
1309 return subset
1335 return subset
1310
1336
1311 def pull(self, remote, heads=None, force=False, lock=None):
1337 def pull(self, remote, heads=None, force=False, lock=None):
1312 mylock = False
1313 if not lock:
1314 lock = self.lock()
1315 mylock = True
1316
1317 try:
1338 try:
1339 if not lock:
1340 lock = self.lock()
1318 fetch = self.findincoming(remote, force=force)
1341 fetch = self.findincoming(remote, force=force)
1319 if fetch == [nullid]:
1342 if fetch == [nullid]:
1320 self.ui.status(_("requesting all changes\n"))
1343 self.ui.status(_("requesting all changes\n"))
@@ -1331,8 +1354,7 b' class localrepository(repo.repository):'
1331 cg = remote.changegroupsubset(fetch, heads, 'pull')
1354 cg = remote.changegroupsubset(fetch, heads, 'pull')
1332 return self.addchangegroup(cg, 'pull', remote.url())
1355 return self.addchangegroup(cg, 'pull', remote.url())
1333 finally:
1356 finally:
1334 if mylock:
1357 del lock
1335 lock.release()
1336
1358
1337 def push(self, remote, force=False, revs=None):
1359 def push(self, remote, force=False, revs=None):
1338 # there are two ways to push to remote repo:
1360 # there are two ways to push to remote repo:
@@ -1405,12 +1427,14 b' class localrepository(repo.repository):'
1405
1427
1406 def push_addchangegroup(self, remote, force, revs):
1428 def push_addchangegroup(self, remote, force, revs):
1407 lock = remote.lock()
1429 lock = remote.lock()
1408
1430 try:
1409 ret = self.prepush(remote, force, revs)
1431 ret = self.prepush(remote, force, revs)
1410 if ret[0] is not None:
1432 if ret[0] is not None:
1411 cg, remote_heads = ret
1433 cg, remote_heads = ret
1412 return remote.addchangegroup(cg, 'push', self.url())
1434 return remote.addchangegroup(cg, 'push', self.url())
1413 return ret[1]
1435 return ret[1]
1436 finally:
1437 del lock
1414
1438
1415 def push_unbundle(self, remote, force, revs):
1439 def push_unbundle(self, remote, force, revs):
1416 # local repo finds heads on server, finds out what revs it
1440 # local repo finds heads on server, finds out what revs it
@@ -1794,65 +1818,67 b' class localrepository(repo.repository):'
1794
1818
1795 changesets = files = revisions = 0
1819 changesets = files = revisions = 0
1796
1820
1797 tr = self.transaction()
1798
1799 # write changelog data to temp files so concurrent readers will not see
1821 # write changelog data to temp files so concurrent readers will not see
1800 # inconsistent view
1822 # inconsistent view
1801 cl = self.changelog
1823 cl = self.changelog
1802 cl.delayupdate()
1824 cl.delayupdate()
1803 oldheads = len(cl.heads())
1825 oldheads = len(cl.heads())
1804
1826
1805 # pull off the changeset group
1827 tr = self.transaction()
1806 self.ui.status(_("adding changesets\n"))
1828 try:
1807 cor = cl.count() - 1
1829 # pull off the changeset group
1808 chunkiter = changegroup.chunkiter(source)
1830 self.ui.status(_("adding changesets\n"))
1809 if cl.addgroup(chunkiter, csmap, tr, 1) is None:
1831 cor = cl.count() - 1
1810 raise util.Abort(_("received changelog group is empty"))
1832 chunkiter = changegroup.chunkiter(source)
1811 cnr = cl.count() - 1
1833 if cl.addgroup(chunkiter, csmap, tr, 1) is None:
1812 changesets = cnr - cor
1834 raise util.Abort(_("received changelog group is empty"))
1835 cnr = cl.count() - 1
1836 changesets = cnr - cor
1813
1837
1814 # pull off the manifest group
1838 # pull off the manifest group
1815 self.ui.status(_("adding manifests\n"))
1839 self.ui.status(_("adding manifests\n"))
1816 chunkiter = changegroup.chunkiter(source)
1840 chunkiter = changegroup.chunkiter(source)
1817 # no need to check for empty manifest group here:
1841 # no need to check for empty manifest group here:
1818 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1842 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1819 # no new manifest will be created and the manifest group will
1843 # no new manifest will be created and the manifest group will
1820 # be empty during the pull
1844 # be empty during the pull
1821 self.manifest.addgroup(chunkiter, revmap, tr)
1845 self.manifest.addgroup(chunkiter, revmap, tr)
1822
1846
1823 # process the files
1847 # process the files
1824 self.ui.status(_("adding file changes\n"))
1848 self.ui.status(_("adding file changes\n"))
1825 while 1:
1849 while 1:
1826 f = changegroup.getchunk(source)
1850 f = changegroup.getchunk(source)
1827 if not f:
1851 if not f:
1828 break
1852 break
1829 self.ui.debug(_("adding %s revisions\n") % f)
1853 self.ui.debug(_("adding %s revisions\n") % f)
1830 fl = self.file(f)
1854 fl = self.file(f)
1831 o = fl.count()
1855 o = fl.count()
1832 chunkiter = changegroup.chunkiter(source)
1856 chunkiter = changegroup.chunkiter(source)
1833 if fl.addgroup(chunkiter, revmap, tr) is None:
1857 if fl.addgroup(chunkiter, revmap, tr) is None:
1834 raise util.Abort(_("received file revlog group is empty"))
1858 raise util.Abort(_("received file revlog group is empty"))
1835 revisions += fl.count() - o
1859 revisions += fl.count() - o
1836 files += 1
1860 files += 1
1861
1862 # make changelog see real files again
1863 cl.finalize(tr)
1837
1864
1838 # make changelog see real files again
1865 newheads = len(self.changelog.heads())
1839 cl.finalize(tr)
1866 heads = ""
1867 if oldheads and newheads != oldheads:
1868 heads = _(" (%+d heads)") % (newheads - oldheads)
1840
1869
1841 newheads = len(self.changelog.heads())
1870 self.ui.status(_("added %d changesets"
1842 heads = ""
1871 " with %d changes to %d files%s\n")
1843 if oldheads and newheads != oldheads:
1872 % (changesets, revisions, files, heads))
1844 heads = _(" (%+d heads)") % (newheads - oldheads)
1845
1873
1846 self.ui.status(_("added %d changesets"
1874 if changesets > 0:
1847 " with %d changes to %d files%s\n")
1875 self.hook('pretxnchangegroup', throw=True,
1848 % (changesets, revisions, files, heads))
1876 node=hex(self.changelog.node(cor+1)), source=srctype,
1877 url=url)
1849
1878
1850 if changesets > 0:
1879 tr.close()
1851 self.hook('pretxnchangegroup', throw=True,
1880 finally:
1852 node=hex(self.changelog.node(cor+1)), source=srctype,
1881 del tr
1853 url=url)
1854
1855 tr.close()
1856
1882
1857 if changesets > 0:
1883 if changesets > 0:
1858 self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
1884 self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
@@ -506,65 +506,67 b' def update(repo, node, branchmerge, forc'
506 wlock = working dir lock, if already held
506 wlock = working dir lock, if already held
507 """
507 """
508
508
509 if not wlock:
509 try:
510 wlock = repo.wlock()
510 if not wlock:
511 wlock = repo.wlock()
511
512
512 wc = repo.workingctx()
513 wc = repo.workingctx()
513 if node is None:
514 if node is None:
514 # tip of current branch
515 # tip of current branch
515 try:
516 try:
516 node = repo.branchtags()[wc.branch()]
517 node = repo.branchtags()[wc.branch()]
517 except KeyError:
518 except KeyError:
518 raise util.Abort(_("branch %s not found") % wc.branch())
519 raise util.Abort(_("branch %s not found") % wc.branch())
519 overwrite = force and not branchmerge
520 overwrite = force and not branchmerge
520 forcemerge = force and branchmerge
521 forcemerge = force and branchmerge
521 pl = wc.parents()
522 pl = wc.parents()
522 p1, p2 = pl[0], repo.changectx(node)
523 p1, p2 = pl[0], repo.changectx(node)
523 pa = p1.ancestor(p2)
524 pa = p1.ancestor(p2)
524 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
525 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
525 fastforward = False
526 fastforward = False
526
527
527 ### check phase
528 ### check phase
528 if not overwrite and len(pl) > 1:
529 if not overwrite and len(pl) > 1:
529 raise util.Abort(_("outstanding uncommitted merges"))
530 raise util.Abort(_("outstanding uncommitted merges"))
530 if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
531 if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
531 if branchmerge:
532 if branchmerge:
532 if p1.branch() != p2.branch() and pa != p2:
533 if p1.branch() != p2.branch() and pa != p2:
533 fastforward = True
534 fastforward = True
534 else:
535 else:
535 raise util.Abort(_("there is nothing to merge, just use "
536 raise util.Abort(_("there is nothing to merge, just use "
536 "'hg update' or look at 'hg heads'"))
537 "'hg update' or look at 'hg heads'"))
537 elif not (overwrite or branchmerge):
538 elif not (overwrite or branchmerge):
538 raise util.Abort(_("update spans branches, use 'hg merge' "
539 raise util.Abort(_("update spans branches, use 'hg merge' "
539 "or 'hg update -C' to lose changes"))
540 "or 'hg update -C' to lose changes"))
540 if branchmerge and not forcemerge:
541 if branchmerge and not forcemerge:
541 if wc.files():
542 if wc.files():
542 raise util.Abort(_("outstanding uncommitted changes"))
543 raise util.Abort(_("outstanding uncommitted changes"))
543
544
544 ### calculate phase
545 ### calculate phase
545 action = []
546 action = []
546 if not force:
547 if not force:
547 checkunknown(wc, p2)
548 checkunknown(wc, p2)
548 if not util.checkfolding(repo.path):
549 if not util.checkfolding(repo.path):
549 checkcollision(p2)
550 checkcollision(p2)
550 if not branchmerge:
551 if not branchmerge:
551 action += forgetremoved(wc, p2)
552 action += forgetremoved(wc, p2)
552 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
553 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
553
554
554 ### apply phase
555 ### apply phase
555 if not branchmerge: # just jump to the new rev
556 if not branchmerge: # just jump to the new rev
556 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
557 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
557 if not partial:
558 if not partial:
558 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
559 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
559
560
560 stats = applyupdates(repo, action, wc, p2)
561 stats = applyupdates(repo, action, wc, p2)
561
562
562 if not partial:
563 if not partial:
563 recordupdates(repo, action, branchmerge)
564 recordupdates(repo, action, branchmerge)
564 repo.dirstate.setparents(fp1, fp2)
565 repo.dirstate.setparents(fp1, fp2)
565 if not branchmerge and not fastforward:
566 if not branchmerge and not fastforward:
566 repo.dirstate.setbranch(p2.branch())
567 repo.dirstate.setbranch(p2.branch())
567 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
568 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
568
569
569 return stats
570 return stats
570
571 finally:
572 del wlock
@@ -66,22 +66,25 b' def stream_out(repo, fileobj, untrusted='
66
66
67 # get consistent snapshot of repo. lock during scan so lock not
67 # get consistent snapshot of repo. lock during scan so lock not
68 # needed while we stream, and commits can happen.
68 # needed while we stream, and commits can happen.
69 lock = None
69 try:
70 try:
70 repolock = repo.lock()
71 try:
71 except (lock.LockHeld, lock.LockUnavailable), inst:
72 repolock = repo.lock()
72 repo.ui.warn('locking the repository failed: %s\n' % (inst,))
73 except (lock.LockHeld, lock.LockUnavailable), inst:
73 fileobj.write('2\n')
74 repo.ui.warn('locking the repository failed: %s\n' % (inst,))
74 return
75 fileobj.write('2\n')
76 return
75
77
76 fileobj.write('0\n')
78 fileobj.write('0\n')
77 repo.ui.debug('scanning\n')
79 repo.ui.debug('scanning\n')
78 entries = []
80 entries = []
79 total_bytes = 0
81 total_bytes = 0
80 for name, size in walkrepo(repo.spath):
82 for name, size in walkrepo(repo.spath):
81 name = repo.decodefn(util.pconvert(name))
83 name = repo.decodefn(util.pconvert(name))
82 entries.append((name, size))
84 entries.append((name, size))
83 total_bytes += size
85 total_bytes += size
84 repolock.release()
86 finally:
87 del repolock
85
88
86 repo.ui.debug('%d files, %d bytes to transfer\n' %
89 repo.ui.debug('%d files, %d bytes to transfer\n' %
87 (len(entries), total_bytes))
90 (len(entries), total_bytes))
@@ -10,6 +10,13 b' from i18n import _'
10 import revlog, mdiff
10 import revlog, mdiff
11
11
12 def verify(repo):
12 def verify(repo):
13 lock = repo.lock()
14 try:
15 return _verify(repo)
16 finally:
17 del lock
18
19 def _verify(repo):
13 filelinkrevs = {}
20 filelinkrevs = {}
14 filenodes = {}
21 filenodes = {}
15 changesets = revisions = files = 0
22 changesets = revisions = files = 0
@@ -17,8 +24,6 b' def verify(repo):'
17 warnings = [0]
24 warnings = [0]
18 neededmanifests = {}
25 neededmanifests = {}
19
26
20 lock = repo.lock()
21
22 def err(msg):
27 def err(msg):
23 repo.ui.warn(msg + "\n")
28 repo.ui.warn(msg + "\n")
24 errors[0] += 1
29 errors[0] += 1
General Comments 0
You need to be logged in to leave comments. Login now