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.

157 lines
4.9 KiB
Plaintext

2 years ago
#!/usr/bin/env python3
'''
2 years ago
Author: blob42
Email: contact@blob42.xyz
Github: https://github.com/blob42
2 years ago
Description: run cargo commands on a remote workstation/server
'''
2 years ago
2 years ago
2 years ago
import argparse
from invoke.exceptions import UnexpectedExit
from fabric import Connection
import sys
from pathlib import Path
import shutil
import sys
import os
from rich import print
import logging
from rich.logging import RichHandler
LOG_FORMAT = '%(message)s'
logging.basicConfig(
level='WARN', format=LOG_FORMAT, datefmt='[%X]', handlers=[RichHandler(markup=True)]
)
log = logging.getLogger('rcargo')
2 years ago
CARGO_BIN_PATH='~/.cargo/bin/'
LOCAL_BIN_PATH=''
2 years ago
DEPS = [
'rsync'
2 years ago
]
ERR_CMD = 1
ERR_DEPENDENCY = 2
2 years ago
#TODO: binary and package names might differ: use `cargo install --list to extract bin name`
9 months ago
def inst_get_binary(conn: Connection, package: str, debug: bool = False) -> None:
find_bin = f'cargo install --list | grep -A1 {package} | sed -nE "s/ *//; 2 p"'
bin_name = ''
try:
res = conn.run(find_bin, echo=False, hide='out')
if len(res.stdout) == 0:
raise ValueError
bin_name = res.stdout.strip()
log.info(f'fetching binary [bold blue]{bin_name}[/bold blue] from package [bold green]{package}[/bold green]')
except Exception as e:
raise e
bin_path = Path(LOCAL_BIN_PATH, bin_name).expanduser()
local_path = Path(LOCAL_BIN_PATH).expanduser().__str__()+'/'
try:
9 months ago
if os.path.exists(bin_path):
os.remove(bin_path)
conn.get(bin_path, local=local_path)
except FileNotFoundError as e:
print('could not copy installed package {} from remote'.format(package))
9 months ago
sys.exit(ERR_CMD)
print(f'installed [bold blue]{bin_name}[/bold blue] at {LOCAL_BIN_PATH}')
2 years ago
def list(args):
"""List installed rust binaries on remote host"""
conn = Connection(args.host)
cargo_list = conn.run("cargo install --list | grep 'v.*:$'", echo=True)
# print(f"{cargo_list.stdout.strip()}")
if cargo_list.failed:
print(cargo_list.stderr)
sys.exit(ERR_CMD)
2 years ago
def install(args):
"""Install rust packages from crates.io on remote host and copy binary to local machine."""
args.debug and print(f'{args}')
print(f'{LOCAL_BIN_PATH}')
# args could be a package name or a list of parameters for cargo install
package = ''
params = []
if len(args.package) == 1 and not args.package[0].startswith('-'):
package = args.package[0]
else:
for arg in args.package:
if arg.startswith('--') or arg.startswith('-'):
params.append(arg)
else:
package = arg
# if len(package) == 0:
# print('no package specified')
# sys.exit(ERR_CMD)
args.debug and print(f"package {package}, params: {params}")
2 years ago
conn = Connection(args.host)
param_str = ' '.join(params)
cargo_install = conn.run(f'cargo install {param_str} {package}', warn=True, echo=True)
# print('{}'.format(cargo_install.stdout.strip()))
2 years ago
if cargo_install.failed:
print(cargo_install.stderr)
sys.exit(ERR_CMD)
if len(package) > 0:
inst_get_binary(conn, package, args.debug)
2 years ago
def ensure_deps():
for dep in DEPS:
installed = shutil.which(dep)
if installed is None:
print('{} dependency missing'.format(dep), file=sys.stderr)
2 years ago
sys.exit(ERR_DEPENDENCY)
# def any_cmd(args):
# conn = Connection(args.host)
# run = conn.run(f'cargo {args.command}', echo=True)
2 years ago
if __name__ == '__main__':
ensure_deps()
default_host = os.environ.get('RCARGO_HOST', 'localhost')
2 years ago
parser = argparse.ArgumentParser(description='remote rust cargo commands')
parser.add_argument('-H', '--host', default=default_host,
help="remote cargo host")
parser.add_argument('-d', '--debug', action='store_true')
parser.add_argument('-b', '--bin-path',
default=CARGO_BIN_PATH,
help='local path for installed binary',
metavar='')
2 years ago
subparsers = parser.add_subparsers(dest='command')
list_parser = subparsers.add_parser('list', help='list installed packages on remote host')
list_parser.set_defaults(func=list)
install_parser = subparsers.add_parser('install', prefix_chars="+", help='install packages from crates.io with remote build')
2 years ago
install_parser.set_defaults(func=install)
install_parser.add_argument('package', nargs="*", help='package name', metavar='PACKAGE_NAME')
2 years ago
build = subparsers.add_parser('build', help='remote build local cargo package')
2 years ago
args = parser.parse_args()
LOCAL_BIN_PATH = args.bin_path
if args.debug:
log.setLevel('INFO')
if args.host == 'localhost':
print('you need to define a host with -H option or RCARGO_HOST env variable')
sys.exit(1)
2 years ago
if args.command is not None:
args.func(args)
else:
parser.print_help()