437 return (True, files, fuzz) |
437 return (True, files, fuzz) |
438 |
438 |
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, |
463 lock=None, all_files={}): |
467 lock=None, all_files={}): |
464 # TODO unify with commands.py |
468 # TODO unify with commands.py |
614 else: |
618 else: |
615 m, a, r, d = self.check_localchanges(repo, force) |
619 m, a, r, d = self.check_localchanges(repo, force) |
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: |
648 |
655 wlock = repo.wlock() |
649 if update: |
656 lock = repo.lock() |
650 self.check_localchanges(repo, refresh=False) |
657 |
651 urev = self.qparents(repo, rev) |
658 if update: |
652 hg.clean(repo, urev, wlock=wlock) |
659 self.check_localchanges(repo, refresh=False) |
653 repo.dirstate.write() |
660 urev = self.qparents(repo, rev) |
654 |
661 hg.clean(repo, urev, wlock=wlock) |
655 self.removeundo(repo) |
662 repo.dirstate.write() |
656 repair.strip(self.ui, repo, rev, backup) |
663 |
|
664 self.removeundo(repo) |
|
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)""" |
660 for i in xrange(len(self.applied)): |
671 for i in xrange(len(self.applied)): |
661 a = self.applied[i] |
672 a = self.applied[i] |
738 |
749 |
739 def push(self, repo, patch=None, force=False, list=False, |
750 def push(self, repo, patch=None, force=False, list=False, |
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: |
|
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 |
|
772 |
|
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) |
|
783 |
|
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 |
|
791 else: |
|
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) |
756 else: |
798 else: |
757 self.ui.warn(_('all patches are currently applied\n')) |
799 ret = self.apply(repo, s, list, wlock=wlock, |
758 return |
800 all_files=all_files) |
759 |
801 except: |
760 # Following the above example, starting at 'top' of B: |
802 self.ui.warn(_('cleaning up working directory...')) |
761 # qpush should be performed (pushes C), but a subsequent qpush without |
803 node = repo.dirstate.parents()[0] |
762 # an argument is an error (nothing to apply). This allows a loop |
804 hg.revert(repo, node, None, wlock) |
763 # of "...while hg qpush..." to work as it detects an error when done |
805 unknown = repo.status(wlock=wlock)[4] |
764 if self.series_end() == len(self.series): |
806 # only remove unknown files that we know we touched or |
765 self.ui.warn(_('patch series already fully applied\n')) |
807 # created while patching |
766 return 1 |
808 for f in unknown: |
767 if not force: |
809 if f in all_files: |
768 self.check_localchanges(repo) |
810 util.unlink(repo.wjoin(f)) |
769 |
811 self.ui.warn(_('done\n')) |
770 self.applied_dirty = 1; |
812 raise |
771 start = self.series_end() |
813 top = self.applied[-1].name |
772 if start > 0: |
814 if ret[0]: |
773 self.check_toppatch(repo) |
815 self.ui.write( |
774 if not patch: |
816 "Errors during apply, please fix and refresh %s\n" % top) |
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 else: |
817 else: |
785 ret = self.apply(repo, s, list, wlock=wlock, |
818 self.ui.write("Now at: %s\n" % top) |
786 all_files=all_files) |
819 return ret[0] |
787 except: |
820 finally: |
788 self.ui.warn(_('cleaning up working directory...')) |
821 del wlock |
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] |
|
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): |
809 def getfile(f, rev): |
825 def getfile(f, rev): |
810 t = repo.file(f).read(rev) |
826 t = repo.file(f).read(rev) |
811 repo.wfile(f, "w").write(t) |
827 repo.wfile(f, "w").write(t) |
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: |
823 |
839 raise util.Abort(_("patch %s is not applied") % patch) |
824 if len(self.applied) == 0: |
840 |
825 # Allow qpop -a to work repeatedly, |
841 if len(self.applied) == 0: |
826 # but not qpop without an argument |
842 # Allow qpop -a to work repeatedly, |
827 self.ui.warn(_("no patches applied\n")) |
843 # but not qpop without an argument |
828 return not all |
844 self.ui.warn(_("no patches applied\n")) |
829 |
845 return not all |
830 if not update: |
846 |
831 parents = repo.dirstate.parents() |
847 if not update: |
832 rr = [ revlog.bin(x.rev) for x in self.applied ] |
848 parents = repo.dirstate.parents() |
833 for p in parents: |
849 rr = [ revlog.bin(x.rev) for x in self.applied ] |
834 if p in rr: |
850 for p in parents: |
835 self.ui.warn("qpop: forcing dirstate update\n") |
851 if p in rr: |
836 update = True |
852 self.ui.warn("qpop: forcing dirstate update\n") |
837 |
853 update = True |
838 if not force and update: |
854 |
839 self.check_localchanges(repo) |
855 if not force and update: |
840 |
856 self.check_localchanges(repo) |
841 self.applied_dirty = 1; |
857 |
842 end = len(self.applied) |
858 self.applied_dirty = 1; |
843 if not patch: |
859 end = len(self.applied) |
844 if all: |
860 if not patch: |
845 popi = 0 |
861 if all: |
|
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 |
871 |
853 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] |
872 start = info[0] |
854 |
873 rev = revlog.bin(info[1]) |
855 start = info[0] |
874 |
856 rev = revlog.bin(info[1]) |
875 # we know there are no local changes, so we can make a simplified |
857 |
876 # form of hg.update. |
858 # we know there are no local changes, so we can make a simplified |
877 if update: |
859 # form of hg.update. |
878 top = self.check_toppatch(repo) |
860 if update: |
879 qp = self.qparents(repo, rev) |
861 top = self.check_toppatch(repo) |
880 changes = repo.changelog.read(qp) |
862 qp = self.qparents(repo, rev) |
881 mmap = repo.manifest.read(changes[0]) |
863 changes = repo.changelog.read(qp) |
882 m, a, r, d, u = repo.status(qp, top)[:5] |
864 mmap = repo.manifest.read(changes[0]) |
883 if d: |
865 m, a, r, d, u = repo.status(qp, top)[:5] |
884 raise util.Abort("deletions found between repo revs") |
866 if d: |
885 for f in m: |
867 raise util.Abort("deletions found between repo revs") |
886 getfile(f, mmap[f]) |
868 for f in m: |
887 for f in r: |
869 getfile(f, mmap[f]) |
888 getfile(f, mmap[f]) |
870 for f in r: |
889 util.set_exec(repo.wjoin(f), mmap.execf(f)) |
871 getfile(f, mmap[f]) |
890 for f in m + r: |
872 util.set_exec(repo.wjoin(f), mmap.execf(f)) |
891 repo.dirstate.normal(f) |
873 for f in m + r: |
892 for f in a: |
874 repo.dirstate.normal(f) |
893 try: |
875 for f in a: |
894 os.unlink(repo.wjoin(f)) |
876 try: |
895 except OSError, e: |
877 os.unlink(repo.wjoin(f)) |
896 if e.errno != errno.ENOENT: |
878 except OSError, e: |
897 raise |
879 if e.errno != errno.ENOENT: |
898 try: os.removedirs(os.path.dirname(repo.wjoin(f))) |
880 raise |
899 except: pass |
881 try: os.removedirs(os.path.dirname(repo.wjoin(f))) |
900 repo.dirstate.forget(f) |
882 except: pass |
901 repo.dirstate.setparents(qp, revlog.nullid) |
883 repo.dirstate.forget(f) |
902 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
884 repo.dirstate.setparents(qp, revlog.nullid) |
903 del self.applied[start:end] |
885 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
904 if len(self.applied): |
886 del self.applied[start:end] |
905 self.ui.write("Now at: %s\n" % self.applied[-1].name) |
887 if len(self.applied): |
906 else: |
888 self.ui.write("Now at: %s\n" % self.applied[-1].name) |
907 self.ui.write("Patch queue now empty\n") |
889 else: |
908 finally: |
890 self.ui.write("Patch queue now empty\n") |
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) |
894 if not top: |
913 if not top: |
895 self.ui.write("No patches applied\n") |
914 self.ui.write("No patches applied\n") |
902 def refresh(self, repo, pats=None, **opts): |
921 def refresh(self, repo, pats=None, **opts): |
903 if len(self.applied) == 0: |
922 if len(self.applied) == 0: |
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+') |
933 |
915 |
934 patchf = self.opener(patchfn, 'r+') |
916 # if the patch was a git patch, refresh it as a git patch |
935 |
917 for line in patchf: |
936 # if the patch was a git patch, refresh it as a git patch |
918 if line.startswith('diff --git'): |
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() |
|
943 |
|
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) |
|
960 |
|
961 if opts.get('git'): |
919 self.diffopts().git = True |
962 self.diffopts().git = True |
920 break |
963 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
921 patchf.seek(0) |
964 tip = repo.changelog.tip() |
922 patchf.truncate() |
965 if top == tip: |
923 |
966 # if the top of our patch queue is also the tip, there is an |
924 msg = opts.get('msg', '').rstrip() |
967 # optimization here. We update the dirstate in place and strip |
925 if msg: |
968 # off the tip commit. Then just commit the current directory |
926 if comments: |
969 # tree. We can also send repo.commit the list of files |
927 # Remove existing message. |
970 # changed to speed up the diff |
928 ci = 0 |
971 # |
929 subj = None |
972 # in short mode, we only diff the files included in the |
930 for mi in xrange(len(message)): |
973 # patch already |
931 if comments[ci].lower().startswith('subject: '): |
974 # |
932 subj = comments[ci][9:] |
975 # this should really read: |
933 while message[mi] != comments[ci] and message[mi] != subj: |
976 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] |
934 ci += 1 |
977 # but we do it backwards to take advantage of manifest/chlog |
935 del comments[ci] |
978 # caching against the next repo.status call |
936 comments.append(msg) |
979 # |
937 if comments: |
980 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] |
938 comments = "\n".join(comments) + '\n\n' |
981 changes = repo.changelog.read(tip) |
939 patchf.write(comments) |
982 man = repo.manifest.read(changes[0]) |
940 |
983 aaa = aa[:] |
941 if opts.get('git'): |
984 if opts.get('short'): |
942 self.diffopts().git = True |
985 filelist = mm + aa + dd |
943 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
986 match = dict.fromkeys(filelist).__contains__ |
944 tip = repo.changelog.tip() |
987 else: |
945 if top == tip: |
988 filelist = None |
946 # if the top of our patch queue is also the tip, there is an |
989 match = util.always |
947 # optimization here. We update the dirstate in place and strip |
990 m, a, r, d, u = repo.status(files=filelist, match=match)[:5] |
948 # off the tip commit. Then just commit the current directory |
991 |
949 # tree. We can also send repo.commit the list of files |
992 # we might end up with files that were added between |
950 # changed to speed up the diff |
993 # tip and the dirstate parent, but then changed in the |
951 # |
994 # local dirstate. in this case, we want them to only |
952 # in short mode, we only diff the files included in the |
995 # show up in the added section |
953 # patch already |
996 for x in m: |
954 # |
997 if x not in aa: |
955 # this should really read: |
998 mm.append(x) |
956 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5] |
999 # we might end up with files added by the local dirstate that |
957 # but we do it backwards to take advantage of manifest/chlog |
1000 # were deleted by the patch. In this case, they should only |
958 # caching against the next repo.status call |
1001 # show up in the changed section. |
959 # |
1002 for x in a: |
960 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] |
1003 if x in dd: |
961 changes = repo.changelog.read(tip) |
1004 del dd[dd.index(x)] |
962 man = repo.manifest.read(changes[0]) |
1005 mm.append(x) |
963 aaa = aa[:] |
1006 else: |
964 if opts.get('short'): |
1007 aa.append(x) |
965 filelist = mm + aa + dd |
1008 # make sure any files deleted in the local dirstate |
966 match = dict.fromkeys(filelist).__contains__ |
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() |
|
1028 |
|
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) |
|
1068 |
|
1069 if not msg: |
|
1070 if not message: |
|
1071 message = "[mq]: %s\n" % patchfn |
|
1072 else: |
|
1073 message = "\n".join(message) |
|
1074 else: |
|
1075 message = msg |
|
1076 |
|
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) |
967 else: |
1084 else: |
968 filelist = None |
1085 self.printdiff(repo, patchparent, fp=patchf) |
969 match = util.always |
1086 patchf.close() |
970 m, a, r, d, u = repo.status(files=filelist, match=match)[:5] |
1087 added = repo.status()[1] |
971 |
1088 for a in added: |
972 # we might end up with files that were added between tip and |
1089 f = repo.wjoin(a) |
973 # the dirstate parent, but then changed in the local dirstate. |
1090 try: |
974 # in this case, we want them to only show up in the added section |
1091 os.unlink(f) |
975 for x in m: |
1092 except OSError, e: |
976 if x not in aa: |
1093 if e.errno != errno.ENOENT: |
977 mm.append(x) |
1094 raise |
978 # we might end up with files added by the local dirstate that |
1095 try: os.removedirs(os.path.dirname(f)) |
979 # were deleted by the patch. In this case, they should only |
1096 except: pass |
980 # show up in the changed section. |
1097 # forget the file copies in the dirstate |
981 for x in a: |
1098 # push should readd the files later on |
982 if x in dd: |
1099 repo.dirstate.forget(a) |
983 del dd[dd.index(x)] |
1100 self.pop(repo, force=True, wlock=wlock) |
984 mm.append(x) |
1101 self.push(repo, force=True, wlock=wlock) |
985 else: |
1102 finally: |
986 aa.append(x) |
1103 del wlock |
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) |
|
998 |
|
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() |
|
1007 |
|
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) |
|
1047 |
|
1048 if not msg: |
|
1049 if not message: |
|
1050 message = "[mq]: %s\n" % patchfn |
|
1051 else: |
|
1052 message = "\n".join(message) |
|
1053 else: |
|
1054 message = msg |
|
1055 |
|
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) |
|
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): |
1083 raise util.Abort(_("patch queue directory already exists")) |
1107 raise util.Abort(_("patch queue directory already exists")) |
1084 try: |
1108 try: |