states.py
changeset 21 aa0870d093b8
parent 20 9983f240ac63
child 22 93dd72d028a1
--- a/states.py	Mon Jun 06 16:52:03 2011 +0200
+++ b/states.py	Mon Jun 06 16:42:56 2011 +0200
@@ -30,6 +30,7 @@
 from mercurial import discovery
 from mercurial import extensions
 from mercurial import wireproto
+from mercurial import pushkey
 
 
 _NOSHARE=2
@@ -88,6 +89,7 @@
 
 STATES = (ST0, ST1, ST2)
 
+@util.cachefunc
 def laststatewithout(prop):
     for state in STATES:
         if not state.properties & prop:
@@ -131,7 +133,22 @@
         cmdmoveheads = makecmd(state)
         cmdtable[state.name] = (cmdmoveheads, [], '<revset>')
 
+# Pushkey mechanism for mutable
+#########################################
 
+def pushimmutableheads(repo, key, old, new):
+    st = ST0
+    w = repo.wlock()
+    try:
+        #print 'pushing', key
+        repo.setstate(ST0, [node.bin(key)])
+    finally:
+        w.release()
+
+def listimmutableheads(repo):
+    return dict.fromkeys(map(node.hex, repo.stateheads(ST0)), '1')
+
+pushkey.register('immutableheads', pushimmutableheads, listimmutableheads)
 
 
 
@@ -175,7 +192,9 @@
     if not repo.local():
         return
 
-    o_cancopy =repo.cancopy
+    ocancopy =repo.cancopy
+    opull =repo.pull
+    opush =repo.push
     class statefulrepo(repo.__class__):
 
         def nodestate(self, node):
@@ -241,9 +260,10 @@
                     self._writeheadsfile(filename, self._statesheads[state])
 
         def setstate(self, state, nodes):
-            """freeze targets changeset and it's ancestors.
+            """change state of targets changeset and it's ancestors.
 
             Simplify the list of head."""
+            assert not isinstance(nodes, basestring)
             heads = self._statesheads[state]
             olds = heads[:]
             heads.extend(nodes)
@@ -274,7 +294,43 @@
 
         def cancopy(self):
             st = laststatewithout(_NOSHARE)
-            return o_cancopy() and (self.stateheads(st) == self.heads())
+            return ocancopy() and (self.stateheads(st) == self.heads())
+
+        def pull(self, remote, *args, **kwargs):
+            result = opull(remote, *args, **kwargs)
+            remoteheads = self._pullimmutableheads(remote)
+            #print [node.short(h) for h in remoteheads]
+            self.setstate(ST0, remoteheads)
+            return result
+
+        def push(self, remote, *args, **opts):
+            result = opush(remote, *args, **opts)
+            remoteheads = self._pullimmutableheads(remote)
+            self.setstate(ST0, remoteheads)
+            if remoteheads != self.stateheads(ST0):
+                #print 'stuff to push'
+                #print 'remote', [node.short(h) for h in remoteheads]
+                #print 'local',  [node.short(h) for h in self._statesheads[ST0]]
+                self._pushimmutableheads(remote, remoteheads)
+            return result
+
+        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')
+
+
+        def _pullimmutableheads(self, remote):
+            self.ui.debug('checking for immutableheadshg on server')
+            if 'immutableheads' not in remote.listkeys('namespaces'):
+                self.ui.debug('immutableheads not enabled on the remote server, '
+                              'marking everything as frozen')
+                remote = remote.heads()
+            else:
+                self.ui.debug('server has immutableheads enabled, merging lists')
+                remote = map(node.bin, remote.listkeys('immutableheads'))
+            return remote
 
     repo.__class__ = statefulrepo