push: put phase in the same bundle2 than changegroup and obsmarkers
authorPierre-Yves David <pierre-yves.david@fb.com>
Fri, 25 Jul 2014 17:13:54 +0200
changeset 1007 1d8ba8244001
parent 1006 deba3a063c63
child 1008 a010ba5a0ffb
push: put phase in the same bundle2 than changegroup and obsmarkers Note that the usual phase push from core will be performed in all case. But the discovery should find already in sync phase at that time. The old ways sync will be properly skipped when this logic is introduced into core.
README
hgext/evolve.py
--- a/README	Fri Jul 25 16:54:08 2014 +0200
+++ b/README	Fri Jul 25 17:13:54 2014 +0200
@@ -62,8 +62,8 @@
 - amend: add -D/--current-date option
 - amend: add -U/--current-user option
 - evolve: add a --tool option
-- push obsmarkers in the same transaction than changesets (when using hg >= 3.1
-  and bundle2-exp is enabled)
+- push obsmarkers and phases in the same transaction than changesets
+  (when using hg >= 3.1 and bundle2-exp is enabled)
 
 4.0.0 -- 2014-06-03
 
--- a/hgext/evolve.py	Fri Jul 25 16:54:08 2014 +0200
+++ b/hgext/evolve.py	Fri Jul 25 17:13:54 2014 +0200
@@ -58,6 +58,7 @@
 from mercurial import node
 from mercurial import phases
 from mercurial import patch
+from mercurial import pushkey
 from mercurial import revset
 from mercurial import scmutil
 from mercurial import templatekw
@@ -2320,7 +2321,64 @@
 
 bundle2partsgenerators = getattr(exchange, 'bundle2partsgenerators', None)
 
+
 if bundle2partsgenerators is not None:
+
+    def _pushb2phases(pushop, bundler):
+        """adds phases update to the main bundle2 push"""
+        outgoing = pushop.outgoing
+        unfi = pushop.repo.unfiltered()
+        remotephases = pushop.remote.listkeys('phases')
+        publishing = remotephases.get('publishing', False)
+        ana = phases.analyzeremotephases(pushop.repo,
+                                         outgoing.commonheads,
+                                         remotephases)
+        pheads, droots = ana
+        revset = 'heads((%ln::%ln))'
+        if not publishing:
+            revset += ' and public()'
+        # Get the list of all revs draft on remote by public here.
+        # XXX Beware that revset break if droots is not strictly
+        # XXX root we may want to ensure it is but it is costly
+        fallback = list(unfi.set(revset, droots, outgoing.commonheads))
+        if not outgoing.missing:
+            future = fallback
+        else:
+            # adds changeset we are going to push as draft
+            #
+            # should not be necessary for pushblishing server, but because of
+            # an issue fixed in xxxxx we have to do it anyway.
+            fdroots = list(unfi.set('roots(%ln  + %ln::)', outgoing.missing, droots))
+            fdroots = [f.node() for f in fdroots]
+            future = list(unfi.set(revset, fdroots, outgoing.missingheads))
+
+        b2caps = bundle2.bundle2caps(pushop.remote)
+        if 'b2x:pushkey' not in b2caps:
+            return
+        pushop.stepsdone.add('phases')
+        part2node = []
+        enc = pushkey.encode
+        for newremotehead in future:
+            part = bundler.newpart('b2x:pushkey')
+            part.addparam('namespace', enc('phases'))
+            part.addparam('key', enc(newremotehead.hex()))
+            part.addparam('old', enc(str(phases.draft)))
+            part.addparam('new', enc(str(phases.public)))
+            part2node.append((part.id, newremotehead))
+        def handlereply(op):
+            for partid, pnode in part2node:
+                partrep = op.records.getreplies(partid)
+                results = partrep['pushkey']
+                assert len(results) <= 1
+                msg = None
+                if not results:
+                    msg = _('server ignored update of %s to public!\n') % pnode
+                elif not int(results[0]['return']):
+                    msg = _('updating %s to public failed!\n') % pnode
+                if msg is not None:
+                    pushop.ui.warn(msg)
+        return handlereply
+
     def _pushb2obsmarker(pushop, bundler):
         """adds obsmarker to the main bundle2 push"""
         repo = pushop.repo
@@ -2347,6 +2405,7 @@
                 repo.ui.progress('OBSEXC', None)
                 repo.ui.status("OBSEXC: DONE\n")
             return callback
+    bundle2partsgenerators.append(_pushb2phases)
     bundle2partsgenerators.append(_pushb2obsmarker)