hgext/narrow/narrowbundle2.py
changeset 43242 561f9bc4b4c5
parent 43115 4aa72cdf616f
child 43243 e94f457998d3
--- a/hgext/narrow/narrowbundle2.py	Fri Oct 11 22:02:44 2019 -0700
+++ b/hgext/narrow/narrowbundle2.py	Thu Oct 10 22:18:35 2019 -0700
@@ -184,6 +184,105 @@
             part.addparam(b'treemanifest', b'1')
 
 
+def generate_ellipses_bundle2_for_widening(
+    bundler,
+    repo,
+    oldinclude,
+    oldexclude,
+    newinclude,
+    newexclude,
+    version,
+    common,
+    heads,
+    known,
+    depth,
+):
+    newmatch = narrowspec.match(
+        repo.root, include=newinclude, exclude=newexclude
+    )
+    if depth is not None:
+        depth = int(depth)
+        if depth < 1:
+            raise error.Abort(_(b'depth must be positive, got %d') % depth)
+
+    heads = set(heads or repo.heads())
+    common = set(common or [nullid])
+    if known and (oldinclude != newinclude or oldexclude != newexclude):
+        # Steps:
+        # 1. Send kill for "$known & ::common"
+        #
+        # 2. Send changegroup for ::common
+        #
+        # 3. Proceed.
+        #
+        # In the future, we can send kills for only the specific
+        # nodes we know should go away or change shape, and then
+        # send a data stream that tells the client something like this:
+        #
+        # a) apply this changegroup
+        # b) apply nodes XXX, YYY, ZZZ that you already have
+        # c) goto a
+        #
+        # until they've built up the full new state.
+        # Convert to revnums and intersect with "common". The client should
+        # have made it a subset of "common" already, but let's be safe.
+        known = set(repo.revs(b"%ln & ::%ln", known, common))
+        # TODO: we could send only roots() of this set, and the
+        # list of nodes in common, and the client could work out
+        # what to strip, instead of us explicitly sending every
+        # single node.
+        deadrevs = known
+
+        def genkills():
+            for r in deadrevs:
+                yield _KILLNODESIGNAL
+                yield repo.changelog.node(r)
+            yield _DONESIGNAL
+
+        bundler.newpart(_CHANGESPECPART, data=genkills())
+        newvisit, newfull, newellipsis = exchange._computeellipsis(
+            repo, set(), common, known, newmatch
+        )
+        if newvisit:
+            packer = changegroup.getbundler(
+                version,
+                repo,
+                matcher=newmatch,
+                ellipses=True,
+                shallow=depth is not None,
+                ellipsisroots=newellipsis,
+                fullnodes=newfull,
+            )
+            cgdata = packer.generate(common, newvisit, False, b'narrow_widen')
+
+            part = bundler.newpart(b'changegroup', data=cgdata)
+            part.addparam(b'version', version)
+            if b'treemanifest' in repo.requirements:
+                part.addparam(b'treemanifest', b'1')
+
+    visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
+        repo, common, heads, set(), newmatch, depth=depth
+    )
+
+    repo.ui.debug(b'Found %d relevant revs\n' % len(relevant_nodes))
+    if visitnodes:
+        packer = changegroup.getbundler(
+            version,
+            repo,
+            matcher=newmatch,
+            ellipses=True,
+            shallow=depth is not None,
+            ellipsisroots=ellipsisroots,
+            fullnodes=relevant_nodes,
+        )
+        cgdata = packer.generate(common, visitnodes, False, b'narrow_widen')
+
+        part = bundler.newpart(b'changegroup', data=cgdata)
+        part.addparam(b'version', version)
+        if b'treemanifest' in repo.requirements:
+            part.addparam(b'treemanifest', b'1')
+
+
 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
 def _handlechangespec_2(op, inpart):
     # XXX: This bundle2 handling is buggy and should be removed after hg5.2 is