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// { 37// "Key": "OUT_DIR", 38// "Value": "out", 39// }, 40func EnvFileContents(envDeps map[string]string) ([]byte, error) { 41 contents := make(envFileData, 0, len(envDeps)) 42 for key, value := range envDeps { 43 contents = append(contents, envFileEntry{key, value}) 44 } 45 46 sort.Sort(contents) 47 48 data, err := json.MarshalIndent(contents, "", " ") 49 if err != nil { 50 return nil, err 51 } 52 53 data = append(data, '\n') 54 55 return data, nil 56} 57 58// Reads and deserializes a Soong environment file located at the given file 59// path to determine its staleness. If any environment variable values have 60// changed, it prints and returns changed environment variable values and 61// returns true. 62// Failing to read or parse the file also causes it to return true. 63func StaleEnvFile(filepath string, getenv func(string) string) (isStale bool, 64 changedEnvironmentVariable []string, err error) { 65 data, err := ioutil.ReadFile(filepath) 66 if err != nil { 67 return true, nil, err 68 } 69 70 var contents envFileData 71 72 err = json.Unmarshal(data, &contents) 73 if err != nil { 74 return true, nil, err 75 } 76 77 var changed []string 78 for _, entry := range contents { 79 key := entry.Key 80 old := entry.Value 81 cur := getenv(key) 82 if old != cur { 83 changed = append(changed, fmt.Sprintf("%s (%q -> %q)", key, old, cur)) 84 changedEnvironmentVariable = append(changedEnvironmentVariable, key) 85 } 86 } 87 88 if len(changed) > 0 { 89 fmt.Printf("environment variables changed value:\n") 90 for _, s := range changed { 91 fmt.Printf(" %s\n", s) 92 } 93 return true, changedEnvironmentVariable, nil 94 } 95 96 return false, nil, nil 97} 98 99// Deserializes and environment serialized by EnvFileContents() and returns it 100// as a map[string]string. 101func EnvFromFile(envFile string) (map[string]string, error) { 102 result := make(map[string]string) 103 data, err := ioutil.ReadFile(envFile) 104 if err != nil { 105 return result, err 106 } 107 108 var contents envFileData 109 err = json.Unmarshal(data, &contents) 110 if err != nil { 111 return result, err 112 } 113 114 for _, entry := range contents { 115 result[entry.Key] = entry.Value 116 } 117 118 return result, nil 119} 120 121// Implements sort.Interface so that we can use sort.Sort on envFileData arrays. 122func (e envFileData) Len() int { 123 return len(e) 124} 125 126func (e envFileData) Less(i, j int) bool { 127 return e[i].Key < e[j].Key 128} 129 130func (e envFileData) Swap(i, j int) { 131 e[i], e[j] = e[j], e[i] 132} 133 134var _ sort.Interface = envFileData{} 135