release_config: cleanup how we emit results
- Allow each of the formats (json, pb, textproto) to be individually controlled. - Include product and release in the name of the aritfact. Bug: 328495189 Test: manual Change-Id: Ia08e7224200a48994bea882a61b8199d53576d38
This commit is contained in:
parent
7ac07deb9b
commit
14e2ac68e3
9 changed files with 291 additions and 105 deletions
|
@ -16,7 +16,9 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
rc_lib "android/soong/cmd/release_config/release_config_lib"
|
||||
)
|
||||
|
@ -29,12 +31,23 @@ func main() {
|
|||
var outputDir string
|
||||
var err error
|
||||
var configs *rc_lib.ReleaseConfigs
|
||||
var json, pb, textproto bool
|
||||
var product string
|
||||
|
||||
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", "trunk_staging", "TARGET_RELEASE for this build")
|
||||
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.Parse()
|
||||
|
||||
if quiet {
|
||||
|
@ -48,16 +61,36 @@ func main() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
config, err := configs.GetReleaseConfig(targetRelease)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
releaseName := config.Name
|
||||
err = os.MkdirAll(outputDir, 0775)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = configs.DumpMakefile(outputDir, targetRelease)
|
||||
makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, releaseName))
|
||||
err = configs.WriteMakefile(makefilePath, targetRelease)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = configs.DumpArtifact(outputDir)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package {
|
|||
|
||||
bootstrap_go_package {
|
||||
name: "soong-cmd-release_config-lib",
|
||||
pkgPath: "android/soong/release_config/release_config_lib",
|
||||
pkgPath: "android/soong/cmd/release_config/release_config_lib",
|
||||
deps: [
|
||||
"golang-protobuf-encoding-prototext",
|
||||
"golang-protobuf-reflect-protoreflect",
|
||||
|
|
|
@ -17,29 +17,37 @@ package release_config_lib
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"android/soong/cmd/release_config/release_config_proto"
|
||||
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 {
|
||||
FlagDeclaration *release_config_proto.FlagDeclaration
|
||||
// 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
|
||||
|
||||
Traces []*release_config_proto.Tracepoint
|
||||
// A history of value assignments and overrides.
|
||||
Traces []*rc_proto.Tracepoint
|
||||
|
||||
// Assigned value
|
||||
Value *release_config_proto.Value
|
||||
// The value of the flag.
|
||||
Value *rc_proto.Value
|
||||
}
|
||||
|
||||
// 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 := &release_config_proto.Value{}
|
||||
value := &rc_proto.Value{}
|
||||
proto.Merge(value, src.Value)
|
||||
return &FlagArtifact{
|
||||
FlagDeclaration: src.FlagDeclaration,
|
||||
|
@ -48,6 +56,11 @@ func (src *FlagArtifact) Clone() *FlagArtifact {
|
|||
}
|
||||
}
|
||||
|
||||
// Clone FlagArtifacts.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// FlagArtifacts: a copy of the source FlagArtifacts.
|
||||
func (src FlagArtifacts) Clone() (dst FlagArtifacts) {
|
||||
if dst == nil {
|
||||
dst = make(FlagArtifacts)
|
||||
|
@ -58,23 +71,34 @@ func (src FlagArtifacts) Clone() (dst FlagArtifacts) {
|
|||
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, &release_config_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
|
||||
fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
|
||||
if fa.Value.GetObsolete() {
|
||||
return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
|
||||
}
|
||||
var newValue *release_config_proto.Value
|
||||
var newValue *rc_proto.Value
|
||||
switch val := flagValue.proto.Value.Val.(type) {
|
||||
case *release_config_proto.Value_StringValue:
|
||||
newValue = &release_config_proto.Value{Val: &release_config_proto.Value_StringValue{val.StringValue}}
|
||||
case *release_config_proto.Value_BoolValue:
|
||||
newValue = &release_config_proto.Value{Val: &release_config_proto.Value_BoolValue{val.BoolValue}}
|
||||
case *release_config_proto.Value_Obsolete:
|
||||
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 = &release_config_proto.Value{Val: &release_config_proto.Value_Obsolete{true}}
|
||||
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)
|
||||
}
|
||||
|
@ -85,8 +109,9 @@ func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (fa *FlagArtifact) Marshal() (*release_config_proto.FlagArtifact, error) {
|
||||
return &release_config_proto.FlagArtifact{
|
||||
// Marshal the FlagArtifact into a flag_artifact message.
|
||||
func (fa *FlagArtifact) Marshal() (*rc_proto.FlagArtifact, error) {
|
||||
return &rc_proto.FlagArtifact{
|
||||
FlagDeclaration: fa.FlagDeclaration,
|
||||
Value: fa.Value,
|
||||
Traces: fa.Traces,
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
package release_config_lib
|
||||
|
||||
import (
|
||||
"android/soong/cmd/release_config/release_config_proto"
|
||||
rc_proto "android/soong/cmd/release_config/release_config_proto"
|
||||
)
|
||||
|
||||
func FlagDeclarationFactory(protoPath string) (fd *release_config_proto.FlagDeclaration) {
|
||||
fd = &release_config_proto.FlagDeclaration{}
|
||||
func FlagDeclarationFactory(protoPath string) (fd *rc_proto.FlagDeclaration) {
|
||||
fd = &rc_proto.FlagDeclaration{}
|
||||
if protoPath != "" {
|
||||
LoadTextproto(protoPath, fd)
|
||||
LoadMessage(protoPath, fd)
|
||||
}
|
||||
return fd
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package release_config_lib
|
||||
|
||||
import (
|
||||
"android/soong/cmd/release_config/release_config_proto"
|
||||
"strings"
|
||||
|
||||
rc_proto "android/soong/cmd/release_config/release_config_proto"
|
||||
)
|
||||
|
||||
type FlagValue struct {
|
||||
|
@ -23,31 +25,46 @@ type FlagValue struct {
|
|||
path string
|
||||
|
||||
// Protobuf
|
||||
proto release_config_proto.FlagValue
|
||||
proto rc_proto.FlagValue
|
||||
}
|
||||
|
||||
func FlagValueFactory(protoPath string) (fv *FlagValue) {
|
||||
fv = &FlagValue{path: protoPath}
|
||||
if protoPath != "" {
|
||||
LoadTextproto(protoPath, &fv.proto)
|
||||
LoadMessage(protoPath, &fv.proto)
|
||||
}
|
||||
return fv
|
||||
}
|
||||
|
||||
func MarshalValue(value *release_config_proto.Value) string {
|
||||
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 {
|
||||
switch val := value.Val.(type) {
|
||||
case *release_config_proto.Value_UnspecifiedValue:
|
||||
case *rc_proto.Value_UnspecifiedValue:
|
||||
// Value was never set.
|
||||
return ""
|
||||
case *release_config_proto.Value_StringValue:
|
||||
case *rc_proto.Value_StringValue:
|
||||
return val.StringValue
|
||||
case *release_config_proto.Value_BoolValue:
|
||||
case *rc_proto.Value_BoolValue:
|
||||
if val.BoolValue {
|
||||
return "true"
|
||||
}
|
||||
// False ==> empty string
|
||||
return ""
|
||||
case *release_config_proto.Value_Obsolete:
|
||||
case *rc_proto.Value_Obsolete:
|
||||
return " #OBSOLETE"
|
||||
default:
|
||||
// Flagged as error elsewhere, so return empty string here.
|
||||
|
|
|
@ -16,8 +16,9 @@ package release_config_lib
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"android/soong/cmd/release_config/release_config_proto"
|
||||
rc_proto "android/soong/cmd/release_config/release_config_proto"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
@ -33,7 +34,7 @@ type ReleaseConfigContribution struct {
|
|||
DeclarationIndex int
|
||||
|
||||
// Protobufs relevant to the config.
|
||||
proto release_config_proto.ReleaseConfig
|
||||
proto rc_proto.ReleaseConfig
|
||||
|
||||
FlagValues []*FlagValue
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ type ReleaseConfig struct {
|
|||
FlagArtifacts FlagArtifacts
|
||||
|
||||
// Generated release config
|
||||
ReleaseConfigArtifact *release_config_proto.ReleaseConfigArtifact
|
||||
ReleaseConfigArtifact *rc_proto.ReleaseConfigArtifact
|
||||
|
||||
// We have begun compiling this release config.
|
||||
compileInProgress bool
|
||||
|
@ -79,12 +80,18 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro
|
|||
return fmt.Errorf("Loop detected for release config %s", config.Name)
|
||||
}
|
||||
config.compileInProgress = true
|
||||
isRoot := config.Name == "root"
|
||||
|
||||
// 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
|
||||
|
@ -101,10 +108,46 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro
|
|||
contributionsToApply = append(contributionsToApply, config.Contributions...)
|
||||
|
||||
myAconfigValueSets := []string{}
|
||||
myAconfigValueSetsMap := map[string]bool{}
|
||||
myFlags := configs.FlagArtifacts.Clone()
|
||||
workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL)
|
||||
container := rc_proto.Container(rc_proto.Container_ALL)
|
||||
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,
|
||||
Container: &container,
|
||||
Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{""}},
|
||||
},
|
||||
DeclarationIndex: -1,
|
||||
Traces: []*rc_proto.Tracepoint{
|
||||
&rc_proto.Tracepoint{
|
||||
Source: proto.String("$release-config"),
|
||||
Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{""}},
|
||||
},
|
||||
},
|
||||
}
|
||||
myFlags["RELEASE_ACONFIG_VALUE_SETS"] = &releaseAconfigValueSets
|
||||
myDirsMap := make(map[int]bool)
|
||||
for _, contrib := range contributionsToApply {
|
||||
myAconfigValueSets = append(myAconfigValueSets, contrib.proto.AconfigValueSets...)
|
||||
if len(contrib.proto.AconfigValueSets) > 0 {
|
||||
contribAconfigValueSets := []string{}
|
||||
for _, v := range contrib.proto.AconfigValueSets {
|
||||
if _, ok := myAconfigValueSetsMap[v]; !ok {
|
||||
contribAconfigValueSets = append(contribAconfigValueSets, v)
|
||||
myAconfigValueSetsMap[v] = true
|
||||
}
|
||||
}
|
||||
myAconfigValueSets = append(myAconfigValueSets, contribAconfigValueSets...)
|
||||
releaseAconfigValueSets.Traces = append(
|
||||
releaseAconfigValueSets.Traces,
|
||||
&rc_proto.Tracepoint{
|
||||
Source: proto.String(contrib.path),
|
||||
Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.Join(contribAconfigValueSets, " ")}},
|
||||
})
|
||||
}
|
||||
myDirsMap[contrib.DeclarationIndex] = true
|
||||
for _, value := range contrib.FlagValues {
|
||||
fa, ok := myFlags[*value.proto.Name]
|
||||
|
@ -116,27 +159,32 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro
|
|||
// Setting location is to the left of declaration.
|
||||
return fmt.Errorf("Setting value for flag %s not allowed in %s\n", *value.proto.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", *value.proto.Name, value.path)
|
||||
}
|
||||
if err := fa.UpdateValue(*value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.Join(myAconfigValueSets, " ")}}
|
||||
|
||||
directories := []string{}
|
||||
for idx, confDir := range configs.ConfigDirs {
|
||||
for idx, confDir := range configs.configDirs {
|
||||
if _, ok := myDirsMap[idx]; ok {
|
||||
directories = append(directories, confDir)
|
||||
}
|
||||
}
|
||||
|
||||
config.FlagArtifacts = myFlags
|
||||
config.ReleaseConfigArtifact = &release_config_proto.ReleaseConfigArtifact{
|
||||
config.ReleaseConfigArtifact = &rc_proto.ReleaseConfigArtifact{
|
||||
Name: proto.String(config.Name),
|
||||
OtherNames: config.OtherNames,
|
||||
FlagArtifacts: func() []*release_config_proto.FlagArtifact {
|
||||
ret := []*release_config_proto.FlagArtifact{}
|
||||
FlagArtifacts: func() []*rc_proto.FlagArtifact {
|
||||
ret := []*rc_proto.FlagArtifact{}
|
||||
for _, flag := range myFlags {
|
||||
ret = append(ret, &release_config_proto.FlagArtifact{
|
||||
ret = append(ret, &rc_proto.FlagArtifact{
|
||||
FlagDeclaration: flag.FlagDeclaration,
|
||||
Traces: flag.Traces,
|
||||
Value: flag.Value,
|
||||
|
|
|
@ -16,7 +16,6 @@ package release_config_lib
|
|||
|
||||
import (
|
||||
"cmp"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
@ -24,9 +23,8 @@ import (
|
|||
"slices"
|
||||
"strings"
|
||||
|
||||
"android/soong/cmd/release_config/release_config_proto"
|
||||
rc_proto "android/soong/cmd/release_config/release_config_proto"
|
||||
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
|
@ -37,10 +35,13 @@ type ReleaseConfigMap struct {
|
|||
path string
|
||||
|
||||
// Data received
|
||||
proto release_config_proto.ReleaseConfigMap
|
||||
proto rc_proto.ReleaseConfigMap
|
||||
|
||||
// Map of name:contribution for release config contributions.
|
||||
ReleaseConfigContributions map[string]*ReleaseConfigContribution
|
||||
FlagDeclarations []release_config_proto.FlagDeclaration
|
||||
|
||||
// Flags declared this directory's flag_declarations/*.textproto
|
||||
FlagDeclarations []rc_proto.FlagDeclaration
|
||||
}
|
||||
|
||||
type ReleaseConfigDirMap map[string]int
|
||||
|
@ -50,50 +51,47 @@ type ReleaseConfigs struct {
|
|||
// Ordered list of release config maps processed.
|
||||
ReleaseConfigMaps []*ReleaseConfigMap
|
||||
|
||||
// Map of directory to *ReleaseConfigMap
|
||||
ReleaseConfigMapsMap map[string]*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
|
||||
|
||||
// Generated release configs
|
||||
Artifact release_config_proto.ReleaseConfigsArtifact
|
||||
// Map of directory to *ReleaseConfigMap
|
||||
releaseConfigMapsMap map[string]*ReleaseConfigMap
|
||||
|
||||
// The list of config directories used.
|
||||
ConfigDirs []string
|
||||
configDirs []string
|
||||
|
||||
// A map from the config directory to its order in the list of config
|
||||
// directories.
|
||||
ConfigDirIndexes ReleaseConfigDirMap
|
||||
configDirIndexes ReleaseConfigDirMap
|
||||
}
|
||||
|
||||
func (configs *ReleaseConfigs) DumpArtifact(outDir string) error {
|
||||
message := &configs.Artifact
|
||||
basePath := filepath.Join(outDir, "all_release_configs")
|
||||
writer := func(suffix string, marshal func() ([]byte, error)) error {
|
||||
data, err := marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(fmt.Sprintf("%s.%s", basePath, suffix), data, 0644)
|
||||
}
|
||||
err := writer("textproto", func() ([]byte, error) { return prototext.MarshalOptions{Multiline: true}.Marshal(message) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writer("pb", func() ([]byte, error) { return proto.Marshal(message) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writer("json", func() ([]byte, error) { return json.MarshalIndent(message, "", " ") })
|
||||
// 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) {
|
||||
|
@ -101,9 +99,9 @@ func ReleaseConfigsFactory() (c *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),
|
||||
releaseConfigMapsMap: make(map[string]*ReleaseConfigMap),
|
||||
configDirs: []string{},
|
||||
configDirIndexes: make(ReleaseConfigDirMap),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +111,7 @@ func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) {
|
|||
ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution),
|
||||
}
|
||||
if protoPath != "" {
|
||||
LoadTextproto(protoPath, &m.proto)
|
||||
LoadMessage(protoPath, &m.proto)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
@ -149,7 +147,7 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex
|
|||
}
|
||||
// If the input didn't specify a value, create one (== UnspecifiedValue).
|
||||
if flagDeclaration.Value == nil {
|
||||
flagDeclaration.Value = &release_config_proto.Value{Val: &release_config_proto.Value_UnspecifiedValue{false}}
|
||||
flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}}
|
||||
}
|
||||
m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
|
||||
name := *flagDeclaration.Name
|
||||
|
@ -160,7 +158,7 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex
|
|||
}
|
||||
// Set the initial value in the flag artifact.
|
||||
configs.FlagArtifacts[name].UpdateValue(
|
||||
FlagValue{path: path, proto: release_config_proto.FlagValue{
|
||||
FlagValue{path: path, proto: rc_proto.FlagValue{
|
||||
Name: proto.String(name), Value: flagDeclaration.Value}})
|
||||
return nil
|
||||
})
|
||||
|
@ -170,7 +168,7 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex
|
|||
|
||||
err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
|
||||
releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex}
|
||||
LoadTextproto(path, &releaseConfigContribution.proto)
|
||||
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)
|
||||
|
@ -201,7 +199,7 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex
|
|||
return err
|
||||
}
|
||||
configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m)
|
||||
configs.ReleaseConfigMapsMap[dir] = m
|
||||
configs.releaseConfigMapsMap[dir] = m
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -217,16 +215,23 @@ func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, er
|
|||
return nil, fmt.Errorf("Missing config %s. Trace=%v", name, trace)
|
||||
}
|
||||
|
||||
func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error {
|
||||
outFile := filepath.Join(outDir, "release_config.mk")
|
||||
// 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 config.FlagArtifacts {
|
||||
for k, _ := range myFlagArtifacts {
|
||||
names = append(names, k)
|
||||
}
|
||||
slices.SortFunc(names, func(a, b string) int {
|
||||
|
@ -242,12 +247,12 @@ func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error
|
|||
}
|
||||
|
||||
for _, name := range names {
|
||||
flag := config.FlagArtifacts[name]
|
||||
flag := myFlagArtifacts[name]
|
||||
decl := flag.FlagDeclaration
|
||||
|
||||
// cName := strings.ToLower(release_config_proto.Container_name[decl.GetContainer()])
|
||||
// cName := strings.ToLower(rc_proto.Container_name[decl.GetContainer()])
|
||||
cName := strings.ToLower(decl.Container.String())
|
||||
if cName == strings.ToLower(release_config_proto.Container_ALL.String()) {
|
||||
if cName == strings.ToLower(rc_proto.Container_ALL.String()) {
|
||||
partitions["product"] = append(partitions["product"], name)
|
||||
partitions["system"] = append(partitions["system"], name)
|
||||
partitions["system_ext"] = append(partitions["system_ext"], name)
|
||||
|
@ -282,7 +287,13 @@ func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error
|
|||
// _ALL_RELEASE_FLAGS.PARTITIONS.*
|
||||
// all _ALL_RELEASE_FLAGS.*, sorted by name
|
||||
// Final flag values, sorted by name.
|
||||
data := fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
|
||||
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], " "))
|
||||
}
|
||||
|
@ -290,8 +301,6 @@ func (configs *ReleaseConfigs) DumpMakefile(outDir, targetRelease string) error
|
|||
data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName])
|
||||
}
|
||||
data += "\n\n# Values for all build flags\n"
|
||||
data += fmt.Sprintf("RELEASE_ACONFIG_VALUE_SETS :=$= %s\n",
|
||||
strings.Join(config.ReleaseConfigArtifact.AconfigValueSets, " "))
|
||||
for _, name := range names {
|
||||
data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name])
|
||||
}
|
||||
|
@ -326,10 +335,10 @@ func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) erro
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configs.Artifact = release_config_proto.ReleaseConfigsArtifact{
|
||||
configs.Artifact = rc_proto.ReleaseConfigsArtifact{
|
||||
ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
|
||||
OtherReleaseConfigs: func() []*release_config_proto.ReleaseConfigArtifact {
|
||||
orc := []*release_config_proto.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)
|
||||
|
@ -337,9 +346,9 @@ func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) erro
|
|||
}
|
||||
return orc
|
||||
}(),
|
||||
ReleaseConfigMapsMap: func() map[string]*release_config_proto.ReleaseConfigMap {
|
||||
ret := make(map[string]*release_config_proto.ReleaseConfigMap)
|
||||
for k, v := range configs.ReleaseConfigMapsMap {
|
||||
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
|
||||
|
@ -363,8 +372,8 @@ func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease strin
|
|||
for idx, releaseConfigMapPath := range releaseConfigMapPaths {
|
||||
// Maintain an ordered list of release config directories.
|
||||
configDir := filepath.Dir(releaseConfigMapPath)
|
||||
configs.ConfigDirIndexes[configDir] = idx
|
||||
configs.ConfigDirs = append(configs.ConfigDirs, configDir)
|
||||
configs.configDirIndexes[configDir] = idx
|
||||
configs.configDirs = append(configs.configDirs, configDir)
|
||||
err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package release_config_lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
@ -38,15 +39,66 @@ func (l *StringList) String() string {
|
|||
return fmt.Sprintf("%v", *l)
|
||||
}
|
||||
|
||||
func LoadTextproto(path string, message proto.Message) error {
|
||||
// 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
|
||||
}
|
||||
ret := prototext.Unmarshal(data, message)
|
||||
return ret
|
||||
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 {
|
||||
|
@ -76,6 +128,7 @@ func warnf(format string, args ...any) (n int, err error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
// Returns the default value for release config artifacts.
|
||||
func GetDefaultOutDir() string {
|
||||
outEnv := os.Getenv("OUT_DIR")
|
||||
if outEnv == "" {
|
||||
|
@ -84,6 +137,7 @@ func GetDefaultOutDir() string {
|
|||
return filepath.Join(outEnv, "soong", "release-config")
|
||||
}
|
||||
|
||||
// Return the default list of map files to use.
|
||||
func GetDefaultMapPaths() StringList {
|
||||
var defaultMapPaths StringList
|
||||
defaultLocations := StringList{
|
||||
|
|
|
@ -18,7 +18,7 @@ package {
|
|||
|
||||
bootstrap_go_package {
|
||||
name: "soong-cmd-release_config-proto",
|
||||
pkgPath: "android/soong/release_config/release_config_proto",
|
||||
pkgPath: "android/soong/cmd/release_config/release_config_proto",
|
||||
deps: [
|
||||
"golang-protobuf-reflect-protoreflect",
|
||||
"golang-protobuf-runtime-protoimpl",
|
||||
|
|
Loading…
Reference in a new issue