| # This file is run by shell scripts generated by the aos_downloader Skylark |
| # macro. Everything before the first -- is a hard-coded list of files to |
| # download. |
| |
| from __future__ import print_function |
| |
| import argparse |
| import sys |
| from tempfile import TemporaryDirectory |
| import subprocess |
| import re |
| import stat |
| import os |
| import shutil |
| |
| |
| def install(ssh_target, pkg, channel, ssh_path, scp_path): |
| """Installs a package from NI on the ssh target.""" |
| print("Installing", pkg) |
| PKG_URL = f"http://download.ni.com/ni-linux-rt/feeds/academic/2023/arm/{channel}/cortexa9-vfpv3/{pkg}" |
| subprocess.check_call(["wget", PKG_URL, "-O", pkg]) |
| try: |
| subprocess.check_call( |
| [scp_path, "-S", ssh_path, pkg, ssh_target + ":/tmp/" + pkg]) |
| subprocess.check_call( |
| [ssh_path, ssh_target, "opkg", "install", "/tmp/" + pkg]) |
| subprocess.check_call([ssh_path, ssh_target, "rm", "/tmp/" + pkg]) |
| finally: |
| subprocess.check_call(["rm", pkg]) |
| |
| |
| def main(argv): |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--target", |
| type=str, |
| default="roborio-971-frc.local", |
| help="Target to deploy code to.") |
| parser.add_argument("--type", |
| type=str, |
| choices=["roborio", "pi", "orin"], |
| required=True, |
| help="Target type for deployment") |
| parser.add_argument("srcs", |
| type=str, |
| nargs='+', |
| help="List of files to copy over") |
| args = parser.parse_args(argv[1:]) |
| |
| srcs = args.srcs |
| |
| destination = args.target |
| |
| result = re.match("(?:([^:@]+)@)?([^:@]+)(?::([^:@]+))?", destination) |
| if not result: |
| print("Not sure how to parse destination \"%s\"!" % destination, |
| file=sys.stderr) |
| return 1 |
| user = None |
| if result.group(1): |
| user = result.group(1) |
| hostname = result.group(2) |
| |
| if result.group(3): |
| target_dir = result.group(3) |
| |
| if user is None: |
| if args.type == "pi" or args.type == "orin": |
| user = "pi" |
| elif args.type == "roborio": |
| user = "admin" |
| target_dir = "/home/" + user + "/bin" |
| |
| ssh_target = "%s@%s" % (user, hostname) |
| |
| ssh_path = "external/ssh/ssh" |
| scp_path = "external/ssh/scp" |
| |
| # install jq |
| try: |
| subprocess.check_call([ssh_path, ssh_target, "jq", "--version"], |
| stdout=subprocess.DEVNULL) |
| except subprocess.CalledProcessError as e: |
| if e.returncode == 127: |
| print("Didn't find jq on roboRIO, installing jq.") |
| install(ssh_target, "jq-lic_1.5-r0.35_cortexa9-vfpv3.ipk", 'extra', |
| ssh_path, scp_path) |
| install(ssh_target, "libonig-lic_5.9.6-r0.27_cortexa9-vfpv3.ipk", |
| 'extra', ssh_path, scp_path) |
| install(ssh_target, "libonig2_5.9.6-r0.27_cortexa9-vfpv3.ipk", |
| 'extra', ssh_path, scp_path) |
| install(ssh_target, "jq_1.5-r0.35_cortexa9-vfpv3.ipk", 'extra', |
| ssh_path, scp_path) |
| |
| subprocess.check_call([ssh_path, ssh_target, "jq", "--version"], |
| stdout=subprocess.DEVNULL) |
| |
| # Since rsync is pretty fixed in what it can do, build up a temporary |
| # directory with the exact contents we want the target to have. This |
| # is faster than multiple SSH connections. |
| with TemporaryDirectory() as temp_dir: |
| pwd = os.getcwd() |
| # Bazel gives us the same file twice, so dedup here rather than |
| # in starlark |
| copied = set() |
| for s in srcs: |
| if ":" in s: |
| folder = os.path.join(temp_dir, s[s.find(":") + 1:]) |
| os.makedirs(folder, exist_ok=True) |
| s = os.path.join(pwd, s[:s.find(":")]) |
| destination = os.path.join(folder, os.path.basename(s)) |
| else: |
| s = os.path.join(pwd, s) |
| destination = os.path.join(temp_dir, os.path.basename(s)) |
| |
| if s in copied: |
| continue |
| copied.add(s) |
| if s.endswith(".stripped"): |
| destination = destination[:destination.find(".stripped")] |
| shutil.copy2(s, destination) |
| # Make sure the folder that gets created on the roboRIO has open |
| # permissions or the executables won't be visible to init. |
| os.chmod(temp_dir, 0o775) |
| # Starter needs to be SUID so we transition from lvuser to admin. |
| if args.type != "pi" and args.type != "orin": |
| os.chmod(os.path.join(temp_dir, "starterd"), 0o775 | stat.S_ISUID) |
| |
| rsync_cmd = ([ |
| "external/rsync/rsync", |
| "-e", |
| ssh_path, |
| "-c", |
| "-r", |
| "-v", |
| "--perms", |
| "-l", |
| temp_dir + "/", |
| ]) |
| |
| # If there is only 1 file to transfer, we would overwrite the destination |
| # folder. In that case, specify the full path to the target. |
| if len(srcs) == 1: |
| rsync_cmd += ["%s:%s/%s" % (ssh_target, target_dir, srcs[0])] |
| else: |
| rsync_cmd += ["%s:%s" % (ssh_target, target_dir)] |
| |
| try: |
| subprocess.check_call(rsync_cmd) |
| except subprocess.CalledProcessError as e: |
| if e.returncode == 127 or e.returncode == 12: |
| print("Unconfigured roboRIO, installing rsync.") |
| install(ssh_target, "libacl1_2.2.52-r0.310_cortexa9-vfpv3.ipk", |
| 'main', ssh_path, scp_path) |
| install(ssh_target, "rsync-lic_3.1.3-r0.23_cortexa9-vfpv3.ipk", |
| 'extra', ssh_path, scp_path) |
| install(ssh_target, "rsync_3.1.3-r0.23_cortexa9-vfpv3.ipk", |
| 'extra', ssh_path, scp_path) |
| subprocess.check_call(rsync_cmd) |
| elif e.returncode == 11: |
| # Directory wasn't created, make it and try again. This keeps the happy path fast. |
| subprocess.check_call( |
| [ssh_path, ssh_target, "mkdir", "-p", target_dir]) |
| subprocess.check_call(rsync_cmd) |
| else: |
| raise e |
| |
| |
| if __name__ == "__main__": |
| main(sys.argv) |