diff --git a/tstest/integration/integration.go b/tstest/integration/integration.go index 560913596..32ee4ddb8 100644 --- a/tstest/integration/integration.go +++ b/tstest/integration/integration.go @@ -129,16 +129,31 @@ func build(outDir string, targets ...string) error { } func findGo() (string, error) { - goBin := filepath.Join(runtime.GOROOT(), "bin", "go"+exe()) - if fi, err := os.Stat(goBin); err != nil { - if os.IsNotExist(err) { - return "", fmt.Errorf("failed to find go at %v", goBin) + // Go 1.19 attempted to be helpful by prepending $PATH with GOROOT/bin based + // on the executed go binary when invoked using `go test` or `go generate`, + // however, this doesn't cover cases when run otherwise, such as via `go run`. + // runtime.GOROOT() may often be empty these days, so the safe thing to do + // here is, in order: + // 1. Look for a go binary in $PATH[0]. + // 2. Look for a go binary in runtime.GOROOT()/bin if runtime.GOROOT() is non-empty. + // 3. Look for a go binary in $PATH. + + paths := strings.FieldsFunc(os.Getenv("PATH"), func(r rune) bool { return os.IsPathSeparator(uint8(r)) }) + if len(paths) > 0 { + candidate := filepath.Join(paths[0], "go"+exe()) + if path, err := exec.LookPath(candidate); err == nil { + return path, err } - return "", fmt.Errorf("looking for go binary: %v", err) - } else if !fi.Mode().IsRegular() { - return "", fmt.Errorf("%v is unexpected %v", goBin, fi.Mode()) } - return goBin, nil + + if runtime.GOROOT() != "" { + candidate := filepath.Join(runtime.GOROOT(), "bin", "go"+exe()) + if path, err := exec.LookPath(candidate); err == nil { + return path, err + } + } + + return exec.LookPath("go") } func exe() string {