blob: c953259f9735e36c1386fc4d580b5ec72769f23a [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
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040014func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000015 value := reflect.ValueOf(list.Value)
16 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040017 return value, []selects{}
Jingwen Chen5d864492021-02-24 07:20:12 -050018 }
Jingwen Chen91220d72021-03-24 02:18:33 -040019
Liz Kammer9abd62d2021-05-21 08:37:59 -040020 var ret []selects
21 for _, axis := range list.SortedConfigurationAxes() {
22 configToLists := list.ConfigurableValues[axis]
23 archSelects := map[string]reflect.Value{}
24 for config, labels := range configToLists {
25 selectKey := axis.SelectKey(config)
26 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040027 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040028 if len(archSelects) > 0 {
29 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040030 }
31 }
32
Liz Kammer9abd62d2021-05-21 08:37:59 -040033 return value, ret
Jingwen Chenc1c26502021-04-05 10:35:13 +000034}
35
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040036func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040037 value := reflect.ValueOf(label.Value)
38 if !label.HasConfigurableValues() {
39 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020040 }
41
Liz Kammer9abd62d2021-05-21 08:37:59 -040042 ret := selects{}
43 for _, axis := range label.SortedConfigurationAxes() {
44 configToLabels := label.ConfigurableValues[axis]
45 for config, labels := range configToLabels {
46 selectKey := axis.SelectKey(config)
47 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040048 }
49 }
50
Liz Kammerdff00ea2021-10-04 13:44:34 -040051 // if there is a select, use the base value as the conditions default value
52 if len(ret) > 0 {
53 ret[bazel.ConditionsDefaultSelectKey] = value
54 value = reflect.Zero(value.Type())
55 }
56
Liz Kammer9abd62d2021-05-21 08:37:59 -040057 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020058}
59
Liz Kammerd366c902021-06-03 13:43:01 -040060func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
61 value := reflect.ValueOf(boolAttr.Value)
62 if !boolAttr.HasConfigurableValues() {
63 return value, []selects{}
64 }
65
66 ret := selects{}
67 for _, axis := range boolAttr.SortedConfigurationAxes() {
68 configToBools := boolAttr.ConfigurableValues[axis]
69 for config, bools := range configToBools {
70 selectKey := axis.SelectKey(config)
71 ret[selectKey] = reflect.ValueOf(bools)
72 }
73 }
74 // if there is a select, use the base value as the conditions default value
75 if len(ret) > 0 {
76 ret[bazel.ConditionsDefaultSelectKey] = value
77 value = reflect.Zero(value.Type())
78 }
79
80 return value, []selects{ret}
81}
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040082func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000083 value := reflect.ValueOf(list.Value.Includes)
Liz Kammer2b07ec72021-05-26 15:08:27 -040084 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -040085 for _, axis := range list.SortedConfigurationAxes() {
86 configToLabels := list.ConfigurableValues[axis]
87 if !configToLabels.HasConfigurableValues() {
88 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -040089 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040090 archSelects := map[string]reflect.Value{}
Chris Parsons51f8c392021-08-03 21:01:05 -040091 defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
Liz Kammer9abd62d2021-05-21 08:37:59 -040092 for config, labels := range configToLabels {
Chris Parsons51f8c392021-08-03 21:01:05 -040093 // Omit any entries in the map which match the default value, for brevity.
94 if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
95 continue
96 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040097 selectKey := axis.SelectKey(config)
Jingwen Chen58ff6802021-11-17 12:14:41 +000098 if use, value := labelListSelectValue(selectKey, labels, list.EmitEmptyList); use {
Liz Kammer9abd62d2021-05-21 08:37:59 -040099 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -0400100 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400101 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400102 if len(archSelects) > 0 {
103 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400104 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000105 }
106
Liz Kammer2b07ec72021-05-26 15:08:27 -0400107 return value, ret
108}
109
Jingwen Chen58ff6802021-11-17 12:14:41 +0000110func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
111 if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
Liz Kammer2b07ec72021-05-26 15:08:27 -0400112 return true, reflect.ValueOf(list.Includes)
113 } else if len(list.Excludes) > 0 {
114 // if there is still an excludes -- we need to have an empty list for this select & use the
115 // value in conditions default Includes
116 return true, reflect.ValueOf([]string{})
117 }
118 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000119}
120
Liz Kammerd366c902021-06-03 13:43:01 -0400121var (
122 emptyBazelList = "[]"
123 bazelNone = "None"
124)
125
Jingwen Chenc1c26502021-04-05 10:35:13 +0000126// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
127// select statements.
128func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
129 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400130 var configurableAttrs []selects
Liz Kammerd366c902021-06-03 13:43:01 -0400131 var defaultSelectValue *string
Jingwen Chen58ff6802021-11-17 12:14:41 +0000132 var emitZeroValues bool
Chris Parsons51f8c392021-08-03 21:01:05 -0400133 // If true, print the default attribute value, even if the attribute is zero.
134 shouldPrintDefault := false
Jingwen Chenc1c26502021-04-05 10:35:13 +0000135 switch list := v.(type) {
136 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400137 value, configurableAttrs = getStringListValues(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400138 defaultSelectValue = &emptyBazelList
Jingwen Chenc1c26502021-04-05 10:35:13 +0000139 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400140 value, configurableAttrs = getLabelListValues(list)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000141 emitZeroValues = list.EmitEmptyList
Liz Kammerd366c902021-06-03 13:43:01 -0400142 defaultSelectValue = &emptyBazelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400143 if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
144 shouldPrintDefault = true
145 }
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200146 case bazel.LabelAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400147 value, configurableAttrs = getLabelValue(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400148 defaultSelectValue = &bazelNone
149 case bazel.BoolAttribute:
150 value, configurableAttrs = getBoolValue(list)
151 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000152 default:
153 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
154 }
155
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400156 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200157 ret := ""
158 if value.Kind() != reflect.Invalid {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000159 s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200160 if err != nil {
161 return ret, err
162 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000163
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200164 ret += s
165 }
Jingwen Chen63930982021-03-24 10:04:33 -0400166 // Convenience function to append selects components to an attribute value.
Liz Kammerd366c902021-06-03 13:43:01 -0400167 appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000168 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400169 if err != nil {
170 return "", err
171 }
172 if s != "" && selectMap != "" {
173 s += " + "
174 }
175 s += selectMap
176
177 return s, nil
178 }
179
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400180 for _, configurableAttr := range configurableAttrs {
181 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
182 if err != nil {
183 return "", err
184 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400185 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400186
Chris Parsons51f8c392021-08-03 21:01:05 -0400187 if ret == "" && shouldPrintDefault {
188 return *defaultSelectValue, nil
189 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400190 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400191}
192
193// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
194// to construct a select map for any kind of attribute type.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000195func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000196 if selectMap == nil {
197 return "", nil
198 }
199
Jingwen Chen91220d72021-03-24 02:18:33 -0400200 var selects string
201 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400202 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000203 // Handle default condition later.
204 continue
205 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400206 value := selectMap[selectKey]
Jingwen Chen58ff6802021-11-17 12:14:41 +0000207 if isZero(value) && !emitZeroValues {
Jingwen Chen91220d72021-03-24 02:18:33 -0400208 // Ignore zero values to not generate empty lists.
209 continue
210 }
Jingwen Chen58ff6802021-11-17 12:14:41 +0000211 s, err := prettyPrintSelectEntry(value, selectKey, indent, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400212 if err != nil {
213 return "", err
214 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000215 // s could still be an empty string, e.g. unset slices of structs with
216 // length of 0.
217 if s != "" {
218 selects += s + ",\n"
219 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400220 }
221
222 if len(selects) == 0 {
223 // No conditions (or all values are empty lists), so no need for a map.
224 return "", nil
225 }
226
227 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400228 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400229 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000230
231 // Handle the default condition
Jingwen Chen58ff6802021-11-17 12:14:41 +0000232 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000233 if err != nil {
234 return "", err
235 }
Liz Kammerd366c902021-06-03 13:43:01 -0400236 if s != "" {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000237 // Print the custom default value.
238 ret += s
239 ret += ",\n"
Liz Kammerd366c902021-06-03 13:43:01 -0400240 } else if defaultValue != nil {
241 // Print an explicit empty list (the default value) even if the value is
242 // empty, to avoid errors about not finding a configuration that matches.
243 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000244 }
245
Jingwen Chen91220d72021-03-24 02:18:33 -0400246 ret += makeIndent(indent)
247 ret += "})"
248
249 return ret, nil
250}
251
252// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
253// with a provided key.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000254func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chen91220d72021-03-24 02:18:33 -0400255 s := makeIndent(indent + 1)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000256 v, err := prettyPrint(value, indent+1, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400257 if err != nil {
258 return "", err
259 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000260 if v == "" {
261 return "", nil
262 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400263 s += fmt.Sprintf("\"%s\": %s", key, v)
264 return s, nil
265}