Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / gobuffalo / envy / envy.go
1 /*
2 package envy makes working with ENV variables in Go trivial.
3
4 * Get ENV variables with default values.
5 * Set ENV variables safely without affecting the underlying system.
6 * Temporarily change ENV vars; useful for testing.
7 * Map all of the key/values in the ENV.
8 * Loads .env files (by using [godotenv](https://github.com/joho/godotenv/))
9 * More!
10 */
11 package envy
12
13 import (
14         "errors"
15         "flag"
16         "fmt"
17         "io/ioutil"
18         "os"
19         "os/exec"
20         "path/filepath"
21         "runtime"
22         "strings"
23         "sync"
24
25         "github.com/joho/godotenv"
26         "github.com/rogpeppe/go-internal/modfile"
27 )
28
29 var gil = &sync.RWMutex{}
30 var env = map[string]string{}
31
32 // GO111MODULE is ENV for turning mods on/off
33 const GO111MODULE = "GO111MODULE"
34
35 func init() {
36         Load()
37         loadEnv()
38 }
39
40 // Load the ENV variables to the env map
41 func loadEnv() {
42         gil.Lock()
43         defer gil.Unlock()
44
45         if os.Getenv("GO_ENV") == "" {
46                 // if the flag "test.v" is *defined*, we're running as a unit test. Note that we don't care
47                 // about v.Value (verbose test mode); we just want to know if the test environment has defined
48                 // it. It's also possible that the flags are not yet fully parsed (i.e. flag.Parsed() == false),
49                 // so we could not depend on v.Value anyway.
50                 //
51                 if v := flag.Lookup("test.v"); v != nil {
52                         env["GO_ENV"] = "test"
53                 }
54         }
55
56         // set the GOPATH if using >= 1.8 and the GOPATH isn't set
57         if os.Getenv("GOPATH") == "" {
58                 out, err := exec.Command("go", "env", "GOPATH").Output()
59                 if err == nil {
60                         gp := strings.TrimSpace(string(out))
61                         os.Setenv("GOPATH", gp)
62                 }
63         }
64
65         for _, e := range os.Environ() {
66                 pair := strings.Split(e, "=")
67                 env[pair[0]] = os.Getenv(pair[0])
68         }
69 }
70
71 func Mods() bool {
72         return Get(GO111MODULE, "off") == "on"
73 }
74
75 // Reload the ENV variables. Useful if
76 // an external ENV manager has been used
77 func Reload() {
78         env = map[string]string{}
79         loadEnv()
80 }
81
82 // Load .env files. Files will be loaded in the same order that are received.
83 // Redefined vars will override previously existing values.
84 // IE: envy.Load(".env", "test_env/.env") will result in DIR=test_env
85 // If no arg passed, it will try to load a .env file.
86 func Load(files ...string) error {
87
88         // If no files received, load the default one
89         if len(files) == 0 {
90                 err := godotenv.Overload()
91                 if err == nil {
92                         Reload()
93                 }
94                 return err
95         }
96
97         // We received a list of files
98         for _, file := range files {
99
100                 // Check if it exists or we can access
101                 if _, err := os.Stat(file); err != nil {
102                         // It does not exist or we can not access.
103                         // Return and stop loading
104                         return err
105                 }
106
107                 // It exists and we have permission. Load it
108                 if err := godotenv.Overload(file); err != nil {
109                         return err
110                 }
111
112                 // Reload the env so all new changes are noticed
113                 Reload()
114
115         }
116         return nil
117 }
118
119 // Get a value from the ENV. If it doesn't exist the
120 // default value will be returned.
121 func Get(key string, value string) string {
122         gil.RLock()
123         defer gil.RUnlock()
124         if v, ok := env[key]; ok {
125                 return v
126         }
127         return value
128 }
129
130 // Get a value from the ENV. If it doesn't exist
131 // an error will be returned
132 func MustGet(key string) (string, error) {
133         gil.RLock()
134         defer gil.RUnlock()
135         if v, ok := env[key]; ok {
136                 return v, nil
137         }
138         return "", fmt.Errorf("could not find ENV var with %s", key)
139 }
140
141 // Set a value into the ENV. This is NOT permanent. It will
142 // only affect values accessed through envy.
143 func Set(key string, value string) {
144         gil.Lock()
145         defer gil.Unlock()
146         env[key] = value
147 }
148
149 // MustSet the value into the underlying ENV, as well as envy.
150 // This may return an error if there is a problem setting the
151 // underlying ENV value.
152 func MustSet(key string, value string) error {
153         gil.Lock()
154         defer gil.Unlock()
155         err := os.Setenv(key, value)
156         if err != nil {
157                 return err
158         }
159         env[key] = value
160         return nil
161 }
162
163 // Map all of the keys/values set in envy.
164 func Map() map[string]string {
165         gil.RLock()
166         defer gil.RUnlock()
167         cp := map[string]string{}
168         for k, v := range env {
169                 cp[k] = v
170         }
171         return env
172 }
173
174 // Temp makes a copy of the values and allows operation on
175 // those values temporarily during the run of the function.
176 // At the end of the function run the copy is discarded and
177 // the original values are replaced. This is useful for testing.
178 // Warning: This function is NOT safe to use from a goroutine or
179 // from code which may access any Get or Set function from a goroutine
180 func Temp(f func()) {
181         oenv := env
182         env = map[string]string{}
183         for k, v := range oenv {
184                 env[k] = v
185         }
186         defer func() { env = oenv }()
187         f()
188 }
189
190 func GoPath() string {
191         return Get("GOPATH", "")
192 }
193
194 func GoBin() string {
195         return Get("GO_BIN", "go")
196 }
197
198 func InGoPath() bool {
199         pwd, _ := os.Getwd()
200         for _, p := range GoPaths() {
201                 if strings.HasPrefix(pwd, p) {
202                         return true
203                 }
204         }
205         return false
206 }
207
208 // GoPaths returns all possible GOPATHS that are set.
209 func GoPaths() []string {
210         gp := Get("GOPATH", "")
211         if runtime.GOOS == "windows" {
212                 return strings.Split(gp, ";") // Windows uses a different separator
213         }
214         return strings.Split(gp, ":")
215 }
216
217 func importPath(path string) string {
218         path = strings.TrimPrefix(path, "/private")
219         for _, gopath := range GoPaths() {
220                 srcpath := filepath.Join(gopath, "src")
221                 rel, err := filepath.Rel(srcpath, path)
222                 if err == nil {
223                         return filepath.ToSlash(rel)
224                 }
225         }
226
227         // fallback to trim
228         rel := strings.TrimPrefix(path, filepath.Join(GoPath(), "src"))
229         rel = strings.TrimPrefix(rel, string(filepath.Separator))
230         return filepath.ToSlash(rel)
231 }
232
233 // CurrentModule will attempt to return the module name from `go.mod` if
234 // modules are enabled.
235 // If modules are not enabled it will fallback to using CurrentPackage instead.
236 func CurrentModule() (string, error) {
237         if !Mods() {
238                 return CurrentPackage(), nil
239         }
240         moddata, err := ioutil.ReadFile("go.mod")
241         if err != nil {
242                 return "", errors.New("go.mod cannot be read or does not exist while go module is enabled")
243         }
244         packagePath := modfile.ModulePath(moddata)
245         if packagePath == "" {
246                 return "", errors.New("go.mod is malformed")
247         }
248         return packagePath, nil
249 }
250
251 // CurrentPackage attempts to figure out the current package name from the PWD
252 // Use CurrentModule for a more accurate package name.
253 func CurrentPackage() string {
254         if Mods() {
255         }
256         pwd, _ := os.Getwd()
257         return importPath(pwd)
258 }
259
260 func Environ() []string {
261         gil.RLock()
262         defer gil.RUnlock()
263         var e []string
264         for k, v := range env {
265                 e = append(e, fmt.Sprintf("%s=%s", k, v))
266         }
267         return e
268 }