xref: /aosp_15_r20/build/soong/shared/env.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2015 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Worker// Implements the environment JSON file handling for serializing the
16*333d2b36SAndroid Build Coastguard Worker// environment variables that were used in soong_build so that soong_ui can
17*333d2b36SAndroid Build Coastguard Worker// check whether they have changed
18*333d2b36SAndroid Build Coastguard Workerpackage shared
19*333d2b36SAndroid Build Coastguard Worker
20*333d2b36SAndroid Build Coastguard Workerimport (
21*333d2b36SAndroid Build Coastguard Worker	"encoding/json"
22*333d2b36SAndroid Build Coastguard Worker	"fmt"
23*333d2b36SAndroid Build Coastguard Worker	"io/ioutil"
24*333d2b36SAndroid Build Coastguard Worker	"sort"
25*333d2b36SAndroid Build Coastguard Worker)
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Workertype envFileEntry struct{ Key, Value string }
28*333d2b36SAndroid Build Coastguard Workertype envFileData []envFileEntry
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Worker// Serializes the given environment variable name/value map into JSON formatted bytes by converting
31*333d2b36SAndroid Build Coastguard Worker// to envFileEntry values and marshaling them.
32*333d2b36SAndroid Build Coastguard Worker//
33*333d2b36SAndroid Build Coastguard Worker// e.g. OUT_DIR = "out"
34*333d2b36SAndroid Build Coastguard Worker// is converted to:
35*333d2b36SAndroid Build Coastguard Worker//
36*333d2b36SAndroid Build Coastguard Worker//	{
37*333d2b36SAndroid Build Coastguard Worker//	    "Key": "OUT_DIR",
38*333d2b36SAndroid Build Coastguard Worker//	    "Value": "out",
39*333d2b36SAndroid Build Coastguard Worker//	},
40*333d2b36SAndroid Build Coastguard Workerfunc EnvFileContents(envDeps map[string]string) ([]byte, error) {
41*333d2b36SAndroid Build Coastguard Worker	contents := make(envFileData, 0, len(envDeps))
42*333d2b36SAndroid Build Coastguard Worker	for key, value := range envDeps {
43*333d2b36SAndroid Build Coastguard Worker		contents = append(contents, envFileEntry{key, value})
44*333d2b36SAndroid Build Coastguard Worker	}
45*333d2b36SAndroid Build Coastguard Worker
46*333d2b36SAndroid Build Coastguard Worker	sort.Sort(contents)
47*333d2b36SAndroid Build Coastguard Worker
48*333d2b36SAndroid Build Coastguard Worker	data, err := json.MarshalIndent(contents, "", "    ")
49*333d2b36SAndroid Build Coastguard Worker	if err != nil {
50*333d2b36SAndroid Build Coastguard Worker		return nil, err
51*333d2b36SAndroid Build Coastguard Worker	}
52*333d2b36SAndroid Build Coastguard Worker
53*333d2b36SAndroid Build Coastguard Worker	data = append(data, '\n')
54*333d2b36SAndroid Build Coastguard Worker
55*333d2b36SAndroid Build Coastguard Worker	return data, nil
56*333d2b36SAndroid Build Coastguard Worker}
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Worker// Reads and deserializes a Soong environment file located at the given file
59*333d2b36SAndroid Build Coastguard Worker// path to determine its staleness. If any environment variable values have
60*333d2b36SAndroid Build Coastguard Worker// changed, it prints and returns changed environment variable values and
61*333d2b36SAndroid Build Coastguard Worker// returns true.
62*333d2b36SAndroid Build Coastguard Worker// Failing to read or parse the file also causes it to return true.
63*333d2b36SAndroid Build Coastguard Workerfunc StaleEnvFile(filepath string, getenv func(string) string) (isStale bool,
64*333d2b36SAndroid Build Coastguard Worker	changedEnvironmentVariable []string, err error) {
65*333d2b36SAndroid Build Coastguard Worker	data, err := ioutil.ReadFile(filepath)
66*333d2b36SAndroid Build Coastguard Worker	if err != nil {
67*333d2b36SAndroid Build Coastguard Worker		return true, nil, err
68*333d2b36SAndroid Build Coastguard Worker	}
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Worker	var contents envFileData
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker	err = json.Unmarshal(data, &contents)
73*333d2b36SAndroid Build Coastguard Worker	if err != nil {
74*333d2b36SAndroid Build Coastguard Worker		return true, nil, err
75*333d2b36SAndroid Build Coastguard Worker	}
76*333d2b36SAndroid Build Coastguard Worker
77*333d2b36SAndroid Build Coastguard Worker	var changed []string
78*333d2b36SAndroid Build Coastguard Worker	for _, entry := range contents {
79*333d2b36SAndroid Build Coastguard Worker		key := entry.Key
80*333d2b36SAndroid Build Coastguard Worker		old := entry.Value
81*333d2b36SAndroid Build Coastguard Worker		cur := getenv(key)
82*333d2b36SAndroid Build Coastguard Worker		if old != cur {
83*333d2b36SAndroid Build Coastguard Worker			changed = append(changed, fmt.Sprintf("%s (%q -> %q)", key, old, cur))
84*333d2b36SAndroid Build Coastguard Worker			changedEnvironmentVariable = append(changedEnvironmentVariable, key)
85*333d2b36SAndroid Build Coastguard Worker		}
86*333d2b36SAndroid Build Coastguard Worker	}
87*333d2b36SAndroid Build Coastguard Worker
88*333d2b36SAndroid Build Coastguard Worker	if len(changed) > 0 {
89*333d2b36SAndroid Build Coastguard Worker		fmt.Printf("environment variables changed value:\n")
90*333d2b36SAndroid Build Coastguard Worker		for _, s := range changed {
91*333d2b36SAndroid Build Coastguard Worker			fmt.Printf("   %s\n", s)
92*333d2b36SAndroid Build Coastguard Worker		}
93*333d2b36SAndroid Build Coastguard Worker		return true, changedEnvironmentVariable, nil
94*333d2b36SAndroid Build Coastguard Worker	}
95*333d2b36SAndroid Build Coastguard Worker
96*333d2b36SAndroid Build Coastguard Worker	return false, nil, nil
97*333d2b36SAndroid Build Coastguard Worker}
98*333d2b36SAndroid Build Coastguard Worker
99*333d2b36SAndroid Build Coastguard Worker// Deserializes and environment serialized by EnvFileContents() and returns it
100*333d2b36SAndroid Build Coastguard Worker// as a map[string]string.
101*333d2b36SAndroid Build Coastguard Workerfunc EnvFromFile(envFile string) (map[string]string, error) {
102*333d2b36SAndroid Build Coastguard Worker	result := make(map[string]string)
103*333d2b36SAndroid Build Coastguard Worker	data, err := ioutil.ReadFile(envFile)
104*333d2b36SAndroid Build Coastguard Worker	if err != nil {
105*333d2b36SAndroid Build Coastguard Worker		return result, err
106*333d2b36SAndroid Build Coastguard Worker	}
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Worker	var contents envFileData
109*333d2b36SAndroid Build Coastguard Worker	err = json.Unmarshal(data, &contents)
110*333d2b36SAndroid Build Coastguard Worker	if err != nil {
111*333d2b36SAndroid Build Coastguard Worker		return result, err
112*333d2b36SAndroid Build Coastguard Worker	}
113*333d2b36SAndroid Build Coastguard Worker
114*333d2b36SAndroid Build Coastguard Worker	for _, entry := range contents {
115*333d2b36SAndroid Build Coastguard Worker		result[entry.Key] = entry.Value
116*333d2b36SAndroid Build Coastguard Worker	}
117*333d2b36SAndroid Build Coastguard Worker
118*333d2b36SAndroid Build Coastguard Worker	return result, nil
119*333d2b36SAndroid Build Coastguard Worker}
120*333d2b36SAndroid Build Coastguard Worker
121*333d2b36SAndroid Build Coastguard Worker// Implements sort.Interface so that we can use sort.Sort on envFileData arrays.
122*333d2b36SAndroid Build Coastguard Workerfunc (e envFileData) Len() int {
123*333d2b36SAndroid Build Coastguard Worker	return len(e)
124*333d2b36SAndroid Build Coastguard Worker}
125*333d2b36SAndroid Build Coastguard Worker
126*333d2b36SAndroid Build Coastguard Workerfunc (e envFileData) Less(i, j int) bool {
127*333d2b36SAndroid Build Coastguard Worker	return e[i].Key < e[j].Key
128*333d2b36SAndroid Build Coastguard Worker}
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Workerfunc (e envFileData) Swap(i, j int) {
131*333d2b36SAndroid Build Coastguard Worker	e[i], e[j] = e[j], e[i]
132*333d2b36SAndroid Build Coastguard Worker}
133*333d2b36SAndroid Build Coastguard Worker
134*333d2b36SAndroid Build Coastguard Workervar _ sort.Interface = envFileData{}
135