#!/usr/bin/env python3 ''' Author: sp4ke Email: contact@honeybadger.systems Github: https://github.com/sp4ke Description: run cargo commands on a remote workstation/server ''' import argparse from invoke.exceptions import UnexpectedExit from fabric import Connection import sys from pathlib import Path import shutil import sys import os CARGO_BIN_PATH='~/.cargo/bin/' DEPS = [ 'rsync' ] ERR_CMD = 1 ERR_DEPENDENCY = 2 #TODO: binary and package names might differ: use `cargo install --list to extract bin name` def inst_get_binary(conn, package): find_bin = f'cargo install --list {package} | grep -A1 {package} | tail -n1 | awk \'{{print $1}}\'' bin_name = '' try: res = conn.run(find_bin, warn=True) if len(res.stdout) == 0: raise ValueError bin_name = res.stdout.strip() except Exception as e: raise e bin_path = Path(CARGO_BIN_PATH, bin_name).expanduser() local_path = Path(CARGO_BIN_PATH).expanduser().__str__()+'/' try: get_remote_bin = conn.get(bin_path, local=local_path) except FileNotFoundError as e: print('could not copy installed package {} from remote'.format(package)) print('installed {} at {}'.format(package, CARGO_BIN_PATH)) def install(args): package = args.package conn = Connection(args.host) cargo_install = conn.run('cargo install {}'.format(package), warn=True, echo=True) print('{}'.format(cargo_install.stdout.strip())) if cargo_install.failed: print(cargo_install.stderr) sys.exit(ERR_CMD) inst_get_binary(conn, package) def ensure_deps(): for dep in DEPS: installed = shutil.which(dep) if installed is None: print('{} dependency missing'.format(dep), file=sys.stderr) sys.exit(ERR_DEPENDENCY) # def any_cmd(args): # conn = Connection(args.host) # run = conn.run(f'cargo {args.command}', echo=True) if __name__ == '__main__': ensure_deps() default_host = os.environ.get('RCARGO_HOST', 'localhost') parser = argparse.ArgumentParser(description='remote rust cargo commands') parser.add_argument('-H', '--host', default=default_host) #TODO: use a dynamic positional argument, we can pass anything to cargo #TODO: it will be tried on the remote cargo and raise error if it does #TODO: not exist. To do special handling (like install) just watch the #TODO: argument value subparsers = parser.add_subparsers(dest='command') install_parser = subparsers.add_parser('install', help='install packages from crates.io with remote build') install_parser.set_defaults(func=install) install_parser.add_argument('package', help='package name', metavar='PACKAGE_NAME') build = subparsers.add_parser('build', help='remote build local cargo package') args = parser.parse_args() if args.host == 'localhost': print('you need to define a host with -H option or RCARGO_HOST env variable') sys.exit(1) if args.command is not None: args.func(args) else: parser.print_help()