rules_go: 'go env GOROOT' does not match runtime.GOROOT

https://github.com/golang/tools/commit/7dd52f09642e72aa8eda78359919c8129a51819b rejects Go command if go env GOROOT != runtime.GOROOT(). However, rules_go doesn’t set the environment variable GOROOT properly, and runtime.GOROOT() reads GOROOT, resulting in the mismatch.

cc @blico @abhinav @vitarb

What version of rules_go are you using?

v0.21.2

What version of gazelle are you using?

v0.20.0

What version of Bazel are you using?

2.1.0

Does this issue reproduce with the latest releases of all the above?

Yes

What operating system and processor architecture are you using?

macOS, amd64

What did you do?

Run this test:

package xtools

import (
	"os"
	"testing"

	"golang.org/x/tools/go/analysis"
	"golang.org/x/tools/go/analysis/analysistest"
)

func Test(t *testing.T) {
	_ = os.Setenv("PATH", os.ExpandEnv("$TEST_SRCDIR/__main__/external/go_sdk/bin:$PATH"))
	a := &analysis.Analyzer{
		Run: func(p *analysis.Pass) (interface{}, error) {
			return nil, nil
		},
	}
	testdata := analysistest.TestData()
	analysistest.Run(t, testdata, a, "a")
}
load("@io_bazel_rules_go//go:def.bzl", "go_test")

go_test(
    name = "go_default_test",
    srcs = ["tool_test.go"],
    data = ["@go_sdk//:files"],
    deps = [
        "@org_golang_x_tools//go/analysis:go_default_library",
        "@org_golang_x_tools//go/analysis/analysistest:go_default_library",
    ],
)

What did you expect to see?

Test fail with error similar to xtools/testdata: no such file or directory *os.PathError

What did you see instead?

analysistest.go:103: go tool not available: 'go env GOROOT' does not match runtime.GOROOT:
    	go env: /private/var/tmp/_bazel_zplin/1b23f78923ad6c0028e8aab1a0a6d5fb/sandbox/darwin-sandbox/110/execroot/__main__/bazel-out/darwin-fastbuild/bin/xtools/darwin_amd64_stripped/go_default_test.runfiles/__main__/external/go_sdk
    	GOROOT: GOROOT

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 18 (15 by maintainers)

Commits related to this issue

Most upvoted comments

In case people running into the same issue in the future, this is the code we ended up with:

func TestMain(m *testing.M) {
	tempDir := os.Getenv("TEST_TMPDIR")
	srcDir := os.Getenv("TEST_SRCDIR")
	if len(tempDir) == 0 || len(srcDir) == 0 || runtime.GOROOT() != "GOROOT" {
		os.Exit(m.Run())
	}
	cmd := exec.Command(os.Args[0], os.Args[1:]...)
        // assuming the Bazel rule has `data = ["@go_sdk//:files"]`
	goRoot := filepath.Join(srcDir, "__main__/external/go_sdk")
	// Go executable requires a GOCACHE to be set after go1.12.
	cmd.Env = append(os.Environ(),
		"GOCACHE="+filepath.Join(tempDir, "cache"),
		"GOROOT="+goRoot,
		fmt.Sprintf("PATH=%s:%s", filepath.Join(goRoot, "bin"), os.Getenv("PATH")),
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err == nil {
		os.Exit(0)
	}
	if xerr, ok := err.(*exec.ExitError); ok {
		os.Exit(xerr.ExitCode())
	}
	fmt.Fprintln(os.Stderr, err)
	// Exist with 6, in line with Bazel's RUN_FAILURE.
	os.Exit(6)
}

Not sure if there is a better way to share this code

It turn out that runtime.GOROOT() only honors the GOROOT during init (https://github.com/golang/go/issues/22302). So I made it work with this:

package xtools

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"

	"golang.org/x/tools/go/analysis"
	"golang.org/x/tools/go/analysis/analysistest"
)

func Test(t *testing.T) {
	a := &analysis.Analyzer{
		Run: func(p *analysis.Pass) (interface{}, error) {
			return nil, nil
		},
	}
	testdata := analysistest.TestData()
	analysistest.Run(t, testdata, a, "a")
}

func init() {
	goRoot := "$TEST_SRCDIR/__main__/external/go_sdk"
	_ = os.Setenv("GOROOT", os.ExpandEnv(goRoot))
	_ = os.Setenv("PATH", os.ExpandEnv(fmt.Sprintf("%s:$PATH", filepath.Join(goRoot, "bin"))))
}