blob: d37a52394ba0deed1cf7a7df37c213a4d8939a54 [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
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040016func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000017 value := reflect.ValueOf(list.Value)
18 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040019 return value, []selects{}
Jingwen Chen5d864492021-02-24 07:20:12 -050020 }
Jingwen Chen91220d72021-03-24 02:18:33 -040021
Liz Kammer9abd62d2021-05-21 08:37:59 -040022 var ret []selects
23 for _, axis := range list.SortedConfigurationAxes() {
24 configToLists := list.ConfigurableValues[axis]
25 archSelects := map[string]reflect.Value{}
26 for config, labels := range configToLists {
27 selectKey := axis.SelectKey(config)
28 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040029 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040030 if len(archSelects) > 0 {
31 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040032 }
33 }
34
Liz Kammer9abd62d2021-05-21 08:37:59 -040035 return value, ret
Jingwen Chenc1c26502021-04-05 10:35:13 +000036}
37
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040038func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040039 value := reflect.ValueOf(label.Value)
40 if !label.HasConfigurableValues() {
41 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020042 }
43
Liz Kammer9abd62d2021-05-21 08:37:59 -040044 ret := selects{}
45 for _, axis := range label.SortedConfigurationAxes() {
46 configToLabels := label.ConfigurableValues[axis]
47 for config, labels := range configToLabels {
48 selectKey := axis.SelectKey(config)
49 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040050 }
51 }
52
Liz Kammerdff00ea2021-10-04 13:44:34 -040053 // if there is a select, use the base value as the conditions default value
54 if len(ret) > 0 {
55 ret[bazel.ConditionsDefaultSelectKey] = value
56 value = reflect.Zero(value.Type())
57 }
58
Liz Kammer9abd62d2021-05-21 08:37:59 -040059 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020060}
61
Liz Kammerd366c902021-06-03 13:43:01 -040062func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
63 value := reflect.ValueOf(boolAttr.Value)
64 if !boolAttr.HasConfigurableValues() {
65 return value, []selects{}
66 }
67
68 ret := selects{}
69 for _, axis := range boolAttr.SortedConfigurationAxes() {
70 configToBools := boolAttr.ConfigurableValues[axis]
71 for config, bools := range configToBools {
72 selectKey := axis.SelectKey(config)
73 ret[selectKey] = reflect.ValueOf(bools)
74 }
75 }
76 // if there is a select, use the base value as the conditions default value
77 if len(ret) > 0 {
78 ret[bazel.ConditionsDefaultSelectKey] = value
79 value = reflect.Zero(value.Type())
80 }
81
82 return value, []selects{ret}
83}
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040084func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000085 value := reflect.ValueOf(list.Value.Includes)
Liz Kammer2b07ec72021-05-26 15:08:27 -040086 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -040087 for _, axis := range list.SortedConfigurationAxes() {
88 configToLabels := list.ConfigurableValues[axis]
89 if !configToLabels.HasConfigurableValues() {
90 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -040091 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040092 archSelects := map[string]reflect.Value{}
Chris Parsons51f8c392021-08-03 21:01:05 -040093 defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
Chris Parsons58852a02021-12-09 18:10:18 -050094 // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
95 emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
Liz Kammer9abd62d2021-05-21 08:37:59 -040096 for config, labels := range configToLabels {
Chris Parsons51f8c392021-08-03 21:01:05 -040097 // Omit any entries in the map which match the default value, for brevity.
98 if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
99 continue
100 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400101 selectKey := axis.SelectKey(config)
Chris Parsons58852a02021-12-09 18:10:18 -0500102 if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400103 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -0400104 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400105 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400106 if len(archSelects) > 0 {
107 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400108 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000109 }
110
Liz Kammer2b07ec72021-05-26 15:08:27 -0400111 return value, ret
112}
113
Jingwen Chen58ff6802021-11-17 12:14:41 +0000114func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
115 if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
Liz Kammer2b07ec72021-05-26 15:08:27 -0400116 return true, reflect.ValueOf(list.Includes)
117 } else if len(list.Excludes) > 0 {
118 // if there is still an excludes -- we need to have an empty list for this select & use the
119 // value in conditions default Includes
120 return true, reflect.ValueOf([]string{})
121 }
122 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000123}
124
Liz Kammerd366c902021-06-03 13:43:01 -0400125var (
126 emptyBazelList = "[]"
127 bazelNone = "None"
128)
129
Jingwen Chenc1c26502021-04-05 10:35:13 +0000130// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
131// select statements.
132func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
133 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400134 var configurableAttrs []selects
Liz Kammerd366c902021-06-03 13:43:01 -0400135 var defaultSelectValue *string
Jingwen Chen58ff6802021-11-17 12:14:41 +0000136 var emitZeroValues bool
Chris Parsons51f8c392021-08-03 21:01:05 -0400137 // If true, print the default attribute value, even if the attribute is zero.
138 shouldPrintDefault := false
Jingwen Chenc1c26502021-04-05 10:35:13 +0000139 switch list := v.(type) {
140 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400141 value, configurableAttrs = getStringListValues(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400142 defaultSelectValue = &emptyBazelList
Jingwen Chenc1c26502021-04-05 10:35:13 +0000143 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400144 value, configurableAttrs = getLabelListValues(list)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000145 emitZeroValues = list.EmitEmptyList
Liz Kammerd366c902021-06-03 13:43:01 -0400146 defaultSelectValue = &emptyBazelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400147 if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
148 shouldPrintDefault = true
149 }
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200150 case bazel.LabelAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500151 if err := list.Collapse(); err != nil {
152 return "", err
153 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400154 value, configurableAttrs = getLabelValue(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400155 defaultSelectValue = &bazelNone
156 case bazel.BoolAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500157 if err := list.Collapse(); err != nil {
158 return "", err
159 }
Liz Kammerd366c902021-06-03 13:43:01 -0400160 value, configurableAttrs = getBoolValue(list)
161 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000162 default:
163 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
164 }
165
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400166 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200167 ret := ""
168 if value.Kind() != reflect.Invalid {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000169 s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200170 if err != nil {
171 return ret, err
172 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000173
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200174 ret += s
175 }
Jingwen Chen63930982021-03-24 10:04:33 -0400176 // Convenience function to append selects components to an attribute value.
Liz Kammerd366c902021-06-03 13:43:01 -0400177 appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000178 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400179 if err != nil {
180 return "", err
181 }
182 if s != "" && selectMap != "" {
183 s += " + "
184 }
185 s += selectMap
186
187 return s, nil
188 }
189
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400190 for _, configurableAttr := range configurableAttrs {
191 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
192 if err != nil {
193 return "", err
194 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400195 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400196
Chris Parsons51f8c392021-08-03 21:01:05 -0400197 if ret == "" && shouldPrintDefault {
198 return *defaultSelectValue, nil
199 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400200 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400201}
202
203// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
204// to construct a select map for any kind of attribute type.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000205func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000206 if selectMap == nil {
207 return "", nil
208 }
209
Jingwen Chen91220d72021-03-24 02:18:33 -0400210 var selects string
211 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400212 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000213 // Handle default condition later.
214 continue
215 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400216 value := selectMap[selectKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500217 if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
218 // Ignore zero values to not generate empty lists. However, always note zero values if
219 // the default value is non-zero.
Jingwen Chen91220d72021-03-24 02:18:33 -0400220 continue
221 }
Chris Parsons58852a02021-12-09 18:10:18 -0500222 s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
Jingwen Chen91220d72021-03-24 02:18:33 -0400223 if err != nil {
224 return "", err
225 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000226 // s could still be an empty string, e.g. unset slices of structs with
227 // length of 0.
228 if s != "" {
229 selects += s + ",\n"
230 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400231 }
232
233 if len(selects) == 0 {
234 // No conditions (or all values are empty lists), so no need for a map.
235 return "", nil
236 }
237
238 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400239 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400240 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000241
242 // Handle the default condition
Jingwen Chen58ff6802021-11-17 12:14:41 +0000243 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000244 if err != nil {
245 return "", err
246 }
Liz Kammerd366c902021-06-03 13:43:01 -0400247 if s != "" {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000248 // Print the custom default value.
249 ret += s
250 ret += ",\n"
Liz Kammerd366c902021-06-03 13:43:01 -0400251 } else if defaultValue != nil {
252 // Print an explicit empty list (the default value) even if the value is
253 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer72beb342022-02-03 08:42:10 -0500254 ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000255 }
256
Liz Kammer72beb342022-02-03 08:42:10 -0500257 ret += starlark_fmt.Indention(indent)
Jingwen Chen91220d72021-03-24 02:18:33 -0400258 ret += "})"
259
260 return ret, nil
261}
262
263// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
264// with a provided key.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000265func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
Liz Kammer72beb342022-02-03 08:42:10 -0500266 s := starlark_fmt.Indention(indent + 1)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000267 v, err := prettyPrint(value, indent+1, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400268 if err != nil {
269 return "", err
270 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000271 if v == "" {
272 return "", nil
273 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400274 s += fmt.Sprintf("\"%s\": %s", key, v)
275 return s, nil
276}