blob: 9398d127cec58a2272f8d4042fb0b44f58dbbfbc [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
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040040func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000041 value := reflect.ValueOf(list.Value)
42 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040043 return value, []selects{}
Jingwen Chen5d864492021-02-24 07:20:12 -050044 }
Jingwen Chen91220d72021-03-24 02:18:33 -040045
Liz Kammer9abd62d2021-05-21 08:37:59 -040046 var ret []selects
47 for _, axis := range list.SortedConfigurationAxes() {
48 configToLists := list.ConfigurableValues[axis]
49 archSelects := map[string]reflect.Value{}
50 for config, labels := range configToLists {
51 selectKey := axis.SelectKey(config)
52 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040053 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040054 if len(archSelects) > 0 {
55 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040056 }
57 }
58
Liz Kammer9abd62d2021-05-21 08:37:59 -040059 return value, ret
Jingwen Chenc1c26502021-04-05 10:35:13 +000060}
61
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040062func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040063 value := reflect.ValueOf(label.Value)
64 if !label.HasConfigurableValues() {
65 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020066 }
67
Liz Kammer9abd62d2021-05-21 08:37:59 -040068 ret := selects{}
69 for _, axis := range label.SortedConfigurationAxes() {
70 configToLabels := label.ConfigurableValues[axis]
71 for config, labels := range configToLabels {
72 selectKey := axis.SelectKey(config)
73 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040074 }
75 }
76
Liz Kammerdff00ea2021-10-04 13:44:34 -040077 // if there is a select, use the base value as the conditions default value
78 if len(ret) > 0 {
79 ret[bazel.ConditionsDefaultSelectKey] = value
80 value = reflect.Zero(value.Type())
81 }
82
Liz Kammer9abd62d2021-05-21 08:37:59 -040083 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020084}
85
Liz Kammerd366c902021-06-03 13:43:01 -040086func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
87 value := reflect.ValueOf(boolAttr.Value)
88 if !boolAttr.HasConfigurableValues() {
89 return value, []selects{}
90 }
91
92 ret := selects{}
93 for _, axis := range boolAttr.SortedConfigurationAxes() {
94 configToBools := boolAttr.ConfigurableValues[axis]
95 for config, bools := range configToBools {
96 selectKey := axis.SelectKey(config)
97 ret[selectKey] = reflect.ValueOf(bools)
98 }
99 }
100 // if there is a select, use the base value as the conditions default value
101 if len(ret) > 0 {
102 ret[bazel.ConditionsDefaultSelectKey] = value
103 value = reflect.Zero(value.Type())
104 }
105
106 return value, []selects{ret}
107}
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400108func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000109 value := reflect.ValueOf(list.Value.Includes)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400110 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -0400111 for _, axis := range list.SortedConfigurationAxes() {
112 configToLabels := list.ConfigurableValues[axis]
113 if !configToLabels.HasConfigurableValues() {
114 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -0400115 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400116 archSelects := map[string]reflect.Value{}
Chris Parsons51f8c392021-08-03 21:01:05 -0400117 defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500118 // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
119 emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
Liz Kammer9abd62d2021-05-21 08:37:59 -0400120 for config, labels := range configToLabels {
Chris Parsons51f8c392021-08-03 21:01:05 -0400121 // Omit any entries in the map which match the default value, for brevity.
122 if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
123 continue
124 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400125 selectKey := axis.SelectKey(config)
Chris Parsons58852a02021-12-09 18:10:18 -0500126 if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400127 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -0400128 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400129 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400130 if len(archSelects) > 0 {
131 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400132 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000133 }
134
Liz Kammer2b07ec72021-05-26 15:08:27 -0400135 return value, ret
136}
137
Jingwen Chen58ff6802021-11-17 12:14:41 +0000138func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
139 if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
Liz Kammer2b07ec72021-05-26 15:08:27 -0400140 return true, reflect.ValueOf(list.Includes)
141 } else if len(list.Excludes) > 0 {
142 // if there is still an excludes -- we need to have an empty list for this select & use the
143 // value in conditions default Includes
144 return true, reflect.ValueOf([]string{})
145 }
146 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000147}
148
Liz Kammerd366c902021-06-03 13:43:01 -0400149var (
150 emptyBazelList = "[]"
151 bazelNone = "None"
152)
153
Jingwen Chenc1c26502021-04-05 10:35:13 +0000154// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
155// select statements.
156func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
157 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400158 var configurableAttrs []selects
Liz Kammerd366c902021-06-03 13:43:01 -0400159 var defaultSelectValue *string
Jingwen Chen58ff6802021-11-17 12:14:41 +0000160 var emitZeroValues bool
Chris Parsons51f8c392021-08-03 21:01:05 -0400161 // If true, print the default attribute value, even if the attribute is zero.
162 shouldPrintDefault := false
Jingwen Chenc1c26502021-04-05 10:35:13 +0000163 switch list := v.(type) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000164 case bazel.StringAttribute:
165 if err := list.Collapse(); err != nil {
166 return "", err
167 }
168 value, configurableAttrs = getStringValue(list)
169 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000170 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400171 value, configurableAttrs = getStringListValues(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400172 defaultSelectValue = &emptyBazelList
Jingwen Chenc1c26502021-04-05 10:35:13 +0000173 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400174 value, configurableAttrs = getLabelListValues(list)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000175 emitZeroValues = list.EmitEmptyList
Liz Kammerd366c902021-06-03 13:43:01 -0400176 defaultSelectValue = &emptyBazelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400177 if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
178 shouldPrintDefault = true
179 }
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200180 case bazel.LabelAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500181 if err := list.Collapse(); err != nil {
182 return "", err
183 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400184 value, configurableAttrs = getLabelValue(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400185 defaultSelectValue = &bazelNone
186 case bazel.BoolAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500187 if err := list.Collapse(); err != nil {
188 return "", err
189 }
Liz Kammerd366c902021-06-03 13:43:01 -0400190 value, configurableAttrs = getBoolValue(list)
191 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000192 default:
193 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
194 }
195
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400196 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200197 ret := ""
198 if value.Kind() != reflect.Invalid {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000199 s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200200 if err != nil {
201 return ret, err
202 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000203
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200204 ret += s
205 }
Jingwen Chen63930982021-03-24 10:04:33 -0400206 // Convenience function to append selects components to an attribute value.
Liz Kammerd366c902021-06-03 13:43:01 -0400207 appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000208 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400209 if err != nil {
210 return "", err
211 }
212 if s != "" && selectMap != "" {
213 s += " + "
214 }
215 s += selectMap
216
217 return s, nil
218 }
219
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400220 for _, configurableAttr := range configurableAttrs {
221 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
222 if err != nil {
223 return "", err
224 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400225 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400226
Chris Parsons51f8c392021-08-03 21:01:05 -0400227 if ret == "" && shouldPrintDefault {
228 return *defaultSelectValue, nil
229 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400230 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400231}
232
233// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
234// to construct a select map for any kind of attribute type.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000235func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000236 if selectMap == nil {
237 return "", nil
238 }
239
Jingwen Chen91220d72021-03-24 02:18:33 -0400240 var selects string
241 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400242 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000243 // Handle default condition later.
244 continue
245 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400246 value := selectMap[selectKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500247 if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
248 // Ignore zero values to not generate empty lists. However, always note zero values if
249 // the default value is non-zero.
Jingwen Chen91220d72021-03-24 02:18:33 -0400250 continue
251 }
Chris Parsons58852a02021-12-09 18:10:18 -0500252 s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
Jingwen Chen91220d72021-03-24 02:18:33 -0400253 if err != nil {
254 return "", err
255 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000256 // s could still be an empty string, e.g. unset slices of structs with
257 // length of 0.
258 if s != "" {
259 selects += s + ",\n"
260 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400261 }
262
263 if len(selects) == 0 {
264 // No conditions (or all values are empty lists), so no need for a map.
265 return "", nil
266 }
267
268 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400269 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400270 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000271
272 // Handle the default condition
Jingwen Chen58ff6802021-11-17 12:14:41 +0000273 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000274 if err != nil {
275 return "", err
276 }
Liz Kammerd366c902021-06-03 13:43:01 -0400277 if s != "" {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000278 // Print the custom default value.
279 ret += s
280 ret += ",\n"
Liz Kammerd366c902021-06-03 13:43:01 -0400281 } else if defaultValue != nil {
282 // Print an explicit empty list (the default value) even if the value is
283 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer72beb342022-02-03 08:42:10 -0500284 ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000285 }
286
Liz Kammer72beb342022-02-03 08:42:10 -0500287 ret += starlark_fmt.Indention(indent)
Jingwen Chen91220d72021-03-24 02:18:33 -0400288 ret += "})"
289
290 return ret, nil
291}
292
293// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
294// with a provided key.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000295func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
Liz Kammer72beb342022-02-03 08:42:10 -0500296 s := starlark_fmt.Indention(indent + 1)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000297 v, err := prettyPrint(value, indent+1, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400298 if err != nil {
299 return "", err
300 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000301 if v == "" {
302 return "", nil
303 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400304 s += fmt.Sprintf("\"%s\": %s", key, v)
305 return s, nil
306}