properties.go 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  1. // 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. package bazel
  15. import (
  16. "fmt"
  17. "path/filepath"
  18. "regexp"
  19. "sort"
  20. "strings"
  21. "github.com/google/blueprint"
  22. )
  23. // BazelTargetModuleProperties contain properties and metadata used for
  24. // Blueprint to BUILD file conversion.
  25. type BazelTargetModuleProperties struct {
  26. // The Bazel rule class for this target.
  27. Rule_class string `blueprint:"mutated"`
  28. // The target label for the bzl file containing the definition of the rule class.
  29. Bzl_load_location string `blueprint:"mutated"`
  30. }
  31. var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
  32. // Label is used to represent a Bazel compatible Label. Also stores the original
  33. // bp text to support string replacement.
  34. type Label struct {
  35. // The string representation of a Bazel target label. This can be a relative
  36. // or fully qualified label. These labels are used for generating BUILD
  37. // files with bp2build.
  38. Label string
  39. // The original Soong/Blueprint module name that the label was derived from.
  40. // This is used for replacing references to the original name with the new
  41. // label, for example in genrule cmds.
  42. //
  43. // While there is a reversible 1:1 mapping from the module name to Bazel
  44. // label with bp2build that could make computing the original module name
  45. // from the label automatic, it is not the case for handcrafted targets,
  46. // where modules can have a custom label mapping through the { bazel_module:
  47. // { label: <label> } } property.
  48. //
  49. // With handcrafted labels, those modules don't go through bp2build
  50. // conversion, but relies on handcrafted targets in the source tree.
  51. OriginalModuleName string
  52. }
  53. // LabelList is used to represent a list of Bazel labels.
  54. type LabelList struct {
  55. Includes []Label
  56. Excludes []Label
  57. }
  58. // MakeLabelList creates a LabelList from a list Label
  59. func MakeLabelList(labels []Label) LabelList {
  60. return LabelList{
  61. Includes: labels,
  62. Excludes: nil,
  63. }
  64. }
  65. func (ll *LabelList) Equals(other LabelList) bool {
  66. if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
  67. return false
  68. }
  69. for i, _ := range ll.Includes {
  70. if ll.Includes[i] != other.Includes[i] {
  71. return false
  72. }
  73. }
  74. for i, _ := range ll.Excludes {
  75. if ll.Excludes[i] != other.Excludes[i] {
  76. return false
  77. }
  78. }
  79. return true
  80. }
  81. func (ll *LabelList) IsNil() bool {
  82. return ll.Includes == nil && ll.Excludes == nil
  83. }
  84. func (ll *LabelList) IsEmpty() bool {
  85. return len(ll.Includes) == 0 && len(ll.Excludes) == 0
  86. }
  87. func (ll *LabelList) deepCopy() LabelList {
  88. return LabelList{
  89. Includes: ll.Includes[:],
  90. Excludes: ll.Excludes[:],
  91. }
  92. }
  93. // uniqueParentDirectories returns a list of the unique parent directories for
  94. // all files in ll.Includes.
  95. func (ll *LabelList) uniqueParentDirectories() []string {
  96. dirMap := map[string]bool{}
  97. for _, label := range ll.Includes {
  98. dirMap[filepath.Dir(label.Label)] = true
  99. }
  100. dirs := []string{}
  101. for dir := range dirMap {
  102. dirs = append(dirs, dir)
  103. }
  104. return dirs
  105. }
  106. // Add inserts the label Label at the end of the LabelList.
  107. func (ll *LabelList) Add(label *Label) {
  108. if label == nil {
  109. return
  110. }
  111. ll.Includes = append(ll.Includes, *label)
  112. }
  113. // Append appends the fields of other labelList to the corresponding fields of ll.
  114. func (ll *LabelList) Append(other LabelList) {
  115. if len(ll.Includes) > 0 || len(other.Includes) > 0 {
  116. ll.Includes = append(ll.Includes, other.Includes...)
  117. }
  118. if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
  119. ll.Excludes = append(other.Excludes, other.Excludes...)
  120. }
  121. }
  122. // UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
  123. // the slice in a sorted order.
  124. func UniqueSortedBazelLabels(originalLabels []Label) []Label {
  125. uniqueLabelsSet := make(map[Label]bool)
  126. for _, l := range originalLabels {
  127. uniqueLabelsSet[l] = true
  128. }
  129. var uniqueLabels []Label
  130. for l, _ := range uniqueLabelsSet {
  131. uniqueLabels = append(uniqueLabels, l)
  132. }
  133. sort.SliceStable(uniqueLabels, func(i, j int) bool {
  134. return uniqueLabels[i].Label < uniqueLabels[j].Label
  135. })
  136. return uniqueLabels
  137. }
  138. func FirstUniqueBazelLabels(originalLabels []Label) []Label {
  139. var labels []Label
  140. found := make(map[Label]bool, len(originalLabels))
  141. for _, l := range originalLabels {
  142. if _, ok := found[l]; ok {
  143. continue
  144. }
  145. labels = append(labels, l)
  146. found[l] = true
  147. }
  148. return labels
  149. }
  150. func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
  151. var uniqueLabelList LabelList
  152. uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
  153. uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
  154. return uniqueLabelList
  155. }
  156. func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
  157. var uniqueLabelList LabelList
  158. uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
  159. uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
  160. return uniqueLabelList
  161. }
  162. // Subtract needle from haystack
  163. func SubtractStrings(haystack []string, needle []string) []string {
  164. // This is really a set
  165. needleMap := make(map[string]bool)
  166. for _, s := range needle {
  167. needleMap[s] = true
  168. }
  169. var strings []string
  170. for _, s := range haystack {
  171. if exclude := needleMap[s]; !exclude {
  172. strings = append(strings, s)
  173. }
  174. }
  175. return strings
  176. }
  177. // Subtract needle from haystack
  178. func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
  179. // This is really a set
  180. needleMap := make(map[Label]bool)
  181. for _, s := range needle {
  182. needleMap[s] = true
  183. }
  184. var labels []Label
  185. for _, label := range haystack {
  186. if exclude := needleMap[label]; !exclude {
  187. labels = append(labels, label)
  188. }
  189. }
  190. return labels
  191. }
  192. // Appends two LabelLists, returning the combined list.
  193. func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
  194. var result LabelList
  195. result.Includes = append(a.Includes, b.Includes...)
  196. result.Excludes = append(a.Excludes, b.Excludes...)
  197. return result
  198. }
  199. // Subtract needle from haystack
  200. func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
  201. var result LabelList
  202. result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
  203. // NOTE: Excludes are intentionally not subtracted
  204. result.Excludes = haystack.Excludes
  205. return result
  206. }
  207. type Attribute interface {
  208. HasConfigurableValues() bool
  209. }
  210. type labelSelectValues map[string]*Label
  211. type configurableLabels map[ConfigurationAxis]labelSelectValues
  212. func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
  213. if cl[axis] == nil {
  214. cl[axis] = make(labelSelectValues)
  215. }
  216. cl[axis][config] = value
  217. }
  218. // Represents an attribute whose value is a single label
  219. type LabelAttribute struct {
  220. Value *Label
  221. ConfigurableValues configurableLabels
  222. }
  223. func (la *LabelAttribute) axisTypes() map[configurationType]bool {
  224. types := map[configurationType]bool{}
  225. for k := range la.ConfigurableValues {
  226. if len(la.ConfigurableValues[k]) > 0 {
  227. types[k.configurationType] = true
  228. }
  229. }
  230. return types
  231. }
  232. // Collapse reduces the configurable axes of the label attribute to a single axis.
  233. // This is necessary for final writing to bp2build, as a configurable label
  234. // attribute can only be comprised by a single select.
  235. func (la *LabelAttribute) Collapse() error {
  236. axisTypes := la.axisTypes()
  237. _, containsOs := axisTypes[os]
  238. _, containsArch := axisTypes[arch]
  239. _, containsOsArch := axisTypes[osArch]
  240. _, containsProductVariables := axisTypes[productVariables]
  241. if containsProductVariables {
  242. if containsOs || containsArch || containsOsArch {
  243. return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
  244. }
  245. }
  246. if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
  247. // If a bool attribute has both os and arch configuration axes, the only
  248. // way to successfully union their values is to increase the granularity
  249. // of the configuration criteria to os_arch.
  250. for osType, supportedArchs := range osToArchMap {
  251. for _, supportedArch := range supportedArchs {
  252. osArch := osArchString(osType, supportedArch)
  253. if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
  254. // Do nothing, as the arch_os is explicitly defined already.
  255. } else {
  256. archVal := la.SelectValue(ArchConfigurationAxis, supportedArch)
  257. osVal := la.SelectValue(OsConfigurationAxis, osType)
  258. if osVal != nil && archVal != nil {
  259. // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
  260. // runs after os mutator.
  261. la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
  262. } else if osVal != nil && archVal == nil {
  263. la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal)
  264. } else if osVal == nil && archVal != nil {
  265. la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
  266. }
  267. }
  268. }
  269. }
  270. // All os_arch values are now set. Clear os and arch axes.
  271. delete(la.ConfigurableValues, ArchConfigurationAxis)
  272. delete(la.ConfigurableValues, OsConfigurationAxis)
  273. }
  274. return nil
  275. }
  276. // HasConfigurableValues returns whether there are configurable values set for this label.
  277. func (la LabelAttribute) HasConfigurableValues() bool {
  278. for _, selectValues := range la.ConfigurableValues {
  279. if len(selectValues) > 0 {
  280. return true
  281. }
  282. }
  283. return false
  284. }
  285. // SetValue sets the base, non-configured value for the Label
  286. func (la *LabelAttribute) SetValue(value Label) {
  287. la.SetSelectValue(NoConfigAxis, "", value)
  288. }
  289. // SetSelectValue set a value for a bazel select for the given axis, config and value.
  290. func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
  291. axis.validateConfig(config)
  292. switch axis.configurationType {
  293. case noConfig:
  294. la.Value = &value
  295. case arch, os, osArch, productVariables:
  296. if la.ConfigurableValues == nil {
  297. la.ConfigurableValues = make(configurableLabels)
  298. }
  299. la.ConfigurableValues.setValueForAxis(axis, config, &value)
  300. default:
  301. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  302. }
  303. }
  304. // SelectValue gets a value for a bazel select for the given axis and config.
  305. func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label {
  306. axis.validateConfig(config)
  307. switch axis.configurationType {
  308. case noConfig:
  309. return la.Value
  310. case arch, os, osArch, productVariables:
  311. return la.ConfigurableValues[axis][config]
  312. default:
  313. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  314. }
  315. }
  316. // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
  317. func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
  318. keys := make([]ConfigurationAxis, 0, len(la.ConfigurableValues))
  319. for k := range la.ConfigurableValues {
  320. keys = append(keys, k)
  321. }
  322. sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
  323. return keys
  324. }
  325. // MakeLabelAttribute turns a string into a LabelAttribute
  326. func MakeLabelAttribute(label string) *LabelAttribute {
  327. return &LabelAttribute{
  328. Value: &Label{
  329. Label: label,
  330. },
  331. }
  332. }
  333. type configToBools map[string]bool
  334. func (ctb configToBools) setValue(config string, value *bool) {
  335. if value == nil {
  336. if _, ok := ctb[config]; ok {
  337. delete(ctb, config)
  338. }
  339. return
  340. }
  341. ctb[config] = *value
  342. }
  343. type configurableBools map[ConfigurationAxis]configToBools
  344. func (cb configurableBools) setValueForAxis(axis ConfigurationAxis, config string, value *bool) {
  345. if cb[axis] == nil {
  346. cb[axis] = make(configToBools)
  347. }
  348. cb[axis].setValue(config, value)
  349. }
  350. // BoolAttribute represents an attribute whose value is a single bool but may be configurable..
  351. type BoolAttribute struct {
  352. Value *bool
  353. ConfigurableValues configurableBools
  354. }
  355. // HasConfigurableValues returns whether there are configurable values for this attribute.
  356. func (ba BoolAttribute) HasConfigurableValues() bool {
  357. for _, cfgToBools := range ba.ConfigurableValues {
  358. if len(cfgToBools) > 0 {
  359. return true
  360. }
  361. }
  362. return false
  363. }
  364. // SetValue sets value for the no config axis
  365. func (ba *BoolAttribute) SetValue(value *bool) {
  366. ba.SetSelectValue(NoConfigAxis, "", value)
  367. }
  368. // SetSelectValue sets value for the given axis/config.
  369. func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
  370. axis.validateConfig(config)
  371. switch axis.configurationType {
  372. case noConfig:
  373. ba.Value = value
  374. case arch, os, osArch, productVariables:
  375. if ba.ConfigurableValues == nil {
  376. ba.ConfigurableValues = make(configurableBools)
  377. }
  378. ba.ConfigurableValues.setValueForAxis(axis, config, value)
  379. default:
  380. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  381. }
  382. }
  383. // ToLabelListAttribute creates and returns a LabelListAttribute from this
  384. // bool attribute, where each bool in this attribute corresponds to a
  385. // label list value in the resultant attribute.
  386. func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) {
  387. getLabelList := func(boolPtr *bool) LabelList {
  388. if boolPtr == nil {
  389. return LabelList{nil, nil}
  390. } else if *boolPtr {
  391. return trueVal
  392. } else {
  393. return falseVal
  394. }
  395. }
  396. mainVal := getLabelList(ba.Value)
  397. if !ba.HasConfigurableValues() {
  398. return MakeLabelListAttribute(mainVal), nil
  399. }
  400. result := LabelListAttribute{}
  401. if err := ba.Collapse(); err != nil {
  402. return result, err
  403. }
  404. for axis, configToBools := range ba.ConfigurableValues {
  405. if len(configToBools) < 1 {
  406. continue
  407. }
  408. for config, boolPtr := range configToBools {
  409. val := getLabelList(&boolPtr)
  410. if !val.Equals(mainVal) {
  411. result.SetSelectValue(axis, config, val)
  412. }
  413. }
  414. result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
  415. }
  416. return result, nil
  417. }
  418. // Collapse reduces the configurable axes of the boolean attribute to a single axis.
  419. // This is necessary for final writing to bp2build, as a configurable boolean
  420. // attribute can only be comprised by a single select.
  421. func (ba *BoolAttribute) Collapse() error {
  422. axisTypes := ba.axisTypes()
  423. _, containsOs := axisTypes[os]
  424. _, containsArch := axisTypes[arch]
  425. _, containsOsArch := axisTypes[osArch]
  426. _, containsProductVariables := axisTypes[productVariables]
  427. if containsProductVariables {
  428. if containsOs || containsArch || containsOsArch {
  429. return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
  430. }
  431. }
  432. if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
  433. // If a bool attribute has both os and arch configuration axes, the only
  434. // way to successfully union their values is to increase the granularity
  435. // of the configuration criteria to os_arch.
  436. for osType, supportedArchs := range osToArchMap {
  437. for _, supportedArch := range supportedArchs {
  438. osArch := osArchString(osType, supportedArch)
  439. if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
  440. // Do nothing, as the arch_os is explicitly defined already.
  441. } else {
  442. archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch)
  443. osVal := ba.SelectValue(OsConfigurationAxis, osType)
  444. if osVal != nil && archVal != nil {
  445. // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
  446. // runs after os mutator.
  447. ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
  448. } else if osVal != nil && archVal == nil {
  449. ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
  450. } else if osVal == nil && archVal != nil {
  451. ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
  452. }
  453. }
  454. }
  455. }
  456. // All os_arch values are now set. Clear os and arch axes.
  457. delete(ba.ConfigurableValues, ArchConfigurationAxis)
  458. delete(ba.ConfigurableValues, OsConfigurationAxis)
  459. // Verify post-condition; this should never fail, provided no additional
  460. // axes are introduced.
  461. if len(ba.ConfigurableValues) > 1 {
  462. panic(fmt.Errorf("error in collapsing attribute: %#v", ba))
  463. }
  464. }
  465. return nil
  466. }
  467. func (ba *BoolAttribute) axisTypes() map[configurationType]bool {
  468. types := map[configurationType]bool{}
  469. for k := range ba.ConfigurableValues {
  470. if len(ba.ConfigurableValues[k]) > 0 {
  471. types[k.configurationType] = true
  472. }
  473. }
  474. return types
  475. }
  476. // SelectValue gets the value for the given axis/config.
  477. func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
  478. axis.validateConfig(config)
  479. switch axis.configurationType {
  480. case noConfig:
  481. return ba.Value
  482. case arch, os, osArch, productVariables:
  483. if v, ok := ba.ConfigurableValues[axis][config]; ok {
  484. return &v
  485. } else {
  486. return nil
  487. }
  488. default:
  489. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  490. }
  491. }
  492. // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
  493. func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis {
  494. keys := make([]ConfigurationAxis, 0, len(ba.ConfigurableValues))
  495. for k := range ba.ConfigurableValues {
  496. keys = append(keys, k)
  497. }
  498. sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
  499. return keys
  500. }
  501. // labelListSelectValues supports config-specific label_list typed Bazel attribute values.
  502. type labelListSelectValues map[string]LabelList
  503. func (ll labelListSelectValues) addSelects(label labelSelectValues) {
  504. for k, v := range label {
  505. if label == nil {
  506. continue
  507. }
  508. l := ll[k]
  509. (&l).Add(v)
  510. ll[k] = l
  511. }
  512. }
  513. func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) {
  514. for k, v := range other {
  515. l := ll[k]
  516. if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() {
  517. l.Includes = []Label{}
  518. }
  519. (&l).Append(v)
  520. ll[k] = l
  521. }
  522. }
  523. // HasConfigurableValues returns whether there are configurable values within this set of selects.
  524. func (ll labelListSelectValues) HasConfigurableValues() bool {
  525. for _, v := range ll {
  526. if v.Includes != nil {
  527. return true
  528. }
  529. }
  530. return false
  531. }
  532. // LabelListAttribute is used to represent a list of Bazel labels as an
  533. // attribute.
  534. type LabelListAttribute struct {
  535. // The non-configured attribute label list Value. Required.
  536. Value LabelList
  537. // The configured attribute label list Values. Optional
  538. // a map of independent configurability axes
  539. ConfigurableValues configurableLabelLists
  540. // If true, differentiate between "nil" and "empty" list. nil means that
  541. // this attribute should not be specified at all, and "empty" means that
  542. // the attribute should be explicitly specified as an empty list.
  543. // This mode facilitates use of attribute defaults: an empty list should
  544. // override the default.
  545. ForceSpecifyEmptyList bool
  546. // If true, signal the intent to the code generator to emit all select keys,
  547. // even if the Includes list for that key is empty. This mode facilitates
  548. // specific select statements where an empty list for a non-default select
  549. // key has a meaning.
  550. EmitEmptyList bool
  551. }
  552. type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
  553. func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
  554. if list.IsNil() {
  555. if _, ok := cll[axis][config]; ok {
  556. delete(cll[axis], config)
  557. }
  558. return
  559. }
  560. if cll[axis] == nil {
  561. cll[axis] = make(labelListSelectValues)
  562. }
  563. cll[axis][config] = list
  564. }
  565. func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) {
  566. for axis, otherSelects := range other {
  567. selects := cll[axis]
  568. if selects == nil {
  569. selects = make(labelListSelectValues, len(otherSelects))
  570. }
  571. selects.appendSelects(otherSelects, forceSpecifyEmptyList)
  572. cll[axis] = selects
  573. }
  574. }
  575. func (lla *LabelListAttribute) Clone() *LabelListAttribute {
  576. result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList}
  577. return result.Append(*lla)
  578. }
  579. // MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
  580. func MakeLabelListAttribute(value LabelList) LabelListAttribute {
  581. return LabelListAttribute{
  582. Value: value,
  583. ConfigurableValues: make(configurableLabelLists),
  584. }
  585. }
  586. // MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
  587. func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
  588. return MakeLabelListAttribute(MakeLabelList([]Label{value}))
  589. }
  590. func (lla *LabelListAttribute) SetValue(list LabelList) {
  591. lla.SetSelectValue(NoConfigAxis, "", list)
  592. }
  593. // SetSelectValue set a value for a bazel select for the given axis, config and value.
  594. func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
  595. axis.validateConfig(config)
  596. switch axis.configurationType {
  597. case noConfig:
  598. lla.Value = list
  599. case arch, os, osArch, productVariables:
  600. if lla.ConfigurableValues == nil {
  601. lla.ConfigurableValues = make(configurableLabelLists)
  602. }
  603. lla.ConfigurableValues.setValueForAxis(axis, config, list)
  604. default:
  605. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  606. }
  607. }
  608. // SelectValue gets a value for a bazel select for the given axis and config.
  609. func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
  610. axis.validateConfig(config)
  611. switch axis.configurationType {
  612. case noConfig:
  613. return lla.Value
  614. case arch, os, osArch, productVariables:
  615. return lla.ConfigurableValues[axis][config]
  616. default:
  617. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  618. }
  619. }
  620. // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
  621. func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
  622. keys := make([]ConfigurationAxis, 0, len(lla.ConfigurableValues))
  623. for k := range lla.ConfigurableValues {
  624. keys = append(keys, k)
  625. }
  626. sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
  627. return keys
  628. }
  629. // Append all values, including os and arch specific ones, from another
  630. // LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute.
  631. func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute {
  632. forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList
  633. if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() {
  634. lla.Value.Includes = []Label{}
  635. }
  636. lla.Value.Append(other.Value)
  637. if lla.ConfigurableValues == nil {
  638. lla.ConfigurableValues = make(configurableLabelLists)
  639. }
  640. lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList)
  641. return lla
  642. }
  643. // Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's
  644. // LabelList within the LabelListAttribute
  645. func (lla *LabelListAttribute) Add(label *LabelAttribute) {
  646. if label == nil {
  647. return
  648. }
  649. lla.Value.Add(label.Value)
  650. if lla.ConfigurableValues == nil && label.ConfigurableValues != nil {
  651. lla.ConfigurableValues = make(configurableLabelLists)
  652. }
  653. for axis, _ := range label.ConfigurableValues {
  654. if _, exists := lla.ConfigurableValues[axis]; !exists {
  655. lla.ConfigurableValues[axis] = make(labelListSelectValues)
  656. }
  657. lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis])
  658. }
  659. }
  660. // HasConfigurableValues returns true if the attribute contains axis-specific label list values.
  661. func (lla LabelListAttribute) HasConfigurableValues() bool {
  662. for _, selectValues := range lla.ConfigurableValues {
  663. if len(selectValues) > 0 {
  664. return true
  665. }
  666. }
  667. return false
  668. }
  669. // IsEmpty returns true if the attribute has no values under any configuration.
  670. func (lla LabelListAttribute) IsEmpty() bool {
  671. if len(lla.Value.Includes) > 0 {
  672. return false
  673. }
  674. for axis, _ := range lla.ConfigurableValues {
  675. if lla.ConfigurableValues[axis].HasConfigurableValues() {
  676. return false
  677. }
  678. }
  679. return true
  680. }
  681. // IsNil returns true if the attribute has not been set for any configuration.
  682. func (lla LabelListAttribute) IsNil() bool {
  683. if lla.Value.Includes != nil {
  684. return false
  685. }
  686. return !lla.HasConfigurableValues()
  687. }
  688. // Exclude for the given axis, config, removes Includes in labelList from Includes and appends them
  689. // to Excludes. This is to special case any excludes that are not specified in a bp file but need to
  690. // be removed, e.g. if they could cause duplicate element failures.
  691. func (lla *LabelListAttribute) Exclude(axis ConfigurationAxis, config string, labelList LabelList) {
  692. val := lla.SelectValue(axis, config)
  693. newList := SubtractBazelLabelList(val, labelList)
  694. newList.Excludes = append(newList.Excludes, labelList.Includes...)
  695. lla.SetSelectValue(axis, config, newList)
  696. }
  697. // ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
  698. // the base value and included in default values as appropriate.
  699. func (lla *LabelListAttribute) ResolveExcludes() {
  700. for axis, configToLabels := range lla.ConfigurableValues {
  701. baseLabels := lla.Value.deepCopy()
  702. for config, val := range configToLabels {
  703. // Exclude config-specific excludes from base value
  704. lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
  705. // add base values to config specific to add labels excluded by others in this axis
  706. // then remove all config-specific excludes
  707. allLabels := baseLabels.deepCopy()
  708. allLabels.Append(val)
  709. lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: val.Excludes})
  710. }
  711. // After going through all configs, delete the duplicates in the config
  712. // values that are already in the base Value.
  713. for config, val := range configToLabels {
  714. lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
  715. }
  716. // Now that the Value list is finalized for this axis, compare it with
  717. // the original list, and union the difference with the default
  718. // condition for the axis.
  719. difference := SubtractBazelLabelList(baseLabels, lla.Value)
  720. existingDefaults := lla.ConfigurableValues[axis][ConditionsDefaultConfigKey]
  721. existingDefaults.Append(difference)
  722. lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = FirstUniqueBazelLabelList(existingDefaults)
  723. // if everything ends up without includes, just delete the axis
  724. if !lla.ConfigurableValues[axis].HasConfigurableValues() {
  725. delete(lla.ConfigurableValues, axis)
  726. }
  727. }
  728. }
  729. // OtherModuleContext is a limited context that has methods with information about other modules.
  730. type OtherModuleContext interface {
  731. ModuleFromName(name string) (blueprint.Module, bool)
  732. OtherModuleType(m blueprint.Module) string
  733. OtherModuleName(m blueprint.Module) string
  734. OtherModuleDir(m blueprint.Module) string
  735. ModuleErrorf(fmt string, args ...interface{})
  736. }
  737. // LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed)
  738. // label and whether it was changed.
  739. type LabelMapper func(OtherModuleContext, Label) (string, bool)
  740. // LabelPartition contains descriptions of a partition for labels
  741. type LabelPartition struct {
  742. // Extensions to include in this partition
  743. Extensions []string
  744. // LabelMapper is a function that can map a label to a new label, and indicate whether to include
  745. // the mapped label in the partition
  746. LabelMapper LabelMapper
  747. // Whether to store files not included in any other partition in a group of LabelPartitions
  748. // Only one partition in a group of LabelPartitions can enabled Keep_remainder
  749. Keep_remainder bool
  750. }
  751. // LabelPartitions is a map of partition name to a LabelPartition describing the elements of the
  752. // partition
  753. type LabelPartitions map[string]LabelPartition
  754. // filter returns a pointer to a label if the label should be included in the partition or nil if
  755. // not.
  756. func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label {
  757. if lf.LabelMapper != nil {
  758. if newLabel, changed := lf.LabelMapper(ctx, label); changed {
  759. return &Label{newLabel, label.OriginalModuleName}
  760. }
  761. }
  762. for _, ext := range lf.Extensions {
  763. if strings.HasSuffix(label.Label, ext) {
  764. return &label
  765. }
  766. }
  767. return nil
  768. }
  769. // PartitionToLabelListAttribute is map of partition name to a LabelListAttribute
  770. type PartitionToLabelListAttribute map[string]LabelListAttribute
  771. type partitionToLabelList map[string]*LabelList
  772. func (p partitionToLabelList) appendIncludes(partition string, label Label) {
  773. if _, ok := p[partition]; !ok {
  774. p[partition] = &LabelList{}
  775. }
  776. p[partition].Includes = append(p[partition].Includes, label)
  777. }
  778. func (p partitionToLabelList) excludes(partition string, excludes []Label) {
  779. if _, ok := p[partition]; !ok {
  780. p[partition] = &LabelList{}
  781. }
  782. p[partition].Excludes = excludes
  783. }
  784. // PartitionLabelListAttribute partitions a LabelListAttribute into the requested partitions
  785. func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute, partitions LabelPartitions) PartitionToLabelListAttribute {
  786. ret := PartitionToLabelListAttribute{}
  787. var partitionNames []string
  788. // Stored as a pointer to distinguish nil (no remainder partition) from empty string partition
  789. var remainderPartition *string
  790. for p, f := range partitions {
  791. partitionNames = append(partitionNames, p)
  792. if f.Keep_remainder {
  793. if remainderPartition != nil {
  794. panic("only one partition can store the remainder")
  795. }
  796. // If we take the address of p in a loop, we'll end up with the last value of p in
  797. // remainderPartition, we want the requested partition
  798. capturePartition := p
  799. remainderPartition = &capturePartition
  800. }
  801. }
  802. partitionLabelList := func(axis ConfigurationAxis, config string) {
  803. value := lla.SelectValue(axis, config)
  804. partitionToLabels := partitionToLabelList{}
  805. for _, item := range value.Includes {
  806. wasFiltered := false
  807. var inPartition *string
  808. for partition, f := range partitions {
  809. filtered := f.filter(ctx, item)
  810. if filtered == nil {
  811. // did not match this filter, keep looking
  812. continue
  813. }
  814. wasFiltered = true
  815. partitionToLabels.appendIncludes(partition, *filtered)
  816. // don't need to check other partitions if this filter used the item,
  817. // continue checking if mapped to another name
  818. if *filtered == item {
  819. if inPartition != nil {
  820. ctx.ModuleErrorf("%q was found in multiple partitions: %q, %q", item.Label, *inPartition, partition)
  821. }
  822. capturePartition := partition
  823. inPartition = &capturePartition
  824. }
  825. }
  826. // if not specified in a partition, add to remainder partition if one exists
  827. if !wasFiltered && remainderPartition != nil {
  828. partitionToLabels.appendIncludes(*remainderPartition, item)
  829. }
  830. }
  831. // ensure empty lists are maintained
  832. if value.Excludes != nil {
  833. for _, partition := range partitionNames {
  834. partitionToLabels.excludes(partition, value.Excludes)
  835. }
  836. }
  837. for partition, list := range partitionToLabels {
  838. val := ret[partition]
  839. (&val).SetSelectValue(axis, config, *list)
  840. ret[partition] = val
  841. }
  842. }
  843. partitionLabelList(NoConfigAxis, "")
  844. for axis, configToList := range lla.ConfigurableValues {
  845. for config, _ := range configToList {
  846. partitionLabelList(axis, config)
  847. }
  848. }
  849. return ret
  850. }
  851. // StringAttribute corresponds to the string Bazel attribute type with
  852. // support for additional metadata, like configurations.
  853. type StringAttribute struct {
  854. // The base value of the string attribute.
  855. Value *string
  856. // The configured attribute label list Values. Optional
  857. // a map of independent configurability axes
  858. ConfigurableValues configurableStrings
  859. }
  860. type configurableStrings map[ConfigurationAxis]stringSelectValues
  861. func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
  862. if cs[axis] == nil {
  863. cs[axis] = make(stringSelectValues)
  864. }
  865. var v = ""
  866. if str != nil {
  867. v = *str
  868. }
  869. cs[axis][config] = v
  870. }
  871. type stringSelectValues map[string]string
  872. // HasConfigurableValues returns true if the attribute contains axis-specific string values.
  873. func (sa StringAttribute) HasConfigurableValues() bool {
  874. for _, selectValues := range sa.ConfigurableValues {
  875. if len(selectValues) > 0 {
  876. return true
  877. }
  878. }
  879. return false
  880. }
  881. // SetSelectValue set a value for a bazel select for the given axis, config and value.
  882. func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
  883. axis.validateConfig(config)
  884. switch axis.configurationType {
  885. case noConfig:
  886. sa.Value = str
  887. case arch, os, osArch, productVariables:
  888. if sa.ConfigurableValues == nil {
  889. sa.ConfigurableValues = make(configurableStrings)
  890. }
  891. sa.ConfigurableValues.setValueForAxis(axis, config, str)
  892. default:
  893. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  894. }
  895. }
  896. // SelectValue gets a value for a bazel select for the given axis and config.
  897. func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
  898. axis.validateConfig(config)
  899. switch axis.configurationType {
  900. case noConfig:
  901. return sa.Value
  902. case arch, os, osArch, productVariables:
  903. if v, ok := sa.ConfigurableValues[axis][config]; ok {
  904. return &v
  905. } else {
  906. return nil
  907. }
  908. default:
  909. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  910. }
  911. }
  912. // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
  913. func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
  914. keys := make([]ConfigurationAxis, 0, len(sa.ConfigurableValues))
  915. for k := range sa.ConfigurableValues {
  916. keys = append(keys, k)
  917. }
  918. sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
  919. return keys
  920. }
  921. // Collapse reduces the configurable axes of the string attribute to a single axis.
  922. // This is necessary for final writing to bp2build, as a configurable string
  923. // attribute can only be comprised by a single select.
  924. func (sa *StringAttribute) Collapse() error {
  925. axisTypes := sa.axisTypes()
  926. _, containsOs := axisTypes[os]
  927. _, containsArch := axisTypes[arch]
  928. _, containsOsArch := axisTypes[osArch]
  929. _, containsProductVariables := axisTypes[productVariables]
  930. if containsProductVariables {
  931. if containsOs || containsArch || containsOsArch {
  932. return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
  933. }
  934. }
  935. if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
  936. // If a bool attribute has both os and arch configuration axes, the only
  937. // way to successfully union their values is to increase the granularity
  938. // of the configuration criteria to os_arch.
  939. for osType, supportedArchs := range osToArchMap {
  940. for _, supportedArch := range supportedArchs {
  941. osArch := osArchString(osType, supportedArch)
  942. if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
  943. // Do nothing, as the arch_os is explicitly defined already.
  944. } else {
  945. archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
  946. osVal := sa.SelectValue(OsConfigurationAxis, osType)
  947. if osVal != nil && archVal != nil {
  948. // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
  949. // runs after os mutator.
  950. sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
  951. } else if osVal != nil && archVal == nil {
  952. sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
  953. } else if osVal == nil && archVal != nil {
  954. sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
  955. }
  956. }
  957. }
  958. }
  959. // All os_arch values are now set. Clear os and arch axes.
  960. delete(sa.ConfigurableValues, ArchConfigurationAxis)
  961. delete(sa.ConfigurableValues, OsConfigurationAxis)
  962. // Verify post-condition; this should never fail, provided no additional
  963. // axes are introduced.
  964. if len(sa.ConfigurableValues) > 1 {
  965. panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
  966. }
  967. }
  968. return nil
  969. }
  970. func (sa *StringAttribute) axisTypes() map[configurationType]bool {
  971. types := map[configurationType]bool{}
  972. for k := range sa.ConfigurableValues {
  973. if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
  974. types[k.configurationType] = true
  975. }
  976. }
  977. return types
  978. }
  979. // StringListAttribute corresponds to the string_list Bazel attribute type with
  980. // support for additional metadata, like configurations.
  981. type StringListAttribute struct {
  982. // The base value of the string list attribute.
  983. Value []string
  984. // The configured attribute label list Values. Optional
  985. // a map of independent configurability axes
  986. ConfigurableValues configurableStringLists
  987. }
  988. type configurableStringLists map[ConfigurationAxis]stringListSelectValues
  989. func (csl configurableStringLists) Append(other configurableStringLists) {
  990. for axis, otherSelects := range other {
  991. selects := csl[axis]
  992. if selects == nil {
  993. selects = make(stringListSelectValues, len(otherSelects))
  994. }
  995. selects.appendSelects(otherSelects)
  996. csl[axis] = selects
  997. }
  998. }
  999. func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
  1000. if csl[axis] == nil {
  1001. csl[axis] = make(stringListSelectValues)
  1002. }
  1003. csl[axis][config] = list
  1004. }
  1005. type stringListSelectValues map[string][]string
  1006. func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
  1007. for k, v := range other {
  1008. sl[k] = append(sl[k], v...)
  1009. }
  1010. }
  1011. func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
  1012. for _, val := range sl {
  1013. if len(val) > 0 {
  1014. return true
  1015. }
  1016. }
  1017. return false
  1018. }
  1019. // MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
  1020. func MakeStringListAttribute(value []string) StringListAttribute {
  1021. // NOTE: These strings are not necessarily unique or sorted.
  1022. return StringListAttribute{
  1023. Value: value,
  1024. ConfigurableValues: make(configurableStringLists),
  1025. }
  1026. }
  1027. // HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
  1028. func (sla StringListAttribute) HasConfigurableValues() bool {
  1029. for _, selectValues := range sla.ConfigurableValues {
  1030. if len(selectValues) > 0 {
  1031. return true
  1032. }
  1033. }
  1034. return false
  1035. }
  1036. // Append appends all values, including os and arch specific ones, from another
  1037. // StringListAttribute to this StringListAttribute
  1038. func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute {
  1039. sla.Value = append(sla.Value, other.Value...)
  1040. if sla.ConfigurableValues == nil {
  1041. sla.ConfigurableValues = make(configurableStringLists)
  1042. }
  1043. sla.ConfigurableValues.Append(other.ConfigurableValues)
  1044. return sla
  1045. }
  1046. func (sla *StringListAttribute) Clone() *StringListAttribute {
  1047. result := &StringListAttribute{}
  1048. return result.Append(*sla)
  1049. }
  1050. // SetSelectValue set a value for a bazel select for the given axis, config and value.
  1051. func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
  1052. axis.validateConfig(config)
  1053. switch axis.configurationType {
  1054. case noConfig:
  1055. sla.Value = list
  1056. case arch, os, osArch, productVariables:
  1057. if sla.ConfigurableValues == nil {
  1058. sla.ConfigurableValues = make(configurableStringLists)
  1059. }
  1060. sla.ConfigurableValues.setValueForAxis(axis, config, list)
  1061. default:
  1062. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  1063. }
  1064. }
  1065. // SelectValue gets a value for a bazel select for the given axis and config.
  1066. func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
  1067. axis.validateConfig(config)
  1068. switch axis.configurationType {
  1069. case noConfig:
  1070. return sla.Value
  1071. case arch, os, osArch, productVariables:
  1072. return sla.ConfigurableValues[axis][config]
  1073. default:
  1074. panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
  1075. }
  1076. }
  1077. // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
  1078. func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
  1079. keys := make([]ConfigurationAxis, 0, len(sla.ConfigurableValues))
  1080. for k := range sla.ConfigurableValues {
  1081. keys = append(keys, k)
  1082. }
  1083. sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
  1084. return keys
  1085. }
  1086. // DeduplicateAxesFromBase ensures no duplication of items between the no-configuration value and
  1087. // configuration-specific values. For example, if we would convert this StringListAttribute as:
  1088. //
  1089. // ["a", "b", "c"] + select({
  1090. // "//condition:one": ["a", "d"],
  1091. // "//conditions:default": [],
  1092. // })
  1093. //
  1094. // after this function, we would convert this StringListAttribute as:
  1095. //
  1096. // ["a", "b", "c"] + select({
  1097. // "//condition:one": ["d"],
  1098. // "//conditions:default": [],
  1099. // })
  1100. func (sla *StringListAttribute) DeduplicateAxesFromBase() {
  1101. base := sla.Value
  1102. for axis, configToList := range sla.ConfigurableValues {
  1103. for config, list := range configToList {
  1104. remaining := SubtractStrings(list, base)
  1105. if len(remaining) == 0 {
  1106. delete(sla.ConfigurableValues[axis], config)
  1107. } else {
  1108. sla.ConfigurableValues[axis][config] = remaining
  1109. }
  1110. }
  1111. }
  1112. }
  1113. // TryVariableSubstitution, replace string substitution formatting within each string in slice with
  1114. // Starlark string.format compatible tag for productVariable.
  1115. func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
  1116. ret := make([]string, 0, len(slice))
  1117. changesMade := false
  1118. for _, s := range slice {
  1119. newS, changed := TryVariableSubstitution(s, productVariable)
  1120. ret = append(ret, newS)
  1121. changesMade = changesMade || changed
  1122. }
  1123. return ret, changesMade
  1124. }
  1125. // TryVariableSubstitution, replace string substitution formatting within s with Starlark
  1126. // string.format compatible tag for productVariable.
  1127. func TryVariableSubstitution(s string, productVariable string) (string, bool) {
  1128. sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
  1129. return sub, s != sub
  1130. }