Add support to Soong config list variable
List variables act similar to value variables. Each value in a list variable will be added to a list property after string substitution. Bug: 329208946 Test: m --no-skip-soong-tests Test: m selinux_policy_system_soong Change-Id: I1127bfb0798e7e5f7d665f647307224d5ff5d790
This commit is contained in:
parent
d50832c122
commit
02c8618e1b
4 changed files with 266 additions and 58 deletions
26
README.md
26
README.md
|
@ -449,6 +449,7 @@ soong_config_module_type {
|
||||||
config_namespace: "acme",
|
config_namespace: "acme",
|
||||||
variables: ["board"],
|
variables: ["board"],
|
||||||
bool_variables: ["feature"],
|
bool_variables: ["feature"],
|
||||||
|
list_variables: ["impl"],
|
||||||
value_variables: ["width"],
|
value_variables: ["width"],
|
||||||
properties: ["cflags", "srcs"],
|
properties: ["cflags", "srcs"],
|
||||||
}
|
}
|
||||||
|
@ -460,12 +461,13 @@ soong_config_string_variable {
|
||||||
```
|
```
|
||||||
|
|
||||||
This example describes a new `acme_cc_defaults` module type that extends the
|
This example describes a new `acme_cc_defaults` module type that extends the
|
||||||
`cc_defaults` module type, with three additional conditionals based on
|
`cc_defaults` module type, with four additional conditionals based on variables
|
||||||
variables `board`, `feature` and `width`, which can affect properties `cflags`
|
`board`, `feature`, `impl` and `width` which can affect properties `cflags` and
|
||||||
and `srcs`. Additionally, each conditional will contain a `conditions_default`
|
`srcs`. Additionally, each conditional will contain a `conditions_default`
|
||||||
property can affect `cflags` and `srcs` in the following conditions:
|
property can affect `cflags` and `srcs` in the following conditions:
|
||||||
|
|
||||||
* bool variable (e.g. `feature`): the variable is unspecified or not set to a true value
|
* bool variable (e.g. `feature`): the variable is unspecified or not set to a true value
|
||||||
|
* list variable (e.g. `impl`): the variable is unspecified
|
||||||
* value variable (e.g. `width`): the variable is unspecified
|
* value variable (e.g. `width`): the variable is unspecified
|
||||||
* string variable (e.g. `board`): the variable is unspecified or the variable is set to a string unused in the
|
* string variable (e.g. `board`): the variable is unspecified or the variable is set to a string unused in the
|
||||||
given module. For example, with `board`, if the `board`
|
given module. For example, with `board`, if the `board`
|
||||||
|
@ -478,6 +480,7 @@ The values of the variables can be set from a product's `BoardConfig.mk` file:
|
||||||
```
|
```
|
||||||
$(call soong_config_set,acme,board,soc_a)
|
$(call soong_config_set,acme,board,soc_a)
|
||||||
$(call soong_config_set,acme,feature,true)
|
$(call soong_config_set,acme,feature,true)
|
||||||
|
$(call soong_config_set,acme,impl,foo.cpp bar.cpp)
|
||||||
$(call soong_config_set,acme,width,200)
|
$(call soong_config_set,acme,width,200)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -519,6 +522,12 @@ acme_cc_defaults {
|
||||||
cflags: ["-DWIDTH=DEFAULT"],
|
cflags: ["-DWIDTH=DEFAULT"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
impl: {
|
||||||
|
srcs: ["impl/%s"],
|
||||||
|
conditions_default: {
|
||||||
|
srcs: ["impl/default.cpp"],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +539,8 @@ cc_library {
|
||||||
```
|
```
|
||||||
|
|
||||||
With the `BoardConfig.mk` snippet above, `libacme_foo` would build with
|
With the `BoardConfig.mk` snippet above, `libacme_foo` would build with
|
||||||
`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"`.
|
`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"` and
|
||||||
|
`srcs: ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"]`.
|
||||||
|
|
||||||
Alternatively, with `DefaultBoardConfig.mk`:
|
Alternatively, with `DefaultBoardConfig.mk`:
|
||||||
|
|
||||||
|
@ -539,12 +549,14 @@ SOONG_CONFIG_NAMESPACES += acme
|
||||||
SOONG_CONFIG_acme += \
|
SOONG_CONFIG_acme += \
|
||||||
board \
|
board \
|
||||||
feature \
|
feature \
|
||||||
|
impl \
|
||||||
width \
|
width \
|
||||||
|
|
||||||
SOONG_CONFIG_acme_feature := false
|
SOONG_CONFIG_acme_feature := false
|
||||||
```
|
```
|
||||||
|
|
||||||
then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"`.
|
then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"`
|
||||||
|
and `srcs: ["*.cpp", "impl/default.cpp"]`.
|
||||||
|
|
||||||
Alternatively, with `DefaultBoardConfig.mk`:
|
Alternatively, with `DefaultBoardConfig.mk`:
|
||||||
|
|
||||||
|
@ -553,13 +565,15 @@ SOONG_CONFIG_NAMESPACES += acme
|
||||||
SOONG_CONFIG_acme += \
|
SOONG_CONFIG_acme += \
|
||||||
board \
|
board \
|
||||||
feature \
|
feature \
|
||||||
|
impl \
|
||||||
width \
|
width \
|
||||||
|
|
||||||
SOONG_CONFIG_acme_board := soc_c
|
SOONG_CONFIG_acme_board := soc_c
|
||||||
|
SOONG_CONFIG_acme_impl := baz
|
||||||
```
|
```
|
||||||
|
|
||||||
then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT
|
then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT
|
||||||
-DFEATURE_DEFAULT -DSIZE=DEFAULT"`.
|
-DFEATURE_DEFAULT -DSIZE=DEFAULT"` and `srcs: ["*.cpp", "impl/baz.cpp"]`.
|
||||||
|
|
||||||
`soong_config_module_type` modules will work best when used to wrap defaults
|
`soong_config_module_type` modules will work best when used to wrap defaults
|
||||||
modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
|
modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
|
||||||
|
|
|
@ -64,6 +64,7 @@ type soongConfigModuleTypeImportProperties struct {
|
||||||
// specified in `conditions_default` will only be used under the following conditions:
|
// specified in `conditions_default` will only be used under the following conditions:
|
||||||
// bool variable: the variable is unspecified or not set to a true value
|
// bool variable: the variable is unspecified or not set to a true value
|
||||||
// value variable: the variable is unspecified
|
// value variable: the variable is unspecified
|
||||||
|
// list variable: the variable is unspecified
|
||||||
// string variable: the variable is unspecified or the variable is set to a string unused in the
|
// string variable: the variable is unspecified or the variable is set to a string unused in the
|
||||||
// given module. For example, string variable `test` takes values: "a" and "b",
|
// given module. For example, string variable `test` takes values: "a" and "b",
|
||||||
// if the module contains a property `a` and `conditions_default`, when test=b,
|
// if the module contains a property `a` and `conditions_default`, when test=b,
|
||||||
|
@ -104,6 +105,12 @@ type soongConfigModuleTypeImportProperties struct {
|
||||||
// cflags: ["-DWIDTH=DEFAULT"],
|
// cflags: ["-DWIDTH=DEFAULT"],
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
|
// impl: {
|
||||||
|
// srcs: ["impl/%s"],
|
||||||
|
// conditions_default: {
|
||||||
|
// srcs: ["impl/default.cpp"],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
@ -122,6 +129,7 @@ type soongConfigModuleTypeImportProperties struct {
|
||||||
// variables: ["board"],
|
// variables: ["board"],
|
||||||
// bool_variables: ["feature"],
|
// bool_variables: ["feature"],
|
||||||
// value_variables: ["width"],
|
// value_variables: ["width"],
|
||||||
|
// list_variables: ["impl"],
|
||||||
// properties: ["cflags", "srcs"],
|
// properties: ["cflags", "srcs"],
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
@ -135,8 +143,10 @@ type soongConfigModuleTypeImportProperties struct {
|
||||||
// $(call add_soong_config_var_value, acme, board, soc_a)
|
// $(call add_soong_config_var_value, acme, board, soc_a)
|
||||||
// $(call add_soong_config_var_value, acme, feature, true)
|
// $(call add_soong_config_var_value, acme, feature, true)
|
||||||
// $(call add_soong_config_var_value, acme, width, 200)
|
// $(call add_soong_config_var_value, acme, width, 200)
|
||||||
|
// $(call add_soong_config_var_value, acme, impl, foo.cpp bar.cpp)
|
||||||
//
|
//
|
||||||
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
|
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200" and srcs
|
||||||
|
// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
|
||||||
//
|
//
|
||||||
// Alternatively, if acme BoardConfig.mk file contained:
|
// Alternatively, if acme BoardConfig.mk file contained:
|
||||||
//
|
//
|
||||||
|
@ -148,7 +158,9 @@ type soongConfigModuleTypeImportProperties struct {
|
||||||
// SOONG_CONFIG_acme_feature := false
|
// SOONG_CONFIG_acme_feature := false
|
||||||
//
|
//
|
||||||
// Then libacme_foo would build with cflags:
|
// Then libacme_foo would build with cflags:
|
||||||
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
|
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"
|
||||||
|
// and with srcs:
|
||||||
|
// ["*.cpp", "impl/default.cpp"].
|
||||||
//
|
//
|
||||||
// Similarly, if acme BoardConfig.mk file contained:
|
// Similarly, if acme BoardConfig.mk file contained:
|
||||||
//
|
//
|
||||||
|
@ -158,9 +170,13 @@ type soongConfigModuleTypeImportProperties struct {
|
||||||
// feature \
|
// feature \
|
||||||
//
|
//
|
||||||
// SOONG_CONFIG_acme_board := soc_c
|
// SOONG_CONFIG_acme_board := soc_c
|
||||||
|
// SOONG_CONFIG_acme_impl := foo.cpp bar.cpp
|
||||||
//
|
//
|
||||||
// Then libacme_foo would build with cflags:
|
// Then libacme_foo would build with cflags:
|
||||||
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
|
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"
|
||||||
|
// and with srcs:
|
||||||
|
// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
|
||||||
|
//
|
||||||
|
|
||||||
func SoongConfigModuleTypeImportFactory() Module {
|
func SoongConfigModuleTypeImportFactory() Module {
|
||||||
module := &soongConfigModuleTypeImport{}
|
module := &soongConfigModuleTypeImport{}
|
||||||
|
@ -201,6 +217,7 @@ type soongConfigModuleTypeModule struct {
|
||||||
//
|
//
|
||||||
// bool variable: the variable is unspecified or not set to a true value
|
// bool variable: the variable is unspecified or not set to a true value
|
||||||
// value variable: the variable is unspecified
|
// value variable: the variable is unspecified
|
||||||
|
// list variable: the variable is unspecified
|
||||||
// string variable: the variable is unspecified or the variable is set to a string unused in the
|
// string variable: the variable is unspecified or the variable is set to a string unused in the
|
||||||
// given module. For example, string variable `test` takes values: "a" and "b",
|
// given module. For example, string variable `test` takes values: "a" and "b",
|
||||||
// if the module contains a property `a` and `conditions_default`, when test=b,
|
// if the module contains a property `a` and `conditions_default`, when test=b,
|
||||||
|
@ -209,56 +226,63 @@ type soongConfigModuleTypeModule struct {
|
||||||
//
|
//
|
||||||
// For example, an Android.bp file could have:
|
// For example, an Android.bp file could have:
|
||||||
//
|
//
|
||||||
// soong_config_module_type {
|
// soong_config_module_type {
|
||||||
// name: "acme_cc_defaults",
|
// name: "acme_cc_defaults",
|
||||||
// module_type: "cc_defaults",
|
// module_type: "cc_defaults",
|
||||||
// config_namespace: "acme",
|
// config_namespace: "acme",
|
||||||
// variables: ["board"],
|
// variables: ["board"],
|
||||||
// bool_variables: ["feature"],
|
// bool_variables: ["feature"],
|
||||||
// value_variables: ["width"],
|
// value_variables: ["width"],
|
||||||
// properties: ["cflags", "srcs"],
|
// list_variables: ["impl"],
|
||||||
// }
|
// properties: ["cflags", "srcs"],
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// soong_config_string_variable {
|
// soong_config_string_variable {
|
||||||
// name: "board",
|
// name: "board",
|
||||||
// values: ["soc_a", "soc_b"],
|
// values: ["soc_a", "soc_b"],
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// acme_cc_defaults {
|
// acme_cc_defaults {
|
||||||
// name: "acme_defaults",
|
// name: "acme_defaults",
|
||||||
// cflags: ["-DGENERIC"],
|
// cflags: ["-DGENERIC"],
|
||||||
// soong_config_variables: {
|
// soong_config_variables: {
|
||||||
// board: {
|
// board: {
|
||||||
// soc_a: {
|
// soc_a: {
|
||||||
// cflags: ["-DSOC_A"],
|
// cflags: ["-DSOC_A"],
|
||||||
// },
|
|
||||||
// soc_b: {
|
|
||||||
// cflags: ["-DSOC_B"],
|
|
||||||
// },
|
|
||||||
// conditions_default: {
|
|
||||||
// cflags: ["-DSOC_DEFAULT"],
|
|
||||||
// },
|
|
||||||
// },
|
// },
|
||||||
// feature: {
|
// soc_b: {
|
||||||
// cflags: ["-DFEATURE"],
|
// cflags: ["-DSOC_B"],
|
||||||
// conditions_default: {
|
|
||||||
// cflags: ["-DFEATURE_DEFAULT"],
|
|
||||||
// },
|
|
||||||
// },
|
// },
|
||||||
// width: {
|
// conditions_default: {
|
||||||
// cflags: ["-DWIDTH=%s"],
|
// cflags: ["-DSOC_DEFAULT"],
|
||||||
// conditions_default: {
|
|
||||||
// cflags: ["-DWIDTH=DEFAULT"],
|
|
||||||
// },
|
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// }
|
// feature: {
|
||||||
|
// cflags: ["-DFEATURE"],
|
||||||
|
// conditions_default: {
|
||||||
|
// cflags: ["-DFEATURE_DEFAULT"],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// width: {
|
||||||
|
// cflags: ["-DWIDTH=%s"],
|
||||||
|
// conditions_default: {
|
||||||
|
// cflags: ["-DWIDTH=DEFAULT"],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// impl: {
|
||||||
|
// srcs: ["impl/%s"],
|
||||||
|
// conditions_default: {
|
||||||
|
// srcs: ["impl/default.cpp"],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// cc_library {
|
// cc_library {
|
||||||
// name: "libacme_foo",
|
// name: "libacme_foo",
|
||||||
// defaults: ["acme_defaults"],
|
// defaults: ["acme_defaults"],
|
||||||
// srcs: ["*.cpp"],
|
// srcs: ["*.cpp"],
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// If an acme BoardConfig.mk file contained:
|
// If an acme BoardConfig.mk file contained:
|
||||||
//
|
//
|
||||||
|
@ -270,8 +294,10 @@ type soongConfigModuleTypeModule struct {
|
||||||
// SOONG_CONFIG_acme_board := soc_a
|
// SOONG_CONFIG_acme_board := soc_a
|
||||||
// SOONG_CONFIG_acme_feature := true
|
// SOONG_CONFIG_acme_feature := true
|
||||||
// SOONG_CONFIG_acme_width := 200
|
// SOONG_CONFIG_acme_width := 200
|
||||||
|
// SOONG_CONFIG_acme_impl := foo.cpp bar.cpp
|
||||||
//
|
//
|
||||||
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
|
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE" and srcs
|
||||||
|
// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
|
||||||
func SoongConfigModuleTypeFactory() Module {
|
func SoongConfigModuleTypeFactory() Module {
|
||||||
module := &soongConfigModuleTypeModule{}
|
module := &soongConfigModuleTypeModule{}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,10 @@ type ModuleTypeProperties struct {
|
||||||
// inserted into the properties with %s substitution.
|
// inserted into the properties with %s substitution.
|
||||||
Value_variables []string
|
Value_variables []string
|
||||||
|
|
||||||
|
// the list of SOONG_CONFIG list variables that this module type will read. Each value will be
|
||||||
|
// inserted into the properties with %s substitution.
|
||||||
|
List_variables []string
|
||||||
|
|
||||||
// the list of properties that this module type will extend.
|
// the list of properties that this module type will extend.
|
||||||
Properties []string
|
Properties []string
|
||||||
}
|
}
|
||||||
|
@ -468,6 +472,18 @@ func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, name := range props.List_variables {
|
||||||
|
if err := checkVariableName(name); err != nil {
|
||||||
|
return nil, []error{fmt.Errorf("list_variables %s", err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
mt.Variables = append(mt.Variables, &listVariable{
|
||||||
|
baseVariable: baseVariable{
|
||||||
|
variable: name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return mt, nil
|
return mt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,6 +746,90 @@ func (s *valueVariable) printfIntoPropertyRecursive(fieldName []string, propStru
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Struct to allow conditions set based on a list variable, supporting string substitution.
|
||||||
|
type listVariable struct {
|
||||||
|
baseVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *listVariable) variableValuesType() reflect.Type {
|
||||||
|
return emptyInterfaceType
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializeProperties initializes a property to zero value of typ with an additional conditions
|
||||||
|
// default field.
|
||||||
|
func (s *listVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
|
||||||
|
initializePropertiesWithDefault(v, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
|
||||||
|
// the module. If the variable was not set, conditions_default interface will be returned;
|
||||||
|
// otherwise, the interface in values, without conditions_default will be returned with all
|
||||||
|
// appropriate string substitutions based on variable being set.
|
||||||
|
func (s *listVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
|
||||||
|
// If this variable was not referenced in the module, there are no properties to apply.
|
||||||
|
if !values.IsValid() || values.Elem().IsZero() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if !config.IsSet(s.variable) {
|
||||||
|
return conditionsDefaultField(values.Elem().Elem()).Interface(), nil
|
||||||
|
}
|
||||||
|
configValues := strings.Split(config.String(s.variable), " ")
|
||||||
|
|
||||||
|
values = removeDefault(values)
|
||||||
|
propStruct := values.Elem()
|
||||||
|
if !propStruct.IsValid() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err := s.printfIntoPropertyRecursive(nil, propStruct, configValues); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *listVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValues []string) error {
|
||||||
|
for i := 0; i < propStruct.NumField(); i++ {
|
||||||
|
field := propStruct.Field(i)
|
||||||
|
kind := field.Kind()
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
field = field.Elem()
|
||||||
|
kind = field.Kind()
|
||||||
|
}
|
||||||
|
switch kind {
|
||||||
|
case reflect.Slice:
|
||||||
|
elemType := field.Type().Elem()
|
||||||
|
newLen := field.Len() * len(configValues)
|
||||||
|
newField := reflect.MakeSlice(field.Type(), 0, newLen)
|
||||||
|
for j := 0; j < field.Len(); j++ {
|
||||||
|
for _, configValue := range configValues {
|
||||||
|
res := reflect.Indirect(reflect.New(elemType))
|
||||||
|
res.Set(field.Index(j))
|
||||||
|
err := printfIntoProperty(res, configValue)
|
||||||
|
if err != nil {
|
||||||
|
fieldName = append(fieldName, propStruct.Type().Field(i).Name)
|
||||||
|
return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
|
||||||
|
}
|
||||||
|
newField = reflect.Append(newField, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field.Set(newField)
|
||||||
|
case reflect.Struct:
|
||||||
|
fieldName = append(fieldName, propStruct.Type().Field(i).Name)
|
||||||
|
if err := s.printfIntoPropertyRecursive(fieldName, field, configValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fieldName = fieldName[:len(fieldName)-1]
|
||||||
|
default:
|
||||||
|
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 nil
|
||||||
|
}
|
||||||
|
|
||||||
func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
|
func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
|
||||||
s := propertyValue.String()
|
s := propertyValue.String()
|
||||||
|
|
||||||
|
@ -739,7 +839,7 @@ func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if count > 1 {
|
if count > 1 {
|
||||||
return fmt.Errorf("value variable properties only support a single '%%'")
|
return fmt.Errorf("list/value variable properties only support a single '%%'")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(s, "%s") {
|
if !strings.Contains(s, "%s") {
|
||||||
|
|
|
@ -291,11 +291,13 @@ func Test_createAffectablePropertiesType(t *testing.T) {
|
||||||
type properties struct {
|
type properties struct {
|
||||||
A *string
|
A *string
|
||||||
B bool
|
B bool
|
||||||
|
C []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type boolVarProps struct {
|
type varProps struct {
|
||||||
A *string
|
A *string
|
||||||
B bool
|
B bool
|
||||||
|
C []string
|
||||||
Conditions_default *properties
|
Conditions_default *properties
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +313,19 @@ type valueSoongConfigVars struct {
|
||||||
My_value_var interface{}
|
My_value_var interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type listProperties struct {
|
||||||
|
C []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type listVarProps struct {
|
||||||
|
C []string
|
||||||
|
Conditions_default *listProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
type listSoongConfigVars struct {
|
||||||
|
List_var interface{}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_PropertiesToApply_Bool(t *testing.T) {
|
func Test_PropertiesToApply_Bool(t *testing.T) {
|
||||||
mt, _ := newModuleType(&ModuleTypeProperties{
|
mt, _ := newModuleType(&ModuleTypeProperties{
|
||||||
Module_type: "foo",
|
Module_type: "foo",
|
||||||
|
@ -330,7 +345,7 @@ func Test_PropertiesToApply_Bool(t *testing.T) {
|
||||||
Soong_config_variables boolSoongConfigVars
|
Soong_config_variables boolSoongConfigVars
|
||||||
}{
|
}{
|
||||||
Soong_config_variables: boolSoongConfigVars{
|
Soong_config_variables: boolSoongConfigVars{
|
||||||
Bool_var: &boolVarProps{
|
Bool_var: &varProps{
|
||||||
A: boolVarPositive.A,
|
A: boolVarPositive.A,
|
||||||
B: boolVarPositive.B,
|
B: boolVarPositive.B,
|
||||||
Conditions_default: conditionsDefault,
|
Conditions_default: conditionsDefault,
|
||||||
|
@ -373,6 +388,59 @@ func Test_PropertiesToApply_Bool(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_PropertiesToApply_List(t *testing.T) {
|
||||||
|
mt, _ := newModuleType(&ModuleTypeProperties{
|
||||||
|
Module_type: "foo",
|
||||||
|
Config_namespace: "bar",
|
||||||
|
List_variables: []string{"my_list_var"},
|
||||||
|
Properties: []string{"c"},
|
||||||
|
})
|
||||||
|
conditionsDefault := &listProperties{
|
||||||
|
C: []string{"default"},
|
||||||
|
}
|
||||||
|
actualProps := &struct {
|
||||||
|
Soong_config_variables listSoongConfigVars
|
||||||
|
}{
|
||||||
|
Soong_config_variables: listSoongConfigVars{
|
||||||
|
List_var: &listVarProps{
|
||||||
|
C: []string{"A=%s", "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_list_var": "hello there"}),
|
||||||
|
wantProps: []interface{}{&listProperties{
|
||||||
|
C: []string{"A=hello", "A=there", "B=hello", "B=there"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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_Value(t *testing.T) {
|
func Test_PropertiesToApply_Value(t *testing.T) {
|
||||||
mt, _ := newModuleType(&ModuleTypeProperties{
|
mt, _ := newModuleType(&ModuleTypeProperties{
|
||||||
Module_type: "foo",
|
Module_type: "foo",
|
||||||
|
@ -388,7 +456,7 @@ func Test_PropertiesToApply_Value(t *testing.T) {
|
||||||
Soong_config_variables valueSoongConfigVars
|
Soong_config_variables valueSoongConfigVars
|
||||||
}{
|
}{
|
||||||
Soong_config_variables: valueSoongConfigVars{
|
Soong_config_variables: valueSoongConfigVars{
|
||||||
My_value_var: &boolVarProps{
|
My_value_var: &varProps{
|
||||||
A: proptools.StringPtr("A=%s"),
|
A: proptools.StringPtr("A=%s"),
|
||||||
B: true,
|
B: true,
|
||||||
Conditions_default: conditionsDefault,
|
Conditions_default: conditionsDefault,
|
||||||
|
@ -524,7 +592,7 @@ func Test_PropertiesToApply_String_Error(t *testing.T) {
|
||||||
Soong_config_variables stringSoongConfigVars
|
Soong_config_variables stringSoongConfigVars
|
||||||
}{
|
}{
|
||||||
Soong_config_variables: stringSoongConfigVars{
|
Soong_config_variables: stringSoongConfigVars{
|
||||||
String_var: &boolVarProps{
|
String_var: &varProps{
|
||||||
A: stringVarPositive.A,
|
A: stringVarPositive.A,
|
||||||
B: stringVarPositive.B,
|
B: stringVarPositive.B,
|
||||||
Conditions_default: conditionsDefault,
|
Conditions_default: conditionsDefault,
|
||||||
|
|
Loading…
Reference in a new issue