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