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