Import rules_go

The motivation here is to use Go for the scouting web server. It
sounds like we have enough knowledge in the team to at least give it a
try.

    $ bazel run //build_tests:hello_go
    WARNING: Option 'ui' is deprecated
    INFO: Invocation ID: d227f296-c249-44d3-88c0-42c2aee1bde2
    INFO: SHA256 (https://golang.org/dl/?mode=json&include=all) = dd71d0c702dbeb9a765da037c9792250fb9e440fa3bd5dbdca91db34f0265446
    INFO: Analyzed target //build_tests:hello_go (45 packages loaded, 47836 targets configured).
    INFO: Found 1 target...
    INFO: Writing explanation of rebuilds to '/tmp/bazel_explain.log'
    Target //build_tests:hello_go up-to-date:
      bazel-bin/build_tests/hello_go_/hello_go
    INFO: Elapsed time: 99.935s, Critical Path: 1.57s
    INFO: 8 processes: 4 internal, 4 linux-sandbox.
    INFO: Build completed successfully, 8 total actions
    INFO: Build completed successfully, 8 total actions
    hello world

In order to work around a bazel issue, I created a dummy NOOP Go
toolchain. That toolchain will be used on all platforms where we don't
explicitly support Go. The key is to also mark all `go_*` target as
only being compatible with x86 Linux.

Change-Id: I0a9be3748c59998f5d2dea8d6a162779a0f31af1
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
diff --git a/WORKSPACE b/WORKSPACE
index 61991e9..a464a6d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -126,6 +126,7 @@
     # Find a good way to select between these two M4F toolchains.
     #"//tools/cpp:cc-toolchain-cortex-m4f-k22",
     "//tools/python:python_toolchain",
+    "//tools/go:noop_go_toolchain",
 )
 
 http_archive(
@@ -873,3 +874,18 @@
     name = "snappy",
     path = "third_party/snappy",
 )
+
+http_archive(
+    name = "io_bazel_rules_go",
+    sha256 = "2b1641428dff9018f9e85c0384f03ec6c10660d935b750e3fa1492a281a53b0f",
+    urls = [
+        "https://www.frc971.org/Build-Dependencies/rules_go-v0.29.0.zip",
+        "https://github.com/bazelbuild/rules_go/releases/download/v0.29.0/rules_go-v0.29.0.zip",
+    ],
+)
+
+load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
+
+go_rules_dependencies()
+
+go_register_toolchains(version = "1.17.1")
diff --git a/build_tests/BUILD b/build_tests/BUILD
index d142c13..6563297 100644
--- a/build_tests/BUILD
+++ b/build_tests/BUILD
@@ -1,5 +1,6 @@
 load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library")
 load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_py_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
 
 cc_test(
     name = "gflags_build_test",
@@ -96,3 +97,9 @@
     target_compatible_with = ["@platforms//os:linux"],
     deps = ["@python_jinja2"],
 )
+
+go_binary(
+    name = "hello_go",
+    srcs = ["hello.go"],
+    target_compatible_with = ["@platforms//cpu:x86_64"],
+)
diff --git a/build_tests/hello.go b/build_tests/hello.go
new file mode 100644
index 0000000..4cc584b
--- /dev/null
+++ b/build_tests/hello.go
@@ -0,0 +1,7 @@
+package main
+
+import "fmt"
+
+func main() {
+    fmt.Println("Hello world")
+}
diff --git a/tools/go/BUILD b/tools/go/BUILD
new file mode 100644
index 0000000..ec8aa26
--- /dev/null
+++ b/tools/go/BUILD
@@ -0,0 +1,53 @@
+# This file exists to create a NOOP toolchain for Go on platforms that don't
+# support Go. We can probably get rid of this once
+# https://github.com/bazelbuild/bazel/issues/12897 is fixed.
+#
+# For platforms that do support Go, we use go_register_toolchain() in
+# WORKSPACE.
+
+load("@bazel_skylib//rules:write_file.bzl", "write_file")
+load("@io_bazel_rules_go//go:def.bzl", "go_sdk", "go_toolchain")
+
+write_file(
+    name = "noop_error_exit",
+    out = "noop_error_exit.sh",
+    content = [
+        "#!/bin/bash",
+        "echo 'This should never be executed. Something went wrong.' >&2",
+        "echo 'This NOOP Go toolchain should never be executed. Something went wrong.' >&2",
+        "echo 'Check that your target has `target_compatible_with` set to a platform that supports Go.' >&2",
+        "exit 1",
+    ],
+    is_executable = True,
+)
+
+go_sdk(
+    name = "noop_sdk",
+    go = ":noop_error_exit",
+    goarch = "none",
+    goos = "none",
+    root_file = "NOOP_FILE_THAT_DOES_NOT_EXIST",
+)
+
+go_toolchain(
+    name = "noop_go_toolchain_impl",
+    builder = ":noop_error_exit",
+    cgo_link_flags = None,
+    goarch = "none",
+    goos = "none",
+    link_flags = None,
+    sdk = ":noop_sdk",
+    tags = ["manual"],
+)
+
+toolchain(
+    name = "noop_go_toolchain",
+    exec_compatible_with = [
+        "@platforms//os:linux",
+    ],
+    target_compatible_with = [
+        "//tools/platforms/go:lacks_support",
+    ],
+    toolchain = ":noop_go_toolchain_impl",
+    toolchain_type = "@io_bazel_rules_go//go:toolchain",
+)
diff --git a/tools/platforms/BUILD b/tools/platforms/BUILD
index 65563bf..4aa3db3 100644
--- a/tools/platforms/BUILD
+++ b/tools/platforms/BUILD
@@ -5,6 +5,7 @@
     constraint_values = [
         "@platforms//os:linux",
         "@platforms//cpu:x86_64",
+        "//tools/platforms/go:has_support",
     ],
 )
 
@@ -14,6 +15,7 @@
         "@platforms//os:linux",
         "@platforms//cpu:armv7",
         "//tools/platforms/hardware:raspberry_pi",
+        "//tools/platforms/go:lacks_support",
     ],
 )
 
@@ -22,6 +24,7 @@
     constraint_values = [
         "@platforms//os:linux",
         "@platforms//cpu:arm64",
+        "//tools/platforms/go:lacks_support",
     ],
 )
 
@@ -31,6 +34,7 @@
         "@platforms//os:linux",
         "@platforms//cpu:armv7",
         "//tools/platforms/hardware:roborio",
+        "//tools/platforms/go:lacks_support",
     ],
 )
 
@@ -39,6 +43,7 @@
     constraint_values = [
         "@platforms//os:none",
         "//tools/platforms/hardware:cortex_m4f",
+        "//tools/platforms/go:lacks_support",
     ],
 )
 
diff --git a/tools/platforms/go/BUILD b/tools/platforms/go/BUILD
new file mode 100644
index 0000000..5936287
--- /dev/null
+++ b/tools/platforms/go/BUILD
@@ -0,0 +1,13 @@
+package(default_visibility = ["//visibility:public"])
+
+constraint_setting(name = "go_support")
+
+constraint_value(
+    name = "has_support",
+    constraint_setting = ":go_support",
+)
+
+constraint_value(
+    name = "lacks_support",
+    constraint_setting = ":go_support",
+)