diff options
| -rw-r--r-- | bp2build/bp2build.go | 49 | ||||
| -rwxr-xr-x | tests/bp2build_bazel_test.sh | 62 |
2 files changed, 107 insertions, 4 deletions
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go index 062eba88a..d1dfb9d36 100644 --- a/bp2build/bp2build.go +++ b/bp2build/bp2build.go @@ -17,21 +17,57 @@ package bp2build import ( "fmt" "os" + "path/filepath" "strings" "android/soong/android" "android/soong/bazel" + "android/soong/shared" ) +func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) { + // Delete files that should no longer be present. + bp2buildDirAbs := shared.JoinPath(ctx.topDir, rootOutputPath.String()) + + filesToDelete := make(map[string]struct{}) + err := filepath.Walk(bp2buildDirAbs, + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + relPath, err := filepath.Rel(bp2buildDirAbs, path) + if err != nil { + return err + } + filesToDelete[relPath] = struct{}{} + } + return nil + }) + if err != nil { + fmt.Printf("ERROR reading %s: %s", bp2buildDirAbs, err) + os.Exit(1) + } + + for _, bazelFile := range except { + filePath := filepath.Join(bazelFile.Dir, bazelFile.Basename) + delete(filesToDelete, filePath) + } + for f, _ := range filesToDelete { + absPath := shared.JoinPath(bp2buildDirAbs, f) + if err := os.RemoveAll(absPath); err != nil { + fmt.Printf("ERROR deleting %s: %s", absPath, err) + os.Exit(1) + } + } +} + // Codegen is the backend of bp2build. The code generator is responsible for // writing .bzl files that are equivalent to Android.bp files that are capable // of being built with Bazel. func Codegen(ctx *CodegenContext) *CodegenMetrics { // This directory stores BUILD files that could be eventually checked-in. bp2buildDir := android.PathForOutput(ctx, "bp2build") - if err := android.RemoveAllOutputDir(bp2buildDir); err != nil { - fmt.Printf("ERROR: Encountered error while cleaning %s: %s", bp2buildDir, err.Error()) - } res, errs := GenerateBazelTargets(ctx, true) if len(errs) > 0 { @@ -44,6 +80,12 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { } bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode) writeFiles(ctx, bp2buildDir, bp2buildFiles) + // Delete files under the bp2build root which weren't just written. An + // alternative would have been to delete the whole directory and write these + // files. However, this would regenerate files which were otherwise unchanged + // since the last bp2build run, which would have negative incremental + // performance implications. + deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles) injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics) if err != nil { @@ -51,7 +93,6 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics { os.Exit(1) } writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles) - return &res.metrics } diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh index 878b4a16f..1ff1b5bca 100755 --- a/tests/bp2build_bazel_test.sh +++ b/tests/bp2build_bazel_test.sh @@ -21,6 +21,68 @@ function test_bp2build_null_build { fi } +# Tests that, if bp2build reruns due to a blueprint file changing, that +# BUILD files whose contents are unchanged are not regenerated. +function test_bp2build_unchanged { + setup + + mkdir -p pkg + touch pkg/x.txt + cat > pkg/Android.bp <<'EOF' +filegroup { + name: "x", + srcs: ["x.txt"], + bazel_module: {bp2build_available: true}, + } +EOF + + run_soong bp2build + local -r buildfile_mtime1=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel) + local -r marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker) + + # Force bp2build to rerun by updating the timestamp of a blueprint file. + touch pkg/Android.bp + + run_soong bp2build + local -r buildfile_mtime2=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel) + local -r marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker) + + if [[ "$marker_mtime1" == "$marker_mtime2" ]]; then + fail "Expected bp2build marker file to change" + fi + if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then + fail "BUILD.bazel was updated even though contents are same" + fi +} + +# Tests that blueprint files that are deleted are not present when the +# bp2build tree is regenerated. +function test_bp2build_deleted_blueprint { + setup + + mkdir -p pkg + touch pkg/x.txt + cat > pkg/Android.bp <<'EOF' +filegroup { + name: "x", + srcs: ["x.txt"], + bazel_module: {bp2build_available: true}, + } +EOF + + run_soong bp2build + if [[ ! -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then + fail "Expected pkg/BUILD.bazel to be generated" + fi + + rm pkg/Android.bp + + run_soong bp2build + if [[ -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then + fail "Expected pkg/BUILD.bazel to be deleted" + fi +} + function test_bp2build_null_build_with_globs { setup |