From 86dc2c268a0e1e1fbe0d161d349c49c9fa4b10e7 Mon Sep 17 00:00:00 2001 From: Chris Parsons Date: Wed, 28 Sep 2022 14:58:41 -0400 Subject: [PATCH] Support main repository prefixing in cquery This makes mixed builds resilient to a recent backward-incompatbile Bazel feature which explicitly adds the main repository (`@`) prefix to all labels which are stringified by `str(target.label)` in Starlark. This implementation is compatible with both current Bazel and Bazel@HEAD. After a new Bazel release to AOSP, we can clean up this code a little to only support Bazel with this feature active (and that we need not hedge on either Bazel behavior). Bug: 248106697 Test: `m --bazel-mode nothing` with both current Bazel and a new Bazel Change-Id: Id53c8505bb9080d5073c844de7f1ee57ceceae46 --- android/bazel_handler.go | 24 ++++++++++++++++++------ android/bazel_handler_test.go | 4 ++-- bazel/cquery/request_type.go | 3 +++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 3e490dd94..64092927b 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -104,9 +104,16 @@ type cqueryKey struct { configKey configKey } +func makeCqueryKey(label string, cqueryRequest cqueryRequest, cfgKey configKey) cqueryKey { + if strings.HasPrefix(label, "//") { + // Normalize Bazel labels to specify main repository explicitly. + label = "@" + label + } + return cqueryKey{label, cqueryRequest, cfgKey} +} + func (c cqueryKey) String() string { return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey) - } // BazelContext is a context object useful for interacting with Bazel during @@ -261,23 +268,24 @@ func (m MockBazelContext) AqueryDepsets() []bazel.AqueryDepset { var _ BazelContext = MockBazelContext{} func (bazelCtx *bazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) { - key := cqueryKey{label, requestType, cfgKey} + key := makeCqueryKey(label, requestType, cfgKey) bazelCtx.requestMutex.Lock() defer bazelCtx.requestMutex.Unlock() bazelCtx.requests[key] = true } func (bazelCtx *bazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) { - key := cqueryKey{label, cquery.GetOutputFiles, cfgKey} + key := makeCqueryKey(label, cquery.GetOutputFiles, cfgKey) if rawString, ok := bazelCtx.results[key]; ok { bazelOutput := strings.TrimSpace(rawString) + return cquery.GetOutputFiles.ParseResult(bazelOutput), nil } return nil, fmt.Errorf("no bazel response found for %v", key) } func (bazelCtx *bazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) { - key := cqueryKey{label, cquery.GetCcInfo, cfgKey} + key := makeCqueryKey(label, cquery.GetCcInfo, cfgKey) if rawString, ok := bazelCtx.results[key]; ok { bazelOutput := strings.TrimSpace(rawString) return cquery.GetCcInfo.ParseResult(bazelOutput) @@ -286,7 +294,7 @@ func (bazelCtx *bazelContext) GetCcInfo(label string, cfgKey configKey) (cquery. } func (bazelCtx *bazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) { - key := cqueryKey{label, cquery.GetPythonBinary, cfgKey} + key := makeCqueryKey(label, cquery.GetPythonBinary, cfgKey) if rawString, ok := bazelCtx.results[key]; ok { bazelOutput := strings.TrimSpace(rawString) return cquery.GetPythonBinary.ParseResult(bazelOutput), nil @@ -295,7 +303,7 @@ func (bazelCtx *bazelContext) GetPythonBinary(label string, cfgKey configKey) (s } func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) { - key := cqueryKey{label, cquery.GetApexInfo, cfgKey} + key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey) if rawString, ok := bazelCtx.results[key]; ok { return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil } @@ -755,6 +763,10 @@ def get_arch(target): def format(target): id_string = str(target.label) + "|" + get_arch(target) + # TODO(b/248106697): Remove once Bazel is updated to always normalize labels. + if id_string.startswith("//"): + id_string = "@" + id_string + # Main switch section %s # This target was not requested via cquery, and thus must be a dependency diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go index ec2541b3d..dc2261c62 100644 --- a/android/bazel_handler_test.go +++ b/android/bazel_handler_test.go @@ -13,10 +13,10 @@ import ( var testConfig = TestConfig("out", nil, "", nil) func TestRequestResultsAfterInvokeBazel(t *testing.T) { - label := "//foo:bar" + label := "@//foo:bar" cfg := configKey{"arm64_armv8-a", Android} bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ - bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`, + bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`, }) bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg) err := bazelContext.InvokeBazel(testConfig) diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index 3b06f8527..e35b531eb 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -181,6 +181,9 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { decoder := json.NewDecoder(strings.NewReader(rawString)) decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests err := decoder.Decode(&ccInfo) + if err != nil { + return ccInfo, fmt.Errorf("error parsing CcInfo result. %s RAW STRING: %s", err, rawString) + } return ccInfo, err }