Merge #126: Add option to enter commands over stdin

49bc7fa Add tests for stdin interface and travis job (Andrew Chow)
0185391 Add --stdin to enter commands and arguments over stdin (Andrew Chow)

Pull request description:

  This PR adds a `--stdin` option which allows arguments to be entered over stdin in a way similar to bitcoin-cli's `--stdin` option.

  Built on #125 and to test the `stdin` interface

Tree-SHA512: 48e04298b3537ac59523e40fab3e1709d2ec4ca50284b0bcbbe9062f284bcfbf0cbc4492bd5b8fa673be35375fe8d9436d4aaec0a304b574ba411ee0fb284c0d
This commit is contained in:
Andrew Chow 2019-03-14 15:00:09 -04:00
commit 0dd2e86394
No known key found for this signature in database
GPG Key ID: 17565732E08E5E41
6 changed files with 37 additions and 3 deletions

View File

@ -55,6 +55,8 @@ jobs:
script: cd test; poetry run ./run_tests.py --interface=library
- name: With command line interface
script: cd test; poetry run ./run_tests.py --interface=cli
- name: With stdin interface
script: cd test; ./run_tests.py --interface=stdin
- name: With linux binary distribution command line interface
services: docker
before_script:

View File

@ -58,7 +58,7 @@ def prompt_pin_handler(args, client):
def send_pin_handler(args, client):
return send_pin(client, pin=args.pin)
def process_commands(args):
def process_commands(cli_args):
parser = argparse.ArgumentParser(description='Hardware Wallet Interface, version {}.\nAccess and send commands to a hardware wallet device. Responses are in JSON format.'.format(__version__), formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--device-path', '-d', help='Specify the device path of the device to connect to')
parser.add_argument('--device-type', '-t', help='Specify the type of device that will be connected. If `--device-path` not given, the first device of this type enumerated is used.')
@ -68,6 +68,7 @@ def process_commands(args):
parser.add_argument('--debug', help='Print debug statements', action='store_true')
parser.add_argument('--fingerprint', '-f', help='Specify the device to connect to using the first 4 bytes of the hash160 of the master public key. It will connect to the first device that matches this fingerprint.')
parser.add_argument('--version', action='version', version='%(prog)s {}'.format(__version__))
parser.add_argument('--stdin', help='Enter commands and arguments via stdin', action='store_true')
subparsers = parser.add_subparsers(description='Commands', dest='command')
# work-around to make subparser required
@ -135,7 +136,23 @@ def process_commands(args):
sendpin_parser.add_argument('pin', help='The numeric positions of the PIN')
sendpin_parser.set_defaults(func=send_pin_handler)
args = parser.parse_args(args)
if any(arg == '--stdin' for arg in cli_args):
blank_count = 0
while True:
try:
line = input()
# Exit loop when we see 2 consecutive newlines (i.e. an empty line)
if line == '':
break
# Split the line and append it to the cli args
import shlex
cli_args.extend(shlex.split(line))
except EOFError:
# If we see EOF, stop taking input
break
# Parse arguments again for anything entered over stdin
args = parser.parse_args(cli_args)
device_path = args.device_path
device_type = args.device_type

View File

@ -32,7 +32,7 @@ dbb_group.add_argument('--no_bitbox', help='Do not run Digital Bitbox test with
dbb_group.add_argument('--bitbox', help='Path to Digital bitbox simulator.', default='work/mcu/build/bin/simulator')
parser.add_argument('--bitcoind', help='Path to bitcoind.', default='work/bitcoin/src/bitcoind')
parser.add_argument('--interface', help='Which interface to send commands over', choices=['library', 'cli', 'bindist'], default='library')
parser.add_argument('--interface', help='Which interface to send commands over', choices=['library', 'cli', 'bindist', 'stdin'], default='library')
args = parser.parse_args()
# Run tests

View File

@ -87,6 +87,11 @@ class DeviceTestCase(unittest.TestCase):
proc = subprocess.Popen(['../dist/hwi ' + ' '.join(args)], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True)
result = proc.communicate()
return json.loads(result[0].decode())
elif self.interface == 'stdin':
input_str = '\n'.join(args) + '\n'
proc = subprocess.Popen(['hwi', '--stdin'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
result = proc.communicate(input_str.encode())
return json.loads(result[0].decode())
else:
return process_commands(args)

View File

@ -90,6 +90,11 @@ class KeepkeyTestCase(unittest.TestCase):
proc = subprocess.Popen(['../dist/hwi ' + ' '.join(args)], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True)
result = proc.communicate()
return json.loads(result[0].decode())
elif self.interface == 'stdin':
input_str = '\n'.join(args) + '\n'
proc = subprocess.Popen(['hwi', '--stdin'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
result = proc.communicate(input_str.encode())
return json.loads(result[0].decode())
else:
return process_commands(args)

View File

@ -90,6 +90,11 @@ class TrezorTestCase(unittest.TestCase):
proc = subprocess.Popen(['../dist/hwi ' + ' '.join(args)], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True)
result = proc.communicate()
return json.loads(result[0].decode())
elif self.interface == 'stdin':
input_str = '\n'.join(args) + '\n'
proc = subprocess.Popen(['hwi', '--stdin'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
result = proc.communicate(input_str.encode())
return json.loads(result[0].decode())
else:
return process_commands(args)