blob: 3cdc994373fdfa9eac1e93b2581a98246cdf1b42 [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{}
30 for os, selectKey := range bazel.PlatformOsMap {
31 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
32 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040033 if len(osSelects) > 0 {
34 selectValues = append(selectValues, osSelects)
35 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000036
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040037 for _, pv := range list.ProductValues {
38 s := make(selects)
39 if len(pv.Values) > 0 {
40 s[pv.SelectKey()] = reflect.ValueOf(pv.Values)
41 s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{})
42 selectValues = append(selectValues, s)
43 }
44 }
45
46 return value, selectValues
Jingwen Chenc1c26502021-04-05 10:35:13 +000047}
48
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040049func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020050 var value reflect.Value
51 var archSelects selects
52
53 if label.HasConfigurableValues() {
54 archSelects = map[string]reflect.Value{}
55 for arch, selectKey := range bazel.PlatformArchMap {
56 archSelects[selectKey] = reflect.ValueOf(label.GetValueForArch(arch))
57 }
58 } else {
59 value = reflect.ValueOf(label.Value)
60 }
61
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040062 return value, []selects{archSelects}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020063}
64
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040065func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000066 value := reflect.ValueOf(list.Value.Includes)
67 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040068 return value, []selects{}
Jingwen Chenc1c26502021-04-05 10:35:13 +000069 }
70
71 archSelects := map[string]reflect.Value{}
72 for arch, selectKey := range bazel.PlatformArchMap {
73 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
74 }
75
76 osSelects := map[string]reflect.Value{}
77 for os, selectKey := range bazel.PlatformOsMap {
78 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
79 }
80
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040081 return value, []selects{archSelects, osSelects}
Jingwen Chenc1c26502021-04-05 10:35:13 +000082}
83
84// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
85// select statements.
86func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
87 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040088 var configurableAttrs []selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +020089 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +000090 switch list := v.(type) {
91 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040092 value, configurableAttrs = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020093 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +000094 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040095 value, configurableAttrs = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020096 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +020097 case bazel.LabelAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040098 value, configurableAttrs = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020099 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000100 default:
101 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
102 }
103
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400104 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200105 ret := ""
106 if value.Kind() != reflect.Invalid {
107 s, err := prettyPrint(value, indent)
108 if err != nil {
109 return ret, err
110 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000111
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200112 ret += s
113 }
Jingwen Chen63930982021-03-24 10:04:33 -0400114 // Convenience function to append selects components to an attribute value.
115 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
116 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
117 if err != nil {
118 return "", err
119 }
120 if s != "" && selectMap != "" {
121 s += " + "
122 }
123 s += selectMap
124
125 return s, nil
126 }
127
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400128 for _, configurableAttr := range configurableAttrs {
129 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
130 if err != nil {
131 return "", err
132 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400133 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400134
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400135 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400136}
137
138// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
139// to construct a select map for any kind of attribute type.
140func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000141 if selectMap == nil {
142 return "", nil
143 }
144
Jingwen Chene32e9e02021-04-23 09:17:24 +0000145 // addConditionsDefault := false
Jingwen Chene32e9e02021-04-23 09:17:24 +0000146
Jingwen Chen91220d72021-03-24 02:18:33 -0400147 var selects string
148 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400149 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000150 // Handle default condition later.
151 continue
152 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400153 value := selectMap[selectKey]
154 if isZero(value) {
155 // Ignore zero values to not generate empty lists.
156 continue
157 }
158 s, err := prettyPrintSelectEntry(value, selectKey, indent)
159 if err != nil {
160 return "", err
161 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000162 // s could still be an empty string, e.g. unset slices of structs with
163 // length of 0.
164 if s != "" {
165 selects += s + ",\n"
166 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400167 }
168
169 if len(selects) == 0 {
170 // No conditions (or all values are empty lists), so no need for a map.
171 return "", nil
172 }
173
174 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400175 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400176 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000177
178 // Handle the default condition
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400179 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000180 if err != nil {
181 return "", err
182 }
183 if s == "" {
184 // Print an explicit empty list (the default value) even if the value is
185 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400186 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000187 } else {
188 // Print the custom default value.
189 ret += s
190 ret += ",\n"
191 }
192
Jingwen Chen91220d72021-03-24 02:18:33 -0400193 ret += makeIndent(indent)
194 ret += "})"
195
196 return ret, nil
197}
198
199// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
200// with a provided key.
201func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
202 s := makeIndent(indent + 1)
203 v, err := prettyPrint(value, indent+1)
204 if err != nil {
205 return "", err
206 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000207 if v == "" {
208 return "", nil
209 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400210 s += fmt.Sprintf("\"%s\": %s", key, v)
211 return s, nil
212}