diff options
Diffstat (limited to 'android/bazel.go')
-rw-r--r-- | android/bazel.go | 784 |
1 files changed, 0 insertions, 784 deletions
diff --git a/android/bazel.go b/android/bazel.go deleted file mode 100644 index 1602b9b02..000000000 --- a/android/bazel.go +++ /dev/null @@ -1,784 +0,0 @@ -// Copyright 2021 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 android - -import ( - "bufio" - "errors" - "fmt" - "strings" - - "android/soong/ui/metrics/bp2build_metrics_proto" - - "github.com/google/blueprint" - "github.com/google/blueprint/bootstrap" - "github.com/google/blueprint/proptools" - - "android/soong/android/allowlists" -) - -const ( - // A sentinel value to be used as a key in Bp2BuildConfig for modules with - // no package path. This is also the module dir for top level Android.bp - // modules. - Bp2BuildTopLevel = "." -) - -type MixedBuildEnabledStatus int - -const ( - // This module can be mixed_built. - MixedBuildEnabled = iota - - // There is a technical incompatibility preventing this module from being - // bazel-analyzed. Note: the module might also be incompatible. - TechnicalIncompatibility - - // This module cannot be mixed_built due to some incompatibility with it - // that is not a platform incompatibility. Example: the module-type is not - // enabled, or is not bp2build-converted. - ModuleIncompatibility - - // Missing dependencies. We can't query Bazel for modules if it has missing dependencies, there - // will be failures. - ModuleMissingDeps -) - -// FileGroupAsLibrary describes a filegroup module that is converted to some library -// such as aidl_library or proto_library. -type FileGroupAsLibrary interface { - ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool - ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool - GetAidlLibraryLabel(ctx BazelConversionPathContext) string - GetProtoLibraryLabel(ctx BazelConversionPathContext) string -} - -type BazelConversionStatus struct { - // Information about _all_ bp2build targets generated by this module. Multiple targets are - // supported as Soong handles some things within a single target that we may choose to split into - // multiple targets, e.g. renderscript, protos, yacc within a cc module. - Bp2buildInfo []bp2buildInfo `blueprint:"mutated"` - - // UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to - // Bazel - UnconvertedDeps []string `blueprint:"mutated"` - - // MissingBp2buildDep stores the module names of direct dependency that were not found - MissingDeps []string `blueprint:"mutated"` - - // If non-nil, indicates that the module could not be converted successfully - // with bp2build. This will describe the reason the module could not be converted. - UnconvertedReason *UnconvertedReason - - // The Partition this module will be installed on. - // TODO(b/306200980) Investigate how to handle modules that are installed in multiple - // partitions. - Partition string `blueprint:"mutated"` -} - -// The reason a module could not be converted to a BUILD target via bp2build. -// This should match bp2build_metrics_proto.UnconvertedReason, but omits private -// proto-related fields that prevent copying this struct. -type UnconvertedReason struct { - // Should correspond to a valid value in bp2build_metrics_proto.UnconvertedReasonType. - // A raw int is used here instead, because blueprint logic requires that all transitive - // fields of module definitions be primitives. - ReasonType int - Detail string -} - -type BazelModuleProperties struct { - // The label of the Bazel target replacing this Soong module. When run in conversion mode, this - // will import the handcrafted build target into the autogenerated file. Note: this may result in - // a conflict due to duplicate targets if bp2build_available is also set. - Label *string - - // If true, bp2build will generate the converted Bazel target for this module. Note: this may - // cause a conflict due to the duplicate targets if label is also set. - // - // This is a bool pointer to support tristates: true, false, not set. - // - // To opt in a module, set bazel_module: { bp2build_available: true } - // To opt out a module, set bazel_module: { bp2build_available: false } - // To defer the default setting for the directory, do not set the value. - Bp2build_available *bool - - // CanConvertToBazel is set via InitBazelModule to indicate that a module type can be converted to - // Bazel with Bp2build. - CanConvertToBazel bool `blueprint:"mutated"` -} - -// Properties contains common module properties for Bazel migration purposes. -type properties struct { - // In "Bazel mixed build" mode, this represents the Bazel target replacing - // this Soong module. - Bazel_module BazelModuleProperties -} - -// namespacedVariableProperties is a map from a string representing a Soong -// config variable namespace, like "android" or "vendor_name" to a slice of -// pointer to a struct containing a single field called Soong_config_variables -// whose value mirrors the structure in the Blueprint file. -type namespacedVariableProperties map[string][]interface{} - -// BazelModuleBase contains the property structs with metadata for modules which can be converted to -// Bazel. -type BazelModuleBase struct { - bazelProperties properties - - // namespacedVariableProperties is used for soong_config_module_type support - // in bp2build. Soong config modules allow users to set module properties - // based on custom product variables defined in Android.bp files. These - // variables are namespaced to prevent clobbering, especially when set from - // Makefiles. - namespacedVariableProperties namespacedVariableProperties - - // baseModuleType is set when this module was created from a module type - // defined by a soong_config_module_type. Every soong_config_module_type - // "wraps" another module type, e.g. a soong_config_module_type can wrap a - // cc_defaults to a custom_cc_defaults, or cc_binary to a custom_cc_binary. - // This baseModuleType is set to the wrapped module type. - baseModuleType string -} - -// Bazelable is specifies the interface for modules that can be converted to Bazel. -type Bazelable interface { - bazelProps() *properties - HasHandcraftedLabel() bool - HandcraftedLabel() string - GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string - ShouldConvertWithBp2build(ctx ShouldConvertWithBazelContext) bool - shouldConvertWithBp2build(shouldConvertModuleContext, shouldConvertParams) bool - - // ConvertWithBp2build either converts the module to a Bazel build target or - // declares the module as unconvertible (for logging and metrics). - // Modules must implement this function to be bp2build convertible. The function - // must either create at least one Bazel target module (using ctx.CreateBazelTargetModule or - // its related functions), or declare itself unconvertible using ctx.MarkBp2buildUnconvertible. - ConvertWithBp2build(ctx Bp2buildMutatorContext) - - // namespacedVariableProps is a map from a soong config variable namespace - // (e.g. acme, android) to a map of interfaces{}, which are really - // reflect.Struct pointers, representing the value of the - // soong_config_variables property of a module. The struct pointer is the - // one with the single member called Soong_config_variables, which itself is - // a struct containing fields for each supported feature in that namespace. - // - // The reason for using a slice of interface{} is to support defaults - // propagation of the struct pointers. - namespacedVariableProps() namespacedVariableProperties - setNamespacedVariableProps(props namespacedVariableProperties) - BaseModuleType() string - SetBaseModuleType(baseModuleType string) -} - -// ApiProvider is implemented by modules that contribute to an API surface -type ApiProvider interface { - ConvertWithApiBp2build(ctx TopDownMutatorContext) -} - -// MixedBuildBuildable is an interface that module types should implement in order -// to be "handled by Bazel" in a mixed build. -type MixedBuildBuildable interface { - // IsMixedBuildSupported returns true if and only if this module should be - // "handled by Bazel" in a mixed build. - // This "escape hatch" allows modules with corner-case scenarios to opt out - // of being built with Bazel. - IsMixedBuildSupported(ctx BaseModuleContext) bool - - // QueueBazelCall invokes request-queueing functions on the BazelContext - // so that these requests are handled when Bazel's cquery is invoked. - QueueBazelCall(ctx BaseModuleContext) - - // ProcessBazelQueryResponse uses Bazel information (obtained from the BazelContext) - // to set module fields and providers to propagate this module's metadata upstream. - // This effectively "bridges the gap" between Bazel and Soong in a mixed build. - // Soong modules depending on this module should be oblivious to the fact that - // this module was handled by Bazel. - ProcessBazelQueryResponse(ctx ModuleContext) -} - -// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules. -type BazelModule interface { - Module - Bazelable -} - -// InitBazelModule is a wrapper function that decorates a BazelModule with Bazel-conversion -// properties. -func InitBazelModule(module BazelModule) { - module.AddProperties(module.bazelProps()) - module.bazelProps().Bazel_module.CanConvertToBazel = true -} - -// BazelHandcraftedHook is a load hook to possibly register the current module as -// a "handcrafted" Bazel target of a given name. If the current module should be -// registered in this way, the hook function should return the target name. If -// it should not be registered in this way, this function should return the empty string. -type BazelHandcraftedHook func(ctx LoadHookContext) string - -// AddBazelHandcraftedHook adds a load hook to (maybe) mark the given module so that -// it is treated by bp2build as if it has a handcrafted Bazel target. -func AddBazelHandcraftedHook(module BazelModule, hook BazelHandcraftedHook) { - AddLoadHook(module, func(ctx LoadHookContext) { - var targetName string = hook(ctx) - if len(targetName) > 0 { - moduleDir := ctx.ModuleDir() - if moduleDir == Bp2BuildTopLevel { - moduleDir = "" - } - label := fmt.Sprintf("//%s:%s", moduleDir, targetName) - module.bazelProps().Bazel_module.Label = &label - } - }) -} - -// bazelProps returns the Bazel properties for the given BazelModuleBase. -func (b *BazelModuleBase) bazelProps() *properties { - return &b.bazelProperties -} - -func (b *BazelModuleBase) namespacedVariableProps() namespacedVariableProperties { - return b.namespacedVariableProperties -} - -func (b *BazelModuleBase) setNamespacedVariableProps(props namespacedVariableProperties) { - b.namespacedVariableProperties = props -} - -func (b *BazelModuleBase) BaseModuleType() string { - return b.baseModuleType -} - -func (b *BazelModuleBase) SetBaseModuleType(baseModuleType string) { - b.baseModuleType = baseModuleType -} - -// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label. -func (b *BazelModuleBase) HasHandcraftedLabel() bool { - return b.bazelProperties.Bazel_module.Label != nil -} - -// HandcraftedLabel returns the handcrafted label for this module, or empty string if there is none -func (b *BazelModuleBase) HandcraftedLabel() string { - return proptools.String(b.bazelProperties.Bazel_module.Label) -} - -// GetBazelLabel returns the Bazel label for the given BazelModuleBase. -func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string { - if b.HasHandcraftedLabel() { - return b.HandcraftedLabel() - } - if b.ShouldConvertWithBp2build(ctx) { - return bp2buildModuleLabel(ctx, module) - } - panic(fmt.Errorf("requested non-existent label for module %s", module.Name())) -} - -type Bp2BuildConversionAllowlist struct { - // Configure modules in these directories to enable bp2build_available: true or false by default. - defaultConfig allowlists.Bp2BuildConfig - - // Keep any existing BUILD files (and do not generate new BUILD files) for these directories - // in the synthetic Bazel workspace. - keepExistingBuildFile map[string]bool - - // Per-module allowlist to always opt modules into both bp2build and Bazel Dev Mode mixed - // builds. These modules are usually in directories with many other modules that are not ready - // for conversion. - // - // A module can either be in this list or its directory allowlisted entirely - // in bp2buildDefaultConfig, but not both at the same time. - moduleAlwaysConvert map[string]bool - - // Per-module-type allowlist to always opt modules in to both bp2build and - // Bazel Dev Mode mixed builds when they have the same type as one listed. - moduleTypeAlwaysConvert map[string]bool - - // Per-module denylist to always opt modules out of bp2build conversion. - moduleDoNotConvert map[string]bool -} - -// NewBp2BuildAllowlist creates a new, empty Bp2BuildConversionAllowlist -// which can be populated using builder pattern Set* methods -func NewBp2BuildAllowlist() Bp2BuildConversionAllowlist { - return Bp2BuildConversionAllowlist{ - allowlists.Bp2BuildConfig{}, - map[string]bool{}, - map[string]bool{}, - map[string]bool{}, - map[string]bool{}, - } -} - -// SetDefaultConfig copies the entries from defaultConfig into the allowlist -func (a Bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) Bp2BuildConversionAllowlist { - if a.defaultConfig == nil { - a.defaultConfig = allowlists.Bp2BuildConfig{} - } - for k, v := range defaultConfig { - a.defaultConfig[k] = v - } - - return a -} - -// SetKeepExistingBuildFile copies the entries from keepExistingBuildFile into the allowlist -func (a Bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) Bp2BuildConversionAllowlist { - if a.keepExistingBuildFile == nil { - a.keepExistingBuildFile = map[string]bool{} - } - for k, v := range keepExistingBuildFile { - a.keepExistingBuildFile[k] = v - } - - return a -} - -// SetModuleAlwaysConvertList copies the entries from moduleAlwaysConvert into the allowlist -func (a Bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) Bp2BuildConversionAllowlist { - if a.moduleAlwaysConvert == nil { - a.moduleAlwaysConvert = map[string]bool{} - } - for _, m := range moduleAlwaysConvert { - a.moduleAlwaysConvert[m] = true - } - - return a -} - -// SetModuleTypeAlwaysConvertList copies the entries from moduleTypeAlwaysConvert into the allowlist -func (a Bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) Bp2BuildConversionAllowlist { - if a.moduleTypeAlwaysConvert == nil { - a.moduleTypeAlwaysConvert = map[string]bool{} - } - for _, m := range moduleTypeAlwaysConvert { - a.moduleTypeAlwaysConvert[m] = true - } - - return a -} - -// SetModuleDoNotConvertList copies the entries from moduleDoNotConvert into the allowlist -func (a Bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) Bp2BuildConversionAllowlist { - if a.moduleDoNotConvert == nil { - a.moduleDoNotConvert = map[string]bool{} - } - for _, m := range moduleDoNotConvert { - a.moduleDoNotConvert[m] = true - } - - return a -} - -// ShouldKeepExistingBuildFileForDir returns whether an existing BUILD file should be -// added to the build symlink forest based on the current global configuration. -func (a Bp2BuildConversionAllowlist) ShouldKeepExistingBuildFileForDir(dir string) bool { - if _, ok := a.keepExistingBuildFile[dir]; ok { - // Exact dir match - return true - } - var i int - // Check if subtree match - for { - j := strings.Index(dir[i:], "/") - if j == -1 { - return false //default - } - prefix := dir[0 : i+j] - i = i + j + 1 // skip the "/" - if recursive, ok := a.keepExistingBuildFile[prefix]; ok && recursive { - return true - } - } -} - -var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist") -var bp2buildAllowlist OncePer - -func GetBp2BuildAllowList() Bp2BuildConversionAllowlist { - return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} { - return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig). - SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile). - SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList). - SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList). - SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList) - }).(Bp2BuildConversionAllowlist) -} - -// MixedBuildsEnabled returns a MixedBuildEnabledStatus regarding whether -// a module is ready to be replaced by a converted or handcrafted Bazel target. -// As a side effect, calling this method will also log whether this module is -// mixed build enabled for metrics reporting. -func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus { - platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType) - if platformIncompatible { - ctx.Config().LogMixedBuild(ctx, false) - return TechnicalIncompatibility - } - - if ctx.Config().AllowMissingDependencies() { - missingDeps := ctx.getMissingDependencies() - // If there are missing dependencies, querying Bazel will fail. Soong instead fails at execution - // time, not loading/analysis. disable mixed builds and fall back to Soong to maintain that - // behavior. - if len(missingDeps) > 0 { - ctx.Config().LogMixedBuild(ctx, false) - return ModuleMissingDeps - } - } - - module := ctx.Module() - apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo) - withinApex := !apexInfo.IsForPlatform() - mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() && - module.Enabled() && - convertedToBazel(ctx, module) && - ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex) - ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled) - - if mixedBuildEnabled { - return MixedBuildEnabled - } - return ModuleIncompatibility -} - -func isGoModule(module blueprint.Module) bool { - if _, ok := module.(*bootstrap.GoPackage); ok { - return true - } - if _, ok := module.(*bootstrap.GoBinary); ok { - return true - } - return false -} - -// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel. -func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool { - // Special-case bootstrap_go_package and bootstrap_go_binary - // These do not implement Bazelable, but have been converted - if isGoModule(module) { - return true - } - b, ok := module.(Bazelable) - if !ok { - return false - } - - return b.HasHandcraftedLabel() || b.shouldConvertWithBp2build(ctx, shouldConvertParams{ - module: module, - moduleDir: ctx.OtherModuleDir(module), - moduleName: ctx.OtherModuleName(module), - moduleType: ctx.OtherModuleType(module), - }) -} - -type ShouldConvertWithBazelContext interface { - ModuleErrorf(format string, args ...interface{}) - Module() Module - Config() Config - ModuleType() string - ModuleName() string - ModuleDir() string -} - -// ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build -func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx ShouldConvertWithBazelContext) bool { - return b.shouldConvertWithBp2build(ctx, shouldConvertParams{ - module: ctx.Module(), - moduleDir: ctx.ModuleDir(), - moduleName: ctx.ModuleName(), - moduleType: ctx.ModuleType(), - }) -} - -type bazelOtherModuleContext interface { - ModuleErrorf(format string, args ...interface{}) - Config() Config - OtherModuleType(m blueprint.Module) string - OtherModuleName(m blueprint.Module) string - OtherModuleDir(m blueprint.Module) string -} - -func isPlatformIncompatible(osType OsType, arch ArchType) bool { - return osType == Windows || // Windows toolchains are not currently supported. - osType == LinuxBionic || // Linux Bionic toolchains are not currently supported. - osType == LinuxMusl || // Linux musl toolchains are not currently supported (b/259266326). - arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported. -} - -type shouldConvertModuleContext interface { - ModuleErrorf(format string, args ...interface{}) - Config() Config -} - -type shouldConvertParams struct { - module blueprint.Module - moduleType string - moduleDir string - moduleName string -} - -func (b *BazelModuleBase) shouldConvertWithBp2build(ctx shouldConvertModuleContext, p shouldConvertParams) bool { - if !b.bazelProps().Bazel_module.CanConvertToBazel { - return false - } - - module := p.module - - propValue := b.bazelProperties.Bazel_module.Bp2build_available - packagePath := moduleDirWithPossibleOverride(ctx, module, p.moduleDir) - - // Modules in unit tests which are enabled in the allowlist by type or name - // trigger this conditional because unit tests run under the "." package path - isTestModule := packagePath == Bp2BuildTopLevel && proptools.BoolDefault(propValue, false) - if isTestModule { - return true - } - - moduleName := moduleNameWithPossibleOverride(ctx, module, p.moduleName) - // use "prebuilt_" + original module name as the java_import(_host) module name, - // to avoid the failure that a normal module and a prebuilt module with - // the same name are both allowlisted. This cannot be applied to all the *_import - // module types. For example, android_library_import has to use original module - // name here otherwise the *-nodeps targets cannot be handled correctly. - // TODO(b/304385140): remove this special casing - if p.moduleType == "java_import" || p.moduleType == "java_import_host" { - moduleName = module.Name() - } - - allowlist := ctx.Config().Bp2buildPackageConfig - - moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName] - moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[p.moduleType] - allowlistConvert := moduleNameAllowed || moduleTypeAllowed - if moduleNameAllowed && moduleTypeAllowed { - ctx.ModuleErrorf("A module %q of type %q cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert", moduleName, p.moduleType) - return false - } - - if allowlist.moduleDoNotConvert[moduleName] { - if moduleNameAllowed { - ctx.ModuleErrorf("a module %q cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert", moduleName) - } - return false - } - - // This is a tristate value: true, false, or unset. - if ok, directoryPath := bp2buildDefaultTrueRecursively(packagePath, allowlist.defaultConfig); ok { - if moduleNameAllowed { - ctx.ModuleErrorf("A module cannot be in a directory marked Bp2BuildDefaultTrue"+ - " or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: '%s'"+ - " Module: '%s'", directoryPath, moduleName) - return false - } - - // Allow modules to explicitly opt-out. - return proptools.BoolDefault(propValue, true) - } - - // Allow modules to explicitly opt-in. - return proptools.BoolDefault(propValue, allowlistConvert) -} - -// bp2buildDefaultTrueRecursively checks that the package contains a prefix from the -// set of package prefixes where all modules must be converted. That is, if the -// package is x/y/z, and the list contains either x, x/y, or x/y/z, this function will -// return true. -// -// However, if the package is x/y, and it matches a Bp2BuildDefaultFalse "x/y" entry -// exactly, this module will return false early. -// -// This function will also return false if the package doesn't match anything in -// the config. -// -// This function will also return the allowlist entry which caused a particular -// package to be enabled. Since packages can be enabled via a recursive declaration, -// the path returned will not always be the same as the one provided. -func bp2buildDefaultTrueRecursively(packagePath string, config allowlists.Bp2BuildConfig) (bool, string) { - // Check if the package path has an exact match in the config. - if config[packagePath] == allowlists.Bp2BuildDefaultTrue || config[packagePath] == allowlists.Bp2BuildDefaultTrueRecursively { - return true, packagePath - } else if config[packagePath] == allowlists.Bp2BuildDefaultFalse || config[packagePath] == allowlists.Bp2BuildDefaultFalseRecursively { - return false, packagePath - } - - // If not, check for the config recursively. - packagePrefix := packagePath - - // e.g. for x/y/z, iterate over x/y, then x, taking the most-specific value from the allowlist. - for strings.Contains(packagePrefix, "/") { - dirIndex := strings.LastIndex(packagePrefix, "/") - packagePrefix = packagePrefix[:dirIndex] - switch value := config[packagePrefix]; value { - case allowlists.Bp2BuildDefaultTrueRecursively: - // package contains this prefix and this prefix should convert all modules - return true, packagePrefix - case allowlists.Bp2BuildDefaultFalseRecursively: - //package contains this prefix and this prefix should NOT convert any modules - return false, packagePrefix - } - // Continue to the next part of the package dir. - - } - - return false, packagePath -} - -func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) { - ctx.BottomUp("bp2build_conversion", bp2buildConversionMutator).Parallel() - ctx.BottomUp("bp2build_deps", bp2buildDepsMutator).Parallel() -} - -func bp2buildConversionMutator(ctx BottomUpMutatorContext) { - // If an existing BUILD file in the module directory has a target defined - // with this same name as this module, assume that this is an existing - // definition for this target. - if ctx.Config().HasBazelBuildTargetInSource(ctx.ModuleDir(), ctx.ModuleName()) { - ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, ctx.ModuleName()) - return - } - bModule, ok := ctx.Module().(Bazelable) - if !ok { - ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "") - return - } - // There may be cases where the target is created by a macro rather than in a BUILD file, those - // should be captured as well. - if bModule.HasHandcraftedLabel() { - // Defer to the BUILD target. Generating an additional target would - // cause a BUILD file conflict. - ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "") - return - } - // TODO: b/285631638 - Differentiate between denylisted modules and missing bp2build capabilities. - if !bModule.shouldConvertWithBp2build(ctx, shouldConvertParams{ - module: ctx.Module(), - moduleDir: ctx.ModuleDir(), - moduleName: ctx.ModuleName(), - moduleType: ctx.ModuleType(), - }) { - ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "") - return - } - if ctx.Module().base().GetUnconvertedReason() != nil { - return - } - - bModule.ConvertWithBp2build(ctx) - - installCtx := &baseModuleContextToModuleInstallPathContext{ctx} - ctx.Module().base().setPartitionForBp2build(modulePartition(installCtx, true)) - - if len(ctx.Module().base().Bp2buildTargets()) == 0 && ctx.Module().base().GetUnconvertedReason() == nil { - panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", ctx.ModuleName())) - } - - // If an existing BUILD file in the module directory has a target defined - // with the same name as any target generated by this module, assume that this - // is an existing definition for this target. (These generated target names - // may be different than the module name, as checked at the beginning of this function!) - for _, targetInfo := range ctx.Module().base().Bp2buildTargets() { - if ctx.Config().HasBazelBuildTargetInSource(targetInfo.TargetPackage(), targetInfo.TargetName()) { - // Defer to the BUILD target. Generating an additional target would - // cause a BUILD file conflict. - ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, targetInfo.TargetName()) - return - } - } -} - -// TODO: b/285631638 - Add this as a new mutator to the bp2build conversion mutators. -// Currently, this only exists to prepare test coverage for the launch of this feature. -func bp2buildDepsMutator(ctx BottomUpMutatorContext) { - if ctx.Module().base().GetUnconvertedReason() != nil { - return - } - - if len(ctx.Module().GetMissingBp2buildDeps()) > 0 { - exampleDep := ctx.Module().GetMissingBp2buildDeps()[0] - ctx.MarkBp2buildUnconvertible( - bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, exampleDep) - } - - // Transitively mark modules unconvertible with the following set of conditions. - ctx.VisitDirectDeps(func(dep Module) { - if dep.base().GetUnconvertedReason() == nil { - return - } - - if dep.base().GetUnconvertedReason().ReasonType == - int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) { - return - } - - if ctx.OtherModuleDependencyTag(dep) != Bp2buildDepTag { - return - } - - ctx.MarkBp2buildUnconvertible( - bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, dep.Name()) - }) -} - -// GetMainClassInManifest scans the manifest file specified in filepath and returns -// the value of attribute Main-Class in the manifest file if it exists, or returns error. -// WARNING: this is for bp2build converters of java_* modules only. -func GetMainClassInManifest(c Config, filepath string) (string, error) { - file, err := c.fs.Open(filepath) - if err != nil { - return "", err - } - defer file.Close() - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, "Main-Class:") { - return strings.TrimSpace(line[len("Main-Class:"):]), nil - } - } - - return "", errors.New("Main-Class is not found.") -} - -func AttachValidationActions(ctx ModuleContext, outputFilePath Path, validations Paths) ModuleOutPath { - validatedOutputFilePath := PathForModuleOut(ctx, "validated", outputFilePath.Base()) - ctx.Build(pctx, BuildParams{ - Rule: CpNoPreserveSymlink, - Description: "run validations " + outputFilePath.Base(), - Output: validatedOutputFilePath, - Input: outputFilePath, - Validations: validations, - }) - return validatedOutputFilePath -} - -func RunsOn(hostSupported bool, deviceSupported bool, unitTest bool) []string { - var runsOn []string - - if hostSupported && deviceSupported { - runsOn = []string{"host_without_device", "device"} - } else if hostSupported { - if unitTest { - runsOn = []string{"host_without_device"} - } else { - runsOn = []string{"host_with_device"} - } - } else if deviceSupported { - runsOn = []string{"device"} - } - - return runsOn -} |