blob: 3d9f0a274e1aea34f29d98b99a113ee7cf43da3e [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 }
Liz Kammer9d2d4102022-12-21 14:51:37 -050031
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +000032 // if there is a select, use the base value as the conditions default value
33 if len(ret) > 0 {
Liz Kammer9d2d4102022-12-21 14:51:37 -050034 if _, ok := ret[bazel.ConditionsDefaultSelectKey]; !ok {
35 ret[bazel.ConditionsDefaultSelectKey] = value
36 value = reflect.Zero(value.Type())
37 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +000038 }
39
40 return value, []selects{ret}
41}
42
Zi Wang1cb11802022-12-09 16:08:54 -080043func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects, bool) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000044 value := reflect.ValueOf(list.Value)
Zi Wang0f828442022-12-28 11:18:11 -080045 prepend := list.Prepend
Jingwen Chenc1c26502021-04-05 10:35:13 +000046 if !list.HasConfigurableValues() {
Zi Wang1cb11802022-12-09 16:08:54 -080047 return value, []selects{}, prepend
Jingwen Chen5d864492021-02-24 07:20:12 -050048 }
Jingwen Chen91220d72021-03-24 02:18:33 -040049
Liz Kammer9abd62d2021-05-21 08:37:59 -040050 var ret []selects
51 for _, axis := range list.SortedConfigurationAxes() {
52 configToLists := list.ConfigurableValues[axis]
53 archSelects := map[string]reflect.Value{}
54 for config, labels := range configToLists {
55 selectKey := axis.SelectKey(config)
56 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040057 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040058 if len(archSelects) > 0 {
59 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040060 }
61 }
62
Zi Wang1cb11802022-12-09 16:08:54 -080063 return value, ret, prepend
Jingwen Chenc1c26502021-04-05 10:35:13 +000064}
65
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040066func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040067 value := reflect.ValueOf(label.Value)
68 if !label.HasConfigurableValues() {
69 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020070 }
71
Liz Kammer9abd62d2021-05-21 08:37:59 -040072 ret := selects{}
73 for _, axis := range label.SortedConfigurationAxes() {
74 configToLabels := label.ConfigurableValues[axis]
75 for config, labels := range configToLabels {
76 selectKey := axis.SelectKey(config)
77 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040078 }
79 }
80
Liz Kammerdff00ea2021-10-04 13:44:34 -040081 // if there is a select, use the base value as the conditions default value
82 if len(ret) > 0 {
83 ret[bazel.ConditionsDefaultSelectKey] = value
84 value = reflect.Zero(value.Type())
85 }
86
Liz Kammer9abd62d2021-05-21 08:37:59 -040087 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020088}
89
Liz Kammerd366c902021-06-03 13:43:01 -040090func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
91 value := reflect.ValueOf(boolAttr.Value)
92 if !boolAttr.HasConfigurableValues() {
93 return value, []selects{}
94 }
95
96 ret := selects{}
97 for _, axis := range boolAttr.SortedConfigurationAxes() {
98 configToBools := boolAttr.ConfigurableValues[axis]
99 for config, bools := range configToBools {
100 selectKey := axis.SelectKey(config)
101 ret[selectKey] = reflect.ValueOf(bools)
102 }
103 }
104 // if there is a select, use the base value as the conditions default value
105 if len(ret) > 0 {
106 ret[bazel.ConditionsDefaultSelectKey] = value
107 value = reflect.Zero(value.Type())
108 }
109
110 return value, []selects{ret}
111}
Zi Wang9f609db2023-01-04 11:06:54 -0800112func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects, bool) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000113 value := reflect.ValueOf(list.Value.Includes)
Zi Wang9f609db2023-01-04 11:06:54 -0800114 prepend := list.Prepend
Liz Kammer2b07ec72021-05-26 15:08:27 -0400115 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -0400116 for _, axis := range list.SortedConfigurationAxes() {
117 configToLabels := list.ConfigurableValues[axis]
118 if !configToLabels.HasConfigurableValues() {
119 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -0400120 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400121 archSelects := map[string]reflect.Value{}
Chris Parsons51f8c392021-08-03 21:01:05 -0400122 defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500123 // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
124 emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
Liz Kammer9abd62d2021-05-21 08:37:59 -0400125 for config, labels := range configToLabels {
Chris Parsons51f8c392021-08-03 21:01:05 -0400126 // Omit any entries in the map which match the default value, for brevity.
127 if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
128 continue
129 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400130 selectKey := axis.SelectKey(config)
Chris Parsons58852a02021-12-09 18:10:18 -0500131 if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400132 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -0400133 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400134 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400135 if len(archSelects) > 0 {
136 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400137 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000138 }
139
Zi Wang9f609db2023-01-04 11:06:54 -0800140 return value, ret, prepend
Liz Kammer2b07ec72021-05-26 15:08:27 -0400141}
142
Jingwen Chen58ff6802021-11-17 12:14:41 +0000143func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
144 if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
Liz Kammer2b07ec72021-05-26 15:08:27 -0400145 return true, reflect.ValueOf(list.Includes)
146 } else if len(list.Excludes) > 0 {
147 // if there is still an excludes -- we need to have an empty list for this select & use the
148 // value in conditions default Includes
149 return true, reflect.ValueOf([]string{})
150 }
151 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000152}
153
Liz Kammerd366c902021-06-03 13:43:01 -0400154var (
155 emptyBazelList = "[]"
156 bazelNone = "None"
157)
158
Jingwen Chenc1c26502021-04-05 10:35:13 +0000159// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
160// select statements.
161func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
162 var value reflect.Value
Chris Parsons7b3289b2023-01-26 17:30:44 -0500163 // configurableAttrs is the list of individual select statements to be
164 // concatenated together. These select statements should be along different
165 // axes. For example, one element may be
166 // `select({"//color:red": "one", "//color:green": "two"})`, and the second
167 // element may be `select({"//animal:cat": "three", "//animal:dog": "four"}).
168 // These selects should be sorted by axis identifier.
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400169 var configurableAttrs []selects
Zi Wang1cb11802022-12-09 16:08:54 -0800170 var prepend bool
Liz Kammerd366c902021-06-03 13:43:01 -0400171 var defaultSelectValue *string
Jingwen Chen58ff6802021-11-17 12:14:41 +0000172 var emitZeroValues bool
Chris Parsons51f8c392021-08-03 21:01:05 -0400173 // If true, print the default attribute value, even if the attribute is zero.
174 shouldPrintDefault := false
Jingwen Chenc1c26502021-04-05 10:35:13 +0000175 switch list := v.(type) {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +0000176 case bazel.StringAttribute:
177 if err := list.Collapse(); err != nil {
178 return "", err
179 }
180 value, configurableAttrs = getStringValue(list)
181 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000182 case bazel.StringListAttribute:
Zi Wang1cb11802022-12-09 16:08:54 -0800183 value, configurableAttrs, prepend = getStringListValues(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400184 defaultSelectValue = &emptyBazelList
Jingwen Chenc1c26502021-04-05 10:35:13 +0000185 case bazel.LabelListAttribute:
Zi Wang9f609db2023-01-04 11:06:54 -0800186 value, configurableAttrs, prepend = getLabelListValues(list)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000187 emitZeroValues = list.EmitEmptyList
Liz Kammerd366c902021-06-03 13:43:01 -0400188 defaultSelectValue = &emptyBazelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400189 if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
190 shouldPrintDefault = true
191 }
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200192 case bazel.LabelAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500193 if err := list.Collapse(); err != nil {
194 return "", err
195 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400196 value, configurableAttrs = getLabelValue(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400197 defaultSelectValue = &bazelNone
198 case bazel.BoolAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500199 if err := list.Collapse(); err != nil {
200 return "", err
201 }
Liz Kammerd366c902021-06-03 13:43:01 -0400202 value, configurableAttrs = getBoolValue(list)
203 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000204 default:
205 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
206 }
207
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400208 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200209 ret := ""
210 if value.Kind() != reflect.Invalid {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000211 s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200212 if err != nil {
213 return ret, err
214 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000215
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200216 ret += s
217 }
Zi Wang1cb11802022-12-09 16:08:54 -0800218 // Convenience function to prepend/append selects components to an attribute value.
219 concatenateSelects := func(selectsData selects, defaultValue *string, s string, prepend bool) (string, error) {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000220 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400221 if err != nil {
222 return "", err
223 }
Zi Wang1cb11802022-12-09 16:08:54 -0800224 var left, right string
225 if prepend {
226 left, right = selectMap, s
227 } else {
228 left, right = s, selectMap
Jingwen Chen63930982021-03-24 10:04:33 -0400229 }
Zi Wang1cb11802022-12-09 16:08:54 -0800230 if left != "" && right != "" {
231 left += " + "
232 }
233 left += right
Jingwen Chen63930982021-03-24 10:04:33 -0400234
Zi Wang1cb11802022-12-09 16:08:54 -0800235 return left, nil
Jingwen Chen63930982021-03-24 10:04:33 -0400236 }
237
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400238 for _, configurableAttr := range configurableAttrs {
Zi Wang1cb11802022-12-09 16:08:54 -0800239 ret, err = concatenateSelects(configurableAttr, defaultSelectValue, ret, prepend)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400240 if err != nil {
241 return "", err
242 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400243 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400244
Chris Parsons51f8c392021-08-03 21:01:05 -0400245 if ret == "" && shouldPrintDefault {
246 return *defaultSelectValue, nil
247 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400248 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400249}
250
251// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
252// to construct a select map for any kind of attribute type.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000253func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000254 if selectMap == nil {
255 return "", nil
256 }
257
Jingwen Chen91220d72021-03-24 02:18:33 -0400258 var selects string
Cole Faust18994c72023-02-28 16:02:16 -0800259 for _, selectKey := range android.SortedKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400260 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000261 // Handle default condition later.
262 continue
263 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400264 value := selectMap[selectKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500265 if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
266 // Ignore zero values to not generate empty lists. However, always note zero values if
267 // the default value is non-zero.
Jingwen Chen91220d72021-03-24 02:18:33 -0400268 continue
269 }
Chris Parsons58852a02021-12-09 18:10:18 -0500270 s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
Jingwen Chen91220d72021-03-24 02:18:33 -0400271 if err != nil {
272 return "", err
273 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000274 // s could still be an empty string, e.g. unset slices of structs with
275 // length of 0.
276 if s != "" {
277 selects += s + ",\n"
278 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400279 }
280
281 if len(selects) == 0 {
Spandan Das921af322023-04-26 02:56:37 +0000282 // If there is a default value, and there are no selects for this axis, print that without any selects.
283 if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists {
284 return prettyPrint(val, indent, emitZeroValues)
285 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400286 // No conditions (or all values are empty lists), so no need for a map.
287 return "", nil
288 }
289
290 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400291 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400292 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000293
294 // Handle the default condition
Jingwen Chen58ff6802021-11-17 12:14:41 +0000295 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000296 if err != nil {
297 return "", err
298 }
Liz Kammerd366c902021-06-03 13:43:01 -0400299 if s != "" {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000300 // Print the custom default value.
301 ret += s
302 ret += ",\n"
Liz Kammerd366c902021-06-03 13:43:01 -0400303 } else if defaultValue != nil {
304 // Print an explicit empty list (the default value) even if the value is
305 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer72beb342022-02-03 08:42:10 -0500306 ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000307 }
308
Liz Kammer72beb342022-02-03 08:42:10 -0500309 ret += starlark_fmt.Indention(indent)
Jingwen Chen91220d72021-03-24 02:18:33 -0400310 ret += "})"
311
312 return ret, nil
313}
314
315// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
316// with a provided key.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000317func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
Liz Kammer72beb342022-02-03 08:42:10 -0500318 s := starlark_fmt.Indention(indent + 1)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000319 v, err := prettyPrint(value, indent+1, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400320 if err != nil {
321 return "", err
322 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000323 if v == "" {
324 return "", nil
325 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400326 s += fmt.Sprintf("\"%s\": %s", key, v)
327 return s, nil
328}