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// Environ returns the []string required for exec.Cmd.Env 67func (e *Environment) Environ() []string { 68 return []string(*e) 69} 70 71// Copy returns a copy of the Environment so that independent changes may be made. 72func (e *Environment) Copy() *Environment { 73 ret := Environment(make([]string, len(*e))) 74 for i, v := range *e { 75 ret[i] = v 76 } 77 return &ret 78} 79 80// IsTrue returns whether an environment variable is set to a positive value (1,y,yes,on,true) 81func (e *Environment) IsEnvTrue(key string) bool { 82 if value, ok := e.Get(key); ok { 83 return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" 84 } 85 return false 86} 87 88// IsFalse returns whether an environment variable is set to a negative value (0,n,no,off,false) 89func (e *Environment) IsFalse(key string) bool { 90 if value, ok := e.Get(key); ok { 91 return value == "0" || value == "n" || value == "no" || value == "off" || value == "false" 92 } 93 return false 94} 95 96// AppendFromKati reads a shell script written by Kati that exports or unsets 97// environment variables, and applies those to the local Environment. 98func (e *Environment) AppendFromKati(filename string) error { 99 file, err := os.Open(filename) 100 if err != nil { 101 return err 102 } 103 defer file.Close() 104 105 return e.appendFromKati(file) 106} 107 108func (e *Environment) appendFromKati(reader io.Reader) error { 109 scanner := bufio.NewScanner(reader) 110 for scanner.Scan() { 111 text := strings.TrimSpace(scanner.Text()) 112 113 if len(text) == 0 || text[0] == '#' { 114 continue 115 } 116 117 cmd := strings.SplitN(text, " ", 2) 118 if len(cmd) != 2 { 119 return fmt.Errorf("Unknown kati environment line: %q", text) 120 } 121 122 if cmd[0] == "unset" { 123 str, ok := singleUnquote(cmd[1]) 124 if !ok { 125 fmt.Errorf("Failed to unquote kati line: %q", text) 126 } 127 e.Unset(str) 128 } else if cmd[0] == "export" { 129 key, value, ok := decodeKeyValue(cmd[1]) 130 if !ok { 131 return fmt.Errorf("Failed to parse export: %v", cmd) 132 } 133 134 key, ok = singleUnquote(key) 135 if !ok { 136 return fmt.Errorf("Failed to unquote kati line: %q", text) 137 } 138 value, ok = singleUnquote(value) 139 if !ok { 140 return fmt.Errorf("Failed to unquote kati line: %q", text) 141 } 142 143 e.Set(key, value) 144 } else { 145 return fmt.Errorf("Unknown kati environment command: %q", text) 146 } 147 } 148 if err := scanner.Err(); err != nil { 149 return err 150 } 151 return nil 152} 153