blob: 42ff1972616979bfd4a7e0bef8edd6ace062c817 [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 }
Liz Kammer2b07ec72021-05-26 15:08:27 -040083 var ret []selects
Jingwen Chenc1c26502021-04-05 10:35:13 +000084
85 archSelects := map[string]reflect.Value{}
86 for arch, selectKey := range bazel.PlatformArchMap {
Liz Kammer2b07ec72021-05-26 15:08:27 -040087 if use, value := labelListSelectValue(selectKey, list.GetValueForArch(arch)); use {
88 archSelects[selectKey] = value
89 }
90 }
91 if len(archSelects) > 0 {
92 ret = append(ret, archSelects)
Jingwen Chenc1c26502021-04-05 10:35:13 +000093 }
94
95 osSelects := map[string]reflect.Value{}
Liz Kammer2b07ec72021-05-26 15:08:27 -040096 osArchSelects := []selects{}
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040097 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
98 selectKey := bazel.PlatformOsMap[os]
Liz Kammer2b07ec72021-05-26 15:08:27 -040099 if use, value := labelListSelectValue(selectKey, list.GetOsValueForTarget(os)); use {
100 osSelects[selectKey] = value
101 }
102 selects := make(map[string]reflect.Value)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400103 // TODO(b/187530594): Should we also check arch=CONDITIOSN_DEFAULT? (not in AllArches)
104 for _, arch := range bazel.AllArches {
105 target := os + "_" + arch
106 selectKey := bazel.PlatformTargetMap[target]
Liz Kammer2b07ec72021-05-26 15:08:27 -0400107 if use, value := labelListSelectValue(selectKey, list.GetOsArchValueForTarget(os, arch)); use {
108 selects[selectKey] = value
109 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400110 }
Liz Kammer2b07ec72021-05-26 15:08:27 -0400111 if len(selects) > 0 {
112 osArchSelects = append(osArchSelects, selects)
113 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000114 }
Liz Kammer2b07ec72021-05-26 15:08:27 -0400115 if len(osSelects) > 0 {
116 ret = append(ret, osSelects)
117 }
118 ret = append(ret, osArchSelects...)
Jingwen Chenc1c26502021-04-05 10:35:13 +0000119
Liz Kammer2b07ec72021-05-26 15:08:27 -0400120 return value, ret
121}
122
123func labelListSelectValue(selectKey string, list bazel.LabelList) (bool, reflect.Value) {
124 if selectKey == bazel.ConditionsDefaultSelectKey || len(list.Includes) > 0 {
125 return true, reflect.ValueOf(list.Includes)
126 } else if len(list.Excludes) > 0 {
127 // if there is still an excludes -- we need to have an empty list for this select & use the
128 // value in conditions default Includes
129 return true, reflect.ValueOf([]string{})
130 }
131 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +0000132}
133
134// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
135// select statements.
136func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
137 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400138 var configurableAttrs []selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200139 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +0000140 switch list := v.(type) {
141 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400142 value, configurableAttrs = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200143 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000144 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400145 value, configurableAttrs = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200146 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200147 case bazel.LabelAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400148 value, configurableAttrs = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200149 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000150 default:
151 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
152 }
153
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400154 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200155 ret := ""
156 if value.Kind() != reflect.Invalid {
157 s, err := prettyPrint(value, indent)
158 if err != nil {
159 return ret, err
160 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000161
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200162 ret += s
163 }
Jingwen Chen63930982021-03-24 10:04:33 -0400164 // Convenience function to append selects components to an attribute value.
165 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
166 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
167 if err != nil {
168 return "", err
169 }
170 if s != "" && selectMap != "" {
171 s += " + "
172 }
173 s += selectMap
174
175 return s, nil
176 }
177
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400178 for _, configurableAttr := range configurableAttrs {
179 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
180 if err != nil {
181 return "", err
182 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400183 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400184
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400185 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400186}
187
188// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
189// to construct a select map for any kind of attribute type.
190func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000191 if selectMap == nil {
192 return "", nil
193 }
194
Jingwen Chene32e9e02021-04-23 09:17:24 +0000195 // addConditionsDefault := false
Jingwen Chene32e9e02021-04-23 09:17:24 +0000196
Jingwen Chen91220d72021-03-24 02:18:33 -0400197 var selects string
198 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400199 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000200 // Handle default condition later.
201 continue
202 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400203 value := selectMap[selectKey]
204 if isZero(value) {
205 // Ignore zero values to not generate empty lists.
206 continue
207 }
208 s, err := prettyPrintSelectEntry(value, selectKey, indent)
209 if err != nil {
210 return "", err
211 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000212 // s could still be an empty string, e.g. unset slices of structs with
213 // length of 0.
214 if s != "" {
215 selects += s + ",\n"
216 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400217 }
218
219 if len(selects) == 0 {
220 // No conditions (or all values are empty lists), so no need for a map.
221 return "", nil
222 }
223
224 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400225 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400226 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000227
228 // Handle the default condition
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400229 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000230 if err != nil {
231 return "", err
232 }
233 if s == "" {
234 // Print an explicit empty list (the default value) even if the value is
235 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400236 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000237 } else {
238 // Print the custom default value.
239 ret += s
240 ret += ",\n"
241 }
242
Jingwen Chen91220d72021-03-24 02:18:33 -0400243 ret += makeIndent(indent)
244 ret += "})"
245
246 return ret, nil
247}
248
249// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
250// with a provided key.
251func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
252 s := makeIndent(indent + 1)
253 v, err := prettyPrint(value, indent+1)
254 if err != nil {
255 return "", err
256 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000257 if v == "" {
258 return "", nil
259 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400260 s += fmt.Sprintf("\"%s\": %s", key, v)
261 return s, nil
262}