1// Copyright 2015 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// Implements the environment JSON file handling for serializing the 16// environment variables that were used in soong_build so that soong_ui can 17// check whether they have changed 18package shared 19 20import ( 21 "encoding/json" 22 "fmt" 23 "io/ioutil" 24 "sort" 25) 26 27type envFileEntry struct{ Key, Value string } 28type envFileData []envFileEntry 29 30// Serializes the given environment variable name/value map into JSON formatted bytes by converting 31// to envFileEntry values and marshaling them. 32// 33// e.g. OUT_DIR = "out" 34// is converted to: 35// { 36// "Key": "OUT_DIR", 37// "Value": "out", 38// }, 39func EnvFileContents(envDeps map[string]string) ([]byte, error) { 40 contents := make(envFileData, 0, len(envDeps)) 41 for key, value := range envDeps { 42 contents = append(contents, envFileEntry{key, value}) 43 } 44 45 sort.Sort(contents) 46 47 data, err := json.MarshalIndent(contents, "", " ") 48 if err != nil { 49 return nil, err 50 } 51 52 data = append(data, '\n') 53 54 return data, nil 55} 56 57// Reads and deserializes a Soong environment file located at the given file path to determine its 58// staleness. If any environment variable values have changed, it prints them out and returns true. 59// Failing to read or parse the file also causes it to return true. 60func StaleEnvFile(filepath string, getenv func(string) string) (bool, error) { 61 data, err := ioutil.ReadFile(filepath) 62 if err != nil { 63 return true, err 64 } 65 66 var contents envFileData 67 68 err = json.Unmarshal(data, &contents) 69 if err != nil { 70 return true, err 71 } 72 73 var changed []string 74 for _, entry := range contents { 75 key := entry.Key 76 old := entry.Value 77 cur := getenv(key) 78 if old != cur { 79 changed = append(changed, fmt.Sprintf("%s (%q -> %q)", key, old, cur)) 80 } 81 } 82 83 if len(changed) > 0 { 84 fmt.Printf("environment variables changed value:\n") 85 for _, s := range changed { 86 fmt.Printf(" %s\n", s) 87 } 88 return true, nil 89 } 90 91 return false, nil 92} 93 94// Deserializes and environment serialized by EnvFileContents() and returns it 95// as a map[string]string. 96func EnvFromFile(envFile string) (map[string]string, error) { 97 result := make(map[string]string) 98 data, err := ioutil.ReadFile(envFile) 99 if err != nil { 100 return result, err 101 } 102 103 var contents envFileData 104 err = json.Unmarshal(data, &contents) 105 if err != nil { 106 return result, err 107 } 108 109 for _, entry := range contents { 110 result[entry.Key] = entry.Value 111 } 112 113 return result, nil 114} 115 116// Implements sort.Interface so that we can use sort.Sort on envFileData arrays. 117func (e envFileData) Len() int { 118 return len(e) 119} 120 121func (e envFileData) Less(i, j int) bool { 122 return e[i].Key < e[j].Key 123} 124 125func (e envFileData) Swap(i, j int) { 126 e[i], e[j] = e[j], e[i] 127} 128 129var _ sort.Interface = envFileData{} 130