forked from tinygo-org/tinygo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
main: refactor environment variables into a separate package
This makes it possible to query these environment variables from anywhere, which might be useful. More importantly, it puts them in a central location from where they can be queried, useful for a `go env` subcommand.
- Loading branch information
1 parent
2a71aa9
commit 2463153
Showing
7 changed files
with
214 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// Package goenv returns environment variables that are used in various parts of | ||
// the compiler. You can query it manually with the `tinygo env` subcommand. | ||
package goenv | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"os/user" | ||
"path/filepath" | ||
"runtime" | ||
) | ||
|
||
// Keys is a slice of all available environment variable keys. | ||
var Keys = []string{ | ||
"GOOS", | ||
"GOARCH", | ||
"GOROOT", | ||
"GOPATH", | ||
"GOCACHE", | ||
"TINYGOROOT", | ||
} | ||
|
||
// TINYGOROOT is the path to the final location for checking tinygo files. If | ||
// unset (by a -X ldflag), then sourceDir() will fallback to the original build | ||
// directory. | ||
var TINYGOROOT string | ||
|
||
// Get returns a single environment variable, possibly calculating it on-demand. | ||
// The empty string is returned for unknown environment variables. | ||
func Get(name string) string { | ||
switch name { | ||
case "GOOS": | ||
if dir := os.Getenv("GOOS"); dir != "" { | ||
return dir | ||
} | ||
return runtime.GOOS | ||
case "GOARCH": | ||
if dir := os.Getenv("GOARCH"); dir != "" { | ||
return dir | ||
} | ||
return runtime.GOARCH | ||
case "GOROOT": | ||
return getGoroot() | ||
case "GOPATH": | ||
if dir := os.Getenv("GOPATH"); dir != "" { | ||
return dir | ||
} | ||
|
||
// fallback | ||
home := getHomeDir() | ||
return filepath.Join(home, "go") | ||
case "GOCACHE": | ||
// Get the cache directory, usually ~/.cache/tinygo | ||
dir, err := os.UserCacheDir() | ||
if err != nil { | ||
panic("could not find cache dir: " + err.Error()) | ||
} | ||
return filepath.Join(dir, "tinygo") | ||
case "TINYGOROOT": | ||
return sourceDir() | ||
default: | ||
return "" | ||
} | ||
} | ||
|
||
// Return the TINYGOROOT, or exit with an error. | ||
func sourceDir() string { | ||
// Use $TINYGOROOT as root, if available. | ||
root := os.Getenv("TINYGOROOT") | ||
if root != "" { | ||
if !isSourceDir(root) { | ||
fmt.Fprintln(os.Stderr, "error: $TINYGOROOT was not set to the correct root") | ||
os.Exit(1) | ||
} | ||
return root | ||
} | ||
|
||
if TINYGOROOT != "" { | ||
if !isSourceDir(TINYGOROOT) { | ||
fmt.Fprintln(os.Stderr, "error: TINYGOROOT was not set to the correct root") | ||
os.Exit(1) | ||
} | ||
return TINYGOROOT | ||
} | ||
|
||
// Find root from executable path. | ||
path, err := os.Executable() | ||
if err != nil { | ||
// Very unlikely. Bail out if it happens. | ||
panic("could not get executable path: " + err.Error()) | ||
} | ||
root = filepath.Dir(filepath.Dir(path)) | ||
if isSourceDir(root) { | ||
return root | ||
} | ||
|
||
// Fallback: use the original directory from where it was built | ||
// https://stackoverflow.com/a/32163888/559350 | ||
_, path, _, _ = runtime.Caller(0) | ||
root = filepath.Dir(filepath.Dir(path)) | ||
if isSourceDir(root) { | ||
return root | ||
} | ||
|
||
fmt.Fprintln(os.Stderr, "error: could not autodetect root directory, set the TINYGOROOT environment variable to override") | ||
os.Exit(1) | ||
panic("unreachable") | ||
} | ||
|
||
// isSourceDir returns true if the directory looks like a TinyGo source directory. | ||
func isSourceDir(root string) bool { | ||
_, err := os.Stat(filepath.Join(root, "src/runtime/internal/sys/zversion.go")) | ||
if err != nil { | ||
return false | ||
} | ||
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go")) | ||
return err == nil | ||
} | ||
|
||
func getHomeDir() string { | ||
u, err := user.Current() | ||
if err != nil { | ||
panic("cannot get current user: " + err.Error()) | ||
} | ||
if u.HomeDir == "" { | ||
// This is very unlikely, so panic here. | ||
// Not the nicest solution, however. | ||
panic("could not find home directory") | ||
} | ||
return u.HomeDir | ||
} | ||
|
||
// getGoroot returns an appropriate GOROOT from various sources. If it can't be | ||
// found, it returns an empty string. | ||
func getGoroot() string { | ||
goroot := os.Getenv("GOROOT") | ||
if goroot != "" { | ||
// An explicitly set GOROOT always has preference. | ||
return goroot | ||
} | ||
|
||
// Check for the location of the 'go' binary and base GOROOT on that. | ||
binpath, err := exec.LookPath("go") | ||
if err == nil { | ||
binpath, err = filepath.EvalSymlinks(binpath) | ||
if err == nil { | ||
goroot := filepath.Dir(filepath.Dir(binpath)) | ||
if isGoroot(goroot) { | ||
return goroot | ||
} | ||
} | ||
} | ||
|
||
// Check what GOROOT was at compile time. | ||
if isGoroot(runtime.GOROOT()) { | ||
return runtime.GOROOT() | ||
} | ||
|
||
// Check for some standard locations, as a last resort. | ||
var candidates []string | ||
switch runtime.GOOS { | ||
case "linux": | ||
candidates = []string{ | ||
"/usr/local/go", // manually installed | ||
"/usr/lib/go", // from the distribution | ||
} | ||
case "darwin": | ||
candidates = []string{ | ||
"/usr/local/go", // manually installed | ||
"/usr/local/opt/go/libexec", // from Homebrew | ||
} | ||
} | ||
|
||
for _, candidate := range candidates { | ||
if isGoroot(candidate) { | ||
return candidate | ||
} | ||
} | ||
|
||
// Can't find GOROOT... | ||
return "" | ||
} | ||
|
||
// isGoroot checks whether the given path looks like a GOROOT. | ||
func isGoroot(goroot string) bool { | ||
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go")) | ||
return err == nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.