github.com/sirkon/goproxy@v1.4.8/internal/envcmd/env.go (about) 1 // Copyright 2012 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 envcmd implements the ``go env'' command. 6 package envcmd 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "os" 12 "path/filepath" 13 "runtime" 14 "strings" 15 16 "github.com/sirkon/goproxy/internal/base" 17 "github.com/sirkon/goproxy/internal/cache" 18 "github.com/sirkon/goproxy/internal/cfg" 19 "github.com/sirkon/goproxy/internal/load" 20 "github.com/sirkon/goproxy/internal/modload" 21 "github.com/sirkon/goproxy/internal/work" 22 ) 23 24 var CmdEnv = &base.Command{ 25 UsageLine: "go env [-json] [var ...]", 26 Short: "print Go environment information", 27 Long: ` 28 Env prints Go environment information. 29 30 By default env prints information as a shell cache 31 (on Windows, a batch file). If one or more variable 32 names is given as arguments, env prints the value of 33 each named variable on its own line. 34 35 The -json flag prints the environment in JSON format 36 instead of as a shell cache. 37 38 For more about environment variables, see 'go help environment'. 39 `, 40 } 41 42 func init() { 43 CmdEnv.Run = runEnv // break init cycle 44 } 45 46 var envJson = CmdEnv.Flag.Bool("json", false, "") 47 48 func MkEnv() []cfg.EnvVar { 49 var b work.Builder 50 b.Init() 51 52 env := []cfg.EnvVar{ 53 {Name: "GOARCH", Value: cfg.Goarch}, 54 {Name: "GOBIN", Value: cfg.GOBIN}, 55 {Name: "GOCACHE", Value: cache.DefaultDir()}, 56 {Name: "GOEXE", Value: cfg.ExeSuffix}, 57 {Name: "GOFLAGS", Value: os.Getenv("GOFLAGS")}, 58 {Name: "GOHOSTARCH", Value: runtime.GOARCH}, 59 {Name: "GOHOSTOS", Value: runtime.GOOS}, 60 {Name: "GOOS", Value: cfg.Goos}, 61 {Name: "GOPATH", Value: cfg.BuildContext.GOPATH}, 62 {Name: "GOPROXY", Value: os.Getenv("GOPROXY")}, 63 {Name: "GORACE", Value: os.Getenv("GORACE")}, 64 {Name: "GOROOT", Value: cfg.GOROOT}, 65 {Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")}, 66 {Name: "GOTOOLDIR", Value: base.ToolDir}, 67 } 68 69 if work.GccgoBin != "" { 70 env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoBin}) 71 } else { 72 env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoName}) 73 } 74 75 switch cfg.Goarch { 76 case "arm": 77 env = append(env, cfg.EnvVar{Name: "GOARM", Value: cfg.GOARM}) 78 case "386": 79 env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386}) 80 case "mips", "mipsle": 81 env = append(env, cfg.EnvVar{Name: "GOMIPS", Value: cfg.GOMIPS}) 82 case "mips64", "mips64le": 83 env = append(env, cfg.EnvVar{Name: "GOMIPS64", Value: cfg.GOMIPS64}) 84 } 85 86 cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch) 87 if env := strings.Fields(os.Getenv("CC")); len(env) > 0 { 88 cc = env[0] 89 } 90 cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch) 91 if env := strings.Fields(os.Getenv("CXX")); len(env) > 0 { 92 cxx = env[0] 93 } 94 env = append(env, cfg.EnvVar{Name: "CC", Value: cc}) 95 env = append(env, cfg.EnvVar{Name: "CXX", Value: cxx}) 96 97 if cfg.BuildContext.CgoEnabled { 98 env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "1"}) 99 } else { 100 env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "0"}) 101 } 102 103 return env 104 } 105 106 func findEnv(env []cfg.EnvVar, name string) string { 107 for _, e := range env { 108 if e.Name == name { 109 return e.Value 110 } 111 } 112 return "" 113 } 114 115 // ExtraEnvVars returns environment variables that should not leak into child processes. 116 func ExtraEnvVars() []cfg.EnvVar { 117 gomod := "" 118 if modload.Init(); modload.ModRoot != "" { 119 gomod = filepath.Join(modload.ModRoot, "go.mod") 120 } 121 return []cfg.EnvVar{ 122 {Name: "GOMOD", Value: gomod}, 123 } 124 } 125 126 // ExtraEnvVarsCostly returns environment variables that should not leak into child processes 127 // but are costly to evaluate. 128 func ExtraEnvVarsCostly() []cfg.EnvVar { 129 var b work.Builder 130 b.Init() 131 cppflags, cflags, cxxflags, fflags, ldflags, err := b.CFlags(&load.Package{}) 132 if err != nil { 133 // Should not happen - b.CFlags was given an empty package. 134 fmt.Fprintf(os.Stderr, "go: invalid cflags: %v\n", err) 135 return nil 136 } 137 cmd := b.GccCmd(".", "") 138 139 return []cfg.EnvVar{ 140 // Note: Update the switch in runEnv below when adding to this list. 141 {Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")}, 142 {Name: "CGO_CPPFLAGS", Value: strings.Join(cppflags, " ")}, 143 {Name: "CGO_CXXFLAGS", Value: strings.Join(cxxflags, " ")}, 144 {Name: "CGO_FFLAGS", Value: strings.Join(fflags, " ")}, 145 {Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")}, 146 {Name: "PKG_CONFIG", Value: b.PkgconfigCmd()}, 147 {Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")}, 148 } 149 } 150 151 func runEnv(cmd *base.Command, args []string) { 152 env := cfg.CmdEnv 153 env = append(env, ExtraEnvVars()...) 154 155 // Do we need to call ExtraEnvVarsCostly, which is a bit expensive? 156 // Only if we're listing all environment variables ("go env") 157 // or the variables being requested are in the extra list. 158 needCostly := true 159 if len(args) > 0 { 160 needCostly = false 161 for _, arg := range args { 162 switch arg { 163 case "CGO_CFLAGS", 164 "CGO_CPPFLAGS", 165 "CGO_CXXFLAGS", 166 "CGO_FFLAGS", 167 "CGO_LDFLAGS", 168 "PKG_CONFIG", 169 "GOGCCFLAGS": 170 needCostly = true 171 } 172 } 173 } 174 if needCostly { 175 env = append(env, ExtraEnvVarsCostly()...) 176 } 177 178 if len(args) > 0 { 179 if *envJson { 180 var es []cfg.EnvVar 181 for _, name := range args { 182 e := cfg.EnvVar{Name: name, Value: findEnv(env, name)} 183 es = append(es, e) 184 } 185 printEnvAsJSON(es) 186 } else { 187 for _, name := range args { 188 fmt.Printf("%s\n", findEnv(env, name)) 189 } 190 } 191 return 192 } 193 194 if *envJson { 195 printEnvAsJSON(env) 196 return 197 } 198 199 for _, e := range env { 200 if e.Name != "TERM" { 201 switch runtime.GOOS { 202 default: 203 fmt.Printf("%s=\"%s\"\n", e.Name, e.Value) 204 case "plan9": 205 if strings.IndexByte(e.Value, '\x00') < 0 { 206 fmt.Printf("%s='%s'\n", e.Name, strings.Replace(e.Value, "'", "''", -1)) 207 } else { 208 v := strings.Split(e.Value, "\x00") 209 fmt.Printf("%s=(", e.Name) 210 for x, s := range v { 211 if x > 0 { 212 fmt.Printf(" ") 213 } 214 fmt.Printf("%s", s) 215 } 216 fmt.Printf(")\n") 217 } 218 case "windows": 219 fmt.Printf("set %s=%s\n", e.Name, e.Value) 220 } 221 } 222 } 223 } 224 225 func printEnvAsJSON(env []cfg.EnvVar) { 226 m := make(map[string]string) 227 for _, e := range env { 228 if e.Name == "TERM" { 229 continue 230 } 231 m[e.Name] = e.Value 232 } 233 enc := json.NewEncoder(os.Stdout) 234 enc.SetIndent("", "\t") 235 if err := enc.Encode(m); err != nil { 236 base.Fatalf("%s", err) 237 } 238 }