changeset 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 5724aaa99dd6
children 4cf60d5894b5
files mercurial/debugcommands.py mercurial/obsutil.py tests/test-completion.t tests/test-obsolete-divergent.t
diffstat 4 files changed, 216 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/debugcommands.py	Fri Jun 30 15:02:19 2017 +0200
+++ b/mercurial/debugcommands.py	Fri Jun 30 15:27:19 2017 +0200
@@ -2067,13 +2067,14 @@
         ui.write((' revision %s\n') % v[1])
 
 @command('debugsuccessorssets',
-    [],
+    [('', 'closest', False, _('return closest successors sets only'))],
     _('[REV]'))
-def debugsuccessorssets(ui, repo, *revs):
+def debugsuccessorssets(ui, repo, *revs, **opts):
     """show set of successors for revision
 
     A successors set of changeset A is a consistent group of revisions that
-    succeed A. It contains non-obsolete changesets only.
+    succeed A. It contains non-obsolete changesets only unless closests
+    successors set is set.
 
     In most cases a changeset A has a single successors set containing a single
     successor (changeset A replaced by A').
@@ -2111,7 +2112,9 @@
     for rev in scmutil.revrange(repo, revs):
         ctx = repo[rev]
         ui.write('%s\n'% ctx2str(ctx))
-        for succsset in obsutil.successorssets(repo, ctx.node(), cache=cache):
+        for succsset in obsutil.successorssets(repo, ctx.node(),
+                                                closest=opts['closest'],
+                                                cache=cache):
             if succsset:
                 ui.write('    ')
                 ui.write(node2str(succsset[0]))
--- 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.
--- a/tests/test-completion.t	Fri Jun 30 15:02:19 2017 +0200
+++ b/tests/test-completion.t	Fri Jun 30 15:27:19 2017 +0200
@@ -284,7 +284,7 @@
   debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
   debugsetparents: 
   debugsub: rev
-  debugsuccessorssets: 
+  debugsuccessorssets: closest
   debugtemplate: rev, define
   debugupdatecaches: 
   debugupgraderepo: optimize, run
--- a/tests/test-obsolete-divergent.t	Fri Jun 30 15:02:19 2017 +0200
+++ b/tests/test-obsolete-divergent.t	Fri Jun 30 15:27:19 2017 +0200
@@ -80,6 +80,23 @@
   $ hg log -r 'divergent()'
   2:82623d38b9ba A_1
   3:392fd25390da A_2
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba
+      392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
 
 check that mercurial refuse to push
 
@@ -128,6 +145,25 @@
   $ hg log -r 'divergent()'
   2:82623d38b9ba A_1
   4:01f36c5a8fda A_3
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  82623d38b9ba
+      82623d38b9ba
+  01f36c5a8fda
+      01f36c5a8fda
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba
+      392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  01f36c5a8fda
+      01f36c5a8fda
   $ cd ..
 
 
@@ -160,6 +196,23 @@
   $ hg log -r 'divergent()'
   2:82623d38b9ba A_1
   3:392fd25390da A_2
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba
+      392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
   $ cd ..
 
 do not take unknown node in account if they are final
@@ -175,6 +228,10 @@
   $ hg debugsuccessorssets --hidden 'desc('A_0')'
   007dc284c1f8
       392fd25390da
+  $ hg debugsuccessorssets 'desc('A_0')' --closest
+  $ hg debugsuccessorssets 'desc('A_0')' --closest --hidden
+  007dc284c1f8
+      82623d38b9ba
 
   $ cd ..
 
@@ -211,6 +268,23 @@
   01f36c5a8fda
       01f36c5a8fda
   $ hg log -r 'divergent()'
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  01f36c5a8fda
+      01f36c5a8fda
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba
+      392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  01f36c5a8fda
+      01f36c5a8fda
   $ cd ..
 
 split is not divergences
@@ -237,6 +311,22 @@
   392fd25390da
       392fd25390da
   $ hg log -r 'divergent()'
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba 392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
 
 Even when subsequent rewriting happen
 
@@ -283,6 +373,28 @@
       e442cfc57690
   e442cfc57690
       e442cfc57690
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  01f36c5a8fda
+      01f36c5a8fda
+  e442cfc57690
+      e442cfc57690
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba 392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  01f36c5a8fda
+      01f36c5a8fda
+  6a411f0d7a0a
+      e442cfc57690
+  e442cfc57690
+      e442cfc57690
   $ hg log -r 'divergent()'
 
 Check more complex obsolescence graft (with divergence)
@@ -352,6 +464,40 @@
       14608b260df8
   bed64f5d2f5a
       bed64f5d2f5a
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  01f36c5a8fda
+      01f36c5a8fda
+  7ae126973a96
+      7ae126973a96
+  14608b260df8
+      14608b260df8
+  bed64f5d2f5a
+      bed64f5d2f5a
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba 392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  01f36c5a8fda
+      01f36c5a8fda
+  6a411f0d7a0a
+      e442cfc57690
+  e442cfc57690
+      e442cfc57690
+  3750ebee865d
+      392fd25390da
+  7ae126973a96
+      7ae126973a96
+  14608b260df8
+      14608b260df8
+  bed64f5d2f5a
+      bed64f5d2f5a
   $ hg log -r 'divergent()'
   4:01f36c5a8fda A_3
   8:7ae126973a96 A_7
@@ -416,6 +562,38 @@
       a139f71be9da
   a139f71be9da
       a139f71be9da
+  $ hg debugsuccessorssets 'all()' --closest
+  d20a80d4def3
+      d20a80d4def3
+  01f36c5a8fda
+      01f36c5a8fda
+  a139f71be9da
+      a139f71be9da
+  $ hg debugsuccessorssets 'all()' --closest --hidden
+  d20a80d4def3
+      d20a80d4def3
+  007dc284c1f8
+      82623d38b9ba 392fd25390da
+  82623d38b9ba
+      82623d38b9ba
+  392fd25390da
+      392fd25390da
+  01f36c5a8fda
+      01f36c5a8fda
+  6a411f0d7a0a
+      e442cfc57690
+  e442cfc57690
+      e442cfc57690
+  3750ebee865d
+      392fd25390da
+  7ae126973a96
+      a139f71be9da
+  14608b260df8
+      a139f71be9da
+  bed64f5d2f5a
+      a139f71be9da
+  a139f71be9da
+      a139f71be9da
   $ hg log -r 'divergent()'
 
   $ cd ..
@@ -433,5 +611,9 @@
   $ hg debugsuccessorssets --hidden 'desc('A_0')'
   007dc284c1f8
       82623d38b9ba 392fd25390da
+  $ hg debugsuccessorssets 'desc('A_0')' --closest
+  $ hg debugsuccessorssets 'desc('A_0')' --closest --hidden
+  007dc284c1f8
+      82623d38b9ba 392fd25390da
 
   $ cd ..