Import gazelle

This patch imports gazelle as a linter. It automatically generates
BUILD file entries for Go code and at the same time keeps BUILD files
formatted.

The `tools/lint:run-ci` target is set up to automatically add new Go
repositories as well.

I added a tool at `//tools/go:mirror_go_repos` that needs to be run
before anyone can merge code that uses third-party Go libraries.

Change-Id: I1fbf6761439d45893f5be88d294ccc3c567840ca
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
diff --git a/tools/go/mirror_lib.py b/tools/go/mirror_lib.py
new file mode 100644
index 0000000..faad896
--- /dev/null
+++ b/tools/go/mirror_lib.py
@@ -0,0 +1,41 @@
+"""Provides helper functions for mirroring Go repositories."""
+
+import unittest.mock
+from typing import List, Dict
+
+
+def read_file(filepath: str) -> str:
+    """Reads an entire file by returning its contents as a string."""
+    with open(filepath, "r") as file:
+        return file.read()
+
+def parse_go_repositories(filepath: str) -> List[Dict[str, str]]:
+    """Parses the top-level go_deps.bzl file.
+
+    This function can parse both the original version of the file generated by
+    gazelle as well as the tweaked version generated by
+    tweak_gazelle_go_deps.py. The two versions are identical other than what function they call.
+    """
+    global_functions = {
+        "load": unittest.mock.MagicMock(),
+        # The gazelle generated version uses go_repository().
+        "go_repository": unittest.mock.MagicMock(),
+        # The tweak_gazelle_go_deps.py generated version uses
+        # maybe_override_go_dep().
+        "maybe_override_go_dep": unittest.mock.MagicMock()
+    }
+    compiled_code = compile(read_file(filepath), filepath, "exec")
+    eval(compiled_code, global_functions)
+
+    # Extract the repositories defined in the go_dependencies() function from
+    # go_deps.bzl.
+    global_functions["go_dependencies"]()
+
+    repositories = []
+    for repo_kind in ("go_repository", "maybe_override_go_dep"):
+        for repo in global_functions[repo_kind].mock_calls:
+            _, _, kwargs = repo
+            repositories.append(kwargs)
+
+    return repositories
+