blob: 181a721d8410115cdcbc4ef05ff5ec11532cc89d [file] [log] [blame] [edit]
# 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)