diff mercurial/obsutil.py @ 33274:68f3e819d41d

obsolete: closest divergent support Add a closest argument to successorssets changing the definition of latest successors. With "closest=false" (current behavior), latest successors are "leafs" on the obsmarker graph. They don't have any successor and are known locally. With "closest=true", latest successors are the closest locally-known changesets that are visible in the repository or repoview. Closest successors can be then obsolete, orphan. This will be used in a later patch to show the closest successor of changesets with the successorssets template.
author Boris Feld <boris.feld@octobus.net>
date Fri, 30 Jun 2017 15:27:19 +0200
parents df90f4d6c609
children 888f24810ea2
line wrap: on
line diff
--- a/mercurial/obsutil.py	Fri Jun 30 15:02:19 2017 +0200
+++ b/mercurial/obsutil.py	Fri Jun 30 15:27:19 2017 +0200
@@ -311,12 +311,15 @@
             obsoleted.add(rev)
     return obsoleted
 
-def successorssets(repo, initialnode, cache=None):
+def successorssets(repo, initialnode, closest=False, cache=None):
     """Return set of all latest successors of initial nodes
 
     The successors set of a changeset A are the group of revisions that succeed
     A. It succeeds A as a consistent whole, each revision being only a partial
-    replacement. The successors set contains non-obsolete changesets only.
+    replacement. By default, the successors set contains non-obsolete
+    changesets only, walking the obsolescence graph until reaching a leaf. If
+    'closest' is set to True, closest successors-sets are return (the
+    obsolescence walk stops on known changesets).
 
     This function returns the full list of successor sets which is why it
     returns a list of tuples and not just a single tuple. Each tuple is a valid
@@ -342,12 +345,19 @@
     (pruned: obsoleted without any successors). (Final: successors not affected
     by markers).
 
+    The 'closest' mode respect the repoview filtering. For example, without
+    filter it will stop at the first locally known changeset, with 'visible'
+    filter it will stop on visible changesets).
+
     The optional `cache` parameter is a dictionary that may contains
     precomputed successors sets. It is meant to reuse the computation of a
     previous call to `successorssets` when multiple calls are made at the same
     time. The cache dictionary is updated in place. The caller is responsible
     for its life span. Code that makes multiple calls to `successorssets`
     *should* use this cache mechanism or risk a performance hit.
+
+    Since results are different depending of the 'closest' most, the same cache
+    cannot be reused for both mode.
     """
 
     succmarkers = repo.obsstore.successors
@@ -394,8 +404,10 @@
         #
         # 1) We already know the successors sets of CURRENT:
         #    -> mission accomplished, pop it from the stack.
-        # 2) Node is not obsolete:
-        #    -> the node is its own successors sets. Add it to the cache.
+        # 2) Stop the walk:
+        #    default case: Node is not obsolete
+        #    closest case: Node is known at this repo filter level
+        #      -> the node is its own successors sets. Add it to the cache.
         # 3) We do not know successors set of direct successors of CURRENT:
         #    -> We add those successors to the stack.
         # 4) We know successors sets of all direct successors of CURRENT:
@@ -403,13 +415,20 @@
         #       cache.
         #
         current = toproceed[-1]
+
+        # case 2 condition is a bit hairy because of closest,
+        # we compute it on its own
+        case2condition =  ((current not in succmarkers)
+                           or (closest and current != initialnode
+                               and current in repo))
+
         if current in cache:
             # case (1): We already know the successors sets
             stackedset.remove(toproceed.pop())
-        elif current not in succmarkers:
-            # case (2): The node is not obsolete.
+        elif case2condition:
+            # case (2): end of walk.
             if current in repo:
-                # We have a valid last successors.
+                # We have a valid successors.
                 cache[current] = [(current,)]
             else:
                 # Final obsolete version is unknown locally.