comparison 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
comparison
equal deleted inserted replaced
6547:d13cfd9eb6c0 6548:445240ccb701
1 # topic/server.py - server specific behavior with topic 1 # topic/server.py - server specific behavior with topic
2 # 2 #
3 # This software may be used and distributed according to the terms of the 3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version. 4 # GNU General Public License version 2 or any later version.
5 from mercurial.i18n import _
6
5 from mercurial import ( 7 from mercurial import (
6 branchmap, 8 branchmap,
9 error,
7 extensions, 10 extensions,
11 localrepo,
8 repoview, 12 repoview,
9 wireprototypes, 13 wireprototypes,
10 wireprotov1peer, 14 wireprotov1peer,
11 wireprotov1server, 15 wireprotov1server,
12 ) 16 )
56 def topicheads(repo, proto): 60 def topicheads(repo, proto):
57 """Same as the normal wireprotocol command, but accessing with a different end point.""" 61 """Same as the normal wireprotocol command, but accessing with a different end point."""
58 h = repo.heads() 62 h = repo.heads()
59 return wireprototypes.bytesresponse(wireprototypes.encodelist(h) + b'\n') 63 return wireprototypes.bytesresponse(wireprototypes.encodelist(h) + b'\n')
60 64
65 def tns_heads(repo, proto, namespaces):
66 """wireprotocol command to filter heads based on topic namespaces"""
67 if not common.hastopicext(repo):
68 return topicheads(repo, proto)
69
70 namespaces = wireprototypes.decodelist(namespaces)
71 if b'*' in namespaces:
72 # pulling all topic namespaces, all changesets are visible
73 h = repo.heads()
74 else:
75 # only changesets in the selected topic namespaces are visible
76 h = []
77 for branch, nodes in repo.branchmaptns().items():
78 namedbranch, tns, topic = common.parsefqbn(branch)
79 if tns == b'none' or tns in namespaces:
80 h.extend(nodes)
81 return wireprototypes.bytesresponse(wireprototypes.encodelist(h) + b'\n')
82
61 def wireprotocaps(orig, repo, proto): 83 def wireprotocaps(orig, repo, proto):
62 """advertise the new topic specific `head` command for client with topic""" 84 """advertise the new topic specific `head` command for client with topic"""
63 caps = orig(repo, proto) 85 caps = orig(repo, proto)
64 if common.hastopicext(repo) and repo.peer().capable(b'topics'): 86 if common.hastopicext(repo) and repo.peer().capable(b'topics'):
65 caps.append(b'_exttopics_heads') 87 caps.append(b'_exttopics_heads')
68 elif repo.ui.configbool(b'experimental', b'topic.publish-bare-branch'): 90 elif repo.ui.configbool(b'experimental', b'topic.publish-bare-branch'):
69 mode = b'auto' 91 mode = b'auto'
70 else: 92 else:
71 mode = b'none' 93 mode = b'none'
72 caps.append(b'ext-topics-publish=%s' % mode) 94 caps.append(b'ext-topics-publish=%s' % mode)
95 caps.append(b'ext-topics-tns-heads')
73 return caps 96 return caps
74 97
75 def setupserver(ui): 98 def setupserver(ui):
76 extensions.wrapfunction(wireprotov1server, 'heads', wrapheads) 99 extensions.wrapfunction(wireprotov1server, 'heads', wrapheads)
77 wireprotov1server.commands.pop(b'heads') 100 wireprotov1server.commands.pop(b'heads')
78 wireprotov1server.wireprotocommand(b'heads', permission=b'pull')(wireprotov1server.heads) 101 wireprotov1server.wireprotocommand(b'heads', permission=b'pull')(wireprotov1server.heads)
79 wireprotov1server.wireprotocommand(b'_exttopics_heads', permission=b'pull')(topicheads) 102 wireprotov1server.wireprotocommand(b'_exttopics_heads', permission=b'pull')(topicheads)
103 wireprotov1server.wireprotocommand(b'tns_heads', b'namespaces', permission=b'pull')(tns_heads)
80 extensions.wrapfunction(wireprotov1server, '_capabilities', wireprotocaps) 104 extensions.wrapfunction(wireprotov1server, '_capabilities', wireprotocaps)
105
106 class tnspeer(wireprotov1peer.wirepeer):
107 @wireprotov1peer.batchable
108 def tns_heads(self, namespaces):
109 def decode(d):
110 try:
111 return wireprototypes.decodelist(d[:-1])
112 except ValueError:
113 self._abort(error.ResponseError(_(b"unexpected response:"), d))
114
115 return {b'namespaces': wireprototypes.encodelist(namespaces)}, decode
116
117 wireprotov1peer.wirepeer = tnspeer
81 118
82 class topicpeerexecutor(wireprotov1peer.peerexecutor): 119 class topicpeerexecutor(wireprotov1peer.peerexecutor):
83 120
84 def callcommand(self, command, args): 121 def callcommand(self, command, args):
85 if command == b'heads': 122 if command == b'heads':
86 if self._peer.capable(b'_exttopics_heads'): 123 if self._peer.capable(b'ext-topics-tns-heads'):
124 command = b'tns_heads'
125 args[b'namespaces'] = self._peer.ui.configlist(b'experimental', b'tns-default-pull-namespaces', [b'*'])
126 elif self._peer.capable(b'_exttopics_heads'):
87 command = b'_exttopics_heads' 127 command = b'_exttopics_heads'
88 if getattr(self._peer, '_exttopics_heads', None) is None: 128 if getattr(self._peer, '_exttopics_heads', None) is None:
89 self._peer._exttopics_heads = self._peer.heads 129 self._peer._exttopics_heads = self._peer.heads
90 s = super(topicpeerexecutor, self) 130 s = super(topicpeerexecutor, self)
91 return s.callcommand(command, args) 131 return s.callcommand(command, args)
92 132
93 wireprotov1peer.peerexecutor = topicpeerexecutor 133 wireprotov1peer.peerexecutor = topicpeerexecutor
94 134
135 class topiccommandexecutor(localrepo.localcommandexecutor):
136 def callcommand(self, command, args):
137 if command == b'heads':
138 if self._peer.capable(b'ext-topics-tns-heads'):
139 command = b'tns_heads'
140 args[b'namespaces'] = self._peer.ui.configlist(b'experimental', b'tns-default-pull-namespaces', [b'*'])
141 s = super(topiccommandexecutor, self)
142 return s.callcommand(command, args)
143
144 localrepo.localcommandexecutor = topiccommandexecutor
145
95 if FILTERNAME not in repoview.filtertable: 146 if FILTERNAME not in repoview.filtertable:
96 repoview.filtertable[FILTERNAME] = computeunservedtopic 147 repoview.filtertable[FILTERNAME] = computeunservedtopic
97 # hg <= 4.9 (caebe5e7f4bd) 148 # hg <= 4.9 (caebe5e7f4bd)
98 branchmap.subsettable[FILTERNAME] = b'immutable' 149 branchmap.subsettable[FILTERNAME] = b'immutable'
99 branchmap.subsettable[b'served'] = FILTERNAME 150 branchmap.subsettable[b'served'] = FILTERNAME