Merge "Add SetProperties to json-module-graph" am: adf1b2a2cd

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1937639

Change-Id: Ibbb048f90c36f6b46210011adf886806147e00f3
This commit is contained in:
Liz Kammer 2022-01-12 13:42:27 +00:00 committed by Automerger Merge Worker
commit b6fdee8f0a
3 changed files with 267 additions and 11 deletions

View file

@ -19,6 +19,7 @@ import (
"os"
"path"
"path/filepath"
"reflect"
"regexp"
"strings"
"text/scanner"
@ -1326,7 +1327,64 @@ func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string {
}
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
(*d)["Android"] = map[string]interface{}{}
(*d)["Android"] = map[string]interface{}{
// Properties set in Blueprint or in blueprint of a defaults modules
"SetProperties": m.propertiesWithValues(),
}
}
type propInfo struct {
Name string
Type string
}
func (m *ModuleBase) propertiesWithValues() []propInfo {
var info []propInfo
props := m.GetProperties()
var propsWithValues func(name string, v reflect.Value)
propsWithValues = func(name string, v reflect.Value) {
kind := v.Kind()
switch kind {
case reflect.Ptr, reflect.Interface:
if v.IsNil() {
return
}
propsWithValues(name, v.Elem())
case reflect.Struct:
if v.IsZero() {
return
}
for i := 0; i < v.NumField(); i++ {
namePrefix := name
sTyp := v.Type().Field(i)
if proptools.ShouldSkipProperty(sTyp) {
continue
}
if name != "" && !strings.HasSuffix(namePrefix, ".") {
namePrefix += "."
}
if !proptools.IsEmbedded(sTyp) {
namePrefix += sTyp.Name
}
sVal := v.Field(i)
propsWithValues(namePrefix, sVal)
}
case reflect.Array, reflect.Slice:
if v.IsNil() {
return
}
elKind := v.Type().Elem().Kind()
info = append(info, propInfo{name, elKind.String() + " " + kind.String()})
default:
info = append(info, propInfo{name, kind.String()})
}
}
for _, p := range props {
propsWithValues("", reflect.ValueOf(p).Elem())
}
return info
}
func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {}

View file

@ -615,3 +615,204 @@ func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []installM
return rules
}
type PropsTestModuleEmbedded struct {
Embedded_prop *string
}
type propsTestModule struct {
ModuleBase
DefaultableModuleBase
props struct {
A string `android:"arch_variant"`
B *bool
C []string
}
otherProps struct {
PropsTestModuleEmbedded
D *int64
Nested struct {
E *string
}
F *string `blueprint:"mutated"`
}
}
func propsTestModuleFactory() Module {
module := &propsTestModule{}
module.AddProperties(&module.props, &module.otherProps)
InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth)
InitDefaultableModule(module)
return module
}
type propsTestModuleDefaults struct {
ModuleBase
DefaultsModuleBase
}
func propsTestModuleDefaultsFactory() Module {
defaults := &propsTestModuleDefaults{}
module := propsTestModule{}
defaults.AddProperties(&module.props, &module.otherProps)
InitDefaultsModule(defaults)
return defaults
}
func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
str := "abc"
p.otherProps.F = &str
}
func TestUsedProperties(t *testing.T) {
testCases := []struct {
desc string
bp string
expectedProps []propInfo
}{
{
desc: "only name",
bp: `test {
name: "foo",
}
`,
expectedProps: []propInfo{
propInfo{"Name", "string"},
},
},
{
desc: "some props",
bp: `test {
name: "foo",
a: "abc",
b: true,
d: 123,
}
`,
expectedProps: []propInfo{
propInfo{"A", "string"},
propInfo{"B", "bool"},
propInfo{"D", "int64"},
propInfo{"Name", "string"},
},
},
{
desc: "unused non-pointer prop",
bp: `test {
name: "foo",
b: true,
d: 123,
}
`,
expectedProps: []propInfo{
// for non-pointer cannot distinguish between unused and intentionally set to empty
propInfo{"A", "string"},
propInfo{"B", "bool"},
propInfo{"D", "int64"},
propInfo{"Name", "string"},
},
},
{
desc: "nested props",
bp: `test {
name: "foo",
nested: {
e: "abc",
}
}
`,
expectedProps: []propInfo{
propInfo{"Nested.E", "string"},
propInfo{"Name", "string"},
},
},
{
desc: "arch props",
bp: `test {
name: "foo",
arch: {
x86_64: {
a: "abc",
},
}
}
`,
expectedProps: []propInfo{
propInfo{"Name", "string"},
propInfo{"Arch.X86_64.A", "string"},
},
},
{
desc: "embedded props",
bp: `test {
name: "foo",
embedded_prop: "a",
}
`,
expectedProps: []propInfo{
propInfo{"Embedded_prop", "string"},
propInfo{"Name", "string"},
},
},
{
desc: "defaults",
bp: `
test_defaults {
name: "foo_defaults",
a: "a",
b: true,
embedded_prop:"a",
arch: {
x86_64: {
a: "a",
},
},
}
test {
name: "foo",
defaults: ["foo_defaults"],
c: ["a"],
nested: {
e: "d",
},
target: {
linux: {
a: "a",
},
},
}
`,
expectedProps: []propInfo{
propInfo{"A", "string"},
propInfo{"B", "bool"},
propInfo{"C", "string slice"},
propInfo{"Embedded_prop", "string"},
propInfo{"Nested.E", "string"},
propInfo{"Name", "string"},
propInfo{"Arch.X86_64.A", "string"},
propInfo{"Target.Linux.A", "string"},
propInfo{"Defaults", "string slice"},
},
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
result := GroupFixturePreparers(
PrepareForTestWithAllowMissingDependencies,
PrepareForTestWithDefaults,
FixtureRegisterWithContext(func(ctx RegistrationContext) {
ctx.RegisterModuleType("test", propsTestModuleFactory)
ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory)
}),
FixtureWithRootAndroidBp(tc.bp),
).RunTest(t)
foo := result.ModuleForTests("foo", "").Module().base()
AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
})
}
}

View file

@ -244,17 +244,14 @@ func TestAddJSONData(t *testing.T) {
}
jsonData := map[string]interface{}{}
prebuiltStubsSources.AddJSONData(&jsonData)
if fmt.Sprint(jsonData) != fmt.Sprint(
expectedOut := []map[string]interface{}{
map[string]interface{}{
"Android": map[string]interface{}{},
"Actions": []map[string]interface{}{
map[string]interface{}{
"Inputs": []string{},
"Outputs": []string{},
},
},
}) {
t.Errorf("The JSON data map isn't as expected %s.", jsonData)
"Inputs": []string{},
"Outputs": []string{},
},
}
if !reflect.DeepEqual(jsonData["Actions"], expectedOut) {
t.Errorf("The JSON action data %#v isn't as expected %#v.", jsonData["Actions"], expectedOut)
}
}