You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
3.0 KiB
Python

#!/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()