diff options
68 files changed, 1916 insertions, 1150 deletions
diff --git a/.gitignore b/.gitignore index 45884c46f..5d2bc0d05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /.idea *.iml +*.ipr +*.iws + diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go index 10c3d098a..a1b7dbfc4 100644 --- a/android/allowlists/allowlists.go +++ b/android/allowlists/allowlists.go @@ -272,6 +272,9 @@ var ( "prebuilts/tools": Bp2BuildDefaultTrue, "prebuilts/tools/common/m2": Bp2BuildDefaultTrue, + "sdk/eventanalyzer": Bp2BuildDefaultTrue, + "sdk/dumpeventlog": Bp2BuildDefaultTrue, + "system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures "system/apex/apexer": Bp2BuildDefaultTrue, "system/apex/libs": Bp2BuildDefaultTrueRecursively, @@ -398,8 +401,6 @@ var ( "com.android.neuralnetworks.certificate", "com.android.neuralnetworks.key", "flatbuffer_headers", - "framework-cppstream-protos", - "framework-javastream-protos", "framework-connectivity-protos", "gemmlowp_headers", "gl_headers", @@ -1336,21 +1337,11 @@ var ( "prebuilt_platform-robolectric-4.4-prebuilt", "prebuilt_platform-robolectric-4.5.1-prebuilt", "prebuilt_currysrc_org.eclipse", - - // TODO(b/247782695 and/or b/242847534) Fix mixed build between unconverted gensrcs and converted filegroup - "data_stall_event_proto", - "device_policy_proto", - "dns_resolver_proto", - "launcher_proto", - "network_stack_proto", - "srcs_bluetooth_protos", - "srcs_bluetooth_leaudio_protos", - "style_proto", - "tethering_proto", - "text_classifier_proto", } - ProdMixedBuildsEnabledList = []string{ - "com.android.adbd", - } + ProdMixedBuildsEnabledList = []string{} + + // Staging builds should be entirely prod, plus some near-ready ones. Add the + // new ones to the first argument as needed. + StagingMixedBuildsEnabledList = append([]string{}, ProdMixedBuildsEnabledList...) ) diff --git a/android/arch.go b/android/arch.go index 75ee922fb..086e945da 100644 --- a/android/arch.go +++ b/android/arch.go @@ -1687,14 +1687,12 @@ type archConfig struct { abi []string } -// getNdkAbisConfig returns the list of archConfigs that are used for bulding -// the API stubs and static libraries that are included in the NDK. These are -// built *without Neon*, because non-Neon is still supported and building these -// with Neon will break those users. +// getNdkAbisConfig returns the list of archConfigs that are used for building +// the API stubs and static libraries that are included in the NDK. func getNdkAbisConfig() []archConfig { return []archConfig{ {"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}}, - {"arm", "armv7-a", "", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}}, {"x86_64", "", "", []string{"x86_64"}}, {"x86", "", "", []string{"x86"}}, } diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 29695d639..c157d39c0 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -386,6 +386,12 @@ func NewBazelContext(c *config) (BazelContext, error) { for _, enabledProdModule := range allowlists.ProdMixedBuildsEnabledList { enabledModules[enabledProdModule] = true } + case BazelStagingMode: + modulesDefaultToBazel = false + for _, enabledStagingMode := range allowlists.StagingMixedBuildsEnabledList { + enabledModules[enabledStagingMode] = true + + } case BazelDevMode: modulesDefaultToBazel = true @@ -551,9 +557,7 @@ func (r *builtinBazelRunner) createBazelCommand(paths *bazelPaths, runName bazel // // The actual platform values here may be overridden by configuration // transitions from the buildroot. - fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_target"), fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"), - // This should be parameterized on the host OS, but let's restrict to linux // to keep things simple for now. fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"), @@ -572,7 +576,7 @@ func (r *builtinBazelRunner) createBazelCommand(paths *bazelPaths, runName bazel "HOME=" + paths.homeDir, pwdPrefix(), "BUILD_DIR=" + absolutePath(paths.soongOutDir), - // Make OUT_DIR absolute here so tools/bazel.sh uses the correct + // Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct // OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out. "OUT_DIR=" + absolutePath(paths.outDir()), // Disables local host detection of gcc; toolchain information is defined @@ -922,7 +926,7 @@ func (context *bazelContext) InvokeBazel(config Config) error { // // 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. - extraFlags := []string{"--output=jsonproto", "--include_file_write_contents"} + extraFlags := []string{"--output=proto", "--include_file_write_contents"} if Bool(config.productVariables.ClangCoverage) { extraFlags = append(extraFlags, "--collect_code_coverage") paths := make([]string, 0, 2) diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go index dc2261c62..c85727217 100644 --- a/android/bazel_handler_test.go +++ b/android/bazel_handler_test.go @@ -1,6 +1,7 @@ package android import ( + "encoding/json" "os" "path/filepath" "reflect" @@ -8,6 +9,8 @@ import ( "testing" "android/soong/bazel/cquery" + "google.golang.org/protobuf/proto" + analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2" ) var testConfig = TestConfig("out", nil, "", nil) @@ -65,52 +68,56 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) { var testCases = []testCase{ {` { - "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" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_Id": 1, + "action_Key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_Ids": [1], + "primary_output_id": 1 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two" }] }`, "cd 'test/exec_root' && rm -f 'one' && touch foo", }, {` { - "artifacts": [ - { "id": 1, "pathFragmentId": 10 }, - { "id": 2, "pathFragmentId": 20 }], - "actions": [{ - "targetId": 100, - "actionKey": "x", - "mnemonic": "x", - "arguments": ["bogus", "command"], - "outputIds": [1, 2], - "primaryOutputId": 1 - }], - "pathFragments": [ - { "id": 10, "label": "one", "parentId": 30 }, - { "id": 20, "label": "one.d", "parentId": 30 }, - { "id": 30, "label": "parent" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 10 }, + { "id": 2, "path_fragment_id": 20 }], + "actions": [{ + "target_Id": 100, + "action_Key": "x", + "mnemonic": "x", + "arguments": ["bogus", "command"], + "output_Ids": [1, 2], + "primary_output_id": 1 + }], + "path_fragments": [ + { "id": 10, "label": "one", "parent_id": 30 }, + { "id": 20, "label": "one.d", "parent_id": 30 }, + { "id": 30, "label": "parent" }] }`, `cd 'test/exec_root' && rm -f 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`, }, } for i, testCase := range testCases { + data, err := JsonToActionGraphContainer(testCase.input) + if err != nil { + t.Error(err) + } bazelContext, _ := testBazelContext(t, map[bazelCommand]string{ - bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: testCase.input}) + bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)}) - err := bazelContext.InvokeBazel(testConfig) + err = bazelContext.InvokeBazel(testConfig) if err != nil { t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err) } @@ -194,3 +201,14 @@ func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) requests: map[cqueryKey]bool{}, }, p.soongOutDir } + +// Transform the json format to ActionGraphContainer +func JsonToActionGraphContainer(inputString string) ([]byte, error) { + var aqueryProtoResult analysis_v2_proto.ActionGraphContainer + err := json.Unmarshal([]byte(inputString), &aqueryProtoResult) + if err != nil { + return []byte(""), err + } + data, _ := proto.Marshal(&aqueryProtoResult) + return data, err +} diff --git a/android/config.go b/android/config.go index 4992882b9..df2c7673a 100644 --- a/android/config.go +++ b/android/config.go @@ -75,6 +75,9 @@ const ( // Don't use bazel at all during module analysis. AnalysisNoBazel SoongBuildMode = iota + // Symlink fores mode: merge two directory trees into a symlink forest + SymlinkForest + // Bp2build mode: Generate BUILD files from blueprint files and exit. Bp2build @@ -97,6 +100,11 @@ const ( // allowlisted on an experimental basis. BazelDevMode + // Use bazel during analysis of a few allowlisted build modules. The allowlist + // is considered "staging, as these are modules being prepared to be released + // into prod mode shortly after. + BazelStagingMode + // Use bazel during analysis of build modules from an allowlist carefully // curated by the build team to be proven stable. BazelProdMode diff --git a/android/filegroup.go b/android/filegroup.go index 6b1117230..af4d89a51 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -234,7 +234,8 @@ func (fg *fileGroup) QueueBazelCall(ctx BaseModuleContext) { } func (fg *fileGroup) IsMixedBuildSupported(ctx BaseModuleContext) bool { - return true + // TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups + return false } func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) { diff --git a/android/filegroup_test.go b/android/filegroup_test.go index a7ea8054c..8292d5e67 100644 --- a/android/filegroup_test.go +++ b/android/filegroup_test.go @@ -6,6 +6,8 @@ import ( ) func TestFileGroupWithPathProp(t *testing.T) { + // TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups + t.Skip("Re-enable once filegroups are corrected for mixed builds") outBaseDir := "outputbase" pathPrefix := outBaseDir + "/execroot/__main__" expectedOutputfile := filepath.Join(pathPrefix, "a/b/c/d/test.aidl") diff --git a/android/makevars.go b/android/makevars.go index 5165a55e2..0800190c3 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -471,7 +471,7 @@ func (s *makeVarsSingleton) writeInstalls(installs, symlinks []katiInstall) []by fmt.Fprintf(buf, " %s", dep.String()) } fmt.Fprintln(buf) - fmt.Fprintln(buf, "\t@echo \"Install $@\"") + fmt.Fprintln(buf, "\t@echo \"Install: $@\"") fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag) if install.executable { fmt.Fprintf(buf, "\tchmod +x $@\n") @@ -515,7 +515,7 @@ func (s *makeVarsSingleton) writeInstalls(installs, symlinks []katiInstall) []by fromStr = symlink.absFrom } - fmt.Fprintln(buf, "\t@echo \"Symlink $@\"") + fmt.Fprintln(buf, "\t@echo \"Symlink: $@\"") fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr) fmt.Fprintln(buf) fmt.Fprintln(buf) diff --git a/android/module.go b/android/module.go index 5aecb05d5..b41a89808 100644 --- a/android/module.go +++ b/android/module.go @@ -928,6 +928,8 @@ type CommonAttributes struct { Tags bazel.StringListAttribute Applicable_licenses bazel.LabelListAttribute + + Testonly *bool } // constraintAttributes represents Bazel attributes pertaining to build constraints, diff --git a/android/neverallow.go b/android/neverallow.go index 1cdccc317..d28843995 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -69,6 +69,7 @@ func AddNeverAllowRules(rules ...Rule) { func createBp2BuildRule() Rule { return NeverAllow(). With("bazel_module.bp2build_available", "true"). + NotIn("soong_tests"). // only used in tests Because("setting bp2build_available in Android.bp is not " + "supported for custom conversion, use allowlists.go instead.") } @@ -162,6 +163,7 @@ func createJavaDeviceForHostRules() []Rule { "development/build", "external/guava", "external/robolectric-shadows", + "external/robolectric", "frameworks/layoutlib", } diff --git a/android/paths.go b/android/paths.go index dbcdb23e9..375297f6a 100644 --- a/android/paths.go +++ b/android/paths.go @@ -1139,6 +1139,21 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { return path } +// MaybeExistentPathForSource joins the provided path components and validates that the result +// neither escapes the source dir nor is in the out dir. +// It does not validate whether the path exists. +func MaybeExistentPathForSource(ctx PathContext, pathComponents ...string) SourcePath { + path, err := pathForSource(ctx, pathComponents...) + if err != nil { + reportPathError(ctx, err) + } + + if pathtools.IsGlob(path.String()) { + ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) + } + return path +} + // ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not* // rooted from the module's local source directory, if the path exists, or an empty OptionalPath if // it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state diff --git a/apex/apex.go b/apex/apex.go index 88a057f1f..b039d0dad 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -17,13 +17,14 @@ package apex import ( - "android/soong/bazel/cquery" "fmt" "path/filepath" "regexp" "sort" "strings" + "android/soong/bazel/cquery" + "github.com/google/blueprint" "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" @@ -47,7 +48,7 @@ func init() { func registerApexBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_test", testApexBundleFactory) + ctx.RegisterModuleType("apex_test", TestApexBundleFactory) ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory) ctx.RegisterModuleType("apex_defaults", defaultsFactory) ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory) @@ -1853,10 +1854,10 @@ func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) { a.outputFile = a.outputApexFile a.setCompression(ctx) - a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[0]) - a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyPair[1]) - a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[0]) - a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyPair[1]) + a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[0]) + a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[1]) + a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[0]) + a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[1]) apexType := a.properties.ApexType switch apexType { case imageApex: @@ -2563,7 +2564,7 @@ func ApexBundleFactory(testApex bool) android.Module { // apex_test is an APEX for testing. The difference from the ordinary apex module type is that // certain compatibility checks such as apex_available are not done for apex_test. -func testApexBundleFactory() android.Module { +func TestApexBundleFactory() android.Module { bundle := newApexBundle() bundle.testApex = true return bundle @@ -3359,6 +3360,7 @@ type bazelApexBundleAttributes struct { Compressible bazel.BoolAttribute Package_name *string Logging_parent *string + Tests bazel.LabelListAttribute } type convertedNativeSharedLibs struct { @@ -3368,13 +3370,19 @@ type convertedNativeSharedLibs struct { // ConvertWithBp2build performs bp2build conversion of an apex func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - // We do not convert apex_test modules at this time - if ctx.ModuleType() != "apex" { + // We only convert apex and apex_test modules at this time + if ctx.ModuleType() != "apex" && ctx.ModuleType() != "apex_test" { return } attrs, props := convertWithBp2build(a, ctx) - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, &attrs) + commonAttrs := android.CommonAttributes{ + Name: a.Name(), + } + if a.testApex { + commonAttrs.Testonly = proptools.BoolPtr(a.testApex) + } + ctx.CreateBazelTargetModule(props, commonAttrs, &attrs) } func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (bazelApexBundleAttributes, bazel.BazelTargetModuleProperties) { @@ -3441,6 +3449,12 @@ func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (baze binaries := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Binaries) binariesLabelListAttribute := bazel.MakeLabelListAttribute(binaries) + var testsAttrs bazel.LabelListAttribute + if a.testApex && len(a.properties.ApexNativeDependencies.Tests) > 0 { + tests := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Tests) + testsAttrs = bazel.MakeLabelListAttribute(tests) + } + var updatableAttribute bazel.BoolAttribute if a.properties.Updatable != nil { updatableAttribute.Value = a.properties.Updatable @@ -3483,6 +3497,7 @@ func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (baze Compressible: compressibleAttribute, Package_name: packageName, Logging_parent: loggingParent, + Tests: testsAttrs, } props := bazel.BazelTargetModuleProperties{ diff --git a/bazel/Android.bp b/bazel/Android.bp index 9e7edc795..d11c78b04 100644 --- a/bazel/Android.bp +++ b/bazel/Android.bp @@ -20,6 +20,7 @@ bootstrap_go_package { "soong_build", ], deps: [ + "bazel_analysis_v2_proto", "blueprint", ], } diff --git a/bazel/aquery.go b/bazel/aquery.go index 05f6ed48c..bc823b36e 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -17,7 +17,6 @@ package bazel import ( "crypto/sha256" "encoding/base64" - "encoding/json" "fmt" "path/filepath" "reflect" @@ -25,6 +24,8 @@ import ( "strings" "github.com/google/blueprint/proptools" + "google.golang.org/protobuf/proto" + analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2" ) type artifactId int @@ -312,11 +313,79 @@ func (a *aqueryArtifactHandler) artifactPathsFromDepsetHash(depsetHash string) ( // BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets // are one-to-one with Bazel's depSetOfFiles objects. func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, []AqueryDepset, error) { - var aqueryResult actionGraphContainer - err := json.Unmarshal(aqueryJsonProto, &aqueryResult) + aqueryProto := &analysis_v2_proto.ActionGraphContainer{} + err := proto.Unmarshal(aqueryJsonProto, aqueryProto) if err != nil { return nil, nil, err } + aqueryResult := actionGraphContainer{} + + for _, protoArtifact := range aqueryProto.Artifacts { + aqueryResult.Artifacts = append(aqueryResult.Artifacts, artifact{artifactId(protoArtifact.Id), + pathFragmentId(protoArtifact.PathFragmentId)}) + } + + for _, protoAction := range aqueryProto.Actions { + var environmentVariable []KeyValuePair + var inputDepSetIds []depsetId + var outputIds []artifactId + var substitutions []KeyValuePair + + for _, protoEnvironmentVariable := range protoAction.EnvironmentVariables { + environmentVariable = append(environmentVariable, KeyValuePair{ + protoEnvironmentVariable.Key, protoEnvironmentVariable.Value, + }) + } + for _, protoInputDepSetIds := range protoAction.InputDepSetIds { + inputDepSetIds = append(inputDepSetIds, depsetId(protoInputDepSetIds)) + } + for _, protoOutputIds := range protoAction.OutputIds { + outputIds = append(outputIds, artifactId(protoOutputIds)) + } + for _, protoSubstitutions := range protoAction.Substitutions { + substitutions = append(substitutions, KeyValuePair{ + protoSubstitutions.Key, protoSubstitutions.Value, + }) + } + + aqueryResult.Actions = append(aqueryResult.Actions, + action{ + Arguments: protoAction.Arguments, + EnvironmentVariables: environmentVariable, + InputDepSetIds: inputDepSetIds, + Mnemonic: protoAction.Mnemonic, + OutputIds: outputIds, + TemplateContent: protoAction.TemplateContent, + Substitutions: substitutions, + FileContents: protoAction.FileContents}) + } + + for _, protoDepSetOfFiles := range aqueryProto.DepSetOfFiles { + var directArtifactIds []artifactId + var transitiveDepSetIds []depsetId + + for _, protoDirectArtifactIds := range protoDepSetOfFiles.DirectArtifactIds { + directArtifactIds = append(directArtifactIds, artifactId(protoDirectArtifactIds)) + } + for _, protoTransitiveDepSetIds := range protoDepSetOfFiles.TransitiveDepSetIds { + transitiveDepSetIds = append(transitiveDepSetIds, depsetId(protoTransitiveDepSetIds)) + } + aqueryResult.DepSetOfFiles = append(aqueryResult.DepSetOfFiles, + depSetOfFiles{ + Id: depsetId(protoDepSetOfFiles.Id), + DirectArtifactIds: directArtifactIds, + TransitiveDepSetIds: transitiveDepSetIds}) + + } + + for _, protoPathFragments := range aqueryProto.PathFragments { + aqueryResult.PathFragments = append(aqueryResult.PathFragments, + pathFragment{ + Id: pathFragmentId(protoPathFragments.Id), + Label: protoPathFragments.Label, + ParentId: pathFragmentId(protoPathFragments.ParentId)}) + + } aqueryHandler, err := newAqueryHandler(aqueryResult) if err != nil { return nil, nil, err diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go index 581036439..2eacafa64 100644 --- a/bazel/aquery_test.go +++ b/bazel/aquery_test.go @@ -15,118 +15,128 @@ package bazel import ( + "encoding/json" "fmt" "reflect" "sort" "testing" + + "google.golang.org/protobuf/proto" + analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2" ) func TestAqueryMultiArchGenrule(t *testing.T) { // This input string is retrieved from a real build of bionic-related genrules. const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 6 }, - { "id": 3, "pathFragmentId": 8 }, - { "id": 4, "pathFragmentId": 12 }, - { "id": 5, "pathFragmentId": 19 }, - { "id": 6, "pathFragmentId": 20 }, - { "id": 7, "pathFragmentId": 21 }], - "actions": [{ - "targetId": 1, - "actionKey": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7", - "mnemonic": "Genrule", - "configurationId": 1, - "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm.S"], - "environmentVariables": [{ - "key": "PATH", - "value": "/bin:/usr/bin:/usr/local/bin" - }], - "inputDepSetIds": [1], - "outputIds": [4], - "primaryOutputId": 4 - }, { - "targetId": 2, - "actionKey": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826", - "mnemonic": "Genrule", - "configurationId": 1, - "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"], - "environmentVariables": [{ - "key": "PATH", - "value": "/bin:/usr/bin:/usr/local/bin" - }], - "inputDepSetIds": [2], - "outputIds": [5], - "primaryOutputId": 5 - }, { - "targetId": 3, - "actionKey": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342", - "mnemonic": "Genrule", - "configurationId": 1, - "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"], - "environmentVariables": [{ - "key": "PATH", - "value": "/bin:/usr/bin:/usr/local/bin" - }], - "inputDepSetIds": [3], - "outputIds": [6], - "primaryOutputId": 6 - }, { - "targetId": 4, - "actionKey": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa", - "mnemonic": "Genrule", - "configurationId": 1, - "arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"], - "environmentVariables": [{ - "key": "PATH", - "value": "/bin:/usr/bin:/usr/local/bin" - }], - "inputDepSetIds": [4], - "outputIds": [7], - "primaryOutputId": 7 - }], - "targets": [ - { "id": 1, "label": "@sourceroot//bionic/libc:syscalls-arm", "ruleClassId": 1 }, - { "id": 2, "label": "@sourceroot//bionic/libc:syscalls-x86", "ruleClassId": 1 }, - { "id": 3, "label": "@sourceroot//bionic/libc:syscalls-x86_64", "ruleClassId": 1 }, - { "id": 4, "label": "@sourceroot//bionic/libc:syscalls-arm64", "ruleClassId": 1 }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1, 2, 3] }, - { "id": 2, "directArtifactIds": [1, 2, 3] }, - { "id": 3, "directArtifactIds": [1, 2, 3] }, - { "id": 4, "directArtifactIds": [1, 2, 3] }], - "configuration": [{ - "id": 1, - "mnemonic": "k8-fastbuild", - "platformName": "k8", - "checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046" - }], - "ruleClasses": [{ "id": 1, "name": "genrule"}], - "pathFragments": [ - { "id": 5, "label": ".." }, - { "id": 4, "label": "sourceroot", "parentId": 5 }, - { "id": 3, "label": "bionic", "parentId": 4 }, - { "id": 2, "label": "libc", "parentId": 3 }, - { "id": 1, "label": "SYSCALLS.TXT", "parentId": 2 }, - { "id": 7, "label": "tools", "parentId": 2 }, - { "id": 6, "label": "gensyscalls.py", "parentId": 7 }, - { "id": 11, "label": "bazel_tools", "parentId": 5 }, - { "id": 10, "label": "tools", "parentId": 11 }, - { "id": 9, "label": "genrule", "parentId": 10 }, - { "id": 8, "label": "genrule-setup.sh", "parentId": 9 }, - { "id": 18, "label": "bazel-out" }, - { "id": 17, "label": "sourceroot", "parentId": 18 }, - { "id": 16, "label": "k8-fastbuild", "parentId": 17 }, - { "id": 15, "label": "bin", "parentId": 16 }, - { "id": 14, "label": "bionic", "parentId": 15 }, - { "id": 13, "label": "libc", "parentId": 14 }, - { "id": 12, "label": "syscalls-arm.S", "parentId": 13 }, - { "id": 19, "label": "syscalls-x86.S", "parentId": 13 }, - { "id": 20, "label": "syscalls-x86_64.S", "parentId": 13 }, - { "id": 21, "label": "syscalls-arm64.S", "parentId": 13 }] -}` - actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString)) + "Artifacts": [ + { "Id": 1, "path_fragment_id": 1 }, + { "Id": 2, "path_fragment_id": 6 }, + { "Id": 3, "path_fragment_id": 8 }, + { "Id": 4, "path_fragment_id": 12 }, + { "Id": 5, "path_fragment_id": 19 }, + { "Id": 6, "path_fragment_id": 20 }, + { "Id": 7, "path_fragment_id": 21 }], + "Actions": [{ + "target_id": 1, + "action_key": "ab53f6ecbdc2ee8cb8812613b63205464f1f5083f6dca87081a0a398c0f1ecf7", + "Mnemonic": "Genrule", + "configuration_id": 1, + "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm.S"], + "environment_variables": [{ + "Key": "PATH", + "Value": "/bin:/usr/bin:/usr/local/bin" + }], + "input_dep_set_ids": [1], + "output_ids": [4], + "primary_output_id": 4 + }, { + "target_id": 2, + "action_key": "9f4309ce165dac458498cb92811c18b0b7919782cc37b82a42d2141b8cc90826", + "Mnemonic": "Genrule", + "configuration_id": 1, + "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86.S"], + "environment_variables": [{ + "Key": "PATH", + "Value": "/bin:/usr/bin:/usr/local/bin" + }], + "input_dep_set_ids": [2], + "output_ids": [5], + "primary_output_id": 5 + }, { + "target_id": 3, + "action_key": "50d6c586103ebeed3a218195540bcc30d329464eae36377eb82f8ce7c36ac342", + "Mnemonic": "Genrule", + "configuration_id": 1, + "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py x86_64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-x86_64.S"], + "environment_variables": [{ + "Key": "PATH", + "Value": "/bin:/usr/bin:/usr/local/bin" + }], + "input_dep_set_ids": [3], + "output_ids": [6], + "primary_output_id": 6 + }, { + "target_id": 4, + "action_key": "f30cbe442f5216f4223cf16a39112cad4ec56f31f49290d85cff587e48647ffa", + "Mnemonic": "Genrule", + "configuration_id": 1, + "Arguments": ["/bin/bash", "-c", "source ../bazel_tools/tools/genrule/genrule-setup.sh; ../sourceroot/bionic/libc/tools/gensyscalls.py arm64 ../sourceroot/bionic/libc/SYSCALLS.TXT \u003e bazel-out/sourceroot/k8-fastbuild/bin/bionic/libc/syscalls-arm64.S"], + "environment_variables": [{ + "Key": "PATH", + "Value": "/bin:/usr/bin:/usr/local/bin" + }], + "input_dep_set_ids": [4], + "output_ids": [7], + "primary_output_id": 7 + }], + "Targets": [ + { "Id": 1, "Label": "@sourceroot//bionic/libc:syscalls-arm", "rule_class_id": 1 }, + { "Id": 2, "Label": "@sourceroot//bionic/libc:syscalls-x86", "rule_class_id": 1 }, + { "Id": 3, "Label": "@sourceroot//bionic/libc:syscalls-x86_64", "rule_class_id": 1 }, + { "Id": 4, "Label": "@sourceroot//bionic/libc:syscalls-arm64", "rule_class_id": 1 }], + "dep_set_of_files": [ + { "Id": 1, "direct_artifact_ids": [1, 2, 3] }, + { "Id": 2, "direct_artifact_ids": [1, 2, 3] }, + { "Id": 3, "direct_artifact_ids": [1, 2, 3] }, + { "Id": 4, "direct_artifact_ids": [1, 2, 3] }], + "Configuration": [{ + "Id": 1, + "Mnemonic": "k8-fastbuild", + "platform_name": "k8", + "Checksum": "485c362832c178e367d972177f68e69e0981e51e67ef1c160944473db53fe046" + }], + "rule_classes": [{ "Id": 1, "Name": "genrule"}], + "path_fragments": [ + { "Id": 5, "Label": ".." }, + { "Id": 4, "Label": "sourceroot", "parent_id": 5 }, + { "Id": 3, "Label": "bionic", "parent_id": 4 }, + { "Id": 2, "Label": "libc", "parent_id": 3 }, + { "Id": 1, "Label": "SYSCALLS.TXT", "parent_id": 2 }, + { "Id": 7, "Label": "tools", "parent_id": 2 }, + { "Id": 6, "Label": "gensyscalls.py", "parent_id": 7 }, + { "Id": 11, "Label": "bazel_tools", "parent_id": 5 }, + { "Id": 10, "Label": "tools", "parent_id": 11 }, + { "Id": 9, "Label": "genrule", "parent_id": 10 }, + { "Id": 8, "Label": "genrule-setup.sh", "parent_id": 9 }, + { "Id": 18, "Label": "bazel-out" }, + { "Id": 17, "Label": "sourceroot", "parent_id": 18 }, + { "Id": 16, "Label": "k8-fastbuild", "parent_id": 17 }, + { "Id": 15, "Label": "bin", "parent_id": 16 }, + { "Id": 14, "Label": "bionic", "parent_id": 15 }, + { "Id": 13, "Label": "libc", "parent_id": 14 }, + { "Id": 12, "Label": "syscalls-arm.S", "parent_id": 13 }, + { "Id": 19, "Label": "syscalls-x86.S", "parent_id": 13 }, + { "Id": 20, "Label": "syscalls-x86_64.S", "parent_id": 13 }, + { "Id": 21, "Label": "syscalls-arm64.S", "parent_id": 13 }] +} +` + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data) var expectedBuildStatements []BuildStatement for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} { expectedBuildStatements = append(expectedBuildStatements, @@ -161,130 +171,155 @@ func TestAqueryMultiArchGenrule(t *testing.T) { func TestInvalidOutputId(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "x", - "arguments": ["touch", "foo"], - "inputDepSetIds": [1], - "outputIds": [3], - "primaryOutputId": 3 - }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1, 2] }], - "pathFragments": [ - { "id": 1, "label": "one" }, - { "id": 2, "label": "two" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_ids": [3], + "primary_output_id": 3 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, "undefined outputId 3") } func TestInvalidInputDepsetIdFromAction(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "x", - "arguments": ["touch", "foo"], - "inputDepSetIds": [2], - "outputIds": [1], - "primaryOutputId": 1 - }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1, 2] }], - "pathFragments": [ - { "id": 1, "label": "one" }, - { "id": 2, "label": "two" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [2], + "output_ids": [1], + "primary_output_id": 1 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, "undefined input depsetId 2") } func TestInvalidInputDepsetIdFromDepset(t *testing.T) { const inputString = ` { - "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], "transitiveDepSetIds": [42] }], - "pathFragments": [ - { "id": 1, "label": "one"}, - { "id": 2, "label": "two" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_ids": [1], + "primary_output_id": 1 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2], "transitive_dep_set_ids": [42] }], + "path_fragments": [ + { "id": 1, "label": "one"}, + { "id": 2, "label": "two" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)") } func TestInvalidInputArtifactId(t *testing.T) { const inputString = ` { - "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, 3] }], - "pathFragments": [ - { "id": 1, "label": "one" }, - { "id": 2, "label": "two" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_ids": [1], + "primary_output_id": 1 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 3] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, "undefined input artifactId 3") } func TestInvalidPathFragmentId(t *testing.T) { const inputString = ` { - "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", "parentId": 3 }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_ids": [1], + "primary_output_id": 1 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two", "parent_id": 3 }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, "undefined path fragment id 3") } @@ -292,27 +327,32 @@ func TestDepfiles(t *testing.T) { const inputString = ` { "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }, - { "id": 3, "pathFragmentId": 3 }], + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }, + { "id": 3, "path_fragment_id": 3 }], "actions": [{ - "targetId": 1, - "actionKey": "x", + "target_Id": 1, + "action_Key": "x", "mnemonic": "x", "arguments": ["touch", "foo"], - "inputDepSetIds": [1], - "outputIds": [2, 3], - "primaryOutputId": 2 + "input_dep_set_ids": [1], + "output_ids": [2, 3], + "primary_output_id": 2 }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1, 2, 3] }], - "pathFragments": [ + "dep_set_of_files": [ + { "id": 1, "direct_Artifact_Ids": [1, 2, 3] }], + "path_fragments": [ { "id": 1, "label": "one" }, { "id": 2, "label": "two" }, { "id": 3, "label": "two.d" }] }` - actual, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -332,32 +372,37 @@ func TestDepfiles(t *testing.T) { func TestMultipleDepfiles(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }, - { "id": 3, "pathFragmentId": 3 }, - { "id": 4, "pathFragmentId": 4 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "x", - "arguments": ["touch", "foo"], - "inputDepSetIds": [1], - "outputIds": [2,3,4], - "primaryOutputId": 2 - }], - "depSetOfFiles": [{ - "id": 1, - "directArtifactIds": [1, 2, 3, 4] - }], - "pathFragments": [ - { "id": 1, "label": "one" }, - { "id": 2, "label": "two" }, - { "id": 3, "label": "two.d" }, - { "id": 4, "label": "other.d" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }, + { "id": 3, "path_fragment_id": 3 }, + { "id": 4, "path_fragment_id": 4 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_ids": [2,3,4], + "primary_output_id": 2 + }], + "dep_set_of_files": [{ + "id": 1, + "direct_artifact_ids": [1, 2, 3, 4] + }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "two" }, + { "id": 3, "label": "two.d" }, + { "id": 4, "label": "other.d" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`) } @@ -366,74 +411,79 @@ func TestTransitiveInputDepsets(t *testing.T) { // a single action with many inputs given via a deep depset. const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 7 }, - { "id": 3, "pathFragmentId": 8 }, - { "id": 4, "pathFragmentId": 9 }, - { "id": 5, "pathFragmentId": 10 }, - { "id": 6, "pathFragmentId": 11 }, - { "id": 7, "pathFragmentId": 12 }, - { "id": 8, "pathFragmentId": 13 }, - { "id": 9, "pathFragmentId": 14 }, - { "id": 10, "pathFragmentId": 15 }, - { "id": 11, "pathFragmentId": 16 }, - { "id": 12, "pathFragmentId": 17 }, - { "id": 13, "pathFragmentId": 18 }, - { "id": 14, "pathFragmentId": 19 }, - { "id": 15, "pathFragmentId": 20 }, - { "id": 16, "pathFragmentId": 21 }, - { "id": 17, "pathFragmentId": 22 }, - { "id": 18, "pathFragmentId": 23 }, - { "id": 19, "pathFragmentId": 24 }, - { "id": 20, "pathFragmentId": 25 }, - { "id": 21, "pathFragmentId": 26 }], - "actions": [{ - "targetId": 1, - "actionKey": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50", - "mnemonic": "Action", - "configurationId": 1, - "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"], - "inputDepSetIds": [1], - "outputIds": [21], - "primaryOutputId": 21 - }], - "depSetOfFiles": [ - { "id": 3, "directArtifactIds": [1, 2, 3, 4, 5] }, - { "id": 4, "directArtifactIds": [6, 7, 8, 9, 10] }, - { "id": 2, "transitiveDepSetIds": [3, 4], "directArtifactIds": [11, 12, 13, 14, 15] }, - { "id": 5, "directArtifactIds": [16, 17, 18, 19] }, - { "id": 1, "transitiveDepSetIds": [2, 5], "directArtifactIds": [20] }], - "pathFragments": [ - { "id": 6, "label": "bazel-out" }, - { "id": 5, "label": "sourceroot", "parentId": 6 }, - { "id": 4, "label": "k8-fastbuild", "parentId": 5 }, - { "id": 3, "label": "bin", "parentId": 4 }, - { "id": 2, "label": "testpkg", "parentId": 3 }, - { "id": 1, "label": "test_1", "parentId": 2 }, - { "id": 7, "label": "test_2", "parentId": 2 }, - { "id": 8, "label": "test_3", "parentId": 2 }, - { "id": 9, "label": "test_4", "parentId": 2 }, - { "id": 10, "label": "test_5", "parentId": 2 }, - { "id": 11, "label": "test_6", "parentId": 2 }, - { "id": 12, "label": "test_7", "parentId": 2 }, - { "id": 13, "label": "test_8", "parentId": 2 }, - { "id": 14, "label": "test_9", "parentId": 2 }, - { "id": 15, "label": "test_10", "parentId": 2 }, - { "id": 16, "label": "test_11", "parentId": 2 }, - { "id": 17, "label": "test_12", "parentId": 2 }, - { "id": 18, "label": "test_13", "parentId": 2 }, - { "id": 19, "label": "test_14", "parentId": 2 }, - { "id": 20, "label": "test_15", "parentId": 2 }, - { "id": 21, "label": "test_16", "parentId": 2 }, - { "id": 22, "label": "test_17", "parentId": 2 }, - { "id": 23, "label": "test_18", "parentId": 2 }, - { "id": 24, "label": "test_19", "parentId": 2 }, - { "id": 25, "label": "test_root", "parentId": 2 }, - { "id": 26,"label": "test_out", "parentId": 2 }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 7 }, + { "id": 3, "path_fragment_id": 8 }, + { "id": 4, "path_fragment_id": 9 }, + { "id": 5, "path_fragment_id": 10 }, + { "id": 6, "path_fragment_id": 11 }, + { "id": 7, "path_fragment_id": 12 }, + { "id": 8, "path_fragment_id": 13 }, + { "id": 9, "path_fragment_id": 14 }, + { "id": 10, "path_fragment_id": 15 }, + { "id": 11, "path_fragment_id": 16 }, + { "id": 12, "path_fragment_id": 17 }, + { "id": 13, "path_fragment_id": 18 }, + { "id": 14, "path_fragment_id": 19 }, + { "id": 15, "path_fragment_id": 20 }, + { "id": 16, "path_fragment_id": 21 }, + { "id": 17, "path_fragment_id": 22 }, + { "id": 18, "path_fragment_id": 23 }, + { "id": 19, "path_fragment_id": 24 }, + { "id": 20, "path_fragment_id": 25 }, + { "id": 21, "path_fragment_id": 26 }], + "actions": [{ + "target_id": 1, + "action_key": "3b826d17fadbbbcd8313e456b90ec47c078c438088891dd45b4adbcd8889dc50", + "mnemonic": "Action", + "configuration_id": 1, + "arguments": ["/bin/bash", "-c", "touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"], + "input_dep_set_ids": [1], + "output_ids": [21], + "primary_output_id": 21 + }], + "dep_set_of_files": [ + { "id": 3, "direct_artifact_ids": [1, 2, 3, 4, 5] }, + { "id": 4, "direct_artifact_ids": [6, 7, 8, 9, 10] }, + { "id": 2, "transitive_dep_set_ids": [3, 4], "direct_artifact_ids": [11, 12, 13, 14, 15] }, + { "id": 5, "direct_artifact_ids": [16, 17, 18, 19] }, + { "id": 1, "transitive_dep_set_ids": [2, 5], "direct_artifact_ids": [20] }], + "path_fragments": [ + { "id": 6, "label": "bazel-out" }, + { "id": 5, "label": "sourceroot", "parent_id": 6 }, + { "id": 4, "label": "k8-fastbuild", "parent_id": 5 }, + { "id": 3, "label": "bin", "parent_id": 4 }, + { "id": 2, "label": "testpkg", "parent_id": 3 }, + { "id": 1, "label": "test_1", "parent_id": 2 }, + { "id": 7, "label": "test_2", "parent_id": 2 }, + { "id": 8, "label": "test_3", "parent_id": 2 }, + { "id": 9, "label": "test_4", "parent_id": 2 }, + { "id": 10, "label": "test_5", "parent_id": 2 }, + { "id": 11, "label": "test_6", "parent_id": 2 }, + { "id": 12, "label": "test_7", "parent_id": 2 }, + { "id": 13, "label": "test_8", "parent_id": 2 }, + { "id": 14, "label": "test_9", "parent_id": 2 }, + { "id": 15, "label": "test_10", "parent_id": 2 }, + { "id": 16, "label": "test_11", "parent_id": 2 }, + { "id": 17, "label": "test_12", "parent_id": 2 }, + { "id": 18, "label": "test_13", "parent_id": 2 }, + { "id": 19, "label": "test_14", "parent_id": 2 }, + { "id": 20, "label": "test_15", "parent_id": 2 }, + { "id": 21, "label": "test_16", "parent_id": 2 }, + { "id": 22, "label": "test_17", "parent_id": 2 }, + { "id": 23, "label": "test_18", "parent_id": 2 }, + { "id": 24, "label": "test_19", "parent_id": 2 }, + { "id": 25, "label": "test_root", "parent_id": 2 }, + { "id": 26,"label": "test_out", "parent_id": 2 }] }` - actualbuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data) expectedBuildStatements := []BuildStatement{ { @@ -463,27 +513,32 @@ func TestTransitiveInputDepsets(t *testing.T) { func TestSymlinkTree(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "SymlinkTree", - "configurationId": 1, - "inputDepSetIds": [1], - "outputIds": [2], - "primaryOutputId": 2, - "executionPlatform": "//build/bazel/platforms:linux_x86_64" - }], - "pathFragments": [ - { "id": 1, "label": "foo.manifest" }, - { "id": 2, "label": "foo.runfiles/MANIFEST" }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1] }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "SymlinkTree", + "configuration_id": 1, + "input_dep_set_ids": [1], + "output_ids": [2], + "primary_output_id": 2, + "execution_platform": "//build/bazel/platforms:linux_x86_64" + }], + "path_fragments": [ + { "id": 1, "label": "foo.manifest" }, + { "id": 2, "label": "foo.runfiles/MANIFEST" }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1] }] } ` - actual, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -499,37 +554,42 @@ func TestSymlinkTree(t *testing.T) { func TestBazelOutRemovalFromInputDepsets(t *testing.T) { const inputString = `{ - "artifacts": [ - { "id": 1, "pathFragmentId": 10 }, - { "id": 2, "pathFragmentId": 20 }, - { "id": 3, "pathFragmentId": 30 }, - { "id": 4, "pathFragmentId": 40 }], - "depSetOfFiles": [{ - "id": 1111, - "directArtifactIds": [3 , 4] - }, { - "id": 2222, - "directArtifactIds": [3] - }], - "actions": [{ - "targetId": 100, - "actionKey": "x", - "inputDepSetIds": [1111, 2222], - "mnemonic": "x", - "arguments": ["bogus", "command"], - "outputIds": [2], - "primaryOutputId": 1 - }], - "pathFragments": [ - { "id": 10, "label": "input" }, - { "id": 20, "label": "output" }, - { "id": 30, "label": "dep1", "parentId": 50 }, - { "id": 40, "label": "dep2", "parentId": 60 }, - { "id": 50, "label": "bazel_tools", "parentId": 60 }, - { "id": 60, "label": ".."} - ] + "artifacts": [ + { "id": 1, "path_fragment_id": 10 }, + { "id": 2, "path_fragment_id": 20 }, + { "id": 3, "path_fragment_id": 30 }, + { "id": 4, "path_fragment_id": 40 }], + "dep_set_of_files": [{ + "id": 1111, + "direct_artifact_ids": [3 , 4] + }, { + "id": 2222, + "direct_artifact_ids": [3] + }], + "actions": [{ + "target_id": 100, + "action_key": "x", + "input_dep_set_ids": [1111, 2222], + "mnemonic": "x", + "arguments": ["bogus", "command"], + "output_ids": [2], + "primary_output_id": 1 + }], + "path_fragments": [ + { "id": 10, "label": "input" }, + { "id": 20, "label": "output" }, + { "id": 30, "label": "dep1", "parent_id": 50 }, + { "id": 40, "label": "dep2", "parent_id": 60 }, + { "id": 50, "label": "bazel_tools", "parent_id": 60 }, + { "id": 60, "label": ".."} + ] }` - actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data) if len(actualDepsets) != 2 { t.Errorf("expected 1 depset but found %#v", actualDepsets) return @@ -567,43 +627,47 @@ func TestBazelOutRemovalFromInputDepsets(t *testing.T) { func TestMiddlemenAction(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }, - { "id": 3, "pathFragmentId": 3 }, - { "id": 4, "pathFragmentId": 4 }, - { "id": 5, "pathFragmentId": 5 }, - { "id": 6, "pathFragmentId": 6 }], - "pathFragments": [ - { "id": 1, "label": "middleinput_one" }, - { "id": 2, "label": "middleinput_two" }, - { "id": 3, "label": "middleman_artifact" }, - { "id": 4, "label": "maininput_one" }, - { "id": 5, "label": "maininput_two" }, - { "id": 6, "label": "output" }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1, 2] }, - { "id": 2, "directArtifactIds": [3, 4, 5] }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "Middleman", - "arguments": ["touch", "foo"], - "inputDepSetIds": [1], - "outputIds": [3], - "primaryOutputId": 3 - }, { - "targetId": 2, - "actionKey": "y", - "mnemonic": "Main action", - "arguments": ["touch", "foo"], - "inputDepSetIds": [2], - "outputIds": [6], - "primaryOutputId": 6 - }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }, + { "id": 3, "path_fragment_id": 3 }, + { "id": 4, "path_fragment_id": 4 }, + { "id": 5, "path_fragment_id": 5 }, + { "id": 6, "path_fragment_id": 6 }], + "path_fragments": [ + { "id": 1, "label": "middleinput_one" }, + { "id": 2, "label": "middleinput_two" }, + { "id": 3, "label": "middleman_artifact" }, + { "id": 4, "label": "maininput_one" }, + { "id": 5, "label": "maininput_two" }, + { "id": 6, "label": "output" }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1, 2] }, + { "id": 2, "direct_artifact_ids": [3, 4, 5] }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "Middleman", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [1], + "output_ids": [3], + "primary_output_id": 3 + }, { + "target_id": 2, + "action_key": "y", + "mnemonic": "Main action", + "arguments": ["touch", "foo"], + "input_dep_set_ids": [2], + "output_ids": [6], + "primary_output_id": 6 + }] }` - - actualBuildStatements, actualDepsets, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -675,28 +739,32 @@ func assertFlattenedDepsets(t *testing.T, actualDepsets []AqueryDepset, expected func TestSimpleSymlink(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 3 }, - { "id": 2, "pathFragmentId": 5 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "Symlink", - "inputDepSetIds": [1], - "outputIds": [2], - "primaryOutputId": 2 - }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1] }], - "pathFragments": [ - { "id": 1, "label": "one" }, - { "id": 2, "label": "file_subdir", "parentId": 1 }, - { "id": 3, "label": "file", "parentId": 2 }, - { "id": 4, "label": "symlink_subdir", "parentId": 1 }, - { "id": 5, "label": "symlink", "parentId": 4 }] + "artifacts": [ + { "id": 1, "path_fragment_id": 3 }, + { "id": 2, "path_fragment_id": 5 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "Symlink", + "input_dep_set_ids": [1], + "output_ids": [2], + "primary_output_id": 2 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "file_subdir", "parent_id": 1 }, + { "id": 3, "label": "file", "parent_id": 2 }, + { "id": 4, "label": "symlink_subdir", "parent_id": 1 }, + { "id": 5, "label": "symlink", "parent_id": 4 }] }` - - actual, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) @@ -719,29 +787,33 @@ func TestSimpleSymlink(t *testing.T) { func TestSymlinkQuotesPaths(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 3 }, - { "id": 2, "pathFragmentId": 5 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "SolibSymlink", - "inputDepSetIds": [1], - "outputIds": [2], - "primaryOutputId": 2 - }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1] }], - "pathFragments": [ - { "id": 1, "label": "one" }, - { "id": 2, "label": "file subdir", "parentId": 1 }, - { "id": 3, "label": "file", "parentId": 2 }, - { "id": 4, "label": "symlink subdir", "parentId": 1 }, - { "id": 5, "label": "symlink", "parentId": 4 }] + "artifacts": [ + { "id": 1, "path_fragment_id": 3 }, + { "id": 2, "path_fragment_id": 5 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "SolibSymlink", + "input_dep_set_ids": [1], + "output_ids": [2], + "primary_output_id": 2 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1] }], + "path_fragments": [ + { "id": 1, "label": "one" }, + { "id": 2, "label": "file subdir", "parent_id": 1 }, + { "id": 3, "label": "file", "parent_id": 2 }, + { "id": 4, "label": "symlink subdir", "parent_id": 1 }, + { "id": 5, "label": "symlink", "parent_id": 4 }] }` - actual, _, err := AqueryBuildStatements([]byte(inputString)) - + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -763,82 +835,95 @@ func TestSymlinkQuotesPaths(t *testing.T) { func TestSymlinkMultipleInputs(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }, - { "id": 3, "pathFragmentId": 3 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "Symlink", - "inputDepSetIds": [1], - "outputIds": [3], - "primaryOutputId": 3 - }], - "depSetOfFiles": [{ "id": 1, "directArtifactIds": [1,2] }], - "pathFragments": [ - { "id": 1, "label": "file" }, - { "id": 2, "label": "other_file" }, - { "id": 3, "label": "symlink" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 2, "path_fragment_id": 2 }, + { "id": 3, "path_fragment_id": 3 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "Symlink", + "input_dep_set_ids": [1], + "output_ids": [3], + "primary_output_id": 3 + }], + "dep_set_of_files": [{ "id": 1, "direct_artifact_ids": [1,2] }], + "path_fragments": [ + { "id": 1, "label": "file" }, + { "id": 2, "label": "other_file" }, + { "id": 3, "label": "symlink" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`) } func TestSymlinkMultipleOutputs(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }, - { "id": 2, "pathFragmentId": 2 }, - { "id": 3, "pathFragmentId": 3 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "Symlink", - "inputDepSetIds": [1], - "outputIds": [2,3], - "primaryOutputId": 2 - }], - "depSetOfFiles": [ - { "id": 1, "directArtifactIds": [1] }], - "pathFragments": [ - { "id": 1, "label": "file" }, - { "id": 2, "label": "symlink" }, - { "id": 3, "label": "other_symlink" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }, + { "id": 3, "path_fragment_id": 3 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "Symlink", + "input_dep_set_ids": [1], + "output_ids": [2,3], + "primary_output_id": 2 + }], + "dep_set_of_files": [ + { "id": 1, "direct_artifact_ids": [1] }], + "path_fragments": [ + { "id": 1, "label": "file" }, + { "id": 2, "label": "symlink" }, + { "id": 3, "label": "other_symlink" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) - assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) + assertError(t, err, "undefined outputId 2") } func TestTemplateExpandActionSubstitutions(t *testing.T) { const inputString = ` { - "artifacts": [{ - "id": 1, - "pathFragmentId": 1 - }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "TemplateExpand", - "configurationId": 1, - "outputIds": [1], - "primaryOutputId": 1, - "executionPlatform": "//build/bazel/platforms:linux_x86_64", - "templateContent": "Test template substitutions: %token1%, %python_binary%", - "substitutions": [ - { "key": "%token1%", "value": "abcd" }, - { "key": "%python_binary%", "value": "python3" }] - }], - "pathFragments": [ - { "id": 1, "label": "template_file" }] + "artifacts": [{ + "id": 1, + "path_fragment_id": 1 + }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "TemplateExpand", + "configuration_id": 1, + "output_ids": [1], + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "template_content": "Test template substitutions: %token1%, %python_binary%", + "substitutions": [ + { "key": "%token1%", "value": "abcd" }, + { "key": "%python_binary%", "value": "python3" }] + }], + "path_fragments": [ + { "id": 1, "label": "template_file" }] }` - actual, _, err := AqueryBuildStatements([]byte(inputString)) - + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -857,48 +942,58 @@ func TestTemplateExpandActionSubstitutions(t *testing.T) { func TestTemplateExpandActionNoOutput(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "TemplateExpand", - "configurationId": 1, - "primaryOutputId": 1, - "executionPlatform": "//build/bazel/platforms:linux_x86_64", - "templateContent": "Test template substitutions: %token1%, %python_binary%", - "substitutions": [ - { "key": "%token1%", "value": "abcd" }, - { "key": "%python_binary%", "value": "python3" }] - }], - "pathFragments": [ - { "id": 1, "label": "template_file" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "TemplateExpand", + "configuration_id": 1, + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "templateContent": "Test template substitutions: %token1%, %python_binary%", + "substitutions": [ + { "key": "%token1%", "value": "abcd" }, + { "key": "%python_binary%", "value": "python3" }] + }], + "path_fragments": [ + { "id": 1, "label": "template_file" }] }` - _, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + _, _, err = AqueryBuildStatements(data) assertError(t, err, `Expect 1 output to template expand action, got: output []`) } func TestFileWrite(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "FileWrite", - "configurationId": 1, - "outputIds": [1], - "primaryOutputId": 1, - "executionPlatform": "//build/bazel/platforms:linux_x86_64", - "fileContents": "file data\n" - }], - "pathFragments": [ - { "id": 1, "label": "foo.manifest" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "FileWrite", + "configuration_id": 1, + "output_ids": [1], + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "file_contents": "file data\n" + }], + "path_fragments": [ + { "id": 1, "label": "foo.manifest" }] } ` - actual, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -914,23 +1009,28 @@ func TestFileWrite(t *testing.T) { func TestSourceSymlinkManifest(t *testing.T) { const inputString = ` { - "artifacts": [ - { "id": 1, "pathFragmentId": 1 }], - "actions": [{ - "targetId": 1, - "actionKey": "x", - "mnemonic": "SourceSymlinkManifest", - "configurationId": 1, - "outputIds": [1], - "primaryOutputId": 1, - "executionPlatform": "//build/bazel/platforms:linux_x86_64", - "fileContents": "symlink target\n" - }], - "pathFragments": [ - { "id": 1, "label": "foo.manifest" }] + "artifacts": [ + { "id": 1, "path_fragment_id": 1 }], + "actions": [{ + "target_id": 1, + "action_key": "x", + "mnemonic": "SourceSymlinkManifest", + "configuration_id": 1, + "output_ids": [1], + "primary_output_id": 1, + "execution_platform": "//build/bazel/platforms:linux_x86_64", + "file_contents": "symlink target\n" + }], + "path_fragments": [ + { "id": 1, "label": "foo.manifest" }] } ` - actual, _, err := AqueryBuildStatements([]byte(inputString)) + data, err := JsonToActionGraphContainer(inputString) + if err != nil { + t.Error(err) + return + } + actual, _, err := AqueryBuildStatements(data) if err != nil { t.Errorf("Unexpected error %q", err) } @@ -1011,3 +1111,14 @@ func sortedStrings(stringSlice []string) []string { sort.Strings(sorted) return sorted } + +// Transform the json format to ActionGraphContainer +func JsonToActionGraphContainer(inputString string) ([]byte, error) { + var aqueryProtoResult analysis_v2_proto.ActionGraphContainer + err := json.Unmarshal([]byte(inputString), &aqueryProtoResult) + if err != nil { + return []byte(""), err + } + data, _ := proto.Marshal(&aqueryProtoResult) + return data, err +} diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index fa73fb2a1..febca5df2 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -208,13 +208,16 @@ func (g getApexInfoType) Name() string { // - The function body should not be indented outside of its own scope. func (g getApexInfoType) StarlarkFunctionBody() string { return `info = providers(target)["//build/bazel/rules/apex:apex.bzl%ApexInfo"] +bundle_key_info = info.bundle_key_info +container_key_info = info.container_key_info return json_encode({ "signed_output": info.signed_output.path, "unsigned_output": info.unsigned_output.path, "provides_native_libs": [str(lib) for lib in info.provides_native_libs], "requires_native_libs": [str(lib) for lib in info.requires_native_libs], - "bundle_key_pair": [f.path for f in info.bundle_key_pair], - "container_key_pair": [f.path for f in info.container_key_pair] + "bundle_key_info": [bundle_key_info.public_key.path, bundle_key_info.private_key.path], + "container_key_info": [container_key_info.pem.path, container_key_info.pk8.path, container_key_info.key_name], + "package_name": info.package_name, })` } @@ -223,8 +226,9 @@ type ApexCqueryInfo struct { UnsignedOutput string `json:"unsigned_output"` ProvidesLibs []string `json:"provides_native_libs"` RequiresLibs []string `json:"requires_native_libs"` - BundleKeyPair []string `json:"bundle_key_pair"` - ContainerKeyPair []string `json:"container_key_pair"` + BundleKeyInfo []string `json:"bundle_key_info"` + ContainerKeyInfo []string `json:"container_key_info"` + PackageName string `json:"package_name"` } // ParseResult returns a value obtained by parsing the result of the request's Starlark function. diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go index 0f51cc040..42b42e10e 100644 --- a/bazel/cquery/request_type_test.go +++ b/bazel/cquery/request_type_test.go @@ -145,16 +145,18 @@ func TestGetApexInfoParseResults(t *testing.T) { input: `{"signed_output":"my.apex",` + `"unsigned_output":"my.apex.unsigned",` + `"requires_native_libs":["//bionic/libc:libc","//bionic/libdl:libdl"],` + - `"bundle_key_pair":["foo.pem","foo.privkey"],` + - `"container_key_pair":["foo.x509.pem", "foo.pk8"],` + + `"bundle_key_info":["foo.pem", "foo.privkey"],` + + `"container_key_info":["foo.x509.pem", "foo.pk8", "foo"],` + + `"package_name":"package.name",` + `"provides_native_libs":[]}`, expectedOutput: ApexCqueryInfo{ SignedOutput: "my.apex", UnsignedOutput: "my.apex.unsigned", RequiresLibs: []string{"//bionic/libc:libc", "//bionic/libdl:libdl"}, ProvidesLibs: []string{}, - BundleKeyPair: []string{"foo.pem", "foo.privkey"}, - ContainerKeyPair: []string{"foo.x509.pem", "foo.pk8"}, + BundleKeyInfo: []string{"foo.pem", "foo.privkey"}, + ContainerKeyInfo: []string{"foo.x509.pem", "foo.pk8", "foo"}, + PackageName: "package.name", }, }, } diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go index a666e4994..b6061e46e 100644 --- a/bp2build/apex_conversion_test.go +++ b/bp2build/apex_conversion_test.go @@ -42,6 +42,7 @@ func registerApexModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory) + ctx.RegisterModuleType("cc_test", cc.TestFactory) } func runOverrideApexTestCase(t *testing.T, tc Bp2buildTestCase) { @@ -1249,3 +1250,28 @@ override_apex { }), }}) } + +func TestApexTestBundleSimple(t *testing.T) { + runApexTestCase(t, Bp2buildTestCase{ + Description: "apex_test - simple", + ModuleTypeUnderTest: "apex_test", + ModuleTypeUnderTestFactory: apex.TestApexBundleFactory, + Filesystem: map[string]string{}, + Blueprint: ` +cc_test { name: "cc_test_1", bazel_module: { bp2build_available: false } } + +apex_test { + name: "test_com.android.apogee", + file_contexts: "file_contexts_file", + tests: ["cc_test_1"], +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("apex", "test_com.android.apogee", AttrNameToString{ + "file_contexts": `"file_contexts_file"`, + "manifest": `"apex_manifest.json"`, + "testonly": `True`, + "tests": `[":cc_test_1"]`, + }), + }}) +} diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go index 86f3d423b..c860844d5 100644 --- a/bp2build/java_binary_host_conversion_test.go +++ b/bp2build/java_binary_host_conversion_test.go @@ -29,6 +29,7 @@ func runJavaBinaryHostTestCase(t *testing.T, tc Bp2buildTestCase) { RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory) ctx.RegisterModuleType("java_library", java.LibraryFactory) + ctx.RegisterModuleType("java_import_host", java.ImportFactory) }, tc) } @@ -102,3 +103,34 @@ java_library { }, }) } + +func TestJavaBinaryHostLibs(t *testing.T) { + runJavaBinaryHostTestCase(t, Bp2buildTestCase{ + Description: "java_binary_host with srcs, libs.", + Filesystem: fs, + Blueprint: `java_binary_host { + name: "java-binary-host-libs", + libs: ["java-lib-dep-1"], + manifest: "test.mf", + srcs: ["a.java"], +} + +java_import_host{ + name: "java-lib-dep-1", + jars: ["foo.jar"], + bazel_module: { bp2build_available: false }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{ + "main_class": `"com.android.test.MainClass"`, + "srcs": `["a.java"]`, + "deps": `[":java-lib-dep-1-neverlink"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + }, + }) +} diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go index 05d714240..ac7dfff15 100644 --- a/bp2build/java_import_conversion_test.go +++ b/bp2build/java_import_conversion_test.go @@ -48,6 +48,10 @@ java_import { MakeBazelTarget("java_import", "example_import", AttrNameToString{ "jars": `["import.jar"]`, }), + MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{ + "exports": `[":example_import"]`, + "neverlink": `True`, + }), }}) } @@ -81,5 +85,35 @@ java_import { "//conditions:default": [], })`, }), + MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{ + "exports": `[":example_import"]`, + "neverlink": `True`, + }), + }}) +} + +func TestJavaImportHost(t *testing.T) { + runJavaImportTestCase(t, Bp2buildTestCase{ + Description: "Java import host- simple example", + ModuleTypeUnderTest: "java_import_host", + ModuleTypeUnderTestFactory: java.ImportFactory, + Filesystem: map[string]string{ + "import.jar": "", + }, + Blueprint: ` +java_import_host { + name: "example_import", + jars: ["import.jar"], + bazel_module: { bp2build_available: true }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("java_import", "example_import", AttrNameToString{ + "jars": `["import.jar"]`, + }), + MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{ + "exports": `[":example_import"]`, + "neverlink": `True`, + }), }}) } diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go index 7c39a118b..45817e352 100644 --- a/bp2build/symlink_forest.go +++ b/bp2build/symlink_forest.go @@ -20,8 +20,9 @@ import ( "os" "path/filepath" "regexp" + "sync" + "sync/atomic" - "android/soong/android" "android/soong/shared" ) @@ -31,14 +32,25 @@ import ( // or a directory. If excluded is true, then that file/directory should be // excluded from symlinking. Otherwise, the node is not excluded, but one of its // descendants is (otherwise the node in question would not exist) -type node struct { + +type instructionsNode struct { name string excluded bool // If false, this is just an intermediate node - children map[string]*node + children map[string]*instructionsNode +} + +type symlinkForestContext struct { + verbose bool + topdir string // $TOPDIR + + // State + wg sync.WaitGroup + depCh chan string + okay atomic.Bool // Whether the forest was successfully constructed } // Ensures that the node for the given path exists in the tree and returns it. -func ensureNodeExists(root *node, path string) *node { +func ensureNodeExists(root *instructionsNode, path string) *instructionsNode { if path == "" { return root } @@ -56,15 +68,14 @@ func ensureNodeExists(root *node, path string) *node { if child, ok := dn.children[base]; ok { return child } else { - dn.children[base] = &node{base, false, make(map[string]*node)} + dn.children[base] = &instructionsNode{base, false, make(map[string]*instructionsNode)} return dn.children[base] } } -// Turns a list of paths to be excluded into a tree made of "node" objects where -// the specified paths are marked as excluded. -func treeFromExcludePathList(paths []string) *node { - result := &node{"", false, make(map[string]*node)} +// Turns a list of paths to be excluded into a tree +func instructionsFromExcludePathList(paths []string) *instructionsNode { + result := &instructionsNode{"", false, make(map[string]*instructionsNode)} for _, p := range paths { ensureNodeExists(result, p).excluded = true @@ -179,17 +190,23 @@ func isDir(path string, fi os.FileInfo) bool { // Recursively plants a symlink forest at forestDir. The symlink tree will // contain every file in buildFilesDir and srcDir excluding the files in -// exclude. Collects every directory encountered during the traversal of srcDir -// into acc. -func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir string, buildFilesDir string, srcDir string, exclude *node, acc *[]string, okay *bool) { - if exclude != nil && exclude.excluded { +// instructions. Collects every directory encountered during the traversal of +// srcDir . +func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *instructionsNode, forestDir string, buildFilesDir string, srcDir string) { + defer context.wg.Done() + + if instructions != nil && instructions.excluded { // This directory is not needed, bail out return } - *acc = append(*acc, srcDir) - srcDirMap := readdirToMap(shared.JoinPath(topdir, srcDir)) - buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir)) + // We don't add buildFilesDir here because the bp2build files marker files is + // already a dependency which covers it. If we ever wanted to turn this into + // a generic symlink forest creation tool, we'd need to add it, too. + context.depCh <- srcDir + + srcDirMap := readdirToMap(shared.JoinPath(context.topdir, srcDir)) + buildFilesMap := readdirToMap(shared.JoinPath(context.topdir, buildFilesDir)) renamingBuildFile := false if _, ok := srcDirMap["BUILD"]; ok { @@ -202,16 +219,16 @@ func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir st } } - allEntries := make(map[string]bool) + allEntries := make(map[string]struct{}) for n := range srcDirMap { - allEntries[n] = true + allEntries[n] = struct{}{} } for n := range buildFilesMap { - allEntries[n] = true + allEntries[n] = struct{}{} } - err := os.MkdirAll(shared.JoinPath(topdir, forestDir), 0777) + err := os.MkdirAll(shared.JoinPath(context.topdir, forestDir), 0777) if err != nil { fmt.Fprintf(os.Stderr, "Cannot mkdir '%s': %s\n", forestDir, err) os.Exit(1) @@ -230,84 +247,72 @@ func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir st } buildFilesChild := shared.JoinPath(buildFilesDir, f) - // Descend in the exclusion tree, if there are any excludes left - var excludeChild *node = nil - if exclude != nil { + // Descend in the instruction tree if it exists + var instructionsChild *instructionsNode = nil + if instructions != nil { if f == "BUILD.bazel" && renamingBuildFile { - excludeChild = exclude.children["BUILD"] + instructionsChild = instructions.children["BUILD"] } else { - excludeChild = exclude.children[f] + instructionsChild = instructions.children[f] } } srcChildEntry, sExists := srcDirMap[f] buildFilesChildEntry, bExists := buildFilesMap[f] - if excludeChild != nil && excludeChild.excluded { + if instructionsChild != nil && instructionsChild.excluded { if bExists { - symlinkIntoForest(topdir, forestChild, buildFilesChild) + symlinkIntoForest(context.topdir, forestChild, buildFilesChild) } continue } - sDir := false - bDir := false - if sExists { - sDir = isDir(shared.JoinPath(topdir, srcChild), srcChildEntry) - } - - if bExists { - bDir = isDir(shared.JoinPath(topdir, buildFilesChild), buildFilesChildEntry) - } + sDir := sExists && isDir(shared.JoinPath(context.topdir, srcChild), srcChildEntry) + bDir := bExists && isDir(shared.JoinPath(context.topdir, buildFilesChild), buildFilesChildEntry) if !sExists { - if bDir && excludeChild != nil { + if bDir && instructionsChild != nil { // Not in the source tree, but we have to exclude something from under // this subtree, so descend - plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) + context.wg.Add(1) + go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild) } else { // Not in the source tree, symlink BUILD file - symlinkIntoForest(topdir, forestChild, buildFilesChild) + symlinkIntoForest(context.topdir, forestChild, buildFilesChild) } } else if !bExists { - if sDir && excludeChild != nil { + if sDir && instructionsChild != nil { // Not in the build file tree, but we have to exclude something from // under this subtree, so descend - plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) + context.wg.Add(1) + go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild) } else { // Not in the build file tree, symlink source tree, carry on - symlinkIntoForest(topdir, forestChild, srcChild) + symlinkIntoForest(context.topdir, forestChild, srcChild) } } else if sDir && bDir { // Both are directories. Descend. - plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay) + context.wg.Add(1) + go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild) } else if !sDir && !bDir { // Neither is a directory. Merge them. - srcBuildFile := shared.JoinPath(topdir, srcChild) - generatedBuildFile := shared.JoinPath(topdir, buildFilesChild) - // Add the src and generated build files as dependencies so that bp2build - // is rerun when they change. Currently, this is only really necessary - // for srcBuildFile, because if we regenerate the generated build files - // we will always rerun the symlink forest generation as well. If that - // is later split up into separate, fully dependency-tracing steps, then - // we'll need srcBuildFile as well. Adding srcBuildFile here today - // technically makes it a dependency of bp2build_workspace_marker, which - // also implicitly outputs that file, but since bp2build_workspace_marker - // will always have a newer timestamp than the generatedBuildFile it - // shouldn't be a problem. - *acc = append(*acc, srcBuildFile, generatedBuildFile) - err = mergeBuildFiles(shared.JoinPath(topdir, forestChild), srcBuildFile, generatedBuildFile, cfg.IsEnvTrue("BP2BUILD_VERBOSE")) + srcBuildFile := shared.JoinPath(context.topdir, srcChild) + generatedBuildFile := shared.JoinPath(context.topdir, buildFilesChild) + // The Android.bp file that codegen used to produce `buildFilesChild` is + // already a dependency, we can ignore `buildFilesChild`. + context.depCh <- srcChild + err = mergeBuildFiles(shared.JoinPath(context.topdir, forestChild), srcBuildFile, generatedBuildFile, context.verbose) if err != nil { fmt.Fprintf(os.Stderr, "Error merging %s and %s: %s", srcBuildFile, generatedBuildFile, err) - *okay = false + context.okay.Store(false) } } else { // Both exist and one is a file. This is an error. fmt.Fprintf(os.Stderr, "Conflict in workspace symlink tree creation: both '%s' and '%s' exist and exactly one is a directory\n", srcChild, buildFilesChild) - *okay = false + context.okay.Store(false) } } } @@ -316,14 +321,33 @@ func plantSymlinkForestRecursive(cfg android.Config, topdir string, forestDir st // "srcDir" while excluding paths listed in "exclude". Returns the set of paths // under srcDir on which readdir() had to be called to produce the symlink // forest. -func PlantSymlinkForest(cfg android.Config, topdir string, forest string, buildFiles string, srcDir string, exclude []string) []string { - deps := make([]string, 0) +func PlantSymlinkForest(verbose bool, topdir string, forest string, buildFiles string, exclude []string) []string { + context := &symlinkForestContext{ + verbose: verbose, + topdir: topdir, + depCh: make(chan string), + } + + context.okay.Store(true) + os.RemoveAll(shared.JoinPath(topdir, forest)) - excludeTree := treeFromExcludePathList(exclude) - okay := true - plantSymlinkForestRecursive(cfg, topdir, forest, buildFiles, srcDir, excludeTree, &deps, &okay) - if !okay { + + instructions := instructionsFromExcludePathList(exclude) + go func() { + context.wg.Add(1) + plantSymlinkForestRecursive(context, instructions, forest, buildFiles, ".") + context.wg.Wait() + close(context.depCh) + }() + + deps := make([]string, 0) + for dep := range context.depCh { + deps = append(deps, dep) + } + + if !context.okay.Load() { os.Exit(1) } + return deps } diff --git a/build_test.bash b/build_test.bash index 92819a1bb..eda4bebe1 100755 --- a/build_test.bash +++ b/build_test.bash @@ -48,8 +48,10 @@ source "${TOP}/build/soong/scripts/microfactory.bash" case $(uname) in Linux) - export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so - export SEGFAULT_USE_ALTSTACK=1 + if [[ -f /lib/x86_64-linux-gnu/libSegFault.so ]]; then + export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so + export SEGFAULT_USE_ALTSTACK=1 + fi ulimit -a ;; esac @@ -62,7 +64,7 @@ df -h || true echo echo "Running Bazel smoke test..." -STANDALONE_BAZEL=true "${TOP}/tools/bazel" --batch --max_idle_secs=1 help +STANDALONE_BAZEL=true "${TOP}/build/bazel/bin/bazel" --batch --max_idle_secs=1 help echo echo "Running Soong test..." diff --git a/cc/builder.go b/cc/builder.go index 39f7dc350..75e473669 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -946,12 +946,8 @@ func sourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceD } var errorMessage string - // When error occurs in previous version ABI diff, Developers can't just update ABI - // reference but need to follow instructions to ensure ABI backward compatibility. if previousVersionDiff { - // TODO(b/241496591): Remove -advice-only after b/239792343 and b/239790286 are reolved. - extraFlags = append(extraFlags, "-advice-only") - errorMessage = "error: Please follow development/vndk/tools/header-checker/README.md to ensure the ABI compatibility between your source code and version " + strconv.Itoa(prevVersion) + "." + errorMessage = "error: Please follow https://android.googlesource.com/platform/development/+/master/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + strconv.Itoa(prevVersion) + "." sourceVersion := prevVersion + 1 extraFlags = append(extraFlags, "-target-version", strconv.Itoa(sourceVersion)) } else { @@ -2335,9 +2335,11 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { ctx.ctx = ctx deps := c.deps(ctx) - apiImportInfo := GetApiImports(c, actx) - deps = updateDepsWithApiImports(deps, apiImportInfo) + + if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled { + deps = updateDepsWithApiImports(deps, apiImportInfo) + } c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs @@ -2362,7 +2364,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } // Check header lib replacement from API surface first, and then check again with VSDK - lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs) + if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled { + lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs) + } lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs) if c.isNDKStubLibrary() { diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go index 2d316e671..9f5124bb4 100644 --- a/cc/config/arm64_linux_host.go +++ b/cc/config/arm64_linux_host.go @@ -58,8 +58,8 @@ var ( ) func init() { - pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " ")) - pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " ")) + exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Cflags", linuxCrossCflags) + exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Ldflags", linuxCrossLdflags) } // toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android diff --git a/cc/config/global.go b/cc/config/global.go index e6b945959..cf6041427 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -293,10 +293,8 @@ var ( } llvmNextExtraCommonGlobalCflags = []string{ - // New warnings to be fixed after clang-r468909 - "-Wno-error=array-parameter", // http://b/241941550 - "-Wno-error=deprecated-builtins", // http://b/241601211 - "-Wno-error=deprecated", // in external/googletest/googletest + // New warnings to be fixed after clang-r475365 + "-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903 } IllegalFlags = []string{ diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go index 96a53bff3..e0064717d 100644 --- a/cc/config/x86_linux_bionic_host.go +++ b/cc/config/x86_linux_bionic_host.go @@ -15,8 +15,6 @@ package config import ( - "strings" - "android/soong/android" ) @@ -71,14 +69,13 @@ const ( ) func init() { - - pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " ")) - pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " ")) - pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLdflags, " ")) + exportedVars.ExportStringListStaticVariable("LinuxBionicCflags", linuxBionicCflags) + exportedVars.ExportStringListStaticVariable("LinuxBionicLdflags", linuxBionicLdflags) + exportedVars.ExportStringListStaticVariable("LinuxBionicLldflags", linuxBionicLdflags) // Use the device gcc toolchain for now - pctx.StaticVariable("LinuxBionicGccVersion", x86_64GccVersion) - pctx.SourcePathVariable("LinuxBionicGccRoot", + exportedVars.ExportStringStaticVariable("LinuxBionicGccVersion", x86_64GccVersion) + exportedVars.ExportSourcePathVariable("LinuxBionicGccRoot", "prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${LinuxBionicGccVersion}") } diff --git a/cc/library_stub.go b/cc/library_stub.go index 1283d76e6..760d36ae9 100644 --- a/cc/library_stub.go +++ b/cc/library_stub.go @@ -77,6 +77,19 @@ func (d *apiLibraryDecorator) Name(basename string) string { return basename + multitree.GetApiImportSuffix() } +// Export include dirs without checking for existence. +// The directories are not guaranteed to exist during Soong analysis. +func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) { + exporterProps := d.flagExporter.Properties + for _, dir := range exporterProps.Export_include_dirs { + d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) + } + // system headers + for _, dir := range exporterProps.Export_system_include_dirs { + d.systemDirs = append(d.systemDirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) + } +} + func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path { // Export headers as system include dirs if specified. Mostly for libc if Bool(d.libraryDecorator.Properties.Llndk.Export_headers_as_system) { @@ -87,15 +100,26 @@ func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps } // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared) - d.libraryDecorator.flagExporter.exportIncludes(ctx) + d.exportIncludes(ctx) d.libraryDecorator.reexportDirs(deps.ReexportedDirs...) d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...) d.libraryDecorator.reexportFlags(deps.ReexportedFlags...) d.libraryDecorator.reexportDeps(deps.ReexportedDeps...) d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...) - d.libraryDecorator.flagExporter.setProvider(ctx) - in := android.PathForModuleSrc(ctx, *d.properties.Src) + if d.properties.Src == nil { + ctx.PropertyErrorf("src", "src is a required property") + } + // Skip the existence check of the stub prebuilt file. + // The file is not guaranteed to exist during Soong analysis. + // Build orchestrator will be responsible for creating a connected ninja graph. + in := android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), *d.properties.Src) + + // Make the _compilation_ of rdeps have an order-only dep on cc_api_library.src (an .so file) + // The .so file itself has an order-only dependency on the headers contributed by this library. + // Creating this dependency ensures that the headers are assembled before compilation of rdeps begins. + d.libraryDecorator.reexportDeps(in) + d.libraryDecorator.flagExporter.setProvider(ctx) d.unstrippedOutputFile = in libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix() diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go index 288a34cf7..54b0ba6f0 100644 --- a/cc/library_stub_test.go +++ b/cc/library_stub_test.go @@ -241,3 +241,46 @@ func TestApiHeadersShouldNotReplaceWithoutApiImport(t *testing.T) { android.AssertBoolEquals(t, "original header should be used for original library", true, hasDirectDependency(t, ctx, libfoo, libfooHeader)) android.AssertBoolEquals(t, "Header from API surface should not be used for original library", false, hasDirectDependency(t, ctx, libfoo, libfooHeaderApiImport)) } + +func TestExportDirFromStubLibrary(t *testing.T) { + bp := ` + cc_library { + name: "libfoo", + export_include_dirs: ["source_include_dir"], + export_system_include_dirs: ["source_system_include_dir"], + vendor_available: true, + } + cc_api_library { + name: "libfoo", + export_include_dirs: ["stub_include_dir"], + export_system_include_dirs: ["stub_system_include_dir"], + vendor_available: true, + src: "libfoo.so", + } + api_imports { + name: "api_imports", + shared_libs: [ + "libfoo", + ], + header_libs: [], + } + // vendor binary + cc_binary { + name: "vendorbin", + vendor: true, + srcs: ["vendor.cc"], + shared_libs: ["libfoo"], + } + ` + ctx := prepareForCcTest.RunTestWithBp(t, bp) + vendorCFlags := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"] + android.AssertStringDoesContain(t, "Vendor binary should compile using headers provided by stub", vendorCFlags, "-Istub_include_dir") + android.AssertStringDoesNotContain(t, "Vendor binary should not compile using headers of source", vendorCFlags, "-Isource_include_dir") + android.AssertStringDoesContain(t, "Vendor binary should compile using system headers provided by stub", vendorCFlags, "-isystem stub_system_include_dir") + android.AssertStringDoesNotContain(t, "Vendor binary should not compile using system headers of source", vendorCFlags, "-isystem source_system_include_dir") + + vendorImplicits := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").OrderOnly.Strings() + // Building the stub.so file first assembles its .h files in multi-tree out. + // These header files are required for compiling the other API domain (vendor in this case) + android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so") +} diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go index 7cb8ab720..d8d5e5d75 100644 --- a/cmd/multiproduct_kati/main.go +++ b/cmd/multiproduct_kati/main.go @@ -48,6 +48,10 @@ var incremental = flag.Bool("incremental", false, "run in incremental mode (savi var outDir = flag.String("out", "", "path to store output directories (defaults to tmpdir under $OUT when empty)") var alternateResultDir = flag.Bool("dist", false, "write select results to $DIST_DIR (or <out>/dist when empty)") +var bazelMode = flag.Bool("bazel-mode", false, "use bazel for analysis of certain modules") +var bazelModeStaging = flag.Bool("bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules") +var bazelModeDev = flag.Bool("bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)") + var onlyConfig = flag.Bool("only-config", false, "Only run product config (not Soong or Kati)") var onlySoong = flag.Bool("only-soong", false, "Only run product config and Soong (not Kati)") @@ -214,6 +218,31 @@ func forceAnsiOutput() bool { return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" } +func getBazelArg() string { + count := 0 + str := "" + if *bazelMode { + count++ + str = "--bazel-mode" + } + if *bazelModeStaging { + count++ + str = "--bazel-mode-staging" + } + if *bazelModeDev { + count++ + str = "--bazel-mode-dev" + } + + if count > 1 { + // Can't set more than one + fmt.Errorf("Only one bazel mode is permitted to be set.") + os.Exit(1) + } + + return str +} + func main() { stdio := terminal.StdioImpl{} @@ -472,6 +501,11 @@ func runSoongUiForProduct(mpctx *mpContext, product string) { args = append(args, "--soong-only") } + bazelStr := getBazelArg() + if bazelStr != "" { + args = append(args, bazelStr) + } + cmd := exec.Command(mpctx.SoongUi, args...) cmd.Stdout = consoleLogWriter cmd.Stderr = consoleLogWriter diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 0ba25c884..1f3507db6 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -15,6 +15,7 @@ package main import ( + "bytes" "flag" "fmt" "io/ioutil" @@ -55,6 +56,7 @@ var ( bazelQueryViewDir string bazelApiBp2buildDir string bp2buildMarker string + symlinkForestMarker string cmdlineArgs bootstrap.Args ) @@ -85,9 +87,11 @@ func init() { flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top") flag.StringVar(&bazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top") flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit") + flag.StringVar(&symlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit") flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output") flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file") flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules") + flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules") flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)") // Flags that probably shouldn't be flags of soong_build but we haven't found @@ -128,7 +132,9 @@ func newContext(configuration android.Config) *android.Context { func newConfig(availableEnv map[string]string) android.Config { var buildMode android.SoongBuildMode - if bp2buildMarker != "" { + if symlinkForestMarker != "" { + buildMode = android.SymlinkForest + } else if bp2buildMarker != "" { buildMode = android.Bp2build } else if bazelQueryViewDir != "" { buildMode = android.GenerateQueryView @@ -142,6 +148,8 @@ func newConfig(availableEnv map[string]string) android.Config { buildMode = android.BazelDevMode } else if cmdlineArgs.BazelMode { buildMode = android.BazelProdMode + } else if cmdlineArgs.BazelModeStaging { + buildMode = android.BazelStagingMode } else { buildMode = android.AnalysisNoBazel } @@ -250,11 +258,10 @@ func runApiBp2build(configuration android.Config, extraNinjaDeps []string) strin // Create the symlink forest symlinkDeps := bp2build.PlantSymlinkForest( - configuration, + configuration.IsEnvTrue("BP2BUILD_VERBOSE"), topDir, workspace, bazelApiBp2buildDir, - ".", excludes) ninjaDeps = append(ninjaDeps, symlinkDeps...) @@ -341,7 +348,10 @@ func writeDepFile(outputFile string, eventHandler metrics.EventHandler, ninjaDep // or the actual Soong build for the build.ninja file. Returns the top level // output file of the specific activity. func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string) string { - if configuration.BuildMode == android.Bp2build { + if configuration.BuildMode == android.SymlinkForest { + runSymlinkForestCreation(configuration, extraNinjaDeps) + return symlinkForestMarker + } else if configuration.BuildMode == android.Bp2build { // Run the alternate pipeline of bp2build mutators and singleton to convert // Blueprint to BUILD files before everything else. runBp2Build(configuration, extraNinjaDeps) @@ -475,12 +485,19 @@ func writeUsedEnvironmentFile(configuration android.Config, finalOutputFile stri os.Exit(1) } - err = ioutil.WriteFile(path, data, 0666) - if err != nil { + if preexistingData, err := os.ReadFile(path); err != nil { + if !os.IsNotExist(err) { + fmt.Fprintf(os.Stderr, "error reading used environment file '%s': %s\n", usedEnvFile, err) + os.Exit(1) + } + } else if bytes.Equal(preexistingData, data) { + // used environment file is unchanged + return + } + if err = os.WriteFile(path, data, 0666); err != nil { fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err) os.Exit(1) } - // Touch the output file so that it's not older than the file we just // wrote. We can't write the environment file earlier because one an access // new environment variables while writing it. @@ -588,6 +605,54 @@ func bazelArtifacts() []string { } } +// This could in theory easily be separated into a binary that generically +// merges two directories into a symlink tree. The main obstacle is that this +// function currently depends on both Bazel-specific knowledge (the existence +// of bazel-* symlinks) and configuration (the set of BUILD.bazel files that +// should and should not be kept) +// +// Ideally, bp2build would write a file that contains instructions to the +// symlink tree creation binary. Then the latter would not need to depend on +// the very heavy-weight machinery of soong_build . +func runSymlinkForestCreation(configuration android.Config, extraNinjaDeps []string) { + eventHandler := metrics.EventHandler{} + + var ninjaDeps []string + ninjaDeps = append(ninjaDeps, extraNinjaDeps...) + + generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build") + workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace") + + excludes := bazelArtifacts() + + if outDir[0] != '/' { + excludes = append(excludes, outDir) + } + + existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir) + if err != nil { + fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err) + os.Exit(1) + } + + pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE")) + excludes = append(excludes, pathsToIgnoredBuildFiles...) + excludes = append(excludes, getTemporaryExcludes()...) + + // PlantSymlinkForest() returns all the directories that were readdir()'ed. + // Such a directory SHOULD be added to `ninjaDeps` so that a child directory + // or file created/deleted under it would trigger an update of the symlink + // forest. + eventHandler.Do("symlink_forest", func() { + symlinkForestDeps := bp2build.PlantSymlinkForest( + configuration.IsEnvTrue("BP2BUILD_VERBOSE"), topDir, workspaceRoot, generatedRoot, excludes) + ninjaDeps = append(ninjaDeps, symlinkForestDeps...) + }) + + writeDepFile(symlinkForestMarker, eventHandler, ninjaDeps) + touch(shared.JoinPath(topDir, symlinkForestMarker)) +} + // Run Soong in the bp2build mode. This creates a standalone context that registers // an alternate pipeline of mutators and singletons specifically for generating // Bazel BUILD files instead of Ninja files. @@ -605,21 +670,11 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies()) bp2buildCtx.SetNameInterface(newNameResolver(configuration)) bp2buildCtx.RegisterForBazelConversion() + bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile) var ninjaDeps []string ninjaDeps = append(ninjaDeps, extraNinjaDeps...) - // The bp2build process is a purely functional process that only depends on - // Android.bp files. It must not depend on the values of per-build product - // configurations or variables, since those will generate different BUILD - // files based on how the user has configured their tree. - bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile) - if modulePaths, err := bp2buildCtx.ListModulePaths("."); err != nil { - panic(err) - } else { - ninjaDeps = append(ninjaDeps, modulePaths...) - } - // Run the loading and analysis pipeline to prepare the graph of regular // Modules parsed from Android.bp files, and the BazelTargetModules mapped // from the regular Modules. @@ -639,41 +694,9 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { codegenMetrics = bp2build.Codegen(codegenContext) }) - generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build") - workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace") - - excludes := bazelArtifacts() - - if outDir[0] != '/' { - excludes = append(excludes, outDir) - } - - existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir) - if err != nil { - fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err) - os.Exit(1) - } - - pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE")) - excludes = append(excludes, pathsToIgnoredBuildFiles...) - - excludes = append(excludes, getTemporaryExcludes()...) - - // PlantSymlinkForest() returns all the directories that were readdir()'ed. - // Such a directory SHOULD be added to `ninjaDeps` so that a child directory - // or file created/deleted under it would trigger an update of the symlink - // forest. - eventHandler.Do("symlink_forest", func() { - symlinkForestDeps := bp2build.PlantSymlinkForest( - configuration, topDir, workspaceRoot, generatedRoot, ".", excludes) - ninjaDeps = append(ninjaDeps, symlinkForestDeps...) - }) - ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...) writeDepFile(bp2buildMarker, eventHandler, ninjaDeps) - - // Create an empty bp2build marker file. touch(shared.JoinPath(topDir, bp2buildMarker)) }) diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index b06e4fe73..19166d26e 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -132,8 +132,13 @@ func main() { build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"), build.OsEnvironment().IsEnvTrue("SOONG_UI_ANSI_OUTPUT")) + // Create and start a new metric record. + met := metrics.New() + met.SetBuildDateTime(buildStarted) + met.SetBuildCommand(os.Args) + // Attach a new logger instance to the terminal output. - log := logger.New(output) + log := logger.NewWithMetrics(output, met) defer log.Cleanup() // Create a context to simplify the program termination process. @@ -144,11 +149,6 @@ func main() { trace := tracer.New(log) defer trace.Close() - // Create and start a new metric record. - met := metrics.New() - met.SetBuildDateTime(buildStarted) - met.SetBuildCommand(os.Args) - // Create a new Status instance, which manages action counts and event output channels. stat := &status.Status{} defer stat.Finish() @@ -281,7 +281,7 @@ func dumpVar(ctx build.Context, config build.Config, args []string, _ string) { if flags.NArg() != 1 { flags.Usage() - os.Exit(1) + ctx.Fatalf("Invalid usage") } varName := flags.Arg(0) @@ -341,7 +341,7 @@ func dumpVars(ctx build.Context, config build.Config, args []string, _ string) { if flags.NArg() != 0 { flags.Usage() - os.Exit(1) + ctx.Fatalf("Invalid usage") } vars := strings.Fields(*varsStr) @@ -502,7 +502,7 @@ func runMake(ctx build.Context, config build.Config, _ []string, logsDir string) fmt.Fprintln(writer, "!") fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files") fmt.Fprintln(writer, "") - ctx.Fatal("done") + ctx.Fatal("Invalid argument") } if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok { @@ -513,7 +513,7 @@ func runMake(ctx build.Context, config build.Config, _ []string, logsDir string) fmt.Fprintln(writer, "!") fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...") fmt.Fprintln(writer, "") - ctx.Fatal("done") + ctx.Fatal("Invalid environment") } build.Build(ctx, config) @@ -13,7 +13,12 @@ exclude github.com/golang/protobuf v1.5.0 replace github.com/google/go-cmp v0.5.5 => ../../external/go-cmp -// Indirect dep from go-cmp -exclude golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +require prebuilts/bazel/common/proto/analysis_v2 v0.0.0 + +replace prebuilts/bazel/common/proto/analysis_v2 => ../../prebuilts/bazel/common/proto/analysis_v2 + +require prebuilts/bazel/common/proto/build v0.0.0 // indirect + +replace prebuilts/bazel/common/proto/build => ../../prebuilts/bazel/common/proto/build go 1.18 diff --git a/java/app_import.go b/java/app_import.go index 6e603c912..8c1e19c3e 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -500,7 +500,18 @@ type androidTestImportProperties struct { type AndroidTestImport struct { AndroidAppImport - testProperties testProperties + testProperties struct { + // list of compatibility suites (for example "cts", "vts") that the module should be + // installed into. + Test_suites []string `android:"arch_variant"` + + // list of files or filegroup modules that provide data that should be installed alongside + // the test + Data []string `android:"path"` + + // Install the test into a folder named for the module in all test suites. + Per_testcase_directory *bool + } testImportProperties androidTestImportProperties diff --git a/java/builder.go b/java/builder.go index c0fadd42c..b1b9a4a07 100644 --- a/java/builder.go +++ b/java/builder.go @@ -83,9 +83,9 @@ var ( _ = pctx.VariableFunc("kytheCuJavaSourceMax", func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuJavaSourceMax() }) _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json") - // Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about - // "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ... - // to field java.nio.Buffer.address" + // Run it with several --add-exports to allow the classes in the + // com.google.devtools.kythe.extractors.java.standalone package access the packages in the + // jdk.compiler compiler module. Long live Java modules. kytheExtract = pctx.AndroidStaticRule("kythe", blueprint.RuleParams{ Command: `${config.ZipSyncCmd} -d $srcJarDir ` + @@ -97,7 +97,17 @@ var ( `KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` + `KYTHE_JAVA_SOURCE_BATCH_SIZE=${kytheCuJavaSourceMax} ` + `${config.SoongJavacWrapper} ${config.JavaCmd} ` + + // Avoid JDK9's warning about "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ... + // to field java.nio.Buffer.address" `--add-opens=java.base/java.nio=ALL-UNNAMED ` + + // Allow the classes in the com.google.devtools.kythe.extractors.java.standalone package + // access the packages in the jdk.compiler compiler module + `--add-opens=java.base/java.nio=ALL-UNNAMED ` + + `--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED ` + + `--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED ` + + `--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ` + + `--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ` + + `--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ` + `-jar ${config.JavaKytheExtractorJar} ` + `${config.JavacHeapFlags} ${config.CommonJdkFlags} ` + `$processorpath $processor $javacFlags $bootClasspath $classpath ` + diff --git a/java/java.go b/java/java.go index 5091d26a2..c8bb22fee 100644 --- a/java/java.go +++ b/java/java.go @@ -2384,7 +2384,18 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) } if m.properties.Libs != nil { - deps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Libs)))) + + // TODO 244210934 ALIX Check if this else statement breaks presubmits get rid of it if it doesn't + if strings.HasPrefix(ctx.ModuleType(), "java_binary") { + for _, d := range m.properties.Libs { + neverlinkLabel := android.BazelLabelForModuleDepSingle(ctx, d) + neverlinkLabel.Label = neverlinkLabel.Label + "-neverlink" + deps.Add(&neverlinkLabel) + } + + } else { + deps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Libs)))) + } } if m.properties.Static_libs != nil { @@ -2409,8 +2420,9 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) type javaLibraryAttributes struct { *javaCommonAttributes - Deps bazel.LabelListAttribute - Exports bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Exports bazel.LabelListAttribute + Neverlink bazel.BoolAttribute } func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { @@ -2440,7 +2452,8 @@ func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { Bzl_load_location: "//build/bazel/rules/java:library.bzl", } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) + name := m.Name() + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs) } type javaBinaryHostAttributes struct { @@ -2522,7 +2535,8 @@ func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { } type bazelJavaImportAttributes struct { - Jars bazel.LabelListAttribute + Jars bazel.LabelListAttribute + Exports bazel.LabelListAttribute } // java_import bp2Build converter. @@ -2543,7 +2557,17 @@ func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"} - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: android.RemoveOptionalPrebuiltPrefix(i.Name())}, attrs) + name := android.RemoveOptionalPrebuiltPrefix(i.Name()) + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs) + + neverlink := true + neverlinkAttrs := &javaLibraryAttributes{ + Neverlink: bazel.BoolAttribute{Value: &neverlink}, + Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}), + } + ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{Rule_class: "java_library"}, android.CommonAttributes{Name: name + "-neverlink"}, neverlinkAttrs) + } var _ android.MixedBuildBuildable = (*Import)(nil) diff --git a/java/java_test.go b/java/java_test.go index d2373e349..3b86f9aa4 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1288,6 +1288,8 @@ func TestAidlExportIncludeDirsFromImports(t *testing.T) { } func TestAidlIncludeDirFromConvertedFileGroupWithPathPropInMixedBuilds(t *testing.T) { + // TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups + t.Skip("Re-enable once filegroups are corrected for mixed builds") bp := ` filegroup { name: "foo_aidl", diff --git a/java/lint.go b/java/lint.go index fcd6d31ff..9827159c8 100644 --- a/java/lint.go +++ b/java/lint.go @@ -333,7 +333,7 @@ func (l *linter) lint(ctx android.ModuleContext) { l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...) // Skip lint warning checks for NewApi warnings for libcore where they come from source // files that reference the API they are adding (b/208656169). - if ctx.ModuleDir() != "libcore" { + if !strings.HasPrefix(ctx.ModuleDir(), "libcore") { _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks) if len(filtered) != 0 { diff --git a/java/robolectric.go b/java/robolectric.go index b6116ec9d..2cb07981e 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -65,6 +65,10 @@ type robolectricProperties struct { // The version number of a robolectric prebuilt to use from prebuilts/misc/common/robolectric // instead of the one built from source in external/robolectric-shadows. Robolectric_prebuilt_version *string + + // Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectri + // to use. /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows + Upstream *bool } type robolectricTest struct { @@ -108,7 +112,11 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" { ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v)) } else { - ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib) + if proptools.Bool(r.robolectricProperties.Upstream) { + ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream") + } else { + ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib) + } } ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...) diff --git a/licenses/Android.bp b/licenses/Android.bp index 61b17bf47..2e5c361ed 100644 --- a/licenses/Android.bp +++ b/licenses/Android.bp @@ -839,84 +839,84 @@ license_kind { license_kind { name: "SPDX-license-identifier-LGPL", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], } license_kind { name: "SPDX-license-identifier-LGPL-2.0", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.0.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.0+", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.0+.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.0-only", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.0-only.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.0-or-later", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.0-or-later.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.1", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.1.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.1+", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.1+.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.1-only", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.1-only.html", } license_kind { name: "SPDX-license-identifier-LGPL-2.1-or-later", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-2.1-or-later.html", } license_kind { name: "SPDX-license-identifier-LGPL-3.0", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-3.0.html", } license_kind { name: "SPDX-license-identifier-LGPL-3.0+", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-3.0+.html", } license_kind { name: "SPDX-license-identifier-LGPL-3.0-only", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-3.0-only.html", } license_kind { name: "SPDX-license-identifier-LGPL-3.0-or-later", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPL-3.0-or-later.html", } license_kind { name: "SPDX-license-identifier-LGPLLR", - conditions: ["restricted"], + conditions: ["restricted_allows_dynamic_linking"], url: "https://spdx.org/licenses/LGPLLR.html", } diff --git a/python/Android.bp b/python/Android.bp index 99c02bd28..e49fa6a3c 100644 --- a/python/Android.bp +++ b/python/Android.bp @@ -27,15 +27,3 @@ bootstrap_go_package { ], pluginFor: ["soong_build"], } - -// We're transitioning all of these flags to be true by default. -// This is a defaults flag that can be used to easily add all of them to -// certain modules. -python_defaults { - name: "modern_python_path_defaults", - dont_add_top_level_directories_to_path: true, - dont_add_entrypoint_folder_to_path: true, - proto: { - respect_pkg_path: true, - }, -} diff --git a/python/binary.go b/python/binary.go index 1f49a5476..670e0d313 100644 --- a/python/binary.go +++ b/python/binary.go @@ -116,22 +116,6 @@ type BinaryProperties struct { // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true // explicitly. Auto_gen_config *bool - - // Currently, both the root of the zipfile and all the directories 1 level - // below that are added to the python path. When this flag is set to true, - // only the root of the zipfile will be added to the python path. This flag - // will be removed after all the python modules in the tree have been updated - // to support it. When using embedded_launcher: true, this is already the - // behavior. The default is currently false. - Dont_add_top_level_directories_to_path *bool - - // Setting this to true will mimic Python 3.11+'s PYTHON_SAFE_PATH environment - // variable or -P flag, even on older python versions. This is a temporary - // flag while modules are changed to support it, eventually true will be the - // default and the flag will be removed. The default is currently false. It - // is only applicable when embedded_launcher is false, when embedded_launcher - // is true this is already implied. - Dont_add_entrypoint_folder_to_path *bool } type binaryDecorator struct { @@ -191,14 +175,9 @@ func (binary *binaryDecorator) bootstrap(ctx android.ModuleContext, actualVersio } }) } - - addTopDirectoriesToPath := !proptools.BoolDefault(binary.binaryProperties.Dont_add_top_level_directories_to_path, true) - dontAddEntrypointFolderToPath := proptools.BoolDefault(binary.binaryProperties.Dont_add_entrypoint_folder_to_path, true) - binFile := registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath, binary.getHostInterpreterName(ctx, actualVersion), - main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...), - addTopDirectoriesToPath, dontAddEntrypointFolderToPath) + main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...)) return android.OptionalPathForPath(binFile) } diff --git a/python/builder.go b/python/builder.go index f7f9a9914..b4ab20691 100644 --- a/python/builder.go +++ b/python/builder.go @@ -43,17 +43,7 @@ var ( hostPar = pctx.AndroidStaticRule("hostPar", blueprint.RuleParams{ - Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' -e 's/ADD_TOP_DIRECTORIES_TO_PATH/$addTopDirectoriesToPath/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` + - `echo "#!/usr/bin/env $interp" >${out}.prefix &&` + - `$mergeParCmd -p --prefix ${out}.prefix -pm $out.main $out $srcsZips && ` + - `chmod +x $out && (rm -f $out.main; rm -f ${out}.prefix)`, - CommandDeps: []string{"$mergeParCmd", "build/soong/python/scripts/stub_template_host.txt"}, - }, - "interp", "main", "srcsZips", "addTopDirectoriesToPath") - - hostParWithoutAddingEntrypointFolderToPath = pctx.AndroidStaticRule("hostParWithoutAddingEntrypointFolderToPath", - blueprint.RuleParams{ - Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/__soong_entrypoint_redirector__.py/g' -e 's/ADD_TOP_DIRECTORIES_TO_PATH/$addTopDirectoriesToPath/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` + + Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/__soong_entrypoint_redirector__.py/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` + "sed -e 's/ENTRY_POINT/$main/g' build/soong/python/scripts/main_non_embedded.py >`dirname $out`/__soong_entrypoint_redirector__.py && " + "$parCmd -o $out.entrypoint_zip -C `dirname $out` -f `dirname $out`/__soong_entrypoint_redirector__.py && " + `echo "#!/usr/bin/env $interp" >${out}.prefix &&` + @@ -61,7 +51,7 @@ var ( "chmod +x $out && (rm -f $out.main; rm -f ${out}.prefix; rm -f $out.entrypoint_zip; rm -f `dirname $out`/__soong_entrypoint_redirector__.py)", CommandDeps: []string{"$mergeParCmd", "$parCmd", "build/soong/python/scripts/stub_template_host.txt", "build/soong/python/scripts/main_non_embedded.py"}, }, - "interp", "main", "srcsZips", "addTopDirectoriesToPath") + "interp", "main", "srcsZips") embeddedPar = pctx.AndroidStaticRule("embeddedPar", blueprint.RuleParams{ @@ -92,7 +82,7 @@ func init() { func registerBuildActionForParFile(ctx android.ModuleContext, embeddedLauncher bool, launcherPath android.OptionalPath, interpreter, main, binName string, - srcsZips android.Paths, addTopDirectoriesToPath bool, dontAddEntrypointFolderToPath bool) android.Path { + srcsZips android.Paths) android.Path { // .intermediate output path for bin executable. binFile := android.PathForModuleOut(ctx, binName) @@ -101,37 +91,17 @@ func registerBuildActionForParFile(ctx android.ModuleContext, embeddedLauncher b implicits := srcsZips if !embeddedLauncher { - addDirsString := "False" - if addTopDirectoriesToPath { - addDirsString = "True" - } - if dontAddEntrypointFolderToPath { - ctx.Build(pctx, android.BuildParams{ - Rule: hostParWithoutAddingEntrypointFolderToPath, - Description: "host python archive", - Output: binFile, - Implicits: implicits, - Args: map[string]string{ - "interp": strings.Replace(interpreter, "/", `\/`, -1), - "main": strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1), - "srcsZips": strings.Join(srcsZips.Strings(), " "), - "addTopDirectoriesToPath": addDirsString, - }, - }) - } else { - ctx.Build(pctx, android.BuildParams{ - Rule: hostPar, - Description: "host python archive", - Output: binFile, - Implicits: implicits, - Args: map[string]string{ - "interp": strings.Replace(interpreter, "/", `\/`, -1), - "main": strings.Replace(main, "/", `\/`, -1), - "srcsZips": strings.Join(srcsZips.Strings(), " "), - "addTopDirectoriesToPath": addDirsString, - }, - }) - } + ctx.Build(pctx, android.BuildParams{ + Rule: hostPar, + Description: "host python archive", + Output: binFile, + Implicits: implicits, + Args: map[string]string{ + "interp": strings.Replace(interpreter, "/", `\/`, -1), + "main": strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1), + "srcsZips": strings.Join(srcsZips.Strings(), " "), + }, + }) } else if launcherPath.Valid() { // added launcherPath to the implicits Ninja dependencies. implicits = append(implicits, launcherPath.Path()) diff --git a/python/proto.go b/python/proto.go index 53ebb5895..400e72c99 100644 --- a/python/proto.go +++ b/python/proto.go @@ -18,7 +18,7 @@ import ( "android/soong/android" ) -func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags, pkgPath string) android.Path { +func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path { srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip") outDir := srcsZipFile.ReplaceExtension(ctx, "tmp") @@ -36,9 +36,6 @@ func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.P zipCmd := rule.Command(). BuiltTool("soong_zip"). FlagWithOutput("-o ", srcsZipFile) - if pkgPath != "" { - zipCmd.FlagWithArg("-P ", pkgPath) - } zipCmd.FlagWithArg("-C ", outDir.String()). FlagWithArg("-D ", outDir.String()) diff --git a/python/python.go b/python/python.go index 6f3a0ecf3..24e1bb2ec 100644 --- a/python/python.go +++ b/python/python.go @@ -120,15 +120,6 @@ type BaseProperties struct { // whether the binary is required to be built with embedded launcher for this actual_version. // this is set by the python version mutator based on version-specific properties Embedded_launcher *bool `blueprint:"mutated"` - - Proto struct { - // Whether generated python protos should include the pkg_path in - // their import statements. This is a temporary flag to help transition to - // the new behavior where this is always true. It will be removed after all - // usages of protos with pkg_path have been updated. The default is currently - // false. - Respect_pkg_path *bool - } } type baseAttributes struct { @@ -677,9 +668,7 @@ func (p *Module) createSrcsZip(ctx android.ModuleContext, pkgPath string) androi protoFlags := android.GetProtoFlags(ctx, &p.protoProperties) protoFlags.OutTypeFlag = "--python_out" - protosRespectPkgPath := proptools.BoolDefault(p.properties.Proto.Respect_pkg_path, true) - pkgPathForProtos := pkgPath - if pkgPathForProtos != "" && protosRespectPkgPath { + if pkgPath != "" { pkgPathStagingDir := android.PathForModuleGen(ctx, "protos_staged_for_pkg_path") rule := android.NewRuleBuilder(pctx, ctx) var stagedProtoSrcs android.Paths @@ -691,11 +680,10 @@ func (p *Module) createSrcsZip(ctx android.ModuleContext, pkgPath string) androi } rule.Build("stage_protos_for_pkg_path", "Stage protos for pkg_path") protoSrcs = stagedProtoSrcs - pkgPathForProtos = "" } for _, srcFile := range protoSrcs { - zip := genProto(ctx, srcFile, protoFlags, pkgPathForProtos) + zip := genProto(ctx, srcFile, protoFlags) zips = append(zips, zip) } } diff --git a/python/scripts/stub_template_host.txt b/python/scripts/stub_template_host.txt index a0ddffe82..5eedc180c 100644 --- a/python/scripts/stub_template_host.txt +++ b/python/scripts/stub_template_host.txt @@ -23,16 +23,7 @@ def Main(): zf.extractall(runfiles_path) zf.close() - # Add runfiles path to PYTHONPATH. - python_path_entries = [runfiles_path] - - if ADD_TOP_DIRECTORIES_TO_PATH: - # Add top dirs within runfiles path to PYTHONPATH. - top_entries = [os.path.join(runfiles_path, i) for i in os.listdir(runfiles_path)] - top_pkg_dirs = [i for i in top_entries if os.path.isdir(i)] - python_path_entries += top_pkg_dirs - - new_python_path = ":".join(python_path_entries) + new_python_path = runfiles_path old_python_path = os.environ.get(PYTHON_PATH) if old_python_path: diff --git a/python/tests/dont_import_folder_of_entrypoint/Android.bp b/python/tests/dont_import_folder_of_entrypoint/Android.bp index ea5076e12..e54e9b2c0 100644 --- a/python/tests/dont_import_folder_of_entrypoint/Android.bp +++ b/python/tests/dont_import_folder_of_entrypoint/Android.bp @@ -9,7 +9,6 @@ python_test_host { "mypkg/main.py", "mypkg/mymodule.py", ], - defaults: ["modern_python_path_defaults"], } python_test_host { diff --git a/python/tests/proto_pkg_path/Android.bp b/python/tests/proto_pkg_path/Android.bp index ef7985050..a6bfd3f61 100644 --- a/python/tests/proto_pkg_path/Android.bp +++ b/python/tests/proto_pkg_path/Android.bp @@ -12,6 +12,5 @@ python_test_host { pkg_path: "mylib/subpackage", proto: { canonical_path_from_root: false, - respect_pkg_path: true, }, } diff --git a/python/tests/top_level_dirs/Android.bp b/python/tests/top_level_dirs/Android.bp index fe13d4faa..574350ac9 100644 --- a/python/tests/top_level_dirs/Android.bp +++ b/python/tests/top_level_dirs/Android.bp @@ -9,5 +9,4 @@ python_test_host { "main.py", "mypkg/mymodule.py", ], - dont_add_top_level_directories_to_path: true, } diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh index 61d131b9e..5fbbd0f0b 100755 --- a/tests/apex_comparison_tests.sh +++ b/tests/apex_comparison_tests.sh @@ -34,7 +34,7 @@ SOONG_OUTPUT_DIR="$OUTPUT_DIR/soong" BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel" function call_bazel() { - tools/bazel --output_base="$BAZEL_OUTPUT_DIR" $@ + build/bazel/bin/bazel --output_base="$BAZEL_OUTPUT_DIR" $@ } function cleanup { diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh index e92a561f1..2331eb15b 100755 --- a/tests/bootstrap_test.sh +++ b/tests/bootstrap_test.sh @@ -551,8 +551,45 @@ function test_bp2build_generates_marker_file { run_soong bp2build + if [[ ! -f "./out/soong/bp2build_files_marker" ]]; then + fail "bp2build marker file was not generated" + fi + if [[ ! -f "./out/soong/bp2build_workspace_marker" ]]; then - fail "Marker file was not generated" + fail "symlink forest marker file was not generated" + fi +} + +function test_bp2build_add_irrelevant_file { + setup + + mkdir -p a/b + touch a/b/c.txt + cat > a/b/Android.bp <<'EOF' +filegroup { + name: "c", + srcs: ["c.txt"], + bazel_module: { bp2build_available: true }, +} +EOF + + run_soong bp2build + if [[ ! -e out/soong/bp2build/a/b/BUILD.bazel ]]; then + fail "BUILD file in symlink forest was not created"; + fi + + local mtime1=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel) + + touch a/irrelevant.txt + run_soong bp2build + local mtime2=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel) + + if [[ "$mtime1" != "$mtime2" ]]; then + fail "BUILD.bazel file was regenerated" + fi + + if [[ ! -e "out/soong/workspace/a/irrelevant.txt" ]]; then + fail "New file was not symlinked into symlink forest" fi } @@ -849,6 +886,7 @@ test_bp2build_generates_marker_file test_bp2build_null_build test_bp2build_back_and_forth_null_build test_bp2build_add_android_bp +test_bp2build_add_irrelevant_file test_bp2build_add_to_glob test_bp2build_bazel_workspace_structure test_bp2build_bazel_workspace_add_file diff --git a/tests/lib.sh b/tests/lib.sh index 4b4d9085c..006186ad1 100644 --- a/tests/lib.sh +++ b/tests/lib.sh @@ -85,6 +85,7 @@ function create_mock_soong { copy_directory build/blueprint copy_directory build/soong copy_directory build/make/tools/rbcrun + copy_directory prebuilts/bazel/common/proto symlink_directory prebuilts/sdk symlink_directory prebuilts/go @@ -128,7 +129,6 @@ function create_mock_bazel { symlink_file WORKSPACE symlink_file BUILD - symlink_file tools/bazel } function run_bazel { @@ -136,7 +136,7 @@ function run_bazel { # output should not be parsed as such. rm -rf out/ninja_build - tools/bazel "$@" + build/bazel/bin/bazel "$@" } function run_ninja { diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh index f6fffad4b..076ec4b54 100755 --- a/tests/mixed_mode_test.sh +++ b/tests/mixed_mode_test.sh @@ -19,4 +19,51 @@ function test_bazel_smoke { run_bazel info --config=bp2build } +function test_add_irrelevant_file { + setup + create_mock_bazel + + mkdir -p soong_tests/a/b + touch soong_tests/a/b/c.txt + cat > soong_tests/a/b/Android.bp <<'EOF' +filegroup { + name: "c", + srcs: ["c.txt"], + bazel_module: { bp2build_available: true }, +} +EOF + + run_soong --bazel-mode nothing + + if [[ ! -e out/soong/bp2build/soong_tests/a/b/BUILD.bazel ]]; then + fail "BUILD.bazel not created" + fi + + if [[ ! -e out/soong/build.ninja ]]; then + fail "build.ninja not created" + fi + + local mtime_build1=$(stat -c "%y" out/soong/bp2build/soong_tests/a/b/BUILD.bazel) + local mtime_ninja1=$(stat -c "%y" out/soong/build.ninja) + + touch soong_tests/a/irrelevant.txt + + run_soong --bazel-mode nothing + local mtime_build2=$(stat -c "%y" out/soong/bp2build/soong_tests/a/b/BUILD.bazel) + local mtime_ninja2=$(stat -c "%y" out/soong/build.ninja) + + if [[ "$mtime_build1" != "$mtime_build2" ]]; then + fail "BUILD.bazel was generated" + fi + + if [[ "$mtime_ninja1" != "$mtime_ninja2" ]]; then + fail "build.ninja was regenerated" + fi + + if [[ ! -e out/soong/workspace/soong_tests/a/irrelevant.txt ]]; then + fail "new file was not symlinked" + fi +} + +test_add_irrelevant_file test_bazel_smoke diff --git a/ui/build/bazel.go b/ui/build/bazel.go index 0ebfcd804..bd469a4cd 100644 --- a/ui/build/bazel.go +++ b/ui/build/bazel.go @@ -85,9 +85,9 @@ func runBazel(ctx Context, config Config) { bazelEnv["SHELL"] = "/bin/bash" - // `tools/bazel` is the default entry point for executing Bazel in the AOSP + // `build/bazel/bin/bazel` is the default entry point for executing Bazel in the AOSP // source tree. - bazelExecutable := filepath.Join("tools", "bazel") + bazelExecutable := filepath.Join("build", "bazel", "bin", "bazel") cmd := Command(ctx, config, "bazel", bazelExecutable) // Append custom startup flags to the Bazel command. Startup flags affect diff --git a/ui/build/build.go b/ui/build/build.go index 2022e50bd..b9bd898b4 100644 --- a/ui/build/build.go +++ b/ui/build/build.go @@ -112,9 +112,19 @@ const ( // checkBazelMode fails the build if there are conflicting arguments for which bazel // build mode to use. func checkBazelMode(ctx Context, config Config) { - if config.bazelProdMode && config.bazelDevMode { + count := 0 + if config.bazelProdMode { + count++ + } + if config.bazelDevMode { + count++ + } + if config.bazelStagingMode { + count++ + } + if count > 1 { ctx.Fatalln("Conflicting bazel mode.\n" + - "Do not specify both --bazel-mode and --bazel-mode-dev") + "Do not specify more than one of --bazel-mode and --bazel-mode-dev and --bazel-mode-staging ") } } diff --git a/ui/build/config.go b/ui/build/config.go index f6f5b4657..36119f0f1 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -100,8 +100,9 @@ type configImpl struct { pathReplaced bool - bazelProdMode bool - bazelDevMode bool + bazelProdMode bool + bazelDevMode bool + bazelStagingMode bool // Set by multiproduct_kati emptyNinjaFile bool @@ -463,10 +464,11 @@ func storeConfigMetrics(ctx Context, config Config) { func buildConfig(config Config) *smpb.BuildConfig { c := &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(config.ForceUseGoma()), - UseGoma: proto.Bool(config.UseGoma()), - UseRbe: proto.Bool(config.UseRBE()), - BazelMixedBuild: proto.Bool(config.BazelBuildEnabled()), + ForceUseGoma: proto.Bool(config.ForceUseGoma()), + UseGoma: proto.Bool(config.UseGoma()), + UseRbe: proto.Bool(config.UseRBE()), + BazelMixedBuild: proto.Bool(config.BazelBuildEnabled()), + ForceDisableBazelMixedBuild: proto.Bool(config.IsBazelMixedBuildForceDisabled()), } c.Targets = append(c.Targets, config.arguments...) @@ -721,6 +723,8 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { c.bazelProdMode = true } else if arg == "--bazel-mode-dev" { c.bazelDevMode = true + } else if arg == "--bazel-mode-staging" { + c.bazelStagingMode = true } else if len(arg) > 0 && arg[0] == '-' { parseArgNum := func(def int) int { if len(arg) > 2 { @@ -907,7 +911,11 @@ func (c *configImpl) UsedEnvFile(tag string) string { return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag) } -func (c *configImpl) Bp2BuildMarkerFile() string { +func (c *configImpl) Bp2BuildFilesMarkerFile() string { + return shared.JoinPath(c.SoongOutDir(), "bp2build_files_marker") +} + +func (c *configImpl) Bp2BuildWorkspaceMarkerFile() string { return shared.JoinPath(c.SoongOutDir(), "bp2build_workspace_marker") } @@ -1115,7 +1123,7 @@ func (c *configImpl) UseRBE() bool { } func (c *configImpl) BazelBuildEnabled() bool { - return c.bazelProdMode || c.bazelDevMode + return c.bazelProdMode || c.bazelDevMode || c.bazelStagingMode } func (c *configImpl) StartRBE() bool { @@ -1449,6 +1457,10 @@ func (c *configImpl) EmptyNinjaFile() bool { return c.emptyNinjaFile } +func (c *configImpl) IsBazelMixedBuildForceDisabled() bool { + return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL") +} + func GetMetricsUploader(topDir string, env *Environment) string { if p, ok := env.Get("METRICS_UPLOADER"); ok { metricsUploader := filepath.Join(topDir, p) diff --git a/ui/build/config_test.go b/ui/build/config_test.go index 150ec35dc..968544be7 100644 --- a/ui/build/config_test.go +++ b/ui/build/config_test.go @@ -28,6 +28,7 @@ import ( "android/soong/ui/logger" smpb "android/soong/ui/metrics/metrics_proto" "android/soong/ui/status" + "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" @@ -1008,46 +1009,62 @@ func TestBuildConfig(t *testing.T) { useBazel bool bazelDevMode bool bazelProdMode bool + bazelStagingMode bool expectedBuildConfig *smpb.BuildConfig }{ { name: "none set", environ: Environment{}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(false), + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(false), + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { name: "force use goma", environ: Environment{"FORCE_USE_GOMA=1"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(true), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(false), + ForceUseGoma: proto.Bool(true), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(false), + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { name: "use goma", environ: Environment{"USE_GOMA=1"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(true), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(false), + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(true), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(false), + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { name: "use rbe", environ: Environment{"USE_RBE=1"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(true), - BazelMixedBuild: proto.Bool(false), + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(true), + BazelMixedBuild: proto.Bool(false), + ForceDisableBazelMixedBuild: proto.Bool(false), + }, + }, + { + name: "disable mixed builds", + environ: Environment{"BUILD_BROKEN_DISABLE_BAZEL=1"}, + expectedBuildConfig: &smpb.BuildConfig{ + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(false), + ForceDisableBazelMixedBuild: proto.Bool(true), }, }, { @@ -1055,10 +1072,11 @@ func TestBuildConfig(t *testing.T) { environ: Environment{}, useBazel: true, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(false), + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(false), + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { @@ -1066,10 +1084,11 @@ func TestBuildConfig(t *testing.T) { environ: Environment{}, bazelDevMode: true, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(true), + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(true), + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { @@ -1077,10 +1096,23 @@ func TestBuildConfig(t *testing.T) { environ: Environment{}, bazelProdMode: true, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(true), + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(true), + ForceDisableBazelMixedBuild: proto.Bool(false), + }, + }, + { + name: "bazel mixed build from staging mode", + environ: Environment{}, + bazelStagingMode: true, + expectedBuildConfig: &smpb.BuildConfig{ + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(true), + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { @@ -1089,11 +1121,12 @@ func TestBuildConfig(t *testing.T) { useBazel: true, arguments: []string{"droid", "dist"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), - BazelMixedBuild: proto.Bool(false), - Targets: []string{"droid", "dist"}, + ForceUseGoma: proto.Bool(false), + UseGoma: proto.Bool(false), + UseRbe: proto.Bool(false), + BazelMixedBuild: proto.Bool(false), + Targets: []string{"droid", "dist"}, + ForceDisableBazelMixedBuild: proto.Bool(false), }, }, { @@ -1102,14 +1135,16 @@ func TestBuildConfig(t *testing.T) { "FORCE_USE_GOMA=1", "USE_GOMA=1", "USE_RBE=1", + "BUILD_BROKEN_DISABLE_BAZEL=1", }, useBazel: true, bazelDevMode: true, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(true), - UseGoma: proto.Bool(true), - UseRbe: proto.Bool(true), - BazelMixedBuild: proto.Bool(true), + ForceUseGoma: proto.Bool(true), + UseGoma: proto.Bool(true), + UseRbe: proto.Bool(true), + BazelMixedBuild: proto.Bool(true), + ForceDisableBazelMixedBuild: proto.Bool(true), }, }, } @@ -1118,10 +1153,11 @@ func TestBuildConfig(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { c := &configImpl{ - environ: &tc.environ, - bazelDevMode: tc.bazelDevMode, - bazelProdMode: tc.bazelProdMode, - arguments: tc.arguments, + environ: &tc.environ, + bazelDevMode: tc.bazelDevMode, + bazelProdMode: tc.bazelProdMode, + bazelStagingMode: tc.bazelStagingMode, + arguments: tc.arguments, } config := Config{c} checkBazelMode(ctx, config) diff --git a/ui/build/context.go b/ui/build/context.go index 4a4352cbb..2fef0d0e4 100644 --- a/ui/build/context.go +++ b/ui/build/context.go @@ -48,7 +48,7 @@ func (c ContextImpl) BeginTrace(name, desc string) { c.Tracer.Begin(desc, c.Thread) } if c.Metrics != nil { - c.Metrics.EventTracer.Begin(name, desc, c.Thread) + c.Metrics.EventTracer.Begin(name, desc) } } @@ -58,7 +58,7 @@ func (c ContextImpl) EndTrace() { c.Tracer.End(c.Thread) } if c.Metrics != nil { - c.Metrics.SetTimeMetrics(c.Metrics.EventTracer.End(c.Thread)) + c.Metrics.SetTimeMetrics(c.Metrics.EventTracer.End()) } } diff --git a/ui/build/soong.go b/ui/build/soong.go index 4ec035435..ebf7166f8 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -41,12 +41,13 @@ const ( availableEnvFile = "soong.environment.available" usedEnvFile = "soong.environment.used" - soongBuildTag = "build" - bp2buildTag = "bp2build" - jsonModuleGraphTag = "modulegraph" - queryviewTag = "queryview" - apiBp2buildTag = "api_bp2build" - soongDocsTag = "soong_docs" + soongBuildTag = "build" + bp2buildFilesTag = "bp2build_files" + bp2buildWorkspaceTag = "bp2build_workspace" + jsonModuleGraphTag = "modulegraph" + queryviewTag = "queryview" + apiBp2buildTag = "api_bp2build" + soongDocsTag = "soong_docs" // bootstrapEpoch is used to determine if an incremental build is incompatible with the current // version of bootstrap and needs cleaning before continuing the build. Increment this for @@ -235,7 +236,7 @@ func bootstrapEpochCleanup(ctx Context, config Config) { func bootstrapGlobFileList(config Config) []string { return []string{ config.NamedGlobFile(soongBuildTag), - config.NamedGlobFile(bp2buildTag), + config.NamedGlobFile(bp2buildFilesTag), config.NamedGlobFile(jsonModuleGraphTag), config.NamedGlobFile(queryviewTag), config.NamedGlobFile(apiBp2buildTag), @@ -260,6 +261,9 @@ func bootstrapBlueprint(ctx Context, config Config) { if config.bazelDevMode { mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-dev") } + if config.bazelStagingMode { + mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-staging") + } mainSoongBuildInvocation := primaryBuilderInvocation( config, @@ -273,20 +277,33 @@ func bootstrapBlueprint(ctx Context, config Config) { // Mixed builds call Bazel from soong_build and they therefore need the // Bazel workspace to be available. Make that so by adding a dependency on // the bp2build marker file to the action that invokes soong_build . - mainSoongBuildInvocation.Inputs = append(mainSoongBuildInvocation.Inputs, - config.Bp2BuildMarkerFile()) + mainSoongBuildInvocation.OrderOnlyInputs = append(mainSoongBuildInvocation.OrderOnlyInputs, + config.Bp2BuildWorkspaceMarkerFile()) } bp2buildInvocation := primaryBuilderInvocation( config, - bp2buildTag, - config.Bp2BuildMarkerFile(), + bp2buildFilesTag, + config.Bp2BuildFilesMarkerFile(), []string{ - "--bp2build_marker", config.Bp2BuildMarkerFile(), + "--bp2build_marker", config.Bp2BuildFilesMarkerFile(), }, fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()), ) + bp2buildWorkspaceInvocation := primaryBuilderInvocation( + config, + bp2buildWorkspaceTag, + config.Bp2BuildWorkspaceMarkerFile(), + []string{ + "--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile(), + }, + fmt.Sprintf("Creating Bazel symlink forest"), + ) + + bp2buildWorkspaceInvocation.Inputs = append(bp2buildWorkspaceInvocation.Inputs, + config.Bp2BuildFilesMarkerFile()) + jsonModuleGraphInvocation := primaryBuilderInvocation( config, jsonModuleGraphTag, @@ -358,6 +375,7 @@ func bootstrapBlueprint(ctx Context, config Config) { primaryBuilderInvocations: []bootstrap.PrimaryBuilderInvocation{ mainSoongBuildInvocation, bp2buildInvocation, + bp2buildWorkspaceInvocation, jsonModuleGraphInvocation, queryviewInvocation, apiBp2buildInvocation, @@ -396,7 +414,7 @@ func runSoong(ctx Context, config Config) { soongBuildEnv := config.Environment().Copy() soongBuildEnv.Set("TOP", os.Getenv("TOP")) // For Bazel mixed builds. - soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel") + soongBuildEnv.Set("BAZEL_PATH", "./build/bazel/bin/bazel") // Bazel's HOME var is set to an output subdirectory which doesn't exist. This // prevents Bazel from file I/O in the actual user HOME directory. soongBuildEnv.Set("BAZEL_HOME", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazelhome"))) @@ -423,7 +441,7 @@ func runSoong(ctx Context, config Config) { checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongBuildTag)) if config.BazelBuildEnabled() || config.Bp2Build() { - checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildTag)) + checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildFilesTag)) } if config.JsonModuleGraph() { @@ -494,7 +512,7 @@ func runSoong(ctx Context, config Config) { } if config.Bp2Build() { - targets = append(targets, config.Bp2BuildMarkerFile()) + targets = append(targets, config.Bp2BuildWorkspaceMarkerFile()) } if config.Queryview() { diff --git a/ui/logger/Android.bp b/ui/logger/Android.bp index 269a5a084..7883ea6e5 100644 --- a/ui/logger/Android.bp +++ b/ui/logger/Android.bp @@ -25,4 +25,7 @@ bootstrap_go_package { testSrcs: [ "logger_test.go", ], + deps: [ + "soong-ui-metrics", + ], } diff --git a/ui/logger/logger.go b/ui/logger/logger.go index 9b26ae80a..11852982a 100644 --- a/ui/logger/logger.go +++ b/ui/logger/logger.go @@ -29,6 +29,7 @@ package logger import ( + "android/soong/ui/metrics" "errors" "fmt" "io" @@ -72,8 +73,8 @@ type Logger interface { Output(calldepth int, str string) error } -// fatalLog is the type used when Fatal[f|ln] -type fatalLog struct { +// fatalError is the type used when Fatal[f|ln] +type fatalError struct { error } @@ -127,7 +128,7 @@ func Recover(fn func(err error)) { if p == nil { return - } else if log, ok := p.(fatalLog); ok { + } else if log, ok := p.(fatalError); ok { fn(error(log)) } else { panic(p) @@ -141,6 +142,7 @@ type stdLogger struct { fileLogger *log.Logger mutex sync.Mutex file *os.File + metrics *metrics.Metrics } var _ Logger = &stdLogger{} @@ -149,9 +151,14 @@ var _ Logger = &stdLogger{} // os.Stderr, but it may be a buffer for tests, or a separate log file if // the user doesn't need to see the output. func New(out io.Writer) *stdLogger { + return NewWithMetrics(out, nil) +} + +func NewWithMetrics(out io.Writer, m *metrics.Metrics) *stdLogger { return &stdLogger{ stderr: log.New(out, "", log.Ltime), fileLogger: log.New(ioutil.Discard, "", log.Ldate|log.Lmicroseconds|log.Llongfile), + metrics: m, } } @@ -201,7 +208,7 @@ func (s *stdLogger) Cleanup() { fatal := false p := recover() - if _, ok := p.(fatalLog); ok { + if _, ok := p.(fatalError); ok { fatal = true p = nil } else if p != nil { @@ -217,40 +224,56 @@ func (s *stdLogger) Cleanup() { } } +type verbosityLevel int + +const ( + verboseLog verbosityLevel = iota + infoLog + fatalLog + panicLog +) + // Output writes string to both stderr and the file log. func (s *stdLogger) Output(calldepth int, str string) error { - s.stderr.Output(calldepth+1, str) + return s.output(calldepth, str, infoLog) +} + +// output writes string to stderr, the file log, and if fatal or panic, to metrics. +func (s *stdLogger) output(calldepth int, str string, level verbosityLevel) error { + if level != verboseLog || s.verbose { + s.stderr.Output(calldepth+1, str) + } + if level >= fatalLog { + s.metrics.SetFatalOrPanicMessage(str) + } return s.fileLogger.Output(calldepth+1, str) } // VerboseOutput is equivalent to Output, but only goes to the file log // unless SetVerbose(true) has been called. func (s *stdLogger) VerboseOutput(calldepth int, str string) error { - if s.verbose { - s.stderr.Output(calldepth+1, str) - } - return s.fileLogger.Output(calldepth+1, str) + return s.output(calldepth, str, verboseLog) } // Print prints to both stderr and the file log. // Arguments are handled in the manner of fmt.Print. func (s *stdLogger) Print(v ...interface{}) { output := fmt.Sprint(v...) - s.Output(2, output) + s.output(2, output, infoLog) } // Printf prints to both stderr and the file log. // Arguments are handled in the manner of fmt.Printf. func (s *stdLogger) Printf(format string, v ...interface{}) { output := fmt.Sprintf(format, v...) - s.Output(2, output) + s.output(2, output, infoLog) } // Println prints to both stderr and the file log. // Arguments are handled in the manner of fmt.Println. func (s *stdLogger) Println(v ...interface{}) { output := fmt.Sprintln(v...) - s.Output(2, output) + s.output(2, output, infoLog) } // Verbose is equivalent to Print, but only goes to the file log unless @@ -278,43 +301,43 @@ func (s *stdLogger) Verboseln(v ...interface{}) { // Cleanup will convert to a os.Exit(1). func (s *stdLogger) Fatal(v ...interface{}) { output := fmt.Sprint(v...) - s.Output(2, output) - panic(fatalLog{errors.New(output)}) + s.output(2, output, fatalLog) + panic(fatalError{errors.New(output)}) } // Fatalf is equivalent to Printf() followed by a call to panic() that // Cleanup will convert to a os.Exit(1). func (s *stdLogger) Fatalf(format string, v ...interface{}) { output := fmt.Sprintf(format, v...) - s.Output(2, output) - panic(fatalLog{errors.New(output)}) + s.output(2, output, fatalLog) + panic(fatalError{errors.New(output)}) } // Fatalln is equivalent to Println() followed by a call to panic() that // Cleanup will convert to a os.Exit(1). func (s *stdLogger) Fatalln(v ...interface{}) { output := fmt.Sprintln(v...) - s.Output(2, output) - panic(fatalLog{errors.New(output)}) + s.output(2, output, fatalLog) + panic(fatalError{errors.New(output)}) } // Panic is equivalent to Print() followed by a call to panic(). func (s *stdLogger) Panic(v ...interface{}) { output := fmt.Sprint(v...) - s.Output(2, output) + s.output(2, output, panicLog) panic(output) } // Panicf is equivalent to Printf() followed by a call to panic(). func (s *stdLogger) Panicf(format string, v ...interface{}) { output := fmt.Sprintf(format, v...) - s.Output(2, output) + s.output(2, output, panicLog) panic(output) } // Panicln is equivalent to Println() followed by a call to panic(). func (s *stdLogger) Panicln(v ...interface{}) { output := fmt.Sprintln(v...) - s.Output(2, output) + s.output(2, output, panicLog) panic(output) } diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp index 05db1d753..2301c562f 100644 --- a/ui/metrics/Android.bp +++ b/ui/metrics/Android.bp @@ -25,7 +25,6 @@ bootstrap_go_package { "soong-ui-metrics_upload_proto", "soong-ui-metrics_proto", "soong-ui-mk_metrics_proto", - "soong-ui-tracer", "soong-shared", ], srcs: [ diff --git a/ui/metrics/event.go b/ui/metrics/event.go index ebe664fc6..b3a027ea0 100644 --- a/ui/metrics/event.go +++ b/ui/metrics/event.go @@ -31,7 +31,6 @@ import ( "time" soong_metrics_proto "android/soong/ui/metrics/metrics_proto" - "android/soong/ui/tracer" "google.golang.org/protobuf/proto" ) @@ -50,6 +49,10 @@ type event struct { // for metrics analysis). desc string + nonZeroExitCode bool + + errorMsg *string + // The time that the event started to occur. start time.Time @@ -68,13 +71,18 @@ func newEvent(name, desc string) *event { func (e event) perfInfo() soong_metrics_proto.PerfInfo { realTime := uint64(_now().Sub(e.start).Nanoseconds()) - return soong_metrics_proto.PerfInfo{ + perfInfo := soong_metrics_proto.PerfInfo{ Description: proto.String(e.desc), Name: proto.String(e.name), StartTime: proto.Uint64(uint64(e.start.UnixNano())), RealTime: proto.Uint64(realTime), ProcessesResourceInfo: e.procResInfo, + NonZeroExit: proto.Bool(e.nonZeroExitCode), + } + if m := e.errorMsg; m != nil { + perfInfo.ErrorMessage = proto.String(*m) } + return perfInfo } // EventTracer is an array of events that provides functionality to trace a @@ -94,6 +102,9 @@ func (t *EventTracer) lastIndex() int { // peek returns the active build event. func (t *EventTracer) peek() *event { + if t.empty() { + return nil + } return (*t)[t.lastIndex()] } @@ -137,12 +148,12 @@ func (t *EventTracer) AddProcResInfo(name string, state *os.ProcessState) { } // Begin starts tracing the event. -func (t *EventTracer) Begin(name, desc string, _ tracer.Thread) { +func (t *EventTracer) Begin(name, desc string) { t.push(newEvent(name, desc)) } // End performs post calculations such as duration of the event, aggregates // the collected performance information into PerfInfo protobuf message. -func (t *EventTracer) End(tracer.Thread) soong_metrics_proto.PerfInfo { +func (t *EventTracer) End() soong_metrics_proto.PerfInfo { return t.pop().perfInfo() } diff --git a/ui/metrics/event_test.go b/ui/metrics/event_test.go index 043450bdd..a80e7cff8 100644 --- a/ui/metrics/event_test.go +++ b/ui/metrics/event_test.go @@ -17,8 +17,6 @@ package metrics import ( "testing" "time" - - "android/soong/ui/tracer" ) func TestEnd(t *testing.T) { @@ -35,8 +33,31 @@ func TestEnd(t *testing.T) { start: startTime, }) - perf := et.End(tracer.Thread(0)) + perf := et.End() if perf.GetRealTime() != uint64(dur.Nanoseconds()) { t.Errorf("got %d, want %d nanoseconds for event duration", perf.GetRealTime(), dur.Nanoseconds()) } } + +func TestEndWithError(t *testing.T) { + startTime := time.Date(2020, time.July, 13, 13, 0, 0, 0, time.UTC) + dur := time.Nanosecond * 10 + initialNow := _now + _now = func() time.Time { return startTime.Add(dur) } + defer func() { _now = initialNow }() + + err := "foobar" + et := &EventTracer{} + et.push(&event{ + desc: "test", + name: "test", + start: startTime, + nonZeroExitCode: true, + errorMsg: &err, + }) + + perf := et.End() + if msg := perf.GetErrorMessage(); msg != err { + t.Errorf("got %q, want %q for even error message", msg, err) + } +} diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go index 0c628658a..ce2d94667 100644 --- a/ui/metrics/metrics.go +++ b/ui/metrics/metrics.go @@ -125,6 +125,21 @@ func (m *Metrics) SetTimeMetrics(perf soong_metrics_proto.PerfInfo) { } } +// SetFatalOrPanicMessage stores a non-zero exit and the relevant message in the latest event if +// available or the metrics base. +func (m *Metrics) SetFatalOrPanicMessage(errMsg string) { + if m == nil { + return + } + if event := m.EventTracer.peek(); event != nil { + event.nonZeroExitCode = true + event.errorMsg = &errMsg + } else { + m.metrics.ErrorMessage = proto.String(errMsg) + } + m.metrics.NonZeroExit = proto.Bool(true) +} + // BuildConfig stores information about the build configuration. func (m *Metrics) BuildConfig(b *soong_metrics_proto.BuildConfig) { m.metrics.BuildConfig = b diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go index 2dd829990..90d124b47 100644 --- a/ui/metrics/metrics_proto/metrics.pb.go +++ b/ui/metrics/metrics_proto/metrics.pb.go @@ -338,6 +338,12 @@ type MetricsBase struct { BazelRuns []*PerfInfo `protobuf:"bytes,27,rep,name=bazel_runs,json=bazelRuns" json:"bazel_runs,omitempty"` // The metrics of the experiment config fetcher ExpConfigFetcher *ExpConfigFetcher `protobuf:"bytes,28,opt,name=exp_config_fetcher,json=expConfigFetcher" json:"exp_config_fetcher,omitempty"` + // Whether the build exited with a panic or non-zero exit code, includes both + // non-zero exits of recorded phases and non-recorded phases of the build. + NonZeroExit *bool `protobuf:"varint,29,opt,name=non_zero_exit,json=nonZeroExit" json:"non_zero_exit,omitempty"` + // The error message due to a non-zero exit _only_ if it did not occur in a + // recorded phase of the build. + ErrorMessage *string `protobuf:"bytes,30,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"` } // Default values for MetricsBase fields. @@ -576,6 +582,20 @@ func (x *MetricsBase) GetExpConfigFetcher() *ExpConfigFetcher { return nil } +func (x *MetricsBase) GetNonZeroExit() bool { + if x != nil && x.NonZeroExit != nil { + return *x.NonZeroExit + } + return false +} + +func (x *MetricsBase) GetErrorMessage() string { + if x != nil && x.ErrorMessage != nil { + return *x.ErrorMessage + } + return "" +} + type BuildConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -592,6 +612,8 @@ type BuildConfig struct { // These are the targets soong passes to ninja, these targets include special // targets such as droid as well as the regular build targets. Targets []string `protobuf:"bytes,6,rep,name=targets" json:"targets,omitempty"` + // Whether the user explicitly disabled bazel mixed builds for this build. + ForceDisableBazelMixedBuild *bool `protobuf:"varint,7,opt,name=force_disable_bazel_mixed_build,json=forceDisableBazelMixedBuild" json:"force_disable_bazel_mixed_build,omitempty"` } func (x *BuildConfig) Reset() { @@ -668,6 +690,13 @@ func (x *BuildConfig) GetTargets() []string { return nil } +func (x *BuildConfig) GetForceDisableBazelMixedBuild() bool { + if x != nil && x.ForceDisableBazelMixedBuild != nil { + return *x.ForceDisableBazelMixedBuild + } + return false +} + type SystemResourceInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -746,6 +775,11 @@ type PerfInfo struct { MemoryUse *uint64 `protobuf:"varint,5,opt,name=memory_use,json=memoryUse" json:"memory_use,omitempty"` // The resource information of each executed process. ProcessesResourceInfo []*ProcessResourceInfo `protobuf:"bytes,6,rep,name=processes_resource_info,json=processesResourceInfo" json:"processes_resource_info,omitempty"` + // Whether the phase of tool running exited with a panic or non-zero exit + // code. + NonZeroExit *bool `protobuf:"varint,7,opt,name=non_zero_exit,json=nonZeroExit" json:"non_zero_exit,omitempty"` + // The error message, if any, due to a non-zero exit. + ErrorMessage *string `protobuf:"bytes,8,opt,name=error_message,json=errorMessage" json:"error_message,omitempty"` } func (x *PerfInfo) Reset() { @@ -823,6 +857,20 @@ func (x *PerfInfo) GetProcessesResourceInfo() []*ProcessResourceInfo { return nil } +func (x *PerfInfo) GetNonZeroExit() bool { + if x != nil && x.NonZeroExit != nil { + return *x.NonZeroExit + } + return false +} + +func (x *PerfInfo) GetErrorMessage() string { + if x != nil && x.ErrorMessage != nil { + return *x.ErrorMessage + } + return "" +} + type ProcessResourceInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1361,7 +1409,7 @@ var File_metrics_proto protoreflect.FileDescriptor var file_metrics_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x22, 0xad, 0x0d, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x72, 0x69, 0x63, 0x73, 0x22, 0xf6, 0x0d, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, @@ -1461,152 +1509,166 @@ var file_metrics_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x10, 0x65, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, - 0x63, 0x68, 0x65, 0x72, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, - 0x69, 0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, - 0x0a, 0x09, 0x55, 0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, - 0x03, 0x45, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, - 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, - 0x52, 0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, - 0x07, 0x0a, 0x03, 0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, - 0x36, 0x34, 0x10, 0x04, 0x22, 0xd3, 0x01, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, - 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x52, 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, - 0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, - 0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, - 0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, - 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, - 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, - 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0x81, 0x02, 0x0a, 0x08, - 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, - 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, - 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, - 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, - 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, - 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, - 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, - 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, - 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, - 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, - 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, - 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, - 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, - 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, - 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, - 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, - 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, - 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, - 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, - 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, - 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, - 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, - 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, - 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, - 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, - 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, - 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, - 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, - 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, - 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, - 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, - 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, - 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x63, 0x68, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, + 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, + 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x30, 0x0a, + 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a, + 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x53, 0x45, 0x52, 0x44, + 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e, 0x47, 0x10, 0x02, 0x22, + 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x38, 0x36, 0x10, + 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10, 0x04, 0x22, 0x99, 0x02, + 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, + 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x52, 0x62, + 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67, + 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c, + 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a, + 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d, + 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x66, 0x6f, + 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, + 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, + 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, + 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, + 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, + 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, - 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, - 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, - 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, - 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, - 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, - 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, - 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, - 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, - 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, - 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, - 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, - 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, + 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, + 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, + 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, + 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, + 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, + 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, + 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, + 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, + 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, + 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, + 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, + 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, + 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, + 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, + 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, + 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, + 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, + 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, + 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, + 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, + 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, + 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, + 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, + 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, + 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, + 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, + 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, + 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, + 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, + 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, + 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, + 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, + 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, + 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, + 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, + 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, + 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, + 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28, + 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, + 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto index 4f8fe7f5c..07a7df19a 100644 --- a/ui/metrics/metrics_proto/metrics.proto +++ b/ui/metrics/metrics_proto/metrics.proto @@ -111,6 +111,14 @@ message MetricsBase { // The metrics of the experiment config fetcher optional ExpConfigFetcher exp_config_fetcher = 28; + + // Whether the build exited with a panic or non-zero exit code, includes both + // non-zero exits of recorded phases and non-recorded phases of the build. + optional bool non_zero_exit = 29; + + // The error message due to a non-zero exit _only_ if it did not occur in a + // recorded phase of the build. + optional string error_message = 30; } message BuildConfig { @@ -130,6 +138,9 @@ message BuildConfig { // These are the targets soong passes to ninja, these targets include special // targets such as droid as well as the regular build targets. repeated string targets = 6; + + // Whether the user explicitly disabled bazel mixed builds for this build. + optional bool force_disable_bazel_mixed_build = 7; } message SystemResourceInfo { @@ -160,6 +171,13 @@ message PerfInfo { // The resource information of each executed process. repeated ProcessResourceInfo processes_resource_info = 6; + + // Whether the phase of tool running exited with a panic or non-zero exit + // code. + optional bool non_zero_exit = 7; + + // The error message, if any, due to a non-zero exit. + optional string error_message = 8; } message ProcessResourceInfo { |