|
|
|
|
@ -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 { |
|
|
|
|
|