Add convenience script for locally running foxglove

Change-Id: I8c2367b26d8a98191486cc636ecd319a7a95bd5b
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/WORKSPACE b/WORKSPACE
index bf609e7..67d3e65 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -249,6 +249,13 @@
     path = "third_party/bazel-toolchain",
 )
 
+http_archive(
+    name = "RangeHTTPServer",
+    sha256 = "98a8e4980f91d048dc9159cfc5f115280d0b5ec59a5b01df0422b887212fa4f0",
+    strip_prefix = "RangeHTTPServer-9070394508a135789238a33259793f3c6f3c127a",
+    url = "https://github.com/jkuszmaul/RangeHTTPServer/archive/9070394508a135789238a33259793f3c6f3c127a.zip",
+)
+
 load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm", "llvm_toolchain")
 
 llvm_version = "17.0.2"
diff --git a/frc971/analysis/BUILD b/frc971/analysis/BUILD
index dd3d092..9b9ab86 100644
--- a/frc971/analysis/BUILD
+++ b/frc971/analysis/BUILD
@@ -216,3 +216,14 @@
         "//third_party/seasocks",
     ],
 )
+
+py_binary(
+    name = "trim_and_plot_foxglove",
+    srcs = ["trim_and_plot_foxglove.py"],
+    data = [
+        ":trim_log_to_enabled",
+        "//aos/util:log_to_mcap",
+        "@foxglove_studio",
+    ],
+    deps = ["@RangeHTTPServer"],
+)
diff --git a/frc971/analysis/trim_and_plot_foxglove.py b/frc971/analysis/trim_and_plot_foxglove.py
new file mode 100644
index 0000000..6812d60
--- /dev/null
+++ b/frc971/analysis/trim_and_plot_foxglove.py
@@ -0,0 +1,51 @@
+import http.server as SimpleHTTPServer
+from RangeHTTPServer import RangeRequestHandler
+import argparse
+import os
+import shutil
+import subprocess
+from tempfile import mkdtemp
+
+parser = argparse.ArgumentParser(
+    description="""Trims & generates MCAP file from log.
+
+Serves foxglove locally, and prints out a URL by which the log can be accessed.
+
+By default, will trim a log to the time period during which the robot was
+enabled. Skips this stip if --skip_trim is passed.""")
+parser.add_argument('--port',
+                    action='store',
+                    default=8000,
+                    type=int,
+                    help='Specify port on which to serve foxglove.')
+parser.add_argument('--skip_trim',
+                    action='store_true',
+                    default=False,
+                    help='If set, do not trim the logfile..')
+parser.add_argument('log',
+                    action='store',
+                    default=None,
+                    type=str,
+                    nargs='+',
+                    help='Log(s) to plot.')
+args = parser.parse_args()
+
+tmpdir = mkdtemp(prefix="foxglove_")
+shutil.copytree("external/foxglove_studio", tmpdir, dirs_exist_ok=True)
+
+trimmed_aos_log = args.log if args.skip_trim else [tmpdir + "/trimmed/"]
+output_mcap = tmpdir + "/log.mcap"
+
+if not args.skip_trim:
+    subprocess.run(["frc971/analysis/trim_log_to_enabled", "--output_folder"] +
+                   trimmed_aos_log + args.log).check_returncode()
+subprocess.run(["aos/util/log_to_mcap", "--output_path", output_mcap] +
+               trimmed_aos_log).check_returncode()
+
+mcap_url = f"http://localhost:{args.port}/log.mcap"
+url_parameters = f"?ds=remote-file&ds.url={mcap_url}"
+print(f"Serving files from {tmpdir}")
+print(f"Local URL: http://localhost:{args.port}/{url_parameters}")
+print(f"Live Website URL: https://studio.foxglove.dev/{url_parameters}")
+os.chdir(tmpdir)
+SimpleHTTPServer.test(HandlerClass=RangeRequestHandler, port=args.port)