changeset 54:ad1a4fb0fc49

Make states more resilient to missing head In particuliar pushkey is now more robust (with a very naif approach)
author Pierre-Yves David <pierre-yves.david@logilab.fr>
date Thu, 08 Sep 2011 18:20:01 +0200
parents 0bcbf690dfca
children cf4626a13345
files hgext/obsolete.py hgext/states.py
diffstat 2 files changed, 52 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/obsolete.py	Thu Sep 08 17:46:54 2011 +0200
+++ b/hgext/obsolete.py	Thu Sep 08 18:20:01 2011 +0200
@@ -6,6 +6,11 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 import os
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO
+
 
 from mercurial import util
 from mercurial import context
@@ -84,10 +89,14 @@
 # Pushkey mechanism for mutable
 #########################################
 
-def pushobsolete(repo, key, old, relations):
+def pushobsolete(repo, key, old, raw):
     assert key == "relations"
     w = repo.wlock()
     try:
+        tmp = StringIO()
+        tmp.write(raw)
+        tmp.seek(0)
+        relations = repo._obsdeserialise(tmp)
         for sub, objs in relations.iteritems():
             for obj in objs:
                 repo.addobsolete(sub, obj)
@@ -95,7 +104,9 @@
         w.release()
 
 def listobsolete(repo):
-    return {'relations': repo._obssubrels}
+    tmp = StringIO()
+    repo._obsserialise(tmp)
+    return {'relations': tmp.getvalue()}
 
 pushkey.register('obsolete', pushobsolete, listobsolete)
 
@@ -170,32 +181,42 @@
             """{<new-node> -> set(<old-node>)}"""
             return self._readobsrels()
 
+        ### serialisation
+        # XXX get this out the repo
+
+        def _obsserialise(self, flike):
+            for sub, objs in self._obssubrels.iteritems():
+                for obj in objs:
+                    flike.write('%s %s\n' % (hex(sub), hex(obj)))
+
+        def _obsdeserialise(self,flike):
+            rels = {}
+            for line in flike:
+                subhex, objhex = line.split()
+                rels.setdefault(bin(subhex), set()).add(bin(objhex))
+            return rels
+
+
 
         ### Disk IO
         def _readobsrels(self):
             """Write obsolete relation on disk"""
             # XXX handle lock
-            rels = {}
             try:
                 f = self.opener('obsolete-relations')
                 try:
-                    for line in f:
-                        subhex, objhex = line.split()
-                        rels.setdefault(bin(subhex), set()).add(bin(objhex))
+                    return self._obsdeserialise(f)
                 finally:
                     f.close()
             except IOError:
-                pass
-            return rels
+                return {}
 
         def _writeobsrels(self):
             """Write obsolete relation on disk"""
             # XXX handle lock
             f = self.opener('obsolete-relations', 'w', atomictemp=True)
             try:
-                for sub, objs in self._obssubrels.iteritems():
-                    for obj in objs:
-                        f.write('%s %s\n' % (hex(sub), hex(obj)))
+                self._obsserialise(f)
                 f.rename()
             finally:
                 f.close()
@@ -221,7 +242,10 @@
             obssupport = 'relations' in obskey
             result = opush(remote, *args, **opts)
             if obssupport:
-                remote.pushkey('obsolete', 'relations', {}, self._obssubrels)
+                tmp = StringIO()
+                repo._obsserialise(tmp)
+                remote.pushkey('obsolete', 'relations', {}, tmp.getvalue())
+
             return result
 
 
--- a/hgext/states.py	Thu Sep 08 17:46:54 2011 +0200
+++ b/hgext/states.py	Thu Sep 08 18:20:01 2011 +0200
@@ -33,6 +33,7 @@
 from mercurial import extensions
 from mercurial import wireproto
 from mercurial import pushkey
+from mercurial import error
 from mercurial.lock import release
 
 
@@ -69,7 +70,12 @@
         assert self.trackheads
         def revsetheads(repo, subset, x):
             args = revset.getargs(x, 0, 0, 'publicheads takes no arguments')
-            heads = map(repo.changelog.rev, repo._statesheads[self])
+            heads = []
+            for h in repo._statesheads[self]:
+                try:
+                    heads.append(repo.changelog.rev(h))
+                except error.LookupError:
+                    pass
             heads.sort()
             return heads
         return revsetheads
@@ -175,8 +181,9 @@
     st = ST0
     w = repo.wlock()
     try:
-        #print 'pushing', key
-        repo.setstate(ST0, [node.bin(key)])
+        newhead = node.bin(key)
+        repo[newhead]
+        repo.setstate(ST0, [newhead])
     finally:
         w.release()
 
@@ -389,9 +396,12 @@
 
         def _pushimmutableheads(self, remote, remoteheads):
             missing = set(self.stateheads(ST0)) - set(remoteheads)
-            for h in missing:
-                #print 'missing', node.short(h)
-                remote.pushkey('immutableheads', node.hex(h), '', '1')
+            while missing:
+                h = missing.pop()
+                try:
+                    remote.pushkey('immutableheads', node.hex(h), '', '1')
+                except error.RepoLookupError:
+                    missing.update(p.node() for p in repo[h].parents())
 
 
         def _pullimmutableheads(self, remote):