Home | History | Annotate | Download | only in build
      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