phases: simplify phase exchange and movement over pushkey
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Fri, 13 Jan 2012 02:04:16 +0100
changeset 15892 592b3d1742a1
parent 15891 249d3420ec9c
child 15893 eb6867b98223
phases: simplify phase exchange and movement over pushkey The code now only exchange draft root and only care about movement related to public//draft boundary. There is multiple reason to simplify this code: * Secret are never discovered anymore * We decided to not support more the three existing phase Removing phase index from pushkey (if ever decided) will be made in another commit.
mercurial/localrepo.py
mercurial/phases.py
tests/test-push-http.t
--- a/mercurial/localrepo.py	Fri Jan 13 01:42:47 2012 +0100
+++ b/mercurial/localrepo.py	Fri Jan 13 02:04:16 2012 +0100
@@ -1555,10 +1555,10 @@
             if remotephases and not publishing:
                 # remote is new and unpublishing
                 subset = common + added
-                rheads, rroots = phases.analyzeremotephases(self, subset,
-                                                            remotephases)
-                for phase, boundary in enumerate(rheads):
-                    phases.advanceboundary(self, phase, boundary)
+                pheads, _dr = phases.analyzeremotephases(self, subset,
+                                                         remotephases)
+                phases.advanceboundary(self, phases.public, pheads)
+                phases.advanceboundary(self, phases.draft, common + added)
             else:
                 # Remote is old or publishing all common changesets
                 # should be seen as public
@@ -1627,72 +1627,32 @@
                     # don't push any phase data as there is nothing to push
                 else:
                     ana = phases.analyzeremotephases(self, fut, remotephases)
-                    rheads, rroots = ana
+                    pheads, droots = ana
                     ### Apply remote phase on local
                     if remotephases.get('publishing', False):
                         phases.advanceboundary(self, phases.public, fut)
                     else: # publish = False
-                        for phase, rpheads in enumerate(rheads):
-                            phases.advanceboundary(self, phase, rpheads)
+                        phases.advanceboundary(self, phases.public, pheads)
+                        phases.advanceboundary(self, phases.draft, fut)
                     ### Apply local phase on remote
                     #
                     # XXX If push failed we should use strict common and not
-                    # future to avoir pushing phase data on unknown changeset.
+                    # future to avoid pushing phase data on unknown changeset.
                     # This is to done later.
 
-                    # element we want to push
-                    topush = []
-
-                    # store details of known remote phase of several revision
-                    # /!\ set of index I holds rev where: I <= rev.phase()
-                    # /!\ public phase (index 0) is ignored
-                    remdetails = [set() for i in xrange(len(phases.allphases))]
-                    _revs = set()
-                    for relremphase in phases.trackedphases[::-1]:
-                        # we iterate backward because the list alway grows
-                        # when filled in this direction.
-                        _revs.update(self.revs('%ln::%ln',
-                                               rroots[relremphase], fut))
-                        remdetails[relremphase].update(_revs)
-
-                    for phase in phases.allphases[:-1]:
-                        # We don't need the last phase as we will never want to
-                        # move anything to it while moving phase backward.
-
-                        # Get the list of all revs on remote which are in a
-                        # phase higher than currently processed phase.
-                        relremrev = remdetails[phase + 1]
-
-                        if not relremrev:
-                            # no candidate to remote push anymore
-                            # break before any expensive revset
-                            break
-
-                        #dynamical inject appropriate phase symbol
-                        phasename = phases.phasenames[phase]
-                        odrevset = 'heads(%%ld and %s())' % phasename
-                        outdated =  self.set(odrevset, relremrev)
-                        for od in outdated:
-                            candstart = len(remdetails) - 1
-                            candstop = phase + 1
-                            candidateold = xrange(candstart, candstop, -1)
-                            for oldphase in candidateold:
-                                if od.rev() in remdetails[oldphase]:
-                                    break
-                            else: # last one: no need to search
-                                oldphase = phase + 1
-                            topush.append((oldphase, phase, od))
-
-                    # push every needed data
-                    for oldphase, newphase, newremotehead in topush:
+                    # 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
+                    outdated =  self.set('heads((%ln::%ln) and public())',
+                                         droots, fut)
+                    for newremotehead in outdated:
                         r = remote.pushkey('phases',
                                            newremotehead.hex(),
-                                           str(oldphase), str(newphase))
+                                           str(phases.draft),
+                                           str(phases.public))
                         if not r:
-                            self.ui.warn(_('updating phase of %s '
-                                           'to %s from %s failed!\n')
-                                            % (newremotehead, newphase,
-                                               oldphase))
+                            self.ui.warn(_('updating %s to public failed!\n')
+                                            % newremotehead)
             finally:
                 locallock.release()
         finally:
--- a/mercurial/phases.py	Fri Jan 13 01:42:47 2012 +0100
+++ b/mercurial/phases.py	Fri Jan 13 02:04:16 2012 +0100
@@ -203,9 +203,10 @@
 def listphases(repo):
     """List phases root for serialisation over pushkey"""
     keys = {}
-    for phase in trackedphases:
-        for root in repo._phaseroots[phase]:
-            keys[hex(root)] = '%i' % phase
+    value = '%i' % draft
+    for root in repo._phaseroots[draft]:
+        keys[hex(root)] = value
+
     if repo.ui.configbool('phases', 'publish', True):
         # Add an extra data to let remote know we are a publishing repo.
         # Publishing repo can't just pretend they are old repo. When pushing to
@@ -264,20 +265,26 @@
     Accept unknown element input
     """
     # build list from dictionary
-    phaseroots = [[] for p in allphases]
+    draftroots = []
+    nm = repo.changelog.nodemap # to filter unknown node
     for nhex, phase in roots.iteritems():
         if nhex == 'publishing': # ignore data related to publish option
             continue
         node = bin(nhex)
         phase = int(phase)
-        if node in repo:
-            phaseroots[phase].append(node)
+        if phase == 0:
+            if node != nullid:
+                msg = _('ignoring inconsistense public root from remote: %s')
+                repo.ui.warn(msg, nhex)
+        elif phase == 1:
+            if node in nm:
+                draftroots.append(node)
+        else:
+            msg = _('ignoring unexpected root from remote: %i %s')
+            repo.ui.warn(msg, phase, nhex)
     # compute heads
-    phaseheads = [[] for p in allphases]
-    for phase in allphases[:-1]:
-        toproof = phaseroots[phase + 1]
-        revset = repo.set('heads((%ln + parents(%ln)) - (%ln::%ln))',
-                          subset, toproof, toproof, subset)
-        phaseheads[phase].extend(c.node() for c in revset)
-    return phaseheads, phaseroots
+    revset = repo.set('heads((%ln + parents(%ln)) - (%ln::%ln))',
+                      subset, draftroots, draftroots, subset)
+    publicheads = [c.node() for c in revset]
+    return publicheads, draftroots
 
--- a/tests/test-push-http.t	Fri Jan 13 01:42:47 2012 +0100
+++ b/tests/test-push-http.t	Fri Jan 13 02:04:16 2012 +0100
@@ -29,7 +29,7 @@
   searching for changes
   remote: ssl required
   remote: ssl required
-  updating phase of ba677d0156c1 to 0 from 1 failed!
+  updating ba677d0156c1 to public failed!
   % serve errors
 
 expect authorization error