Deploy www directory when deploying code and fix vision.

Change-Id: Ifd9fb09b655caaa064219efb6c13946937339849
diff --git a/aos/downloader/downloader.bzl b/aos/downloader/downloader.bzl
index a98571a..0085804 100644
--- a/aos/downloader/downloader.bzl
+++ b/aos/downloader/downloader.bzl
@@ -5,7 +5,13 @@
     executable = True,
     content = '\n'.join([
       '#!/bin/bash',
+      'set -e',
       'cd "${BASH_SOURCE[@]}.runfiles"',
+    ] + ['%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),
@@ -17,15 +23,26 @@
     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 = all_files + ctx.files._downloader + [ctx.outputs._startlist],
+      files = to_download + ctx.files._downloader,
       collect_data = True,
       collect_default = True,
     ),
     files = set([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.
@@ -34,6 +51,7 @@
 
 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.
@@ -54,6 +72,13 @@
       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',
     ),
@@ -63,3 +88,26 @@
     '_startlist': '%{name}.start_list.dir/start_list.txt',
   },
 )
+
+'''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(
+  implementation = _aos_downloader_dir_impl,
+  attrs = {
+    'srcs': attr.label_list(
+      mandatory = True,
+      allow_files = True,
+    ),
+    'dir': attr.string(
+       mandatory = True,
+    ),
+  },
+)
diff --git a/aos/downloader/downloader.py b/aos/downloader/downloader.py
index 5cdd94e..9799b1f 100644
--- a/aos/downloader/downloader.py
+++ b/aos/downloader/downloader.py
@@ -23,9 +23,19 @@
 
 
 def main(argv):
-  srcs = argv[1:argv.index('--')]
   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'
 
@@ -47,7 +57,7 @@
   ssh_target = '%s@%s' % (user, hostname)
 
   rsync_cmd = (['rsync', '-c', '-v', '-z', '--copy-links'] + srcs +
-               ['%s:%s' % (ssh_target, target_dir)])
+               ['%s:%s/%s' % (ssh_target, target_dir, relative_dir)])
   try:
     subprocess.check_call(rsync_cmd)
   except subprocess.CalledProcessError as e:
@@ -60,12 +70,13 @@
     else:
       raise e
 
-  subprocess.check_call(
-      ('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 not recursive:
+    subprocess.check_call(
+        ('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)