Add pull and push support for relevant heads.
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Mon, 06 Jun 2011 16:42:56 +0200
changeset 21 aa0870d093b8
parent 20 9983f240ac63
child 22 93dd72d028a1
Add pull and push support for relevant heads. This use pushkey.
states.py
tests/run-tests.py
tests/test-draft.t
tests/test-ready.t
--- 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
 
--- a/tests/run-tests.py	Mon Jun 06 16:52:03 2011 +0200
+++ b/tests/run-tests.py	Mon Jun 06 16:42:56 2011 +0200
@@ -277,8 +277,12 @@
     return missing, failed
 
 def showdiff(expected, output, ref, err):
-    for line in difflib.unified_diff(expected, output, ref, err):
-        sys.stdout.write(line)
+    try:
+        for line in difflib.unified_diff(expected, output, ref, err):
+            sys.stdout.write(line)
+    except IOError, ex:
+        print >>sys.stderr, 'BORKEN PIPE', ex.errno
+        pass
 
 def findprogram(program):
     """Search PATH for a executable program"""
@@ -765,8 +769,12 @@
         fail("returned error code %d" % ret)
 
     if not options.verbose:
-        sys.stdout.write(mark)
-        sys.stdout.flush()
+        try:
+            sys.stdout.write(mark)
+            sys.stdout.flush()
+        except IOError, ex:
+            print >>sys.stderr, 'BORKEN PIPE', ex.errno
+            pass
 
     killdaemons()
 
--- a/tests/test-draft.t	Mon Jun 06 16:52:03 2011 +0200
+++ b/tests/test-draft.t	Mon Jun 06 16:42:56 2011 +0200
@@ -30,7 +30,6 @@
   adding manifests
   adding file changes
   added 2 changesets with 2 changes to 1 files
-  $ hg publish 1 # until we fix push
   $ echo "tree" >> savanna
   $ hg add savanna
   $ hg ci -m "terrain"
@@ -59,7 +58,7 @@
   searching for changes
   no changes found
   [1]
-  $ hg push  ../remote1
+  $ hg push --traceback  ../remote1
   pushing to ../remote1
   searching for changes
   no changes found
@@ -101,7 +100,7 @@
   comparing with ../local
   0:5caa672bac26
   1:710fe444b3b0
-  $ hg pull  ../local
+  $ hg pull ../local
   pulling from ../local
   requesting all changes
   adding changesets
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ready.t	Mon Jun 06 16:42:56 2011 +0200
@@ -0,0 +1,129 @@
+  $ cat >> $HGRCPATH <<EOF
+  > [liquid]
+  > publish = False
+  > [extensions]
+  > graphlog=
+  > EOF
+  $ echo "states=$(echo $(dirname $TESTDIR))/states.py" >> $HGRCPATH
+
+  $ mkcommit() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg ci -m "add $1"
+  > }
+
+  $ hg init alpha
+  $ cd alpha
+  $ cat > .hg/hgrc << EOF
+  > [states]
+  > ready=yes
+  > EOF
+  $ mkcommit z
+  $ mkcommit a
+  $ mkcommit b
+  $ mkcommit c
+  $ hg published 1
+  $ hg log --graph
+  @  changeset:   3:090483935bca
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add c
+  |
+  o  changeset:   2:720fd97246d7
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add b
+  |
+  o  changeset:   1:7a344d213ee2
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a
+  |
+  o  changeset:   0:d32fd17cb041
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add z
+  
+  $ cat .hg/states/published-heads
+  7a344d213ee2eb3359d94630d4e076460d59dbf0
+
+publishedheads() should return only revision 1:
+  $ hg log -r 'publishedheads()' --graph
+  o  changeset:   1:7a344d213ee2
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a
+  |
+
+ancestors of publishedheads shows all frozen revisions:
+  $ hg log -r '::publishedheads()' --graph
+  o  changeset:   1:7a344d213ee2
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a
+  |
+  o  changeset:   0:d32fd17cb041
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add z
+  
+  $ cd ..
+  $ hg init beta
+  $ cd beta
+  $ cat > .hg/hgrc << EOF
+  > [states]
+  > ready=yes
+  > EOF
+  $ hg pull ../alpha --update
+  pulling from ../alpha
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 4 files
+  4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg log --graph -r 'publishedheads()'
+  o  changeset:   1:7a344d213ee2
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add a
+  |
+
+Freeze in beta and push to alpha:
+  $ hg published 3
+  $ mkcommit d
+  $ hg push --traceback ../alpha
+  pushing to ../alpha
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  $ cd ../alpha
+  $ hg debugrevspec 'publishedheads()'
+  3
+  $ hg log --graph -r 'publishedheads()'
+  @  changeset:   3:090483935bca
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     add c
+  |
+
+  $ hg log -r tip
+  changeset:   4:fb98f3f5bba0
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     add d
+  
+  $ mkcommit e
+  created new head
+  $ hg up -C 4
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg log -r 'publishedheads()'
+  changeset:   3:090483935bca
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     add c
+