diff --git a/android/bazel_handler.go b/android/bazel_handler.go index d4f6e4c9e..4f17fecc6 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -18,11 +18,15 @@ import ( "bytes" "errors" "fmt" + "io/ioutil" "os" "os/exec" + "path/filepath" "runtime" "strings" "sync" + + "github.com/google/blueprint/bootstrap" ) // Map key to describe bazel cquery requests. @@ -237,3 +241,28 @@ func (context *bazelContext) InvokeBazel() error { context.requests = map[cqueryKey]bool{} return nil } + +// Singleton used for registering BUILD file ninja dependencies (needed +// for correctness of builds which use Bazel. +func BazelSingleton() Singleton { + return &bazelSingleton{} +} + +type bazelSingleton struct{} + +func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { + if ctx.Config().BazelContext.BazelEnabled() { + bazelBuildList := absolutePath(filepath.Join( + filepath.Dir(bootstrap.ModuleListFile), "bazel.list")) + ctx.AddNinjaFileDeps(bazelBuildList) + + data, err := ioutil.ReadFile(bazelBuildList) + if err != nil { + ctx.Errorf(err.Error()) + } + files := strings.Split(strings.TrimSpace(string(data)), "\n") + for _, file := range files { + ctx.AddNinjaFileDeps(file) + } + } +} diff --git a/android/register.go b/android/register.go index 036a8113f..ad3df7ead 100644 --- a/android/register.go +++ b/android/register.go @@ -104,6 +104,8 @@ func (ctx *Context) Register() { registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps) + ctx.RegisterSingletonType("bazeldeps", SingletonFactoryAdaptor(BazelSingleton)) + // Register phony just before makevars so it can write out its phony rules as Make rules ctx.RegisterSingletonType("phony", SingletonFactoryAdaptor(phonySingletonFactory)) diff --git a/finder/finder.go b/finder/finder.go index 6513fa301..5413fa6bb 100644 --- a/finder/finder.go +++ b/finder/finder.go @@ -103,6 +103,9 @@ type CacheParams struct { // IncludeFiles are file names to include as matches IncludeFiles []string + + // IncludeSuffixes are filename suffixes to include as matches. + IncludeSuffixes []string } // a cacheConfig stores the inputs that determine what should be included in the cache @@ -1310,6 +1313,20 @@ func (f *Finder) statDirSync(path string) statResponse { return stats } +func (f *Finder) shouldIncludeFile(fileName string) bool { + for _, includedName := range f.cacheMetadata.Config.IncludeFiles { + if fileName == includedName { + return true + } + } + for _, includeSuffix := range f.cacheMetadata.Config.IncludeSuffixes { + if strings.HasSuffix(fileName, includeSuffix) { + return true + } + } + return false +} + // pruneCacheCandidates removes the items that we don't want to include in our persistent cache func (f *Finder) pruneCacheCandidates(items *DirEntries) { @@ -1326,13 +1343,9 @@ func (f *Finder) pruneCacheCandidates(items *DirEntries) { // remove any files that aren't the ones we want to include writeIndex := 0 for _, fileName := range items.FileNames { - // include only these files - for _, includedName := range f.cacheMetadata.Config.IncludeFiles { - if fileName == includedName { - items.FileNames[writeIndex] = fileName - writeIndex++ - break - } + if f.shouldIncludeFile(fileName) { + items.FileNames[writeIndex] = fileName + writeIndex++ } } // resize diff --git a/finder/finder_test.go b/finder/finder_test.go index 88b0c058b..788dbdd35 100644 --- a/finder/finder_test.go +++ b/finder/finder_test.go @@ -21,6 +21,7 @@ import ( "os" "path/filepath" "sort" + "strings" "testing" "android/soong/finder/fs" @@ -92,6 +93,7 @@ func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []strin nil, nil, []string{"findme.txt", "skipme.txt"}, + nil, }, ) defer finder.Shutdown() @@ -104,6 +106,46 @@ func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []strin fs.AssertSameResponse(t, foundPaths, absoluteMatches) } +// runTestWithSuffixes creates a few files, searches for findme.txt or any file +// with suffix `.findme_ext` and checks for the expected matches +func runTestWithSuffixes(t *testing.T, existentPaths []string, expectedMatches []string) { + filesystem := newFs() + root := "/tmp" + filesystem.MkDirs(root) + for _, path := range existentPaths { + fs.Create(t, filepath.Join(root, path), filesystem) + } + + finder := newFinder(t, + filesystem, + CacheParams{ + "/cwd", + []string{root}, + nil, + nil, + []string{"findme.txt", "skipme.txt"}, + []string{".findme_ext"}, + }, + ) + defer finder.Shutdown() + + foundPaths := finder.FindMatching(root, + func(entries DirEntries) (dirs []string, files []string) { + matches := []string{} + for _, foundName := range entries.FileNames { + if foundName == "findme.txt" || strings.HasSuffix(foundName, ".findme_ext") { + matches = append(matches, foundName) + } + } + return entries.DirNames, matches + }) + absoluteMatches := []string{} + for i := range expectedMatches { + absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i])) + } + fs.AssertSameResponse(t, foundPaths, absoluteMatches) +} + // testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test func testAgainstSeveralThreadcounts(t *testing.T, tester func(t *testing.T, numThreads int)) { // test singlethreaded, multithreaded, and also using the same number of threads as @@ -135,6 +177,13 @@ func TestIncludeFiles(t *testing.T) { ) } +func TestIncludeFilesAndSuffixes(t *testing.T) { + runTestWithSuffixes(t, + []string{"findme.txt", "skipme.txt", "alsome.findme_ext"}, + []string{"findme.txt", "alsome.findme_ext"}, + ) +} + func TestNestedDirectories(t *testing.T) { runSimpleTest(t, []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt"}, @@ -142,6 +191,13 @@ func TestNestedDirectories(t *testing.T) { ) } +func TestNestedDirectoriesWithSuffixes(t *testing.T) { + runTestWithSuffixes(t, + []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt", "subdir/alsome.findme_ext"}, + []string{"findme.txt", "subdir/findme.txt", "subdir/alsome.findme_ext"}, + ) +} + func TestEmptyDirectory(t *testing.T) { runSimpleTest(t, []string{}, diff --git a/ui/build/finder.go b/ui/build/finder.go index c019ea2d6..7a856577e 100644 --- a/ui/build/finder.go +++ b/ui/build/finder.go @@ -63,10 +63,13 @@ func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) { "AndroidProducts.mk", "Android.bp", "Blueprints", + "BUILD.bazel", "CleanSpec.mk", "OWNERS", "TEST_MAPPING", + "WORKSPACE", }, + IncludeSuffixes: []string{".bzl"}, } dumpDir := config.FileListDir() f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard), @@ -77,6 +80,16 @@ func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) { return f } +func findBazelFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) { + matches := []string{} + for _, foundName := range entries.FileNames { + if foundName == "BUILD.bazel" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") { + matches = append(matches, foundName) + } + } + return entries.DirNames, matches +} + // FindSources searches for source files known to and writes them to the filesystem for // use later. func FindSources(ctx Context, config Config, f *finder.Finder) { @@ -99,6 +112,12 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { ctx.Fatalf("Could not export product list: %v", err) } + bazelFiles := f.FindMatching(".", findBazelFiles) + err = dumpListToFile(ctx, config, bazelFiles, filepath.Join(dumpDir, "bazel.list")) + if err != nil { + ctx.Fatalf("Could not export bazel BUILD list: %v", err) + } + cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk") err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list")) if err != nil {