bazel.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. // Copyright 2021 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 android
  15. import (
  16. "bufio"
  17. "errors"
  18. "strings"
  19. "github.com/google/blueprint"
  20. "github.com/google/blueprint/proptools"
  21. "android/soong/android/allowlists"
  22. )
  23. const (
  24. // A sentinel value to be used as a key in Bp2BuildConfig for modules with
  25. // no package path. This is also the module dir for top level Android.bp
  26. // modules.
  27. Bp2BuildTopLevel = "."
  28. )
  29. type MixedBuildEnabledStatus int
  30. const (
  31. // This module can be mixed_built.
  32. MixedBuildEnabled = iota
  33. // There is a technical incompatibility preventing this module from being
  34. // bazel-analyzed. Note: the module might also be incompatible.
  35. TechnicalIncompatibility
  36. // This module cannot be mixed_built due to some incompatibility with it
  37. // that is not a platform incompatibility. Example: the module-type is not
  38. // enabled, or is not bp2build-converted.
  39. ModuleIncompatibility
  40. // Missing dependencies. We can't query Bazel for modules if it has missing dependencies, there
  41. // will be failures.
  42. ModuleMissingDeps
  43. )
  44. // FileGroupAsLibrary describes a filegroup module that is converted to some library
  45. // such as aidl_library or proto_library.
  46. type FileGroupAsLibrary interface {
  47. ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool
  48. ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool
  49. GetAidlLibraryLabel(ctx BazelConversionPathContext) string
  50. GetProtoLibraryLabel(ctx BazelConversionPathContext) string
  51. }
  52. type BazelConversionStatus struct {
  53. // Information about _all_ bp2build targets generated by this module. Multiple targets are
  54. // supported as Soong handles some things within a single target that we may choose to split into
  55. // multiple targets, e.g. renderscript, protos, yacc within a cc module.
  56. Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
  57. // UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
  58. // Bazel
  59. UnconvertedDeps []string `blueprint:"mutated"`
  60. // MissingBp2buildDep stores the module names of direct dependency that were not found
  61. MissingDeps []string `blueprint:"mutated"`
  62. }
  63. type BazelModuleProperties struct {
  64. // The label of the Bazel target replacing this Soong module. When run in conversion mode, this
  65. // will import the handcrafted build target into the autogenerated file. Note: this may result in
  66. // a conflict due to duplicate targets if bp2build_available is also set.
  67. Label *string
  68. // If true, bp2build will generate the converted Bazel target for this module. Note: this may
  69. // cause a conflict due to the duplicate targets if label is also set.
  70. //
  71. // This is a bool pointer to support tristates: true, false, not set.
  72. //
  73. // To opt in a module, set bazel_module: { bp2build_available: true }
  74. // To opt out a module, set bazel_module: { bp2build_available: false }
  75. // To defer the default setting for the directory, do not set the value.
  76. Bp2build_available *bool
  77. // CanConvertToBazel is set via InitBazelModule to indicate that a module type can be converted to
  78. // Bazel with Bp2build.
  79. CanConvertToBazel bool `blueprint:"mutated"`
  80. }
  81. // Properties contains common module properties for Bazel migration purposes.
  82. type properties struct {
  83. // In "Bazel mixed build" mode, this represents the Bazel target replacing
  84. // this Soong module.
  85. Bazel_module BazelModuleProperties
  86. }
  87. // namespacedVariableProperties is a map from a string representing a Soong
  88. // config variable namespace, like "android" or "vendor_name" to a slice of
  89. // pointer to a struct containing a single field called Soong_config_variables
  90. // whose value mirrors the structure in the Blueprint file.
  91. type namespacedVariableProperties map[string][]interface{}
  92. // BazelModuleBase contains the property structs with metadata for modules which can be converted to
  93. // Bazel.
  94. type BazelModuleBase struct {
  95. bazelProperties properties
  96. // namespacedVariableProperties is used for soong_config_module_type support
  97. // in bp2build. Soong config modules allow users to set module properties
  98. // based on custom product variables defined in Android.bp files. These
  99. // variables are namespaced to prevent clobbering, especially when set from
  100. // Makefiles.
  101. namespacedVariableProperties namespacedVariableProperties
  102. // baseModuleType is set when this module was created from a module type
  103. // defined by a soong_config_module_type. Every soong_config_module_type
  104. // "wraps" another module type, e.g. a soong_config_module_type can wrap a
  105. // cc_defaults to a custom_cc_defaults, or cc_binary to a custom_cc_binary.
  106. // This baseModuleType is set to the wrapped module type.
  107. baseModuleType string
  108. }
  109. // Bazelable is specifies the interface for modules that can be converted to Bazel.
  110. type Bazelable interface {
  111. bazelProps() *properties
  112. HasHandcraftedLabel() bool
  113. HandcraftedLabel() string
  114. GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
  115. ShouldConvertWithBp2build(ctx BazelConversionContext) bool
  116. shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool
  117. ConvertWithBp2build(ctx TopDownMutatorContext)
  118. // namespacedVariableProps is a map from a soong config variable namespace
  119. // (e.g. acme, android) to a map of interfaces{}, which are really
  120. // reflect.Struct pointers, representing the value of the
  121. // soong_config_variables property of a module. The struct pointer is the
  122. // one with the single member called Soong_config_variables, which itself is
  123. // a struct containing fields for each supported feature in that namespace.
  124. //
  125. // The reason for using a slice of interface{} is to support defaults
  126. // propagation of the struct pointers.
  127. namespacedVariableProps() namespacedVariableProperties
  128. setNamespacedVariableProps(props namespacedVariableProperties)
  129. BaseModuleType() string
  130. SetBaseModuleType(baseModuleType string)
  131. }
  132. // ApiProvider is implemented by modules that contribute to an API surface
  133. type ApiProvider interface {
  134. ConvertWithApiBp2build(ctx TopDownMutatorContext)
  135. }
  136. // MixedBuildBuildable is an interface that module types should implement in order
  137. // to be "handled by Bazel" in a mixed build.
  138. type MixedBuildBuildable interface {
  139. // IsMixedBuildSupported returns true if and only if this module should be
  140. // "handled by Bazel" in a mixed build.
  141. // This "escape hatch" allows modules with corner-case scenarios to opt out
  142. // of being built with Bazel.
  143. IsMixedBuildSupported(ctx BaseModuleContext) bool
  144. // QueueBazelCall invokes request-queueing functions on the BazelContext
  145. // so that these requests are handled when Bazel's cquery is invoked.
  146. QueueBazelCall(ctx BaseModuleContext)
  147. // ProcessBazelQueryResponse uses Bazel information (obtained from the BazelContext)
  148. // to set module fields and providers to propagate this module's metadata upstream.
  149. // This effectively "bridges the gap" between Bazel and Soong in a mixed build.
  150. // Soong modules depending on this module should be oblivious to the fact that
  151. // this module was handled by Bazel.
  152. ProcessBazelQueryResponse(ctx ModuleContext)
  153. }
  154. // BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
  155. type BazelModule interface {
  156. Module
  157. Bazelable
  158. }
  159. // InitBazelModule is a wrapper function that decorates a BazelModule with Bazel-conversion
  160. // properties.
  161. func InitBazelModule(module BazelModule) {
  162. module.AddProperties(module.bazelProps())
  163. module.bazelProps().Bazel_module.CanConvertToBazel = true
  164. }
  165. // bazelProps returns the Bazel properties for the given BazelModuleBase.
  166. func (b *BazelModuleBase) bazelProps() *properties {
  167. return &b.bazelProperties
  168. }
  169. func (b *BazelModuleBase) namespacedVariableProps() namespacedVariableProperties {
  170. return b.namespacedVariableProperties
  171. }
  172. func (b *BazelModuleBase) setNamespacedVariableProps(props namespacedVariableProperties) {
  173. b.namespacedVariableProperties = props
  174. }
  175. func (b *BazelModuleBase) BaseModuleType() string {
  176. return b.baseModuleType
  177. }
  178. func (b *BazelModuleBase) SetBaseModuleType(baseModuleType string) {
  179. b.baseModuleType = baseModuleType
  180. }
  181. // HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
  182. func (b *BazelModuleBase) HasHandcraftedLabel() bool {
  183. return b.bazelProperties.Bazel_module.Label != nil
  184. }
  185. // HandcraftedLabel returns the handcrafted label for this module, or empty string if there is none
  186. func (b *BazelModuleBase) HandcraftedLabel() string {
  187. return proptools.String(b.bazelProperties.Bazel_module.Label)
  188. }
  189. // GetBazelLabel returns the Bazel label for the given BazelModuleBase.
  190. func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
  191. if b.HasHandcraftedLabel() {
  192. return b.HandcraftedLabel()
  193. }
  194. if b.ShouldConvertWithBp2build(ctx) {
  195. return bp2buildModuleLabel(ctx, module)
  196. }
  197. return "" // no label for unconverted module
  198. }
  199. type Bp2BuildConversionAllowlist struct {
  200. // Configure modules in these directories to enable bp2build_available: true or false by default.
  201. defaultConfig allowlists.Bp2BuildConfig
  202. // Keep any existing BUILD files (and do not generate new BUILD files) for these directories
  203. // in the synthetic Bazel workspace.
  204. keepExistingBuildFile map[string]bool
  205. // Per-module allowlist to always opt modules into both bp2build and Bazel Dev Mode mixed
  206. // builds. These modules are usually in directories with many other modules that are not ready
  207. // for conversion.
  208. //
  209. // A module can either be in this list or its directory allowlisted entirely
  210. // in bp2buildDefaultConfig, but not both at the same time.
  211. moduleAlwaysConvert map[string]bool
  212. // Per-module-type allowlist to always opt modules in to both bp2build and
  213. // Bazel Dev Mode mixed builds when they have the same type as one listed.
  214. moduleTypeAlwaysConvert map[string]bool
  215. // Per-module denylist to always opt modules out of bp2build conversion.
  216. moduleDoNotConvert map[string]bool
  217. }
  218. // NewBp2BuildAllowlist creates a new, empty Bp2BuildConversionAllowlist
  219. // which can be populated using builder pattern Set* methods
  220. func NewBp2BuildAllowlist() Bp2BuildConversionAllowlist {
  221. return Bp2BuildConversionAllowlist{
  222. allowlists.Bp2BuildConfig{},
  223. map[string]bool{},
  224. map[string]bool{},
  225. map[string]bool{},
  226. map[string]bool{},
  227. }
  228. }
  229. // SetDefaultConfig copies the entries from defaultConfig into the allowlist
  230. func (a Bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) Bp2BuildConversionAllowlist {
  231. if a.defaultConfig == nil {
  232. a.defaultConfig = allowlists.Bp2BuildConfig{}
  233. }
  234. for k, v := range defaultConfig {
  235. a.defaultConfig[k] = v
  236. }
  237. return a
  238. }
  239. // SetKeepExistingBuildFile copies the entries from keepExistingBuildFile into the allowlist
  240. func (a Bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) Bp2BuildConversionAllowlist {
  241. if a.keepExistingBuildFile == nil {
  242. a.keepExistingBuildFile = map[string]bool{}
  243. }
  244. for k, v := range keepExistingBuildFile {
  245. a.keepExistingBuildFile[k] = v
  246. }
  247. return a
  248. }
  249. // SetModuleAlwaysConvertList copies the entries from moduleAlwaysConvert into the allowlist
  250. func (a Bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) Bp2BuildConversionAllowlist {
  251. if a.moduleAlwaysConvert == nil {
  252. a.moduleAlwaysConvert = map[string]bool{}
  253. }
  254. for _, m := range moduleAlwaysConvert {
  255. a.moduleAlwaysConvert[m] = true
  256. }
  257. return a
  258. }
  259. // SetModuleTypeAlwaysConvertList copies the entries from moduleTypeAlwaysConvert into the allowlist
  260. func (a Bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) Bp2BuildConversionAllowlist {
  261. if a.moduleTypeAlwaysConvert == nil {
  262. a.moduleTypeAlwaysConvert = map[string]bool{}
  263. }
  264. for _, m := range moduleTypeAlwaysConvert {
  265. a.moduleTypeAlwaysConvert[m] = true
  266. }
  267. return a
  268. }
  269. // SetModuleDoNotConvertList copies the entries from moduleDoNotConvert into the allowlist
  270. func (a Bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) Bp2BuildConversionAllowlist {
  271. if a.moduleDoNotConvert == nil {
  272. a.moduleDoNotConvert = map[string]bool{}
  273. }
  274. for _, m := range moduleDoNotConvert {
  275. a.moduleDoNotConvert[m] = true
  276. }
  277. return a
  278. }
  279. // ShouldKeepExistingBuildFileForDir returns whether an existing BUILD file should be
  280. // added to the build symlink forest based on the current global configuration.
  281. func (a Bp2BuildConversionAllowlist) ShouldKeepExistingBuildFileForDir(dir string) bool {
  282. if _, ok := a.keepExistingBuildFile[dir]; ok {
  283. // Exact dir match
  284. return true
  285. }
  286. var i int
  287. // Check if subtree match
  288. for {
  289. j := strings.Index(dir[i:], "/")
  290. if j == -1 {
  291. return false //default
  292. }
  293. prefix := dir[0 : i+j]
  294. i = i + j + 1 // skip the "/"
  295. if recursive, ok := a.keepExistingBuildFile[prefix]; ok && recursive {
  296. return true
  297. }
  298. }
  299. }
  300. var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist")
  301. var bp2buildAllowlist OncePer
  302. func GetBp2BuildAllowList() Bp2BuildConversionAllowlist {
  303. return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} {
  304. return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig).
  305. SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile).
  306. SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList).
  307. SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList).
  308. SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList)
  309. }).(Bp2BuildConversionAllowlist)
  310. }
  311. // MixedBuildsEnabled returns a MixedBuildEnabledStatus regarding whether
  312. // a module is ready to be replaced by a converted or handcrafted Bazel target.
  313. // As a side effect, calling this method will also log whether this module is
  314. // mixed build enabled for metrics reporting.
  315. func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus {
  316. platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType)
  317. if platformIncompatible {
  318. ctx.Config().LogMixedBuild(ctx, false)
  319. return TechnicalIncompatibility
  320. }
  321. if ctx.Config().AllowMissingDependencies() {
  322. missingDeps := ctx.getMissingDependencies()
  323. // If there are missing dependencies, querying Bazel will fail. Soong instead fails at execution
  324. // time, not loading/analysis. disable mixed builds and fall back to Soong to maintain that
  325. // behavior.
  326. if len(missingDeps) > 0 {
  327. ctx.Config().LogMixedBuild(ctx, false)
  328. return ModuleMissingDeps
  329. }
  330. }
  331. module := ctx.Module()
  332. apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
  333. withinApex := !apexInfo.IsForPlatform()
  334. mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
  335. module.Enabled() &&
  336. convertedToBazel(ctx, module) &&
  337. ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
  338. ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
  339. if mixedBuildEnabled {
  340. return MixedBuildEnabled
  341. }
  342. return ModuleIncompatibility
  343. }
  344. // ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
  345. func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool {
  346. b, ok := module.(Bazelable)
  347. if !ok {
  348. return false
  349. }
  350. return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
  351. }
  352. // ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build
  353. func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool {
  354. return b.shouldConvertWithBp2build(ctx, ctx.Module())
  355. }
  356. type bazelOtherModuleContext interface {
  357. ModuleErrorf(format string, args ...interface{})
  358. Config() Config
  359. OtherModuleType(m blueprint.Module) string
  360. OtherModuleName(m blueprint.Module) string
  361. OtherModuleDir(m blueprint.Module) string
  362. }
  363. func isPlatformIncompatible(osType OsType, arch ArchType) bool {
  364. return osType == Windows || // Windows toolchains are not currently supported.
  365. osType == LinuxBionic || // Linux Bionic toolchains are not currently supported.
  366. osType == LinuxMusl || // Linux musl toolchains are not currently supported (b/259266326).
  367. arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported.
  368. }
  369. func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool {
  370. if !b.bazelProps().Bazel_module.CanConvertToBazel {
  371. return false
  372. }
  373. // In api_bp2build mode, all soong modules that can provide API contributions should be converted
  374. // This is irrespective of its presence/absence in bp2build allowlists
  375. if ctx.Config().BuildMode == ApiBp2build {
  376. _, providesApis := module.(ApiProvider)
  377. return providesApis
  378. }
  379. propValue := b.bazelProperties.Bazel_module.Bp2build_available
  380. packagePath := moduleDirWithPossibleOverride(ctx, module)
  381. // Modules in unit tests which are enabled in the allowlist by type or name
  382. // trigger this conditional because unit tests run under the "." package path
  383. isTestModule := packagePath == Bp2BuildTopLevel && proptools.BoolDefault(propValue, false)
  384. if isTestModule {
  385. return true
  386. }
  387. moduleName := moduleNameWithPossibleOverride(ctx, module)
  388. allowlist := ctx.Config().Bp2buildPackageConfig
  389. moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName]
  390. moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)]
  391. allowlistConvert := moduleNameAllowed || moduleTypeAllowed
  392. if moduleNameAllowed && moduleTypeAllowed {
  393. ctx.ModuleErrorf("A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert")
  394. return false
  395. }
  396. if allowlist.moduleDoNotConvert[moduleName] {
  397. if moduleNameAllowed {
  398. ctx.ModuleErrorf("a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert")
  399. }
  400. return false
  401. }
  402. // This is a tristate value: true, false, or unset.
  403. if ok, directoryPath := bp2buildDefaultTrueRecursively(packagePath, allowlist.defaultConfig); ok {
  404. if moduleNameAllowed {
  405. ctx.ModuleErrorf("A module cannot be in a directory marked Bp2BuildDefaultTrue"+
  406. " or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: '%s'"+
  407. " Module: '%s'", directoryPath, moduleName)
  408. return false
  409. }
  410. // Allow modules to explicitly opt-out.
  411. return proptools.BoolDefault(propValue, true)
  412. }
  413. // Allow modules to explicitly opt-in.
  414. return proptools.BoolDefault(propValue, allowlistConvert)
  415. }
  416. // bp2buildDefaultTrueRecursively checks that the package contains a prefix from the
  417. // set of package prefixes where all modules must be converted. That is, if the
  418. // package is x/y/z, and the list contains either x, x/y, or x/y/z, this function will
  419. // return true.
  420. //
  421. // However, if the package is x/y, and it matches a Bp2BuildDefaultFalse "x/y" entry
  422. // exactly, this module will return false early.
  423. //
  424. // This function will also return false if the package doesn't match anything in
  425. // the config.
  426. //
  427. // This function will also return the allowlist entry which caused a particular
  428. // package to be enabled. Since packages can be enabled via a recursive declaration,
  429. // the path returned will not always be the same as the one provided.
  430. func bp2buildDefaultTrueRecursively(packagePath string, config allowlists.Bp2BuildConfig) (bool, string) {
  431. // Check if the package path has an exact match in the config.
  432. if config[packagePath] == allowlists.Bp2BuildDefaultTrue || config[packagePath] == allowlists.Bp2BuildDefaultTrueRecursively {
  433. return true, packagePath
  434. } else if config[packagePath] == allowlists.Bp2BuildDefaultFalse || config[packagePath] == allowlists.Bp2BuildDefaultFalseRecursively {
  435. return false, packagePath
  436. }
  437. // If not, check for the config recursively.
  438. packagePrefix := packagePath
  439. // e.g. for x/y/z, iterate over x/y, then x, taking the most-specific value from the allowlist.
  440. for strings.Contains(packagePrefix, "/") {
  441. dirIndex := strings.LastIndex(packagePrefix, "/")
  442. packagePrefix = packagePrefix[:dirIndex]
  443. switch value := config[packagePrefix]; value {
  444. case allowlists.Bp2BuildDefaultTrueRecursively:
  445. // package contains this prefix and this prefix should convert all modules
  446. return true, packagePrefix
  447. case allowlists.Bp2BuildDefaultFalseRecursively:
  448. //package contains this prefix and this prefix should NOT convert any modules
  449. return false, packagePrefix
  450. }
  451. // Continue to the next part of the package dir.
  452. }
  453. return false, packagePath
  454. }
  455. func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
  456. ctx.TopDown("bp2build_conversion", convertWithBp2build).Parallel()
  457. }
  458. func convertWithBp2build(ctx TopDownMutatorContext) {
  459. if ctx.Config().HasBazelBuildTargetInSource(ctx) {
  460. // Defer to the BUILD target. Generating an additional target would
  461. // cause a BUILD file conflict.
  462. return
  463. }
  464. bModule, ok := ctx.Module().(Bazelable)
  465. if !ok || !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
  466. return
  467. }
  468. bModule.ConvertWithBp2build(ctx)
  469. }
  470. func registerApiBp2buildConversionMutator(ctx RegisterMutatorsContext) {
  471. ctx.TopDown("apiBp2build_conversion", convertWithApiBp2build).Parallel()
  472. }
  473. // Generate API contribution targets if the Soong module provides APIs
  474. func convertWithApiBp2build(ctx TopDownMutatorContext) {
  475. if m, ok := ctx.Module().(ApiProvider); ok {
  476. m.ConvertWithApiBp2build(ctx)
  477. }
  478. }
  479. // GetMainClassInManifest scans the manifest file specified in filepath and returns
  480. // the value of attribute Main-Class in the manifest file if it exists, or returns error.
  481. // WARNING: this is for bp2build converters of java_* modules only.
  482. func GetMainClassInManifest(c Config, filepath string) (string, error) {
  483. file, err := c.fs.Open(filepath)
  484. if err != nil {
  485. return "", err
  486. }
  487. defer file.Close()
  488. scanner := bufio.NewScanner(file)
  489. for scanner.Scan() {
  490. line := scanner.Text()
  491. if strings.HasPrefix(line, "Main-Class:") {
  492. return strings.TrimSpace(line[len("Main-Class:"):]), nil
  493. }
  494. }
  495. return "", errors.New("Main-Class is not found.")
  496. }
  497. func AttachValidationActions(ctx ModuleContext, outputFilePath Path, validations Paths) ModuleOutPath {
  498. validatedOutputFilePath := PathForModuleOut(ctx, "validated", outputFilePath.Base())
  499. ctx.Build(pctx, BuildParams{
  500. Rule: CpNoPreserveSymlink,
  501. Description: "run validations " + outputFilePath.Base(),
  502. Output: validatedOutputFilePath,
  503. Input: outputFilePath,
  504. Validations: validations,
  505. })
  506. return validatedOutputFilePath
  507. }