blob: c55de9541184cc8d1d28c5164620ab918cfbb769 [file] [log] [blame]
Jingwen Chen30f5aaa2020-11-19 05:38:02 -05001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package bazel
16
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000017import (
18 "fmt"
Jingwen Chen63930982021-03-24 10:04:33 -040019 "path/filepath"
Liz Kammera060c452021-03-24 10:14:47 -040020 "regexp"
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000021 "sort"
22)
Jingwen Chen5d864492021-02-24 07:20:12 -050023
Jingwen Chen73850672020-12-14 08:25:34 -050024// BazelTargetModuleProperties contain properties and metadata used for
25// Blueprint to BUILD file conversion.
26type BazelTargetModuleProperties struct {
27 // The Bazel rule class for this target.
Liz Kammerfc46bc12021-02-19 11:06:17 -050028 Rule_class string `blueprint:"mutated"`
Jingwen Chen40067de2021-01-26 21:58:43 -050029
30 // The target label for the bzl file containing the definition of the rule class.
Liz Kammerfc46bc12021-02-19 11:06:17 -050031 Bzl_load_location string `blueprint:"mutated"`
Jingwen Chen73850672020-12-14 08:25:34 -050032}
Liz Kammer356f7d42021-01-26 09:18:53 -050033
Jingwen Chenfb4692a2021-02-07 10:05:16 -050034const BazelTargetModuleNamePrefix = "__bp2build__"
35
Liz Kammera060c452021-03-24 10:14:47 -040036var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
37
Jingwen Chen38e62642021-04-19 05:00:15 +000038// Label is used to represent a Bazel compatible Label. Also stores the original
39// bp text to support string replacement.
Liz Kammer356f7d42021-01-26 09:18:53 -050040type Label struct {
Jingwen Chen38e62642021-04-19 05:00:15 +000041 // The string representation of a Bazel target label. This can be a relative
42 // or fully qualified label. These labels are used for generating BUILD
43 // files with bp2build.
44 Label string
45
46 // The original Soong/Blueprint module name that the label was derived from.
47 // This is used for replacing references to the original name with the new
48 // label, for example in genrule cmds.
49 //
50 // While there is a reversible 1:1 mapping from the module name to Bazel
51 // label with bp2build that could make computing the original module name
52 // from the label automatic, it is not the case for handcrafted targets,
53 // where modules can have a custom label mapping through the { bazel_module:
54 // { label: <label> } } property.
55 //
56 // With handcrafted labels, those modules don't go through bp2build
57 // conversion, but relies on handcrafted targets in the source tree.
58 OriginalModuleName string
Liz Kammer356f7d42021-01-26 09:18:53 -050059}
60
61// LabelList is used to represent a list of Bazel labels.
62type LabelList struct {
63 Includes []Label
64 Excludes []Label
65}
66
Liz Kammer9abd62d2021-05-21 08:37:59 -040067func (ll *LabelList) IsNil() bool {
68 return ll.Includes == nil && ll.Excludes == nil
69}
70
Jingwen Chen63930982021-03-24 10:04:33 -040071// uniqueParentDirectories returns a list of the unique parent directories for
72// all files in ll.Includes.
73func (ll *LabelList) uniqueParentDirectories() []string {
74 dirMap := map[string]bool{}
75 for _, label := range ll.Includes {
76 dirMap[filepath.Dir(label.Label)] = true
77 }
78 dirs := []string{}
79 for dir := range dirMap {
80 dirs = append(dirs, dir)
81 }
82 return dirs
83}
84
Liz Kammer356f7d42021-01-26 09:18:53 -050085// Append appends the fields of other labelList to the corresponding fields of ll.
86func (ll *LabelList) Append(other LabelList) {
87 if len(ll.Includes) > 0 || len(other.Includes) > 0 {
88 ll.Includes = append(ll.Includes, other.Includes...)
89 }
90 if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
91 ll.Excludes = append(other.Excludes, other.Excludes...)
92 }
93}
Jingwen Chen5d864492021-02-24 07:20:12 -050094
Jingwen Chened9c17d2021-04-13 07:14:55 +000095// UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
96// the slice in a sorted order.
97func UniqueSortedBazelLabels(originalLabels []Label) []Label {
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000098 uniqueLabelsSet := make(map[Label]bool)
99 for _, l := range originalLabels {
100 uniqueLabelsSet[l] = true
101 }
102 var uniqueLabels []Label
103 for l, _ := range uniqueLabelsSet {
104 uniqueLabels = append(uniqueLabels, l)
105 }
106 sort.SliceStable(uniqueLabels, func(i, j int) bool {
107 return uniqueLabels[i].Label < uniqueLabels[j].Label
108 })
109 return uniqueLabels
110}
111
Liz Kammer9abd62d2021-05-21 08:37:59 -0400112func FirstUniqueBazelLabels(originalLabels []Label) []Label {
113 var labels []Label
114 found := make(map[Label]bool, len(originalLabels))
115 for _, l := range originalLabels {
116 if _, ok := found[l]; ok {
117 continue
118 }
119 labels = append(labels, l)
120 found[l] = true
121 }
122 return labels
123}
124
125func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
126 var uniqueLabelList LabelList
127 uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
128 uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
129 return uniqueLabelList
130}
131
132func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000133 var uniqueLabelList LabelList
Jingwen Chened9c17d2021-04-13 07:14:55 +0000134 uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
135 uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000136 return uniqueLabelList
137}
138
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000139// Subtract needle from haystack
140func SubtractStrings(haystack []string, needle []string) []string {
141 // This is really a set
142 remainder := make(map[string]bool)
143
144 for _, s := range haystack {
145 remainder[s] = true
146 }
147 for _, s := range needle {
148 delete(remainder, s)
149 }
150
151 var strings []string
152 for s, _ := range remainder {
153 strings = append(strings, s)
154 }
155
156 sort.SliceStable(strings, func(i, j int) bool {
157 return strings[i] < strings[j]
158 })
159
160 return strings
161}
162
Jingwen Chen14a8bda2021-06-02 11:10:02 +0000163// Map a function over all labels in a LabelList.
164func MapLabelList(mapOver LabelList, mapFn func(string) string) LabelList {
165 var includes []Label
166 for _, inc := range mapOver.Includes {
167 mappedLabel := Label{Label: mapFn(inc.Label), OriginalModuleName: inc.OriginalModuleName}
168 includes = append(includes, mappedLabel)
169 }
170 // mapFn is not applied over excludes, but they are propagated as-is.
171 return LabelList{Includes: includes, Excludes: mapOver.Excludes}
172}
173
174// Map a function over all Labels in a LabelListAttribute
175func MapLabelListAttribute(mapOver LabelListAttribute, mapFn func(string) string) LabelListAttribute {
176 var result LabelListAttribute
177
178 result.Value = MapLabelList(mapOver.Value, mapFn)
179
Liz Kammer9abd62d2021-05-21 08:37:59 -0400180 for axis, configToLabels := range mapOver.ConfigurableValues {
181 for config, value := range configToLabels {
182 result.SetSelectValue(axis, config, MapLabelList(value, mapFn))
Jingwen Chen14a8bda2021-06-02 11:10:02 +0000183 }
184 }
185
186 return result
187}
188
Chris Parsons990c4f42021-05-25 12:10:58 -0400189// Return all needles in a given haystack, where needleFn is true for needles.
190func FilterLabelList(haystack LabelList, needleFn func(string) bool) LabelList {
191 var includes []Label
Chris Parsons990c4f42021-05-25 12:10:58 -0400192 for _, inc := range haystack.Includes {
193 if needleFn(inc.Label) {
194 includes = append(includes, inc)
195 }
196 }
Jingwen Chen14a8bda2021-06-02 11:10:02 +0000197 // needleFn is not applied over excludes, but they are propagated as-is.
Chris Parsons990c4f42021-05-25 12:10:58 -0400198 return LabelList{Includes: includes, Excludes: haystack.Excludes}
199}
200
201// Return all needles in a given haystack, where needleFn is true for needles.
202func FilterLabelListAttribute(haystack LabelListAttribute, needleFn func(string) bool) LabelListAttribute {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400203 result := MakeLabelListAttribute(FilterLabelList(haystack.Value, needleFn))
Chris Parsons990c4f42021-05-25 12:10:58 -0400204
Liz Kammer9abd62d2021-05-21 08:37:59 -0400205 for config, selects := range haystack.ConfigurableValues {
206 newSelects := make(labelListSelectValues, len(selects))
207 for k, v := range selects {
208 newSelects[k] = FilterLabelList(v, needleFn)
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400209 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400210 result.ConfigurableValues[config] = newSelects
Chris Parsons990c4f42021-05-25 12:10:58 -0400211 }
212
213 return result
214}
215
216// Subtract needle from haystack
217func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400218 result := MakeLabelListAttribute(SubtractBazelLabelList(haystack.Value, needle.Value))
Chris Parsons990c4f42021-05-25 12:10:58 -0400219
Liz Kammer9abd62d2021-05-21 08:37:59 -0400220 for config, selects := range haystack.ConfigurableValues {
221 newSelects := make(labelListSelectValues, len(selects))
222 needleSelects := needle.ConfigurableValues[config]
Chris Parsons990c4f42021-05-25 12:10:58 -0400223
Liz Kammer9abd62d2021-05-21 08:37:59 -0400224 for k, v := range selects {
225 newSelects[k] = SubtractBazelLabelList(v, needleSelects[k])
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400226 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400227 result.ConfigurableValues[config] = newSelects
Chris Parsons990c4f42021-05-25 12:10:58 -0400228 }
229
Chris Parsons990c4f42021-05-25 12:10:58 -0400230 return result
231}
232
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000233// Subtract needle from haystack
234func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
235 // This is really a set
236 remainder := make(map[Label]bool)
237
238 for _, label := range haystack {
239 remainder[label] = true
240 }
241 for _, label := range needle {
242 delete(remainder, label)
243 }
244
245 var labels []Label
246 for label, _ := range remainder {
247 labels = append(labels, label)
248 }
249
250 sort.SliceStable(labels, func(i, j int) bool {
251 return labels[i].Label < labels[j].Label
252 })
253
254 return labels
255}
256
Chris Parsons484e50a2021-05-13 15:13:04 -0400257// Appends two LabelLists, returning the combined list.
258func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
259 var result LabelList
260 result.Includes = append(a.Includes, b.Includes...)
261 result.Excludes = append(a.Excludes, b.Excludes...)
262 return result
263}
264
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000265// Subtract needle from haystack
266func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
267 var result LabelList
268 result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
269 // NOTE: Excludes are intentionally not subtracted
270 result.Excludes = haystack.Excludes
271 return result
272}
273
Jingwen Chenc1c26502021-04-05 10:35:13 +0000274type Attribute interface {
275 HasConfigurableValues() bool
276}
277
Liz Kammer9abd62d2021-05-21 08:37:59 -0400278type labelSelectValues map[string]*Label
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400279
Liz Kammer9abd62d2021-05-21 08:37:59 -0400280type configurableLabels map[ConfigurationAxis]labelSelectValues
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400281
Liz Kammer9abd62d2021-05-21 08:37:59 -0400282func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
283 if cl[axis] == nil {
284 cl[axis] = make(labelSelectValues)
285 }
286 cl[axis][config] = value
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400287}
288
289// Represents an attribute whose value is a single label
290type LabelAttribute struct {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400291 Value *Label
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400292
Liz Kammer9abd62d2021-05-21 08:37:59 -0400293 ConfigurableValues configurableLabels
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200294}
295
Liz Kammer9abd62d2021-05-21 08:37:59 -0400296// HasConfigurableValues returns whether there are configurable values set for this label.
297func (la LabelAttribute) HasConfigurableValues() bool {
298 return len(la.ConfigurableValues) > 0
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200299}
300
Liz Kammer9abd62d2021-05-21 08:37:59 -0400301// SetValue sets the base, non-configured value for the Label
302func (la *LabelAttribute) SetValue(value Label) {
303 la.SetSelectValue(NoConfigAxis, "", value)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400304}
305
Liz Kammer9abd62d2021-05-21 08:37:59 -0400306// SetSelectValue set a value for a bazel select for the given axis, config and value.
307func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
308 axis.validateConfig(config)
309 switch axis.configurationType {
310 case noConfig:
311 la.Value = &value
312 case arch, os, osArch, productVariables:
313 if la.ConfigurableValues == nil {
314 la.ConfigurableValues = make(configurableLabels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400315 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400316 la.ConfigurableValues.setValueForAxis(axis, config, &value)
317 default:
318 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
319 }
320}
321
322// SelectValue gets a value for a bazel select for the given axis and config.
323func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) Label {
324 axis.validateConfig(config)
325 switch axis.configurationType {
326 case noConfig:
327 return *la.Value
328 case arch, os, osArch, productVariables:
329 return *la.ConfigurableValues[axis][config]
330 default:
331 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
332 }
333}
334
335// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
336func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
337 keys := make([]ConfigurationAxis, 0, len(la.ConfigurableValues))
338 for k := range la.ConfigurableValues {
339 keys = append(keys, k)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400340 }
341
Liz Kammer9abd62d2021-05-21 08:37:59 -0400342 sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
343 return keys
344}
345
346// labelListSelectValues supports config-specific label_list typed Bazel attribute values.
347type labelListSelectValues map[string]LabelList
348
349func (ll labelListSelectValues) appendSelects(other labelListSelectValues) {
350 for k, v := range other {
351 l := ll[k]
352 (&l).Append(v)
353 ll[k] = l
354 }
355}
356
357// HasConfigurableValues returns whether there are configurable values within this set of selects.
358func (ll labelListSelectValues) HasConfigurableValues() bool {
359 for _, v := range ll {
360 if len(v.Includes) > 0 {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400361 return true
362 }
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400363 }
364 return false
365}
366
Jingwen Chen07027912021-03-15 06:02:43 -0400367// LabelListAttribute is used to represent a list of Bazel labels as an
368// attribute.
369type LabelListAttribute struct {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400370 // The non-configured attribute label list Value. Required.
Jingwen Chen07027912021-03-15 06:02:43 -0400371 Value LabelList
372
Liz Kammer9abd62d2021-05-21 08:37:59 -0400373 // The configured attribute label list Values. Optional
374 // a map of independent configurability axes
375 ConfigurableValues configurableLabelLists
376}
Jingwen Chen91220d72021-03-24 02:18:33 -0400377
Liz Kammer9abd62d2021-05-21 08:37:59 -0400378type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
379
380func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
381 if list.IsNil() {
382 if _, ok := cll[axis][config]; ok {
383 delete(cll[axis], config)
384 }
385 return
386 }
387 if cll[axis] == nil {
388 cll[axis] = make(labelListSelectValues)
389 }
390
391 cll[axis][config] = list
392}
393
394func (cll configurableLabelLists) Append(other configurableLabelLists) {
395 for axis, otherSelects := range other {
396 selects := cll[axis]
397 if selects == nil {
398 selects = make(labelListSelectValues, len(otherSelects))
399 }
400 selects.appendSelects(otherSelects)
401 cll[axis] = selects
402 }
Jingwen Chen07027912021-03-15 06:02:43 -0400403}
404
405// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
406func MakeLabelListAttribute(value LabelList) LabelListAttribute {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400407 return LabelListAttribute{
408 Value: value,
409 ConfigurableValues: make(configurableLabelLists),
410 }
411}
412
413func (lla *LabelListAttribute) SetValue(list LabelList) {
414 lla.SetSelectValue(NoConfigAxis, "", list)
415}
416
417// SetSelectValue set a value for a bazel select for the given axis, config and value.
418func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
419 axis.validateConfig(config)
420 switch axis.configurationType {
421 case noConfig:
422 lla.Value = list
423 case arch, os, osArch, productVariables:
424 if lla.ConfigurableValues == nil {
425 lla.ConfigurableValues = make(configurableLabelLists)
426 }
427 lla.ConfigurableValues.setValueForAxis(axis, config, list)
428 default:
429 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
430 }
431}
432
433// SelectValue gets a value for a bazel select for the given axis and config.
434func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
435 axis.validateConfig(config)
436 switch axis.configurationType {
437 case noConfig:
438 return lla.Value
439 case arch, os, osArch, productVariables:
440 return lla.ConfigurableValues[axis][config]
441 default:
442 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
443 }
444}
445
446// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
447func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
448 keys := make([]ConfigurationAxis, 0, len(lla.ConfigurableValues))
449 for k := range lla.ConfigurableValues {
450 keys = append(keys, k)
451 }
452
453 sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
454 return keys
Jingwen Chen07027912021-03-15 06:02:43 -0400455}
456
Jingwen Chened9c17d2021-04-13 07:14:55 +0000457// Append all values, including os and arch specific ones, from another
Jingwen Chen63930982021-03-24 10:04:33 -0400458// LabelListAttribute to this LabelListAttribute.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400459func (lla *LabelListAttribute) Append(other LabelListAttribute) {
460 lla.Value.Append(other.Value)
461 if lla.ConfigurableValues == nil {
462 lla.ConfigurableValues = make(configurableLabelLists)
Jingwen Chen63930982021-03-24 10:04:33 -0400463 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400464 lla.ConfigurableValues.Append(other.ConfigurableValues)
Jingwen Chen63930982021-03-24 10:04:33 -0400465}
466
Liz Kammer9abd62d2021-05-21 08:37:59 -0400467// HasConfigurableValues returns true if the attribute contains axis-specific label list values.
468func (lla LabelListAttribute) HasConfigurableValues() bool {
469 return len(lla.ConfigurableValues) > 0
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400470}
471
Jingwen Chen5d864492021-02-24 07:20:12 -0500472// StringListAttribute corresponds to the string_list Bazel attribute type with
473// support for additional metadata, like configurations.
474type StringListAttribute struct {
475 // The base value of the string list attribute.
476 Value []string
477
Liz Kammer9abd62d2021-05-21 08:37:59 -0400478 // The configured attribute label list Values. Optional
479 // a map of independent configurability axes
480 ConfigurableValues configurableStringLists
481}
Jingwen Chenc1c26502021-04-05 10:35:13 +0000482
Liz Kammer9abd62d2021-05-21 08:37:59 -0400483type configurableStringLists map[ConfigurationAxis]stringListSelectValues
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400484
Liz Kammer9abd62d2021-05-21 08:37:59 -0400485func (csl configurableStringLists) Append(other configurableStringLists) {
486 for axis, otherSelects := range other {
487 selects := csl[axis]
488 if selects == nil {
489 selects = make(stringListSelectValues, len(otherSelects))
490 }
491 selects.appendSelects(otherSelects)
492 csl[axis] = selects
493 }
494}
495
496func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
497 if csl[axis] == nil {
498 csl[axis] = make(stringListSelectValues)
499 }
500 csl[axis][config] = list
501}
502
503type stringListSelectValues map[string][]string
504
505func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
506 for k, v := range other {
507 sl[k] = append(sl[k], v...)
508 }
509}
510
511func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
512 for _, val := range sl {
513 if len(val) > 0 {
514 return true
515 }
516 }
517 return false
Jingwen Chen5d864492021-02-24 07:20:12 -0500518}
519
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000520// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
521func MakeStringListAttribute(value []string) StringListAttribute {
522 // NOTE: These strings are not necessarily unique or sorted.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400523 return StringListAttribute{
524 Value: value,
525 ConfigurableValues: make(configurableStringLists),
Jingwen Chen91220d72021-03-24 02:18:33 -0400526 }
527}
528
Liz Kammer9abd62d2021-05-21 08:37:59 -0400529// HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
530func (sla StringListAttribute) HasConfigurableValues() bool {
531 return len(sla.ConfigurableValues) > 0
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400532}
533
Jingwen Chened9c17d2021-04-13 07:14:55 +0000534// Append appends all values, including os and arch specific ones, from another
535// StringListAttribute to this StringListAttribute
Liz Kammer9abd62d2021-05-21 08:37:59 -0400536func (sla *StringListAttribute) Append(other StringListAttribute) {
537 sla.Value = append(sla.Value, other.Value...)
538 if sla.ConfigurableValues == nil {
539 sla.ConfigurableValues = make(configurableStringLists)
540 }
541 sla.ConfigurableValues.Append(other.ConfigurableValues)
542}
543
544// SetSelectValue set a value for a bazel select for the given axis, config and value.
545func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
546 axis.validateConfig(config)
547 switch axis.configurationType {
548 case noConfig:
549 sla.Value = list
550 case arch, os, osArch, productVariables:
551 if sla.ConfigurableValues == nil {
552 sla.ConfigurableValues = make(configurableStringLists)
553 }
554 sla.ConfigurableValues.setValueForAxis(axis, config, list)
555 default:
556 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
557 }
558}
559
560// SelectValue gets a value for a bazel select for the given axis and config.
561func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
562 axis.validateConfig(config)
563 switch axis.configurationType {
564 case noConfig:
565 return sla.Value
566 case arch, os, osArch, productVariables:
567 return sla.ConfigurableValues[axis][config]
568 default:
569 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
570 }
571}
572
573// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
574func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
575 keys := make([]ConfigurationAxis, 0, len(sla.ConfigurableValues))
576 for k := range sla.ConfigurableValues {
577 keys = append(keys, k)
Jingwen Chened9c17d2021-04-13 07:14:55 +0000578 }
579
Liz Kammer9abd62d2021-05-21 08:37:59 -0400580 sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
581 return keys
Jingwen Chened9c17d2021-04-13 07:14:55 +0000582}
583
Liz Kammera060c452021-03-24 10:14:47 -0400584// TryVariableSubstitution, replace string substitution formatting within each string in slice with
585// Starlark string.format compatible tag for productVariable.
586func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
587 ret := make([]string, 0, len(slice))
588 changesMade := false
589 for _, s := range slice {
590 newS, changed := TryVariableSubstitution(s, productVariable)
591 ret = append(ret, newS)
592 changesMade = changesMade || changed
593 }
594 return ret, changesMade
595}
596
597// TryVariableSubstitution, replace string substitution formatting within s with Starlark
598// string.format compatible tag for productVariable.
599func TryVariableSubstitution(s string, productVariable string) (string, bool) {
Liz Kammerba7a9c52021-05-26 08:45:30 -0400600 sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
Liz Kammera060c452021-03-24 10:14:47 -0400601 return sub, s != sub
602}