Factor out jinja2 template to be generic

This lets us reuse it for many more config setups to avoid duplication.

Change-Id: I9e77e55d460edb3f8037ce164818e45b6ab7a56e
diff --git a/tools/build_rules/BUILD b/tools/build_rules/BUILD
index f96fb3a..8ad7018 100644
--- a/tools/build_rules/BUILD
+++ b/tools/build_rules/BUILD
@@ -3,3 +3,10 @@
     srcs = ["quiet_success.sh"],
     visibility = ["//visibility:public"],
 )
+
+py_binary(
+    name = "jinja2_generator",
+    srcs = ["jinja2_generator.py"],
+    visibility = ["//visibility:public"],
+    deps = ["@python_jinja2"],
+)
diff --git a/y2020/generate_pi_config.py b/tools/build_rules/jinja2_generator.py
similarity index 96%
rename from y2020/generate_pi_config.py
rename to tools/build_rules/jinja2_generator.py
index afd1fca..34f3354 100644
--- a/y2020/generate_pi_config.py
+++ b/tools/build_rules/jinja2_generator.py
@@ -1,7 +1,6 @@
 #!/usr/bin/python3
 
 import argparse
-from pathlib import Path
 import json
 import sys
 
diff --git a/tools/build_rules/template.bzl b/tools/build_rules/template.bzl
new file mode 100644
index 0000000..d4807e8
--- /dev/null
+++ b/tools/build_rules/template.bzl
@@ -0,0 +1,33 @@
+def _jinja2_template_impl(ctx):
+    out = ctx.actions.declare_file(ctx.attr.name)
+
+    ctx.actions.run_shell(
+        inputs = ctx.files.src,
+        tools = [ctx.executable._jinja2],
+        progress_message = "Generating " + out.short_path,
+        outputs = [out],
+        command = ctx.executable._jinja2.path + " " + ctx.files.src[0].path + " '" + str(ctx.attr.parameters) + "' " + out.path,
+    )
+
+    return [DefaultInfo(files = depset([out])), OutputGroupInfo(out = depset([out]))]
+
+jinja2_template = rule(
+    attrs = {
+        "src": attr.label(
+            mandatory = True,
+            allow_single_file = True,
+            doc = """The jinja2 template file to expand.""",
+        ),
+        "parameters": attr.string_dict(
+            mandatory = True,
+            doc = """The parameters to supply to Jinja2.""",
+        ),
+        "_jinja2": attr.label(
+            default = "//tools/build_rules:jinja2_generator",
+            cfg = "host",
+            executable = True,
+        ),
+    },
+    implementation = _jinja2_template_impl,
+    doc = """Expands a jinja2 template given parameters.""",
+)
diff --git a/y2020/BUILD b/y2020/BUILD
index ba2f3a6..38832b8 100644
--- a/y2020/BUILD
+++ b/y2020/BUILD
@@ -2,7 +2,7 @@
 load("//aos:config.bzl", "aos_config")
 load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library")
 load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
-load("//y2020:config_gen.bzl", "generate_pi_config")
+load("//tools/build_rules:template.bzl", "jinja2_template")
 
 robot_downloader(
     binaries = [
@@ -182,11 +182,30 @@
         "pi2",
         "pi3",
         "pi4",
-        "laptop",
     ]
 ]
 
 aos_config(
+    name = "config_laptop",
+    src = "y2020_laptop.json",
+    flatbuffers = [
+        "//aos/network:message_bridge_client_fbs",
+        "//aos/network:message_bridge_server_fbs",
+        "//aos/network:timestamp_fbs",
+        "//y2020/vision/sift:sift_fbs",
+        "//y2020/vision/sift:sift_training_fbs",
+        "//y2020/vision:vision_fbs",
+        "//aos/events/logging:logger_fbs",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos/events:config",
+        "//aos/robot_state:config",
+        "//frc971/control_loops/drivetrain:config",
+    ],
+)
+
+aos_config(
     name = "config_roborio",
     src = "y2020_roborio.json",
     flatbuffers = [
@@ -248,10 +267,11 @@
     ],
 )
 
-py_binary(
-    name = "generate_pi_config",
-    srcs = ["generate_pi_config.py"],
-    deps = ["@python_jinja2"],
-)
-
-[generate_pi_config(num) for num in range(1, 5)]
+[
+    jinja2_template(
+        name = "y2020_pi" + str(num) + ".json",
+        src = "y2020_pi_template.json",
+        parameters = {"NUM": str(num)},
+    )
+    for num in range(1, 5)
+]