D3200: wireproto: implement capabilities for wire protocol v2

2018-04-11 Thread indygreg (Gregory Szorc)
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=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

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', 

D3200: wireproto: implement capabilities for wire protocol v2

2018-04-09 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The capabilities mechanism for wire protocol version 2 represents a
  clean break from version 1.
  
  Instead of effectively exchanging a set of capabilities, we're
  exchanging a rich data structure.
  
  This data structure currently contains information about
  every available command, including its accepted arguments. It also
  contains information about supported compression formats.
  
  Exposing information about supported commands will allow clients
  to automatically generate bindings to the server. Clients will be
  able to do things like detect when they are attempting to run a
  command that isn't known to the server. Exposing the required
  permissions to run a command can be used by clients to determine if
  they have privileges to call a command before actually calling it.
  We could potentially even have clients send credentials
  preemptively without waiting for the server to deny the command
  request. Lots of potential here.
  
  The data returned by this command will likely evolve heavily. So we
  shouldn't bikeshed the implementation just yet.

REPOSITORY
  rHG Mercurial

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

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$