Add release_config_contributions modules
These are used to enumerate what directories may contribute to release
configs, whether or not they are actually used in the build.
Bug: b/370544058
Test: manual, TH
Change-Id: I1509eb3795a9b51b29995b182b77ade76021bb52
diff --git a/aconfig/build_flags/Android.bp b/aconfig/build_flags/Android.bp
index be1b872..139aeac 100644
--- a/aconfig/build_flags/Android.bp
+++ b/aconfig/build_flags/Android.bp
@@ -17,6 +17,7 @@
"build_flags_singleton.go",
"declarations.go",
"init.go",
+ "release_configs.go",
],
testSrcs: [
],
diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go
index 5f02912..ba27a85 100644
--- a/aconfig/build_flags/build_flags_singleton.go
+++ b/aconfig/build_flags/build_flags_singleton.go
@@ -30,49 +30,94 @@
}
type allBuildFlagDeclarationsSingleton struct {
- intermediateBinaryProtoPath android.OutputPath
- intermediateTextProtoPath android.OutputPath
+ flagsBinaryProtoPath android.OutputPath
+ flagsTextProtoPath android.OutputPath
+ configsBinaryProtoPath android.OutputPath
+ configsTextProtoPath android.OutputPath
}
func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
// Find all of the build_flag_declarations modules
- var intermediateFiles android.Paths
+ var flagsFiles android.Paths
+ // Find all of the release_config_contribution modules
+ var contributionDirs android.Paths
ctx.VisitAllModules(func(module android.Module) {
decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
- if !ok {
- return
+ if ok {
+ flagsFiles = append(flagsFiles, decl.IntermediateCacheOutputPath)
}
- intermediateFiles = append(intermediateFiles, decl.IntermediateCacheOutputPath)
+
+ contrib, ok := android.OtherModuleProvider(ctx, module, ReleaseConfigContributionsProviderKey)
+ if ok {
+ contributionDirs = append(contributionDirs, contrib.ContributionDir)
+ }
})
// Generate build action for build_flag (binary proto output)
- this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb")
+ this.flagsBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb")
ctx.Build(pctx, android.BuildParams{
Rule: allDeclarationsRule,
- Inputs: intermediateFiles,
- Output: this.intermediateBinaryProtoPath,
+ Inputs: flagsFiles,
+ Output: this.flagsBinaryProtoPath,
Description: "all_build_flag_declarations",
Args: map[string]string{
- "intermediates": android.JoinPathsWithPrefix(intermediateFiles, "--intermediate "),
+ "intermediates": android.JoinPathsWithPrefix(flagsFiles, "--intermediate "),
},
})
- ctx.Phony("all_build_flag_declarations", this.intermediateBinaryProtoPath)
+ ctx.Phony("all_build_flag_declarations", this.flagsBinaryProtoPath)
// Generate build action for build_flag (text proto output)
- this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto")
+ this.flagsTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto")
ctx.Build(pctx, android.BuildParams{
Rule: allDeclarationsRuleTextProto,
- Input: this.intermediateBinaryProtoPath,
- Output: this.intermediateTextProtoPath,
+ Input: this.flagsBinaryProtoPath,
+ Output: this.flagsTextProtoPath,
Description: "all_build_flag_declarations_textproto",
})
- ctx.Phony("all_build_flag_declarations_textproto", this.intermediateTextProtoPath)
+ ctx.Phony("all_build_flag_declarations_textproto", this.flagsTextProtoPath)
+
+ // Generate build action for release_configs (binary proto output)
+ this.configsBinaryProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allReleaseConfigContributionsRule,
+ Inputs: contributionDirs,
+ Output: this.configsBinaryProtoPath,
+ Description: "all_release_config_contributions",
+ Args: map[string]string{
+ "dirs": android.JoinPathsWithPrefix(contributionDirs, "--dir "),
+ "format": "pb",
+ },
+ })
+ ctx.Phony("all_release_config_contributions", this.configsBinaryProtoPath)
+
+ this.configsTextProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.textproto")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allReleaseConfigContributionsRule,
+ Inputs: contributionDirs,
+ Output: this.configsTextProtoPath,
+ Description: "all_release_config_contributions_textproto",
+ Args: map[string]string{
+ "dirs": android.JoinPathsWithPrefix(contributionDirs, "--dir "),
+ "format": "textproto",
+ },
+ })
+ ctx.Phony("all_release_config_contributions_textproto", this.configsTextProtoPath)
+
+ // Add a simple target for ci/build_metadata to use.
+ ctx.Phony("release_config_metadata",
+ this.flagsBinaryProtoPath,
+ this.flagsTextProtoPath,
+ this.configsBinaryProtoPath,
+ this.configsTextProtoPath,
+ )
}
func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
+ ctx.DistForGoal("droid", this.flagsBinaryProtoPath)
for _, goal := range []string{"docs", "droid", "sdk"} {
- ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "build_flags/all_flags.pb")
- ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "build_flags/all_flags.textproto")
+ ctx.DistForGoalWithFilename(goal, this.flagsBinaryProtoPath, "build_flags/all_flags.pb")
+ ctx.DistForGoalWithFilename(goal, this.flagsTextProtoPath, "build_flags/all_flags.textproto")
+ ctx.DistForGoalWithFilename(goal, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb")
+ ctx.DistForGoalWithFilename(goal, this.configsTextProtoPath, "build_flags/all_release_config_contributions.textproto")
}
}
diff --git a/aconfig/build_flags/declarations.go b/aconfig/build_flags/declarations.go
index e927db2..4a54269 100644
--- a/aconfig/build_flags/declarations.go
+++ b/aconfig/build_flags/declarations.go
@@ -35,7 +35,7 @@
// Properties for "aconfig_declarations"
properties struct {
- // aconfig files, relative to this Android.bp file
+ // build flag declaration files, relative to this Android.bp file
Srcs []string `android:"path"`
}
}
diff --git a/aconfig/build_flags/init.go b/aconfig/build_flags/init.go
index dc1369c..a7575e8 100644
--- a/aconfig/build_flags/init.go
+++ b/aconfig/build_flags/init.go
@@ -65,15 +65,32 @@
"${buildFlagDeclarations}",
},
})
+
+ allReleaseConfigContributionsRule = pctx.AndroidStaticRule("all-release-config-contributions-dump",
+ blueprint.RuleParams{
+ Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`,
+ CommandDeps: []string{
+ "${releaseConfigContributions}",
+ },
+ }, "dirs", "format")
+ allReleaseConfigContributionsRuleText = pctx.AndroidStaticRule("all-release-config-contributions-dumptext",
+ blueprint.RuleParams{
+ Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`,
+ CommandDeps: []string{
+ "${releaseConfigContributions}",
+ },
+ }, "dirs", "format")
)
func init() {
RegisterBuildComponents(android.InitRegistrationContext)
pctx.Import("android/soong/android")
pctx.HostBinToolVariable("buildFlagDeclarations", "build-flag-declarations")
+ pctx.HostBinToolVariable("releaseConfigContributions", "release-config-contributions")
}
func RegisterBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("build_flag_declarations", DeclarationsFactory)
+ ctx.RegisterModuleType("release_config_contributions", ReleaseConfigContributionsFactory)
ctx.RegisterParallelSingletonType("all_build_flag_declarations", AllBuildFlagDeclarationsFactory)
}
diff --git a/aconfig/build_flags/release_configs.go b/aconfig/build_flags/release_configs.go
new file mode 100644
index 0000000..3fa8a7c
--- /dev/null
+++ b/aconfig/build_flags/release_configs.go
@@ -0,0 +1,78 @@
+// Copyright 2023 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 build_flags
+
+import (
+ "path/filepath"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+type ReleaseConfigContributionsProviderData struct {
+ ContributionDir android.SourcePath
+}
+
+var ReleaseConfigContributionsProviderKey = blueprint.NewProvider[ReleaseConfigContributionsProviderData]()
+
+// Soong uses `release_config_contributions` modules to produce the
+// `build_flags/all_release_config_contributions.*` artifacts, listing *all* of
+// the directories in the source tree that contribute to each release config,
+// whether or not they are actually used for the lunch product.
+//
+// This artifact helps flagging automation determine in which directory a flag
+// should be placed by default.
+type ReleaseConfigContributionsModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ // Properties for "release_config_contributions"
+ properties struct {
+ // The `release_configs/*.textproto` files provided by this
+ // directory, relative to this Android.bp file
+ Srcs []string `android:"path"`
+ }
+}
+
+func ReleaseConfigContributionsFactory() android.Module {
+ module := &ReleaseConfigContributionsModule{}
+
+ android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
+ module.AddProperties(&module.properties)
+
+ return module
+}
+
+func (module *ReleaseConfigContributionsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcs := android.PathsForModuleSrc(ctx, module.properties.Srcs)
+ if len(srcs) == 0 {
+ return
+ }
+ contributionDir := filepath.Dir(filepath.Dir(srcs[0].String()))
+ for _, file := range srcs {
+ if filepath.Dir(filepath.Dir(file.String())) != contributionDir {
+ ctx.ModuleErrorf("Cannot include %s with %s contributions", file, contributionDir)
+ }
+ if filepath.Base(filepath.Dir(file.String())) != "release_configs" || file.Ext() != ".textproto" {
+ ctx.ModuleErrorf("Invalid contribution file %s", file)
+ }
+ }
+ android.SetProvider(ctx, ReleaseConfigContributionsProviderKey, ReleaseConfigContributionsProviderData{
+ ContributionDir: android.PathForSource(ctx, contributionDir),
+ })
+
+}
diff --git a/cmd/release_config/release_config_contributions/Android.bp b/cmd/release_config/release_config_contributions/Android.bp
new file mode 100644
index 0000000..6882ea2
--- /dev/null
+++ b/cmd/release_config/release_config_contributions/Android.bp
@@ -0,0 +1,32 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "release-config-contributions",
+ 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-release_config_contributions",
+ pkgPath: "android/soong/cmd/release_config/release_config_contributions",
+ 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_contributions/main.go b/cmd/release_config/release_config_contributions/main.go
new file mode 100644
index 0000000..6abf768
--- /dev/null
+++ b/cmd/release_config/release_config_contributions/main.go
@@ -0,0 +1,130 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "slices"
+ "strings"
+
+ rc_lib "android/soong/cmd/release_config/release_config_lib"
+ rc_proto "android/soong/cmd/release_config/release_config_proto"
+)
+
+type Flags struct {
+ // The path to the top of the workspace. Default: ".".
+ top string
+
+ // Output file.
+ output string
+
+ // Format for output file
+ format string
+
+ // List of release config directories to process.
+ dirs rc_lib.StringList
+
+ // Disable warning messages
+ quiet bool
+
+ // Panic on errors.
+ debug bool
+}
+
+func sortDirectories(dirList []string) {
+ order := func(dir string) int {
+ switch {
+ // These three are always in this order.
+ case dir == "build/release":
+ return 1
+ case dir == "vendor/google_shared/build/release":
+ return 2
+ case dir == "vendor/google/release":
+ return 3
+ // Keep their subdirs in the same order.
+ case strings.HasPrefix(dir, "build/release/"):
+ return 21
+ case strings.HasPrefix(dir, "vendor/google_shared/build/release/"):
+ return 22
+ case strings.HasPrefix(dir, "vendor/google/release/"):
+ return 23
+ // Everything else sorts by directory path.
+ default:
+ return 99
+ }
+ }
+
+ slices.SortFunc(dirList, func(a, b string) int {
+ aOrder, bOrder := order(a), order(b)
+ if aOrder != bOrder {
+ return aOrder - bOrder
+ }
+ return strings.Compare(a, b)
+ })
+}
+
+func main() {
+ var flags Flags
+ topDir, err := rc_lib.GetTopDir()
+
+ // Handle the common arguments
+ flag.StringVar(&flags.top, "top", topDir, "path to top of workspace")
+ flag.Var(&flags.dirs, "dir", "path to a release config contribution directory. May be repeated")
+ flag.StringVar(&flags.format, "format", "pb", "output file format")
+ flag.StringVar(&flags.output, "output", "release_config_contributions.pb", "output file")
+ flag.BoolVar(&flags.debug, "debug", false, "turn on debugging output for errors")
+ flag.BoolVar(&flags.quiet, "quiet", false, "disable warning messages")
+ flag.Parse()
+
+ errorExit := func(err error) {
+ if flags.debug {
+ panic(err)
+ }
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+
+ if flags.quiet {
+ rc_lib.DisableWarnings()
+ }
+
+ if err = os.Chdir(flags.top); err != nil {
+ errorExit(err)
+ }
+
+ contributingDirsMap := make(map[string][]string)
+ for _, dir := range flags.dirs {
+ contributions, err := rc_lib.EnumerateReleaseConfigs(dir)
+ if err != nil {
+ errorExit(err)
+ }
+ for _, name := range contributions {
+ contributingDirsMap[name] = append(contributingDirsMap[name], dir)
+ }
+ }
+
+ releaseConfigNames := []string{}
+ for name := range contributingDirsMap {
+ releaseConfigNames = append(releaseConfigNames, name)
+ }
+ slices.Sort(releaseConfigNames)
+
+ message := &rc_proto.ReleaseConfigContributionsArtifacts{
+ ReleaseConfigContributionsArtifactList: []*rc_proto.ReleaseConfigContributionsArtifact{},
+ }
+ for _, name := range releaseConfigNames {
+ dirs := contributingDirsMap[name]
+ slices.Sort(dirs)
+ message.ReleaseConfigContributionsArtifactList = append(
+ message.ReleaseConfigContributionsArtifactList,
+ &rc_proto.ReleaseConfigContributionsArtifact{
+ Name: &name,
+ ContributingDirectories: dirs,
+ })
+ }
+
+ err = rc_lib.WriteFormattedMessage(flags.output, flags.format, message)
+ if err != nil {
+ errorExit(err)
+ }
+}
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
index 97eb8f1..831ec02 100644
--- a/cmd/release_config/release_config_lib/release_configs.go
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -248,6 +248,18 @@
return configs.configDirs[index], nil
}
+// Return the (unsorted) release configs contributed to by `dir`.
+func EnumerateReleaseConfigs(dir string) ([]string, error) {
+ var ret []string
+ err := WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
+ // Strip off the trailing `.textproto` from the name.
+ name := filepath.Base(path)
+ ret = append(ret, name[:len(name)-10])
+ return err
+ })
+ return ret, err
+}
+
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)
diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp
index c34d203..c6869b1 100644
--- a/cmd/release_config/release_config_proto/Android.bp
+++ b/cmd/release_config/release_config_proto/Android.bp
@@ -28,5 +28,6 @@
"build_flags_declarations.pb.go",
"build_flags_src.pb.go",
"build_flags_out.pb.go",
+ "release_configs_contributions.pb.go",
],
}