Relocatable go env (#2385)
**What type of PR is this?**
Feature
**What package or component does this PR mostly affect?**
go repository cache
**What does this PR do? Why is it needed?**
go.env having user path dependent means that after performing bazel
vendoring, users of another machine from the machine that performs
vendoring cannot use said dependency anymore without IGNORE-ing gazelle.
**Which issues(s) does this PR fix?**
Makes go.env path independent. Fixes #2382
**Other notes for review**
---------
Co-authored-by: Jay Conrod <jay@engflow.com>diff --git a/internal/go_repository_cache.bzl b/internal/go_repository_cache.bzl
index 33f1c3c..ee1e432 100644
--- a/internal/go_repository_cache.bzl
+++ b/internal/go_repository_cache.bzl
@@ -36,8 +36,8 @@
go_sdk_label = Label("@" + go_sdk_name + "//:ROOT")
go_root = str(ctx.path(go_sdk_label).dirname)
- go_path = str(ctx.path("."))
- go_cache = str(ctx.path("gocache"))
+ go_path = "" # default: the cache repo itself; recomputed by read_cache_env()
+ go_cache = "" # default: <cache repo>/gocache; recomputed by read_cache_env()
go_mod_cache = ""
if getenv(ctx, "GO_REPOSITORY_USE_HOST_MODCACHE") == "1":
extension = executable_extension(ctx)
@@ -62,7 +62,6 @@
# This avoids a class of staleness issues, both with and without repo
# content caches.
"GOROOT": str(go_sdk_label),
- "GOCACHE": go_cache,
# Since Go v1.21.0, set GOTOOLCHAIN to "local" to use the current toolchain
# of the Go SDK. This is required to avoid `go mod download` commands
@@ -76,6 +75,8 @@
}
if go_path:
cache_env["GOPATH"] = go_path
+ if go_cache:
+ cache_env["GOCACHE"] = go_cache
if go_mod_cache:
cache_env["GOMODCACHE"] = go_mod_cache
@@ -83,7 +84,7 @@
ctx,
direct = ctx.attr.go_env,
inherit = ctx.attr.go_env_inherit,
- reserved = cache_env.keys(),
+ reserved = cache_env.keys() + ["GOCACHE", "GOPATH"],
))
env_content = "\n".join(["{k}='{v}'\n".format(k = k, v = v) for k, v in cache_env.items()])
@@ -127,6 +128,9 @@
# path and register a dependency by doing so.
if env.get("GOROOT"):
env["GOROOT"] = str(ctx.path(Label(env["GOROOT"])).dirname)
+ cache_dir = str(ctx.path(path).dirname)
+ env.setdefault("GOPATH", cache_dir)
+ env.setdefault("GOCACHE", cache_dir + "/gocache")
return env
# copied from rules_go. Keep in sync.
diff --git a/internal/go_repository_test.go b/internal/go_repository_test.go
index 2dff055..8ae7b2a 100644
--- a/internal/go_repository_test.go
+++ b/internal/go_repository_test.go
@@ -262,6 +262,25 @@
}
}
+ // The cache env must stay relocatable so that vendoring across users can use said go.env.
+ for _, line := range strings.Split(string(gotBytes), "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ key, value, found := strings.Cut(line, "=")
+ if !found {
+ t.Fatalf("malformed go.env line %q", line)
+ }
+ value = strings.Trim(value, "'")
+ if filepath.IsAbs(value) {
+ t.Errorf("go.env: %s=%s is an absolute path; go.env must be relocatable", key, value)
+ }
+ if strings.Contains(value, outputBase) {
+ t.Errorf("go.env: %s=%s references the output base; go.env must be relocatable", key, value)
+ }
+ }
+
goEnvBzlPath := filepath.Join(outputBase, "external/bazel_gazelle_go_repository_config", "go_env.bzl")
goEnvBzl, err := os.ReadFile(goEnvBzlPath)
if err != nil {