diff hgext3rd/topic/server.py @ 6548:445240ccb701

topic: add experimental.tns-default-pull-namespaces config option This config option controls what topic namespaces get pulled by default. The current default option is '*', which means all namespaces get pulled.
author Anton Shestakov <av6@dwimlabs.net>
date Thu, 27 Jul 2023 16:39:43 -0300
parents a87abe69a2f8
children 2d3771d61068
line wrap: on
line diff
--- a/hgext3rd/topic/server.py	Wed Aug 30 15:08:35 2023 -0300
+++ b/hgext3rd/topic/server.py	Thu Jul 27 16:39:43 2023 -0300
@@ -2,9 +2,13 @@
 #
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
+from mercurial.i18n import _
+
 from mercurial import (
     branchmap,
+    error,
     extensions,
+    localrepo,
     repoview,
     wireprototypes,
     wireprotov1peer,
@@ -58,6 +62,24 @@
     h = repo.heads()
     return wireprototypes.bytesresponse(wireprototypes.encodelist(h) + b'\n')
 
+def tns_heads(repo, proto, namespaces):
+    """wireprotocol command to filter heads based on topic namespaces"""
+    if not common.hastopicext(repo):
+        return topicheads(repo, proto)
+
+    namespaces = wireprototypes.decodelist(namespaces)
+    if b'*' in namespaces:
+        # pulling all topic namespaces, all changesets are visible
+        h = repo.heads()
+    else:
+        # only changesets in the selected topic namespaces are visible
+        h = []
+        for branch, nodes in repo.branchmaptns().items():
+            namedbranch, tns, topic = common.parsefqbn(branch)
+            if tns == b'none' or tns in namespaces:
+                h.extend(nodes)
+    return wireprototypes.bytesresponse(wireprototypes.encodelist(h) + b'\n')
+
 def wireprotocaps(orig, repo, proto):
     """advertise the new topic specific `head` command for client with topic"""
     caps = orig(repo, proto)
@@ -70,6 +92,7 @@
         else:
             mode = b'none'
         caps.append(b'ext-topics-publish=%s' % mode)
+        caps.append(b'ext-topics-tns-heads')
     return caps
 
 def setupserver(ui):
@@ -77,13 +100,30 @@
     wireprotov1server.commands.pop(b'heads')
     wireprotov1server.wireprotocommand(b'heads', permission=b'pull')(wireprotov1server.heads)
     wireprotov1server.wireprotocommand(b'_exttopics_heads', permission=b'pull')(topicheads)
+    wireprotov1server.wireprotocommand(b'tns_heads', b'namespaces', permission=b'pull')(tns_heads)
     extensions.wrapfunction(wireprotov1server, '_capabilities', wireprotocaps)
 
+    class tnspeer(wireprotov1peer.wirepeer):
+        @wireprotov1peer.batchable
+        def tns_heads(self, namespaces):
+            def decode(d):
+                try:
+                    return wireprototypes.decodelist(d[:-1])
+                except ValueError:
+                    self._abort(error.ResponseError(_(b"unexpected response:"), d))
+
+            return {b'namespaces': wireprototypes.encodelist(namespaces)}, decode
+
+    wireprotov1peer.wirepeer = tnspeer
+
     class topicpeerexecutor(wireprotov1peer.peerexecutor):
 
         def callcommand(self, command, args):
             if command == b'heads':
-                if self._peer.capable(b'_exttopics_heads'):
+                if self._peer.capable(b'ext-topics-tns-heads'):
+                    command = b'tns_heads'
+                    args[b'namespaces'] = self._peer.ui.configlist(b'experimental', b'tns-default-pull-namespaces', [b'*'])
+                elif self._peer.capable(b'_exttopics_heads'):
                     command = b'_exttopics_heads'
                     if getattr(self._peer, '_exttopics_heads', None) is None:
                         self._peer._exttopics_heads = self._peer.heads
@@ -92,6 +132,17 @@
 
     wireprotov1peer.peerexecutor = topicpeerexecutor
 
+    class topiccommandexecutor(localrepo.localcommandexecutor):
+        def callcommand(self, command, args):
+            if command == b'heads':
+                if self._peer.capable(b'ext-topics-tns-heads'):
+                    command = b'tns_heads'
+                    args[b'namespaces'] = self._peer.ui.configlist(b'experimental', b'tns-default-pull-namespaces', [b'*'])
+            s = super(topiccommandexecutor, self)
+            return s.callcommand(command, args)
+
+    localrepo.localcommandexecutor = topiccommandexecutor
+
     if FILTERNAME not in repoview.filtertable:
         repoview.filtertable[FILTERNAME] = computeunservedtopic
         # hg <= 4.9 (caebe5e7f4bd)