Loading android/bazel_handler.go +91 −42 Original line number Original line Diff line number Diff line Loading @@ -89,16 +89,24 @@ type BazelContext interface { BuildStatementsToRegister() []bazel.BuildStatement BuildStatementsToRegister() []bazel.BuildStatement } } // A context object which tracks queued requests that need to be made to Bazel, type bazelRunner interface { // and their results after the requests have been made. issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) type bazelContext struct { } type bazelPaths struct { homeDir string homeDir string bazelPath string bazelPath string outputBase string outputBase string workspaceDir string workspaceDir string buildDir string buildDir string metricsDir string metricsDir string } // A context object which tracks queued requests that need to be made to Bazel, // and their results after the requests have been made. type bazelContext struct { bazelRunner paths *bazelPaths requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel requestMutex sync.Mutex // requests can be written in parallel requestMutex sync.Mutex // requests can be written in parallel Loading Loading @@ -228,42 +236,56 @@ func NewBazelContext(c *config) (BazelContext, error) { return noopBazelContext{}, nil return noopBazelContext{}, nil } } bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)} p, err := bazelPathsFromConfig(c) if err != nil { return nil, err } return &bazelContext{ bazelRunner: &builtinBazelRunner{}, paths: p, requests: make(map[cqueryKey]bool), }, nil } func bazelPathsFromConfig(c *config) (*bazelPaths, error) { p := bazelPaths{ buildDir: c.buildDir, } missingEnvVars := []string{} missingEnvVars := []string{} if len(c.Getenv("BAZEL_HOME")) > 1 { if len(c.Getenv("BAZEL_HOME")) > 1 { bazelCtx.homeDir = c.Getenv("BAZEL_HOME") p.homeDir = c.Getenv("BAZEL_HOME") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_HOME") missingEnvVars = append(missingEnvVars, "BAZEL_HOME") } } if len(c.Getenv("BAZEL_PATH")) > 1 { if len(c.Getenv("BAZEL_PATH")) > 1 { bazelCtx.bazelPath = c.Getenv("BAZEL_PATH") p.bazelPath = c.Getenv("BAZEL_PATH") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_PATH") missingEnvVars = append(missingEnvVars, "BAZEL_PATH") } } if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 { if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 { bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE") p.outputBase = c.Getenv("BAZEL_OUTPUT_BASE") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE") missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE") } } if len(c.Getenv("BAZEL_WORKSPACE")) > 1 { if len(c.Getenv("BAZEL_WORKSPACE")) > 1 { bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE") p.workspaceDir = c.Getenv("BAZEL_WORKSPACE") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE") missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE") } } if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 { if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 { bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR") p.metricsDir = c.Getenv("BAZEL_METRICS_DIR") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR") missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR") } } if len(missingEnvVars) > 0 { if len(missingEnvVars) > 0 { return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars)) return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars)) } else { } else { return &bazelCtx, nil return &p, nil } } } } func (context *bazelContext) BazelMetricsDir() string { func (p *bazelPaths) BazelMetricsDir() string { return context.metricsDir return p.metricsDir } } func (context *bazelContext) BazelEnabled() bool { func (context *bazelContext) BazelEnabled() bool { Loading Loading @@ -296,17 +318,40 @@ func pwdPrefix() string { return "" return "" } } type bazelCommand struct { command string // query or label expression string } type mockBazelRunner struct { bazelCommandResults map[bazelCommand]string commands []bazelCommand } func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) { r.commands = append(r.commands, command) if ret, ok := r.bazelCommandResults[command]; ok { return ret, "", nil } return "", "", nil } type builtinBazelRunner struct{} // Issues the given bazel command with given build label and additional flags. // Issues the given bazel command with given build label and additional flags. // Returns (stdout, stderr, error). The first and second return values are strings // Returns (stdout, stderr, error). The first and second return values are strings // containing the stdout and stderr of the run command, and an error is returned if // containing the stdout and stderr of the run command, and an error is returned if // the invocation returned an error code. // the invocation returned an error code. func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string, func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) { extraFlags ...string) (string, string, error) { cmdFlags := []string{"--output_base=" + paths.outputBase, command.command} cmdFlags := []string{"--output_base=" + context.outputBase, command} cmdFlags = append(cmdFlags, command.expression) cmdFlags = append(cmdFlags, labels...) cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+paths.intermediatesDir()) cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir()) cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName)) cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName)) // Set default platforms to canonicalized values for mixed builds requests. // Set default platforms to canonicalized values for mixed builds requests. // If these are set in the bazelrc, they will have values that are // If these are set in the bazelrc, they will have values that are Loading @@ -328,9 +373,9 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st cmdFlags = append(cmdFlags, "--experimental_repository_disable_download") cmdFlags = append(cmdFlags, "--experimental_repository_disable_download") cmdFlags = append(cmdFlags, extraFlags...) cmdFlags = append(cmdFlags, extraFlags...) bazelCmd := exec.Command(context.bazelPath, cmdFlags...) bazelCmd := exec.Command(paths.bazelPath, cmdFlags...) bazelCmd.Dir = context.workspaceDir bazelCmd.Dir = paths.workspaceDir bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix(), bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(), // Disables local host detection of gcc; toolchain information is defined // Disables local host detection of gcc; toolchain information is defined // explicitly in BUILD files. // explicitly in BUILD files. "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1") "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1") Loading Loading @@ -367,7 +412,7 @@ local_repository( path = "%[1]s/build/bazel/bazel_skylib", path = "%[1]s/build/bazel/bazel_skylib", ) ) ` ` return []byte(fmt.Sprintf(formatString, context.workspaceDir)) return []byte(fmt.Sprintf(formatString, context.paths.workspaceDir)) } } func (context *bazelContext) mainBzlFileContents() []byte { func (context *bazelContext) mainBzlFileContents() []byte { Loading Loading @@ -577,8 +622,8 @@ def format(target): // Returns a workspace-relative path containing build-related metadata required // Returns a workspace-relative path containing build-related metadata required // for interfacing with Bazel. Example: out/soong/bazel. // for interfacing with Bazel. Example: out/soong/bazel. func (context *bazelContext) intermediatesDir() string { func (p *bazelPaths) intermediatesDir() string { return filepath.Join(context.buildDir, "bazel") return filepath.Join(p.buildDir, "bazel") } } // Issues commands to Bazel to receive results for all cquery requests // Issues commands to Bazel to receive results for all cquery requests Loading @@ -590,7 +635,7 @@ func (context *bazelContext) InvokeBazel() error { var cqueryErr string var cqueryErr string var err error var err error intermediatesDirPath := absolutePath(context.intermediatesDir()) intermediatesDirPath := absolutePath(context.paths.intermediatesDir()) if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) { if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) { err = os.Mkdir(intermediatesDirPath, 0777) err = os.Mkdir(intermediatesDirPath, 0777) } } Loading @@ -599,38 +644,38 @@ func (context *bazelContext) InvokeBazel() error { return err return err } } err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")), filepath.Join(intermediatesDirPath, "main.bzl"), context.mainBzlFileContents(), 0666) context.mainBzlFileContents(), 0666) if err != nil { if err != nil { return err return err } } err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")), filepath.Join(intermediatesDirPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666) context.mainBuildFileContents(), 0666) if err != nil { if err != nil { return err return err } } cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery") cqueryFileRelpath := filepath.Join(context.paths.intermediatesDir(), "buildroot.cquery") err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(cqueryFileRelpath), absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666) context.cqueryStarlarkFileContents(), 0666) if err != nil { if err != nil { return err return err } } workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel") err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(workspaceFileRelpath), filepath.Join(intermediatesDirPath, "WORKSPACE.bazel"), context.workspaceFileContents(), 0666) context.workspaceFileContents(), 0666) if err != nil { if err != nil { return err return err } } buildrootLabel := "//:buildroot" buildrootLabel := "//:buildroot" cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", cqueryOutput, cqueryErr, err = context.issueBazelCommand( []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, context.paths, bazel.CqueryBuildRootRunName, bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, "--output=starlark", "--output=starlark", "--starlark:file="+cqueryFileRelpath) "--starlark:file="+cqueryFileRelpath) err = ioutil.WriteFile( err = ioutil.WriteFile(filepath.Join(intermediatesDirPath, "cquery.out"), absolutePath(filepath.Join(context.intermediatesDir(), "cquery.out")), []byte(cqueryOutput), 0666) []byte(cqueryOutput), 0666) if err != nil { if err != nil { return err return err Loading Loading @@ -661,11 +706,13 @@ func (context *bazelContext) InvokeBazel() error { // // // TODO(cparsons): Use --target_pattern_file to avoid command line limits. // TODO(cparsons): Use --target_pattern_file to avoid command line limits. var aqueryOutput string var aqueryOutput string aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", aqueryOutput, _, err = context.issueBazelCommand( []string{fmt.Sprintf("deps(%s)", buildrootLabel), context.paths, bazel.AqueryBuildRootRunName, bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}, // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // proto sources, which would add a number of unnecessary dependencies. // proto sources, which would add a number of unnecessary dependencies. "--output=jsonproto"}) "--output=jsonproto") if err != nil { if err != nil { return err return err Loading @@ -679,8 +726,10 @@ func (context *bazelContext) InvokeBazel() error { // Issue a build command of the phony root to generate symlink forests for dependencies of the // Issue a build command of the phony root to generate symlink forests for dependencies of the // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // but some of symlinks may be required to resolve source dependencies of the build. // but some of symlinks may be required to resolve source dependencies of the build. _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", _, _, err = context.issueBazelCommand( []string{"//:phonyroot"}) context.paths, bazel.BazelBuildPhonyRootRunName, bazelCommand{"build", "//:phonyroot"}) if err != nil { if err != nil { return err return err Loading @@ -696,7 +745,7 @@ func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement } } func (context *bazelContext) OutputBase() string { func (context *bazelContext) OutputBase() string { return context.outputBase return context.paths.outputBase } } // Singleton used for registering BUILD file ninja dependencies (needed // Singleton used for registering BUILD file ninja dependencies (needed Loading android/bazel_handler_test.go 0 → 100644 +118 −0 Original line number Original line Diff line number Diff line package android import ( "os" "path/filepath" "reflect" "testing" ) func TestRequestResultsAfterInvokeBazel(t *testing.T) { label := "//foo:bar" arch := Arm64 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ bazelCommand{command: "cquery", expression: "kind(rule, deps(//:buildroot))"}: `@sourceroot//foo:bar|arm64>>out/foo/bar.txt`, }) g, ok := bazelContext.GetOutputFiles(label, arch) if ok { t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g) } err := bazelContext.InvokeBazel() if err != nil { t.Fatalf("Did not expect error invoking Bazel, but got %s", err) } g, ok = bazelContext.GetOutputFiles(label, arch) if !ok { t.Errorf("Expected cquery results after running InvokeBazel(), but got none") } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) { t.Errorf("Expected output %s, got %s", w, g) } } func TestInvokeBazelWritesBazelFiles(t *testing.T) { bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{}) err := bazelContext.InvokeBazel() if err != nil { t.Fatalf("Did not expect error invoking Bazel, but got %s", err) } if _, err := os.Stat(filepath.Join(baseDir, "bazel", "main.bzl")); os.IsNotExist(err) { t.Errorf("Expected main.bzl to exist, but it does not") } else if err != nil { t.Errorf("Unexpected error stating main.bzl %s", err) } if _, err := os.Stat(filepath.Join(baseDir, "bazel", "BUILD.bazel")); os.IsNotExist(err) { t.Errorf("Expected BUILD.bazel to exist, but it does not") } else if err != nil { t.Errorf("Unexpected error stating BUILD.bazel %s", err) } if _, err := os.Stat(filepath.Join(baseDir, "bazel", "WORKSPACE.bazel")); os.IsNotExist(err) { t.Errorf("Expected WORKSPACE.bazel to exist, but it does not") } else if err != nil { t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err) } } func TestInvokeBazelPopulatesBuildStatements(t *testing.T) { bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}: ` { "artifacts": [{ "id": 1, "pathFragmentId": 1 }, { "id": 2, "pathFragmentId": 2 }], "actions": [{ "targetId": 1, "actionKey": "x", "mnemonic": "x", "arguments": ["touch", "foo"], "inputDepSetIds": [1], "outputIds": [1], "primaryOutputId": 1 }], "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1, 2] }], "pathFragments": [{ "id": 1, "label": "one" }, { "id": 2, "label": "two" }] }`, }) err := bazelContext.InvokeBazel() if err != nil { t.Fatalf("Did not expect error invoking Bazel, but got %s", err) } got := bazelContext.BuildStatementsToRegister() if want := 1; len(got) != want { t.Errorf("Expected %d registered build statements, got %#v", want, got) } } func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) { t.Helper() p := bazelPaths{ buildDir: t.TempDir(), outputBase: "outputbase", workspaceDir: "workspace_dir", } aqueryCommand := bazelCommand{command: "aquery", expression: "deps(//:buildroot)"} if _, exists := bazelCommandResults[aqueryCommand]; !exists { bazelCommandResults[aqueryCommand] = "{}\n" } runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults} return &bazelContext{ bazelRunner: runner, paths: &p, requests: map[cqueryKey]bool{}, }, p.buildDir } Loading
android/bazel_handler.go +91 −42 Original line number Original line Diff line number Diff line Loading @@ -89,16 +89,24 @@ type BazelContext interface { BuildStatementsToRegister() []bazel.BuildStatement BuildStatementsToRegister() []bazel.BuildStatement } } // A context object which tracks queued requests that need to be made to Bazel, type bazelRunner interface { // and their results after the requests have been made. issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) type bazelContext struct { } type bazelPaths struct { homeDir string homeDir string bazelPath string bazelPath string outputBase string outputBase string workspaceDir string workspaceDir string buildDir string buildDir string metricsDir string metricsDir string } // A context object which tracks queued requests that need to be made to Bazel, // and their results after the requests have been made. type bazelContext struct { bazelRunner paths *bazelPaths requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel requestMutex sync.Mutex // requests can be written in parallel requestMutex sync.Mutex // requests can be written in parallel Loading Loading @@ -228,42 +236,56 @@ func NewBazelContext(c *config) (BazelContext, error) { return noopBazelContext{}, nil return noopBazelContext{}, nil } } bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)} p, err := bazelPathsFromConfig(c) if err != nil { return nil, err } return &bazelContext{ bazelRunner: &builtinBazelRunner{}, paths: p, requests: make(map[cqueryKey]bool), }, nil } func bazelPathsFromConfig(c *config) (*bazelPaths, error) { p := bazelPaths{ buildDir: c.buildDir, } missingEnvVars := []string{} missingEnvVars := []string{} if len(c.Getenv("BAZEL_HOME")) > 1 { if len(c.Getenv("BAZEL_HOME")) > 1 { bazelCtx.homeDir = c.Getenv("BAZEL_HOME") p.homeDir = c.Getenv("BAZEL_HOME") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_HOME") missingEnvVars = append(missingEnvVars, "BAZEL_HOME") } } if len(c.Getenv("BAZEL_PATH")) > 1 { if len(c.Getenv("BAZEL_PATH")) > 1 { bazelCtx.bazelPath = c.Getenv("BAZEL_PATH") p.bazelPath = c.Getenv("BAZEL_PATH") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_PATH") missingEnvVars = append(missingEnvVars, "BAZEL_PATH") } } if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 { if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 { bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE") p.outputBase = c.Getenv("BAZEL_OUTPUT_BASE") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE") missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE") } } if len(c.Getenv("BAZEL_WORKSPACE")) > 1 { if len(c.Getenv("BAZEL_WORKSPACE")) > 1 { bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE") p.workspaceDir = c.Getenv("BAZEL_WORKSPACE") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE") missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE") } } if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 { if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 { bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR") p.metricsDir = c.Getenv("BAZEL_METRICS_DIR") } else { } else { missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR") missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR") } } if len(missingEnvVars) > 0 { if len(missingEnvVars) > 0 { return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars)) return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars)) } else { } else { return &bazelCtx, nil return &p, nil } } } } func (context *bazelContext) BazelMetricsDir() string { func (p *bazelPaths) BazelMetricsDir() string { return context.metricsDir return p.metricsDir } } func (context *bazelContext) BazelEnabled() bool { func (context *bazelContext) BazelEnabled() bool { Loading Loading @@ -296,17 +318,40 @@ func pwdPrefix() string { return "" return "" } } type bazelCommand struct { command string // query or label expression string } type mockBazelRunner struct { bazelCommandResults map[bazelCommand]string commands []bazelCommand } func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) { r.commands = append(r.commands, command) if ret, ok := r.bazelCommandResults[command]; ok { return ret, "", nil } return "", "", nil } type builtinBazelRunner struct{} // Issues the given bazel command with given build label and additional flags. // Issues the given bazel command with given build label and additional flags. // Returns (stdout, stderr, error). The first and second return values are strings // Returns (stdout, stderr, error). The first and second return values are strings // containing the stdout and stderr of the run command, and an error is returned if // containing the stdout and stderr of the run command, and an error is returned if // the invocation returned an error code. // the invocation returned an error code. func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string, func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error) { extraFlags ...string) (string, string, error) { cmdFlags := []string{"--output_base=" + paths.outputBase, command.command} cmdFlags := []string{"--output_base=" + context.outputBase, command} cmdFlags = append(cmdFlags, command.expression) cmdFlags = append(cmdFlags, labels...) cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+paths.intermediatesDir()) cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir()) cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName)) cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName)) // Set default platforms to canonicalized values for mixed builds requests. // Set default platforms to canonicalized values for mixed builds requests. // If these are set in the bazelrc, they will have values that are // If these are set in the bazelrc, they will have values that are Loading @@ -328,9 +373,9 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st cmdFlags = append(cmdFlags, "--experimental_repository_disable_download") cmdFlags = append(cmdFlags, "--experimental_repository_disable_download") cmdFlags = append(cmdFlags, extraFlags...) cmdFlags = append(cmdFlags, extraFlags...) bazelCmd := exec.Command(context.bazelPath, cmdFlags...) bazelCmd := exec.Command(paths.bazelPath, cmdFlags...) bazelCmd.Dir = context.workspaceDir bazelCmd.Dir = paths.workspaceDir bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix(), bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(), // Disables local host detection of gcc; toolchain information is defined // Disables local host detection of gcc; toolchain information is defined // explicitly in BUILD files. // explicitly in BUILD files. "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1") "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1") Loading Loading @@ -367,7 +412,7 @@ local_repository( path = "%[1]s/build/bazel/bazel_skylib", path = "%[1]s/build/bazel/bazel_skylib", ) ) ` ` return []byte(fmt.Sprintf(formatString, context.workspaceDir)) return []byte(fmt.Sprintf(formatString, context.paths.workspaceDir)) } } func (context *bazelContext) mainBzlFileContents() []byte { func (context *bazelContext) mainBzlFileContents() []byte { Loading Loading @@ -577,8 +622,8 @@ def format(target): // Returns a workspace-relative path containing build-related metadata required // Returns a workspace-relative path containing build-related metadata required // for interfacing with Bazel. Example: out/soong/bazel. // for interfacing with Bazel. Example: out/soong/bazel. func (context *bazelContext) intermediatesDir() string { func (p *bazelPaths) intermediatesDir() string { return filepath.Join(context.buildDir, "bazel") return filepath.Join(p.buildDir, "bazel") } } // Issues commands to Bazel to receive results for all cquery requests // Issues commands to Bazel to receive results for all cquery requests Loading @@ -590,7 +635,7 @@ func (context *bazelContext) InvokeBazel() error { var cqueryErr string var cqueryErr string var err error var err error intermediatesDirPath := absolutePath(context.intermediatesDir()) intermediatesDirPath := absolutePath(context.paths.intermediatesDir()) if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) { if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) { err = os.Mkdir(intermediatesDirPath, 0777) err = os.Mkdir(intermediatesDirPath, 0777) } } Loading @@ -599,38 +644,38 @@ func (context *bazelContext) InvokeBazel() error { return err return err } } err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")), filepath.Join(intermediatesDirPath, "main.bzl"), context.mainBzlFileContents(), 0666) context.mainBzlFileContents(), 0666) if err != nil { if err != nil { return err return err } } err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")), filepath.Join(intermediatesDirPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666) context.mainBuildFileContents(), 0666) if err != nil { if err != nil { return err return err } } cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery") cqueryFileRelpath := filepath.Join(context.paths.intermediatesDir(), "buildroot.cquery") err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(cqueryFileRelpath), absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666) context.cqueryStarlarkFileContents(), 0666) if err != nil { if err != nil { return err return err } } workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel") err = ioutil.WriteFile( err = ioutil.WriteFile( absolutePath(workspaceFileRelpath), filepath.Join(intermediatesDirPath, "WORKSPACE.bazel"), context.workspaceFileContents(), 0666) context.workspaceFileContents(), 0666) if err != nil { if err != nil { return err return err } } buildrootLabel := "//:buildroot" buildrootLabel := "//:buildroot" cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", cqueryOutput, cqueryErr, err = context.issueBazelCommand( []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, context.paths, bazel.CqueryBuildRootRunName, bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, "--output=starlark", "--output=starlark", "--starlark:file="+cqueryFileRelpath) "--starlark:file="+cqueryFileRelpath) err = ioutil.WriteFile( err = ioutil.WriteFile(filepath.Join(intermediatesDirPath, "cquery.out"), absolutePath(filepath.Join(context.intermediatesDir(), "cquery.out")), []byte(cqueryOutput), 0666) []byte(cqueryOutput), 0666) if err != nil { if err != nil { return err return err Loading Loading @@ -661,11 +706,13 @@ func (context *bazelContext) InvokeBazel() error { // // // TODO(cparsons): Use --target_pattern_file to avoid command line limits. // TODO(cparsons): Use --target_pattern_file to avoid command line limits. var aqueryOutput string var aqueryOutput string aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", aqueryOutput, _, err = context.issueBazelCommand( []string{fmt.Sprintf("deps(%s)", buildrootLabel), context.paths, bazel.AqueryBuildRootRunName, bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}, // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // proto sources, which would add a number of unnecessary dependencies. // proto sources, which would add a number of unnecessary dependencies. "--output=jsonproto"}) "--output=jsonproto") if err != nil { if err != nil { return err return err Loading @@ -679,8 +726,10 @@ func (context *bazelContext) InvokeBazel() error { // Issue a build command of the phony root to generate symlink forests for dependencies of the // Issue a build command of the phony root to generate symlink forests for dependencies of the // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // but some of symlinks may be required to resolve source dependencies of the build. // but some of symlinks may be required to resolve source dependencies of the build. _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", _, _, err = context.issueBazelCommand( []string{"//:phonyroot"}) context.paths, bazel.BazelBuildPhonyRootRunName, bazelCommand{"build", "//:phonyroot"}) if err != nil { if err != nil { return err return err Loading @@ -696,7 +745,7 @@ func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement } } func (context *bazelContext) OutputBase() string { func (context *bazelContext) OutputBase() string { return context.outputBase return context.paths.outputBase } } // Singleton used for registering BUILD file ninja dependencies (needed // Singleton used for registering BUILD file ninja dependencies (needed Loading
android/bazel_handler_test.go 0 → 100644 +118 −0 Original line number Original line Diff line number Diff line package android import ( "os" "path/filepath" "reflect" "testing" ) func TestRequestResultsAfterInvokeBazel(t *testing.T) { label := "//foo:bar" arch := Arm64 bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ bazelCommand{command: "cquery", expression: "kind(rule, deps(//:buildroot))"}: `@sourceroot//foo:bar|arm64>>out/foo/bar.txt`, }) g, ok := bazelContext.GetOutputFiles(label, arch) if ok { t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g) } err := bazelContext.InvokeBazel() if err != nil { t.Fatalf("Did not expect error invoking Bazel, but got %s", err) } g, ok = bazelContext.GetOutputFiles(label, arch) if !ok { t.Errorf("Expected cquery results after running InvokeBazel(), but got none") } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) { t.Errorf("Expected output %s, got %s", w, g) } } func TestInvokeBazelWritesBazelFiles(t *testing.T) { bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{}) err := bazelContext.InvokeBazel() if err != nil { t.Fatalf("Did not expect error invoking Bazel, but got %s", err) } if _, err := os.Stat(filepath.Join(baseDir, "bazel", "main.bzl")); os.IsNotExist(err) { t.Errorf("Expected main.bzl to exist, but it does not") } else if err != nil { t.Errorf("Unexpected error stating main.bzl %s", err) } if _, err := os.Stat(filepath.Join(baseDir, "bazel", "BUILD.bazel")); os.IsNotExist(err) { t.Errorf("Expected BUILD.bazel to exist, but it does not") } else if err != nil { t.Errorf("Unexpected error stating BUILD.bazel %s", err) } if _, err := os.Stat(filepath.Join(baseDir, "bazel", "WORKSPACE.bazel")); os.IsNotExist(err) { t.Errorf("Expected WORKSPACE.bazel to exist, but it does not") } else if err != nil { t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err) } } func TestInvokeBazelPopulatesBuildStatements(t *testing.T) { bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}: ` { "artifacts": [{ "id": 1, "pathFragmentId": 1 }, { "id": 2, "pathFragmentId": 2 }], "actions": [{ "targetId": 1, "actionKey": "x", "mnemonic": "x", "arguments": ["touch", "foo"], "inputDepSetIds": [1], "outputIds": [1], "primaryOutputId": 1 }], "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1, 2] }], "pathFragments": [{ "id": 1, "label": "one" }, { "id": 2, "label": "two" }] }`, }) err := bazelContext.InvokeBazel() if err != nil { t.Fatalf("Did not expect error invoking Bazel, but got %s", err) } got := bazelContext.BuildStatementsToRegister() if want := 1; len(got) != want { t.Errorf("Expected %d registered build statements, got %#v", want, got) } } func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) { t.Helper() p := bazelPaths{ buildDir: t.TempDir(), outputBase: "outputbase", workspaceDir: "workspace_dir", } aqueryCommand := bazelCommand{command: "aquery", expression: "deps(//:buildroot)"} if _, exists := bazelCommandResults[aqueryCommand]; !exists { bazelCommandResults[aqueryCommand] = "{}\n" } runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults} return &bazelContext{ bazelRunner: runner, paths: &p, requests: map[cqueryKey]bool{}, }, p.buildDir }