Bp2build: handle embedded structs as blueprint
For structs that are embedded, Blueprint does not nest under the
embedded name, flattening them into the original struct for blueprint
files (e.g.
https://cs.android.com/android/_/android/platform/build/blueprint/+/9fd2ed93dfb82baf7688c1b2b29aa4b2cc125721:proptools/unpack_test.go;l=402-431;drc=3adb2409648d6f8b25354ac47f083dae87731f10).
We should do the same for bp2build.
This will also allow us to embed structs for bp2build conversion
allowing more reuse.
Test: go test bp2build tests
Change-Id: I9ce088462adaf59bffa80bea76cd488e31f98e9d
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index f652a35..94084af 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -575,6 +575,19 @@
// Ignore zero-valued fields
continue
}
+ // if the struct is embedded (anonymous), flatten the properties into the containing struct
+ if field.Anonymous {
+ if field.Type.Kind() == reflect.Ptr {
+ fieldValue = fieldValue.Elem()
+ }
+ if fieldValue.Type().Kind() == reflect.Struct {
+ propsToMerge := extractStructProperties(fieldValue, indent)
+ for prop, value := range propsToMerge {
+ ret[prop] = value
+ }
+ continue
+ }
+ }
propertyName := proptools.PropertyNameForField(field.Name)
prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index ecea6b2..c327112 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -322,6 +322,30 @@
)`,
},
},
+ {
+ blueprint: `custom {
+ name: "embedded_props",
+ embedded_prop: "abc",
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`custom(
+ name = "embedded_props",
+ embedded_attr = "abc",
+)`,
+ },
+ },
+ {
+ blueprint: `custom {
+ name: "ptr_to_embedded_props",
+ other_embedded_prop: "abc",
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`custom(
+ name = "ptr_to_embedded_props",
+ other_embedded_attr = "abc",
+)`,
+ },
+ },
}
dir := "."
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
index f2f6b01..992cc1c 100644
--- a/bp2build/bzl_conversion.go
+++ b/bp2build/bzl_conversion.go
@@ -160,8 +160,15 @@
if shouldSkipStructField(field) {
continue
}
-
- properties = append(properties, extractPropertyDescriptions(field.Name, field.Type)...)
+ subProps := extractPropertyDescriptions(field.Name, field.Type)
+ // if the struct is embedded (anonymous), flatten the properties into the containing struct
+ if field.Anonymous {
+ for _, prop := range subProps {
+ properties = append(properties, prop.properties...)
+ }
+ } else {
+ properties = append(properties, subProps...)
+ }
}
return properties
}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 9e0c0a1..1e78c0e 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -92,6 +92,7 @@
# bazel_module end
"bool_prop": attr.bool(),
"bool_ptr_prop": attr.bool(),
+ "embedded_prop": attr.string(),
"int64_ptr_prop": attr.int(),
# nested_props start
# "nested_prop": attr.string(),
@@ -99,6 +100,7 @@
# nested_props_ptr start
# "nested_prop": attr.string(),
# nested_props_ptr end
+ "other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
@@ -118,6 +120,7 @@
"arch_paths_exclude": attr.string_list(),
"bool_prop": attr.bool(),
"bool_ptr_prop": attr.bool(),
+ "embedded_prop": attr.string(),
"int64_ptr_prop": attr.int(),
# nested_props start
# "nested_prop": attr.string(),
@@ -125,6 +128,7 @@
# nested_props_ptr start
# "nested_prop": attr.string(),
# nested_props_ptr end
+ "other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
@@ -144,6 +148,7 @@
"arch_paths_exclude": attr.string_list(),
"bool_prop": attr.bool(),
"bool_ptr_prop": attr.bool(),
+ "embedded_prop": attr.string(),
"int64_ptr_prop": attr.int(),
# nested_props start
# "nested_prop": attr.string(),
@@ -151,6 +156,7 @@
# nested_props_ptr start
# "nested_prop": attr.string(),
# nested_props_ptr end
+ "other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 3ebe63d..b39d363 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -148,7 +148,18 @@
Nested_prop string
}
+type EmbeddedProps struct {
+ Embedded_prop string
+}
+
+type OtherEmbeddedProps struct {
+ Other_embedded_prop string
+}
+
type customProps struct {
+ EmbeddedProps
+ *OtherEmbeddedProps
+
Bool_prop bool
Bool_ptr_prop *bool
// Ensure that properties tagged `blueprint:mutated` are omitted
@@ -246,7 +257,17 @@
return m
}
+type EmbeddedAttr struct {
+ Embedded_attr string
+}
+
+type OtherEmbeddedAttr struct {
+ Other_embedded_attr string
+}
+
type customBazelModuleAttributes struct {
+ EmbeddedAttr
+ *OtherEmbeddedAttr
String_prop string
String_list_prop []string
Arch_paths bazel.LabelListAttribute
@@ -275,6 +296,10 @@
String_list_prop: m.props.String_list_prop,
Arch_paths: paths,
}
+ attrs.Embedded_attr = m.props.Embedded_prop
+ if m.props.OtherEmbeddedProps != nil {
+ attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
+ }
props := bazel.BazelTargetModuleProperties{
Rule_class: "custom",