github.com/knieriem/gointernal@v0.2.0-pre2/cmd/go/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 "os" 13 "path/filepath" 14 "strings" 15 "sync" 16 ) 17 18 // These are general "build flags" used by build and other commands. 19 var ( 20 BuildX bool // -x flag 21 ) 22 23 // An EnvVar is an environment variable Name=Value, 24 // and an optional pointer to a corresponding variable 25 type EnvVar struct { 26 Name string 27 Value string 28 Var *string 29 } 30 31 // OrigEnv is the original environment of the program at startup. 32 var OrigEnv []string 33 34 // CmdEnv is the new environment for running go tool commands. 35 // User binaries (during go test or go run) are run with OrigEnv, 36 // not CmdEnv. 37 var CmdEnv []EnvVar 38 39 func SetupEnv(env []EnvVar) { 40 envFile, _ := EnvFile() 41 env = append(env, EnvVar{Name: EnvName, Value: envFile}) 42 for i := range env { 43 knownEnv += "\t" + env[i].Name + "\n" 44 } 45 for i := range env { 46 e := &env[i] 47 if v := Getenv(e.Name); v != "" { 48 e.Value = v 49 } 50 if e.Var != nil { 51 *e.Var = e.Value 52 } 53 } 54 CmdEnv = env 55 } 56 57 var envCache struct { 58 once sync.Once 59 m map[string]string 60 } 61 62 // Variables to be set by the main package 63 var ( 64 EnvName string 65 ConfigDirname string 66 knownEnv string 67 ) 68 69 // EnvFile returns the name of the Go environment configuration file. 70 func EnvFile() (string, error) { 71 if file := os.Getenv(EnvName); file != "" { 72 if file == "off" { 73 return "", fmt.Errorf("%s=off", EnvName) 74 } 75 return file, nil 76 } 77 dir, err := os.UserConfigDir() 78 if err != nil { 79 return "", err 80 } 81 if dir == "" { 82 return "", fmt.Errorf("missing user-config dir") 83 } 84 return filepath.Join(dir, ConfigDirname, "env"), nil 85 } 86 87 func initEnvCache() { 88 envCache.m = make(map[string]string) 89 file, _ := EnvFile() 90 if file == "" { 91 return 92 } 93 data, err := os.ReadFile(file) 94 if err != nil { 95 return 96 } 97 98 for len(data) > 0 { 99 // Get next line. 100 line := data 101 i := bytes.IndexByte(data, '\n') 102 if i >= 0 { 103 line, data = line[:i], data[i+1:] 104 } else { 105 data = nil 106 } 107 108 i = bytes.IndexByte(line, '=') 109 if i < 0 || line[0] < 'A' || 'Z' < line[0] { 110 // Line is missing = (or empty) or a comment or not a valid env name. Ignore. 111 // (This should not happen, since the file should be maintained almost 112 // exclusively by "go env -w", but better to silently ignore than to make 113 // the go command unusable just because somehow the env file has 114 // gotten corrupted.) 115 continue 116 } 117 key, val := line[:i], line[i+1:] 118 envCache.m[string(key)] = string(val) 119 } 120 } 121 122 // Getenv gets the value for the configuration key. 123 // It consults the operating system environment 124 // and then the go/env file. 125 // If Getenv is called for a key that cannot be set 126 // in the go/env file (for example GODEBUG), it panics. 127 // This ensures that CanGetenv is accurate, so that 128 // 'go env -w' stays in sync with what Getenv can retrieve. 129 func Getenv(key string) string { 130 if !CanGetenv(key) { 131 panic("internal error: invalid Getenv " + key) 132 } 133 val := os.Getenv(key) 134 if val != "" { 135 return val 136 } 137 envCache.once.Do(initEnvCache) 138 return envCache.m[key] 139 } 140 141 // CanGetenv reports whether key is a valid go/env configuration key. 142 func CanGetenv(key string) bool { 143 return strings.Contains(knownEnv, "\t"+key+"\n") 144 } 145 146 var ( 147 GOMODCACHE string 148 ) 149 150 // EnvOr returns Getenv(key) if set, or else def. 151 func EnvOr(key, def string) string { 152 val := Getenv(key) 153 if val == "" { 154 val = def 155 } 156 return val 157 }