Patchwork [1,of,2,V2] obsolete: extract foreground computation from bookmark.validdest

login
register
mail settings
Submitter Pierre-Yves David
Date April 16, 2013, 1:44 p.m.
Message ID <36fe662305fa1ec8a34c.1366119895@crater2.logilab.fr>
Download mbox | patch
Permalink /patch/1347/
State Accepted
Commit efef056b1ae9c9d71cad6b99da455595eb349b1d
Headers show

Comments

Pierre-Yves David - April 16, 2013, 1:44 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@logilab.fr>
# Date 1366118193 -7200
#      Tue Apr 16 15:16:33 2013 +0200
# Node ID 36fe662305fa1ec8a34c14e550f76afb47577455
# Parent  8c0a7eeda06d2773ec92b14527280db3e0167588
obsolete: extract foreground computation from bookmark.validdest

This foreground logic will be reused by update logic.

Patch

diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
--- a/mercurial/bookmarks.py
+++ b/mercurial/bookmarks.py
@@ -290,21 +290,9 @@  def validdest(repo, old, new):
     elif not old:
         # old is nullrev, anything is valid.
         # (new != nullrev has been excluded by the previous check)
         return True
     elif repo.obsstore:
-        # We only need this complicated logic if there is obsolescence
-        # XXX will probably deserve an optimised revset.
-        nm = repo.changelog.nodemap
-        validdests = set([old])
-        plen = -1
-        # compute the whole set of successors or descendants
-        while len(validdests) != plen:
-            plen = len(validdests)
-            succs = set(c.node() for c in validdests)
-            mutable = [c.node() for c in validdests if c.mutable()]
-            succs.update(obsolete.allsuccessors(repo.obsstore, mutable))
-            known = (n for n in succs if n in nm)
-            validdests = set(repo.set('%ln::', known))
-        return new in validdests
+        return new.node() in obsolete.foreground(repo, [old.node()])
     else:
+        # still an independant clause as it is lazyer (and therefore faster)
         return old.descendant(new)
diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -401,10 +401,37 @@  def allsuccessors(obsstore, nodes, ignor
             for suc in mark[1]:
                 if suc not in seen:
                     seen.add(suc)
                     remaining.add(suc)
 
+def foreground(repo, nodes):
+    """return all nodes in the "foreground" of other node
+
+    The foreground of a revision is anything reachable using parent -> children
+    or precursor -> sucessor relation. It is very similars to "descendant" but
+    augmented with obsolescence information.
+
+    Beware that possible obsolescence cycle may result if complexe situation.
+    """
+    repo = repo.unfiltered()
+    foreground = set(repo.set('%ln::', nodes))
+    if repo.obsstore:
+        # We only need this complicated logic if there is obsolescence
+        # XXX will probably deserve an optimised revset.
+        nm = repo.changelog.nodemap
+        plen = -1
+        # compute the whole set of successors or descendants
+        while len(foreground) != plen:
+            plen = len(foreground)
+            succs = set(c.node() for c in foreground)
+            mutable = [c.node() for c in foreground if c.mutable()]
+            succs.update(allsuccessors(repo.obsstore, mutable))
+            known = (n for n in succs if n in nm)
+            foreground = set(repo.set('%ln::', known))
+    return set(c.node() for c in foreground)
+
+
 def successorssets(repo, initialnode, cache=None):
     """Return all set of successors of initial nodes
 
     Successors set of changeset A are a group of revision that succeed A. It
     succeed A as a consistent whole, each revision being only partial