diff options
22 files changed, 3950 insertions, 0 deletions
diff --git a/bin/build-flag b/bin/build-flag new file mode 100755 index 000000000..dc404bc97 --- /dev/null +++ b/bin/build-flag @@ -0,0 +1,28 @@ +#!/bin/bash -eu +# +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh +require_top + +# Save the current PWD for use in soong_ui +export ORIGINAL_PWD=${PWD} +export TOP=$(gettop) +source ${TOP}/build/soong/scripts/microfactory.bash + +soong_build_go build-flag android/soong/cmd/release_config/build_flag + +cd ${TOP} +exec "$(getoutdir)/build-flag" "$@" diff --git a/cmd/release_config/build_flag/Android.bp b/cmd/release_config/build_flag/Android.bp new file mode 100644 index 000000000..0f10c91cb --- /dev/null +++ b/cmd/release_config/build_flag/Android.bp @@ -0,0 +1,32 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +blueprint_go_binary { + name: "build-flag", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-proto", + "soong-cmd-release_config-lib", + ], + srcs: [ + "main.go", + ], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-build_flag", + pkgPath: "android/soong/cmd/release_config/build_flag", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-proto", + "soong-cmd-release_config-lib", + ], + srcs: [ + "main.go", + ], +} diff --git a/cmd/release_config/build_flag/main.go b/cmd/release_config/build_flag/main.go new file mode 100644 index 000000000..56c49d883 --- /dev/null +++ b/cmd/release_config/build_flag/main.go @@ -0,0 +1,356 @@ +package main + +import ( + "cmp" + "flag" + "fmt" + "os" + "path/filepath" + "slices" + "strings" + + rc_lib "android/soong/cmd/release_config/release_config_lib" + rc_proto "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +type Flags struct { + // The path to the top of the workspace. Default: ".". + top string + + // Pathlist of release config map textproto files. + // If not specified, then the value is (if present): + // - build/release/release_config_map.textproto + // - vendor/google_shared/build/release/release_config_map.textproto + // - vendor/google/release/release_config_map.textproto + // + // Additionally, any maps specified in the environment variable + // `PRODUCT_RELEASE_CONFIG_MAPS` are used. + maps rc_lib.StringList + + // Output directory (relative to `top`). + outDir string + + // Which $TARGET_RELEASE(s) should we use. Some commands will only + // accept one value, others also accept `--release --all`. + targetReleases rc_lib.StringList + + // Disable warning messages + quiet bool + + // Show all release configs + allReleases bool + + // Call get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get the + // product-specific map directories. + useGetBuildVar bool + + // Panic on errors. + debug bool +} + +type CommandFunc func(*rc_lib.ReleaseConfigs, Flags, string, []string) error + +var commandMap map[string]CommandFunc = map[string]CommandFunc{ + "get": GetCommand, + "set": SetCommand, + "trace": GetCommand, // Also handled by GetCommand +} + +// Find the top of the release config contribution directory. +// Returns the parent of the flag_declarations and flag_values directories. +func GetMapDir(path string) (string, error) { + for p := path; p != "."; p = filepath.Dir(p) { + switch filepath.Base(p) { + case "flag_declarations": + return filepath.Dir(p), nil + case "flag_values": + return filepath.Dir(p), nil + } + } + return "", fmt.Errorf("Could not determine directory from %s", path) +} + +func MarshalFlagDefaultValue(config *rc_lib.ReleaseConfig, name string) (ret string, err error) { + fa, ok := config.FlagArtifacts[name] + if !ok { + return "", fmt.Errorf("%s not found in %s", name, config.Name) + } + return rc_lib.MarshalValue(fa.Traces[0].Value), nil +} + +func MarshalFlagValue(config *rc_lib.ReleaseConfig, name string) (ret string, err error) { + fa, ok := config.FlagArtifacts[name] + if !ok { + return "", fmt.Errorf("%s not found in %s", name, config.Name) + } + return rc_lib.MarshalValue(fa.Value), nil +} + +// Returns a list of ReleaseConfig objects for which to process flags. +func GetReleaseArgs(configs *rc_lib.ReleaseConfigs, commonFlags Flags) ([]*rc_lib.ReleaseConfig, error) { + var all bool + relFlags := flag.NewFlagSet("releaseFlags", flag.ExitOnError) + relFlags.BoolVar(&all, "all", false, "Display all releases") + relFlags.Parse(commonFlags.targetReleases) + var ret []*rc_lib.ReleaseConfig + if all || commonFlags.allReleases { + sortMap := map[string]int{ + "trunk_staging": 0, + "trunk_food": 10, + "trunk": 20, + // Anything not listed above, uses this for key 1 in the sort. + "-default": 100, + } + + for _, config := range configs.ReleaseConfigs { + ret = append(ret, config) + } + slices.SortFunc(ret, func(a, b *rc_lib.ReleaseConfig) int { + mapValue := func(v *rc_lib.ReleaseConfig) int { + if v, ok := sortMap[v.Name]; ok { + return v + } + return sortMap["-default"] + } + if n := cmp.Compare(mapValue(a), mapValue(b)); n != 0 { + return n + } + return cmp.Compare(a.Name, b.Name) + }) + return ret, nil + } + for _, arg := range relFlags.Args() { + // Return releases in the order that they were given. + config, err := configs.GetReleaseConfig(arg) + if err != nil { + return nil, err + } + ret = append(ret, config) + } + return ret, nil +} + +func GetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, args []string) error { + isTrace := cmd == "trace" + isSet := cmd == "set" + + var all bool + getFlags := flag.NewFlagSet("get", flag.ExitOnError) + getFlags.BoolVar(&all, "all", false, "Display all flags") + getFlags.Parse(args) + args = getFlags.Args() + + if isSet { + commonFlags.allReleases = true + } + releaseConfigList, err := GetReleaseArgs(configs, commonFlags) + if err != nil { + return err + } + if isTrace && len(releaseConfigList) > 1 { + return fmt.Errorf("trace command only allows one --release argument. Got: %s", strings.Join(commonFlags.targetReleases, " ")) + } + + if all { + args = []string{} + for _, fa := range configs.FlagArtifacts { + args = append(args, *fa.FlagDeclaration.Name) + } + } + + var maxVariableNameLen, maxReleaseNameLen int + var releaseNameFormat, variableNameFormat string + valueFormat := "%s" + showReleaseName := len(releaseConfigList) > 1 + showVariableName := len(args) > 1 + if showVariableName { + for _, arg := range args { + maxVariableNameLen = max(len(arg), maxVariableNameLen) + } + variableNameFormat = fmt.Sprintf("%%-%ds ", maxVariableNameLen) + valueFormat = "'%s'" + } + if showReleaseName { + for _, config := range releaseConfigList { + maxReleaseNameLen = max(len(config.Name), maxReleaseNameLen) + } + releaseNameFormat = fmt.Sprintf("%%-%ds ", maxReleaseNameLen) + valueFormat = "'%s'" + } + + outputOneLine := func(variable, release, value, valueFormat string) { + var outStr string + if showVariableName { + outStr += fmt.Sprintf(variableNameFormat, variable) + } + if showReleaseName { + outStr += fmt.Sprintf(releaseNameFormat, release) + } + outStr += fmt.Sprintf(valueFormat, value) + fmt.Println(outStr) + } + + for _, arg := range args { + if _, ok := configs.FlagArtifacts[arg]; !ok { + return fmt.Errorf("%s is not a defined build flag", arg) + } + } + + for _, arg := range args { + for _, config := range releaseConfigList { + if isSet { + // If this is from the set command, format the output as: + // <default> "" + // trunk_staging "" + // trunk "" + // + // ap1a "" + // ... + switch { + case config.Name == "trunk_staging": + defaultValue, err := MarshalFlagDefaultValue(config, arg) + if err != nil { + return err + } + outputOneLine(arg, "<default>", defaultValue, valueFormat) + case config.AconfigFlagsOnly: + continue + case config.Name == "trunk": + fmt.Println() + } + } + val, err := MarshalFlagValue(config, arg) + if err == nil { + outputOneLine(arg, config.Name, val, valueFormat) + } else { + outputOneLine(arg, config.Name, "REDACTED", "%s") + } + if isTrace { + for _, trace := range config.FlagArtifacts[arg].Traces { + fmt.Printf(" => \"%s\" in %s\n", rc_lib.MarshalValue(trace.Value), *trace.Source) + } + } + } + } + return nil +} + +func SetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, args []string) error { + var valueDir string + if len(commonFlags.targetReleases) > 1 { + return fmt.Errorf("set command only allows one --release argument. Got: %s", strings.Join(commonFlags.targetReleases, " ")) + } + targetRelease := commonFlags.targetReleases[0] + + setFlags := flag.NewFlagSet("set", flag.ExitOnError) + setFlags.StringVar(&valueDir, "dir", "", "Directory in which to place the value") + setFlags.Parse(args) + setArgs := setFlags.Args() + if len(setArgs) != 2 { + return fmt.Errorf("set command expected flag and value, got: %s", strings.Join(setArgs, " ")) + } + name := setArgs[0] + value := setArgs[1] + release, err := configs.GetReleaseConfig(targetRelease) + targetRelease = release.Name + if err != nil { + return err + } + if release.AconfigFlagsOnly { + return fmt.Errorf("%s does not allow build flag overrides", targetRelease) + } + flagArtifact, ok := release.FlagArtifacts[name] + if !ok { + return fmt.Errorf("Unknown build flag %s", name) + } + if valueDir == "" { + mapDir, err := GetMapDir(*flagArtifact.Traces[len(flagArtifact.Traces)-1].Source) + if err != nil { + return err + } + valueDir = mapDir + } + + flagValue := &rc_proto.FlagValue{ + Name: proto.String(name), + Value: rc_lib.UnmarshalValue(value), + } + flagPath := filepath.Join(valueDir, "flag_values", targetRelease, fmt.Sprintf("%s.textproto", name)) + err = rc_lib.WriteMessage(flagPath, flagValue) + if err != nil { + return err + } + + // Reload the release configs. + configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, commonFlags.targetReleases[0], commonFlags.useGetBuildVar) + if err != nil { + return err + } + err = GetCommand(configs, commonFlags, cmd, args[0:1]) + if err != nil { + return err + } + fmt.Printf("Updated: %s\n", flagPath) + return nil +} + +func main() { + var commonFlags Flags + var configs *rc_lib.ReleaseConfigs + topDir, err := rc_lib.GetTopDir() + + // Handle the common arguments + flag.StringVar(&commonFlags.top, "top", topDir, "path to top of workspace") + flag.BoolVar(&commonFlags.quiet, "quiet", false, "disable warning messages") + flag.Var(&commonFlags.maps, "map", "path to a release_config_map.textproto. may be repeated") + flag.StringVar(&commonFlags.outDir, "out-dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created") + flag.Var(&commonFlags.targetReleases, "release", "TARGET_RELEASE for this build") + flag.BoolVar(&commonFlags.allReleases, "all-releases", false, "operate on all releases. (Ignored for set command)") + flag.BoolVar(&commonFlags.useGetBuildVar, "use-get-build-var", true, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get needed maps") + flag.BoolVar(&commonFlags.debug, "debug", false, "turn on debugging output for errors") + flag.Parse() + + errorExit := func(err error) { + if commonFlags.debug { + panic(err) + } + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } + + if commonFlags.quiet { + rc_lib.DisableWarnings() + } + + if len(commonFlags.targetReleases) == 0 { + release, ok := os.LookupEnv("TARGET_RELEASE") + if ok { + commonFlags.targetReleases = rc_lib.StringList{release} + } else { + commonFlags.targetReleases = rc_lib.StringList{"trunk_staging"} + } + } + + if err = os.Chdir(commonFlags.top); err != nil { + errorExit(err) + } + + // Get the current state of flagging. + relName := commonFlags.targetReleases[0] + if relName == "--all" || relName == "-all" { + commonFlags.allReleases = true + } + configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, relName, commonFlags.useGetBuildVar) + if err != nil { + errorExit(err) + } + + if cmd, ok := commandMap[flag.Arg(0)]; ok { + args := flag.Args() + if err = cmd(configs, commonFlags, args[0], args[1:]); err != nil { + errorExit(err) + } + } +} diff --git a/cmd/release_config/crunch_flags/Android.bp b/cmd/release_config/crunch_flags/Android.bp new file mode 100644 index 000000000..89c95913d --- /dev/null +++ b/cmd/release_config/crunch_flags/Android.bp @@ -0,0 +1,32 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +blueprint_go_binary { + name: "crunch-flags", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-lib", + "soong-cmd-release_config-proto", + ], + srcs: [ + "main.go", + ], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-crunch_flags", + pkgPath: "android/soong/cmd/release_config/crunch_flags", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-lib", + "soong-cmd-release_config-proto", + ], + srcs: [ + "main.go", + ], +} diff --git a/cmd/release_config/crunch_flags/main.go b/cmd/release_config/crunch_flags/main.go new file mode 100644 index 000000000..4d763c8d7 --- /dev/null +++ b/cmd/release_config/crunch_flags/main.go @@ -0,0 +1,400 @@ +package main + +import ( + "flag" + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + + rc_lib "android/soong/cmd/release_config/release_config_lib" + rc_proto "android/soong/cmd/release_config/release_config_proto" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" +) + +var ( + // When a flag declaration has an initial value that is a string, the default workflow is PREBUILT. + // If the flag name starts with any of prefixes in manualFlagNamePrefixes, it is MANUAL. + manualFlagNamePrefixes []string = []string{ + "RELEASE_ACONFIG_", + "RELEASE_PLATFORM_", + "RELEASE_BUILD_FLAGS_", + } + + // Set `aconfig_flags_only: true` in these release configs. + aconfigFlagsOnlyConfigs map[string]bool = map[string]bool{ + "trunk_food": true, + } + + // Default namespace value. This is intentionally invalid. + defaultFlagNamespace string = "android_UNKNOWN" + + // What is the current name for "next". + nextName string = "ap3a" +) + +func RenameNext(name string) string { + if name == "next" { + return nextName + } + return name +} + +func WriteFile(path string, message proto.Message) error { + data, err := prototext.MarshalOptions{Multiline: true}.Marshal(message) + if err != nil { + return err + } + + err = os.MkdirAll(filepath.Dir(path), 0775) + if err != nil { + return err + } + return os.WriteFile(path, data, 0644) +} + +func WalkValueFiles(dir string, Func fs.WalkDirFunc) error { + valPath := filepath.Join(dir, "build_config") + if _, err := os.Stat(valPath); err != nil { + fmt.Printf("%s not found, ignoring.\n", valPath) + return nil + } + + return filepath.WalkDir(valPath, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.HasSuffix(d.Name(), ".scl") && d.Type().IsRegular() { + return Func(path, d, err) + } + return nil + }) +} + +func ProcessBuildFlags(dir string, namespaceMap map[string]string) error { + var rootAconfigModule string + + path := filepath.Join(dir, "build_flags.scl") + if _, err := os.Stat(path); err != nil { + fmt.Printf("%s not found, ignoring.\n", path) + return nil + } else { + fmt.Printf("Processing %s\n", path) + } + commentRegexp, err := regexp.Compile("^[[:space:]]*#(?<comment>.+)") + if err != nil { + return err + } + declRegexp, err := regexp.Compile("^[[:space:]]*flag.\"(?<name>[A-Z_0-9]+)\",[[:space:]]*(?<container>[_A-Z]*),[[:space:]]*(?<value>(\"[^\"]*\"|[^\",)]*))") + if err != nil { + return err + } + declIn, err := os.ReadFile(path) + if err != nil { + return err + } + lines := strings.Split(string(declIn), "\n") + var description string + for _, line := range lines { + if comment := commentRegexp.FindStringSubmatch(commentRegexp.FindString(line)); comment != nil { + // Description is the text from any contiguous series of lines before a `flag()` call. + descLine := strings.TrimSpace(comment[commentRegexp.SubexpIndex("comment")]) + if !strings.HasPrefix(descLine, "keep-sorted") { + description += fmt.Sprintf(" %s", descLine) + } + continue + } + matches := declRegexp.FindStringSubmatch(declRegexp.FindString(line)) + if matches == nil { + // The line is neither a comment nor a `flag()` call. + // Discard any description we have gathered and process the next line. + description = "" + continue + } + declName := matches[declRegexp.SubexpIndex("name")] + declValue := matches[declRegexp.SubexpIndex("value")] + description = strings.TrimSpace(description) + containers := []string{strings.ToLower(matches[declRegexp.SubexpIndex("container")])} + if containers[0] == "all" { + containers = []string{"product", "system", "system_ext", "vendor"} + } + var namespace string + var ok bool + if namespace, ok = namespaceMap[declName]; !ok { + namespace = defaultFlagNamespace + } + flagDeclaration := &rc_proto.FlagDeclaration{ + Name: proto.String(declName), + Namespace: proto.String(namespace), + Description: proto.String(description), + Containers: containers, + } + description = "" + // Most build flags are `workflow: PREBUILT`. + workflow := rc_proto.Workflow(rc_proto.Workflow_PREBUILT) + switch { + case declName == "RELEASE_ACONFIG_VALUE_SETS": + rootAconfigModule = declValue[1 : len(declValue)-1] + continue + case strings.HasPrefix(declValue, "\""): + // String values mean that the flag workflow is (most likely) either MANUAL or PREBUILT. + declValue = declValue[1 : len(declValue)-1] + flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{declValue}} + for _, prefix := range manualFlagNamePrefixes { + if strings.HasPrefix(declName, prefix) { + workflow = rc_proto.Workflow(rc_proto.Workflow_MANUAL) + break + } + } + case declValue == "False" || declValue == "True": + // Boolean values are LAUNCH flags. + flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{declValue == "True"}} + workflow = rc_proto.Workflow(rc_proto.Workflow_LAUNCH) + case declValue == "None": + // Use PREBUILT workflow with no initial value. + default: + fmt.Printf("%s: Unexpected value %s=%s\n", path, declName, declValue) + } + flagDeclaration.Workflow = &workflow + if flagDeclaration != nil { + declPath := filepath.Join(dir, "flag_declarations", fmt.Sprintf("%s.textproto", declName)) + err := WriteFile(declPath, flagDeclaration) + if err != nil { + return err + } + } + } + if rootAconfigModule != "" { + rootProto := &rc_proto.ReleaseConfig{ + Name: proto.String("root"), + AconfigValueSets: []string{rootAconfigModule}, + } + return WriteFile(filepath.Join(dir, "release_configs", "root.textproto"), rootProto) + } + return nil +} + +func ProcessBuildConfigs(dir, name string, paths []string, releaseProto *rc_proto.ReleaseConfig) error { + valRegexp, err := regexp.Compile("[[:space:]]+value.\"(?<name>[A-Z_0-9]+)\",[[:space:]]*(?<value>(\"[^\"]*\"|[^\",)]*))") + if err != nil { + return err + } + for _, path := range paths { + fmt.Printf("Processing %s\n", path) + valIn, err := os.ReadFile(path) + if err != nil { + fmt.Printf("%s: error: %v\n", path, err) + return err + } + vals := valRegexp.FindAllString(string(valIn), -1) + for _, val := range vals { + matches := valRegexp.FindStringSubmatch(val) + valValue := matches[valRegexp.SubexpIndex("value")] + valName := matches[valRegexp.SubexpIndex("name")] + flagValue := &rc_proto.FlagValue{ + Name: proto.String(valName), + } + switch { + case valName == "RELEASE_ACONFIG_VALUE_SETS": + flagValue = nil + if releaseProto.AconfigValueSets == nil { + releaseProto.AconfigValueSets = []string{} + } + releaseProto.AconfigValueSets = append(releaseProto.AconfigValueSets, valValue[1:len(valValue)-1]) + case strings.HasPrefix(valValue, "\""): + valValue = valValue[1 : len(valValue)-1] + flagValue.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{valValue}} + case valValue == "None": + // nothing to do here. + case valValue == "True": + flagValue.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{true}} + case valValue == "False": + flagValue.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}} + default: + fmt.Printf("%s: Unexpected value %s=%s\n", path, valName, valValue) + } + if flagValue != nil { + if releaseProto.GetAconfigFlagsOnly() { + return fmt.Errorf("%s does not allow build flag overrides", RenameNext(name)) + } + valPath := filepath.Join(dir, "flag_values", RenameNext(name), fmt.Sprintf("%s.textproto", valName)) + err := WriteFile(valPath, flagValue) + if err != nil { + return err + } + } + } + } + return err +} + +var ( + allContainers = func() []string { + return []string{"product", "system", "system_ext", "vendor"} + }() +) + +func ProcessReleaseConfigMap(dir string, descriptionMap map[string]string) error { + path := filepath.Join(dir, "release_config_map.mk") + if _, err := os.Stat(path); err != nil { + fmt.Printf("%s not found, ignoring.\n", path) + return nil + } else { + fmt.Printf("Processing %s\n", path) + } + configRegexp, err := regexp.Compile("^..call[[:space:]]+declare-release-config,[[:space:]]+(?<name>[_a-z0-9A-Z]+),[[:space:]]+(?<files>[^,]*)(,[[:space:]]*(?<inherits>.*)|[[:space:]]*)[)]$") + if err != nil { + return err + } + aliasRegexp, err := regexp.Compile("^..call[[:space:]]+alias-release-config,[[:space:]]+(?<name>[_a-z0-9A-Z]+),[[:space:]]+(?<target>[_a-z0-9A-Z]+)") + if err != nil { + return err + } + + mapIn, err := os.ReadFile(path) + if err != nil { + return err + } + cleanDir := strings.TrimLeft(dir, "../") + var defaultContainers []string + switch { + case strings.HasPrefix(cleanDir, "build/") || cleanDir == "vendor/google_shared/build": + defaultContainers = allContainers + case cleanDir == "vendor/google/release": + defaultContainers = allContainers + default: + defaultContainers = []string{"vendor"} + } + releaseConfigMap := &rc_proto.ReleaseConfigMap{DefaultContainers: defaultContainers} + // If we find a description for the directory, include it. + if description, ok := descriptionMap[cleanDir]; ok { + releaseConfigMap.Description = proto.String(description) + } + lines := strings.Split(string(mapIn), "\n") + for _, line := range lines { + alias := aliasRegexp.FindStringSubmatch(aliasRegexp.FindString(line)) + if alias != nil { + fmt.Printf("processing alias %s\n", line) + name := alias[aliasRegexp.SubexpIndex("name")] + target := alias[aliasRegexp.SubexpIndex("target")] + if target == "next" { + if RenameNext(target) != name { + return fmt.Errorf("Unexpected name for next (%s)", RenameNext(target)) + } + target, name = name, target + } + releaseConfigMap.Aliases = append(releaseConfigMap.Aliases, + &rc_proto.ReleaseAlias{ + Name: proto.String(name), + Target: proto.String(target), + }) + } + config := configRegexp.FindStringSubmatch(configRegexp.FindString(line)) + if config == nil { + continue + } + name := config[configRegexp.SubexpIndex("name")] + releaseConfig := &rc_proto.ReleaseConfig{ + Name: proto.String(RenameNext(name)), + } + if aconfigFlagsOnlyConfigs[name] { + releaseConfig.AconfigFlagsOnly = proto.Bool(true) + } + configFiles := config[configRegexp.SubexpIndex("files")] + files := strings.Split(strings.ReplaceAll(configFiles, "$(local_dir)", dir+"/"), " ") + configInherits := config[configRegexp.SubexpIndex("inherits")] + if len(configInherits) > 0 { + releaseConfig.Inherits = strings.Split(configInherits, " ") + } + err := ProcessBuildConfigs(dir, name, files, releaseConfig) + if err != nil { + return err + } + + releasePath := filepath.Join(dir, "release_configs", fmt.Sprintf("%s.textproto", RenameNext(name))) + err = WriteFile(releasePath, releaseConfig) + if err != nil { + return err + } + } + return WriteFile(filepath.Join(dir, "release_config_map.textproto"), releaseConfigMap) +} + +func main() { + var err error + var top string + var dirs rc_lib.StringList + var namespacesFile string + var descriptionsFile string + var debug bool + defaultTopDir, err := rc_lib.GetTopDir() + + flag.StringVar(&top, "top", defaultTopDir, "path to top of workspace") + flag.Var(&dirs, "dir", "directory to process, relative to the top of the workspace") + flag.StringVar(&namespacesFile, "namespaces", "", "location of file with 'flag_name namespace' information") + flag.StringVar(&descriptionsFile, "descriptions", "", "location of file with 'directory description' information") + flag.BoolVar(&debug, "debug", false, "turn on debugging output for errors") + flag.Parse() + + errorExit := func(err error) { + if debug { + panic(err) + } + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } + + if err = os.Chdir(top); err != nil { + errorExit(err) + } + if len(dirs) == 0 { + dirs = rc_lib.StringList{"build/release", "vendor/google_shared/build/release", "vendor/google/release"} + } + + namespaceMap := make(map[string]string) + if namespacesFile != "" { + data, err := os.ReadFile(namespacesFile) + if err != nil { + errorExit(err) + } + for idx, line := range strings.Split(string(data), "\n") { + fields := strings.Split(line, " ") + if len(fields) > 2 { + errorExit(fmt.Errorf("line %d: too many fields: %s", idx, line)) + } + namespaceMap[fields[0]] = fields[1] + } + + } + + descriptionMap := make(map[string]string) + descriptionMap["build/release"] = "Published open-source flags and declarations" + if descriptionsFile != "" { + data, err := os.ReadFile(descriptionsFile) + if err != nil { + errorExit(err) + } + for _, line := range strings.Split(string(data), "\n") { + if strings.TrimSpace(line) != "" { + fields := strings.SplitN(line, " ", 2) + descriptionMap[fields[0]] = fields[1] + } + } + + } + + for _, dir := range dirs { + err = ProcessBuildFlags(dir, namespaceMap) + if err != nil { + errorExit(err) + } + + err = ProcessReleaseConfigMap(dir, descriptionMap) + if err != nil { + errorExit(err) + } + } +} diff --git a/cmd/release_config/release_config/Android.bp b/cmd/release_config/release_config/Android.bp new file mode 100644 index 000000000..3c7382637 --- /dev/null +++ b/cmd/release_config/release_config/Android.bp @@ -0,0 +1,18 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-release_config", + pkgPath: "android/soong/cmd/release_config/release_config", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-proto", + "soong-cmd-release_config-lib", + ], + srcs: [ + "main.go", + ], +} diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go new file mode 100644 index 000000000..101dbe381 --- /dev/null +++ b/cmd/release_config/release_config/main.go @@ -0,0 +1,123 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + + rc_lib "android/soong/cmd/release_config/release_config_lib" +) + +func main() { + var top string + var quiet bool + var releaseConfigMapPaths rc_lib.StringList + var targetRelease string + var outputDir string + var err error + var configs *rc_lib.ReleaseConfigs + var json, pb, textproto bool + var product string + var allMake bool + var useBuildVar bool + var guard bool + + defaultRelease := os.Getenv("TARGET_RELEASE") + if defaultRelease == "" { + defaultRelease = "trunk_staging" + } + + flag.StringVar(&top, "top", ".", "path to top of workspace") + flag.StringVar(&product, "product", os.Getenv("TARGET_PRODUCT"), "TARGET_PRODUCT for the build") + flag.BoolVar(&quiet, "quiet", false, "disable warning messages") + flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated") + flag.StringVar(&targetRelease, "release", defaultRelease, "TARGET_RELEASE for this build") + flag.StringVar(&outputDir, "out_dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created") + flag.BoolVar(&textproto, "textproto", true, "write artifacts as text protobuf") + flag.BoolVar(&json, "json", true, "write artifacts as json") + flag.BoolVar(&pb, "pb", true, "write artifacts as binary protobuf") + flag.BoolVar(&allMake, "all_make", true, "write makefiles for all release configs") + flag.BoolVar(&useBuildVar, "use_get_build_var", false, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS") + flag.BoolVar(&guard, "guard", true, "whether to guard with RELEASE_BUILD_FLAGS_IN_PROTOBUF") + + flag.Parse() + + if quiet { + rc_lib.DisableWarnings() + } + + if err = os.Chdir(top); err != nil { + panic(err) + } + configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease, useBuildVar) + if err != nil { + panic(err) + } + config, err := configs.GetReleaseConfig(targetRelease) + if err != nil { + panic(err) + } + err = os.MkdirAll(outputDir, 0775) + if err != nil { + panic(err) + } + + makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, targetRelease)) + useProto, ok := config.FlagArtifacts["RELEASE_BUILD_FLAGS_IN_PROTOBUF"] + if guard && (!ok || rc_lib.MarshalValue(useProto.Value) == "") { + // We were told to guard operation and either we have no build flag, or it is False. + // Write an empty file so that release_config.mk will use the old process. + os.WriteFile(makefilePath, []byte{}, 0644) + } else if allMake { + // Write one makefile per release config, using the canonical release name. + for k, _ := range configs.ReleaseConfigs { + makefilePath = filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, k)) + err = configs.WriteMakefile(makefilePath, k) + if err != nil { + panic(err) + } + } + } else { + err = configs.WriteMakefile(makefilePath, targetRelease) + if err != nil { + panic(err) + } + } + if json { + err = configs.WriteArtifact(outputDir, product, "json") + if err != nil { + panic(err) + } + } + if pb { + err = configs.WriteArtifact(outputDir, product, "pb") + if err != nil { + panic(err) + } + } + if textproto { + err = configs.WriteArtifact(outputDir, product, "textproto") + if err != nil { + panic(err) + } + } + if err = config.WritePartitionBuildFlags(outputDir, product, targetRelease); err != nil { + panic(err) + } + +} diff --git a/cmd/release_config/release_config_lib/Android.bp b/cmd/release_config/release_config_lib/Android.bp new file mode 100644 index 000000000..0c67e1106 --- /dev/null +++ b/cmd/release_config/release_config_lib/Android.bp @@ -0,0 +1,36 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-lib", + pkgPath: "android/soong/cmd/release_config/release_config_lib", + deps: [ + "golang-protobuf-encoding-prototext", + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + "soong-cmd-release_config-proto", + ], + srcs: [ + "flag_artifact.go", + "flag_declaration.go", + "flag_value.go", + "release_config.go", + "release_configs.go", + "util.go", + ], +} diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go new file mode 100644 index 000000000..cba1b5cd8 --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_artifact.go @@ -0,0 +1,142 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "fmt" + + rc_proto "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +// A flag artifact, with its final value and declaration/override history. +type FlagArtifact struct { + // The flag_declaration message. + FlagDeclaration *rc_proto.FlagDeclaration + + // The index of the config directory where this flag was declared. + // Flag values cannot be set in a location with a lower index. + DeclarationIndex int + + // A history of value assignments and overrides. + Traces []*rc_proto.Tracepoint + + // The value of the flag. + Value *rc_proto.Value + + // This flag is redacted. Set by UpdateValue when the FlagValue proto + // says to redact it. + Redacted bool +} + +// Key is flag name. +type FlagArtifacts map[string]*FlagArtifact + +// Create a clone of the flag artifact. +// +// Returns: +// +// *FlagArtifact: the copy of the artifact. +func (src *FlagArtifact) Clone() *FlagArtifact { + value := &rc_proto.Value{} + proto.Merge(value, src.Value) + return &FlagArtifact{ + FlagDeclaration: src.FlagDeclaration, + Traces: src.Traces, + Value: value, + } +} + +// Clone FlagArtifacts. +// +// Returns: +// +// FlagArtifacts: a copy of the source FlagArtifacts. +func (src FlagArtifacts) Clone() (dst FlagArtifacts) { + if dst == nil { + dst = make(FlagArtifacts) + } + for k, v := range src { + dst[k] = v.Clone() + } + return +} + +// Update the value of a flag. +// +// This appends to flagArtifact.Traces, and updates flagArtifact.Value. +// +// Args: +// +// flagValue FlagValue: the value to assign +// +// Returns: +// +// error: any error encountered +func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { + name := *flagValue.proto.Name + fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value}) + if flagValue.proto.GetRedacted() { + fa.Redacted = true + fmt.Printf("Redacting flag %s in %s\n", name, flagValue.path) + return nil + } + if fa.Value.GetObsolete() { + return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces) + } + var newValue *rc_proto.Value + switch val := flagValue.proto.Value.Val.(type) { + case *rc_proto.Value_StringValue: + newValue = &rc_proto.Value{Val: &rc_proto.Value_StringValue{val.StringValue}} + case *rc_proto.Value_BoolValue: + newValue = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{val.BoolValue}} + case *rc_proto.Value_Obsolete: + if !val.Obsolete { + return fmt.Errorf("%s: Cannot set obsolete=false. Trace=%v", name, fa.Traces) + } + newValue = &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}} + default: + return fmt.Errorf("Invalid type for flag_value: %T. Trace=%v", val, fa.Traces) + } + if proto.Equal(newValue, fa.Value) { + warnf("%s: redundant override (set in %s)\n", flagValue.path, *fa.Traces[len(fa.Traces)-2].Source) + } + fa.Value = newValue + return nil +} + +// Marshal the FlagArtifact into a flag_artifact message. +func (fa *FlagArtifact) Marshal() (*rc_proto.FlagArtifact, error) { + if fa.Redacted { + return nil, nil + } + return &rc_proto.FlagArtifact{ + FlagDeclaration: fa.FlagDeclaration, + Value: fa.Value, + Traces: fa.Traces, + }, nil +} + +// Marshal the FlagArtifact without Traces. +func (fa *FlagArtifact) MarshalWithoutTraces() (*rc_proto.FlagArtifact, error) { + if fa.Redacted { + return nil, nil + } + return &rc_proto.FlagArtifact{ + FlagDeclaration: fa.FlagDeclaration, + Value: fa.Value, + }, nil +} diff --git a/cmd/release_config/release_config_lib/flag_declaration.go b/cmd/release_config/release_config_lib/flag_declaration.go new file mode 100644 index 000000000..97d4d4c76 --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_declaration.go @@ -0,0 +1,27 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + rc_proto "android/soong/cmd/release_config/release_config_proto" +) + +func FlagDeclarationFactory(protoPath string) (fd *rc_proto.FlagDeclaration) { + fd = &rc_proto.FlagDeclaration{} + if protoPath != "" { + LoadMessage(protoPath, fd) + } + return fd +} diff --git a/cmd/release_config/release_config_lib/flag_value.go b/cmd/release_config/release_config_lib/flag_value.go new file mode 100644 index 000000000..59021e260 --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_value.go @@ -0,0 +1,76 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "strings" + + rc_proto "android/soong/cmd/release_config/release_config_proto" +) + +type FlagValue struct { + // The path providing this value. + path string + + // Protobuf + proto rc_proto.FlagValue +} + +func FlagValueFactory(protoPath string) (fv *FlagValue) { + fv = &FlagValue{path: protoPath} + if protoPath != "" { + LoadMessage(protoPath, &fv.proto) + } + return fv +} + +func UnmarshalValue(str string) *rc_proto.Value { + ret := &rc_proto.Value{} + switch v := strings.ToLower(str); v { + case "true": + ret = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{true}} + case "false": + ret = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}} + case "##obsolete": + ret = &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}} + default: + ret = &rc_proto.Value{Val: &rc_proto.Value_StringValue{str}} + } + return ret +} + +func MarshalValue(value *rc_proto.Value) string { + if value == nil { + return "" + } + switch val := value.Val.(type) { + case *rc_proto.Value_UnspecifiedValue: + // Value was never set. + return "" + case *rc_proto.Value_StringValue: + return val.StringValue + case *rc_proto.Value_BoolValue: + if val.BoolValue { + return "true" + } + // False ==> empty string + return "" + case *rc_proto.Value_Obsolete: + return " #OBSOLETE" + default: + // Flagged as error elsewhere, so return empty string here. + return "" + } +} diff --git a/cmd/release_config/release_config_lib/flag_value_test.go b/cmd/release_config/release_config_lib/flag_value_test.go new file mode 100644 index 000000000..8a98baf6a --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_value_test.go @@ -0,0 +1,114 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "os" + "path/filepath" + "testing" + + rc_proto "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +type testCaseFlagValueFactory struct { + protoPath string + name string + data []byte + expected rc_proto.FlagValue + err error +} + +func (tc testCaseFlagValueFactory) assertProtoEqual(t *testing.T, expected, actual proto.Message) { + if !proto.Equal(expected, actual) { + t.Errorf("Expected %q found %q", expected, actual) + } +} + +func TestFlagValueFactory(t *testing.T) { + testCases := []testCaseFlagValueFactory{ + { + name: "stringVal", + protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto", + data: []byte(`name: "RELEASE_FOO" value {string_value: "BAR"}`), + expected: rc_proto.FlagValue{ + Name: proto.String("RELEASE_FOO"), + Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}}, + }, + err: nil, + }, + } + for _, tc := range testCases { + var err error + tempdir := t.TempDir() + path := filepath.Join(tempdir, tc.protoPath) + if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { + t.Fatal(err) + } + if err = os.WriteFile(path, tc.data, 0644); err != nil { + t.Fatal(err) + } + actual := FlagValueFactory(path) + tc.assertProtoEqual(t, &tc.expected, &actual.proto) + } +} + +type testCaseMarshalValue struct { + name string + value *rc_proto.Value + expected string +} + +func TestMarshalValue(t *testing.T) { + testCases := []testCaseMarshalValue{ + { + name: "nil", + value: nil, + expected: "", + }, + { + name: "unspecified", + value: &rc_proto.Value{}, + expected: "", + }, + { + name: "false", + value: &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}}, + expected: "", + }, + { + name: "true", + value: &rc_proto.Value{Val: &rc_proto.Value_BoolValue{true}}, + expected: "true", + }, + { + name: "string", + value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}}, + expected: "BAR", + }, + { + name: "obsolete", + value: &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}}, + expected: " #OBSOLETE", + }, + } + for _, tc := range testCases { + actual := MarshalValue(tc.value) + if actual != tc.expected { + t.Errorf("Expected %q found %q", tc.expected, actual) + } + } +} diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go new file mode 100644 index 000000000..f25cc6e66 --- /dev/null +++ b/cmd/release_config/release_config_lib/release_config.go @@ -0,0 +1,267 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "cmp" + "fmt" + "path/filepath" + "slices" + "sort" + "strings" + + rc_proto "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +// One directory's contribution to the a release config. +type ReleaseConfigContribution struct { + // Paths to files providing this config. + path string + + // The index of the config directory where this release config + // contribution was declared. + // Flag values cannot be set in a location with a lower index. + DeclarationIndex int + + // Protobufs relevant to the config. + proto rc_proto.ReleaseConfig + + FlagValues []*FlagValue +} + +// A generated release config. +type ReleaseConfig struct { + // the Name of the release config + Name string + + // The index of the config directory where this release config was + // first declared. + // Flag values cannot be set in a location with a lower index. + DeclarationIndex int + + // What contributes to this config. + Contributions []*ReleaseConfigContribution + + // Aliases for this release + OtherNames []string + + // The names of release configs that we inherit + InheritNames []string + + // True if this release config only allows inheritance and aconfig flag + // overrides. Build flag value overrides are an error. + AconfigFlagsOnly bool + + // Unmarshalled flag artifacts + FlagArtifacts FlagArtifacts + + // Generated release config + ReleaseConfigArtifact *rc_proto.ReleaseConfigArtifact + + // We have begun compiling this release config. + compileInProgress bool + + // Partitioned artifacts for {partition}/etc/build_flags.json + PartitionBuildFlags map[string]*rc_proto.FlagArtifacts +} + +func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) { + return &ReleaseConfig{Name: name, DeclarationIndex: index} +} + +func (config *ReleaseConfig) InheritConfig(iConfig *ReleaseConfig) error { + for _, fa := range iConfig.FlagArtifacts { + name := *fa.FlagDeclaration.Name + myFa, ok := config.FlagArtifacts[name] + if !ok { + return fmt.Errorf("Could not inherit flag %s from %s", name, iConfig.Name) + } + if name == "RELEASE_ACONFIG_VALUE_SETS" { + if len(fa.Traces) > 0 { + myFa.Traces = append(myFa.Traces, fa.Traces...) + myFa.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{ + myFa.Value.GetStringValue() + " " + fa.Value.GetStringValue()}} + } + } else if len(fa.Traces) > 1 { + // A value was assigned. Set our value. + myFa.Traces = append(myFa.Traces, fa.Traces[1:]...) + myFa.Value = fa.Value + } + } + return nil +} + +func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error { + if config.ReleaseConfigArtifact != nil { + return nil + } + if config.compileInProgress { + return fmt.Errorf("Loop detected for release config %s", config.Name) + } + config.compileInProgress = true + isRoot := config.Name == "root" + + // Start with only the flag declarations. + config.FlagArtifacts = configs.FlagArtifacts.Clone() + releaseAconfigValueSets := config.FlagArtifacts["RELEASE_ACONFIG_VALUE_SETS"] + + // Generate any configs we need to inherit. This will detect loops in + // the config. + contributionsToApply := []*ReleaseConfigContribution{} + myInherits := []string{} + myInheritsSet := make(map[string]bool) + // If there is a "root" release config, it is the start of every inheritance chain. + _, err := configs.GetReleaseConfig("root") + if err == nil && !isRoot { + config.InheritNames = append([]string{"root"}, config.InheritNames...) + } + for _, inherit := range config.InheritNames { + if _, ok := myInheritsSet[inherit]; ok { + continue + } + myInherits = append(myInherits, inherit) + myInheritsSet[inherit] = true + iConfig, err := configs.GetReleaseConfig(inherit) + if err != nil { + return err + } + iConfig.GenerateReleaseConfig(configs) + if err := config.InheritConfig(iConfig); err != nil { + return err + } + } + contributionsToApply = append(contributionsToApply, config.Contributions...) + + workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL) + myDirsMap := make(map[int]bool) + for _, contrib := range contributionsToApply { + contribAconfigValueSets := []string{} + // Gather the aconfig_value_sets from this contribution, allowing duplicates for simplicity. + for _, v := range contrib.proto.AconfigValueSets { + contribAconfigValueSets = append(contribAconfigValueSets, v) + } + contribAconfigValueSetsString := strings.Join(contribAconfigValueSets, " ") + releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{ + releaseAconfigValueSets.Value.GetStringValue() + " " + contribAconfigValueSetsString}} + releaseAconfigValueSets.Traces = append( + releaseAconfigValueSets.Traces, + &rc_proto.Tracepoint{ + Source: proto.String(contrib.path), + Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{contribAconfigValueSetsString}}, + }) + + myDirsMap[contrib.DeclarationIndex] = true + if config.AconfigFlagsOnly && len(contrib.FlagValues) > 0 { + return fmt.Errorf("%s does not allow build flag overrides", config.Name) + } + for _, value := range contrib.FlagValues { + name := *value.proto.Name + fa, ok := config.FlagArtifacts[name] + if !ok { + return fmt.Errorf("Setting value for undefined flag %s in %s\n", name, value.path) + } + myDirsMap[fa.DeclarationIndex] = true + if fa.DeclarationIndex > contrib.DeclarationIndex { + // Setting location is to the left of declaration. + return fmt.Errorf("Setting value for flag %s not allowed in %s\n", name, value.path) + } + if isRoot && *fa.FlagDeclaration.Workflow != workflowManual { + // The "root" release config can only contain workflow: MANUAL flags. + return fmt.Errorf("Setting value for non-MANUAL flag %s is not allowed in %s", name, value.path) + } + if err := fa.UpdateValue(*value); err != nil { + return err + } + if fa.Redacted { + delete(config.FlagArtifacts, name) + } + } + } + // Now remove any duplicates from the actual value of RELEASE_ACONFIG_VALUE_SETS + myAconfigValueSets := []string{} + myAconfigValueSetsMap := map[string]bool{} + for _, v := range strings.Split(releaseAconfigValueSets.Value.GetStringValue(), " ") { + if myAconfigValueSetsMap[v] { + continue + } + myAconfigValueSetsMap[v] = true + myAconfigValueSets = append(myAconfigValueSets, v) + } + releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.TrimSpace(strings.Join(myAconfigValueSets, " "))}} + + directories := []string{} + for idx, confDir := range configs.configDirs { + if _, ok := myDirsMap[idx]; ok { + directories = append(directories, confDir) + } + } + + // Now build the per-partition artifacts + config.PartitionBuildFlags = make(map[string]*rc_proto.FlagArtifacts) + for _, v := range config.FlagArtifacts { + artifact, err := v.MarshalWithoutTraces() + if err != nil { + return err + } + for _, container := range v.FlagDeclaration.Containers { + if _, ok := config.PartitionBuildFlags[container]; !ok { + config.PartitionBuildFlags[container] = &rc_proto.FlagArtifacts{} + } + config.PartitionBuildFlags[container].FlagArtifacts = append(config.PartitionBuildFlags[container].FlagArtifacts, artifact) + } + } + config.ReleaseConfigArtifact = &rc_proto.ReleaseConfigArtifact{ + Name: proto.String(config.Name), + OtherNames: config.OtherNames, + FlagArtifacts: func() []*rc_proto.FlagArtifact { + ret := []*rc_proto.FlagArtifact{} + flagNames := []string{} + for k := range config.FlagArtifacts { + flagNames = append(flagNames, k) + } + sort.Strings(flagNames) + for _, flagName := range flagNames { + flag := config.FlagArtifacts[flagName] + ret = append(ret, &rc_proto.FlagArtifact{ + FlagDeclaration: flag.FlagDeclaration, + Traces: flag.Traces, + Value: flag.Value, + }) + } + return ret + }(), + AconfigValueSets: myAconfigValueSets, + Inherits: myInherits, + Directories: directories, + } + + config.compileInProgress = false + return nil +} + +func (config *ReleaseConfig) WritePartitionBuildFlags(outDir, product, targetRelease string) error { + var err error + for partition, flags := range config.PartitionBuildFlags { + slices.SortFunc(flags.FlagArtifacts, func(a, b *rc_proto.FlagArtifact) int { + return cmp.Compare(*a.FlagDeclaration.Name, *b.FlagDeclaration.Name) + }) + if err = WriteMessage(filepath.Join(outDir, fmt.Sprintf("build_flags_%s-%s-%s.json", partition, config.Name, product)), flags); err != nil { + return err + } + } + return nil +} diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go new file mode 100644 index 000000000..34294002c --- /dev/null +++ b/cmd/release_config/release_config_lib/release_configs.go @@ -0,0 +1,433 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "cmp" + "fmt" + "io/fs" + "os" + "path/filepath" + "slices" + "strings" + + rc_proto "android/soong/cmd/release_config/release_config_proto" + + "google.golang.org/protobuf/proto" +) + +// A single release_config_map.textproto and its associated data. +// Used primarily for debugging. +type ReleaseConfigMap struct { + // The path to this release_config_map file. + path string + + // Data received + proto rc_proto.ReleaseConfigMap + + // Map of name:contribution for release config contributions. + ReleaseConfigContributions map[string]*ReleaseConfigContribution + + // Flags declared this directory's flag_declarations/*.textproto + FlagDeclarations []rc_proto.FlagDeclaration +} + +type ReleaseConfigDirMap map[string]int + +// The generated release configs. +type ReleaseConfigs struct { + // Ordered list of release config maps processed. + ReleaseConfigMaps []*ReleaseConfigMap + + // Aliases + Aliases map[string]*string + + // Dictionary of flag_name:FlagDeclaration, with no overrides applied. + FlagArtifacts FlagArtifacts + + // Generated release configs artifact + Artifact rc_proto.ReleaseConfigsArtifact + + // Dictionary of name:ReleaseConfig + // Use `GetReleaseConfigs(name)` to get a release config. + ReleaseConfigs map[string]*ReleaseConfig + + // Map of directory to *ReleaseConfigMap + releaseConfigMapsMap map[string]*ReleaseConfigMap + + // The list of config directories used. + configDirs []string + + // A map from the config directory to its order in the list of config + // directories. + configDirIndexes ReleaseConfigDirMap +} + +// Write the "all_release_configs" artifact. +// +// The file will be in "{outDir}/all_release_configs-{product}.{format}" +// +// Args: +// +// outDir string: directory path. Will be created if not present. +// product string: TARGET_PRODUCT for the release_configs. +// format string: one of "json", "pb", or "textproto" +// +// Returns: +// +// error: Any error encountered. +func (configs *ReleaseConfigs) WriteArtifact(outDir, product, format string) error { + return WriteMessage( + filepath.Join(outDir, fmt.Sprintf("all_release_configs-%s.%s", product, format)), + &configs.Artifact) +} + +func ReleaseConfigsFactory() (c *ReleaseConfigs) { + configs := ReleaseConfigs{ + Aliases: make(map[string]*string), + FlagArtifacts: make(map[string]*FlagArtifact), + ReleaseConfigs: make(map[string]*ReleaseConfig), + releaseConfigMapsMap: make(map[string]*ReleaseConfigMap), + configDirs: []string{}, + configDirIndexes: make(ReleaseConfigDirMap), + } + workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL) + releaseAconfigValueSets := FlagArtifact{ + FlagDeclaration: &rc_proto.FlagDeclaration{ + Name: proto.String("RELEASE_ACONFIG_VALUE_SETS"), + Namespace: proto.String("android_UNKNOWN"), + Description: proto.String("Aconfig value sets assembled by release-config"), + Workflow: &workflowManual, + Containers: []string{"system", "system_ext", "product", "vendor"}, + Value: &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}}, + }, + DeclarationIndex: -1, + Traces: []*rc_proto.Tracepoint{}, + } + configs.FlagArtifacts["RELEASE_ACONFIG_VALUE_SETS"] = &releaseAconfigValueSets + return &configs +} + +func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) { + m = &ReleaseConfigMap{ + path: protoPath, + ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution), + } + if protoPath != "" { + LoadMessage(protoPath, &m.proto) + } + return m +} + +func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error { + if _, err := os.Stat(path); err != nil { + return fmt.Errorf("%s does not exist\n", path) + } + m := ReleaseConfigMapFactory(path) + if m.proto.DefaultContainers == nil { + return fmt.Errorf("Release config map %s lacks default_containers", path) + } + for _, container := range m.proto.DefaultContainers { + if !validContainer(container) { + return fmt.Errorf("Release config map %s has invalid container %s", path, container) + } + } + dir := filepath.Dir(path) + // Record any aliases, checking for duplicates. + for _, alias := range m.proto.Aliases { + name := *alias.Name + oldTarget, ok := configs.Aliases[name] + if ok { + if *oldTarget != *alias.Target { + return fmt.Errorf("Conflicting alias declarations: %s vs %s", + *oldTarget, *alias.Target) + } + } + configs.Aliases[name] = alias.Target + } + var err error + err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error { + flagDeclaration := FlagDeclarationFactory(path) + // Container must be specified. + if flagDeclaration.Containers == nil { + flagDeclaration.Containers = m.proto.DefaultContainers + } else { + for _, container := range flagDeclaration.Containers { + if !validContainer(container) { + return fmt.Errorf("Flag declaration %s has invalid container %s", path, container) + } + } + } + + // TODO: once we have namespaces initialized, we can throw an error here. + if flagDeclaration.Namespace == nil { + flagDeclaration.Namespace = proto.String("android_UNKNOWN") + } + // If the input didn't specify a value, create one (== UnspecifiedValue). + if flagDeclaration.Value == nil { + flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}} + } + m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration) + name := *flagDeclaration.Name + if name == "RELEASE_ACONFIG_VALUE_SETS" { + return fmt.Errorf("%s: %s is a reserved build flag", path, name) + } + if def, ok := configs.FlagArtifacts[name]; !ok { + configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex} + } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) { + return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name) + } + // Set the initial value in the flag artifact. + configs.FlagArtifacts[name].UpdateValue( + FlagValue{path: path, proto: rc_proto.FlagValue{ + Name: proto.String(name), Value: flagDeclaration.Value}}) + if configs.FlagArtifacts[name].Redacted { + return fmt.Errorf("%s may not be redacted by default.", name) + } + return nil + }) + if err != nil { + return err + } + + err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error { + releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex} + LoadMessage(path, &releaseConfigContribution.proto) + name := *releaseConfigContribution.proto.Name + if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) { + return fmt.Errorf("%s incorrectly declares release config %s", path, name) + } + if _, ok := configs.ReleaseConfigs[name]; !ok { + configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex) + } + config := configs.ReleaseConfigs[name] + config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...) + + // Only walk flag_values/{RELEASE} for defined releases. + err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error { + flagValue := FlagValueFactory(path) + if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) { + return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name) + } + if *flagValue.proto.Name == "RELEASE_ACONFIG_VALUE_SETS" { + return fmt.Errorf("%s: %s is a reserved build flag", path, *flagValue.proto.Name) + } + releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue) + return nil + }) + if err2 != nil { + return err2 + } + if releaseConfigContribution.proto.GetAconfigFlagsOnly() { + config.AconfigFlagsOnly = true + } + m.ReleaseConfigContributions[name] = releaseConfigContribution + config.Contributions = append(config.Contributions, releaseConfigContribution) + return nil + }) + if err != nil { + return err + } + configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m) + configs.releaseConfigMapsMap[dir] = m + return nil +} + +func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) { + trace := []string{name} + for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] { + name = *target + trace = append(trace, name) + } + if config, ok := configs.ReleaseConfigs[name]; ok { + return config, nil + } + return nil, fmt.Errorf("Missing config %s. Trace=%v", name, trace) +} + +// Write the makefile for this targetRelease. +func (configs *ReleaseConfigs) WriteMakefile(outFile, targetRelease string) error { + makeVars := make(map[string]string) + var allReleaseNames []string + for _, v := range configs.ReleaseConfigs { + allReleaseNames = append(allReleaseNames, v.Name) + allReleaseNames = append(allReleaseNames, v.OtherNames...) + } + config, err := configs.GetReleaseConfig(targetRelease) + if err != nil { + return err + } + + myFlagArtifacts := config.FlagArtifacts.Clone() + // Sort the flags by name first. + names := []string{} + for k, _ := range myFlagArtifacts { + names = append(names, k) + } + slices.SortFunc(names, func(a, b string) int { + return cmp.Compare(a, b) + }) + partitions := make(map[string][]string) + + vNames := []string{} + addVar := func(name, suffix, value string) { + fullName := fmt.Sprintf("_ALL_RELEASE_FLAGS.%s.%s", name, suffix) + vNames = append(vNames, fullName) + makeVars[fullName] = value + } + + for _, name := range names { + flag := myFlagArtifacts[name] + decl := flag.FlagDeclaration + + for _, container := range decl.Containers { + partitions[container] = append(partitions[container], name) + } + value := MarshalValue(flag.Value) + makeVars[name] = value + addVar(name, "PARTITIONS", strings.Join(decl.Containers, " ")) + addVar(name, "DEFAULT", MarshalValue(decl.Value)) + addVar(name, "VALUE", value) + addVar(name, "DECLARED_IN", *flag.Traces[0].Source) + addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source) + addVar(name, "NAMESPACE", *decl.Namespace) + } + pNames := []string{} + for k, _ := range partitions { + pNames = append(pNames, k) + } + slices.SortFunc(pNames, func(a, b string) int { + return cmp.Compare(a, b) + }) + + // Now sort the make variables, and output them. + slices.SortFunc(vNames, func(a, b string) int { + return cmp.Compare(a, b) + }) + + // Write the flags as: + // _ALL_RELELASE_FLAGS + // _ALL_RELEASE_FLAGS.PARTITIONS.* + // all _ALL_RELEASE_FLAGS.*, sorted by name + // Final flag values, sorted by name. + data := fmt.Sprintf("# TARGET_RELEASE=%s\n", config.Name) + if targetRelease != config.Name { + data += fmt.Sprintf("# User specified TARGET_RELEASE=%s\n", targetRelease) + } + // The variable _all_release_configs will get deleted during processing, so do not mark it read-only. + data += fmt.Sprintf("_all_release_configs := %s\n", strings.Join(allReleaseNames, " ")) + data += fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " ")) + for _, pName := range pNames { + data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " ")) + } + for _, vName := range vNames { + data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName]) + } + data += "\n\n# Values for all build flags\n" + for _, name := range names { + data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name]) + } + return os.WriteFile(outFile, []byte(data), 0644) +} + +func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) error { + otherNames := make(map[string][]string) + for aliasName, aliasTarget := range configs.Aliases { + if _, ok := configs.ReleaseConfigs[aliasName]; ok { + return fmt.Errorf("Alias %s is a declared release config", aliasName) + } + if _, ok := configs.ReleaseConfigs[*aliasTarget]; !ok { + if _, ok2 := configs.Aliases[*aliasTarget]; !ok2 { + return fmt.Errorf("Alias %s points to non-existing config %s", aliasName, *aliasTarget) + } + } + otherNames[*aliasTarget] = append(otherNames[*aliasTarget], aliasName) + } + for name, aliases := range otherNames { + configs.ReleaseConfigs[name].OtherNames = aliases + } + + for _, config := range configs.ReleaseConfigs { + err := config.GenerateReleaseConfig(configs) + if err != nil { + return err + } + } + + releaseConfig, err := configs.GetReleaseConfig(targetRelease) + if err != nil { + return err + } + configs.Artifact = rc_proto.ReleaseConfigsArtifact{ + ReleaseConfig: releaseConfig.ReleaseConfigArtifact, + OtherReleaseConfigs: func() []*rc_proto.ReleaseConfigArtifact { + orc := []*rc_proto.ReleaseConfigArtifact{} + for name, config := range configs.ReleaseConfigs { + if name != releaseConfig.Name { + orc = append(orc, config.ReleaseConfigArtifact) + } + } + return orc + }(), + ReleaseConfigMapsMap: func() map[string]*rc_proto.ReleaseConfigMap { + ret := make(map[string]*rc_proto.ReleaseConfigMap) + for k, v := range configs.releaseConfigMapsMap { + ret[k] = &v.proto + } + return ret + }(), + } + return nil +} + +func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string, useBuildVar bool) (*ReleaseConfigs, error) { + var err error + + if len(releaseConfigMapPaths) == 0 { + releaseConfigMapPaths, err = GetDefaultMapPaths(useBuildVar) + if err != nil { + return nil, err + } + if len(releaseConfigMapPaths) == 0 { + return nil, fmt.Errorf("No maps found") + } + if !useBuildVar { + warnf("No --map argument provided. Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map ")) + } + } + + configs := ReleaseConfigsFactory() + mapsRead := make(map[string]bool) + for idx, releaseConfigMapPath := range releaseConfigMapPaths { + // Maintain an ordered list of release config directories. + configDir := filepath.Dir(releaseConfigMapPath) + if mapsRead[configDir] { + continue + } + mapsRead[configDir] = true + configs.configDirIndexes[configDir] = idx + configs.configDirs = append(configs.configDirs, configDir) + // Force the path to be the textproto path, so that both the scl and textproto formats can coexist. + releaseConfigMapPath = filepath.Join(configDir, "release_config_map.textproto") + err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx) + if err != nil { + return nil, err + } + } + + // Now that we have all of the release config maps, can meld them and generate the artifacts. + err = configs.GenerateReleaseConfigs(targetRelease) + return configs, err +} diff --git a/cmd/release_config/release_config_lib/util.go b/cmd/release_config/release_config_lib/util.go new file mode 100644 index 000000000..c0ea7897b --- /dev/null +++ b/cmd/release_config/release_config_lib/util.go @@ -0,0 +1,209 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package release_config_lib + +import ( + "encoding/json" + "fmt" + "io/fs" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" +) + +var ( + disableWarnings bool + containerRegexp, _ = regexp.Compile("^[a-z][a-z0-9]*([._][a-z][a-z0-9]*)*$") +) + +type StringList []string + +func (l *StringList) Set(v string) error { + *l = append(*l, v) + return nil +} + +func (l *StringList) String() string { + return fmt.Sprintf("%v", *l) +} + +// Write a marshalled message to a file. +// +// Marshal the message based on the extension of the path we are writing it to. +// +// Args: +// +// path string: the path of the file to write to. Directories are not created. +// Supported extensions are: ".json", ".pb", and ".textproto". +// message proto.Message: the message to write. +// +// Returns: +// +// error: any error encountered. +func WriteMessage(path string, message proto.Message) (err error) { + var data []byte + switch filepath.Ext(path) { + case ".json": + data, err = json.MarshalIndent(message, "", " ") + case ".pb": + data, err = proto.Marshal(message) + case ".textproto": + data, err = prototext.MarshalOptions{Multiline: true}.Marshal(message) + default: + return fmt.Errorf("Unknown message format for %s", path) + } + if err != nil { + return err + } + return os.WriteFile(path, data, 0644) +} + +// Read a message from a file. +// +// The message is unmarshalled based on the extension of the file read. +// +// Args: +// +// path string: the path of the file to read. +// message proto.Message: the message to unmarshal the message into. +// +// Returns: +// +// error: any error encountered. +func LoadMessage(path string, message proto.Message) error { + data, err := os.ReadFile(path) + if err != nil { + return err + } + switch filepath.Ext(path) { + case ".json": + return json.Unmarshal(data, message) + case ".pb": + return proto.Unmarshal(data, message) + case ".textproto": + return prototext.Unmarshal(data, message) + } + return fmt.Errorf("Unknown message format for %s", path) +} + +// Call Func for any textproto files found in {root}/{subdir}. +func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error { + path := filepath.Join(root, subdir) + if _, err := os.Stat(path); err != nil { + // Missing subdirs are not an error. + return nil + } + return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() { + return Func(path, d, err) + } + return nil + }) +} + +// Turn off all warning output +func DisableWarnings() { + disableWarnings = true +} + +func warnf(format string, args ...any) (n int, err error) { + if !disableWarnings { + return fmt.Fprintf(os.Stderr, format, args...) + } + return 0, nil +} + +func validContainer(container string) bool { + return containerRegexp.MatchString(container) +} + +// Returns the default value for release config artifacts. +func GetDefaultOutDir() string { + outEnv := os.Getenv("OUT_DIR") + if outEnv == "" { + outEnv = "out" + } + return filepath.Join(outEnv, "soong", "release-config") +} + +// Find the top of the workspace. +// +// This mirrors the logic in build/envsetup.sh's gettop(). +func GetTopDir() (topDir string, err error) { + workingDir, err := os.Getwd() + if err != nil { + return + } + topFile := "build/make/core/envsetup.mk" + for topDir = workingDir; topDir != "/"; topDir = filepath.Dir(topDir) { + if _, err = os.Stat(filepath.Join(topDir, topFile)); err == nil { + return filepath.Rel(workingDir, topDir) + } + } + return "", fmt.Errorf("Unable to locate top of workspace") +} + +// Return the default list of map files to use. +func GetDefaultMapPaths(queryMaps bool) (defaultMapPaths StringList, err error) { + var defaultLocations StringList + workingDir, err := os.Getwd() + if err != nil { + return + } + defer func() { + os.Chdir(workingDir) + }() + topDir, err := GetTopDir() + os.Chdir(topDir) + + defaultLocations = StringList{ + "build/release/release_config_map.textproto", + "vendor/google_shared/build/release/release_config_map.textproto", + "vendor/google/release/release_config_map.textproto", + } + for _, path := range defaultLocations { + if _, err = os.Stat(path); err == nil { + defaultMapPaths = append(defaultMapPaths, path) + } + } + + var prodMaps string + if queryMaps { + getBuildVar := exec.Command("build/soong/soong_ui.bash", "--dumpvar-mode", "PRODUCT_RELEASE_CONFIG_MAPS") + var stdout strings.Builder + getBuildVar.Stdin = strings.NewReader("") + getBuildVar.Stdout = &stdout + err = getBuildVar.Run() + if err != nil { + return + } + prodMaps = stdout.String() + } else { + prodMaps = os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS") + } + prodMaps = strings.TrimSpace(prodMaps) + if len(prodMaps) > 0 { + defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...) + } + return +} diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp new file mode 100644 index 000000000..8c47f2ac0 --- /dev/null +++ b/cmd/release_config/release_config_proto/Android.bp @@ -0,0 +1,30 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-release_config-proto", + pkgPath: "android/soong/cmd/release_config/release_config_proto", + deps: [ + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + ], + srcs: [ + "build_flags_src.pb.go", + "build_flags_out.pb.go", + ], +} diff --git a/cmd/release_config/release_config_proto/build_flags_out.pb.go b/cmd/release_config/release_config_proto/build_flags_out.pb.go new file mode 100644 index 000000000..483cffac1 --- /dev/null +++ b/cmd/release_config/release_config_proto/build_flags_out.pb.go @@ -0,0 +1,583 @@ +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: build_flags_out.proto + +package release_config_proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Tracepoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Path to declaration or value file relative to $TOP + Source *string `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` +} + +func (x *Tracepoint) Reset() { + *x = Tracepoint{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_out_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Tracepoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Tracepoint) ProtoMessage() {} + +func (x *Tracepoint) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_out_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Tracepoint.ProtoReflect.Descriptor instead. +func (*Tracepoint) Descriptor() ([]byte, []int) { + return file_build_flags_out_proto_rawDescGZIP(), []int{0} +} + +func (x *Tracepoint) GetSource() string { + if x != nil && x.Source != nil { + return *x.Source + } + return "" +} + +func (x *Tracepoint) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +type FlagArtifact struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The original declaration + FlagDeclaration *FlagDeclaration `protobuf:"bytes,1,opt,name=flag_declaration,json=flagDeclaration" json:"flag_declaration,omitempty"` + // Value for the flag + Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` + // Trace of where the flag value was assigned. + Traces []*Tracepoint `protobuf:"bytes,8,rep,name=traces" json:"traces,omitempty"` +} + +func (x *FlagArtifact) Reset() { + *x = FlagArtifact{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_out_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagArtifact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagArtifact) ProtoMessage() {} + +func (x *FlagArtifact) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_out_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagArtifact.ProtoReflect.Descriptor instead. +func (*FlagArtifact) Descriptor() ([]byte, []int) { + return file_build_flags_out_proto_rawDescGZIP(), []int{1} +} + +func (x *FlagArtifact) GetFlagDeclaration() *FlagDeclaration { + if x != nil { + return x.FlagDeclaration + } + return nil +} + +func (x *FlagArtifact) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *FlagArtifact) GetTraces() []*Tracepoint { + if x != nil { + return x.Traces + } + return nil +} + +type FlagArtifacts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The artifacts + FlagArtifacts []*FlagArtifact `protobuf:"bytes,1,rep,name=flag_artifacts,json=flagArtifacts" json:"flag_artifacts,omitempty"` +} + +func (x *FlagArtifacts) Reset() { + *x = FlagArtifacts{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_out_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagArtifacts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagArtifacts) ProtoMessage() {} + +func (x *FlagArtifacts) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_out_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagArtifacts.ProtoReflect.Descriptor instead. +func (*FlagArtifacts) Descriptor() ([]byte, []int) { + return file_build_flags_out_proto_rawDescGZIP(), []int{2} +} + +func (x *FlagArtifacts) GetFlagArtifacts() []*FlagArtifact { + if x != nil { + return x.FlagArtifacts + } + return nil +} + +type ReleaseConfigArtifact struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the release config. + // See # name for format detail + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Other names by which this release is known (for example, `next`) + OtherNames []string `protobuf:"bytes,2,rep,name=other_names,json=otherNames" json:"other_names,omitempty"` + // The complete set of build flags in this release config, after all + // inheritance and other processing is complete. + FlagArtifacts []*FlagArtifact `protobuf:"bytes,3,rep,name=flag_artifacts,json=flagArtifacts" json:"flag_artifacts,omitempty"` + // The (complete) list of aconfig_value_sets Soong modules to use. + AconfigValueSets []string `protobuf:"bytes,4,rep,name=aconfig_value_sets,json=aconfigValueSets" json:"aconfig_value_sets,omitempty"` + // The names of the release_config_artifacts from which we inherited. + // Included for reference only. + Inherits []string `protobuf:"bytes,5,rep,name=inherits" json:"inherits,omitempty"` + // The release config directories used for this config. + // For example, "build/release". + Directories []string `protobuf:"bytes,6,rep,name=directories" json:"directories,omitempty"` +} + +func (x *ReleaseConfigArtifact) Reset() { + *x = ReleaseConfigArtifact{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_out_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReleaseConfigArtifact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseConfigArtifact) ProtoMessage() {} + +func (x *ReleaseConfigArtifact) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_out_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReleaseConfigArtifact.ProtoReflect.Descriptor instead. +func (*ReleaseConfigArtifact) Descriptor() ([]byte, []int) { + return file_build_flags_out_proto_rawDescGZIP(), []int{3} +} + +func (x *ReleaseConfigArtifact) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *ReleaseConfigArtifact) GetOtherNames() []string { + if x != nil { + return x.OtherNames + } + return nil +} + +func (x *ReleaseConfigArtifact) GetFlagArtifacts() []*FlagArtifact { + if x != nil { + return x.FlagArtifacts + } + return nil +} + +func (x *ReleaseConfigArtifact) GetAconfigValueSets() []string { + if x != nil { + return x.AconfigValueSets + } + return nil +} + +func (x *ReleaseConfigArtifact) GetInherits() []string { + if x != nil { + return x.Inherits + } + return nil +} + +func (x *ReleaseConfigArtifact) GetDirectories() []string { + if x != nil { + return x.Directories + } + return nil +} + +type ReleaseConfigsArtifact struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The active release config for this build. + ReleaseConfig *ReleaseConfigArtifact `protobuf:"bytes,1,opt,name=release_config,json=releaseConfig" json:"release_config,omitempty"` + // All other release configs defined for this TARGET_PRODUCT. + OtherReleaseConfigs []*ReleaseConfigArtifact `protobuf:"bytes,2,rep,name=other_release_configs,json=otherReleaseConfigs" json:"other_release_configs,omitempty"` + // Map of release_config_artifact.directories to release_config_map message. + ReleaseConfigMapsMap map[string]*ReleaseConfigMap `protobuf:"bytes,3,rep,name=release_config_maps_map,json=releaseConfigMapsMap" json:"release_config_maps_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` +} + +func (x *ReleaseConfigsArtifact) Reset() { + *x = ReleaseConfigsArtifact{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_out_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReleaseConfigsArtifact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseConfigsArtifact) ProtoMessage() {} + +func (x *ReleaseConfigsArtifact) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_out_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReleaseConfigsArtifact.ProtoReflect.Descriptor instead. +func (*ReleaseConfigsArtifact) Descriptor() ([]byte, []int) { + return file_build_flags_out_proto_rawDescGZIP(), []int{4} +} + +func (x *ReleaseConfigsArtifact) GetReleaseConfig() *ReleaseConfigArtifact { + if x != nil { + return x.ReleaseConfig + } + return nil +} + +func (x *ReleaseConfigsArtifact) GetOtherReleaseConfigs() []*ReleaseConfigArtifact { + if x != nil { + return x.OtherReleaseConfigs + } + return nil +} + +func (x *ReleaseConfigsArtifact) GetReleaseConfigMapsMap() map[string]*ReleaseConfigMap { + if x != nil { + return x.ReleaseConfigMapsMap + } + return nil +} + +var File_build_flags_out_proto protoreflect.FileDescriptor + +var file_build_flags_out_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x75, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, + 0x67, 0x73, 0x5f, 0x73, 0x72, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x60, 0x0a, 0x0a, + 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe8, + 0x01, 0x0a, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x12, 0x59, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x6e, 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, + 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x6c, 0x61, 0x67, + 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, + 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, + 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, + 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0e, 0x66, 0x6c, 0x61, + 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x52, 0x0a, 0x0e, 0x66, + 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x52, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, + 0x8e, 0x02, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x12, 0x52, 0x0a, 0x0e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, + 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, + 0x22, 0xe8, 0x03, 0x0a, 0x18, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x5c, 0x0a, + 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x15, 0x6f, + 0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d, + 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, + 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, + 0x1a, 0x79, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61, + 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, +} + +var ( + file_build_flags_out_proto_rawDescOnce sync.Once + file_build_flags_out_proto_rawDescData = file_build_flags_out_proto_rawDesc +) + +func file_build_flags_out_proto_rawDescGZIP() []byte { + file_build_flags_out_proto_rawDescOnce.Do(func() { + file_build_flags_out_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_out_proto_rawDescData) + }) + return file_build_flags_out_proto_rawDescData +} + +var file_build_flags_out_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_build_flags_out_proto_goTypes = []interface{}{ + (*Tracepoint)(nil), // 0: android.release_config_proto.tracepoint + (*FlagArtifact)(nil), // 1: android.release_config_proto.flag_artifact + (*FlagArtifacts)(nil), // 2: android.release_config_proto.flag_artifacts + (*ReleaseConfigArtifact)(nil), // 3: android.release_config_proto.release_config_artifact + (*ReleaseConfigsArtifact)(nil), // 4: android.release_config_proto.release_configs_artifact + nil, // 5: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry + (*Value)(nil), // 6: android.release_config_proto.value + (*FlagDeclaration)(nil), // 7: android.release_config_proto.flag_declaration + (*ReleaseConfigMap)(nil), // 8: android.release_config_proto.release_config_map +} +var file_build_flags_out_proto_depIdxs = []int32{ + 6, // 0: android.release_config_proto.tracepoint.value:type_name -> android.release_config_proto.value + 7, // 1: android.release_config_proto.flag_artifact.flag_declaration:type_name -> android.release_config_proto.flag_declaration + 6, // 2: android.release_config_proto.flag_artifact.value:type_name -> android.release_config_proto.value + 0, // 3: android.release_config_proto.flag_artifact.traces:type_name -> android.release_config_proto.tracepoint + 1, // 4: android.release_config_proto.flag_artifacts.flag_artifacts:type_name -> android.release_config_proto.flag_artifact + 1, // 5: android.release_config_proto.release_config_artifact.flag_artifacts:type_name -> android.release_config_proto.flag_artifact + 3, // 6: android.release_config_proto.release_configs_artifact.release_config:type_name -> android.release_config_proto.release_config_artifact + 3, // 7: android.release_config_proto.release_configs_artifact.other_release_configs:type_name -> android.release_config_proto.release_config_artifact + 5, // 8: android.release_config_proto.release_configs_artifact.release_config_maps_map:type_name -> android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry + 8, // 9: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry.value:type_name -> android.release_config_proto.release_config_map + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_build_flags_out_proto_init() } +func file_build_flags_out_proto_init() { + if File_build_flags_out_proto != nil { + return + } + file_build_flags_src_proto_init() + if !protoimpl.UnsafeEnabled { + file_build_flags_out_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Tracepoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_out_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagArtifact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_out_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagArtifacts); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_out_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseConfigArtifact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_out_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseConfigsArtifact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_build_flags_out_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_build_flags_out_proto_goTypes, + DependencyIndexes: file_build_flags_out_proto_depIdxs, + MessageInfos: file_build_flags_out_proto_msgTypes, + }.Build() + File_build_flags_out_proto = out.File + file_build_flags_out_proto_rawDesc = nil + file_build_flags_out_proto_goTypes = nil + file_build_flags_out_proto_depIdxs = nil +} diff --git a/cmd/release_config/release_config_proto/build_flags_out.proto b/cmd/release_config/release_config_proto/build_flags_out.proto new file mode 100644 index 000000000..6f34d6f67 --- /dev/null +++ b/cmd/release_config/release_config_proto/build_flags_out.proto @@ -0,0 +1,94 @@ +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto2"; +package android.release_config_proto; +option go_package = "android/soong/release_config/release_config_proto"; + +import "build_flags_src.proto"; + +// This protobuf file defines messages used to represent the release config for +// the android build system, delivered as a build artifact for use by tools such +// as Gantry. +// +// The following format requirements apply across various message fields: +// +// # name: name of the flag +// +// format: an uppercase string in SNAKE_CASE format starting with RELEASE_, +// no consecutive underscores, and no leading digit. For example +// RELEASE_MY_PACKAGE_FLAG is a valid name, while MY_PACKAGE_FLAG, and +// RELEASE_MY_PACKAGE__FLAG are invalid. +// +// # package: package to which the flag belongs +// +// format: lowercase strings in snake_case format, delimited by dots, no +// consecutive underscores and no leading digit in each string. For example +// com.android.mypackage is a valid name while com.android.myPackage, +// com.android.1mypackage are invalid + +message tracepoint { + // Path to declaration or value file relative to $TOP + optional string source = 1; + optional value value = 201; +} + +message flag_artifact { + // The original declaration + optional flag_declaration flag_declaration = 1; + + // Value for the flag + optional value value = 201; + + // Trace of where the flag value was assigned. + repeated tracepoint traces = 8; +} + +message flag_artifacts { + // The artifacts + repeated flag_artifact flag_artifacts = 1; +} + +message release_config_artifact { + // The name of the release config. + // See # name for format detail + optional string name = 1; + + // Other names by which this release is known (for example, `next`) + repeated string other_names = 2; + + // The complete set of build flags in this release config, after all + // inheritance and other processing is complete. + repeated flag_artifact flag_artifacts = 3; + + // The (complete) list of aconfig_value_sets Soong modules to use. + repeated string aconfig_value_sets = 4; + + // The names of the release_config_artifacts from which we inherited. + // Included for reference only. + repeated string inherits = 5; + + // The release config directories used for this config. + // For example, "build/release". + repeated string directories = 6; +} + +message release_configs_artifact { + // The active release config for this build. + optional release_config_artifact release_config = 1; + + // All other release configs defined for this TARGET_PRODUCT. + repeated release_config_artifact other_release_configs = 2; + + // Map of release_config_artifact.directories to release_config_map message. + map<string, release_config_map> release_config_maps_map = 3; +} + diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go new file mode 100644 index 000000000..dded97566 --- /dev/null +++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go @@ -0,0 +1,795 @@ +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: build_flags_src.proto + +package release_config_proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Workflow int32 + +const ( + Workflow_UNSPECIFIED_workflow Workflow = 0 + // Boolean value flags that progress from false to true. + Workflow_LAUNCH Workflow = 1 + // String value flags that get updated with new version strings to control + // prebuilt inclusion. + Workflow_PREBUILT Workflow = 2 + // Manually managed outside flags. These are likely to be found in a + // different directory than flags with other workflows. + Workflow_MANUAL Workflow = 3 +) + +// Enum value maps for Workflow. +var ( + Workflow_name = map[int32]string{ + 0: "UNSPECIFIED_workflow", + 1: "LAUNCH", + 2: "PREBUILT", + 3: "MANUAL", + } + Workflow_value = map[string]int32{ + "UNSPECIFIED_workflow": 0, + "LAUNCH": 1, + "PREBUILT": 2, + "MANUAL": 3, + } +) + +func (x Workflow) Enum() *Workflow { + p := new(Workflow) + *p = x + return p +} + +func (x Workflow) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Workflow) Descriptor() protoreflect.EnumDescriptor { + return file_build_flags_src_proto_enumTypes[0].Descriptor() +} + +func (Workflow) Type() protoreflect.EnumType { + return &file_build_flags_src_proto_enumTypes[0] +} + +func (x Workflow) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *Workflow) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = Workflow(num) + return nil +} + +// Deprecated: Use Workflow.Descriptor instead. +func (Workflow) EnumDescriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{0} +} + +type Value struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Val: + // + // *Value_UnspecifiedValue + // *Value_StringValue + // *Value_BoolValue + // *Value_Obsolete + Val isValue_Val `protobuf_oneof:"val"` +} + +func (x *Value) Reset() { + *x = Value{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_src_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Value) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Value) ProtoMessage() {} + +func (x *Value) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_src_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Value.ProtoReflect.Descriptor instead. +func (*Value) Descriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{0} +} + +func (m *Value) GetVal() isValue_Val { + if m != nil { + return m.Val + } + return nil +} + +func (x *Value) GetUnspecifiedValue() bool { + if x, ok := x.GetVal().(*Value_UnspecifiedValue); ok { + return x.UnspecifiedValue + } + return false +} + +func (x *Value) GetStringValue() string { + if x, ok := x.GetVal().(*Value_StringValue); ok { + return x.StringValue + } + return "" +} + +func (x *Value) GetBoolValue() bool { + if x, ok := x.GetVal().(*Value_BoolValue); ok { + return x.BoolValue + } + return false +} + +func (x *Value) GetObsolete() bool { + if x, ok := x.GetVal().(*Value_Obsolete); ok { + return x.Obsolete + } + return false +} + +type isValue_Val interface { + isValue_Val() +} + +type Value_UnspecifiedValue struct { + UnspecifiedValue bool `protobuf:"varint,200,opt,name=unspecified_value,json=unspecifiedValue,oneof"` +} + +type Value_StringValue struct { + StringValue string `protobuf:"bytes,201,opt,name=string_value,json=stringValue,oneof"` +} + +type Value_BoolValue struct { + BoolValue bool `protobuf:"varint,202,opt,name=bool_value,json=boolValue,oneof"` +} + +type Value_Obsolete struct { + // If true, the flag is obsolete. Assigning it further will be flagged. + Obsolete bool `protobuf:"varint,203,opt,name=obsolete,oneof"` +} + +func (*Value_UnspecifiedValue) isValue_Val() {} + +func (*Value_StringValue) isValue_Val() {} + +func (*Value_BoolValue) isValue_Val() {} + +func (*Value_Obsolete) isValue_Val() {} + +// The proto used in the source tree. +type FlagDeclaration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the flag. + // See # name for format detail + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Namespace the flag belongs to (required) + // See # namespace for format detail + Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` + // Text description of the flag's purpose. + Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + // Value for the flag + Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` + // Workflow for this flag. + Workflow *Workflow `protobuf:"varint,205,opt,name=workflow,enum=android.release_config_proto.Workflow" json:"workflow,omitempty"` + // The container for this flag. This overrides any default container given + // in the release_config_map message. + Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"` +} + +func (x *FlagDeclaration) Reset() { + *x = FlagDeclaration{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_src_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagDeclaration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagDeclaration) ProtoMessage() {} + +func (x *FlagDeclaration) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_src_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagDeclaration.ProtoReflect.Descriptor instead. +func (*FlagDeclaration) Descriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{1} +} + +func (x *FlagDeclaration) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *FlagDeclaration) GetNamespace() string { + if x != nil && x.Namespace != nil { + return *x.Namespace + } + return "" +} + +func (x *FlagDeclaration) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *FlagDeclaration) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *FlagDeclaration) GetWorkflow() Workflow { + if x != nil && x.Workflow != nil { + return *x.Workflow + } + return Workflow_UNSPECIFIED_workflow +} + +func (x *FlagDeclaration) GetContainers() []string { + if x != nil { + return x.Containers + } + return nil +} + +type FlagValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name of the flag. + // See # name for format detail + Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + // Value for the flag + Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` + // If true, the flag is completely removed from the release config as if + // never declared. + Redacted *bool `protobuf:"varint,202,opt,name=redacted" json:"redacted,omitempty"` +} + +func (x *FlagValue) Reset() { + *x = FlagValue{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_src_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagValue) ProtoMessage() {} + +func (x *FlagValue) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_src_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagValue.ProtoReflect.Descriptor instead. +func (*FlagValue) Descriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{2} +} + +func (x *FlagValue) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *FlagValue) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *FlagValue) GetRedacted() bool { + if x != nil && x.Redacted != nil { + return *x.Redacted + } + return false +} + +// This replaces $(call declare-release-config). +type ReleaseConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the release config. + // See # name for format detail + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // From which other release configs does this one inherit? + Inherits []string `protobuf:"bytes,2,rep,name=inherits" json:"inherits,omitempty"` + // List of names of the aconfig_value_set soong module(s) for this + // contribution. + AconfigValueSets []string `protobuf:"bytes,3,rep,name=aconfig_value_sets,json=aconfigValueSets" json:"aconfig_value_sets,omitempty"` + // Only aconfig flags are allowed in this release config. + AconfigFlagsOnly *bool `protobuf:"varint,4,opt,name=aconfig_flags_only,json=aconfigFlagsOnly" json:"aconfig_flags_only,omitempty"` +} + +func (x *ReleaseConfig) Reset() { + *x = ReleaseConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_src_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReleaseConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseConfig) ProtoMessage() {} + +func (x *ReleaseConfig) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_src_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReleaseConfig.ProtoReflect.Descriptor instead. +func (*ReleaseConfig) Descriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{3} +} + +func (x *ReleaseConfig) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *ReleaseConfig) GetInherits() []string { + if x != nil { + return x.Inherits + } + return nil +} + +func (x *ReleaseConfig) GetAconfigValueSets() []string { + if x != nil { + return x.AconfigValueSets + } + return nil +} + +func (x *ReleaseConfig) GetAconfigFlagsOnly() bool { + if x != nil && x.AconfigFlagsOnly != nil { + return *x.AconfigFlagsOnly + } + return false +} + +// Any aliases. These are used for continuous integration builder config. +type ReleaseAlias struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the alias. + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // The release that `name` is an alias for. + Target *string `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"` +} + +func (x *ReleaseAlias) Reset() { + *x = ReleaseAlias{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_src_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReleaseAlias) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseAlias) ProtoMessage() {} + +func (x *ReleaseAlias) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_src_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReleaseAlias.ProtoReflect.Descriptor instead. +func (*ReleaseAlias) Descriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{4} +} + +func (x *ReleaseAlias) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *ReleaseAlias) GetTarget() string { + if x != nil && x.Target != nil { + return *x.Target + } + return "" +} + +// This provides the data from release_config_map.mk +type ReleaseConfigMap struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Any aliases. + Aliases []*ReleaseAlias `protobuf:"bytes,1,rep,name=aliases" json:"aliases,omitempty"` + // Description of this map and its intended use. + Description *string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` + // The default container for flags declared here. + DefaultContainers []string `protobuf:"bytes,3,rep,name=default_containers,json=defaultContainers" json:"default_containers,omitempty"` +} + +func (x *ReleaseConfigMap) Reset() { + *x = ReleaseConfigMap{} + if protoimpl.UnsafeEnabled { + mi := &file_build_flags_src_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReleaseConfigMap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseConfigMap) ProtoMessage() {} + +func (x *ReleaseConfigMap) ProtoReflect() protoreflect.Message { + mi := &file_build_flags_src_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReleaseConfigMap.ProtoReflect.Descriptor instead. +func (*ReleaseConfigMap) Descriptor() ([]byte, []int) { + return file_build_flags_src_proto_rawDescGZIP(), []int{5} +} + +func (x *ReleaseConfigMap) GetAliases() []*ReleaseAlias { + if x != nil { + return x.Aliases + } + return nil +} + +func (x *ReleaseConfigMap) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *ReleaseConfigMap) GetDefaultContainers() []string { + if x != nil { + return x.DefaultContainers + } + return nil +} + +var File_build_flags_src_proto protoreflect.FileDescriptor + +var file_build_flags_src_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x73, 0x72, + 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, 0x01, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x2e, 0x0a, 0x11, 0x75, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x10, 0x75, + 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x24, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0xc9, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x20, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, + 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x6f, 0x6c, + 0x65, 0x74, 0x65, 0x18, 0xcb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x62, + 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0x96, 0x02, + 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0xcd, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0xce, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x06, + 0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x79, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, + 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, + 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, + 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, + 0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65, + 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, + 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x4f, 0x6e, 0x6c, 0x79, + 0x22, 0x3b, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xac, 0x01, + 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x5f, 0x6d, 0x61, 0x70, 0x12, 0x45, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, + 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2a, 0x4a, 0x0a, 0x08, + 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c, + 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, + 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, +} + +var ( + file_build_flags_src_proto_rawDescOnce sync.Once + file_build_flags_src_proto_rawDescData = file_build_flags_src_proto_rawDesc +) + +func file_build_flags_src_proto_rawDescGZIP() []byte { + file_build_flags_src_proto_rawDescOnce.Do(func() { + file_build_flags_src_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_src_proto_rawDescData) + }) + return file_build_flags_src_proto_rawDescData +} + +var file_build_flags_src_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_build_flags_src_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_build_flags_src_proto_goTypes = []interface{}{ + (Workflow)(0), // 0: android.release_config_proto.workflow + (*Value)(nil), // 1: android.release_config_proto.value + (*FlagDeclaration)(nil), // 2: android.release_config_proto.flag_declaration + (*FlagValue)(nil), // 3: android.release_config_proto.flag_value + (*ReleaseConfig)(nil), // 4: android.release_config_proto.release_config + (*ReleaseAlias)(nil), // 5: android.release_config_proto.release_alias + (*ReleaseConfigMap)(nil), // 6: android.release_config_proto.release_config_map +} +var file_build_flags_src_proto_depIdxs = []int32{ + 1, // 0: android.release_config_proto.flag_declaration.value:type_name -> android.release_config_proto.value + 0, // 1: android.release_config_proto.flag_declaration.workflow:type_name -> android.release_config_proto.workflow + 1, // 2: android.release_config_proto.flag_value.value:type_name -> android.release_config_proto.value + 5, // 3: android.release_config_proto.release_config_map.aliases:type_name -> android.release_config_proto.release_alias + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_build_flags_src_proto_init() } +func file_build_flags_src_proto_init() { + if File_build_flags_src_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_build_flags_src_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Value); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_src_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagDeclaration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_src_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_src_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_src_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseAlias); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_build_flags_src_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReleaseConfigMap); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_build_flags_src_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Value_UnspecifiedValue)(nil), + (*Value_StringValue)(nil), + (*Value_BoolValue)(nil), + (*Value_Obsolete)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_build_flags_src_proto_rawDesc, + NumEnums: 1, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_build_flags_src_proto_goTypes, + DependencyIndexes: file_build_flags_src_proto_depIdxs, + EnumInfos: file_build_flags_src_proto_enumTypes, + MessageInfos: file_build_flags_src_proto_msgTypes, + }.Build() + File_build_flags_src_proto = out.File + file_build_flags_src_proto_rawDesc = nil + file_build_flags_src_proto_goTypes = nil + file_build_flags_src_proto_depIdxs = nil +} diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto new file mode 100644 index 000000000..0ef1a5ffa --- /dev/null +++ b/cmd/release_config/release_config_proto/build_flags_src.proto @@ -0,0 +1,151 @@ +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto2"; +package android.release_config_proto; +option go_package = "android/soong/release_config/release_config_proto"; + +// This protobuf file defines messages used to represent the build flags used by +// a release in a more human-editable form. It is used for on-disk files in the +// source tree. +// +// The following format requirements apply across various message fields: +// +// # name: name of the flag +// +// format: an uppercase string in SNAKE_CASE format starting with RELEASE_, +// no consecutive underscores, and no leading digit. For example +// RELEASE_MY_PACKAGE_FLAG is a valid name, while MY_PACKAGE_FLAG, and +// RELEASE_MY_PACKAGE__FLAG are invalid. +// +// # namespace: namespace the flag belongs to +// +// format: a lowercase string in snake_case format, no consecutive underscores, and no leading +// digit. For example android_bar_system +// +// # package: package to which the flag belongs +// +// format: lowercase strings in snake_case format, delimited by dots, no +// consecutive underscores and no leading digit in each string. For example +// com.android.mypackage is a valid name while com.android.myPackage, +// com.android.1mypackage are invalid + +enum workflow { + UNSPECIFIED_workflow = 0; + + // Boolean value flags that progress from false to true. + LAUNCH = 1; + + // String value flags that get updated with new version strings to control + // prebuilt inclusion. + PREBUILT = 2; + + // Manually managed outside flags. These are likely to be found in a + // different directory than flags with other workflows. + MANUAL = 3; +} + +message value { + oneof val { + bool unspecified_value = 200; + string string_value = 201; + bool bool_value = 202; + // If true, the flag is obsolete. Assigning it further will be flagged. + bool obsolete = 203; + } +} + +// The proto used in the source tree. +message flag_declaration { + // The name of the flag. + // See # name for format detail + optional string name = 1; + + // Namespace the flag belongs to (required) + // See # namespace for format detail + optional string namespace = 2; + + // Text description of the flag's purpose. + optional string description = 3; + + // reserve this for bug, if needed. + reserved 4; + + // Value for the flag + optional value value = 201; + + // Workflow for this flag. + optional workflow workflow = 205; + + // The container for this flag. This overrides any default container given + // in the release_config_map message. + repeated string containers = 206; + + // The package associated with this flag. + // (when Gantry is ready for it) optional string package = 207; + reserved 207; +} + +message flag_value { + // Name of the flag. + // See # name for format detail + optional string name = 2; + + // Value for the flag + optional value value = 201; + + // If true, the flag is completely removed from the release config as if + // never declared. + optional bool redacted = 202; +} + +// This replaces $(call declare-release-config). +message release_config { + // The name of the release config. + // See # name for format detail + optional string name = 1; + + // From which other release configs does this one inherit? + repeated string inherits = 2; + + // List of names of the aconfig_value_set soong module(s) for this + // contribution. + repeated string aconfig_value_sets = 3; + + // Only aconfig flags are allowed in this release config. + optional bool aconfig_flags_only = 4; +} + +// Any aliases. These are used for continuous integration builder config. +message release_alias { + // The name of the alias. + optional string name = 1; + + // The release that `name` is an alias for. + optional string target = 2; +} + +// This provides the data from release_config_map.mk +message release_config_map { + // Any aliases. + repeated release_alias aliases = 1; + + // Description of this map and its intended use. + optional string description = 2; + + // The default container for flags declared here. + repeated string default_containers = 3; + + // If needed, we can add these fields instead of hardcoding the location. + // Flag declarations: `flag_declarations/*.textproto` + // Release config contributions: `release_configs/*.textproto` + // Flag values: `flag_values/{RELEASE_NAME}/*.textproto` +} diff --git a/cmd/release_config/release_config_proto/regen.sh b/cmd/release_config/release_config_proto/regen.sh new file mode 100644 index 000000000..1846c4d87 --- /dev/null +++ b/cmd/release_config/release_config_proto/regen.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +aprotoc --go_out=paths=source_relative:. build_flags_src.proto build_flags_out.proto diff --git a/soong_ui.bash b/soong_ui.bash index 8e7cd195d..77378807f 100755 --- a/soong_ui.bash +++ b/soong_ui.bash @@ -35,6 +35,7 @@ source ${TOP}/build/soong/scripts/microfactory.bash soong_build_go soong_ui android/soong/cmd/soong_ui soong_build_go mk2rbc android/soong/mk2rbc/mk2rbc soong_build_go rbcrun rbcrun/rbcrun +soong_build_go release-config android/soong/cmd/release_config/release_config cd ${TOP} exec "$(getoutdir)/soong_ui" "$@" |
