Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72beb346 authored by Liz Kammer's avatar Liz Kammer
Browse files

Add package for printing starlark formatted data

Bug: 216168792
Test: build/bazel/ci/bp2build.sh
Change-Id: I3a06b19396f7ffe1c638042cda7e731dd840f1d6
parent db07f002
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@ bootstrap_go_package {
        "soong-remoteexec",
        "soong-response",
        "soong-shared",
        "soong-starlark-format",
        "soong-ui-metrics_proto",

        "golang-protobuf-proto",
        "golang-protobuf-encoding-prototext",

+3 −4
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import (
	"android/soong/android/soongconfig"
	"android/soong/bazel"
	"android/soong/remoteexec"
	"android/soong/starlark_fmt"
)

// Bool re-exports proptools.Bool for the android package.
@@ -286,14 +287,12 @@ func saveToBazelConfigFile(config *productVariables, outDir string) error {
		}
	}

	//TODO(b/216168792) should use common function to print Starlark code
	nonArchVariantProductVariablesJson, err := json.MarshalIndent(&nonArchVariantProductVariables, "", "    ")
	nonArchVariantProductVariablesJson := starlark_fmt.PrintStringList(nonArchVariantProductVariables, 0)
	if err != nil {
		return fmt.Errorf("cannot marshal product variable data: %s", err.Error())
	}

	//TODO(b/216168792) should use common function to print Starlark code
	archVariantProductVariablesJson, err := json.MarshalIndent(&archVariantProductVariables, "", "    ")
	archVariantProductVariablesJson := starlark_fmt.PrintStringList(archVariantProductVariables, 0)
	if err != nil {
		return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error())
	}
+40 −0
Original line number Diff line number Diff line
@@ -386,6 +386,46 @@ func TestNonExistentPropertyInSoongConfigModule(t *testing.T) {
	})).RunTest(t)
}

func TestDuplicateStringValueInSoongConfigStringVariable(t *testing.T) {
	bp := `
		soong_config_string_variable {
			name: "board",
			values: ["soc_a", "soc_b", "soc_c", "soc_a"],
		}

		soong_config_module_type {
			name: "acme_test",
			module_type: "test",
			config_namespace: "acme",
			variables: ["board"],
			properties: ["cflags", "srcs", "defaults"],
		}
    `

	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
		return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
			variables.VendorVars = vars
		})
	}

	GroupFixturePreparers(
		fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
		PrepareForTestWithDefaults,
		FixtureRegisterWithContext(func(ctx RegistrationContext) {
			ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
			ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
			ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
			ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
			ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
			ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
		}),
		FixtureWithRootAndroidBp(bp),
	).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
		// TODO(b/171232169): improve the error message for non-existent properties
		`Android.bp: soong_config_string_variable: values property error: duplicate value: "soc_a"`,
	})).RunTest(t)
}

func testConfigWithVendorVars(buildDir, bp string, fs map[string][]byte, vendorVars map[string]map[string]string) Config {
	config := TestConfig(buildDir, nil, bp, fs)

+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ bootstrap_go_package {
        "blueprint-parser",
        "blueprint-proptools",
        "soong-bazel",
        "soong-starlark-format",
    ],
    srcs: [
        "config.go",
+34 −27
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import (
	"github.com/google/blueprint"
	"github.com/google/blueprint/parser"
	"github.com/google/blueprint/proptools"

	"android/soong/starlark_fmt"
)

const conditionsDefault = "conditions_default"
@@ -177,10 +179,14 @@ func processStringVariableDef(v *SoongConfigDefinition, def *parser.Module) (err
		return []error{fmt.Errorf("values property must be set")}
	}

	vals := make(map[string]bool, len(stringProps.Values))
	for _, name := range stringProps.Values {
		if err := checkVariableName(name); err != nil {
			return []error{fmt.Errorf("soong_config_string_variable: values property error %s", err)}
		} else if _, ok := vals[name]; ok {
			return []error{fmt.Errorf("soong_config_string_variable: values property error: duplicate value: %q", name)}
		}
		vals[name] = true
	}

	v.variables[base.variable] = &stringVariable{
@@ -235,7 +241,12 @@ type SoongConfigDefinition struct {
// string vars, bool vars and value vars created by every
// soong_config_module_type in this build.
type Bp2BuildSoongConfigDefinitions struct {
	StringVars map[string]map[string]bool
	// varCache contains a cache of string variables namespace + property
	// The same variable may be used in multiple module types (for example, if need support
	// for cc_default and java_default), only need to process once
	varCache map[string]bool

	StringVars map[string][]string
	BoolVars   map[string]bool
	ValueVars  map[string]bool
}
@@ -253,7 +264,7 @@ func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef SoongConfigDefinition)
	defer bp2buildSoongConfigVarsLock.Unlock()

	if defs.StringVars == nil {
		defs.StringVars = make(map[string]map[string]bool)
		defs.StringVars = make(map[string][]string)
	}
	if defs.BoolVars == nil {
		defs.BoolVars = make(map[string]bool)
@@ -261,15 +272,24 @@ func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef SoongConfigDefinition)
	if defs.ValueVars == nil {
		defs.ValueVars = make(map[string]bool)
	}
	if defs.varCache == nil {
		defs.varCache = make(map[string]bool)
	}
	for _, moduleType := range mtDef.ModuleTypes {
		for _, v := range moduleType.Variables {
			key := strings.Join([]string{moduleType.ConfigNamespace, v.variableProperty()}, "__")
			if strVar, ok := v.(*stringVariable); ok {
				if _, ok := defs.StringVars[key]; !ok {
					defs.StringVars[key] = make(map[string]bool, 0)

			// The same variable may be used in multiple module types (for example, if need support
			// for cc_default and java_default), only need to process once
			if _, keyInCache := defs.varCache[key]; keyInCache {
				continue
			} else {
				defs.varCache[key] = true
			}

			if strVar, ok := v.(*stringVariable); ok {
				for _, value := range strVar.values {
					defs.StringVars[key][value] = true
					defs.StringVars[key] = append(defs.StringVars[key], value)
				}
			} else if _, ok := v.(*boolVariable); ok {
				defs.BoolVars[key] = true
@@ -302,29 +322,16 @@ func sortedStringKeys(m interface{}) []string {
// String emits the Soong config variable definitions as Starlark dictionaries.
func (defs Bp2BuildSoongConfigDefinitions) String() string {
	ret := ""
	ret += "soong_config_bool_variables = {\n"
	for _, boolVar := range sortedStringKeys(defs.BoolVars) {
		ret += fmt.Sprintf("    \"%s\": True,\n", boolVar)
	}
	ret += "}\n"
	ret += "\n"
	ret += "soong_config_bool_variables = "
	ret += starlark_fmt.PrintBoolDict(defs.BoolVars, 0)
	ret += "\n\n"

	ret += "soong_config_value_variables = {\n"
	for _, valueVar := range sortedStringKeys(defs.ValueVars) {
		ret += fmt.Sprintf("    \"%s\": True,\n", valueVar)
	}
	ret += "}\n"
	ret += "\n"
	ret += "soong_config_value_variables = "
	ret += starlark_fmt.PrintBoolDict(defs.ValueVars, 0)
	ret += "\n\n"

	ret += "soong_config_string_variables = {\n"
	for _, stringVar := range sortedStringKeys(defs.StringVars) {
		ret += fmt.Sprintf("    \"%s\": [\n", stringVar)
		for _, choice := range sortedStringKeys(defs.StringVars[stringVar]) {
			ret += fmt.Sprintf("        \"%s\",\n", choice)
		}
		ret += fmt.Sprintf("    ],\n")
	}
	ret += "}"
	ret += "soong_config_string_variables = "
	ret += starlark_fmt.PrintStringListDict(defs.StringVars, 0)

	return ret
}
Loading