blob: b5070b9c921ae64697478a4f2d7a1a379d3c2499 [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 Kammer6fd7b3f2021-05-06 13:54:29 -040020 selectValues := make([]selects, 0)
Jingwen Chen91220d72021-03-24 02:18:33 -040021 archSelects := map[string]reflect.Value{}
22 for arch, selectKey := range bazel.PlatformArchMap {
Jingwen Chenc1c26502021-04-05 10:35:13 +000023 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
Jingwen Chen91220d72021-03-24 02:18:33 -040024 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040025 if len(archSelects) > 0 {
26 selectValues = append(selectValues, archSelects)
27 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000028
29 osSelects := map[string]reflect.Value{}
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040030 osArchSelects := make([]selects, 0)
31 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
32 selectKey := bazel.PlatformOsMap[os]
33 osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os))
34 archSelects := make(map[string]reflect.Value)
35 // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (not in AllArches)
36 for _, arch := range bazel.AllArches {
37 target := os + "_" + arch
38 selectKey := bazel.PlatformTargetMap[target]
39 archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch))
40 }
41 osArchSelects = append(osArchSelects, archSelects)
Jingwen Chenc1c26502021-04-05 10:35:13 +000042 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040043 if len(osSelects) > 0 {
44 selectValues = append(selectValues, osSelects)
45 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040046 if len(osArchSelects) > 0 {
47 selectValues = append(selectValues, osArchSelects...)
48 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000049
Liz Kammere3e4a5f2021-05-10 11:39:53 -040050 for _, pv := range list.SortedProductVariables() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040051 s := make(selects)
52 if len(pv.Values) > 0 {
53 s[pv.SelectKey()] = reflect.ValueOf(pv.Values)
54 s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{})
55 selectValues = append(selectValues, s)
56 }
57 }
58
59 return value, selectValues
Jingwen Chenc1c26502021-04-05 10:35:13 +000060}
61
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040062func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020063 var value reflect.Value
64 var archSelects selects
65
66 if label.HasConfigurableValues() {
67 archSelects = map[string]reflect.Value{}
68 for arch, selectKey := range bazel.PlatformArchMap {
69 archSelects[selectKey] = reflect.ValueOf(label.GetValueForArch(arch))
70 }
71 } else {
72 value = reflect.ValueOf(label.Value)
73 }
74
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040075 return value, []selects{archSelects}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020076}
77
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040078func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000079 value := reflect.ValueOf(list.Value.Includes)
80 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040081 return value, []selects{}
Jingwen Chenc1c26502021-04-05 10:35:13 +000082 }
83
84 archSelects := map[string]reflect.Value{}
85 for arch, selectKey := range bazel.PlatformArchMap {
86 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
87 }
88
89 osSelects := map[string]reflect.Value{}
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040090 osArchSelects := make([]selects, 0)
91 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
92 selectKey := bazel.PlatformOsMap[os]
93 osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os).Includes)
94 archSelects := make(map[string]reflect.Value)
95 // TODO(b/187530594): Should we also check arch=CONDITIOSN_DEFAULT? (not in AllArches)
96 for _, arch := range bazel.AllArches {
97 target := os + "_" + arch
98 selectKey := bazel.PlatformTargetMap[target]
99 archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch).Includes)
100 }
101 osArchSelects = append(osArchSelects, archSelects)
Jingwen Chenc1c26502021-04-05 10:35:13 +0000102 }
103
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400104 var selects []selects
105 selects = append(selects, archSelects)
106 selects = append(selects, osSelects)
107 selects = append(selects, osArchSelects...)
108 return value, selects
Jingwen Chenc1c26502021-04-05 10:35:13 +0000109}
110
111// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
112// select statements.
113func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
114 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400115 var configurableAttrs []selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200116 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +0000117 switch list := v.(type) {
118 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400119 value, configurableAttrs = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200120 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000121 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400122 value, configurableAttrs = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200123 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200124 case bazel.LabelAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400125 value, configurableAttrs = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200126 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000127 default:
128 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
129 }
130
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400131 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200132 ret := ""
133 if value.Kind() != reflect.Invalid {
134 s, err := prettyPrint(value, indent)
135 if err != nil {
136 return ret, err
137 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000138
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200139 ret += s
140 }
Jingwen Chen63930982021-03-24 10:04:33 -0400141 // Convenience function to append selects components to an attribute value.
142 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
143 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
144 if err != nil {
145 return "", err
146 }
147 if s != "" && selectMap != "" {
148 s += " + "
149 }
150 s += selectMap
151
152 return s, nil
153 }
154
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400155 for _, configurableAttr := range configurableAttrs {
156 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
157 if err != nil {
158 return "", err
159 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400160 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400161
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400162 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400163}
164
165// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
166// to construct a select map for any kind of attribute type.
167func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000168 if selectMap == nil {
169 return "", nil
170 }
171
Jingwen Chene32e9e02021-04-23 09:17:24 +0000172 // addConditionsDefault := false
Jingwen Chene32e9e02021-04-23 09:17:24 +0000173
Jingwen Chen91220d72021-03-24 02:18:33 -0400174 var selects string
175 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400176 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000177 // Handle default condition later.
178 continue
179 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400180 value := selectMap[selectKey]
181 if isZero(value) {
182 // Ignore zero values to not generate empty lists.
183 continue
184 }
185 s, err := prettyPrintSelectEntry(value, selectKey, indent)
186 if err != nil {
187 return "", err
188 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000189 // s could still be an empty string, e.g. unset slices of structs with
190 // length of 0.
191 if s != "" {
192 selects += s + ",\n"
193 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400194 }
195
196 if len(selects) == 0 {
197 // No conditions (or all values are empty lists), so no need for a map.
198 return "", nil
199 }
200
201 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400202 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400203 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000204
205 // Handle the default condition
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400206 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000207 if err != nil {
208 return "", err
209 }
210 if s == "" {
211 // Print an explicit empty list (the default value) even if the value is
212 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400213 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000214 } else {
215 // Print the custom default value.
216 ret += s
217 ret += ",\n"
218 }
219
Jingwen Chen91220d72021-03-24 02:18:33 -0400220 ret += makeIndent(indent)
221 ret += "})"
222
223 return ret, nil
224}
225
226// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
227// with a provided key.
228func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
229 s := makeIndent(indent + 1)
230 v, err := prettyPrint(value, indent+1)
231 if err != nil {
232 return "", err
233 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000234 if v == "" {
235 return "", nil
236 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400237 s += fmt.Sprintf("\"%s\": %s", key, v)
238 return s, nil
239}