blob: b9ffc0450a659d534ebc695b47704a5a47a7de03 [file] [log] [blame]
Jingwen Chen5d864492021-02-24 07:20:12 -05001package bp2build
2
Jingwen Chen91220d72021-03-24 02:18:33 -04003import (
4 "android/soong/android"
5 "android/soong/bazel"
6 "fmt"
7 "reflect"
8)
Jingwen Chen5d864492021-02-24 07:20:12 -05009
10// Configurability support for bp2build.
11
Jingwen Chenc1c26502021-04-05 10:35:13 +000012type selects map[string]reflect.Value
13
14func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
15 value := reflect.ValueOf(list.Value)
16 if !list.HasConfigurableValues() {
17 return value, nil, nil
Jingwen Chen5d864492021-02-24 07:20:12 -050018 }
Jingwen Chen91220d72021-03-24 02:18:33 -040019
Jingwen Chen91220d72021-03-24 02:18:33 -040020 archSelects := map[string]reflect.Value{}
21 for arch, selectKey := range bazel.PlatformArchMap {
Jingwen Chenc1c26502021-04-05 10:35:13 +000022 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
Jingwen Chen91220d72021-03-24 02:18:33 -040023 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000024
25 osSelects := map[string]reflect.Value{}
26 for os, selectKey := range bazel.PlatformOsMap {
27 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
28 }
29
30 return value, archSelects, osSelects
31}
32
33func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
34 value := reflect.ValueOf(list.Value.Includes)
35 if !list.HasConfigurableValues() {
36 return value, nil, nil
37 }
38
39 archSelects := map[string]reflect.Value{}
40 for arch, selectKey := range bazel.PlatformArchMap {
41 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
42 }
43
44 osSelects := map[string]reflect.Value{}
45 for os, selectKey := range bazel.PlatformOsMap {
46 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
47 }
48
49 return value, archSelects, osSelects
50}
51
52// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
53// select statements.
54func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
55 var value reflect.Value
56 var archSelects, osSelects selects
57
58 switch list := v.(type) {
59 case bazel.StringListAttribute:
60 value, archSelects, osSelects = getStringListValues(list)
61 case bazel.LabelListAttribute:
62 value, archSelects, osSelects = getLabelListValues(list)
63 default:
64 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
65 }
66
67 ret, err := prettyPrint(value, indent)
68 if err != nil {
69 return ret, err
70 }
71
Jingwen Chen63930982021-03-24 10:04:33 -040072 // Convenience function to append selects components to an attribute value.
73 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
74 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
75 if err != nil {
76 return "", err
77 }
78 if s != "" && selectMap != "" {
79 s += " + "
80 }
81 s += selectMap
82
83 return s, nil
84 }
85
86 ret, err = appendSelects(archSelects, "[]", ret)
Jingwen Chen91220d72021-03-24 02:18:33 -040087 if err != nil {
88 return "", err
89 }
Jingwen Chen91220d72021-03-24 02:18:33 -040090
Jingwen Chen63930982021-03-24 10:04:33 -040091 ret, err = appendSelects(osSelects, "[]", ret)
Jingwen Chenc1c26502021-04-05 10:35:13 +000092 return ret, err
Jingwen Chen91220d72021-03-24 02:18:33 -040093}
94
95// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
96// to construct a select map for any kind of attribute type.
97func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000098 if selectMap == nil {
99 return "", nil
100 }
101
Jingwen Chen91220d72021-03-24 02:18:33 -0400102 var selects string
103 for _, selectKey := range android.SortedStringKeys(selectMap) {
104 value := selectMap[selectKey]
105 if isZero(value) {
106 // Ignore zero values to not generate empty lists.
107 continue
108 }
109 s, err := prettyPrintSelectEntry(value, selectKey, indent)
110 if err != nil {
111 return "", err
112 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000113 // s could still be an empty string, e.g. unset slices of structs with
114 // length of 0.
115 if s != "" {
116 selects += s + ",\n"
117 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400118 }
119
120 if len(selects) == 0 {
121 // No conditions (or all values are empty lists), so no need for a map.
122 return "", nil
123 }
124
125 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400126 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400127 ret += selects
128 // default condition comes last.
129 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
130 ret += makeIndent(indent)
131 ret += "})"
132
133 return ret, nil
134}
135
136// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
137// with a provided key.
138func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
139 s := makeIndent(indent + 1)
140 v, err := prettyPrint(value, indent+1)
141 if err != nil {
142 return "", err
143 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000144 if v == "" {
145 return "", nil
146 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400147 s += fmt.Sprintf("\"%s\": %s", key, v)
148 return s, nil
149}