refactoring build_conversion.go to remove panic

Returning errors throughout instead of calling panic()
Errors will be more useful for testing

Test: bp2build tests
Change-Id: I3b03f0a30e7a80878e91c7f0e2df5a94d9d6b780
This commit is contained in:
Alix
2022-08-16 20:37:33 +00:00
parent 5aa5dc4121
commit 94e2603ab7
2 changed files with 64 additions and 32 deletions

View File

@@ -289,7 +289,9 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
return return
} }
} }
targets = generateBazelTargets(bpCtx, aModule) var targetErrs []error
targets, targetErrs = generateBazelTargets(bpCtx, aModule)
errs = append(errs, targetErrs...)
for _, t := range targets { for _, t := range targets {
// A module can potentially generate more than 1 Bazel // A module can potentially generate more than 1 Bazel
// target, each of a different rule class. // target, each of a different rule class.
@@ -306,7 +308,10 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
// be mapped cleanly to a bazel label. // be mapped cleanly to a bazel label.
return return
} }
t := generateSoongModuleTarget(bpCtx, m) t, err := generateSoongModuleTarget(bpCtx, m)
if err != nil {
errs = append(errs, err)
}
targets = append(targets, t) targets = append(targets, t)
default: default:
errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode())) errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
@@ -347,12 +352,18 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
}, errs }, errs
} }
func generateBazelTargets(ctx bpToBuildContext, m android.Module) []BazelTarget { func generateBazelTargets(ctx bpToBuildContext, m android.Module) ([]BazelTarget, []error) {
var targets []BazelTarget var targets []BazelTarget
var errs []error
for _, m := range m.Bp2buildTargets() { for _, m := range m.Bp2buildTargets() {
targets = append(targets, generateBazelTarget(ctx, m)) target, err := generateBazelTarget(ctx, m)
if err != nil {
errs = append(errs, err)
return targets, errs
} }
return targets targets = append(targets, target)
}
return targets, errs
} }
type bp2buildModule interface { type bp2buildModule interface {
@@ -363,13 +374,16 @@ type bp2buildModule interface {
BazelAttributes() []interface{} BazelAttributes() []interface{}
} }
func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) BazelTarget { func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) (BazelTarget, error) {
ruleClass := m.BazelRuleClass() ruleClass := m.BazelRuleClass()
bzlLoadLocation := m.BazelRuleLoadLocation() bzlLoadLocation := m.BazelRuleLoadLocation()
// extract the bazel attributes from the module. // extract the bazel attributes from the module.
attrs := m.BazelAttributes() attrs := m.BazelAttributes()
props := extractModuleProperties(attrs, true) props, err := extractModuleProperties(attrs, true)
if err != nil {
return BazelTarget{}, err
}
// name is handled in a special manner // name is handled in a special manner
delete(props.Attrs, "name") delete(props.Attrs, "name")
@@ -389,13 +403,13 @@ func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) BazelTarget {
targetName, targetName,
attributes, attributes,
), ),
} }, nil
} }
// Convert a module and its deps and props into a Bazel macro/rule // Convert a module and its deps and props into a Bazel macro/rule
// representation in the BUILD file. // representation in the BUILD file.
func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget { func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) (BazelTarget, error) {
props := getBuildProperties(ctx, m) props, err := getBuildProperties(ctx, m)
// TODO(b/163018919): DirectDeps can have duplicate (module, variant) // TODO(b/163018919): DirectDeps can have duplicate (module, variant)
// items, if the modules are added using different DependencyTag. Figure // items, if the modules are added using different DependencyTag. Figure
@@ -429,21 +443,21 @@ func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) BazelTa
ctx.ModuleSubDir(m), ctx.ModuleSubDir(m),
depLabelList, depLabelList,
attributes), attributes),
} }, err
} }
func getBuildProperties(ctx bpToBuildContext, m blueprint.Module) BazelAttributes { func getBuildProperties(ctx bpToBuildContext, m blueprint.Module) (BazelAttributes, error) {
// TODO: this omits properties for blueprint modules (blueprint_go_binary, // TODO: this omits properties for blueprint modules (blueprint_go_binary,
// bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately. // bootstrap_go_binary, bootstrap_go_package), which will have to be handled separately.
if aModule, ok := m.(android.Module); ok { if aModule, ok := m.(android.Module); ok {
return extractModuleProperties(aModule.GetProperties(), false) return extractModuleProperties(aModule.GetProperties(), false)
} }
return BazelAttributes{} return BazelAttributes{}, nil
} }
// Generically extract module properties and types into a map, keyed by the module property name. // Generically extract module properties and types into a map, keyed by the module property name.
func extractModuleProperties(props []interface{}, checkForDuplicateProperties bool) BazelAttributes { func extractModuleProperties(props []interface{}, checkForDuplicateProperties bool) (BazelAttributes, error) {
ret := map[string]string{} ret := map[string]string{}
// Iterate over this android.Module's property structs. // Iterate over this android.Module's property structs.
@@ -456,24 +470,29 @@ func extractModuleProperties(props []interface{}, checkForDuplicateProperties bo
// manipulate internal props, if needed. // manipulate internal props, if needed.
if isStructPtr(propertiesValue.Type()) { if isStructPtr(propertiesValue.Type()) {
structValue := propertiesValue.Elem() structValue := propertiesValue.Elem()
for k, v := range extractStructProperties(structValue, 0) { ok, err := extractStructProperties(structValue, 0)
if err != nil {
return BazelAttributes{}, err
}
for k, v := range ok {
if existing, exists := ret[k]; checkForDuplicateProperties && exists { if existing, exists := ret[k]; checkForDuplicateProperties && exists {
panic(fmt.Errorf( return BazelAttributes{}, fmt.Errorf(
"%s (%v) is present in properties whereas it should be consolidated into a commonAttributes", "%s (%v) is present in properties whereas it should be consolidated into a commonAttributes",
k, existing)) k, existing)
} }
ret[k] = v ret[k] = v
} }
} else { } else {
panic(fmt.Errorf( return BazelAttributes{},
fmt.Errorf(
"properties must be a pointer to a struct, got %T", "properties must be a pointer to a struct, got %T",
propertiesValue.Interface())) propertiesValue.Interface())
} }
} }
return BazelAttributes{ return BazelAttributes{
Attrs: ret, Attrs: ret,
} }, nil
} }
func isStructPtr(t reflect.Type) bool { func isStructPtr(t reflect.Type) bool {
@@ -531,7 +550,12 @@ func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) (
} }
// Sort and print the struct props by the key. // Sort and print the struct props by the key.
structProps := extractStructProperties(propertyValue, indent) structProps, err := extractStructProperties(propertyValue, indent)
if err != nil {
return "", err
}
if len(structProps) == 0 { if len(structProps) == 0 {
return "", nil return "", nil
} }
@@ -550,11 +574,13 @@ func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) (
// which each property value correctly pretty-printed and indented at the right nest level, // which each property value correctly pretty-printed and indented at the right nest level,
// since property structs can be nested. In Starlark, nested structs are represented as nested // since property structs can be nested. In Starlark, nested structs are represented as nested
// dicts: https://docs.bazel.build/skylark/lib/dict.html // dicts: https://docs.bazel.build/skylark/lib/dict.html
func extractStructProperties(structValue reflect.Value, indent int) map[string]string { func extractStructProperties(structValue reflect.Value, indent int) (map[string]string, error) {
if structValue.Kind() != reflect.Struct { if structValue.Kind() != reflect.Struct {
panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())) return map[string]string{}, fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())
} }
var err error
ret := map[string]string{} ret := map[string]string{}
structType := structValue.Type() structType := structValue.Type()
for i := 0; i < structValue.NumField(); i++ { for i := 0; i < structValue.NumField(); i++ {
@@ -575,7 +601,10 @@ func extractStructProperties(structValue reflect.Value, indent int) map[string]s
fieldValue = fieldValue.Elem() fieldValue = fieldValue.Elem()
} }
if fieldValue.Type().Kind() == reflect.Struct { if fieldValue.Type().Kind() == reflect.Struct {
propsToMerge := extractStructProperties(fieldValue, indent) propsToMerge, err := extractStructProperties(fieldValue, indent)
if err != nil {
return map[string]string{}, err
}
for prop, value := range propsToMerge { for prop, value := range propsToMerge {
ret[prop] = value ret[prop] = value
} }
@@ -584,20 +613,20 @@ func extractStructProperties(structValue reflect.Value, indent int) map[string]s
} }
propertyName := proptools.PropertyNameForField(field.Name) propertyName := proptools.PropertyNameForField(field.Name)
prettyPrintedValue, err := prettyPrint(fieldValue, indent+1, false) var prettyPrintedValue string
prettyPrintedValue, err = prettyPrint(fieldValue, indent+1, false)
if err != nil { if err != nil {
panic( return map[string]string{}, fmt.Errorf(
fmt.Errorf(
"Error while parsing property: %q. %s", "Error while parsing property: %q. %s",
propertyName, propertyName,
err)) err)
} }
if prettyPrintedValue != "" { if prettyPrintedValue != "" {
ret[propertyName] = prettyPrintedValue ret[propertyName] = prettyPrintedValue
} }
} }
return ret return ret, nil
} }
func isZero(value reflect.Value) bool { func isZero(value reflect.Value) bool {

View File

@@ -384,6 +384,9 @@ func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule)
func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) { func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
// TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
res, err := GenerateBazelTargets(codegenCtx, false) res, err := GenerateBazelTargets(codegenCtx, false)
if err != nil {
return BazelTargets{}, err
}
return res.buildFileToTargets[dir], err return res.buildFileToTargets[dir], err
} }