51f8c39261
- If no system_shared_libs is specified, bp2build writes no attribute value. In this case, the bazel library macros determine the correct default behavior. - If any system_shared_libs is specified for any variant, then bp2build writes the value verbatim. This includes if an empty list is specified, as this should override defaulting behavior. Note this defaulting behavior is incomplete and will be incorrect in corner cases. For example, if, in an Android.bp, system_shared_libs is specified for os.linux_bionic but not for os.android, then the bazel default for os.android will be incorrect. However, there are no current modules in AOSP which fit this case. As a related fix, supports static struct for cc_library_static. Also, removes some elements from the bp2build denylist. Test: mixed_droid CI Change-Id: Iee5feeaaf05e8e7209c7a90c913173832ad7bf91
764 lines
24 KiB
Go
764 lines
24 KiB
Go
// Copyright 2020 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package bazel
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// BazelTargetModuleProperties contain properties and metadata used for
|
|
// Blueprint to BUILD file conversion.
|
|
type BazelTargetModuleProperties struct {
|
|
// The Bazel rule class for this target.
|
|
Rule_class string `blueprint:"mutated"`
|
|
|
|
// The target label for the bzl file containing the definition of the rule class.
|
|
Bzl_load_location string `blueprint:"mutated"`
|
|
}
|
|
|
|
const BazelTargetModuleNamePrefix = "__bp2build__"
|
|
|
|
func StripNamePrefix(moduleName string) string {
|
|
return strings.TrimPrefix(moduleName, BazelTargetModuleNamePrefix)
|
|
}
|
|
|
|
var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
|
|
|
|
// Label is used to represent a Bazel compatible Label. Also stores the original
|
|
// bp text to support string replacement.
|
|
type Label struct {
|
|
// The string representation of a Bazel target label. This can be a relative
|
|
// or fully qualified label. These labels are used for generating BUILD
|
|
// files with bp2build.
|
|
Label string
|
|
|
|
// The original Soong/Blueprint module name that the label was derived from.
|
|
// This is used for replacing references to the original name with the new
|
|
// label, for example in genrule cmds.
|
|
//
|
|
// While there is a reversible 1:1 mapping from the module name to Bazel
|
|
// label with bp2build that could make computing the original module name
|
|
// from the label automatic, it is not the case for handcrafted targets,
|
|
// where modules can have a custom label mapping through the { bazel_module:
|
|
// { label: <label> } } property.
|
|
//
|
|
// With handcrafted labels, those modules don't go through bp2build
|
|
// conversion, but relies on handcrafted targets in the source tree.
|
|
OriginalModuleName string
|
|
}
|
|
|
|
// LabelList is used to represent a list of Bazel labels.
|
|
type LabelList struct {
|
|
Includes []Label
|
|
Excludes []Label
|
|
}
|
|
|
|
func (ll *LabelList) Equals(other LabelList) bool {
|
|
if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
|
|
return false
|
|
}
|
|
for i, _ := range ll.Includes {
|
|
if ll.Includes[i] != other.Includes[i] {
|
|
return false
|
|
}
|
|
}
|
|
for i, _ := range ll.Excludes {
|
|
if ll.Excludes[i] != other.Excludes[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (ll *LabelList) IsNil() bool {
|
|
return ll.Includes == nil && ll.Excludes == nil
|
|
}
|
|
|
|
func (ll *LabelList) deepCopy() LabelList {
|
|
return LabelList{
|
|
Includes: ll.Includes[:],
|
|
Excludes: ll.Excludes[:],
|
|
}
|
|
}
|
|
|
|
// uniqueParentDirectories returns a list of the unique parent directories for
|
|
// all files in ll.Includes.
|
|
func (ll *LabelList) uniqueParentDirectories() []string {
|
|
dirMap := map[string]bool{}
|
|
for _, label := range ll.Includes {
|
|
dirMap[filepath.Dir(label.Label)] = true
|
|
}
|
|
dirs := []string{}
|
|
for dir := range dirMap {
|
|
dirs = append(dirs, dir)
|
|
}
|
|
return dirs
|
|
}
|
|
|
|
// Append appends the fields of other labelList to the corresponding fields of ll.
|
|
func (ll *LabelList) Append(other LabelList) {
|
|
if len(ll.Includes) > 0 || len(other.Includes) > 0 {
|
|
ll.Includes = append(ll.Includes, other.Includes...)
|
|
}
|
|
if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
|
|
ll.Excludes = append(other.Excludes, other.Excludes...)
|
|
}
|
|
}
|
|
|
|
// UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
|
|
// the slice in a sorted order.
|
|
func UniqueSortedBazelLabels(originalLabels []Label) []Label {
|
|
uniqueLabelsSet := make(map[Label]bool)
|
|
for _, l := range originalLabels {
|
|
uniqueLabelsSet[l] = true
|
|
}
|
|
var uniqueLabels []Label
|
|
for l, _ := range uniqueLabelsSet {
|
|
uniqueLabels = append(uniqueLabels, l)
|
|
}
|
|
sort.SliceStable(uniqueLabels, func(i, j int) bool {
|
|
return uniqueLabels[i].Label < uniqueLabels[j].Label
|
|
})
|
|
return uniqueLabels
|
|
}
|
|
|
|
func FirstUniqueBazelLabels(originalLabels []Label) []Label {
|
|
var labels []Label
|
|
found := make(map[Label]bool, len(originalLabels))
|
|
for _, l := range originalLabels {
|
|
if _, ok := found[l]; ok {
|
|
continue
|
|
}
|
|
labels = append(labels, l)
|
|
found[l] = true
|
|
}
|
|
return labels
|
|
}
|
|
|
|
func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
|
|
var uniqueLabelList LabelList
|
|
uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
|
|
uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
|
|
return uniqueLabelList
|
|
}
|
|
|
|
func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
|
|
var uniqueLabelList LabelList
|
|
uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
|
|
uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
|
|
return uniqueLabelList
|
|
}
|
|
|
|
// Subtract needle from haystack
|
|
func SubtractStrings(haystack []string, needle []string) []string {
|
|
// This is really a set
|
|
remainder := make(map[string]bool)
|
|
|
|
for _, s := range haystack {
|
|
remainder[s] = true
|
|
}
|
|
for _, s := range needle {
|
|
delete(remainder, s)
|
|
}
|
|
|
|
var strings []string
|
|
for s, _ := range remainder {
|
|
strings = append(strings, s)
|
|
}
|
|
|
|
sort.SliceStable(strings, func(i, j int) bool {
|
|
return strings[i] < strings[j]
|
|
})
|
|
|
|
return strings
|
|
}
|
|
|
|
// Map a function over all labels in a LabelList.
|
|
func MapLabelList(mapOver LabelList, mapFn func(string) string) LabelList {
|
|
var includes []Label
|
|
for _, inc := range mapOver.Includes {
|
|
mappedLabel := Label{Label: mapFn(inc.Label), OriginalModuleName: inc.OriginalModuleName}
|
|
includes = append(includes, mappedLabel)
|
|
}
|
|
// mapFn is not applied over excludes, but they are propagated as-is.
|
|
return LabelList{Includes: includes, Excludes: mapOver.Excludes}
|
|
}
|
|
|
|
// Map a function over all Labels in a LabelListAttribute
|
|
func MapLabelListAttribute(mapOver LabelListAttribute, mapFn func(string) string) LabelListAttribute {
|
|
var result LabelListAttribute
|
|
|
|
result.Value = MapLabelList(mapOver.Value, mapFn)
|
|
|
|
for axis, configToLabels := range mapOver.ConfigurableValues {
|
|
for config, value := range configToLabels {
|
|
result.SetSelectValue(axis, config, MapLabelList(value, mapFn))
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Return all needles in a given haystack, where needleFn is true for needles.
|
|
func FilterLabelList(haystack LabelList, needleFn func(string) bool) LabelList {
|
|
var includes []Label
|
|
for _, inc := range haystack.Includes {
|
|
if needleFn(inc.Label) {
|
|
includes = append(includes, inc)
|
|
}
|
|
}
|
|
// needleFn is not applied over excludes, but they are propagated as-is.
|
|
return LabelList{Includes: includes, Excludes: haystack.Excludes}
|
|
}
|
|
|
|
// Return all needles in a given haystack, where needleFn is true for needles.
|
|
func FilterLabelListAttribute(haystack LabelListAttribute, needleFn func(string) bool) LabelListAttribute {
|
|
result := MakeLabelListAttribute(FilterLabelList(haystack.Value, needleFn))
|
|
|
|
for config, selects := range haystack.ConfigurableValues {
|
|
newSelects := make(labelListSelectValues, len(selects))
|
|
for k, v := range selects {
|
|
newSelects[k] = FilterLabelList(v, needleFn)
|
|
}
|
|
result.ConfigurableValues[config] = newSelects
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Subtract needle from haystack
|
|
func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
|
|
result := MakeLabelListAttribute(SubtractBazelLabelList(haystack.Value, needle.Value))
|
|
|
|
for config, selects := range haystack.ConfigurableValues {
|
|
newSelects := make(labelListSelectValues, len(selects))
|
|
needleSelects := needle.ConfigurableValues[config]
|
|
|
|
for k, v := range selects {
|
|
newSelects[k] = SubtractBazelLabelList(v, needleSelects[k])
|
|
}
|
|
result.ConfigurableValues[config] = newSelects
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Subtract needle from haystack
|
|
func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
|
|
// This is really a set
|
|
remainder := make(map[Label]bool)
|
|
|
|
for _, label := range haystack {
|
|
remainder[label] = true
|
|
}
|
|
for _, label := range needle {
|
|
delete(remainder, label)
|
|
}
|
|
|
|
var labels []Label
|
|
for label, _ := range remainder {
|
|
labels = append(labels, label)
|
|
}
|
|
|
|
sort.SliceStable(labels, func(i, j int) bool {
|
|
return labels[i].Label < labels[j].Label
|
|
})
|
|
|
|
return labels
|
|
}
|
|
|
|
// Appends two LabelLists, returning the combined list.
|
|
func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
|
|
var result LabelList
|
|
result.Includes = append(a.Includes, b.Includes...)
|
|
result.Excludes = append(a.Excludes, b.Excludes...)
|
|
return result
|
|
}
|
|
|
|
// Subtract needle from haystack
|
|
func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
|
|
var result LabelList
|
|
result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
|
|
// NOTE: Excludes are intentionally not subtracted
|
|
result.Excludes = haystack.Excludes
|
|
return result
|
|
}
|
|
|
|
type Attribute interface {
|
|
HasConfigurableValues() bool
|
|
}
|
|
|
|
type labelSelectValues map[string]*Label
|
|
|
|
type configurableLabels map[ConfigurationAxis]labelSelectValues
|
|
|
|
func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
|
|
if cl[axis] == nil {
|
|
cl[axis] = make(labelSelectValues)
|
|
}
|
|
cl[axis][config] = value
|
|
}
|
|
|
|
// Represents an attribute whose value is a single label
|
|
type LabelAttribute struct {
|
|
Value *Label
|
|
|
|
ConfigurableValues configurableLabels
|
|
}
|
|
|
|
// HasConfigurableValues returns whether there are configurable values set for this label.
|
|
func (la LabelAttribute) HasConfigurableValues() bool {
|
|
return len(la.ConfigurableValues) > 0
|
|
}
|
|
|
|
// SetValue sets the base, non-configured value for the Label
|
|
func (la *LabelAttribute) SetValue(value Label) {
|
|
la.SetSelectValue(NoConfigAxis, "", value)
|
|
}
|
|
|
|
// SetSelectValue set a value for a bazel select for the given axis, config and value.
|
|
func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
la.Value = &value
|
|
case arch, os, osArch, bionic, productVariables:
|
|
if la.ConfigurableValues == nil {
|
|
la.ConfigurableValues = make(configurableLabels)
|
|
}
|
|
la.ConfigurableValues.setValueForAxis(axis, config, &value)
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SelectValue gets a value for a bazel select for the given axis and config.
|
|
func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) Label {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
return *la.Value
|
|
case arch, os, osArch, bionic, productVariables:
|
|
return *la.ConfigurableValues[axis][config]
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
|
|
func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
|
|
keys := make([]ConfigurationAxis, 0, len(la.ConfigurableValues))
|
|
for k := range la.ConfigurableValues {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
|
|
return keys
|
|
}
|
|
|
|
type configToBools map[string]bool
|
|
|
|
func (ctb configToBools) setValue(config string, value *bool) {
|
|
if value == nil {
|
|
if _, ok := ctb[config]; ok {
|
|
delete(ctb, config)
|
|
}
|
|
return
|
|
}
|
|
ctb[config] = *value
|
|
}
|
|
|
|
type configurableBools map[ConfigurationAxis]configToBools
|
|
|
|
func (cb configurableBools) setValueForAxis(axis ConfigurationAxis, config string, value *bool) {
|
|
if cb[axis] == nil {
|
|
cb[axis] = make(configToBools)
|
|
}
|
|
cb[axis].setValue(config, value)
|
|
}
|
|
|
|
// BoolAttribute represents an attribute whose value is a single bool but may be configurable..
|
|
type BoolAttribute struct {
|
|
Value *bool
|
|
|
|
ConfigurableValues configurableBools
|
|
}
|
|
|
|
// HasConfigurableValues returns whether there are configurable values for this attribute.
|
|
func (ba BoolAttribute) HasConfigurableValues() bool {
|
|
return len(ba.ConfigurableValues) > 0
|
|
}
|
|
|
|
// SetSelectValue sets value for the given axis/config.
|
|
func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
ba.Value = value
|
|
case arch, os, osArch, bionic, productVariables:
|
|
if ba.ConfigurableValues == nil {
|
|
ba.ConfigurableValues = make(configurableBools)
|
|
}
|
|
ba.ConfigurableValues.setValueForAxis(axis, config, value)
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SelectValue gets the value for the given axis/config.
|
|
func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
return ba.Value
|
|
case arch, os, osArch, bionic, productVariables:
|
|
if v, ok := ba.ConfigurableValues[axis][config]; ok {
|
|
return &v
|
|
} else {
|
|
return nil
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
|
|
func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis {
|
|
keys := make([]ConfigurationAxis, 0, len(ba.ConfigurableValues))
|
|
for k := range ba.ConfigurableValues {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
|
|
return keys
|
|
}
|
|
|
|
// labelListSelectValues supports config-specific label_list typed Bazel attribute values.
|
|
type labelListSelectValues map[string]LabelList
|
|
|
|
func (ll labelListSelectValues) appendSelects(other labelListSelectValues) {
|
|
for k, v := range other {
|
|
l := ll[k]
|
|
(&l).Append(v)
|
|
ll[k] = l
|
|
}
|
|
}
|
|
|
|
// HasConfigurableValues returns whether there are configurable values within this set of selects.
|
|
func (ll labelListSelectValues) HasConfigurableValues() bool {
|
|
for _, v := range ll {
|
|
if v.Includes != nil {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// LabelListAttribute is used to represent a list of Bazel labels as an
|
|
// attribute.
|
|
type LabelListAttribute struct {
|
|
// The non-configured attribute label list Value. Required.
|
|
Value LabelList
|
|
|
|
// The configured attribute label list Values. Optional
|
|
// a map of independent configurability axes
|
|
ConfigurableValues configurableLabelLists
|
|
|
|
// If true, differentiate between "nil" and "empty" list. nil means that
|
|
// this attribute should not be specified at all, and "empty" means that
|
|
// the attribute should be explicitly specified as an empty list.
|
|
// This mode facilitates use of attribute defaults: an empty list should
|
|
// override the default.
|
|
ForceSpecifyEmptyList bool
|
|
}
|
|
|
|
type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
|
|
|
|
func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
|
|
if list.IsNil() {
|
|
if _, ok := cll[axis][config]; ok {
|
|
delete(cll[axis], config)
|
|
}
|
|
return
|
|
}
|
|
if cll[axis] == nil {
|
|
cll[axis] = make(labelListSelectValues)
|
|
}
|
|
|
|
cll[axis][config] = list
|
|
}
|
|
|
|
func (cll configurableLabelLists) Append(other configurableLabelLists) {
|
|
for axis, otherSelects := range other {
|
|
selects := cll[axis]
|
|
if selects == nil {
|
|
selects = make(labelListSelectValues, len(otherSelects))
|
|
}
|
|
selects.appendSelects(otherSelects)
|
|
cll[axis] = selects
|
|
}
|
|
}
|
|
|
|
// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
|
|
func MakeLabelListAttribute(value LabelList) LabelListAttribute {
|
|
return LabelListAttribute{
|
|
Value: value,
|
|
ConfigurableValues: make(configurableLabelLists),
|
|
}
|
|
}
|
|
|
|
func (lla *LabelListAttribute) SetValue(list LabelList) {
|
|
lla.SetSelectValue(NoConfigAxis, "", list)
|
|
}
|
|
|
|
// SetSelectValue set a value for a bazel select for the given axis, config and value.
|
|
func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
lla.Value = list
|
|
case arch, os, osArch, bionic, productVariables:
|
|
if lla.ConfigurableValues == nil {
|
|
lla.ConfigurableValues = make(configurableLabelLists)
|
|
}
|
|
lla.ConfigurableValues.setValueForAxis(axis, config, list)
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SelectValue gets a value for a bazel select for the given axis and config.
|
|
func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
return lla.Value
|
|
case arch, os, osArch, bionic, productVariables:
|
|
return lla.ConfigurableValues[axis][config]
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
|
|
func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
|
|
keys := make([]ConfigurationAxis, 0, len(lla.ConfigurableValues))
|
|
for k := range lla.ConfigurableValues {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
|
|
return keys
|
|
}
|
|
|
|
// Append all values, including os and arch specific ones, from another
|
|
// LabelListAttribute to this LabelListAttribute.
|
|
func (lla *LabelListAttribute) Append(other LabelListAttribute) {
|
|
if lla.ForceSpecifyEmptyList && !other.Value.IsNil() {
|
|
lla.Value.Includes = []Label{}
|
|
}
|
|
lla.Value.Append(other.Value)
|
|
if lla.ConfigurableValues == nil {
|
|
lla.ConfigurableValues = make(configurableLabelLists)
|
|
}
|
|
lla.ConfigurableValues.Append(other.ConfigurableValues)
|
|
}
|
|
|
|
// HasConfigurableValues returns true if the attribute contains axis-specific label list values.
|
|
func (lla LabelListAttribute) HasConfigurableValues() bool {
|
|
return len(lla.ConfigurableValues) > 0
|
|
}
|
|
|
|
// IsEmpty returns true if the attribute has no values under any configuration.
|
|
func (lla LabelListAttribute) IsEmpty() bool {
|
|
if len(lla.Value.Includes) > 0 {
|
|
return false
|
|
}
|
|
for axis, _ := range lla.ConfigurableValues {
|
|
if lla.ConfigurableValues[axis].HasConfigurableValues() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
|
|
// the base value and included in default values as appropriate.
|
|
func (lla *LabelListAttribute) ResolveExcludes() {
|
|
for axis, configToLabels := range lla.ConfigurableValues {
|
|
baseLabels := lla.Value.deepCopy()
|
|
for config, val := range configToLabels {
|
|
// Exclude config-specific excludes from base value
|
|
lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
|
|
|
|
// add base values to config specific to add labels excluded by others in this axis
|
|
// then remove all config-specific excludes
|
|
allLabels := baseLabels.deepCopy()
|
|
allLabels.Append(val)
|
|
lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: val.Excludes})
|
|
}
|
|
|
|
// After going through all configs, delete the duplicates in the config
|
|
// values that are already in the base Value.
|
|
for config, val := range configToLabels {
|
|
lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
|
|
}
|
|
|
|
// Now that the Value list is finalized for this axis, compare it with the original
|
|
// list, and put the difference into the default condition for the axis.
|
|
lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = SubtractBazelLabelList(baseLabels, lla.Value)
|
|
|
|
// if everything ends up without includes, just delete the axis
|
|
if !lla.ConfigurableValues[axis].HasConfigurableValues() {
|
|
delete(lla.ConfigurableValues, axis)
|
|
}
|
|
}
|
|
}
|
|
|
|
// StringListAttribute corresponds to the string_list Bazel attribute type with
|
|
// support for additional metadata, like configurations.
|
|
type StringListAttribute struct {
|
|
// The base value of the string list attribute.
|
|
Value []string
|
|
|
|
// The configured attribute label list Values. Optional
|
|
// a map of independent configurability axes
|
|
ConfigurableValues configurableStringLists
|
|
}
|
|
|
|
type configurableStringLists map[ConfigurationAxis]stringListSelectValues
|
|
|
|
func (csl configurableStringLists) Append(other configurableStringLists) {
|
|
for axis, otherSelects := range other {
|
|
selects := csl[axis]
|
|
if selects == nil {
|
|
selects = make(stringListSelectValues, len(otherSelects))
|
|
}
|
|
selects.appendSelects(otherSelects)
|
|
csl[axis] = selects
|
|
}
|
|
}
|
|
|
|
func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
|
|
if csl[axis] == nil {
|
|
csl[axis] = make(stringListSelectValues)
|
|
}
|
|
csl[axis][config] = list
|
|
}
|
|
|
|
type stringListSelectValues map[string][]string
|
|
|
|
func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
|
|
for k, v := range other {
|
|
sl[k] = append(sl[k], v...)
|
|
}
|
|
}
|
|
|
|
func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
|
|
for _, val := range sl {
|
|
if len(val) > 0 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
|
|
func MakeStringListAttribute(value []string) StringListAttribute {
|
|
// NOTE: These strings are not necessarily unique or sorted.
|
|
return StringListAttribute{
|
|
Value: value,
|
|
ConfigurableValues: make(configurableStringLists),
|
|
}
|
|
}
|
|
|
|
// HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
|
|
func (sla StringListAttribute) HasConfigurableValues() bool {
|
|
return len(sla.ConfigurableValues) > 0
|
|
}
|
|
|
|
// Append appends all values, including os and arch specific ones, from another
|
|
// StringListAttribute to this StringListAttribute
|
|
func (sla *StringListAttribute) Append(other StringListAttribute) {
|
|
sla.Value = append(sla.Value, other.Value...)
|
|
if sla.ConfigurableValues == nil {
|
|
sla.ConfigurableValues = make(configurableStringLists)
|
|
}
|
|
sla.ConfigurableValues.Append(other.ConfigurableValues)
|
|
}
|
|
|
|
// SetSelectValue set a value for a bazel select for the given axis, config and value.
|
|
func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
sla.Value = list
|
|
case arch, os, osArch, bionic, productVariables:
|
|
if sla.ConfigurableValues == nil {
|
|
sla.ConfigurableValues = make(configurableStringLists)
|
|
}
|
|
sla.ConfigurableValues.setValueForAxis(axis, config, list)
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SelectValue gets a value for a bazel select for the given axis and config.
|
|
func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
|
|
axis.validateConfig(config)
|
|
switch axis.configurationType {
|
|
case noConfig:
|
|
return sla.Value
|
|
case arch, os, osArch, bionic, productVariables:
|
|
return sla.ConfigurableValues[axis][config]
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
|
}
|
|
}
|
|
|
|
// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
|
|
func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
|
|
keys := make([]ConfigurationAxis, 0, len(sla.ConfigurableValues))
|
|
for k := range sla.ConfigurableValues {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
|
|
return keys
|
|
}
|
|
|
|
// TryVariableSubstitution, replace string substitution formatting within each string in slice with
|
|
// Starlark string.format compatible tag for productVariable.
|
|
func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
|
|
ret := make([]string, 0, len(slice))
|
|
changesMade := false
|
|
for _, s := range slice {
|
|
newS, changed := TryVariableSubstitution(s, productVariable)
|
|
ret = append(ret, newS)
|
|
changesMade = changesMade || changed
|
|
}
|
|
return ret, changesMade
|
|
}
|
|
|
|
// TryVariableSubstitution, replace string substitution formatting within s with Starlark
|
|
// string.format compatible tag for productVariable.
|
|
func TryVariableSubstitution(s string, productVariable string) (string, bool) {
|
|
sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
|
|
return sub, s != sub
|
|
}
|