blob: 95a2747d62ad2b67f568916cb71c2b97f0b24be9 [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
14func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
15 value := reflect.ValueOf(list.Value)
16 if !list.HasConfigurableValues() {
17 return value, nil, nil
Jingwen Chen5d864492021-02-24 07:20:12 -050018 }
Jingwen Chen91220d72021-03-24 02:18:33 -040019
Jingwen Chen91220d72021-03-24 02:18:33 -040020 archSelects := map[string]reflect.Value{}
21 for arch, selectKey := range bazel.PlatformArchMap {
Jingwen Chenc1c26502021-04-05 10:35:13 +000022 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
Jingwen Chen91220d72021-03-24 02:18:33 -040023 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000024
25 osSelects := map[string]reflect.Value{}
26 for os, selectKey := range bazel.PlatformOsMap {
27 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
28 }
29
30 return value, archSelects, osSelects
31}
32
Lukacs T. Berki1353e592021-04-30 15:35:09 +020033func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects) {
34 value := reflect.ValueOf(label.Value)
35 return value, nil, nil
36}
37
Jingwen Chenc1c26502021-04-05 10:35:13 +000038func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
39 value := reflect.ValueOf(list.Value.Includes)
40 if !list.HasConfigurableValues() {
41 return value, nil, nil
42 }
43
44 archSelects := map[string]reflect.Value{}
45 for arch, selectKey := range bazel.PlatformArchMap {
46 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
47 }
48
49 osSelects := map[string]reflect.Value{}
50 for os, selectKey := range bazel.PlatformOsMap {
51 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
52 }
53
54 return value, archSelects, osSelects
55}
56
57// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
58// select statements.
59func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
60 var value reflect.Value
61 var archSelects, osSelects selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +020062 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +000063 switch list := v.(type) {
64 case bazel.StringListAttribute:
65 value, archSelects, osSelects = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020066 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +000067 case bazel.LabelListAttribute:
68 value, archSelects, osSelects = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020069 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +020070 case bazel.LabelAttribute:
71 value, archSelects, osSelects = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020072 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +000073 default:
74 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
75 }
76
Lukacs T. Berki598dd002021-05-05 09:00:01 +020077 ret := ""
78 if value.Kind() != reflect.Invalid {
79 s, err := prettyPrint(value, indent)
80 if err != nil {
81 return ret, err
82 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000083
Lukacs T. Berki598dd002021-05-05 09:00:01 +020084 ret += s
85 }
Jingwen Chen63930982021-03-24 10:04:33 -040086 // Convenience function to append selects components to an attribute value.
87 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
88 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
89 if err != nil {
90 return "", err
91 }
92 if s != "" && selectMap != "" {
93 s += " + "
94 }
95 s += selectMap
96
97 return s, nil
98 }
99
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200100 ret, err := appendSelects(archSelects, defaultSelectValue, ret)
Jingwen Chen91220d72021-03-24 02:18:33 -0400101 if err != nil {
102 return "", err
103 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400104
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200105 ret, err = appendSelects(osSelects, defaultSelectValue, ret)
Jingwen Chenc1c26502021-04-05 10:35:13 +0000106 return ret, err
Jingwen Chen91220d72021-03-24 02:18:33 -0400107}
108
109// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
110// to construct a select map for any kind of attribute type.
111func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000112 if selectMap == nil {
113 return "", nil
114 }
115
Jingwen Chene32e9e02021-04-23 09:17:24 +0000116 // addConditionsDefault := false
117 conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT]
118
Jingwen Chen91220d72021-03-24 02:18:33 -0400119 var selects string
120 for _, selectKey := range android.SortedStringKeys(selectMap) {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000121 if selectKey == conditionsDefaultKey {
122 // Handle default condition later.
123 continue
124 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400125 value := selectMap[selectKey]
126 if isZero(value) {
127 // Ignore zero values to not generate empty lists.
128 continue
129 }
130 s, err := prettyPrintSelectEntry(value, selectKey, indent)
131 if err != nil {
132 return "", err
133 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000134 // s could still be an empty string, e.g. unset slices of structs with
135 // length of 0.
136 if s != "" {
137 selects += s + ",\n"
138 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400139 }
140
141 if len(selects) == 0 {
142 // No conditions (or all values are empty lists), so no need for a map.
143 return "", nil
144 }
145
146 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400147 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400148 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000149
150 // Handle the default condition
151 s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent)
152 if err != nil {
153 return "", err
154 }
155 if s == "" {
156 // Print an explicit empty list (the default value) even if the value is
157 // empty, to avoid errors about not finding a configuration that matches.
158 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
159 } else {
160 // Print the custom default value.
161 ret += s
162 ret += ",\n"
163 }
164
Jingwen Chen91220d72021-03-24 02:18:33 -0400165 ret += makeIndent(indent)
166 ret += "})"
167
168 return ret, nil
169}
170
171// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
172// with a provided key.
173func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
174 s := makeIndent(indent + 1)
175 v, err := prettyPrint(value, indent+1)
176 if err != nil {
177 return "", err
178 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000179 if v == "" {
180 return "", nil
181 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400182 s += fmt.Sprintf("\"%s\": %s", key, v)
183 return s, nil
184}