Skip to content

Commit

Permalink
Use Gazelle's go_env in @rules_go//go (#3909)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmeum committed Apr 14, 2024
1 parent c40b336 commit 6d352d6
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 39 deletions.
4 changes: 3 additions & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use_repo(

register_toolchains("@go_toolchains//:all")

bazel_dep(name = "gazelle", version = "0.34.0")
bazel_dep(name = "gazelle", version = "0.36.0")

go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
Expand All @@ -42,4 +42,6 @@ use_repo(
"org_golang_google_protobuf",
"org_golang_x_net",
"org_golang_x_tools",
# Exported by gazelle specifically for rules_go.
"bazel_gazelle_go_repository_config",
)
15 changes: 15 additions & 0 deletions docs/go/core/bzlmod.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ A dependency can be added via
bazel run @rules_go//go get golang.org/x/text@v0.3.2
```

### Environment variables

Environment variables (such as `GOPROXY` and `GOPRIVATE`) required for fetching Go dependencies can be set as follows:

```starlark
go_deps.config(
go_env = {
"GOPRIVATE": "...",
},
)
```

Variables set in this way are used by `go_deps` as well as `@rules_go//go`, with other variables inheriting their value from the host environment.
`go_env` does *not* affect Go build actions.

### Overrides

The root module can override certain aspects of the dependency resolution performed by the `go_deps` extension.
Expand Down
3 changes: 3 additions & 0 deletions go/private/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,6 @@ _RULES_GO_RAW_REPO_NAME = str(Label("//:unused"))[:-len("//:unused")]
# not start with a "@", so we need to add it.
RULES_GO_REPO_NAME = _RULES_GO_RAW_REPO_NAME if _RULES_GO_RAW_REPO_NAME.startswith("@") else "@" + _RULES_GO_RAW_REPO_NAME
RULES_GO_STDLIB_PREFIX = RULES_GO_REPO_NAME + "//stdlib:"

# TODO: Remove the "and" once the rules_go repo itself uses Bzlmod.
RULES_GO_IS_BZLMOD_REPO = _RULES_GO_RAW_REPO_NAME.lstrip("@") != "io_bazel_rules_go" and _RULES_GO_RAW_REPO_NAME.lstrip("@")
7 changes: 5 additions & 2 deletions go/tools/go_bin_runner/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# gazelle:exclude

load("//go:def.bzl", "go_binary", "go_library")
load("//go/private:common.bzl", "RULES_GO_IS_BZLMOD_REPO")
load("//go/private/rules:go_bin_for_host.bzl", "go_bin_for_host")

go_bin_for_host(
Expand All @@ -12,7 +13,6 @@ go_library(
name = "go_bin_runner_lib",
srcs = [
"main.go",
"process.go",
],
importpath = "github.com/bazelbuild/rules_go/go/tools/go_bin_runner",
visibility = ["//visibility:private"],
Expand All @@ -28,11 +28,14 @@ go_binary(
"@platforms//os:windows": "bin/go.exe",
"//conditions:default": "bin/go",
}),
data = [":go_bin_for_host"],
data = [":go_bin_for_host"] + (
["@bazel_gazelle_go_repository_config//:config.json"] if RULES_GO_IS_BZLMOD_REPO else []
),
embed = [":go_bin_runner_lib"],
visibility = ["//go:__pkg__"],
x_defs = {
"GoBinRlocationPath": "$(rlocationpath :go_bin_for_host)",
"ConfigRlocationPath": "$(rlocationpath @bazel_gazelle_go_repository_config//:config.json)" if RULES_GO_IS_BZLMOD_REPO else "WORKSPACE",
},
)

Expand Down
77 changes: 64 additions & 13 deletions go/tools/go_bin_runner/main.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,92 @@
package main

import (
"encoding/json"
"log"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/bazelbuild/rules_go/go/runfiles"
)

var GoBinRlocationPath = "not set"
var ConfigRlocationPath = "not set"

// Produced by gazelle's go_deps extension.
type Config struct {
GoEnv map[string]string `json:"go_env"`
}

func main() {
goBin, err := runfiles.Rlocation(GoBinRlocationPath)
if err != nil {
log.Fatal(err)
}
// The go binary lies at $GOROOT/bin/go.
goRoot, err := filepath.Abs(filepath.Dir(filepath.Dir(goBin)))

cfg, err := parseConfig()
if err != nil {
log.Fatal(err)
}

env, err := getGoEnv(goBin, cfg)
if err != nil {
log.Fatal(err)
}

args := append([]string{goBin}, os.Args[1:]...)
log.Fatal(runProcess(args, env, os.Getenv("BUILD_WORKING_DIRECTORY")))
}

func parseConfig() (Config, error) {
var cfg *Config
// Special value set when rules_go is loaded as a WORKSPACE repo, in which
// the cfg file isn't available from Gazelle.
if ConfigRlocationPath == "WORKSPACE" {
return Config{}, nil
}
cfgJsonPath, err := runfiles.Rlocation(ConfigRlocationPath)
if err != nil {
return Config{}, err
}
cfgJson, err := os.ReadFile(cfgJsonPath)
if err != nil {
return Config{}, err
}
err = json.Unmarshal(cfgJson, &cfg)
if err != nil {
return Config{}, err
}
return *cfg, nil
}

func getGoEnv(goBin string, cfg Config) ([]string, error) {
env := os.Environ()
var filteredEnv []string
for i := 0; i < len(env); i++ {
if !strings.HasPrefix(env[i], "GOROOT=") {
filteredEnv = append(filteredEnv, env[i])
}
for k, v := range cfg.GoEnv {
env = append(env, k+"="+v)
}
filteredEnv = append(filteredEnv, "GOROOT="+goRoot)

err = os.Chdir(os.Getenv("BUILD_WORKING_DIRECTORY"))
// The go binary lies at $GOROOT/bin/go.
goRoot, err := filepath.Abs(filepath.Dir(filepath.Dir(goBin)))
if err != nil {
log.Fatal(err)
return nil, err
}

args := append([]string{goBin}, os.Args[1:]...)
log.Fatal(ReplaceWithProcess(args, filteredEnv))
// Override GOROOT to point to the hermetic Go SDK.
return append(env, "GOROOT="+goRoot), nil
}

func runProcess(args, env []string, dir string) error {
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = dir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = env
err := cmd.Run()
if exitErr, ok := err.(*exec.ExitError); ok {
os.Exit(exitErr.ExitCode())
} else if err == nil {
os.Exit(0)
}
return err
}
20 changes: 0 additions & 20 deletions go/tools/go_bin_runner/process.go

This file was deleted.

2 changes: 1 addition & 1 deletion tests/bcr/.bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.0.0
6.4.0
4 changes: 2 additions & 2 deletions tests/bcr/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ go_test(
)

sh_test(
name = "go_version_test",
srcs = ["go_version_test.sh"],
name = "go_tool_test",
srcs = ["go_tool_test.sh"],
data = ["@my_rules_go//go"],
env = {"GO_TOOL_RLOCATION": "$(rlocationpath @my_rules_go//go)"},
deps = ["@bazel_tools//tools/bash/runfiles"],
Expand Down
5 changes: 5 additions & 0 deletions tests/bcr/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,9 @@ go_deps.module(
sum = "h1:pnP7OclFFFgFi4VHQDQDaoXUVauOFyktqTsqqgzFKbc=",
version = "v1.40.1",
)

# Read in go_tool_test.sh.
go_deps.config(
go_env = {"GOPRIVATE": "example.com"},
)
use_repo(go_deps, "org_golang_google_grpc")
1 change: 1 addition & 0 deletions tests/bcr/go_version_test.sh → tests/bcr/go_tool_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ runfiles_export_envvars
# Simulate a bazel run environment.
export BUILD_WORKING_DIRECTORY=$(pwd)
[[ "$("$GO_TOOL" version)" =~ ^go ]]
[[ "$("$GO_TOOL" env GOPRIVATE)" == example.com ]]

0 comments on commit 6d352d6

Please sign in to comment.