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 15package build 16 17import ( 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. 27type Environment []string 28 29// OsEnvironment wraps the current environment returned by os.Environ() 30func 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. 38func (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. 49func (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. 55func (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. 67func (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// Allow removes all keys that are not present in the input list 79func (e *Environment) Allow(keys ...string) { 80 out := (*e)[:0] 81 for _, env := range *e { 82 if key, _, ok := decodeKeyValue(env); ok && inList(key, keys) { 83 out = append(out, env) 84 } 85 } 86 *e = out 87} 88 89// Environ returns the []string required for exec.Cmd.Env 90func (e *Environment) Environ() []string { 91 return []string(*e) 92} 93 94// Copy returns a copy of the Environment so that independent changes may be made. 95func (e *Environment) Copy() *Environment { 96 ret := Environment(make([]string, len(*e))) 97 for i, v := range *e { 98 ret[i] = v 99 } 100 return &ret 101} 102 103// IsTrue returns whether an environment variable is set to a positive value (1,y,yes,on,true) 104func (e *Environment) IsEnvTrue(key string) bool { 105 if value, ok := e.Get(key); ok { 106 return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" 107 } 108 return false 109} 110 111// IsFalse returns whether an environment variable is set to a negative value (0,n,no,off,false) 112func (e *Environment) IsFalse(key string) bool { 113 if value, ok := e.Get(key); ok { 114 return value == "0" || value == "n" || value == "no" || value == "off" || value == "false" 115 } 116 return false 117} 118 119// AppendFromKati reads a shell script written by Kati that exports or unsets 120// environment variables, and applies those to the local Environment. 121func (e *Environment) AppendFromKati(filename string) error { 122 file, err := os.Open(filename) 123 if err != nil { 124 return err 125 } 126 defer file.Close() 127 128 return e.appendFromKati(file) 129} 130 131func (e *Environment) appendFromKati(reader io.Reader) error { 132 scanner := bufio.NewScanner(reader) 133 for scanner.Scan() { 134 text := strings.TrimSpace(scanner.Text()) 135 136 if len(text) == 0 || text[0] == '#' { 137 continue 138 } 139 140 cmd := strings.SplitN(text, " ", 2) 141 if len(cmd) != 2 { 142 return fmt.Errorf("Unknown kati environment line: %q", text) 143 } 144 145 if cmd[0] == "unset" { 146 str, ok := singleUnquote(cmd[1]) 147 if !ok { 148 return fmt.Errorf("Failed to unquote kati line: %q", text) 149 } 150 e.Unset(str) 151 } else if cmd[0] == "export" { 152 key, value, ok := decodeKeyValue(cmd[1]) 153 if !ok { 154 return fmt.Errorf("Failed to parse export: %v", cmd) 155 } 156 157 key, ok = singleUnquote(key) 158 if !ok { 159 return fmt.Errorf("Failed to unquote kati line: %q", text) 160 } 161 value, ok = singleUnquote(value) 162 if !ok { 163 return fmt.Errorf("Failed to unquote kati line: %q", text) 164 } 165 166 e.Set(key, value) 167 } else { 168 return fmt.Errorf("Unknown kati environment command: %q", text) 169 } 170 } 171 if err := scanner.Err(); err != nil { 172 return err 173 } 174 return nil 175} 176