Convert aos over to flatbuffers
Everything builds, and all the tests pass. I suspect that some entries
are missing from the config files, but those will be found pretty
quickly on startup.
There is no logging or live introspection of queue messages.
Change-Id: I496ee01ed68f202c7851bed7e8786cee30df29f5
diff --git a/frc971/downloader/BUILD b/frc971/downloader/BUILD
new file mode 100644
index 0000000..1aab653
--- /dev/null
+++ b/frc971/downloader/BUILD
@@ -0,0 +1,12 @@
+py_binary(
+ name = "downloader",
+ srcs = [
+ "downloader.py",
+ ],
+ data = [
+ "@rsync",
+ "@ssh",
+ "@ssh//:scp",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/frc971/downloader/downloader.bzl b/frc971/downloader/downloader.bzl
new file mode 100644
index 0000000..a5d1bc1
--- /dev/null
+++ b/frc971/downloader/downloader.bzl
@@ -0,0 +1,119 @@
+def _aos_downloader_impl(ctx):
+ all_files = ctx.files.srcs + ctx.files.start_srcs + [ctx.outputs._startlist]
+ ctx.file_action(
+ output = ctx.outputs.executable,
+ executable = True,
+ content = "\n".join([
+ "#!/bin/bash",
+ "set -e",
+ 'cd "${BASH_SOURCE[0]}.runfiles/%s"' % ctx.workspace_name,
+ ] + ['%s %s --dirs %s -- %s "$@"' % (
+ ctx.executable._downloader.short_path,
+ " ".join([src.short_path for src in d.downloader_srcs]),
+ d.downloader_dir,
+ ctx.attr.default_target,
+ ) for d in ctx.attr.dirs] + [
+ 'exec %s %s -- %s "$@"' % (
+ ctx.executable._downloader.short_path,
+ " ".join([src.short_path for src in all_files]),
+ ctx.attr.default_target,
+ ),
+ ]),
+ )
+
+ ctx.file_action(
+ output = ctx.outputs._startlist,
+ content = "\n".join([f.basename for f in ctx.files.start_srcs]) + "\n",
+ )
+
+ to_download = [ctx.outputs._startlist]
+ to_download += all_files
+ for d in ctx.attr.dirs:
+ to_download += d.downloader_srcs
+
+ return struct(
+ runfiles = ctx.runfiles(
+ files = to_download + ctx.files._downloader,
+ transitive_files = ctx.attr._downloader.default_runfiles.files,
+ collect_data = True,
+ collect_default = True,
+ ),
+ files = depset([ctx.outputs.executable]),
+ )
+
+def _aos_downloader_dir_impl(ctx):
+ return struct(
+ downloader_dir = ctx.attr.dir,
+ downloader_srcs = ctx.files.srcs,
+ )
+
+"""Creates a binary which downloads code to a robot.
+
+Running this with `bazel run` will actually download everything.
+
+This also generates a start_list.txt file with the names of binaries to start.
+
+Attrs:
+ srcs: The files to download. They currently all get shoved into one folder.
+ dirs: A list of aos_downloader_dirs to download too.
+ start_srcs: Like srcs, except they also get put into start_list.txt.
+ default_target: The default host to download to. If not specified, defaults to
+ roboRIO-971.local.
+"""
+
+aos_downloader = rule(
+ attrs = {
+ "_downloader": attr.label(
+ executable = True,
+ cfg = "host",
+ default = Label("//frc971/downloader"),
+ ),
+ "start_srcs": attr.label_list(
+ mandatory = True,
+ allow_files = True,
+ ),
+ "srcs": attr.label_list(
+ mandatory = True,
+ allow_files = True,
+ ),
+ "dirs": attr.label_list(
+ mandatory = False,
+ providers = [
+ "downloader_dir",
+ "downloader_srcs",
+ ],
+ ),
+ "default_target": attr.string(
+ default = "roboRIO-971-frc.local",
+ ),
+ },
+ executable = True,
+ outputs = {
+ "_startlist": "%{name}.start_list.dir/start_list.txt",
+ },
+ implementation = _aos_downloader_impl,
+)
+
+"""Downloads files to a specific directory.
+
+This rule does nothing by itself. Use it by adding to the dirs attribute of an
+aos_downloader rule.
+
+Attrs:
+ srcs: The files to download. They all go in the same directory.
+ dir: The directory (relative to the standard download directory) to put all
+ the files in.
+"""
+
+aos_downloader_dir = rule(
+ attrs = {
+ "srcs": attr.label_list(
+ mandatory = True,
+ allow_files = True,
+ ),
+ "dir": attr.string(
+ mandatory = True,
+ ),
+ },
+ implementation = _aos_downloader_dir_impl,
+)
diff --git a/frc971/downloader/downloader.py b/frc971/downloader/downloader.py
new file mode 100644
index 0000000..e49ee5d
--- /dev/null
+++ b/frc971/downloader/downloader.py
@@ -0,0 +1,94 @@
+# 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 sys
+import subprocess
+import re
+import os
+
+
+def install(ssh_target, pkg):
+ """Installs a package from NI on the ssh target."""
+ print("Installing", pkg)
+ PKG_URL = "http://download.ni.com/ni-linux-rt/feeds/2015/arm/ipk/cortexa9-vfpv3/" + pkg
+ subprocess.check_call(["wget", PKG_URL, "-O", pkg])
+ try:
+ subprocess.check_call([
+ "external/ssh/usr/bin/scp", "-S", "external/ssh/usr/bin/ssh", pkg,
+ ssh_target + ":/tmp/" + pkg
+ ])
+ subprocess.check_call([
+ "external/ssh/usr/bin/ssh", ssh_target, "opkg", "install",
+ "/tmp/" + pkg
+ ])
+ subprocess.check_call(
+ ["external/ssh/usr/bin/ssh", ssh_target, "rm", "/tmp/" + pkg])
+ finally:
+ subprocess.check_call(["rm", pkg])
+
+
+def main(argv):
+ args = argv[argv.index("--") + 1:]
+
+ relative_dir = ""
+ recursive = False
+
+ if "--dirs" in argv:
+ dirs_index = argv.index("--dirs")
+ srcs = argv[1:dirs_index]
+ relative_dir = argv[dirs_index + 1]
+ recursive = True
+ else:
+ srcs = argv[1:argv.index("--")]
+
+ ROBORIO_TARGET_DIR = "/home/admin/robot_code"
+ ROBORIO_USER = "admin"
+
+ target_dir = ROBORIO_TARGET_DIR
+ user = ROBORIO_USER
+ destination = args[-1]
+
+ result = re.match("(?:([^:@]+)@)?([^:@]+)(?::([^:@]+))?", destination)
+ if not result:
+ print(
+ "Not sure how to parse destination \"%s\"!" % destination,
+ file=sys.stderr)
+ return 1
+ if result.group(1):
+ user = result.group(1)
+ hostname = result.group(2)
+ if result.group(3):
+ target_dir = result.group(3)
+
+ ssh_target = "%s@%s" % (user, hostname)
+
+ rsync_cmd = ([
+ "external/rsync/usr/bin/rsync", "-e", "external/ssh/usr/bin/ssh", "-c",
+ "-v", "-z", "--copy-links"
+ ] + srcs + ["%s:%s/%s" % (ssh_target, target_dir, relative_dir)])
+ try:
+ subprocess.check_call(rsync_cmd)
+ except subprocess.CalledProcessError as e:
+ if e.returncode == 127:
+ print("Unconfigured roboRIO, installing rsync.")
+ install(ssh_target, "libattr1_2.4.47-r0.36_cortexa9-vfpv3.ipk")
+ install(ssh_target, "libacl1_2.2.52-r0.36_cortexa9-vfpv3.ipk")
+ install(ssh_target, "rsync_3.1.0-r0.7_cortexa9-vfpv3.ipk")
+ subprocess.check_call(rsync_cmd)
+ else:
+ raise e
+
+ if not recursive:
+ subprocess.check_call(
+ ("external/ssh/usr/bin/ssh", ssh_target, "&&".join([
+ "chmod u+s %s/starter_exe" % target_dir,
+ "echo \'Done moving new executables into place\'",
+ "bash -c \'sync && sync && sync\'",
+ ])))
+
+
+if __name__ == "__main__":
+ main(sys.argv)