blob: 987c9034357f8569a9a97ccc18f9ce21f12a4c36 [file] [log] [blame]
Jingwen Chen5d864492021-02-24 07:20:12 -05001package bp2build
2
Jingwen Chen91220d72021-03-24 02:18:33 -04003import (
Jingwen Chen91220d72021-03-24 02:18:33 -04004 "fmt"
5 "reflect"
Chris Parsons58852a02021-12-09 18:10:18 -05006
7 "android/soong/android"
8 "android/soong/bazel"
Liz Kammer72beb342022-02-03 08:42:10 -05009 "android/soong/starlark_fmt"
Jingwen Chen91220d72021-03-24 02:18:33 -040010)
Jingwen Chen5d864492021-02-24 07:20:12 -050011
12// Configurability support for bp2build.
13
Jingwen Chenc1c26502021-04-05 10:35:13 +000014type selects map[string]reflect.Value
15
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +000016func getStringValue(str bazel.StringAttribute) (reflect.Value, []selects) {
17 value := reflect.ValueOf(str.Value)
18
19 if !str.HasConfigurableValues() {
20 return value, []selects{}
21 }
22
23 ret := selects{}
24 for _, axis := range str.SortedConfigurationAxes() {
25 configToStrs := str.ConfigurableValues[axis]
26 for config, strs := range configToStrs {
27 selectKey := axis.SelectKey(config)
28 ret[selectKey] = reflect.ValueOf(strs)
29 }
30 }
31 // if there is a select, use the base value as the conditions default value
32 if len(ret) > 0 {
33 ret[bazel.ConditionsDefaultSelectKey] = value
34 value = reflect.Zero(value.Type())
35 }
36
37 return value, []selects{ret}
38}
39
Zi Wang1cb11802022-12-09 16:08:54 -080040func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects, bool) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000041 value := reflect.ValueOf(list.Value)
Zi Wang0f828442022-12-28 11:18:11 -080042 prepend := list.Prepend
Jingwen Chenc1c26502021-04-05 10:35:13 +000043 if !list.HasConfigurableValues() {
Zi Wang1cb11802022-12-09 16:08:54 -080044 return value, []selects{}, prepend
Jingwen Chen5d864492021-02-24 07:20:12 -050045 }
Jingwen Chen91220d72021-03-24 02:18:33 -040046
Liz Kammer9abd62d2021-05-21 08:37:59 -040047 var ret []selects
48 for _, axis := range list.SortedConfigurationAxes() {
49 configToLists := list.ConfigurableValues[axis]
50 archSelects := map[string]reflect.Value{}
51 for config, labels := range configToLists {
52 selectKey := axis.SelectKey(config)
53 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040054 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040055 if len(archSelects) > 0 {
56 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040057 }
58 }
59
Zi Wang1cb11802022-12-09 16:08:54 -080060 return value, ret, prepend
Jingwen Chenc1c26502021-04-05 10:35:13 +000061}
62
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040063func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040064 value := reflect.ValueOf(label.Value)
65 if !label.HasConfigurableValues() {
66 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020067 }
68
Liz Kammer9abd62d2021-05-21 08:37:59 -040069 ret := selects{}
70 for _, axis := range label.SortedConfigurationAxes() {
71 configToLabels := label.ConfigurableValues[axis]
72 for config, labels := range configToLabels {
73 selectKey := axis.SelectKey(config)
74 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040075 }
76 }
77
Liz Kammerdff00ea2021-10-04 13:44:34 -040078 // if there is a select, use the base value as the conditions default value
79 if len(ret) > 0 {
80 ret[bazel.ConditionsDefaultSelectKey] = value
81 value = reflect.Zero(value.Type())
82 }
83
Liz Kammer9abd62d2021-05-21 08:37:59 -040084 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020085}
86
Liz Kammerd366c902021-06-03 13:43:01 -040087func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
88 value := reflect.ValueOf(boolAttr.Value)
89 if !boolAttr.HasConfigurableValues() {
90 return value, []selects{}
91 }
92
93 ret := selects{}
94 for _, axis := range boolAttr.SortedConfigurationAxes() {
95 configToBools := boolAttr.ConfigurableValues[axis]
96 for config, bools := range configToBools {
97 selectKey := axis.SelectKey(config)
98 ret[selectKey] = reflect.ValueOf(bools)
99 }
100 }
101 // if there is a select, use the base value as the conditions default value
102 if len(ret) > 0 {
103 ret[bazel.ConditionsDefaultSelectKey] = value
104 value = reflect.Zero(value.Type())
105 }
106
107 return value, []selects{ret}
108}
Zi Wang9f609db2023-01-04 11:06:54 -0800109func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects, bool) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000110 value := reflect.ValueOf(list.Value.Includes)
Zi Wang9f609db2023-01-04 11:06:54 -0800111 prepend := list.Prepend
Liz Kammer2b07ec72021-05-26 15:08:27 -0400112 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -0400113 for _, axis := range list.SortedConfigurationAxes() {
114 configToLabels := list.ConfigurableValues[axis]
115 if !configToLabels.HasConfigurableValues() {
116 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -0400117 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400118 archSelects := map[string]reflect.Value{}
Chris Parsons51f8c392021-08-03 21:01:05 -0400119 defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500120 // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
121 emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
Liz Kammer9abd62d2021-05-21 08:37:59 -0400122 for config, labels := range configToLabels {
Chris Parsons51f8c392021-08-03 21:01:05 -0400123 // Omit any entries in the map which match the default value, for brevity.
124 if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
125 continue
126 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400127 selectKey := axis.SelectKey(config)
Chris Parsons58852a02021-12-09 18:10:18 -0500128 if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400129 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -0400130 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400131 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400132 if len(archSelects) > 0 {
133 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400134 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000135 }
136
Zi Wang9f609db2023-01-04 11:06:54 -0800137 return value, ret, prepend
Liz Kammer2b07ec72021-05-26 15:08:27 -0400138}
139
Jingwen Chen58ff6802021-11-17 12:14:41 +0000140func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
141 if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
Liz Kammer2b07ec72021-05-26 15:08:27 -0400142 return true, reflect.ValueOf(list.Includes)
143 } else if len(list.Excludes) > 0 {
144 // if there is still an excludes -- we need to have an empty list for this select & use the
145 // value in conditions default Includes
146 return true, reflect.ValueOf([]string{})
147 }
148 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000149}
150
Liz Kammerd366c902021-06-03 13:43:01 -0400151var (
152 emptyBazelList = "[]"
153 bazelNone = "None"
154)
155
Jingwen Chenc1c26502021-04-05 10:35:13 +0000156// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
157// select statements.
158func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
159 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400160 var configurableAttrs []selects
Zi Wang1cb11802022-12-09 16:08:54 -0800161 var prepend bool
Liz Kammerd366c902021-06-03 13:43:01 -0400162 var defaultSelectValue *string
Jingwen Chen58ff6802021-11-17 12:14:41 +0000163 var emitZeroValues bool
Chris Parsons51f8c392021-08-03 21:01:05 -0400164 // If true, print the default attribute value, even if the attribute is zero.
165 shouldPrintDefault := false
Jingwen Chenc1c26502021-04-05 10:35:13 +0000166 switch list := v.(type) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000167 case bazel.StringAttribute:
168 if err := list.Collapse(); err != nil {
169 return "", err
170 }
171 value, configurableAttrs = getStringValue(list)
172 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000173 case bazel.StringListAttribute:
Zi Wang1cb11802022-12-09 16:08:54 -0800174 value, configurableAttrs, prepend = getStringListValues(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400175 defaultSelectValue = &emptyBazelList
Jingwen Chenc1c26502021-04-05 10:35:13 +0000176 case bazel.LabelListAttribute:
Zi Wang9f609db2023-01-04 11:06:54 -0800177 value, configurableAttrs, prepend = getLabelListValues(list)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000178 emitZeroValues = list.EmitEmptyList
Liz Kammerd366c902021-06-03 13:43:01 -0400179 defaultSelectValue = &emptyBazelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400180 if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
181 shouldPrintDefault = true
182 }
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200183 case bazel.LabelAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500184 if err := list.Collapse(); err != nil {
185 return "", err
186 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400187 value, configurableAttrs = getLabelValue(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400188 defaultSelectValue = &bazelNone
189 case bazel.BoolAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500190 if err := list.Collapse(); err != nil {
191 return "", err
192 }
Liz Kammerd366c902021-06-03 13:43:01 -0400193 value, configurableAttrs = getBoolValue(list)
194 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000195 default:
196 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
197 }
198
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400199 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200200 ret := ""
201 if value.Kind() != reflect.Invalid {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000202 s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200203 if err != nil {
204 return ret, err
205 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000206
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200207 ret += s
208 }
Zi Wang1cb11802022-12-09 16:08:54 -0800209 // Convenience function to prepend/append selects components to an attribute value.
210 concatenateSelects := func(selectsData selects, defaultValue *string, s string, prepend bool) (string, error) {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000211 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400212 if err != nil {
213 return "", err
214 }
Zi Wang1cb11802022-12-09 16:08:54 -0800215 var left, right string
216 if prepend {
217 left, right = selectMap, s
218 } else {
219 left, right = s, selectMap
Jingwen Chen63930982021-03-24 10:04:33 -0400220 }
Zi Wang1cb11802022-12-09 16:08:54 -0800221 if left != "" && right != "" {
222 left += " + "
223 }
224 left += right
Jingwen Chen63930982021-03-24 10:04:33 -0400225
Zi Wang1cb11802022-12-09 16:08:54 -0800226 return left, nil
Jingwen Chen63930982021-03-24 10:04:33 -0400227 }
228
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400229 for _, configurableAttr := range configurableAttrs {
Zi Wang1cb11802022-12-09 16:08:54 -0800230 ret, err = concatenateSelects(configurableAttr, defaultSelectValue, ret, prepend)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400231 if err != nil {
232 return "", err
233 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400234 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400235
Chris Parsons51f8c392021-08-03 21:01:05 -0400236 if ret == "" && shouldPrintDefault {
237 return *defaultSelectValue, nil
238 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400239 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400240}
241
242// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
243// to construct a select map for any kind of attribute type.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000244func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000245 if selectMap == nil {
246 return "", nil
247 }
248
Jingwen Chen91220d72021-03-24 02:18:33 -0400249 var selects string
250 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400251 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000252 // Handle default condition later.
253 continue
254 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400255 value := selectMap[selectKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500256 if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
257 // Ignore zero values to not generate empty lists. However, always note zero values if
258 // the default value is non-zero.
Jingwen Chen91220d72021-03-24 02:18:33 -0400259 continue
260 }
Chris Parsons58852a02021-12-09 18:10:18 -0500261 s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
Jingwen Chen91220d72021-03-24 02:18:33 -0400262 if err != nil {
263 return "", err
264 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000265 // s could still be an empty string, e.g. unset slices of structs with
266 // length of 0.
267 if s != "" {
268 selects += s + ",\n"
269 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400270 }
271
272 if len(selects) == 0 {
273 // No conditions (or all values are empty lists), so no need for a map.
274 return "", nil
275 }
276
277 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400278 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400279 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000280
281 // Handle the default condition
Jingwen Chen58ff6802021-11-17 12:14:41 +0000282 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000283 if err != nil {
284 return "", err
285 }
Liz Kammerd366c902021-06-03 13:43:01 -0400286 if s != "" {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000287 // Print the custom default value.
288 ret += s
289 ret += ",\n"
Liz Kammerd366c902021-06-03 13:43:01 -0400290 } else if defaultValue != nil {
291 // Print an explicit empty list (the default value) even if the value is
292 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer72beb342022-02-03 08:42:10 -0500293 ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000294 }
295
Liz Kammer72beb342022-02-03 08:42:10 -0500296 ret += starlark_fmt.Indention(indent)
Jingwen Chen91220d72021-03-24 02:18:33 -0400297 ret += "})"
298
299 return ret, nil
300}
301
302// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
303// with a provided key.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000304func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
Liz Kammer72beb342022-02-03 08:42:10 -0500305 s := starlark_fmt.Indention(indent + 1)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000306 v, err := prettyPrint(value, indent+1, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400307 if err != nil {
308 return "", err
309 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000310 if v == "" {
311 return "", nil
312 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400313 s += fmt.Sprintf("\"%s\": %s", key, v)
314 return s, nil
315}