bp2build: add allowlist for package-level conversions.

This CL adds the support for specifying lists of directories in
build/soong/android/bazel.go, which are then written into
out/soong/bp2build/MANIFEST. Using this configuration,
modules/directories can either default to bp2build_available: true or
false, while still retaining the ability to opt-in or out at the module level.

It also ensures that ConvertWithBp2Build returns true iff the module
type has a registered bp2build converter.

Test: go tests
Test: demo.sh full
Test: TreeHugger presubmits for bp2build and mixed builds.

Change-Id: I0e0f6f4b1b2ec045f2f1c338f7084defc5d23a55
This commit is contained in:
Jingwen Chen 2021-03-10 02:05:59 -05:00
parent dca349a782
commit 12b4c2706d
20 changed files with 409 additions and 57 deletions

View File

@ -85,6 +85,7 @@ bootstrap_go_package {
"androidmk_test.go", "androidmk_test.go",
"apex_test.go", "apex_test.go",
"arch_test.go", "arch_test.go",
"bazel_test.go",
"config_test.go", "config_test.go",
"csuite_config_test.go", "csuite_config_test.go",
"depset_test.go", "depset_test.go",

View File

@ -32,7 +32,13 @@ type bazelModuleProperties struct {
// If true, bp2build will generate the converted Bazel target for this module. Note: this may // 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. // cause a conflict due to the duplicate targets if label is also set.
Bp2build_available bool //
// 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
} }
// Properties contains common module properties for Bazel migration purposes. // Properties contains common module properties for Bazel migration purposes.
@ -54,9 +60,9 @@ type Bazelable interface {
HasHandcraftedLabel() bool HasHandcraftedLabel() bool
HandcraftedLabel() string HandcraftedLabel() string
GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
ConvertWithBp2build() bool ConvertWithBp2build(ctx BazelConversionPathContext) bool
GetBazelBuildFileContents(c Config, path, name string) (string, error) GetBazelBuildFileContents(c Config, path, name string) (string, error)
ConvertedToBazel() bool ConvertedToBazel(ctx BazelConversionPathContext) bool
} }
// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules. // BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
@ -91,15 +97,91 @@ func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module b
if b.HasHandcraftedLabel() { if b.HasHandcraftedLabel() {
return b.HandcraftedLabel() return b.HandcraftedLabel()
} }
if b.ConvertWithBp2build() { if b.ConvertWithBp2build(ctx) {
return bp2buildModuleLabel(ctx, module) return bp2buildModuleLabel(ctx, module)
} }
return "" // no label for unconverted module return "" // no label for unconverted module
} }
// Configuration to decide if modules in a directory should default to true/false for bp2build_available
type Bp2BuildConfig map[string]BazelConversionConfigEntry
type BazelConversionConfigEntry int
const (
// iota + 1 ensures that the int value is not 0 when used in the Bp2buildAllowlist map,
// which can also mean that the key doesn't exist in a lookup.
// all modules in this package and subpackages default to bp2build_available: true.
// allows modules to opt-out.
Bp2BuildDefaultTrueRecursively BazelConversionConfigEntry = iota + 1
// all modules in this package (not recursively) default to bp2build_available: false.
// allows modules to opt-in.
Bp2BuildDefaultFalse
)
var (
// Configure modules in these directories to enable bp2build_available: true or false by default.
bp2buildDefaultConfig = Bp2BuildConfig{
"bionic": Bp2BuildDefaultTrueRecursively,
"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
}
)
// ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build. // ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
func (b *BazelModuleBase) ConvertWithBp2build() bool { func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionPathContext) bool {
return b.bazelProperties.Bazel_module.Bp2build_available // Ensure that the module type of this module has a bp2build converter. This
// prevents mixed builds from using auto-converted modules just by matching
// the package dir; it also has to have a bp2build mutator as well.
if ctx.Config().bp2buildModuleTypeConfig[ctx.ModuleType()] == false {
return false
}
packagePath := ctx.ModuleDir()
config := ctx.Config().bp2buildPackageConfig
// This is a tristate value: true, false, or unset.
propValue := b.bazelProperties.Bazel_module.Bp2build_available
if bp2buildDefaultTrueRecursively(packagePath, config) {
// Allow modules to explicitly opt-out.
return proptools.BoolDefault(propValue, true)
}
// Allow modules to explicitly opt-in.
return proptools.BoolDefault(propValue, false)
}
// 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.
func bp2buildDefaultTrueRecursively(packagePath string, config Bp2BuildConfig) bool {
ret := false
if config[packagePath] == Bp2BuildDefaultFalse {
return false
}
packagePrefix := ""
// e.g. for x/y/z, iterate over x, x/y, then x/y/z, taking the final value from the allowlist.
for _, part := range strings.Split(packagePath, "/") {
packagePrefix += part
if config[packagePrefix] == Bp2BuildDefaultTrueRecursively {
// package contains this prefix and this prefix should convert all modules
return true
}
// Continue to the next part of the package dir.
packagePrefix += "/"
}
return ret
} }
// GetBazelBuildFileContents returns the file contents of a hand-crafted BUILD file if available or // GetBazelBuildFileContents returns the file contents of a hand-crafted BUILD file if available or
@ -126,6 +208,6 @@ func (b *BazelModuleBase) GetBazelBuildFileContents(c Config, path, name string)
// ConvertedToBazel returns whether this module has been converted to Bazel, whether automatically // ConvertedToBazel returns whether this module has been converted to Bazel, whether automatically
// or manually // or manually
func (b *BazelModuleBase) ConvertedToBazel() bool { func (b *BazelModuleBase) ConvertedToBazel(ctx BazelConversionPathContext) bool {
return b.ConvertWithBp2build() || b.HasHandcraftedLabel() return b.ConvertWithBp2build(ctx) || b.HasHandcraftedLabel()
} }

134
android/bazel_test.go Normal file
View File

@ -0,0 +1,134 @@
// 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 "testing"
func TestConvertAllModulesInPackage(t *testing.T) {
testCases := []struct {
prefixes Bp2BuildConfig
packageDir string
}{
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a",
},
{
prefixes: Bp2BuildConfig{
"a/b": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a/b": Bp2BuildDefaultTrueRecursively,
"a/b/c": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultTrueRecursively,
"d/e/f": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultFalse,
"a/b": Bp2BuildDefaultTrueRecursively,
"a/b/c": Bp2BuildDefaultFalse,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultTrueRecursively,
"a/b": Bp2BuildDefaultFalse,
"a/b/c": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a",
},
}
for _, test := range testCases {
if !bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes) {
t.Errorf("Expected to convert all modules in %s based on %v, but failed.", test.packageDir, test.prefixes)
}
}
}
func TestModuleOptIn(t *testing.T) {
testCases := []struct {
prefixes Bp2BuildConfig
packageDir string
}{
{
prefixes: Bp2BuildConfig{
"a/b": Bp2BuildDefaultFalse,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultFalse,
"a/b": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a",
},
{
prefixes: Bp2BuildConfig{
"a/b": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a", // opt-in by default
},
{
prefixes: Bp2BuildConfig{
"a/b/c": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultTrueRecursively,
"d/e/f": Bp2BuildDefaultTrueRecursively,
},
packageDir: "foo/bar",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultTrueRecursively,
"a/b": Bp2BuildDefaultFalse,
"a/b/c": Bp2BuildDefaultTrueRecursively,
},
packageDir: "a/b",
},
{
prefixes: Bp2BuildConfig{
"a": Bp2BuildDefaultFalse,
"a/b": Bp2BuildDefaultTrueRecursively,
"a/b/c": Bp2BuildDefaultFalse,
},
packageDir: "a",
},
}
for _, test := range testCases {
if bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes) {
t.Errorf("Expected to allow module opt-in in %s based on %v, but failed.", test.packageDir, test.prefixes)
}
}
}

View File

@ -140,6 +140,9 @@ type config struct {
fs pathtools.FileSystem fs pathtools.FileSystem
mockBpList string mockBpList string
bp2buildPackageConfig Bp2BuildConfig
bp2buildModuleTypeConfig map[string]bool
// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error // If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
// in tests when a path doesn't exist. // in tests when a path doesn't exist.
TestAllowNonExistentPaths bool TestAllowNonExistentPaths bool
@ -281,6 +284,8 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string
config.mockFileSystem(bp, fs) config.mockFileSystem(bp, fs)
config.bp2buildModuleTypeConfig = map[string]bool{}
return Config{config} return Config{config}
} }
@ -452,6 +457,8 @@ func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) {
Bool(config.productVariables.ClangCoverage)) Bool(config.productVariables.ClangCoverage))
config.BazelContext, err = NewBazelContext(config) config.BazelContext, err = NewBazelContext(config)
config.bp2buildPackageConfig = bp2buildDefaultConfig
config.bp2buildModuleTypeConfig = make(map[string]bool)
return Config{config}, err return Config{config}, err
} }

View File

@ -53,7 +53,7 @@ func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {}
func FilegroupBp2Build(ctx TopDownMutatorContext) { func FilegroupBp2Build(ctx TopDownMutatorContext) {
fg, ok := ctx.Module().(*fileGroup) fg, ok := ctx.Module().(*fileGroup)
if !ok || !fg.ConvertWithBp2build() { if !ok || !fg.ConvertWithBp2build(ctx) {
return return
} }

View File

@ -226,7 +226,7 @@ func FinalDepsMutators(f RegisterMutatorFunc) {
var bp2buildPreArchMutators = []RegisterMutatorFunc{} var bp2buildPreArchMutators = []RegisterMutatorFunc{}
var bp2buildDepsMutators = []RegisterMutatorFunc{} var bp2buildDepsMutators = []RegisterMutatorFunc{}
var bp2buildMutators = []RegisterMutatorFunc{} var bp2buildMutators = map[string]RegisterMutatorFunc{}
// RegisterBp2BuildMutator registers specially crafted mutators for // RegisterBp2BuildMutator registers specially crafted mutators for
// converting Blueprint/Android modules into special modules that can // converting Blueprint/Android modules into special modules that can
@ -237,7 +237,7 @@ func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
f := func(ctx RegisterMutatorsContext) { f := func(ctx RegisterMutatorsContext) {
ctx.TopDown(moduleType, m) ctx.TopDown(moduleType, m)
} }
bp2buildMutators = append(bp2buildMutators, f) bp2buildMutators[moduleType] = f
} }
// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules

View File

@ -340,6 +340,7 @@ type BazelConversionPathContext interface {
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
Module() Module Module() Module
ModuleType() string
OtherModuleName(m blueprint.Module) string OtherModuleName(m blueprint.Module) string
OtherModuleDir(m blueprint.Module) string OtherModuleDir(m blueprint.Module) string
} }
@ -450,7 +451,7 @@ func bazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module, t
// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets. // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
b, ok := module.(Bazelable) b, ok := module.(Bazelable)
// TODO(b/181155349): perhaps return an error here if the module can't be/isn't being converted // TODO(b/181155349): perhaps return an error here if the module can't be/isn't being converted
if !ok || !b.ConvertedToBazel() { if !ok || !b.ConvertedToBazel(ctx) {
return bp2buildModuleLabel(ctx, module) return bp2buildModuleLabel(ctx, module)
} }
return b.GetBazelLabel(ctx, module) return b.GetBazelLabel(ctx, module)

View File

@ -174,7 +174,13 @@ func (ctx *Context) RegisterForBazelConversion() {
t.register(ctx) t.register(ctx)
} }
RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators) bp2buildMutatorList := []RegisterMutatorFunc{}
for t, f := range bp2buildMutators {
ctx.config.bp2buildModuleTypeConfig[t] = true
bp2buildMutatorList = append(bp2buildMutatorList, f)
}
RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutatorList)
} }
// Register the pipeline of singletons, module types, and mutators for // Register the pipeline of singletons, module types, and mutators for

View File

@ -158,12 +158,17 @@ func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) {
ctx.finalDeps = append(ctx.finalDeps, f) ctx.finalDeps = append(ctx.finalDeps, f)
} }
func (ctx *TestContext) RegisterBp2BuildConfig(config Bp2BuildConfig) {
ctx.config.bp2buildPackageConfig = config
}
// RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module // RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module
// type to the equivalent Bazel target. // type to the equivalent Bazel target.
func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) { func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
f := func(ctx RegisterMutatorsContext) { f := func(ctx RegisterMutatorsContext) {
ctx.TopDown(moduleType, m) ctx.TopDown(moduleType, m)
} }
ctx.config.bp2buildModuleTypeConfig[moduleType] = true
ctx.bp2buildMutators = append(ctx.bp2buildMutators, f) ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
} }

View File

@ -18,44 +18,48 @@ import (
"android/soong/android" "android/soong/android"
"fmt" "fmt"
"os" "os"
"strings"
) )
// The Bazel bp2build code generator is responsible for writing .bzl files that are equivalent to // Codegen is the backend of bp2build. The code generator is responsible for
// Android.bp files that are capable of being built with Bazel. // writing .bzl files that are equivalent to Android.bp files that are capable
// of being built with Bazel.
func Codegen(ctx *CodegenContext) CodegenMetrics { func Codegen(ctx *CodegenContext) CodegenMetrics {
outputDir := android.PathForOutput(ctx, "bp2build") outputDir := android.PathForOutput(ctx, "bp2build")
android.RemoveAllOutputDir(outputDir) android.RemoveAllOutputDir(outputDir)
ruleShims := CreateRuleShims(android.ModuleTypeFactories())
buildToTargets, metrics := GenerateBazelTargets(ctx) buildToTargets, metrics := GenerateBazelTargets(ctx)
filesToWrite := CreateBazelFiles(ruleShims, buildToTargets, ctx.mode) filesToWrite := CreateBazelFiles(nil, buildToTargets, ctx.mode)
generatedBuildFiles := []string{}
for _, f := range filesToWrite { for _, f := range filesToWrite {
if err := writeFile(outputDir, ctx, f); err != nil { p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
if err := writeFile(ctx, p, f.Contents); err != nil {
fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err) fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)
} }
// if these generated files are modified, regenerate on next run.
generatedBuildFiles = append(generatedBuildFiles, p.String())
} }
// The MANIFEST file contains the full list of files generated by bp2build, excluding itself.
// Its purpose is for downstream tools to understand the set of files converted by bp2build.
manifestFile := outputDir.Join(ctx, "MANIFEST")
writeFile(ctx, manifestFile, strings.Join(generatedBuildFiles, "\n"))
generatedBuildFiles = append(generatedBuildFiles, manifestFile.String())
return metrics return metrics
} }
func writeFile(outputDir android.OutputPath, ctx android.PathContext, f BazelFile) error { // Get the output directory and create it if it doesn't exist.
return writeReadOnlyFile(ctx, getOutputPath(outputDir, ctx, f.Dir), f.Basename, f.Contents) func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
dirPath := outputDir.Join(ctx, dir)
android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm)
return dirPath
} }
func getOutputPath(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath { func writeFile(ctx android.PathContext, pathToFile android.OutputPath, content string) error {
return outputDir.Join(ctx, dir) // These files are made editable to allow users to modify and iterate on them
} // in the source tree.
return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644)
// The auto-conversion directory should be read-only, sufficient for bazel query. The files
// are not intended to be edited by end users.
func writeReadOnlyFile(ctx android.PathContext, dir android.OutputPath, baseName, content string) error {
android.CreateOutputDirIfNonexistent(dir, os.ModePerm)
pathToFile := dir.Join(ctx, baseName)
// 0444 is read-only
err := android.WriteFileToOutputDir(pathToFile, []byte(content), 0444)
return err
} }

View File

@ -412,7 +412,7 @@ load("//build/bazel/rules:rules.bzl", "my_library")`,
config := android.TestConfig(buildDir, nil, testCase.bp, nil) config := android.TestConfig(buildDir, nil, testCase.bp, nil)
ctx := android.NewTestContext(config) ctx := android.NewTestContext(config)
ctx.RegisterModuleType("custom", customModuleFactory) ctx.RegisterModuleType("custom", customModuleFactory)
ctx.RegisterBp2BuildMutator("custom_starlark", customBp2BuildMutatorFromStarlark) ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutatorFromStarlark)
ctx.RegisterForBazelConversion() ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@ -1144,7 +1144,7 @@ genrule {
} }
} }
func TestAllowlistingBp2buildTargets(t *testing.T) { func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
testCases := []struct { testCases := []struct {
moduleTypeUnderTest string moduleTypeUnderTest string
moduleTypeUnderTestFactory android.ModuleFactory moduleTypeUnderTestFactory android.ModuleFactory
@ -1222,6 +1222,124 @@ func TestAllowlistingBp2buildTargets(t *testing.T) {
} }
} }
func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) {
testCases := []struct {
moduleTypeUnderTest string
moduleTypeUnderTestFactory android.ModuleFactory
moduleTypeUnderTestBp2BuildMutator bp2buildMutator
expectedCount map[string]int
description string
bp2buildConfig android.Bp2BuildConfig
checkDir string
fs map[string]string
}{
{
description: "test bp2build config package and subpackages config",
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
expectedCount: map[string]int{
"migrated": 1,
"migrated/but_not_really": 0,
"migrated/but_not_really/but_really": 1,
"not_migrated": 0,
"also_not_migrated": 0,
},
bp2buildConfig: android.Bp2BuildConfig{
"migrated": android.Bp2BuildDefaultTrueRecursively,
"migrated/but_not_really": android.Bp2BuildDefaultFalse,
"not_migrated": android.Bp2BuildDefaultFalse,
},
fs: map[string]string{
"migrated/Android.bp": `filegroup { name: "a" }`,
"migrated/but_not_really/Android.bp": `filegroup { name: "b" }`,
"migrated/but_not_really/but_really/Android.bp": `filegroup { name: "c" }`,
"not_migrated/Android.bp": `filegroup { name: "d" }`,
"also_not_migrated/Android.bp": `filegroup { name: "e" }`,
},
},
{
description: "test bp2build config opt-in and opt-out",
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
expectedCount: map[string]int{
"package-opt-in": 2,
"package-opt-in/subpackage": 0,
"package-opt-out": 1,
"package-opt-out/subpackage": 0,
},
bp2buildConfig: android.Bp2BuildConfig{
"package-opt-in": android.Bp2BuildDefaultFalse,
"package-opt-out": android.Bp2BuildDefaultTrueRecursively,
},
fs: map[string]string{
"package-opt-in/Android.bp": `
filegroup { name: "opt-in-a" }
filegroup { name: "opt-in-b", bazel_module: { bp2build_available: true } }
filegroup { name: "opt-in-c", bazel_module: { bp2build_available: true } }
`,
"package-opt-in/subpackage/Android.bp": `
filegroup { name: "opt-in-d" } // parent package not configured to DefaultTrueRecursively
`,
"package-opt-out/Android.bp": `
filegroup { name: "opt-out-a" }
filegroup { name: "opt-out-b", bazel_module: { bp2build_available: false } }
filegroup { name: "opt-out-c", bazel_module: { bp2build_available: false } }
`,
"package-opt-out/subpackage/Android.bp": `
filegroup { name: "opt-out-g", bazel_module: { bp2build_available: false } }
filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } }
`,
},
},
}
dir := "."
for _, testCase := range testCases {
fs := make(map[string][]byte)
toParse := []string{
"Android.bp",
}
for f, content := range testCase.fs {
if strings.HasSuffix(f, "Android.bp") {
toParse = append(toParse, f)
}
fs[f] = []byte(content)
}
config := android.TestConfig(buildDir, nil, "", fs)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
ctx.RegisterBp2BuildConfig(testCase.bp2buildConfig)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, toParse)
android.FailIfErrored(t, errs)
_, errs = ctx.ResolveDependencies(config)
android.FailIfErrored(t, errs)
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
// For each directory, test that the expected number of generated targets is correct.
for dir, expectedCount := range testCase.expectedCount {
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
if actualCount := len(bazelTargets); actualCount != expectedCount {
t.Fatalf(
"%s: Expected %d bazel target for %s package, got %d",
testCase.description,
expectedCount,
dir,
actualCount)
}
}
}
}
func TestCombineBuildFilesBp2buildTargets(t *testing.T) { func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
testCases := []struct { testCases := []struct {
description string description string

View File

@ -21,14 +21,15 @@ func CreateBazelFiles(
mode CodegenMode) []BazelFile { mode CodegenMode) []BazelFile {
files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles) files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
// Write top level files: WORKSPACE and BUILD. These files are empty. // Write top level files: WORKSPACE. These files are empty.
files = append(files, newFile("", "WORKSPACE", "")) files = append(files, newFile("", "WORKSPACE", ""))
// Used to denote that the top level directory is a package.
files = append(files, newFile("", GeneratedBuildFileName, ""))
files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
if mode == QueryView { if mode == QueryView {
// Used to denote that the top level directory is a package.
files = append(files, newFile("", GeneratedBuildFileName, ""))
files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
// These files are only used for queryview. // These files are only used for queryview.
files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl)) files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))

View File

@ -87,18 +87,10 @@ func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
func TestCreateBazelFiles_Bp2Build_AddsTopLevelFiles(t *testing.T) { func TestCreateBazelFiles_Bp2Build_AddsTopLevelFiles(t *testing.T) {
files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build) files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build)
expectedFilePaths := []filepath{ expectedFilePaths := []filepath{
{
dir: "",
basename: "BUILD",
},
{ {
dir: "", dir: "",
basename: "WORKSPACE", basename: "WORKSPACE",
}, },
{
dir: bazelRulesSubDir,
basename: "BUILD",
},
} }
assertFilecountsAreEqual(t, files, expectedFilePaths) assertFilecountsAreEqual(t, files, expectedFilePaths)

View File

@ -126,7 +126,7 @@ func (m *customBazelModule) GenerateAndroidBuildActions(ctx android.ModuleContex
func customBp2BuildMutator(ctx android.TopDownMutatorContext) { func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
if m, ok := ctx.Module().(*customModule); ok { if m, ok := ctx.Module().(*customModule); ok {
if !m.ConvertWithBp2build() { if !m.ConvertWithBp2build(ctx) {
return return
} }
@ -147,7 +147,7 @@ func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
// module to target. // module to target.
func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) { func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
if m, ok := ctx.Module().(*customModule); ok { if m, ok := ctx.Module().(*customModule); ok {
if !m.ConvertWithBp2build() { if !m.ConvertWithBp2build(ctx) {
return return
} }

View File

@ -86,7 +86,7 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) {
return return
} }
if !module.ConvertWithBp2build() { if !module.ConvertWithBp2build(ctx) {
return return
} }

View File

@ -131,7 +131,7 @@ func BazelObjectFactory() android.Module {
// Bazel equivalent target, plus any necessary include deps for the cc_object. // Bazel equivalent target, plus any necessary include deps for the cc_object.
func ObjectBp2Build(ctx android.TopDownMutatorContext) { func ObjectBp2Build(ctx android.TopDownMutatorContext) {
m, ok := ctx.Module().(*Module) m, ok := ctx.Module().(*Module)
if !ok || !m.ConvertWithBp2build() { if !ok || !m.ConvertWithBp2build(ctx) {
return return
} }

View File

@ -22,6 +22,7 @@ import (
"strings" "strings"
"android/soong/shared" "android/soong/shared"
"github.com/google/blueprint/bootstrap" "github.com/google/blueprint/bootstrap"
"android/soong/android" "android/soong/android"

View File

@ -820,7 +820,7 @@ func BazelGenruleFactory() android.Module {
func GenruleBp2Build(ctx android.TopDownMutatorContext) { func GenruleBp2Build(ctx android.TopDownMutatorContext) {
m, ok := ctx.Module().(*Module) m, ok := ctx.Module().(*Module)
if !ok || !m.ConvertWithBp2build() { if !ok || !m.ConvertWithBp2build(ctx) {
return return
} }

View File

@ -61,7 +61,7 @@ func (m *bazelPythonBinary) GenerateAndroidBuildActions(ctx android.ModuleContex
func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) { func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) {
m, ok := ctx.Module().(*Module) m, ok := ctx.Module().(*Module)
if !ok || !m.ConvertWithBp2build() { if !ok || !m.ConvertWithBp2build(ctx) {
return return
} }

View File

@ -521,7 +521,7 @@ func BazelShBinaryFactory() android.Module {
func ShBinaryBp2Build(ctx android.TopDownMutatorContext) { func ShBinaryBp2Build(ctx android.TopDownMutatorContext) {
m, ok := ctx.Module().(*ShBinary) m, ok := ctx.Module().(*ShBinary)
if !ok || !m.ConvertWithBp2build() { if !ok || !m.ConvertWithBp2build(ctx) {
return return
} }