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