Merge "Support fetching config files from experiments fetcher binary"
This commit is contained in:
@@ -15,10 +15,12 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -35,6 +37,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
envConfigDir = "vendor/google/tools/soong_config"
|
envConfigDir = "vendor/google/tools/soong_config"
|
||||||
jsonSuffix = "json"
|
jsonSuffix = "json"
|
||||||
|
|
||||||
|
configFetcher = "vendor/google/tools/soong/expconfigfetcher"
|
||||||
|
envConfigFetchTimeout = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct{ *configImpl }
|
type Config struct{ *configImpl }
|
||||||
@@ -135,40 +140,82 @@ func checkTopDir(ctx Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadEnvConfig(config *configImpl) error {
|
// fetchEnvConfig optionally fetches environment config from an
|
||||||
|
// experiments system to control Soong features dynamically.
|
||||||
|
func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
|
||||||
|
s, err := os.Stat(configFetcher)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if s.Mode()&0111 == 0 {
|
||||||
|
return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
|
||||||
|
}
|
||||||
|
|
||||||
|
configExists := false
|
||||||
|
outConfigFilePath := filepath.Join(config.OutDir(), envConfigName + jsonSuffix)
|
||||||
|
if _, err := os.Stat(outConfigFilePath); err == nil {
|
||||||
|
configExists = true
|
||||||
|
}
|
||||||
|
|
||||||
|
tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir())
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a config file already exists, return immediately and run the config file
|
||||||
|
// fetch in the background. Otherwise, wait for the config file to be fetched.
|
||||||
|
if configExists {
|
||||||
|
go cmd.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadEnvConfig(ctx Context, config *configImpl) error {
|
||||||
bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
|
bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
|
||||||
if bc == "" {
|
if bc == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := fetchEnvConfig(ctx, config, bc); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fetch config file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
configDirs := []string{
|
configDirs := []string{
|
||||||
os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
|
|
||||||
config.OutDir(),
|
config.OutDir(),
|
||||||
|
os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
|
||||||
envConfigDir,
|
envConfigDir,
|
||||||
}
|
}
|
||||||
var cfgFile string
|
|
||||||
for _, dir := range configDirs {
|
for _, dir := range configDirs {
|
||||||
cfgFile = filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
|
cfgFile := filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
|
||||||
if _, err := os.Stat(cfgFile); err == nil {
|
envVarsJSON, err := ioutil.ReadFile(cfgFile)
|
||||||
break
|
if err != nil {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
envVarsJSON, err := ioutil.ReadFile(cfgFile)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "\033[33mWARNING:\033[0m failed to open config file %s: %s\n", cfgFile, err.Error())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var envVars map[string]map[string]string
|
|
||||||
if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
|
|
||||||
return fmt.Errorf("env vars config file: %s did not parse correctly: %s", cfgFile, err.Error())
|
|
||||||
}
|
|
||||||
for k, v := range envVars["env"] {
|
|
||||||
if os.Getenv(k) != "" {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
config.Environment().Set(k, v)
|
ctx.Verbosef("Loading config file %v\n", cfgFile)
|
||||||
|
var envVars map[string]map[string]string
|
||||||
|
if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Env vars config file %s did not parse correctly: %s", cfgFile, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for k, v := range envVars["env"] {
|
||||||
|
if os.Getenv(k) != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
config.environ.Set(k, v)
|
||||||
|
}
|
||||||
|
ctx.Verbosef("Finished loading config file %v\n", cfgFile)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +250,7 @@ func NewConfig(ctx Context, args ...string) Config {
|
|||||||
|
|
||||||
// loadEnvConfig needs to know what the OUT_DIR is, so it should
|
// loadEnvConfig needs to know what the OUT_DIR is, so it should
|
||||||
// be called after we determine the appropriate out directory.
|
// be called after we determine the appropriate out directory.
|
||||||
if err := loadEnvConfig(ret); err != nil {
|
if err := loadEnvConfig(ctx, ret); err != nil {
|
||||||
ctx.Fatalln("Failed to parse env config files: %v", err)
|
ctx.Fatalln("Failed to parse env config files: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user