Mercurial > hg
changeset 36530:bde0bd50f368
debugcommands: allow sending of simple commands with debugwireproto
Previously, we only had support for low-level "raw" operations.
A goal of `hg debugwireproto` is to allow easily performing
higher-level primitives, such as sending a wire protocol command
and reading its response.
We implement a "command" action that does just this.
Currently, we only support simple commands (those without payloads).
We have basic support for sending command arguments. We don't yet
support sending dictionary arguments. This will be implemented later.
To prove it works, we add tests to test-ssh-proto.t that send some
"listkeys" commands.
Note: we don't observe/report os.read() events because these may not be
deterministic. We instead observe/report the read() and readline()
operations on the bufferedinputpipe. These *should* be deterministic.
Differential Revision: https://phab.mercurial-scm.org/D2406
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 01 Mar 2018 08:27:30 -0800 |
parents | 33c6f8f0388d |
children | 097ad1079192 |
files | mercurial/debugcommands.py tests/test-ssh-proto.t |
diffstat | 2 files changed, 616 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/debugcommands.py Fri Feb 23 09:40:12 2018 -0800 +++ b/mercurial/debugcommands.py Thu Mar 01 08:27:30 2018 -0800 @@ -2614,6 +2614,21 @@ Behaves like ``raw`` except flushes output afterwards. + command <X> + ----------- + + Send a request to run a named command, whose name follows the ``command`` + string. + + Arguments to the command are defined as lines in this block. The format of + each line is ``<key> <value>``. e.g.:: + + command listkeys + namespace bookmarks + + Values are interpreted as Python b'' literals. This allows encoding + special byte sequences via backslash escaping. + close ----- @@ -2713,6 +2728,29 @@ stdin.flush() elif action == 'flush': stdin.flush() + elif action.startswith('command'): + if not peer: + raise error.Abort(_('cannot send commands unless peer instance ' + 'is available')) + + command = action.split(' ', 1)[1] + + args = {} + for line in lines: + # We need to allow empty values. + fields = line.lstrip().split(' ', 1) + if len(fields) == 1: + key = fields[0] + value = '' + else: + key, value = fields + + args[key] = util.unescapestr(value) + + ui.status(_('sending %s command\n') % command) + res = peer._call(command, **args) + ui.status(_('response: %s\n') % util.escapedata(res)) + elif action == 'close': peer.close() elif action == 'readavailable':
--- a/tests/test-ssh-proto.t Fri Feb 23 09:40:12 2018 -0800 +++ b/tests/test-ssh-proto.t Thu Mar 01 08:27:30 2018 -0800 @@ -1,3 +1,23 @@ + $ cat > hgrc-sshv2 << EOF + > %include $HGRCPATH + > [experimental] + > sshpeer.advertise-v2 = true + > sshserver.support-v2 = true + > EOF + +Helper function to run protocol tests against multiple protocol versions. +This is easier than using #testcases because managing differences between +protocols with inline conditional output is hard to read. + + $ debugwireproto() { + > commands=`cat -` + > echo 'testing ssh1' + > echo "${commands}" | hg --verbose debugwireproto --localssh + > echo "" + > echo 'testing ssh2' + > echo "${commands}" | HGRCPATH=$TESTTMP/hgrc-sshv2 hg --verbose debugwireproto --localssh + > } + $ cat >> $HGRCPATH << EOF > [ui] > ssh = $PYTHON "$TESTDIR/dummyssh" @@ -1252,3 +1272,561 @@ e> read(-1) -> 49: e> malformed handshake protocol: missing pairs 81\n e> -\n + + $ cd .. + +Test listkeys for listing namespaces + + $ hg init empty + $ cd empty + $ debugwireproto << EOF + > command listkeys + > namespace namespaces + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(13) -> None: + i> namespace 10\n + i> write(10) -> None: namespaces + i> flush() -> None + o> bufferedreadline() -> 3: + o> 30\n + o> bufferedread(30) -> 30: + o> bookmarks \n + o> namespaces \n + o> phases + response: bookmarks \nnamespaces \nphases + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(13) -> None: + i> namespace 10\n + i> write(10) -> None: namespaces + i> flush() -> None + o> bufferedreadline() -> 3: + o> 30\n + o> bufferedread(30) -> 30: + o> bookmarks \n + o> namespaces \n + o> phases + response: bookmarks \nnamespaces \nphases + + $ cd .. + +Test listkeys for bookmarks + + $ hg init bookmarkrepo + $ cd bookmarkrepo + $ echo 0 > foo + $ hg add foo + $ hg -q commit -m initial + $ echo 1 > foo + $ hg commit -m second + +With no bookmarks set + + $ debugwireproto << EOF + > command listkeys + > namespace bookmarks + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 9\n + i> write(9) -> None: bookmarks + i> flush() -> None + o> bufferedreadline() -> 2: + o> 0\n + response: + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 9\n + i> write(9) -> None: bookmarks + i> flush() -> None + o> bufferedreadline() -> 2: + o> 0\n + response: + +With a single bookmark set + + $ hg book -r 0 bookA + $ debugwireproto << EOF + > command listkeys + > namespace bookmarks + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 9\n + i> write(9) -> None: bookmarks + i> flush() -> None + o> bufferedreadline() -> 3: + o> 46\n + o> bufferedread(46) -> 46: bookA 68986213bd4485ea51533535e3fc9e78007a711f + response: bookA 68986213bd4485ea51533535e3fc9e78007a711f + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 9\n + i> write(9) -> None: bookmarks + i> flush() -> None + o> bufferedreadline() -> 3: + o> 46\n + o> bufferedread(46) -> 46: bookA 68986213bd4485ea51533535e3fc9e78007a711f + response: bookA 68986213bd4485ea51533535e3fc9e78007a711f + +With multiple bookmarks set + + $ hg book -r 1 bookB + $ debugwireproto << EOF + > command listkeys + > namespace bookmarks + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 9\n + i> write(9) -> None: bookmarks + i> flush() -> None + o> bufferedreadline() -> 3: + o> 93\n + o> bufferedread(93) -> 93: + o> bookA 68986213bd4485ea51533535e3fc9e78007a711f\n + o> bookB 1880f3755e2e52e3199e0ee5638128b08642f34d + response: bookA 68986213bd4485ea51533535e3fc9e78007a711f\nbookB 1880f3755e2e52e3199e0ee5638128b08642f34d + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 9\n + i> write(9) -> None: bookmarks + i> flush() -> None + o> bufferedreadline() -> 3: + o> 93\n + o> bufferedread(93) -> 93: + o> bookA 68986213bd4485ea51533535e3fc9e78007a711f\n + o> bookB 1880f3755e2e52e3199e0ee5638128b08642f34d + response: bookA 68986213bd4485ea51533535e3fc9e78007a711f\nbookB 1880f3755e2e52e3199e0ee5638128b08642f34d + + $ cd .. + +Test listkeys for phases + + $ hg init phasesrepo + $ cd phasesrepo + +Phases on empty repo + + $ debugwireproto << EOF + > command listkeys + > namespace phases + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 3: + o> 15\n + o> bufferedread(15) -> 15: publishing True + response: publishing True + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 3: + o> 15\n + o> bufferedread(15) -> 15: publishing True + response: publishing True + +Create some commits + + $ echo 0 > foo + $ hg add foo + $ hg -q commit -m initial + $ hg phase --public + $ echo 1 > foo + $ hg commit -m 'head 1 commit 1' + $ echo 2 > foo + $ hg commit -m 'head 1 commit 2' + $ hg -q up 0 + $ echo 1a > foo + $ hg commit -m 'head 2 commit 1' + created new head + $ echo 2a > foo + $ hg commit -m 'head 2 commit 2' + +Two draft heads + + $ debugwireproto << EOF + > command listkeys + > namespace phases + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 4: + o> 101\n + o> bufferedread(101) -> 101: + o> 20b8a89289d80036e6c4e87c2083e3bea1586637 1\n + o> c4750011d906c18ea2f0527419cbc1a544435150 1\n + o> publishing True + response: 20b8a89289d80036e6c4e87c2083e3bea1586637 1\nc4750011d906c18ea2f0527419cbc1a544435150 1\npublishing True + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 4: + o> 101\n + o> bufferedread(101) -> 101: + o> 20b8a89289d80036e6c4e87c2083e3bea1586637 1\n + o> c4750011d906c18ea2f0527419cbc1a544435150 1\n + o> publishing True + response: 20b8a89289d80036e6c4e87c2083e3bea1586637 1\nc4750011d906c18ea2f0527419cbc1a544435150 1\npublishing True + +Single draft head + + $ hg phase --public -r 2 + $ debugwireproto << EOF + > command listkeys + > namespace phases + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 3: + o> 58\n + o> bufferedread(58) -> 58: + o> c4750011d906c18ea2f0527419cbc1a544435150 1\n + o> publishing True + response: c4750011d906c18ea2f0527419cbc1a544435150 1\npublishing True + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 3: + o> 58\n + o> bufferedread(58) -> 58: + o> c4750011d906c18ea2f0527419cbc1a544435150 1\n + o> publishing True + response: c4750011d906c18ea2f0527419cbc1a544435150 1\npublishing True + +All public heads + + $ hg phase --public -r 4 + $ debugwireproto << EOF + > command listkeys + > namespace phases + > EOF + testing ssh1 + creating ssh peer from handshake results + i> write(104) -> None: + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 4: + o> 384\n + o> readline() -> 384: + o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n + o> readline() -> 2: + o> 1\n + o> readline() -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 3: + o> 15\n + o> bufferedread(15) -> 15: publishing True + response: publishing True + + testing ssh2 + creating ssh peer from handshake results + i> write(171) -> None: + i> upgrade * proto=exp-ssh-v2-0001\n (glob) + i> hello\n + i> between\n + i> pairs 81\n + i> 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 + i> flush() -> None + o> readline() -> 62: + o> upgraded * exp-ssh-v2-0001\n (glob) + o> readline() -> 4: + o> 383\n + o> read(383) -> 383: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN + o> read(1) -> 1: + o> \n + sending listkeys command + i> write(9) -> None: + i> listkeys\n + i> write(12) -> None: + i> namespace 6\n + i> write(6) -> None: phases + i> flush() -> None + o> bufferedreadline() -> 3: + o> 15\n + o> bufferedread(15) -> 15: publishing True + response: publishing True