diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py --- a/mercurial/httppeer.py +++ b/mercurial/httppeer.py @@ -493,6 +493,15 @@ def _call(self, name, **args): """Call a wire protocol command with arguments.""" + # Having this early has a side-effect of importing wireprotov2server, + # which has the side-effect of ensuring commands are registered. + + # TODO modify user-agent to reflect v2. + headers = { + r'Accept': wireprotov2server.FRAMINGTYPE, + r'Content-Type': wireprotov2server.FRAMINGTYPE, + } + # TODO permissions should come from capabilities results. permission = wireproto.commandsv2[name].permission if permission not in ('push', 'pull'): @@ -507,12 +516,6 @@ url = '%s/api/%s/%s/%s' % (self.url, wireprotov2server.HTTPV2, permission, name) - # TODO modify user-agent to reflect v2. - headers = { - r'Accept': wireprotov2server.FRAMINGTYPE, - r'Content-Type': wireprotov2server.FRAMINGTYPE, - } - # TODO this should be part of a generic peer for the frame-based # protocol. reactor = wireprotoframing.clientreactor(hasmultiplesend=False, diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py --- a/mercurial/wireproto.py +++ b/mercurial/wireproto.py @@ -1305,113 +1305,3 @@ bundler.newpart('error:pushraced', [('message', stringutil.forcebytestr(exc))]) return wireprototypes.streamreslegacy(gen=bundler.getchunks()) - -# Wire protocol version 2 commands only past this point. - -def _capabilitiesv2(repo, proto): - """Obtain the set of capabilities for version 2 transports. - - These capabilities are distinct from the capabilities for version 1 - transports. - """ - compression = [] - for engine in supportedcompengines(repo.ui, util.SERVERROLE): - compression.append({ - b'name': engine.wireprotosupport().name, - }) - - caps = { - 'commands': {}, - 'compression': compression, - } - - for command, entry in commandsv2.items(): - caps['commands'][command] = { - 'args': entry.args, - 'permissions': [entry.permission], - } - - return proto.addcapabilities(repo, caps) - -@wireprotocommand('branchmap', permission='pull', - transportpolicy=POLICY_V2_ONLY) -def branchmapv2(repo, proto): - branchmap = {encoding.fromlocal(k): v - for k, v in repo.branchmap().iteritems()} - - return wireprototypes.cborresponse(branchmap) - -@wireprotocommand('capabilities', permission='pull', - transportpolicy=POLICY_V2_ONLY) -def capabilitiesv2(repo, proto): - caps = _capabilitiesv2(repo, proto) - - return wireprototypes.cborresponse(caps) - -@wireprotocommand('heads', - args={ - 'publiconly': False, - }, - permission='pull', - transportpolicy=POLICY_V2_ONLY) -def headsv2(repo, proto, publiconly=False): - if publiconly: - repo = repo.filtered('immutable') - - return wireprototypes.cborresponse(repo.heads()) - -@wireprotocommand('known', - args={ - 'nodes': [b'deadbeef'], - }, - permission='pull', - transportpolicy=POLICY_V2_ONLY) -def knownv2(repo, proto, nodes=None): - nodes = nodes or [] - result = b''.join(b'1' if n else b'0' for n in repo.known(nodes)) - return wireprototypes.cborresponse(result) - -@wireprotocommand('listkeys', - args={ - 'namespace': b'ns', - }, - permission='pull', - transportpolicy=POLICY_V2_ONLY) -def listkeysv2(repo, proto, namespace=None): - keys = repo.listkeys(encoding.tolocal(namespace)) - keys = {encoding.fromlocal(k): encoding.fromlocal(v) - for k, v in keys.iteritems()} - - return wireprototypes.cborresponse(keys) - -@wireprotocommand('lookup', - args={ - 'key': b'foo', - }, - permission='pull', - transportpolicy=POLICY_V2_ONLY) -def lookupv2(repo, proto, key): - key = encoding.tolocal(key) - - # TODO handle exception. - node = repo.lookup(key) - - return wireprototypes.cborresponse(node) - -@wireprotocommand('pushkey', - args={ - 'namespace': b'ns', - 'key': b'key', - 'old': b'old', - 'new': b'new', - }, - permission='push', - transportpolicy=POLICY_V2_ONLY) -def pushkeyv2(repo, proto, namespace, key, old, new): - # TODO handle ui output redirection - r = repo.pushkey(encoding.tolocal(namespace), - encoding.tolocal(key), - encoding.tolocal(old), - encoding.tolocal(new)) - - return wireprototypes.cborresponse(r) diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py --- a/mercurial/wireprotov2server.py +++ b/mercurial/wireprotov2server.py @@ -16,8 +16,10 @@ interface as zi, ) from . import ( + encoding, error, pycompat, + util, wireproto, wireprotoframing, wireprototypes, @@ -362,3 +364,111 @@ def checkperm(self, perm): raise NotImplementedError + +def _capabilitiesv2(repo, proto): + """Obtain the set of capabilities for version 2 transports. + + These capabilities are distinct from the capabilities for version 1 + transports. + """ + compression = [] + for engine in wireproto.supportedcompengines(repo.ui, util.SERVERROLE): + compression.append({ + b'name': engine.wireprotosupport().name, + }) + + caps = { + 'commands': {}, + 'compression': compression, + } + + for command, entry in wireproto.commandsv2.items(): + caps['commands'][command] = { + 'args': entry.args, + 'permissions': [entry.permission], + } + + return proto.addcapabilities(repo, caps) + +def wireprotocommand(*args, **kwargs): + def register(func): + return wireproto.wireprotocommand( + *args, transportpolicy=wireproto.POLICY_V2_ONLY, **kwargs)(func) + + return register + +@wireprotocommand('branchmap', permission='pull') +def branchmapv2(repo, proto): + branchmap = {encoding.fromlocal(k): v + for k, v in repo.branchmap().iteritems()} + + return wireprototypes.cborresponse(branchmap) + +@wireprotocommand('capabilities', permission='pull') +def capabilitiesv2(repo, proto): + caps = _capabilitiesv2(repo, proto) + + return wireprototypes.cborresponse(caps) + +@wireprotocommand('heads', + args={ + 'publiconly': False, + }, + permission='pull') +def headsv2(repo, proto, publiconly=False): + if publiconly: + repo = repo.filtered('immutable') + + return wireprototypes.cborresponse(repo.heads()) + +@wireprotocommand('known', + args={ + 'nodes': [b'deadbeef'], + }, + permission='pull') +def knownv2(repo, proto, nodes=None): + nodes = nodes or [] + result = b''.join(b'1' if n else b'0' for n in repo.known(nodes)) + return wireprototypes.cborresponse(result) + +@wireprotocommand('listkeys', + args={ + 'namespace': b'ns', + }, + permission='pull') +def listkeysv2(repo, proto, namespace=None): + keys = repo.listkeys(encoding.tolocal(namespace)) + keys = {encoding.fromlocal(k): encoding.fromlocal(v) + for k, v in keys.iteritems()} + + return wireprototypes.cborresponse(keys) + +@wireprotocommand('lookup', + args={ + 'key': b'foo', + }, + permission='pull') +def lookupv2(repo, proto, key): + key = encoding.tolocal(key) + + # TODO handle exception. + node = repo.lookup(key) + + return wireprototypes.cborresponse(node) + +@wireprotocommand('pushkey', + args={ + 'namespace': b'ns', + 'key': b'key', + 'old': b'old', + 'new': b'new', + }, + permission='push') +def pushkeyv2(repo, proto, namespace, key, old, new): + # TODO handle ui output redirection + r = repo.pushkey(encoding.tolocal(namespace), + encoding.tolocal(key), + encoding.tolocal(old), + encoding.tolocal(new)) + + return wireprototypes.cborresponse(r)