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