blob: dfbb265d268400ca0a19d21fca61eff5f69fd1fc [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"
Jingwen Chen91220d72021-03-24 02:18:33 -04009)
Jingwen Chen5d864492021-02-24 07:20:12 -050010
11// Configurability support for bp2build.
12
Jingwen Chenc1c26502021-04-05 10:35:13 +000013type selects map[string]reflect.Value
14
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040015func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000016 value := reflect.ValueOf(list.Value)
17 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040018 return value, []selects{}
Jingwen Chen5d864492021-02-24 07:20:12 -050019 }
Jingwen Chen91220d72021-03-24 02:18:33 -040020
Liz Kammer9abd62d2021-05-21 08:37:59 -040021 var ret []selects
22 for _, axis := range list.SortedConfigurationAxes() {
23 configToLists := list.ConfigurableValues[axis]
24 archSelects := map[string]reflect.Value{}
25 for config, labels := range configToLists {
26 selectKey := axis.SelectKey(config)
27 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040028 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040029 if len(archSelects) > 0 {
30 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040031 }
32 }
33
Liz Kammer9abd62d2021-05-21 08:37:59 -040034 return value, ret
Jingwen Chenc1c26502021-04-05 10:35:13 +000035}
36
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040037func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040038 value := reflect.ValueOf(label.Value)
39 if !label.HasConfigurableValues() {
40 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020041 }
42
Liz Kammer9abd62d2021-05-21 08:37:59 -040043 ret := selects{}
44 for _, axis := range label.SortedConfigurationAxes() {
45 configToLabels := label.ConfigurableValues[axis]
46 for config, labels := range configToLabels {
47 selectKey := axis.SelectKey(config)
48 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040049 }
50 }
51
Liz Kammerdff00ea2021-10-04 13:44:34 -040052 // if there is a select, use the base value as the conditions default value
53 if len(ret) > 0 {
54 ret[bazel.ConditionsDefaultSelectKey] = value
55 value = reflect.Zero(value.Type())
56 }
57
Liz Kammer9abd62d2021-05-21 08:37:59 -040058 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020059}
60
Liz Kammerd366c902021-06-03 13:43:01 -040061func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
62 value := reflect.ValueOf(boolAttr.Value)
63 if !boolAttr.HasConfigurableValues() {
64 return value, []selects{}
65 }
66
67 ret := selects{}
68 for _, axis := range boolAttr.SortedConfigurationAxes() {
69 configToBools := boolAttr.ConfigurableValues[axis]
70 for config, bools := range configToBools {
71 selectKey := axis.SelectKey(config)
72 ret[selectKey] = reflect.ValueOf(bools)
73 }
74 }
75 // if there is a select, use the base value as the conditions default value
76 if len(ret) > 0 {
77 ret[bazel.ConditionsDefaultSelectKey] = value
78 value = reflect.Zero(value.Type())
79 }
80
81 return value, []selects{ret}
82}
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040083func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000084 value := reflect.ValueOf(list.Value.Includes)
Liz Kammer2b07ec72021-05-26 15:08:27 -040085 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -040086 for _, axis := range list.SortedConfigurationAxes() {
87 configToLabels := list.ConfigurableValues[axis]
88 if !configToLabels.HasConfigurableValues() {
89 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -040090 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040091 archSelects := map[string]reflect.Value{}
Chris Parsons51f8c392021-08-03 21:01:05 -040092 defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
Chris Parsons58852a02021-12-09 18:10:18 -050093 // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
94 emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
Liz Kammer9abd62d2021-05-21 08:37:59 -040095 for config, labels := range configToLabels {
Chris Parsons51f8c392021-08-03 21:01:05 -040096 // Omit any entries in the map which match the default value, for brevity.
97 if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
98 continue
99 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400100 selectKey := axis.SelectKey(config)
Chris Parsons58852a02021-12-09 18:10:18 -0500101 if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400102 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -0400103 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400104 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400105 if len(archSelects) > 0 {
106 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -0400107 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000108 }
109
Liz Kammer2b07ec72021-05-26 15:08:27 -0400110 return value, ret
111}
112
Jingwen Chen58ff6802021-11-17 12:14:41 +0000113func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
114 if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
Liz Kammer2b07ec72021-05-26 15:08:27 -0400115 return true, reflect.ValueOf(list.Includes)
116 } else if len(list.Excludes) > 0 {
117 // if there is still an excludes -- we need to have an empty list for this select & use the
118 // value in conditions default Includes
119 return true, reflect.ValueOf([]string{})
120 }
121 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000122}
123
Liz Kammerd366c902021-06-03 13:43:01 -0400124var (
125 emptyBazelList = "[]"
126 bazelNone = "None"
127)
128
Jingwen Chenc1c26502021-04-05 10:35:13 +0000129// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
130// select statements.
131func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
132 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400133 var configurableAttrs []selects
Liz Kammerd366c902021-06-03 13:43:01 -0400134 var defaultSelectValue *string
Jingwen Chen58ff6802021-11-17 12:14:41 +0000135 var emitZeroValues bool
Chris Parsons51f8c392021-08-03 21:01:05 -0400136 // If true, print the default attribute value, even if the attribute is zero.
137 shouldPrintDefault := false
Jingwen Chenc1c26502021-04-05 10:35:13 +0000138 switch list := v.(type) {
139 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400140 value, configurableAttrs = getStringListValues(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400141 defaultSelectValue = &emptyBazelList
Jingwen Chenc1c26502021-04-05 10:35:13 +0000142 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400143 value, configurableAttrs = getLabelListValues(list)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000144 emitZeroValues = list.EmitEmptyList
Liz Kammerd366c902021-06-03 13:43:01 -0400145 defaultSelectValue = &emptyBazelList
Chris Parsons51f8c392021-08-03 21:01:05 -0400146 if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
147 shouldPrintDefault = true
148 }
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200149 case bazel.LabelAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500150 if err := list.Collapse(); err != nil {
151 return "", err
152 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400153 value, configurableAttrs = getLabelValue(list)
Liz Kammerd366c902021-06-03 13:43:01 -0400154 defaultSelectValue = &bazelNone
155 case bazel.BoolAttribute:
Chris Parsons58852a02021-12-09 18:10:18 -0500156 if err := list.Collapse(); err != nil {
157 return "", err
158 }
Liz Kammerd366c902021-06-03 13:43:01 -0400159 value, configurableAttrs = getBoolValue(list)
160 defaultSelectValue = &bazelNone
Jingwen Chenc1c26502021-04-05 10:35:13 +0000161 default:
162 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
163 }
164
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400165 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200166 ret := ""
167 if value.Kind() != reflect.Invalid {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000168 s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200169 if err != nil {
170 return ret, err
171 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000172
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200173 ret += s
174 }
Jingwen Chen63930982021-03-24 10:04:33 -0400175 // Convenience function to append selects components to an attribute value.
Liz Kammerd366c902021-06-03 13:43:01 -0400176 appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
Jingwen Chen58ff6802021-11-17 12:14:41 +0000177 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400178 if err != nil {
179 return "", err
180 }
181 if s != "" && selectMap != "" {
182 s += " + "
183 }
184 s += selectMap
185
186 return s, nil
187 }
188
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400189 for _, configurableAttr := range configurableAttrs {
190 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
191 if err != nil {
192 return "", err
193 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400194 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400195
Chris Parsons51f8c392021-08-03 21:01:05 -0400196 if ret == "" && shouldPrintDefault {
197 return *defaultSelectValue, nil
198 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400199 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400200}
201
202// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
203// to construct a select map for any kind of attribute type.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000204func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000205 if selectMap == nil {
206 return "", nil
207 }
208
Jingwen Chen91220d72021-03-24 02:18:33 -0400209 var selects string
210 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400211 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000212 // Handle default condition later.
213 continue
214 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400215 value := selectMap[selectKey]
Chris Parsons58852a02021-12-09 18:10:18 -0500216 if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
217 // Ignore zero values to not generate empty lists. However, always note zero values if
218 // the default value is non-zero.
Jingwen Chen91220d72021-03-24 02:18:33 -0400219 continue
220 }
Chris Parsons58852a02021-12-09 18:10:18 -0500221 s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
Jingwen Chen91220d72021-03-24 02:18:33 -0400222 if err != nil {
223 return "", err
224 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000225 // s could still be an empty string, e.g. unset slices of structs with
226 // length of 0.
227 if s != "" {
228 selects += s + ",\n"
229 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400230 }
231
232 if len(selects) == 0 {
233 // No conditions (or all values are empty lists), so no need for a map.
234 return "", nil
235 }
236
237 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400238 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400239 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000240
241 // Handle the default condition
Jingwen Chen58ff6802021-11-17 12:14:41 +0000242 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000243 if err != nil {
244 return "", err
245 }
Liz Kammerd366c902021-06-03 13:43:01 -0400246 if s != "" {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000247 // Print the custom default value.
248 ret += s
249 ret += ",\n"
Liz Kammerd366c902021-06-03 13:43:01 -0400250 } else if defaultValue != nil {
251 // Print an explicit empty list (the default value) even if the value is
252 // empty, to avoid errors about not finding a configuration that matches.
253 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000254 }
255
Jingwen Chen91220d72021-03-24 02:18:33 -0400256 ret += makeIndent(indent)
257 ret += "})"
258
259 return ret, nil
260}
261
262// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
263// with a provided key.
Jingwen Chen58ff6802021-11-17 12:14:41 +0000264func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
Jingwen Chen91220d72021-03-24 02:18:33 -0400265 s := makeIndent(indent + 1)
Jingwen Chen58ff6802021-11-17 12:14:41 +0000266 v, err := prettyPrint(value, indent+1, emitZeroValues)
Jingwen Chen91220d72021-03-24 02:18:33 -0400267 if err != nil {
268 return "", err
269 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000270 if v == "" {
271 return "", nil
272 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400273 s += fmt.Sprintf("\"%s\": %s", key, v)
274 return s, nil
275}