| // Copyright 2015 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. | 
 |  | 
 | // Implements the environment JSON file handling for serializing the | 
 | // environment variables that were used in soong_build so that soong_ui can | 
 | // check whether they have changed | 
 | package shared | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"fmt" | 
 | 	"io/ioutil" | 
 | 	"sort" | 
 | ) | 
 |  | 
 | type envFileEntry struct{ Key, Value string } | 
 | type envFileData []envFileEntry | 
 |  | 
 | // Serializes the given environment variable name/value map into JSON formatted bytes by converting | 
 | // to envFileEntry values and marshaling them. | 
 | // | 
 | // e.g. OUT_DIR = "out" | 
 | // is converted to: | 
 | // | 
 | //	{ | 
 | //	    "Key": "OUT_DIR", | 
 | //	    "Value": "out", | 
 | //	}, | 
 | func EnvFileContents(envDeps map[string]string) ([]byte, error) { | 
 | 	contents := make(envFileData, 0, len(envDeps)) | 
 | 	for key, value := range envDeps { | 
 | 		contents = append(contents, envFileEntry{key, value}) | 
 | 	} | 
 |  | 
 | 	sort.Sort(contents) | 
 |  | 
 | 	data, err := json.MarshalIndent(contents, "", "    ") | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 |  | 
 | 	data = append(data, '\n') | 
 |  | 
 | 	return data, nil | 
 | } | 
 |  | 
 | // Reads and deserializes a Soong environment file located at the given file | 
 | // path to determine its staleness. If any environment variable values have | 
 | // changed, it prints and returns changed environment variable values and | 
 | // returns true. | 
 | // Failing to read or parse the file also causes it to return true. | 
 | func StaleEnvFile(filepath string, getenv func(string) string) (isStale bool, | 
 | 	changedEnvironmentVariable []string, err error) { | 
 | 	data, err := ioutil.ReadFile(filepath) | 
 | 	if err != nil { | 
 | 		return true, nil, err | 
 | 	} | 
 |  | 
 | 	var contents envFileData | 
 |  | 
 | 	err = json.Unmarshal(data, &contents) | 
 | 	if err != nil { | 
 | 		return true, nil, err | 
 | 	} | 
 |  | 
 | 	var changed []string | 
 | 	for _, entry := range contents { | 
 | 		key := entry.Key | 
 | 		old := entry.Value | 
 | 		cur := getenv(key) | 
 | 		if old != cur { | 
 | 			changed = append(changed, fmt.Sprintf("%s (%q -> %q)", key, old, cur)) | 
 | 			changedEnvironmentVariable = append(changedEnvironmentVariable, key) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if len(changed) > 0 { | 
 | 		fmt.Printf("environment variables changed value:\n") | 
 | 		for _, s := range changed { | 
 | 			fmt.Printf("   %s\n", s) | 
 | 		} | 
 | 		return true, changedEnvironmentVariable, nil | 
 | 	} | 
 |  | 
 | 	return false, nil, nil | 
 | } | 
 |  | 
 | // Deserializes and environment serialized by EnvFileContents() and returns it | 
 | // as a map[string]string. | 
 | func EnvFromFile(envFile string) (map[string]string, error) { | 
 | 	result := make(map[string]string) | 
 | 	data, err := ioutil.ReadFile(envFile) | 
 | 	if err != nil { | 
 | 		return result, err | 
 | 	} | 
 |  | 
 | 	var contents envFileData | 
 | 	err = json.Unmarshal(data, &contents) | 
 | 	if err != nil { | 
 | 		return result, err | 
 | 	} | 
 |  | 
 | 	for _, entry := range contents { | 
 | 		result[entry.Key] = entry.Value | 
 | 	} | 
 |  | 
 | 	return result, nil | 
 | } | 
 |  | 
 | // Implements sort.Interface so that we can use sort.Sort on envFileData arrays. | 
 | func (e envFileData) Len() int { | 
 | 	return len(e) | 
 | } | 
 |  | 
 | func (e envFileData) Less(i, j int) bool { | 
 | 	return e[i].Key < e[j].Key | 
 | } | 
 |  | 
 | func (e envFileData) Swap(i, j int) { | 
 | 	e[i], e[j] = e[j], e[i] | 
 | } | 
 |  | 
 | var _ sort.Interface = envFileData{} |