Expand handling of unconverted deps in bp2build

Support three options for converting modules with unconverted
dependencies
1. (default) Warn when converting a module if it has unconverted deps.
2. Error when encountering a module with unconverted deps. (not hooked
up yet)

Test: build/bazel/ci/bp2build.sh
Test: build/bazel/ci/mixed_libc.sh
Test: BP2BUILD_ERROR_UNCONVERTED=1 build/bazel/ci/bp2build.sh with
      unconverted deps -- get appropriate error
Bug: 181155349
Change-Id: Ifaabf0cd2e43e963366dc137159c705294165c3d
This commit is contained in:
Liz Kammer
2021-08-26 08:37:59 -04:00
parent 4011ebb12d
commit 6eff323206
11 changed files with 190 additions and 100 deletions

View File

@@ -61,8 +61,8 @@ type Bazelable interface {
HandcraftedLabel() string HandcraftedLabel() string
GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
ConvertWithBp2build(ctx BazelConversionPathContext) bool ConvertWithBp2build(ctx BazelConversionPathContext) bool
convertWithBp2build(ctx BazelConversionPathContext, module blueprint.Module) bool
GetBazelBuildFileContents(c Config, path, name string) (string, error) GetBazelBuildFileContents(c Config, path, name string) (string, error)
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.
@@ -311,9 +311,10 @@ func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) boo
if !ctx.Config().BazelContext.BazelEnabled() { if !ctx.Config().BazelContext.BazelEnabled() {
return false return false
} }
if len(b.GetBazelLabel(ctx, ctx.Module())) == 0 { if !convertedToBazel(ctx, ctx.Module()) {
return false return false
} }
if GenerateCcLibraryStaticOnly(ctx) { if GenerateCcLibraryStaticOnly(ctx) {
// Don't use partially-converted cc_library targets in mixed builds, // Don't use partially-converted cc_library targets in mixed builds,
// since mixed builds would generally rely on both static and shared // since mixed builds would generally rely on both static and shared
@@ -323,20 +324,33 @@ func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) boo
return !mixedBuildsDisabled[ctx.Module().Name()] return !mixedBuildsDisabled[ctx.Module().Name()]
} }
// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
func convertedToBazel(ctx BazelConversionPathContext, module blueprint.Module) bool {
b, ok := module.(Bazelable)
if !ok {
return false
}
return b.convertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
}
// 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(ctx BazelConversionPathContext) bool { func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionPathContext) bool {
if bp2buildModuleDoNotConvert[ctx.Module().Name()] { return b.convertWithBp2build(ctx, ctx.Module())
}
func (b *BazelModuleBase) convertWithBp2build(ctx BazelConversionPathContext, module blueprint.Module) bool {
if bp2buildModuleDoNotConvert[module.Name()] {
return false return false
} }
// Ensure that the module type of this module has a bp2build converter. This // Ensure that the module type of this module has a bp2build converter. This
// prevents mixed builds from using auto-converted modules just by matching // prevents mixed builds from using auto-converted modules just by matching
// the package dir; it also has to have a bp2build mutator as well. // the package dir; it also has to have a bp2build mutator as well.
if ctx.Config().bp2buildModuleTypeConfig[ctx.ModuleType()] == false { if ctx.Config().bp2buildModuleTypeConfig[ctx.OtherModuleType(module)] == false {
return false return false
} }
packagePath := ctx.ModuleDir() packagePath := ctx.OtherModuleDir(module)
config := ctx.Config().bp2buildPackageConfig config := ctx.Config().bp2buildPackageConfig
// This is a tristate value: true, false, or unset. // This is a tristate value: true, false, or unset.
@@ -407,9 +421,3 @@ func (b *BazelModuleBase) GetBazelBuildFileContents(c Config, path, name string)
} }
return string(data[:]), nil return string(data[:]), nil
} }
// ConvertedToBazel returns whether this module has been converted to Bazel, whether automatically
// or manually
func (b *BazelModuleBase) ConvertedToBazel(ctx BazelConversionPathContext) bool {
return b.ConvertWithBp2build(ctx) || b.HasHandcraftedLabel()
}

View File

@@ -75,9 +75,10 @@ type BazelConversionPathContext interface {
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
ModuleFromName(name string) (blueprint.Module, bool) ModuleFromName(name string) (blueprint.Module, bool)
Module() Module Module() Module
ModuleType() string OtherModuleType(m blueprint.Module) string
OtherModuleName(m blueprint.Module) string OtherModuleName(m blueprint.Module) string
OtherModuleDir(m blueprint.Module) string OtherModuleDir(m blueprint.Module) string
AddUnconvertedBp2buildDep(string)
} }
// BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>" // BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>"
@@ -345,6 +346,9 @@ func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string, isWhol
if m == nil { if m == nil {
panic(fmt.Errorf("No module named %q found, but was a direct dep of %q", dep, ctx.Module().Name())) panic(fmt.Errorf("No module named %q found, but was a direct dep of %q", dep, ctx.Module().Name()))
} }
if !convertedToBazel(ctx, m) {
ctx.AddUnconvertedBp2buildDep(dep)
}
otherLabel := bazelModuleLabel(ctx, m, tag) otherLabel := bazelModuleLabel(ctx, m, tag)
label := bazelModuleLabel(ctx, ctx.Module(), "") label := bazelModuleLabel(ctx, ctx.Module(), "")
if isWholeLibs { if isWholeLibs {
@@ -363,11 +367,10 @@ func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string, isWhol
func bazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module, tag string) string { func bazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module, tag string) string {
// 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) if !convertedToBazel(ctx, module) {
// TODO(b/181155349): perhaps return an error here if the module can't be/isn't being converted
if !ok || !b.ConvertedToBazel(ctx) {
return bp2buildModuleLabel(ctx, module) return bp2buildModuleLabel(ctx, module)
} }
b, _ := module.(Bazelable)
return b.GetBazelLabel(ctx, module) return b.GetBazelLabel(ctx, module)
} }

View File

@@ -316,6 +316,9 @@ type BaseModuleContext interface {
AddMissingDependencies(missingDeps []string) AddMissingDependencies(missingDeps []string)
// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
AddUnconvertedBp2buildDep(dep string)
Target() Target Target() Target
TargetPrimary() bool TargetPrimary() bool
@@ -496,6 +499,7 @@ type Module interface {
IsConvertedByBp2build() bool IsConvertedByBp2build() bool
// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module // Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
Bp2buildTargets() []bp2buildInfo Bp2buildTargets() []bp2buildInfo
GetUnconvertedBp2buildDeps() []string
BuildParamsForTests() []BuildParams BuildParamsForTests() []BuildParams
RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
@@ -833,6 +837,10 @@ type commonProperties struct {
// supported as Soong handles some things within a single target that we may choose to split into // 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. // multiple targets, e.g. renderscript, protos, yacc within a cc module.
Bp2buildInfo []bp2buildInfo `blueprint:"mutated"` Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
// UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
// Bazel
UnconvertedBp2buildDeps []string `blueprint:"mutated"`
} }
type distProperties struct { type distProperties struct {
@@ -1212,6 +1220,18 @@ func (m *ModuleBase) Bp2buildTargets() []bp2buildInfo {
return m.commonProperties.Bp2buildInfo return m.commonProperties.Bp2buildInfo
} }
// AddUnconvertedBp2buildDep stores module name of a dependency that was not converted to Bazel.
func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) {
unconvertedDeps := &b.Module().base().commonProperties.UnconvertedBp2buildDeps
*unconvertedDeps = append(*unconvertedDeps, dep)
}
// GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that
// were not converted to Bazel.
func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string {
return m.commonProperties.UnconvertedBp2buildDeps
}
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) { func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
(*d)["Android"] = map[string]interface{}{} (*d)["Android"] = map[string]interface{}{}
} }

View File

@@ -532,7 +532,6 @@ func (t *topDownMutatorContext) CreateBazelTargetModule(
BazelProps: bazelProps, BazelProps: bazelProps,
Attrs: attrs, Attrs: attrs,
} }
t.Module().base().addBp2buildInfo(info) t.Module().base().addBp2buildInfo(info)
} }

View File

@@ -19,6 +19,7 @@ import (
"android/soong/bazel" "android/soong/bazel"
"fmt" "fmt"
"os" "os"
"strings"
) )
// Codegen is the backend of bp2build. The code generator is responsible for // Codegen is the backend of bp2build. The code generator is responsible for
@@ -29,14 +30,22 @@ func Codegen(ctx *CodegenContext) CodegenMetrics {
bp2buildDir := android.PathForOutput(ctx, "bp2build") bp2buildDir := android.PathForOutput(ctx, "bp2build")
android.RemoveAllOutputDir(bp2buildDir) android.RemoveAllOutputDir(bp2buildDir)
buildToTargets, metrics, compatLayer := GenerateBazelTargets(ctx, true) res, errs := GenerateBazelTargets(ctx, true)
bp2buildFiles := CreateBazelFiles(nil, buildToTargets, ctx.mode) if len(errs) > 0 {
errMsgs := make([]string, len(errs))
for i, err := range errs {
errMsgs[i] = fmt.Sprintf("%q", err)
}
fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
os.Exit(1)
}
bp2buildFiles := CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
writeFiles(ctx, bp2buildDir, bp2buildFiles) writeFiles(ctx, bp2buildDir, bp2buildFiles)
soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName) soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(compatLayer)) writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(res.compatLayer))
return metrics return res.metrics
} }
// Get the output directory and create it if it doesn't exist. // Get the output directory and create it if it doesn't exist.

View File

@@ -157,6 +157,7 @@ type CodegenContext struct {
context android.Context context android.Context
mode CodegenMode mode CodegenMode
additionalDeps []string additionalDeps []string
unconvertedDepMode unconvertedDepsMode
} }
func (c *CodegenContext) Mode() CodegenMode { func (c *CodegenContext) Mode() CodegenMode {
@@ -181,6 +182,16 @@ const (
QueryView QueryView
) )
type unconvertedDepsMode int
const (
// Include a warning in conversion metrics about converted modules with unconverted direct deps
warnUnconvertedDeps unconvertedDepsMode = iota
// Error and fail conversion if encountering a module with unconverted direct deps
// Enabled by setting environment variable `BP2BUILD_ERROR_UNCONVERTED`
errorModulesUnconvertedDeps
)
func (mode CodegenMode) String() string { func (mode CodegenMode) String() string {
switch mode { switch mode {
case Bp2Build: case Bp2Build:
@@ -211,10 +222,15 @@ func (ctx *CodegenContext) Context() android.Context { return ctx.context }
// NewCodegenContext creates a wrapper context that conforms to PathContext for // NewCodegenContext creates a wrapper context that conforms to PathContext for
// writing BUILD files in the output directory. // writing BUILD files in the output directory.
func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) *CodegenContext { func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) *CodegenContext {
var unconvertedDeps unconvertedDepsMode
if config.IsEnvTrue("BP2BUILD_ERROR_UNCONVERTED") {
unconvertedDeps = errorModulesUnconvertedDeps
}
return &CodegenContext{ return &CodegenContext{
context: context, context: context,
config: config, config: config,
mode: mode, mode: mode,
unconvertedDepMode: unconvertedDeps,
} }
} }
@@ -230,7 +246,17 @@ func propsToAttributes(props map[string]string) string {
return attributes return attributes
} }
func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[string]BazelTargets, CodegenMetrics, CodegenCompatLayer) { type conversionResults struct {
buildFileToTargets map[string]BazelTargets
metrics CodegenMetrics
compatLayer CodegenCompatLayer
}
func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
return r.buildFileToTargets
}
func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
buildFileToTargets := make(map[string]BazelTargets) buildFileToTargets := make(map[string]BazelTargets)
buildFileToAppend := make(map[string]bool) buildFileToAppend := make(map[string]bool)
@@ -245,6 +271,8 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
dirs := make(map[string]bool) dirs := make(map[string]bool)
var errs []error
bpCtx := ctx.Context() bpCtx := ctx.Context()
bpCtx.VisitAllModules(func(m blueprint.Module) { bpCtx.VisitAllModules(func(m blueprint.Module) {
dir := bpCtx.ModuleDir(m) dir := bpCtx.ModuleDir(m)
@@ -266,13 +294,24 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
} }
t, err := getHandcraftedBuildContent(ctx, b, pathToBuildFile) t, err := getHandcraftedBuildContent(ctx, b, pathToBuildFile)
if err != nil { if err != nil {
panic(fmt.Errorf("Error converting %s: %s", bpCtx.ModuleName(m), err)) errs = append(errs, fmt.Errorf("Error converting %s: %s", bpCtx.ModuleName(m), err))
return
} }
targets = append(targets, t) targets = append(targets, t)
// TODO(b/181575318): currently we append the whole BUILD file, let's change that to do // TODO(b/181575318): currently we append the whole BUILD file, let's change that to do
// something more targeted based on the rule type and target // something more targeted based on the rule type and target
buildFileToAppend[pathToBuildFile] = true buildFileToAppend[pathToBuildFile] = true
} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() { } else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
if unconvertedDeps := aModule.GetUnconvertedBp2buildDeps(); len(unconvertedDeps) > 0 {
msg := fmt.Sprintf("%q depends on unconverted modules: %s", m.Name(), strings.Join(unconvertedDeps, ", "))
if ctx.unconvertedDepMode == warnUnconvertedDeps {
metrics.moduleWithUnconvertedDepsMsgs = append(metrics.moduleWithUnconvertedDepsMsgs, msg)
} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
metrics.TotalModuleCount += 1
errs = append(errs, fmt.Errorf(msg))
return
}
}
targets = generateBazelTargets(bpCtx, aModule) targets = generateBazelTargets(bpCtx, aModule)
for _, t := range targets { for _, t := range targets {
if t.name == m.Name() { if t.name == m.Name() {
@@ -295,11 +334,17 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
t := generateSoongModuleTarget(bpCtx, m) t := generateSoongModuleTarget(bpCtx, m)
targets = append(targets, t) targets = append(targets, t)
default: default:
panic(fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode())) errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
return
} }
buildFileToTargets[dir] = append(buildFileToTargets[dir], targets...) buildFileToTargets[dir] = append(buildFileToTargets[dir], targets...)
}) })
if len(errs) > 0 {
return conversionResults{}, errs
}
if generateFilegroups { if generateFilegroups {
// Add a filegroup target that exposes all sources in the subtree of this package // Add a filegroup target that exposes all sources in the subtree of this package
// NOTE: This also means we generate a BUILD file for every Android.bp file (as long as it has at least one module) // NOTE: This also means we generate a BUILD file for every Android.bp file (as long as it has at least one module)
@@ -312,7 +357,11 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
} }
} }
return buildFileToTargets, metrics, compatLayer return conversionResults{
buildFileToTargets: buildFileToTargets,
metrics: metrics,
compatLayer: compatLayer,
}, errs
} }
func getBazelPackagePath(b android.Bazelable) string { func getBazelPackagePath(b android.Bazelable) string {

View File

@@ -16,6 +16,7 @@ package bp2build
import ( import (
"android/soong/android" "android/soong/android"
"fmt"
"strings" "strings"
"testing" "testing"
) )
@@ -199,7 +200,8 @@ func TestGenerateSoongModuleTargets(t *testing.T) {
android.FailIfErrored(t, errs) android.FailIfErrored(t, errs)
codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView) codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView)
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount { if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount) t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
} }
@@ -341,7 +343,8 @@ custom {
} }
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount) t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount)
@@ -502,7 +505,8 @@ load("//build/bazel/rules:rules.bzl", "my_library")`,
android.FailIfErrored(t, errs) android.FailIfErrored(t, errs)
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount { if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount) t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount)
} }
@@ -679,59 +683,38 @@ func TestModuleTypeBp2Build(t *testing.T) {
"other/Android.bp": `filegroup { "other/Android.bp": `filegroup {
name: "foo", name: "foo",
srcs: ["a", "b"], srcs: ["a", "b"],
bazel_module: { bp2build_available: true },
}`,
},
},
{
description: "depends_on_other_unconverted_module_error",
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
unconvertedDepsMode: errorModulesUnconvertedDeps,
blueprint: `filegroup {
name: "foobar",
srcs: [
":foo",
"c",
],
bazel_module: { bp2build_available: true },
}`,
expectedErr: fmt.Errorf(`"foobar" depends on unconverted modules: foo`),
filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "foo",
srcs: ["a", "b"],
}`, }`,
}, },
}, },
} }
dir := "."
for _, testCase := range testCases { for _, testCase := range testCases {
fs := make(map[string][]byte) t.Run(testCase.description, func(t *testing.T) {
toParse := []string{ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
"Android.bp", })
}
for f, content := range testCase.filesystem {
if strings.HasSuffix(f, "Android.bp") {
toParse = append(toParse, f)
}
fs[f] = []byte(content)
}
config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, toParse)
if errored(t, testCase, errs) {
continue
}
_, errs = ctx.ResolveDependencies(config)
if errored(t, testCase, errs) {
continue
}
checkDir := dir
if testCase.dir != "" {
checkDir = testCase.dir
}
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
} else {
for i, target := range bazelTargets {
if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
t.Errorf(
"%s: Expected generated Bazel target to be '%s', got '%s'",
testCase.description,
w,
g,
)
}
}
}
} }
} }
@@ -809,7 +792,8 @@ func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
android.FailIfErrored(t, errs) android.FailIfErrored(t, errs)
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
if actualCount := len(bazelTargets); actualCount != testCase.expectedCount { if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount) t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount)
} }
@@ -921,7 +905,8 @@ filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } }
// For each directory, test that the expected number of generated targets is correct. // For each directory, test that the expected number of generated targets is correct.
for dir, expectedCount := range testCase.expectedCount { for dir, expectedCount := range testCase.expectedCount {
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
if actualCount := len(bazelTargets); actualCount != expectedCount { if actualCount := len(bazelTargets); actualCount != expectedCount {
t.Fatalf( t.Fatalf(
"%s: Expected %d bazel target for %s package, got %d", "%s: Expected %d bazel target for %s package, got %d",
@@ -1064,7 +1049,9 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
if testCase.dir != "" { if testCase.dir != "" {
checkDir = testCase.dir checkDir = testCase.dir
} }
bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
android.FailIfErrored(t, err)
bazelTargets.sort() bazelTargets.sort()
actualCount := len(bazelTargets) actualCount := len(bazelTargets)
expectedCount := len(testCase.expectedBazelTargets) expectedCount := len(testCase.expectedBazelTargets)
@@ -1185,7 +1172,9 @@ func TestGlobExcludeSrcs(t *testing.T) {
if testCase.dir != "" { if testCase.dir != "" {
checkDir = testCase.dir checkDir = testCase.dir
} }
bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
android.FailIfErrored(t, err)
if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets) t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
} else { } else {

View File

@@ -267,7 +267,8 @@ genrule {
} }
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
android.FailIfErrored(t, err)
if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount) t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
} else { } else {
@@ -461,7 +462,8 @@ genrule {
android.FailIfErrored(t, errs) android.FailIfErrored(t, errs)
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
android.FailIfErrored(t, err)
if actualCount := len(bazelTargets); actualCount != 1 { if actualCount := len(bazelTargets); actualCount != 1 {
t.Fatalf("%s: Expected 1 bazel target, got %d", testCase.description, actualCount) t.Fatalf("%s: Expected 1 bazel target, got %d", testCase.description, actualCount)
} }

View File

@@ -3,6 +3,7 @@ package bp2build
import ( import (
"android/soong/android" "android/soong/android"
"fmt" "fmt"
"strings"
) )
// Simple metrics struct to collect information about a Blueprint to BUILD // Simple metrics struct to collect information about a Blueprint to BUILD
@@ -16,6 +17,8 @@ type CodegenMetrics struct {
// Total number of handcrafted targets // Total number of handcrafted targets
handCraftedTargetCount int handCraftedTargetCount int
moduleWithUnconvertedDepsMsgs []string
} }
// Print the codegen metrics to stdout. // Print the codegen metrics to stdout.
@@ -27,8 +30,10 @@ func (metrics CodegenMetrics) Print() {
generatedTargetCount += count generatedTargetCount += count
} }
fmt.Printf( fmt.Printf(
"[bp2build] Generated %d total BUILD targets and included %d handcrafted BUILD targets from %d Android.bp modules.\n", "[bp2build] Generated %d total BUILD targets and included %d handcrafted BUILD targets from %d Android.bp modules.\n With %d modules with unconverted deps \n\t%s",
generatedTargetCount, generatedTargetCount,
metrics.handCraftedTargetCount, metrics.handCraftedTargetCount,
metrics.TotalModuleCount) metrics.TotalModuleCount,
len(metrics.moduleWithUnconvertedDepsMsgs),
strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"))
} }

View File

@@ -39,9 +39,8 @@ var (
func checkError(t *testing.T, errs []error, expectedErr error) bool { func checkError(t *testing.T, errs []error, expectedErr error) bool {
t.Helper() t.Helper()
// expectedErr is not nil, find it in the list of errors
if len(errs) != 1 { if len(errs) != 1 {
t.Errorf("Expected only 1 error, got %d: %q", len(errs), errs) return false
} }
if errs[0].Error() == expectedErr.Error() { if errs[0].Error() == expectedErr.Error() {
return true return true
@@ -83,6 +82,7 @@ type bp2buildTestCase struct {
filesystem map[string]string filesystem map[string]string
dir string dir string
expectedErr error expectedErr error
unconvertedDepsMode unconvertedDepsMode
} }
func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) { func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
@@ -126,7 +126,13 @@ func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi
checkDir = tc.dir checkDir = tc.dir
} }
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir) codegenCtx.unconvertedDepMode = tc.unconvertedDepsMode
bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
if tc.expectedErr != nil && checkError(t, errs, tc.expectedErr) {
return
} else {
android.FailIfErrored(t, errs)
}
if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount { if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
t.Errorf("%s: Expected %d bazel target, got %d; %v", t.Errorf("%s: Expected %d bazel target, got %d; %v",
tc.description, expectedCount, actualCount, bazelTargets) tc.description, expectedCount, actualCount, bazelTargets)
@@ -316,10 +322,10 @@ func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
} }
// Helper method for tests to easily access the targets in a dir. // Helper method for tests to easily access the targets in a dir.
func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) BazelTargets { func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
// TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely // TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
buildFileToTargets, _, _ := GenerateBazelTargets(codegenCtx, false) res, err := GenerateBazelTargets(codegenCtx, false)
return buildFileToTargets[dir] return res.buildFileToTargets[dir], err
} }
func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) { func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {

View File

@@ -27,12 +27,12 @@ func createBazelQueryView(ctx *bp2build.CodegenContext, bazelQueryViewDir string
os.RemoveAll(bazelQueryViewDir) os.RemoveAll(bazelQueryViewDir)
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories()) ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
// Ignore metrics reporting and compat layers for queryview, since queryview res, err := bp2build.GenerateBazelTargets(ctx, true)
// is already a full-repo conversion and can use data from bazel query if err != nil {
// directly. panic(err)
buildToTargets, _, _ := bp2build.GenerateBazelTargets(ctx, true) }
filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets, bp2build.QueryView) filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), bp2build.QueryView)
for _, f := range filesToWrite { for _, f := range filesToWrite {
if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil { if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil {
return err return err