d366c909ca
Test: ci/bp2build.sh Bug: 187928307 Change-Id: Ib80c4318169652b322e5d878c8784679e42f87dd
244 lines
6.6 KiB
Go
244 lines
6.6 KiB
Go
package bp2build
|
|
|
|
import (
|
|
"android/soong/android"
|
|
"android/soong/bazel"
|
|
"fmt"
|
|
"reflect"
|
|
)
|
|
|
|
// Configurability support for bp2build.
|
|
|
|
type selects map[string]reflect.Value
|
|
|
|
func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
|
|
value := reflect.ValueOf(list.Value)
|
|
if !list.HasConfigurableValues() {
|
|
return value, []selects{}
|
|
}
|
|
|
|
var ret []selects
|
|
for _, axis := range list.SortedConfigurationAxes() {
|
|
configToLists := list.ConfigurableValues[axis]
|
|
archSelects := map[string]reflect.Value{}
|
|
for config, labels := range configToLists {
|
|
selectKey := axis.SelectKey(config)
|
|
archSelects[selectKey] = reflect.ValueOf(labels)
|
|
}
|
|
if len(archSelects) > 0 {
|
|
ret = append(ret, archSelects)
|
|
}
|
|
}
|
|
|
|
return value, ret
|
|
}
|
|
|
|
func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
|
|
value := reflect.ValueOf(label.Value)
|
|
if !label.HasConfigurableValues() {
|
|
return value, []selects{}
|
|
}
|
|
|
|
ret := selects{}
|
|
for _, axis := range label.SortedConfigurationAxes() {
|
|
configToLabels := label.ConfigurableValues[axis]
|
|
for config, labels := range configToLabels {
|
|
selectKey := axis.SelectKey(config)
|
|
ret[selectKey] = reflect.ValueOf(labels)
|
|
}
|
|
}
|
|
|
|
return value, []selects{ret}
|
|
}
|
|
|
|
func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
|
|
value := reflect.ValueOf(boolAttr.Value)
|
|
if !boolAttr.HasConfigurableValues() {
|
|
return value, []selects{}
|
|
}
|
|
|
|
ret := selects{}
|
|
for _, axis := range boolAttr.SortedConfigurationAxes() {
|
|
configToBools := boolAttr.ConfigurableValues[axis]
|
|
for config, bools := range configToBools {
|
|
selectKey := axis.SelectKey(config)
|
|
ret[selectKey] = reflect.ValueOf(bools)
|
|
}
|
|
}
|
|
// if there is a select, use the base value as the conditions default value
|
|
if len(ret) > 0 {
|
|
ret[bazel.ConditionsDefaultSelectKey] = value
|
|
value = reflect.Zero(value.Type())
|
|
}
|
|
|
|
return value, []selects{ret}
|
|
}
|
|
func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
|
|
value := reflect.ValueOf(list.Value.Includes)
|
|
var ret []selects
|
|
for _, axis := range list.SortedConfigurationAxes() {
|
|
configToLabels := list.ConfigurableValues[axis]
|
|
if !configToLabels.HasConfigurableValues() {
|
|
continue
|
|
}
|
|
archSelects := map[string]reflect.Value{}
|
|
for config, labels := range configToLabels {
|
|
selectKey := axis.SelectKey(config)
|
|
if use, value := labelListSelectValue(selectKey, labels); use {
|
|
archSelects[selectKey] = value
|
|
}
|
|
}
|
|
if len(archSelects) > 0 {
|
|
ret = append(ret, archSelects)
|
|
}
|
|
}
|
|
|
|
return value, ret
|
|
}
|
|
|
|
func labelListSelectValue(selectKey string, list bazel.LabelList) (bool, reflect.Value) {
|
|
if selectKey == bazel.ConditionsDefaultSelectKey || len(list.Includes) > 0 {
|
|
return true, reflect.ValueOf(list.Includes)
|
|
} else if len(list.Excludes) > 0 {
|
|
// if there is still an excludes -- we need to have an empty list for this select & use the
|
|
// value in conditions default Includes
|
|
return true, reflect.ValueOf([]string{})
|
|
}
|
|
return false, reflect.Zero(reflect.TypeOf([]string{}))
|
|
}
|
|
|
|
var (
|
|
emptyBazelList = "[]"
|
|
bazelNone = "None"
|
|
)
|
|
|
|
// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
|
|
// select statements.
|
|
func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
|
|
var value reflect.Value
|
|
var configurableAttrs []selects
|
|
var defaultSelectValue *string
|
|
switch list := v.(type) {
|
|
case bazel.StringListAttribute:
|
|
value, configurableAttrs = getStringListValues(list)
|
|
defaultSelectValue = &emptyBazelList
|
|
case bazel.LabelListAttribute:
|
|
value, configurableAttrs = getLabelListValues(list)
|
|
defaultSelectValue = &emptyBazelList
|
|
case bazel.LabelAttribute:
|
|
value, configurableAttrs = getLabelValue(list)
|
|
defaultSelectValue = &bazelNone
|
|
case bazel.BoolAttribute:
|
|
value, configurableAttrs = getBoolValue(list)
|
|
defaultSelectValue = &bazelNone
|
|
default:
|
|
return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
|
|
}
|
|
|
|
var err error
|
|
ret := ""
|
|
if value.Kind() != reflect.Invalid {
|
|
s, err := prettyPrint(value, indent)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
ret += s
|
|
}
|
|
// Convenience function to append selects components to an attribute value.
|
|
appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
|
|
selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if s != "" && selectMap != "" {
|
|
s += " + "
|
|
}
|
|
s += selectMap
|
|
|
|
return s, nil
|
|
}
|
|
|
|
for _, configurableAttr := range configurableAttrs {
|
|
ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
|
|
// to construct a select map for any kind of attribute type.
|
|
func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int) (string, error) {
|
|
if selectMap == nil {
|
|
return "", nil
|
|
}
|
|
|
|
var selects string
|
|
for _, selectKey := range android.SortedStringKeys(selectMap) {
|
|
if selectKey == bazel.ConditionsDefaultSelectKey {
|
|
// Handle default condition later.
|
|
continue
|
|
}
|
|
value := selectMap[selectKey]
|
|
if isZero(value) {
|
|
// Ignore zero values to not generate empty lists.
|
|
continue
|
|
}
|
|
s, err := prettyPrintSelectEntry(value, selectKey, indent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// s could still be an empty string, e.g. unset slices of structs with
|
|
// length of 0.
|
|
if s != "" {
|
|
selects += s + ",\n"
|
|
}
|
|
}
|
|
|
|
if len(selects) == 0 {
|
|
// No conditions (or all values are empty lists), so no need for a map.
|
|
return "", nil
|
|
}
|
|
|
|
// Create the map.
|
|
ret := "select({\n"
|
|
ret += selects
|
|
|
|
// Handle the default condition
|
|
s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if s != "" {
|
|
// Print the custom default value.
|
|
ret += s
|
|
ret += ",\n"
|
|
} else if defaultValue != nil {
|
|
// Print an explicit empty list (the default value) even if the value is
|
|
// empty, to avoid errors about not finding a configuration that matches.
|
|
ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
|
|
}
|
|
|
|
ret += makeIndent(indent)
|
|
ret += "})"
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
|
|
// with a provided key.
|
|
func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
|
|
s := makeIndent(indent + 1)
|
|
v, err := prettyPrint(value, indent+1)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if v == "" {
|
|
return "", nil
|
|
}
|
|
s += fmt.Sprintf("\"%s\": %s", key, v)
|
|
return s, nil
|
|
}
|