|  | // Copyright 2017 Google Inc. All rights reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package build | 
|  |  | 
|  | import ( | 
|  | "bufio" | 
|  | "fmt" | 
|  | "io" | 
|  | "os" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | // Environment adds a number of useful manipulation functions to the list of | 
|  | // strings returned by os.Environ() and used in exec.Cmd.Env. | 
|  | type Environment []string | 
|  |  | 
|  | // OsEnvironment wraps the current environment returned by os.Environ() | 
|  | func OsEnvironment() *Environment { | 
|  | env := Environment(os.Environ()) | 
|  | return &env | 
|  | } | 
|  |  | 
|  | // Get returns the value associated with the key, and whether it exists. | 
|  | // It's equivalent to the os.LookupEnv function, but with this copy of the | 
|  | // Environment. | 
|  | func (e *Environment) Get(key string) (string, bool) { | 
|  | for _, env := range *e { | 
|  | if k, v, ok := decodeKeyValue(env); ok && k == key { | 
|  | return v, true | 
|  | } | 
|  | } | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | // Set sets the value associated with the key, overwriting the current value | 
|  | // if it exists. | 
|  | func (e *Environment) Set(key, value string) { | 
|  | e.Unset(key) | 
|  | *e = append(*e, key+"="+value) | 
|  | } | 
|  |  | 
|  | // Unset removes the specified keys from the Environment. | 
|  | func (e *Environment) Unset(keys ...string) { | 
|  | out := (*e)[:0] | 
|  | for _, env := range *e { | 
|  | if key, _, ok := decodeKeyValue(env); ok && inList(key, keys) { | 
|  | continue | 
|  | } | 
|  | out = append(out, env) | 
|  | } | 
|  | *e = out | 
|  | } | 
|  |  | 
|  | // UnsetWithPrefix removes all keys that start with prefix. | 
|  | func (e *Environment) UnsetWithPrefix(prefix string) { | 
|  | out := (*e)[:0] | 
|  | for _, env := range *e { | 
|  | if key, _, ok := decodeKeyValue(env); ok && strings.HasPrefix(key, prefix) { | 
|  | continue | 
|  | } | 
|  | out = append(out, env) | 
|  | } | 
|  | *e = out | 
|  | } | 
|  |  | 
|  | // Allow removes all keys that are not present in the input list | 
|  | func (e *Environment) Allow(keys ...string) { | 
|  | out := (*e)[:0] | 
|  | for _, env := range *e { | 
|  | if key, _, ok := decodeKeyValue(env); ok && inList(key, keys) { | 
|  | out = append(out, env) | 
|  | } | 
|  | } | 
|  | *e = out | 
|  | } | 
|  |  | 
|  | // Environ returns the []string required for exec.Cmd.Env | 
|  | func (e *Environment) Environ() []string { | 
|  | return []string(*e) | 
|  | } | 
|  |  | 
|  | // Copy returns a copy of the Environment so that independent changes may be made. | 
|  | func (e *Environment) Copy() *Environment { | 
|  | ret := Environment(make([]string, len(*e))) | 
|  | for i, v := range *e { | 
|  | ret[i] = v | 
|  | } | 
|  | return &ret | 
|  | } | 
|  |  | 
|  | // IsTrue returns whether an environment variable is set to a positive value (1,y,yes,on,true) | 
|  | func (e *Environment) IsEnvTrue(key string) bool { | 
|  | if value, ok := e.Get(key); ok { | 
|  | return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // IsFalse returns whether an environment variable is set to a negative value (0,n,no,off,false) | 
|  | func (e *Environment) IsFalse(key string) bool { | 
|  | if value, ok := e.Get(key); ok { | 
|  | return value == "0" || value == "n" || value == "no" || value == "off" || value == "false" | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // AppendFromKati reads a shell script written by Kati that exports or unsets | 
|  | // environment variables, and applies those to the local Environment. | 
|  | func (e *Environment) AppendFromKati(filename string) error { | 
|  | file, err := os.Open(filename) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | defer file.Close() | 
|  |  | 
|  | return e.appendFromKati(file) | 
|  | } | 
|  |  | 
|  | func (e *Environment) appendFromKati(reader io.Reader) error { | 
|  | scanner := bufio.NewScanner(reader) | 
|  | for scanner.Scan() { | 
|  | text := strings.TrimSpace(scanner.Text()) | 
|  |  | 
|  | if len(text) == 0 || text[0] == '#' { | 
|  | continue | 
|  | } | 
|  |  | 
|  | cmd := strings.SplitN(text, " ", 2) | 
|  | if len(cmd) != 2 { | 
|  | return fmt.Errorf("Unknown kati environment line: %q", text) | 
|  | } | 
|  |  | 
|  | if cmd[0] == "unset" { | 
|  | str, ok := singleUnquote(cmd[1]) | 
|  | if !ok { | 
|  | return fmt.Errorf("Failed to unquote kati line: %q", text) | 
|  | } | 
|  | e.Unset(str) | 
|  | } else if cmd[0] == "export" { | 
|  | key, value, ok := decodeKeyValue(cmd[1]) | 
|  | if !ok { | 
|  | return fmt.Errorf("Failed to parse export: %v", cmd) | 
|  | } | 
|  |  | 
|  | key, ok = singleUnquote(key) | 
|  | if !ok { | 
|  | return fmt.Errorf("Failed to unquote kati line: %q", text) | 
|  | } | 
|  | value, ok = singleUnquote(value) | 
|  | if !ok { | 
|  | return fmt.Errorf("Failed to unquote kati line: %q", text) | 
|  | } | 
|  |  | 
|  | e.Set(key, value) | 
|  | } else { | 
|  | return fmt.Errorf("Unknown kati environment command: %q", text) | 
|  | } | 
|  | } | 
|  | if err := scanner.Err(); err != nil { | 
|  | return err | 
|  | } | 
|  | return nil | 
|  | } |