• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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