diff --git a/ui/build/config.go b/ui/build/config.go index 4de019c28..7238c3245 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -307,12 +307,10 @@ func getConfigArgs(action BuildAction, dir string, buildDependencies bool, ctx C if topDir == dir { break } - // Find the build file from the directory where the build action was triggered by traversing up - // the source tree. If a blank build filename is returned, simply use the directory where the build - // action was invoked. + buildFile := findBuildFile(ctx, relDir) if buildFile == "" { - buildFile = filepath.Join(relDir, "Android.mk") + ctx.Fatalf("Build file not found for %s directory", relDir) } buildFiles = []string{buildFile} targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)} @@ -360,19 +358,43 @@ func hasBuildFile(ctx Context, dir string) bool { return false } -// findBuildFile finds a build file (makefile or blueprint file) by looking at dir first. If not -// found, go up one level and repeat again until one is found and the path of that build file -// relative to the root directory of the source tree is returned. The returned filename of build -// file is "Android.mk". If one was not found, a blank string is returned. +// findBuildFile finds a build file (makefile or blueprint file) by looking if there is a build file +// in the current and any sub directory of dir. If a build file is not found, traverse the path +// up by one directory and repeat again until either a build file is found or reached to the root +// source tree. The returned filename of build file is "Android.mk". If one was not found, a blank +// string is returned. func findBuildFile(ctx Context, dir string) string { - // If the string is empty, assume it is top directory of the source tree. - if dir == "" { + // If the string is empty or ".", assume it is top directory of the source tree. + if dir == "" || dir == "." { return "" } - for ; dir != "."; dir = filepath.Dir(dir) { - if hasBuildFile(ctx, dir) { - return filepath.Join(dir, "Android.mk") + found := false + for buildDir := dir; buildDir != "."; buildDir = filepath.Dir(buildDir) { + err := filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if found { + return filepath.SkipDir + } + if info.IsDir() { + return nil + } + for _, buildFile := range buildFiles { + if info.Name() == buildFile { + found = true + return filepath.SkipDir + } + } + return nil + }) + if err != nil { + ctx.Fatalf("Error finding Android build file: %v", err) + } + + if found { + return filepath.Join(buildDir, "Android.mk") } } diff --git a/ui/build/config_test.go b/ui/build/config_test.go index 18dd151cd..463405a3a 100644 --- a/ui/build/config_test.go +++ b/ui/build/config_test.go @@ -545,8 +545,11 @@ func TestConfigFindBuildFile(t *testing.T) { // Array of build files to create in dir. buildFiles []string + // Directories that exist in the source tree. + dirsInTrees []string + // ********* Action ********* - // Directory to create, also the base directory is where findBuildFile is invoked. + // The base directory is where findBuildFile is invoked. dir string // ********* Validation ********* @@ -555,38 +558,63 @@ func TestConfigFindBuildFile(t *testing.T) { }{{ description: "build file exists at leaf directory", buildFiles: []string{"1/2/3/Android.bp"}, + dirsInTrees: []string{"1/2/3"}, dir: "1/2/3", expectedBuildFile: "1/2/3/Android.mk", }, { description: "build file exists in all directory paths", buildFiles: []string{"1/Android.mk", "1/2/Android.mk", "1/2/3/Android.mk"}, + dirsInTrees: []string{"1/2/3"}, dir: "1/2/3", expectedBuildFile: "1/2/3/Android.mk", }, { description: "build file does not exist in all directory paths", buildFiles: []string{}, + dirsInTrees: []string{"1/2/3"}, dir: "1/2/3", expectedBuildFile: "", }, { description: "build file exists only at top directory", buildFiles: []string{"Android.bp"}, + dirsInTrees: []string{"1/2/3"}, dir: "1/2/3", expectedBuildFile: "", }, { description: "build file exist in a subdirectory", buildFiles: []string{"1/2/Android.bp"}, + dirsInTrees: []string{"1/2/3"}, dir: "1/2/3", expectedBuildFile: "1/2/Android.mk", }, { description: "build file exists in a subdirectory", buildFiles: []string{"1/Android.mk"}, + dirsInTrees: []string{"1/2/3"}, dir: "1/2/3", expectedBuildFile: "1/Android.mk", }, { description: "top directory", buildFiles: []string{"Android.bp"}, + dirsInTrees: []string{}, dir: ".", expectedBuildFile: "", + }, { + description: "build file exists in subdirectory", + buildFiles: []string{"1/2/3/Android.bp", "1/2/4/Android.bp"}, + dirsInTrees: []string{"1/2/3", "1/2/4"}, + dir: "1/2", + expectedBuildFile: "1/2/Android.mk", + }, { + description: "build file exists in parent subdirectory", + buildFiles: []string{"1/5/Android.bp"}, + dirsInTrees: []string{"1/2/3", "1/2/4", "1/5"}, + dir: "1/2", + expectedBuildFile: "1/Android.mk", + }, { + description: "build file exists in deep parent's subdirectory.", + buildFiles: []string{"1/5/6/Android.bp"}, + dirsInTrees: []string{"1/2/3", "1/2/4", "1/5/6", "1/5/7"}, + dir: "1/2", + expectedBuildFile: "1/Android.mk", }} for _, tt := range tests { @@ -601,10 +629,7 @@ func TestConfigFindBuildFile(t *testing.T) { } defer os.RemoveAll(topDir) - if tt.dir != "" { - createDirectories(t, topDir, []string{tt.dir}) - } - + createDirectories(t, topDir, tt.dirsInTrees) createBuildFiles(t, topDir, tt.buildFiles) curDir, err := os.Getwd() @@ -709,11 +734,23 @@ type buildActionTestCase struct { // Expected environment variables to be set. expectedEnvVars []envVar + + // Expecting error from running test case. + expectedErrStr string } func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) { ctx := testContext() + defer logger.Recover(func(err error) { + if tt.expectedErrStr == "" { + t.Fatalf("Got unexpected error: %v", err) + } + if tt.expectedErrStr != err.Error() { + t.Errorf("expected %s, got %s", tt.expectedErrStr, err.Error()) + } + }) + // Environment variables to set it to blank on every test case run. resetEnvVars := []string{ "ONE_SHOT_MAKEFILE", @@ -780,6 +817,11 @@ func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, t.Errorf("expecting %s, got %s for environment variable %s", env.value, val, env.name) } } + + // If the execution reached here and there was an expected error code, the unit test case failed. + if tt.expectedErrStr != "" { + t.Errorf("expecting error %s", tt.expectedErrStr) + } } func TestGetConfigArgsBuildModules(t *testing.T) { @@ -875,6 +917,7 @@ func TestGetConfigArgsBuildModulesInDirecotoryNoDeps(t *testing.T) { envVar{ name: "ONE_SHOT_MAKEFILE", value: "0/1/2/Android.mk"}}, + expectedErrStr: "Build file not found for 0/1/2 directory", }, { description: "build action executed at root directory", dirsInTrees: []string{}, @@ -978,7 +1021,7 @@ func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) { expectedArgs: []string{}, expectedEnvVars: []envVar{}, }, { - description: "build file not found - no error is expected to return", + description: "build file not found", dirsInTrees: []string{"0/1/2"}, buildFiles: []string{}, args: []string{}, @@ -986,6 +1029,7 @@ func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) { tidyOnly: "", expectedArgs: []string{"MODULES-IN-0-1-2"}, expectedEnvVars: []envVar{}, + expectedErrStr: "Build file not found for 0/1/2 directory", }, { description: "GET-INSTALL-PATH specified,", dirsInTrees: []string{"0/1/2"},