blob: 2b8f6cc2ec5cb2427ef70c26afd46fc8bb1bd369 [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) {
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020034 var value reflect.Value
35 var archSelects selects
36
37 if label.HasConfigurableValues() {
38 archSelects = map[string]reflect.Value{}
39 for arch, selectKey := range bazel.PlatformArchMap {
40 archSelects[selectKey] = reflect.ValueOf(label.GetValueForArch(arch))
41 }
42 } else {
43 value = reflect.ValueOf(label.Value)
44 }
45
46 return value, archSelects, nil
Lukacs T. Berki1353e592021-04-30 15:35:09 +020047}
48
Jingwen Chenc1c26502021-04-05 10:35:13 +000049func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
50 value := reflect.ValueOf(list.Value.Includes)
51 if !list.HasConfigurableValues() {
52 return value, nil, nil
53 }
54
55 archSelects := map[string]reflect.Value{}
56 for arch, selectKey := range bazel.PlatformArchMap {
57 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
58 }
59
60 osSelects := map[string]reflect.Value{}
61 for os, selectKey := range bazel.PlatformOsMap {
62 osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
63 }
64
65 return value, archSelects, osSelects
66}
67
68// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
69// select statements.
70func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
71 var value reflect.Value
72 var archSelects, osSelects selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +020073 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +000074 switch list := v.(type) {
75 case bazel.StringListAttribute:
76 value, archSelects, osSelects = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020077 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +000078 case bazel.LabelListAttribute:
79 value, archSelects, osSelects = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020080 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +020081 case bazel.LabelAttribute:
82 value, archSelects, osSelects = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020083 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +000084 default:
85 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
86 }
87
Lukacs T. Berki598dd002021-05-05 09:00:01 +020088 ret := ""
89 if value.Kind() != reflect.Invalid {
90 s, err := prettyPrint(value, indent)
91 if err != nil {
92 return ret, err
93 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000094
Lukacs T. Berki598dd002021-05-05 09:00:01 +020095 ret += s
96 }
Jingwen Chen63930982021-03-24 10:04:33 -040097 // Convenience function to append selects components to an attribute value.
98 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
99 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
100 if err != nil {
101 return "", err
102 }
103 if s != "" && selectMap != "" {
104 s += " + "
105 }
106 s += selectMap
107
108 return s, nil
109 }
110
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200111 ret, err := appendSelects(archSelects, defaultSelectValue, ret)
Jingwen Chen91220d72021-03-24 02:18:33 -0400112 if err != nil {
113 return "", err
114 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400115
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200116 ret, err = appendSelects(osSelects, defaultSelectValue, ret)
Jingwen Chenc1c26502021-04-05 10:35:13 +0000117 return ret, err
Jingwen Chen91220d72021-03-24 02:18:33 -0400118}
119
120// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
121// to construct a select map for any kind of attribute type.
122func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000123 if selectMap == nil {
124 return "", nil
125 }
126
Jingwen Chene32e9e02021-04-23 09:17:24 +0000127 // addConditionsDefault := false
128 conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT]
129
Jingwen Chen91220d72021-03-24 02:18:33 -0400130 var selects string
131 for _, selectKey := range android.SortedStringKeys(selectMap) {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000132 if selectKey == conditionsDefaultKey {
133 // Handle default condition later.
134 continue
135 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400136 value := selectMap[selectKey]
137 if isZero(value) {
138 // Ignore zero values to not generate empty lists.
139 continue
140 }
141 s, err := prettyPrintSelectEntry(value, selectKey, indent)
142 if err != nil {
143 return "", err
144 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000145 // s could still be an empty string, e.g. unset slices of structs with
146 // length of 0.
147 if s != "" {
148 selects += s + ",\n"
149 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400150 }
151
152 if len(selects) == 0 {
153 // No conditions (or all values are empty lists), so no need for a map.
154 return "", nil
155 }
156
157 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400158 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400159 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000160
161 // Handle the default condition
162 s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent)
163 if err != nil {
164 return "", err
165 }
166 if s == "" {
167 // Print an explicit empty list (the default value) even if the value is
168 // empty, to avoid errors about not finding a configuration that matches.
169 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
170 } else {
171 // Print the custom default value.
172 ret += s
173 ret += ",\n"
174 }
175
Jingwen Chen91220d72021-03-24 02:18:33 -0400176 ret += makeIndent(indent)
177 ret += "})"
178
179 return ret, nil
180}
181
182// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
183// with a provided key.
184func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
185 s := makeIndent(indent + 1)
186 v, err := prettyPrint(value, indent+1)
187 if err != nil {
188 return "", err
189 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000190 if v == "" {
191 return "", nil
192 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400193 s += fmt.Sprintf("\"%s\": %s", key, v)
194 return s, nil
195}