1 // Copyright 2017 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package build 16 17 import ( 18 "bufio" 19 "fmt" 20 "io" 21 "os" 22 "strings" 23 ) 24 25 // Environment adds a number of useful manipulation functions to the list of 26 // strings returned by os.Environ() and used in exec.Cmd.Env. 27 type Environment []string 28 29 // OsEnvironment wraps the current environment returned by os.Environ() 30 func OsEnvironment() *Environment { 31 env := Environment(os.Environ()) 32 return &env 33 } 34 35 // Get returns the value associated with the key, and whether it exists. 36 // It's equivalent to the os.LookupEnv function, but with this copy of the 37 // Environment. 38 func (e *Environment) Get(key string) (string, bool) { 39 for _, env := range *e { 40 if k, v, ok := decodeKeyValue(env); ok && k == key { 41 return v, true 42 } 43 } 44 return "", false 45 } 46 47 // Set sets the value associated with the key, overwriting the current value 48 // if it exists. 49 func (e *Environment) Set(key, value string) { 50 e.Unset(key) 51 *e = append(*e, key+"="+value) 52 } 53 54 // Unset removes the specified keys from the Environment. 55 func (e *Environment) Unset(keys ...string) { 56 out := (*e)[:0] 57 for _, env := range *e { 58 if key, _, ok := decodeKeyValue(env); ok && inList(key, keys) { 59 continue 60 } 61 out = append(out, env) 62 } 63 *e = out 64 } 65 66 // UnsetWithPrefix removes all keys that start with prefix. 67 func (e *Environment) UnsetWithPrefix(prefix string) { 68 out := (*e)[:0] 69 for _, env := range *e { 70 if key, _, ok := decodeKeyValue(env); ok && strings.HasPrefix(key, prefix) { 71 continue 72 } 73 out = append(out, env) 74 } 75 *e = out 76 } 77 78 // Environ returns the []string required for exec.Cmd.Env 79 func (e *Environment) Environ() []string { 80 return []string(*e) 81 } 82 83 // Copy returns a copy of the Environment so that independent changes may be made. 84 func (e *Environment) Copy() *Environment { 85 ret := Environment(make([]string, len(*e))) 86 for i, v := range *e { 87 ret[i] = v 88 } 89 return &ret 90 } 91 92 // IsTrue returns whether an environment variable is set to a positive value (1,y,yes,on,true) 93 func (e *Environment) IsEnvTrue(key string) bool { 94 if value, ok := e.Get(key); ok { 95 return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" 96 } 97 return false 98 } 99 100 // IsFalse returns whether an environment variable is set to a negative value (0,n,no,off,false) 101 func (e *Environment) IsFalse(key string) bool { 102 if value, ok := e.Get(key); ok { 103 return value == "0" || value == "n" || value == "no" || value == "off" || value == "false" 104 } 105 return false 106 } 107 108 // AppendFromKati reads a shell script written by Kati that exports or unsets 109 // environment variables, and applies those to the local Environment. 110 func (e *Environment) AppendFromKati(filename string) error { 111 file, err := os.Open(filename) 112 if err != nil { 113 return err 114 } 115 defer file.Close() 116 117 return e.appendFromKati(file) 118 } 119 120 func (e *Environment) appendFromKati(reader io.Reader) error { 121 scanner := bufio.NewScanner(reader) 122 for scanner.Scan() { 123 text := strings.TrimSpace(scanner.Text()) 124 125 if len(text) == 0 || text[0] == '#' { 126 continue 127 } 128 129 cmd := strings.SplitN(text, " ", 2) 130 if len(cmd) != 2 { 131 return fmt.Errorf("Unknown kati environment line: %q", text) 132 } 133 134 if cmd[0] == "unset" { 135 str, ok := singleUnquote(cmd[1]) 136 if !ok { 137 fmt.Errorf("Failed to unquote kati line: %q", text) 138 } 139 e.Unset(str) 140 } else if cmd[0] == "export" { 141 key, value, ok := decodeKeyValue(cmd[1]) 142 if !ok { 143 return fmt.Errorf("Failed to parse export: %v", cmd) 144 } 145 146 key, ok = singleUnquote(key) 147 if !ok { 148 return fmt.Errorf("Failed to unquote kati line: %q", text) 149 } 150 value, ok = singleUnquote(value) 151 if !ok { 152 return fmt.Errorf("Failed to unquote kati line: %q", text) 153 } 154 155 e.Set(key, value) 156 } else { 157 return fmt.Errorf("Unknown kati environment command: %q", text) 158 } 159 } 160 if err := scanner.Err(); err != nil { 161 return err 162 } 163 return nil 164 } 165