From 774c86e21b443cbb5eef4315e1c7cebd118f8e73 Mon Sep 17 00:00:00 2001 From: ardnew Date: Sun, 14 Mar 2021 16:26:44 -0500 Subject: [PATCH] goenv: use physical path instead of cached GOROOT in function getGoroot (fixes #433, #1658) --- goenv/goenv.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/goenv/goenv.go b/goenv/goenv.go index fb5e353d..9db71552 100644 --- a/goenv/goenv.go +++ b/goenv/goenv.go @@ -142,10 +142,11 @@ func getHomeDir() string { // getGoroot returns an appropriate GOROOT from various sources. If it can't be // found, it returns an empty string. func getGoroot() string { + // An explicitly set GOROOT always has preference. goroot := os.Getenv("GOROOT") if goroot != "" { - // An explicitly set GOROOT always has preference. - return goroot + // Convert to the standard GOROOT being referenced, if it's a TinyGo cache. + return getStandardGoroot(goroot) } // Check for the location of the 'go' binary and base GOROOT on that. @@ -195,3 +196,21 @@ func isGoroot(goroot string) bool { _, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go")) return err == nil } + +// getStandardGoroot returns the physical path to a real, standard Go GOROOT +// implied by the given path. +// If the given path appears to be a TinyGo cached GOROOT, it returns the path +// referenced by symlinks contained in the cache. Otherwise, it returns the +// given path as-is. +func getStandardGoroot(path string) string { + // Check if the "bin" subdirectory of our given GOROOT is a symlink, and then + // return the _parent_ directory of its destination. + if dest, err := os.Readlink(filepath.Join(path, "bin")); nil == err { + // Clean the destination to remove any trailing slashes, so that + // filepath.Dir will always return the parent. + // (because both "/foo" and "/foo/" are valid symlink destinations, + // but filepath.Dir would return "/" and "/foo", respectively) + return filepath.Dir(filepath.Clean(dest)) + } + return path +}