blob: 60f6330e3e75a3e28ce285b7c242cdc2c008d1b8 [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 Kammer9abd62d2021-05-21 08:37:59 -040020 var ret []selects
21 for _, axis := range list.SortedConfigurationAxes() {
22 configToLists := list.ConfigurableValues[axis]
23 archSelects := map[string]reflect.Value{}
24 for config, labels := range configToLists {
25 selectKey := axis.SelectKey(config)
26 archSelects[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040027 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040028 if len(archSelects) > 0 {
29 ret = append(ret, archSelects)
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040030 }
31 }
32
Liz Kammer9abd62d2021-05-21 08:37:59 -040033 return value, ret
Jingwen Chenc1c26502021-04-05 10:35:13 +000034}
35
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040036func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040037 value := reflect.ValueOf(label.Value)
38 if !label.HasConfigurableValues() {
39 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020040 }
41
Liz Kammer9abd62d2021-05-21 08:37:59 -040042 ret := selects{}
43 for _, axis := range label.SortedConfigurationAxes() {
44 configToLabels := label.ConfigurableValues[axis]
45 for config, labels := range configToLabels {
46 selectKey := axis.SelectKey(config)
47 ret[selectKey] = reflect.ValueOf(labels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040048 }
49 }
50
Liz Kammer9abd62d2021-05-21 08:37:59 -040051 return value, []selects{ret}
Lukacs T. Berki1353e592021-04-30 15:35:09 +020052}
53
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040054func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000055 value := reflect.ValueOf(list.Value.Includes)
Liz Kammer2b07ec72021-05-26 15:08:27 -040056 var ret []selects
Liz Kammer9abd62d2021-05-21 08:37:59 -040057 for _, axis := range list.SortedConfigurationAxes() {
58 configToLabels := list.ConfigurableValues[axis]
59 if !configToLabels.HasConfigurableValues() {
60 continue
Liz Kammer2b07ec72021-05-26 15:08:27 -040061 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040062 archSelects := map[string]reflect.Value{}
63 for config, labels := range configToLabels {
64 selectKey := axis.SelectKey(config)
65 if use, value := labelListSelectValue(selectKey, labels); use {
66 archSelects[selectKey] = value
Liz Kammer2b07ec72021-05-26 15:08:27 -040067 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040068 }
Liz Kammer9abd62d2021-05-21 08:37:59 -040069 if len(archSelects) > 0 {
70 ret = append(ret, archSelects)
Liz Kammer2b07ec72021-05-26 15:08:27 -040071 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000072 }
73
Liz Kammer2b07ec72021-05-26 15:08:27 -040074 return value, ret
75}
76
77func labelListSelectValue(selectKey string, list bazel.LabelList) (bool, reflect.Value) {
78 if selectKey == bazel.ConditionsDefaultSelectKey || len(list.Includes) > 0 {
79 return true, reflect.ValueOf(list.Includes)
80 } else if len(list.Excludes) > 0 {
81 // if there is still an excludes -- we need to have an empty list for this select & use the
82 // value in conditions default Includes
83 return true, reflect.ValueOf([]string{})
84 }
85 return false, reflect.Zero(reflect.TypeOf([]string{}))
Jingwen Chenc1c26502021-04-05 10:35:13 +000086}
87
88// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
89// select statements.
90func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
91 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040092 var configurableAttrs []selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +020093 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +000094 switch list := v.(type) {
95 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040096 value, configurableAttrs = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +020097 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +000098 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040099 value, configurableAttrs = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200100 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200101 case bazel.LabelAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400102 value, configurableAttrs = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200103 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000104 default:
105 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
106 }
107
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400108 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200109 ret := ""
110 if value.Kind() != reflect.Invalid {
111 s, err := prettyPrint(value, indent)
112 if err != nil {
113 return ret, err
114 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000115
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200116 ret += s
117 }
Jingwen Chen63930982021-03-24 10:04:33 -0400118 // Convenience function to append selects components to an attribute value.
119 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
120 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
121 if err != nil {
122 return "", err
123 }
124 if s != "" && selectMap != "" {
125 s += " + "
126 }
127 s += selectMap
128
129 return s, nil
130 }
131
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400132 for _, configurableAttr := range configurableAttrs {
133 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
134 if err != nil {
135 return "", err
136 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400137 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400138
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400139 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400140}
141
142// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
143// to construct a select map for any kind of attribute type.
144func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000145 if selectMap == nil {
146 return "", nil
147 }
148
Jingwen Chene32e9e02021-04-23 09:17:24 +0000149 // addConditionsDefault := false
Jingwen Chene32e9e02021-04-23 09:17:24 +0000150
Jingwen Chen91220d72021-03-24 02:18:33 -0400151 var selects string
152 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400153 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000154 // Handle default condition later.
155 continue
156 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400157 value := selectMap[selectKey]
158 if isZero(value) {
159 // Ignore zero values to not generate empty lists.
160 continue
161 }
162 s, err := prettyPrintSelectEntry(value, selectKey, indent)
163 if err != nil {
164 return "", err
165 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000166 // s could still be an empty string, e.g. unset slices of structs with
167 // length of 0.
168 if s != "" {
169 selects += s + ",\n"
170 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400171 }
172
173 if len(selects) == 0 {
174 // No conditions (or all values are empty lists), so no need for a map.
175 return "", nil
176 }
177
178 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400179 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400180 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000181
182 // Handle the default condition
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400183 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000184 if err != nil {
185 return "", err
186 }
187 if s == "" {
188 // Print an explicit empty list (the default value) even if the value is
189 // empty, to avoid errors about not finding a configuration that matches.
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400190 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000191 } else {
192 // Print the custom default value.
193 ret += s
194 ret += ",\n"
195 }
196
Jingwen Chen91220d72021-03-24 02:18:33 -0400197 ret += makeIndent(indent)
198 ret += "})"
199
200 return ret, nil
201}
202
203// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
204// with a provided key.
205func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
206 s := makeIndent(indent + 1)
207 v, err := prettyPrint(value, indent+1)
208 if err != nil {
209 return "", err
210 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000211 if v == "" {
212 return "", nil
213 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400214 s += fmt.Sprintf("\"%s\": %s", key, v)
215 return s, nil
216}