Allow soong config value variables to set nested properties
Previously, it would error out if it saw anything that wasn't a string
or slice of strings. Now it will also recurse in sub-structs.
Fixes: 326255534
Test: go test
Change-Id: Icbca8e4a2cf54b5610599a10805550fed05eb396
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index d525bdc..c78b726 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -681,6 +681,14 @@
if !propStruct.IsValid() {
return nil, nil
}
+ if err := s.printfIntoPropertyRecursive(nil, propStruct, configValue); err != nil {
+ return nil, err
+ }
+
+ return values.Interface(), nil
+}
+
+func (s *valueVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValue string) error {
for i := 0; i < propStruct.NumField(); i++ {
field := propStruct.Field(i)
kind := field.Kind()
@@ -695,23 +703,31 @@
case reflect.String:
err := printfIntoProperty(field, configValue)
if err != nil {
- return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
}
case reflect.Slice:
for j := 0; j < field.Len(); j++ {
err := printfIntoProperty(field.Index(j), configValue)
if err != nil {
- return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
}
}
case reflect.Bool:
// Nothing to do
+ case reflect.Struct:
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ if err := s.printfIntoPropertyRecursive(fieldName, field, configValue); err != nil {
+ return err
+ }
+ fieldName = fieldName[:len(fieldName)-1]
default:
- return nil, fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, propStruct.Type().Field(i).Name, kind)
+ fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+ return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind)
}
}
-
- return values.Interface(), nil
+ return nil
}
func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index db2c83c..1da0b49 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -429,6 +429,76 @@
}
}
+func Test_PropertiesToApply_Value_Nested(t *testing.T) {
+ mt, _ := newModuleType(&ModuleTypeProperties{
+ Module_type: "foo",
+ Config_namespace: "bar",
+ Value_variables: []string{"my_value_var"},
+ Properties: []string{"a.b"},
+ })
+ type properties struct {
+ A struct {
+ B string
+ }
+ }
+ conditionsDefault := &properties{
+ A: struct{ B string }{
+ B: "default",
+ },
+ }
+ type valueVarProps struct {
+ A struct {
+ B string
+ }
+ Conditions_default *properties
+ }
+ actualProps := &struct {
+ Soong_config_variables valueSoongConfigVars
+ }{
+ Soong_config_variables: valueSoongConfigVars{
+ My_value_var: &valueVarProps{
+ A: struct{ B string }{
+ B: "A.B=%s",
+ },
+ Conditions_default: conditionsDefault,
+ },
+ },
+ }
+ props := reflect.ValueOf(actualProps)
+
+ testCases := []struct {
+ name string
+ config SoongConfig
+ wantProps []interface{}
+ }{
+ {
+ name: "no_vendor_config",
+ config: Config(map[string]string{}),
+ wantProps: []interface{}{conditionsDefault},
+ },
+ {
+ name: "value_var_set",
+ config: Config(map[string]string{"my_value_var": "Hello"}),
+ wantProps: []interface{}{&properties{
+ A: struct{ B string }{
+ B: "A.B=Hello",
+ },
+ }},
+ },
+ }
+
+ for _, tc := range testCases {
+ gotProps, err := PropertiesToApply(mt, props, tc.config)
+ if err != nil {
+ t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
+ }
+
+ if !reflect.DeepEqual(gotProps, tc.wantProps) {
+ t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
+ }
+ }
+}
+
func Test_PropertiesToApply_String_Error(t *testing.T) {
mt, _ := newModuleType(&ModuleTypeProperties{
Module_type: "foo",