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  }