Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 4915:97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Sat, 21 Jul 2007 16:02:10 -0500 |
parents | 9a2a73ea6135 |
children | 5c5d23d93447 |
comparison
equal
deleted
inserted
replaced
4914:9a2a73ea6135 | 4915:97b734fb9c6f |
---|---|
514 self.transhandle = tr | 514 self.transhandle = tr |
515 return tr | 515 return tr |
516 | 516 |
517 def recover(self): | 517 def recover(self): |
518 l = self.lock() | 518 l = self.lock() |
519 if os.path.exists(self.sjoin("journal")): | 519 try: |
520 self.ui.status(_("rolling back interrupted transaction\n")) | 520 if os.path.exists(self.sjoin("journal")): |
521 transaction.rollback(self.sopener, self.sjoin("journal")) | 521 self.ui.status(_("rolling back interrupted transaction\n")) |
522 self.invalidate() | 522 transaction.rollback(self.sopener, self.sjoin("journal")) |
523 return True | 523 self.invalidate() |
524 else: | 524 return True |
525 self.ui.warn(_("no interrupted transaction available\n")) | 525 else: |
526 return False | 526 self.ui.warn(_("no interrupted transaction available\n")) |
527 return False | |
528 finally: | |
529 del l | |
527 | 530 |
528 def rollback(self, wlock=None, lock=None): | 531 def rollback(self, wlock=None, lock=None): |
529 if not wlock: | 532 try: |
530 wlock = self.wlock() | 533 if not wlock: |
531 if not lock: | 534 wlock = self.wlock() |
532 lock = self.lock() | 535 if not lock: |
533 if os.path.exists(self.sjoin("undo")): | 536 lock = self.lock() |
534 self.ui.status(_("rolling back last transaction\n")) | 537 if os.path.exists(self.sjoin("undo")): |
535 transaction.rollback(self.sopener, self.sjoin("undo")) | 538 self.ui.status(_("rolling back last transaction\n")) |
536 util.rename(self.join("undo.dirstate"), self.join("dirstate")) | 539 transaction.rollback(self.sopener, self.sjoin("undo")) |
537 self.invalidate() | 540 util.rename(self.join("undo.dirstate"), self.join("dirstate")) |
538 self.dirstate.invalidate() | 541 self.invalidate() |
539 else: | 542 self.dirstate.invalidate() |
540 self.ui.warn(_("no rollback information available\n")) | 543 else: |
544 self.ui.warn(_("no rollback information available\n")) | |
545 finally: | |
546 del wlock, lock | |
541 | 547 |
542 def invalidate(self): | 548 def invalidate(self): |
543 for a in "changelog manifest".split(): | 549 for a in "changelog manifest".split(): |
544 if hasattr(self, a): | 550 if hasattr(self, a): |
545 self.__delattr__(a) | 551 self.__delattr__(a) |
637 p1=p1, p2=p2, wlock=wlock, extra=extra) | 643 p1=p1, p2=p2, wlock=wlock, extra=extra) |
638 | 644 |
639 def commit(self, files=None, text="", user=None, date=None, | 645 def commit(self, files=None, text="", user=None, date=None, |
640 match=util.always, force=False, lock=None, wlock=None, | 646 match=util.always, force=False, lock=None, wlock=None, |
641 force_editor=False, p1=None, p2=None, extra={}): | 647 force_editor=False, p1=None, p2=None, extra={}): |
642 | 648 tr = None |
643 commit = [] | 649 try: |
644 remove = [] | 650 commit = [] |
645 changed = [] | 651 remove = [] |
646 use_dirstate = (p1 is None) # not rawcommit | 652 changed = [] |
647 extra = extra.copy() | 653 use_dirstate = (p1 is None) # not rawcommit |
648 | 654 extra = extra.copy() |
649 if use_dirstate: | 655 |
650 if files: | 656 if use_dirstate: |
651 for f in files: | 657 if files: |
652 s = self.dirstate[f] | 658 for f in files: |
653 if s in 'nma': | 659 s = self.dirstate[f] |
654 commit.append(f) | 660 if s in 'nma': |
655 elif s == 'r': | 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 | |
671 else: | |
672 commit = files | |
673 | |
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) | |
680 | |
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]) | |
685 | |
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 = "" | |
694 | |
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 | |
701 | |
702 xp1 = hex(p1) | |
703 if p2 == nullid: xp2 = '' | |
704 else: xp2 = hex(p2) | |
705 | |
706 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) | |
707 | |
708 if not wlock: | |
709 wlock = self.wlock() | |
710 if not lock: | |
711 lock = self.lock() | |
712 tr = self.transaction() | |
713 | |
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: | |
656 remove.append(f) | 740 remove.append(f) |
657 else: | 741 |
658 self.ui.warn(_("%s not tracked!\n") % f) | 742 # update manifest |
659 else: | 743 m1.update(new) |
660 changes = self.status(match=match)[:5] | 744 remove.sort() |
661 modified, added, removed, deleted, unknown = changes | 745 removed = [] |
662 commit = modified + added | 746 |
663 remove = removed | 747 for f in remove: |
664 else: | 748 if f in m1: |
665 commit = files | 749 del m1[f] |
666 | 750 removed.append(f) |
667 if use_dirstate: | 751 elif f in m2: |
668 p1, p2 = self.dirstate.parents() | 752 removed.append(f) |
669 update_dirstate = True | 753 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], |
670 else: | 754 (new, removed)) |
671 p1, p2 = p1, p2 or nullid | 755 |
672 update_dirstate = (self.dirstate.parents()[0] == p1) | 756 # add changeset |
673 | 757 new = new.keys() |
674 c1 = self.changelog.read(p1) | 758 new.sort() |
675 c2 = self.changelog.read(p2) | 759 |
676 m1 = self.manifest.read(c1[0]).copy() | 760 user = user or self.ui.username() |
677 m2 = self.manifest.read(c2[0]) | 761 if not text or force_editor: |
678 | 762 edittext = [] |
679 if use_dirstate: | 763 if text: |
680 branchname = self.workingctx().branch() | 764 edittext.append(text) |
681 try: | 765 edittext.append("") |
682 branchname = branchname.decode('UTF-8').encode('UTF-8') | 766 edittext.append("HG: user: %s" % user) |
683 except UnicodeDecodeError: | 767 if p2 != nullid: |
684 raise util.Abort(_('branch name not in UTF-8!')) | 768 edittext.append("HG: branch merge") |
685 else: | 769 if branchname: |
686 branchname = "" | 770 edittext.append("HG: branch %s" % util.tolocal(branchname)) |
687 | 771 edittext.extend(["HG: changed %s" % f for f in changed]) |
688 if use_dirstate: | 772 edittext.extend(["HG: removed %s" % f for f in removed]) |
689 oldname = c1[5].get("branch") # stored in UTF-8 | 773 if not changed and not remove: |
690 if (not commit and not remove and not force and p2 == nullid | 774 edittext.append("HG: no files changed") |
691 and branchname == oldname): | 775 edittext.append("") |
692 self.ui.status(_("nothing changed\n")) | 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) | |
781 | |
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: | |
693 return None | 786 return None |
694 | 787 text = '\n'.join(lines) |
695 xp1 = hex(p1) | 788 if branchname: |
696 if p2 == nullid: xp2 = '' | 789 extra["branch"] = branchname |
697 else: xp2 = hex(p2) | 790 n = self.changelog.add(mn, changed + removed, text, tr, p1, p2, |
698 | 791 user, date, extra) |
699 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) | 792 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, |
700 | 793 parent2=xp2) |
701 if not wlock: | 794 tr.close() |
702 wlock = self.wlock() | 795 |
703 if not lock: | 796 if self.branchcache and "branch" in extra: |
704 lock = self.lock() | 797 self.branchcache[util.tolocal(extra["branch"])] = n |
705 tr = self.transaction() | 798 |
706 | 799 if use_dirstate or update_dirstate: |
707 # check in files | 800 self.dirstate.setparents(n) |
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: | 801 if use_dirstate: |
729 self.ui.warn(_("trouble committing %s!\n") % f) | 802 for f in new: |
730 raise | 803 self.dirstate.normal(f) |
731 else: | 804 for f in removed: |
732 remove.append(f) | 805 self.dirstate.forget(f) |
733 | 806 |
734 # update manifest | 807 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) |
735 m1.update(new) | 808 return n |
736 remove.sort() | 809 finally: |
737 removed = [] | 810 del lock, wlock, tr |
738 | |
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)) | |
746 | |
747 # add changeset | |
748 new = new.keys() | |
749 new.sort() | |
750 | |
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) | |
772 | |
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() | |
786 | |
787 if self.branchcache and "branch" in extra: | |
788 self.branchcache[util.tolocal(extra["branch"])] = n | |
789 | |
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) | |
797 | |
798 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) | |
799 return n | |
800 | 811 |
801 def walk(self, node=None, files=[], match=util.always, badmatch=None): | 812 def walk(self, node=None, files=[], match=util.always, badmatch=None): |
802 ''' | 813 ''' |
803 walk recursively through the directory tree or a given | 814 walk recursively through the directory tree or a given |
804 changeset, finding all files matched by the match | 815 changeset, finding all files matched by the match |
893 if list_clean: | 904 if list_clean: |
894 clean.append(f) | 905 clean.append(f) |
895 | 906 |
896 # update dirstate for files that are actually clean | 907 # update dirstate for files that are actually clean |
897 if fixup: | 908 if fixup: |
898 cleanup = False | 909 fixlock = wlock |
899 if not wlock: | 910 try: |
900 try: | 911 if not fixlock: |
901 wlock = self.wlock(False) | 912 try: |
902 cleanup = True | 913 fixlock = self.wlock(False) |
903 except lock.LockException: | 914 except lock.LockException: |
904 pass | 915 pass |
905 if wlock: | 916 if fixlock: |
906 for f in fixup: | 917 for f in fixup: |
907 self.dirstate.normal(f) | 918 self.dirstate.normal(f) |
908 if cleanup: | 919 finally: |
909 wlock.release() | 920 del fixlock |
910 else: | 921 else: |
911 # we are comparing working dir against non-parent | 922 # we are comparing working dir against non-parent |
912 # generate a pseudo-manifest for the working dir | 923 # generate a pseudo-manifest for the working dir |
913 # XXX: create it in dirstate.py ? | 924 # XXX: create it in dirstate.py ? |
914 mf2 = mfmatches(self.dirstate.parents()[0]) | 925 mf2 = mfmatches(self.dirstate.parents()[0]) |
952 for l in modified, added, removed, deleted, unknown, ignored, clean: | 963 for l in modified, added, removed, deleted, unknown, ignored, clean: |
953 l.sort() | 964 l.sort() |
954 return (modified, added, removed, deleted, unknown, ignored, clean) | 965 return (modified, added, removed, deleted, unknown, ignored, clean) |
955 | 966 |
956 def add(self, list, wlock=None): | 967 def add(self, list, wlock=None): |
957 if not wlock: | 968 try: |
958 wlock = self.wlock() | |
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) | |
978 | |
979 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) | |
987 | |
988 def remove(self, list, unlink=False, wlock=None): | |
989 if unlink: | |
990 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) | |
1007 | |
1008 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) | |
1021 | |
1022 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: | 969 if not wlock: |
1031 wlock = self.wlock() | 970 wlock = self.wlock() |
1032 if dest not in self.dirstate: | 971 for f in list: |
1033 self.dirstate.add(dest) | 972 p = self.wjoin(f) |
1034 self.dirstate.copy(source, dest) | 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 | |
992 | |
993 def forget(self, list, wlock=None): | |
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 | |
1004 | |
1005 def remove(self, list, unlink=False, wlock=None): | |
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() | |
1016 for f in list: | |
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 | |
1027 | |
1028 def undelete(self, list, wlock=None): | |
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 | |
1044 | |
1045 def copy(self, source, dest, wlock=None): | |
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 def heads(self, start=None): | 1062 def heads(self, start=None): |
1037 heads = self.changelog.heads(start) | 1063 heads = self.changelog.heads(start) |
1038 # sort the output in rev descending order | 1064 # sort the output in rev descending order |
1039 heads = [(-self.changelog.rev(h), h) for h in heads] | 1065 heads = [(-self.changelog.rev(h), h) for h in heads] |
1307 return subset, updated_heads.keys() | 1333 return subset, updated_heads.keys() |
1308 else: | 1334 else: |
1309 return subset | 1335 return subset |
1310 | 1336 |
1311 def pull(self, remote, heads=None, force=False, lock=None): | 1337 def pull(self, remote, heads=None, force=False, lock=None): |
1312 mylock = False | |
1313 if not lock: | |
1314 lock = self.lock() | |
1315 mylock = True | |
1316 | |
1317 try: | 1338 try: |
1339 if not lock: | |
1340 lock = self.lock() | |
1318 fetch = self.findincoming(remote, force=force) | 1341 fetch = self.findincoming(remote, force=force) |
1319 if fetch == [nullid]: | 1342 if fetch == [nullid]: |
1320 self.ui.status(_("requesting all changes\n")) | 1343 self.ui.status(_("requesting all changes\n")) |
1321 | 1344 |
1322 if not fetch: | 1345 if not fetch: |
1329 if 'changegroupsubset' not in remote.capabilities: | 1352 if 'changegroupsubset' not in remote.capabilities: |
1330 raise util.Abort(_("Partial pull cannot be done because other repository doesn't support changegroupsubset.")) | 1353 raise util.Abort(_("Partial pull cannot be done because other repository doesn't support changegroupsubset.")) |
1331 cg = remote.changegroupsubset(fetch, heads, 'pull') | 1354 cg = remote.changegroupsubset(fetch, heads, 'pull') |
1332 return self.addchangegroup(cg, 'pull', remote.url()) | 1355 return self.addchangegroup(cg, 'pull', remote.url()) |
1333 finally: | 1356 finally: |
1334 if mylock: | 1357 del lock |
1335 lock.release() | |
1336 | 1358 |
1337 def push(self, remote, force=False, revs=None): | 1359 def push(self, remote, force=False, revs=None): |
1338 # there are two ways to push to remote repo: | 1360 # there are two ways to push to remote repo: |
1339 # | 1361 # |
1340 # addchangegroup assumes local user can lock remote | 1362 # addchangegroup assumes local user can lock remote |
1403 cg = self.changegroupsubset(update, revs, 'push') | 1425 cg = self.changegroupsubset(update, revs, 'push') |
1404 return cg, remote_heads | 1426 return cg, remote_heads |
1405 | 1427 |
1406 def push_addchangegroup(self, remote, force, revs): | 1428 def push_addchangegroup(self, remote, force, revs): |
1407 lock = remote.lock() | 1429 lock = remote.lock() |
1408 | 1430 try: |
1409 ret = self.prepush(remote, force, revs) | 1431 ret = self.prepush(remote, force, revs) |
1410 if ret[0] is not None: | 1432 if ret[0] is not None: |
1411 cg, remote_heads = ret | 1433 cg, remote_heads = ret |
1412 return remote.addchangegroup(cg, 'push', self.url()) | 1434 return remote.addchangegroup(cg, 'push', self.url()) |
1413 return ret[1] | 1435 return ret[1] |
1436 finally: | |
1437 del lock | |
1414 | 1438 |
1415 def push_unbundle(self, remote, force, revs): | 1439 def push_unbundle(self, remote, force, revs): |
1416 # local repo finds heads on server, finds out what revs it | 1440 # local repo finds heads on server, finds out what revs it |
1417 # must push. once revs transferred, if server finds it has | 1441 # must push. once revs transferred, if server finds it has |
1418 # different heads (someone else won commit/push race), server | 1442 # different heads (someone else won commit/push race), server |
1792 | 1816 |
1793 self.hook('prechangegroup', throw=True, source=srctype, url=url) | 1817 self.hook('prechangegroup', throw=True, source=srctype, url=url) |
1794 | 1818 |
1795 changesets = files = revisions = 0 | 1819 changesets = files = revisions = 0 |
1796 | 1820 |
1797 tr = self.transaction() | |
1798 | |
1799 # write changelog data to temp files so concurrent readers will not see | 1821 # write changelog data to temp files so concurrent readers will not see |
1800 # inconsistent view | 1822 # inconsistent view |
1801 cl = self.changelog | 1823 cl = self.changelog |
1802 cl.delayupdate() | 1824 cl.delayupdate() |
1803 oldheads = len(cl.heads()) | 1825 oldheads = len(cl.heads()) |
1804 | 1826 |
1805 # pull off the changeset group | 1827 tr = self.transaction() |
1806 self.ui.status(_("adding changesets\n")) | 1828 try: |
1807 cor = cl.count() - 1 | 1829 # pull off the changeset group |
1808 chunkiter = changegroup.chunkiter(source) | 1830 self.ui.status(_("adding changesets\n")) |
1809 if cl.addgroup(chunkiter, csmap, tr, 1) is None: | 1831 cor = cl.count() - 1 |
1810 raise util.Abort(_("received changelog group is empty")) | |
1811 cnr = cl.count() - 1 | |
1812 changesets = cnr - cor | |
1813 | |
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) | |
1822 | |
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) | 1832 chunkiter = changegroup.chunkiter(source) |
1833 if fl.addgroup(chunkiter, revmap, tr) is None: | 1833 if cl.addgroup(chunkiter, csmap, tr, 1) is None: |
1834 raise util.Abort(_("received file revlog group is empty")) | 1834 raise util.Abort(_("received changelog group is empty")) |
1835 revisions += fl.count() - o | 1835 cnr = cl.count() - 1 |
1836 files += 1 | 1836 changesets = cnr - cor |
1837 | 1837 |
1838 # make changelog see real files again | 1838 # pull off the manifest group |
1839 cl.finalize(tr) | 1839 self.ui.status(_("adding manifests\n")) |
1840 | 1840 chunkiter = changegroup.chunkiter(source) |
1841 newheads = len(self.changelog.heads()) | 1841 # no need to check for empty manifest group here: |
1842 heads = "" | 1842 # if the result of the merge of 1 and 2 is the same in 3 and 4, |
1843 if oldheads and newheads != oldheads: | 1843 # no new manifest will be created and the manifest group will |
1844 heads = _(" (%+d heads)") % (newheads - oldheads) | 1844 # be empty during the pull |
1845 | 1845 self.manifest.addgroup(chunkiter, revmap, tr) |
1846 self.ui.status(_("added %d changesets" | 1846 |
1847 " with %d changes to %d files%s\n") | 1847 # process the files |
1848 % (changesets, revisions, files, heads)) | 1848 self.ui.status(_("adding file changes\n")) |
1849 | 1849 while 1: |
1850 if changesets > 0: | 1850 f = changegroup.getchunk(source) |
1851 self.hook('pretxnchangegroup', throw=True, | 1851 if not f: |
1852 node=hex(self.changelog.node(cor+1)), source=srctype, | 1852 break |
1853 url=url) | 1853 self.ui.debug(_("adding %s revisions\n") % f) |
1854 | 1854 fl = self.file(f) |
1855 tr.close() | 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) | |
1864 | |
1865 newheads = len(self.changelog.heads()) | |
1866 heads = "" | |
1867 if oldheads and newheads != oldheads: | |
1868 heads = _(" (%+d heads)") % (newheads - oldheads) | |
1869 | |
1870 self.ui.status(_("added %d changesets" | |
1871 " with %d changes to %d files%s\n") | |
1872 % (changesets, revisions, files, heads)) | |
1873 | |
1874 if changesets > 0: | |
1875 self.hook('pretxnchangegroup', throw=True, | |
1876 node=hex(self.changelog.node(cor+1)), source=srctype, | |
1877 url=url) | |
1878 | |
1879 tr.close() | |
1880 finally: | |
1881 del tr | |
1856 | 1882 |
1857 if changesets > 0: | 1883 if changesets > 0: |
1858 self.hook("changegroup", node=hex(self.changelog.node(cor+1)), | 1884 self.hook("changegroup", node=hex(self.changelog.node(cor+1)), |
1859 source=srctype, url=url) | 1885 source=srctype, url=url) |
1860 | 1886 |