github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/cfg/cfg.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package cfg holds configuration shared by multiple parts
     6  // of the go command.
     7  package cfg
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"go/build"
    13  	"github.com/gagliardetto/golang-go/not-internal/cfg"
    14  	"io/ioutil"
    15  	"os"
    16  	"path/filepath"
    17  	"runtime"
    18  	"strings"
    19  	"sync"
    20  
    21  	"github.com/gagliardetto/golang-go/cmd/internal/objabi"
    22  )
    23  
    24  // These are general "build flags" used by build and other commands.
    25  var (
    26  	BuildA                 bool   // -a flag
    27  	BuildBuildmode         string // -buildmode flag
    28  	BuildContext           = defaultContext()
    29  	BuildMod               string             // -mod flag
    30  	BuildModReason         string             // reason -mod flag is set, if set by default
    31  	BuildI                 bool               // -i flag
    32  	BuildLinkshared        bool               // -linkshared flag
    33  	BuildMSan              bool               // -msan flag
    34  	BuildN                 bool               // -n flag
    35  	BuildO                 string             // -o flag
    36  	BuildP                 = runtime.NumCPU() // -p flag
    37  	BuildPkgdir            string             // -pkgdir flag
    38  	BuildRace              bool               // -race flag
    39  	BuildToolexec          []string           // -toolexec flag
    40  	BuildToolchainName     string
    41  	BuildToolchainCompiler func() string
    42  	BuildToolchainLinker   func() string
    43  	BuildTrimpath          bool // -trimpath flag
    44  	BuildV                 bool // -v flag
    45  	BuildWork              bool // -work flag
    46  	BuildX                 bool // -x flag
    47  
    48  	ModCacheRW bool   // -modcacherw flag
    49  	ModFile    string // -modfile flag
    50  
    51  	CmdName string // "build", "install", "list", "mod tidy", etc.
    52  
    53  	DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
    54  )
    55  
    56  func defaultContext() build.Context {
    57  	ctxt := build.Default
    58  	ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
    59  
    60  	ctxt.GOROOT = findGOROOT()
    61  	if runtime.Compiler != "gccgo" {
    62  		// Note that we must use runtime.GOOS and runtime.GOARCH here,
    63  		// as the tool directory does not move based on environment
    64  		// variables. This matches the initialization of ToolDir in
    65  		// go/build, except for using ctxt.GOROOT rather than
    66  		// runtime.GOROOT.
    67  		build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
    68  	}
    69  
    70  	ctxt.GOPATH = envOr("GOPATH", ctxt.GOPATH)
    71  
    72  	// Override defaults computed in go/build with defaults
    73  	// from go environment configuration file, if known.
    74  	ctxt.GOOS = envOr("GOOS", ctxt.GOOS)
    75  	ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH)
    76  
    77  	// The go/build rule for whether cgo is enabled is:
    78  	//	1. If $CGO_ENABLED is set, respect it.
    79  	//	2. Otherwise, if this is a cross-compile, disable cgo.
    80  	//	3. Otherwise, use built-in default for GOOS/GOARCH.
    81  	// Recreate that logic here with the new GOOS/GOARCH setting.
    82  	if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" {
    83  		ctxt.CgoEnabled = v[0] == '1'
    84  	} else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH {
    85  		ctxt.CgoEnabled = false
    86  	} else {
    87  		// Use built-in default cgo setting for GOOS/GOARCH.
    88  		// Note that ctxt.GOOS/GOARCH are derived from the preference list
    89  		// (1) environment, (2) go/env file, (3) runtime constants,
    90  		// while go/build.Default.GOOS/GOARCH are derived from the preference list
    91  		// (1) environment, (2) runtime constants.
    92  		// We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH;
    93  		// no matter how that happened, go/build.Default will make the
    94  		// same decision (either the environment variables are set explicitly
    95  		// to match the runtime constants, or else they are unset, in which
    96  		// case go/build falls back to the runtime constants), so
    97  		// go/build.Default.GOOS/GOARCH == runtime.GOOS/GOARCH.
    98  		// So ctxt.CgoEnabled (== go/build.Default.CgoEnabled) is correct
    99  		// as is and can be left unmodified.
   100  		// Nothing to do here.
   101  	}
   102  
   103  	return ctxt
   104  }
   105  
   106  func init() {
   107  	BuildToolchainCompiler = func() string { return "missing-compiler" }
   108  	BuildToolchainLinker = func() string { return "missing-linker" }
   109  }
   110  
   111  // An EnvVar is an environment variable Name=Value.
   112  type EnvVar struct {
   113  	Name  string
   114  	Value string
   115  }
   116  
   117  // OrigEnv is the original environment of the program at startup.
   118  var OrigEnv []string
   119  
   120  // CmdEnv is the new environment for running go tool commands.
   121  // User binaries (during go test or go run) are run with OrigEnv,
   122  // not CmdEnv.
   123  var CmdEnv []EnvVar
   124  
   125  // Global build parameters (used during package load)
   126  var (
   127  	Goarch = BuildContext.GOARCH
   128  	Goos   = BuildContext.GOOS
   129  
   130  	ExeSuffix = exeSuffix()
   131  
   132  	// ModulesEnabled specifies whether the go command is running
   133  	// in module-aware mode (as opposed to GOPATH mode).
   134  	// It is equal to modload.Enabled, but not all packages can import modload.
   135  	ModulesEnabled bool
   136  )
   137  
   138  func exeSuffix() string {
   139  	if Goos == "windows" {
   140  		return ".exe"
   141  	}
   142  	return ""
   143  }
   144  
   145  var envCache struct {
   146  	once sync.Once
   147  	m    map[string]string
   148  }
   149  
   150  // EnvFile returns the name of the Go environment configuration file.
   151  func EnvFile() (string, error) {
   152  	if file := os.Getenv("GOENV"); file != "" {
   153  		if file == "off" {
   154  			return "", fmt.Errorf("GOENV=off")
   155  		}
   156  		return file, nil
   157  	}
   158  	dir, err := os.UserConfigDir()
   159  	if err != nil {
   160  		return "", err
   161  	}
   162  	if dir == "" {
   163  		return "", fmt.Errorf("missing user-config dir")
   164  	}
   165  	return filepath.Join(dir, "go/env"), nil
   166  }
   167  
   168  func initEnvCache() {
   169  	envCache.m = make(map[string]string)
   170  	file, _ := EnvFile()
   171  	if file == "" {
   172  		return
   173  	}
   174  	data, err := ioutil.ReadFile(file)
   175  	if err != nil {
   176  		return
   177  	}
   178  
   179  	for len(data) > 0 {
   180  		// Get next line.
   181  		line := data
   182  		i := bytes.IndexByte(data, '\n')
   183  		if i >= 0 {
   184  			line, data = line[:i], data[i+1:]
   185  		} else {
   186  			data = nil
   187  		}
   188  
   189  		i = bytes.IndexByte(line, '=')
   190  		if i < 0 || line[0] < 'A' || 'Z' < line[0] {
   191  			// Line is missing = (or empty) or a comment or not a valid env name. Ignore.
   192  			// (This should not happen, since the file should be maintained almost
   193  			// exclusively by "go env -w", but better to silently ignore than to make
   194  			// the go command unusable just because somehow the env file has
   195  			// gotten corrupted.)
   196  			continue
   197  		}
   198  		key, val := line[:i], line[i+1:]
   199  		envCache.m[string(key)] = string(val)
   200  	}
   201  }
   202  
   203  // Getenv gets the value for the configuration key.
   204  // It consults the operating system environment
   205  // and then the go/env file.
   206  // If Getenv is called for a key that cannot be set
   207  // in the go/env file (for example GODEBUG), it panics.
   208  // This ensures that CanGetenv is accurate, so that
   209  // 'go env -w' stays in sync with what Getenv can retrieve.
   210  func Getenv(key string) string {
   211  	if !CanGetenv(key) {
   212  		switch key {
   213  		case "CGO_TEST_ALLOW", "CGO_TEST_DISALLOW", "CGO_test_ALLOW", "CGO_test_DISALLOW":
   214  			// used by internal/work/security_test.go; allow
   215  		default:
   216  			panic("internal error: invalid Getenv " + key)
   217  		}
   218  	}
   219  	val := os.Getenv(key)
   220  	if val != "" {
   221  		return val
   222  	}
   223  	envCache.once.Do(initEnvCache)
   224  	return envCache.m[key]
   225  }
   226  
   227  // CanGetenv reports whether key is a valid go/env configuration key.
   228  func CanGetenv(key string) bool {
   229  	return strings.Contains(cfg.KnownEnv, "\t"+key+"\n")
   230  }
   231  
   232  var (
   233  	GOROOT       = BuildContext.GOROOT
   234  	GOBIN        = Getenv("GOBIN")
   235  	GOROOTbin    = filepath.Join(GOROOT, "bin")
   236  	GOROOTpkg    = filepath.Join(GOROOT, "pkg")
   237  	GOROOTsrc    = filepath.Join(GOROOT, "src")
   238  	GOROOT_FINAL = findGOROOT_FINAL()
   239  
   240  	// Used in envcmd.MkEnv and build ID computations.
   241  	GOARM    = envOr("GOARM", fmt.Sprint(objabi.GOARM))
   242  	GO386    = envOr("GO386", objabi.GO386)
   243  	GOMIPS   = envOr("GOMIPS", objabi.GOMIPS)
   244  	GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
   245  	GOPPC64  = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
   246  	GOWASM   = envOr("GOWASM", fmt.Sprint(objabi.GOWASM))
   247  
   248  	GOPROXY    = envOr("GOPROXY", "https://proxy.golang.org,direct")
   249  	GOSUMDB    = envOr("GOSUMDB", "sum.golang.org")
   250  	GOPRIVATE  = Getenv("GOPRIVATE")
   251  	GONOPROXY  = envOr("GONOPROXY", GOPRIVATE)
   252  	GONOSUMDB  = envOr("GONOSUMDB", GOPRIVATE)
   253  	GOINSECURE = Getenv("GOINSECURE")
   254  )
   255  
   256  // GetArchEnv returns the name and setting of the
   257  // GOARCH-specific architecture environment variable.
   258  // If the current architecture has no GOARCH-specific variable,
   259  // GetArchEnv returns empty key and value.
   260  func GetArchEnv() (key, val string) {
   261  	switch Goarch {
   262  	case "arm":
   263  		return "GOARM", GOARM
   264  	case "386":
   265  		return "GO386", GO386
   266  	case "mips", "mipsle":
   267  		return "GOMIPS", GOMIPS
   268  	case "mips64", "mips64le":
   269  		return "GOMIPS64", GOMIPS64
   270  	case "ppc64", "ppc64le":
   271  		return "GOPPC64", GOPPC64
   272  	case "wasm":
   273  		return "GOWASM", GOWASM
   274  	}
   275  	return "", ""
   276  }
   277  
   278  // envOr returns Getenv(key) if set, or else def.
   279  func envOr(key, def string) string {
   280  	val := Getenv(key)
   281  	if val == "" {
   282  		val = def
   283  	}
   284  	return val
   285  }
   286  
   287  // There is a copy of findGOROOT, isSameDir, and isGOROOT in
   288  // x/tools/cmd/godoc/goroot.go.
   289  // Try to keep them in sync for now.
   290  
   291  // findGOROOT returns the GOROOT value, using either an explicitly
   292  // provided environment variable, a GOROOT that contains the current
   293  // os.Executable value, or else the GOROOT that the binary was built
   294  // with from runtime.GOROOT().
   295  //
   296  // There is a copy of this code in x/tools/cmd/godoc/goroot.go.
   297  func findGOROOT() string {
   298  	if env := Getenv("GOROOT"); env != "" {
   299  		return filepath.Clean(env)
   300  	}
   301  	def := filepath.Clean(runtime.GOROOT())
   302  	if runtime.Compiler == "gccgo" {
   303  		// gccgo has no real GOROOT, and it certainly doesn't
   304  		// depend on the executable's location.
   305  		return def
   306  	}
   307  	exe, err := os.Executable()
   308  	if err == nil {
   309  		exe, err = filepath.Abs(exe)
   310  		if err == nil {
   311  			if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
   312  				// If def (runtime.GOROOT()) and dir are the same
   313  				// directory, prefer the spelling used in def.
   314  				if isSameDir(def, dir) {
   315  					return def
   316  				}
   317  				return dir
   318  			}
   319  			exe, err = filepath.EvalSymlinks(exe)
   320  			if err == nil {
   321  				if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
   322  					if isSameDir(def, dir) {
   323  						return def
   324  					}
   325  					return dir
   326  				}
   327  			}
   328  		}
   329  	}
   330  	return def
   331  }
   332  
   333  func findGOROOT_FINAL() string {
   334  	// $GOROOT_FINAL is only for use during make.bash
   335  	// so it is not settable using go/env, so we use os.Getenv here.
   336  	def := GOROOT
   337  	if env := os.Getenv("GOROOT_FINAL"); env != "" {
   338  		def = filepath.Clean(env)
   339  	}
   340  	return def
   341  }
   342  
   343  // isSameDir reports whether dir1 and dir2 are the same directory.
   344  func isSameDir(dir1, dir2 string) bool {
   345  	if dir1 == dir2 {
   346  		return true
   347  	}
   348  	info1, err1 := os.Stat(dir1)
   349  	info2, err2 := os.Stat(dir2)
   350  	return err1 == nil && err2 == nil && os.SameFile(info1, info2)
   351  }
   352  
   353  // isGOROOT reports whether path looks like a GOROOT.
   354  //
   355  // It does this by looking for the path/pkg/tool directory,
   356  // which is necessary for useful operation of the cmd/go tool,
   357  // and is not typically present in a GOPATH.
   358  //
   359  // There is a copy of this code in x/tools/cmd/godoc/goroot.go.
   360  func isGOROOT(path string) bool {
   361  	stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
   362  	if err != nil {
   363  		return false
   364  	}
   365  	return stat.IsDir()
   366  }