github.com/containers/podman/v4@v4.9.4/pkg/env/env.go (about) 1 // Package for processing environment variables. 2 package env 3 4 // TODO: we need to add tests for this package. 5 6 import ( 7 "bufio" 8 "fmt" 9 "os" 10 "strings" 11 ) 12 13 const whiteSpaces = " \t" 14 15 // DefaultEnvVariables returns a default environment, with $PATH and $TERM set. 16 func DefaultEnvVariables() map[string]string { 17 return map[string]string{ 18 "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 19 "container": "podman", 20 } 21 } 22 23 // Slice transforms the specified map of environment variables into a 24 // slice. If a value is non-empty, the key and value are joined with '='. 25 func Slice(m map[string]string) []string { 26 env := make([]string, 0, len(m)) 27 for k, v := range m { 28 var s string 29 if len(v) > 0 { 30 s = fmt.Sprintf("%s=%s", k, v) 31 } else { 32 s = k 33 } 34 env = append(env, s) 35 } 36 return env 37 } 38 39 // Map transforms the specified slice of environment variables into a 40 // map. 41 func Map(slice []string) map[string]string { 42 envmap := make(map[string]string, len(slice)) 43 for _, val := range slice { 44 data := strings.SplitN(val, "=", 2) 45 46 if len(data) > 1 { 47 envmap[data[0]] = data[1] 48 } else { 49 envmap[data[0]] = "" 50 } 51 } 52 return envmap 53 } 54 55 // Join joins the two environment maps with override overriding base. 56 func Join(base map[string]string, override map[string]string) map[string]string { 57 if len(base) == 0 { 58 return override 59 } 60 for k, v := range override { 61 base[k] = v 62 } 63 return base 64 } 65 66 // ParseFile parses the specified path for environment variables and returns them 67 // as a map. 68 func ParseFile(path string) (_ map[string]string, err error) { 69 env := make(map[string]string) 70 defer func() { 71 if err != nil { 72 err = fmt.Errorf("parsing file %q: %w", path, err) 73 } 74 }() 75 76 fh, err := os.Open(path) 77 if err != nil { 78 return nil, err 79 } 80 defer fh.Close() 81 82 scanner := bufio.NewScanner(fh) 83 for scanner.Scan() { 84 // trim the line from all leading whitespace first 85 line := strings.TrimLeft(scanner.Text(), whiteSpaces) 86 // line is not empty, and not starting with '#' 87 if len(line) > 0 && !strings.HasPrefix(line, "#") { 88 if err := parseEnv(env, line); err != nil { 89 return nil, err 90 } 91 } 92 } 93 return env, scanner.Err() 94 } 95 96 func parseEnv(env map[string]string, line string) error { 97 data := strings.SplitN(line, "=", 2) 98 99 // catch invalid variables such as "=" or "=A" 100 if data[0] == "" { 101 return fmt.Errorf("invalid variable: %q", line) 102 } 103 // trim the front of a variable, but nothing else 104 name := strings.TrimLeft(data[0], whiteSpaces) 105 if len(data) > 1 { 106 env[name] = data[1] 107 } else { 108 if strings.HasSuffix(name, "*") { 109 name = strings.TrimSuffix(name, "*") 110 for _, e := range os.Environ() { 111 part := strings.SplitN(e, "=", 2) 112 if len(part) < 2 { 113 continue 114 } 115 if strings.HasPrefix(part[0], name) { 116 env[part[0]] = part[1] 117 } 118 } 119 } else if val, ok := os.LookupEnv(name); ok { 120 // if only a pass-through variable is given, clean it up. 121 env[name] = val 122 } 123 } 124 return nil 125 }