Patchwork D3200: wireproto: implement capabilities for wire protocol v2

login
register
mail settings
Submitter phabricator
Date April 11, 2018, 4:34 p.m.
Message ID <dc79bb0b61b9e4f9ad9abd7fffff5095@localhost.localdomain>
Download mbox | patch
Permalink /patch/30706/
State Not Applicable
Headers show

Comments

phabricator - April 11, 2018, 4:34 p.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHGdf4985497986: wireproto: implement capabilities for wire protocol v2 (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3200?vs=7904&id=7979

REVISION DETAIL
  https://phab.mercurial-scm.org/D3200

AFFECTED FILES
  mercurial/help/internals/wireprotocol.txt
  mercurial/wireproto.py
  mercurial/wireprotoserver.py
  tests/test-ssh-proto.t
  tests/test-wireproto-command-capabilities.t

CHANGE DETAILS




To: indygreg, #hg-reviewers, durin42
Cc: mercurial-devel

Patch

diff --git a/tests/test-wireproto-command-capabilities.t b/tests/test-wireproto-command-capabilities.t
new file mode 100644
--- /dev/null
+++ b/tests/test-wireproto-command-capabilities.t
@@ -0,0 +1,40 @@ 
+  $ . $TESTDIR/wireprotohelpers.sh
+
+  $ hg init server
+  $ enablehttpv2 server
+  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
+  $ cat hg.pid > $DAEMON_PIDS
+
+capabilities request returns an array of capability strings
+
+  $ sendhttpv2peer << EOF
+  > command capabilities
+  > EOF
+  creating http peer for wire protocol version 2
+  sending capabilities command
+  s>     POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
+  s>     Accept-Encoding: identity\r\n
+  s>     accept: application/mercurial-exp-framing-0003\r\n
+  s>     content-type: application/mercurial-exp-framing-0003\r\n
+  s>     content-length: 27\r\n
+  s>     host: $LOCALIP:$HGPORT\r\n (glob)
+  s>     user-agent: Mercurial debugwireproto\r\n
+  s>     \r\n
+  s>     \x13\x00\x00\x01\x00\x01\x01\x11\xa1DnameLcapabilities
+  s> makefile('rb', None)
+  s>     HTTP/1.1 200 OK\r\n
+  s>     Server: testing stub value\r\n
+  s>     Date: $HTTP_DATE$\r\n
+  s>     Content-Type: application/mercurial-exp-framing-0003\r\n
+  s>     Transfer-Encoding: chunked\r\n
+  s>     \r\n
+  s>     *\r\n (glob)
+  s>     *\x00\x01\x00\x02\x01F (glob)
+  s>     \xa2Hcommands\xabEheads\xa2Dargs\x81JpubliconlyKpermissions\x81DpullEknown\xa2Dargs\x81EnodesKpermissions\x81DpullFlookup\xa2Dargs\x81CkeyKpermissions\x81DpullGpushkey\xa2Dargs\x84CkeyInamespaceCnewColdKpermissions\x81DpushHlistkeys\xa2Dargs\x81InamespaceKpermissions\x81DpullHunbundle\xa2Dargs\x81EheadsKpermissions\x81DpushIbranchmap\xa2Dargs\x80Kpermissions\x81DpullIgetbundle\xa2Dargs\x81A*Kpermissions\x81DpullJstream_out\xa2Dargs\x80Kpermissions\x81DpullLcapabilities\xa2Dargs\x80Kpermissions\x81DpullLclonebundles\xa2Dargs\x80Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlib
+  s>     \r\n
+  received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob)
+  s>     0\r\n
+  s>     \r\n
+  response: [{b'commands': {b'branchmap': {b'args': [], b'permissions': [b'pull']}, b'capabilities': {b'args': [], b'permissions': [b'pull']}, b'clonebundles': {b'args': [], b'permissions': [b'pull']}, b'getbundle': {b'args': [b'*'], b'permissions': [b'pull']}, b'heads': {b'args': [b'publiconly'], b'permissions': [b'pull']}, b'known': {b'args': [b'nodes'], b'permissions': [b'pull']}, b'listkeys': {b'args': [b'namespace'], b'permissions': [b'pull']}, b'lookup': {b'args': [b'key'], b'permissions': [b'pull']}, b'pushkey': {b'args': [b'key', b'namespace', b'new', b'old'], b'permissions': [b'push']}, b'stream_out': {b'args': [], b'permissions': [b'pull']}, b'unbundle': {b'args': [b'heads'], b'permissions': [b'push']}}, b'compression': [{b'name': b'zstd'}, {b'name': b'zlib'}]}]
+
+  $ cat error.log
diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t
--- a/tests/test-ssh-proto.t
+++ b/tests/test-ssh-proto.t
@@ -1120,9 +1120,9 @@ 
   i> write(6) -> 6:
   i>     hello\n
   o> readline() -> 4:
-  o>     403\n
-  o> readline() -> 403:
-  o>     capabilities: batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
+  o>     397\n
+  o> readline() -> 397:
+  o>     capabilities: branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
 
 Multiple upgrades is not allowed
 
diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -831,6 +831,9 @@ 
     def name(self):
         return wireprototypes.SSHV2
 
+    def addcapabilities(self, repo, caps):
+        return caps
+
 def _runsshserver(ui, repo, fin, fout, ev):
     # This function operates like a state machine of sorts. The following
     # states are defined:
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -903,7 +903,8 @@ 
 
 # If you are writing an extension and consider wrapping this function. Wrap
 # `_capabilities` instead.
-@wireprotocommand('capabilities', permission='pull')
+@wireprotocommand('capabilities', permission='pull',
+                  transportpolicy=POLICY_V1_ONLY)
 def capabilities(repo, proto):
     caps = _capabilities(repo, proto)
     return wireprototypes.bytesresponse(' '.join(sorted(caps)))
@@ -1283,14 +1284,46 @@ 
 
 # 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': sorted(entry.args.split()) if entry.args else [],
+            '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', permission='pull',
                   transportpolicy=POLICY_V2_ONLY)
 def headsv2(repo, proto, publiconly=False):
diff --git a/mercurial/help/internals/wireprotocol.txt b/mercurial/help/internals/wireprotocol.txt
--- a/mercurial/help/internals/wireprotocol.txt
+++ b/mercurial/help/internals/wireprotocol.txt
@@ -1690,6 +1690,42 @@ 
 The response is a map with bytestring keys defining the branch name.
 Values are arrays of bytestring defining raw changeset nodes.
 
+capabilities
+------------
+
+Obtain the server's capabilities.
+
+Receives no arguments.
+
+This command is typically called only as part of the handshake during
+initial connection establishment.
+
+The response is a map with bytestring keys defining server information.
+
+The defined keys are:
+
+commands
+   A map defining available wire protocol commands on this server.
+
+   Keys in the map are the names of commands that can be invoked. Values
+   are maps defining information about that command. The bytestring keys
+   are:
+
+      args
+         An array of argument names accepted by this command.
+      permissions
+         An array of permissions required to execute this command.
+
+compression
+   An array of maps defining available compression format support.
+
+   The array is sorted from most preferred to least preferred.
+
+   Each entry has the following bytestring keys:
+
+      name
+         Name of the compression engine. e.g. ``zstd`` or ``zlib``.
+
 heads
 -----