Merge "Skip the noop Soong dep edge for api_domain and contributions"
diff --git a/.gitignore b/.gitignore
index 45884c4..5d2bc0d 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 1cc4d54..a1b7dbf 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -272,6 +272,9 @@
"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,
@@ -1336,9 +1339,7 @@
"prebuilt_currysrc_org.eclipse",
}
- 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.
diff --git a/android/arch.go b/android/arch.go
index 75ee922..086e945 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1687,14 +1687,12 @@
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 e829326..c157d39 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -558,7 +558,6 @@
// The actual platform values here may be overridden by configuration
// transitions from the buildroot.
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"),
@@ -927,7 +926,7 @@
//
// 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 dc2261c..c857272 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 @@
"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 @@
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 @@
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 1ed405b..df2c767 100644
--- a/android/config.go
+++ b/android/config.go
@@ -75,6 +75,9 @@
// 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
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index d6b2bcf..2beeb51 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -69,6 +69,7 @@
ret = append(ret, ev.exportedStringListDictVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
// Note: ExportedVariableReferenceDictVars collections can only contain references to other variables and must be printed last
ret = append(ret, ev.exportedVariableReferenceDictVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
+ ret = append(ret, ev.exportedConfigDependingVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
return ret
}
@@ -141,6 +142,33 @@
m[k] = v
}
+func (m ExportedConfigDependingVariables) asBazel(config Config,
+ stringVars ExportedStringVariables, stringListVars ExportedStringListVariables, cfgDepVars ExportedConfigDependingVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ for variable, unevaluatedVar := range m {
+ evalFunc := reflect.ValueOf(unevaluatedVar)
+ validateVariableMethod(variable, evalFunc)
+ evaluatedResult := evalFunc.Call([]reflect.Value{reflect.ValueOf(config)})
+ evaluatedValue := evaluatedResult[0].Interface().(string)
+ expandedVars, err := expandVar(config, evaluatedValue, stringVars, stringListVars, cfgDepVars)
+ if err != nil {
+ panic(fmt.Errorf("error expanding config variable %s: %s", variable, err))
+ }
+ if len(expandedVars) > 1 {
+ ret = append(ret, bazelConstant{
+ variableName: variable,
+ internalDefinition: starlark_fmt.PrintStringList(expandedVars, 0),
+ })
+ } else {
+ ret = append(ret, bazelConstant{
+ variableName: variable,
+ internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVars[0])),
+ })
+ }
+ }
+ return ret
+}
+
// Ensure that string s has no invalid characters to be generated into the bzl file.
func validateCharacters(s string) string {
for _, c := range []string{`\n`, `"`, `\`} {
diff --git a/android/makevars.go b/android/makevars.go
index 5165a55..0800190 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -471,7 +471,7 @@
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 @@
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 5aecb05..b41a898 100644
--- a/android/module.go
+++ b/android/module.go
@@ -928,6 +928,8 @@
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 cf149b2..d288439 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -69,6 +69,7 @@
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.")
}
diff --git a/apex/apex.go b/apex/apex.go
index 88a057f..b039d0d 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 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 @@
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 @@
// 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 @@
Compressible bazel.BoolAttribute
Package_name *string
Logging_parent *string
+ Tests bazel.LabelListAttribute
}
type convertedNativeSharedLibs struct {
@@ -3368,13 +3370,19 @@
// 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 @@
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 @@
Compressible: compressibleAttribute,
Package_name: packageName,
Logging_parent: loggingParent,
+ Tests: testsAttrs,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/bazel/Android.bp b/bazel/Android.bp
index 9e7edc7..d11c78b 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -20,6 +20,7 @@
"soong_build",
],
deps: [
+ "bazel_analysis_v2_proto",
"blueprint",
],
}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 05f6ed4..bc823b3 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,7 +17,6 @@
import (
"crypto/sha256"
"encoding/base64"
- "encoding/json"
"fmt"
"path/filepath"
"reflect"
@@ -25,6 +24,8 @@
"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 @@
// 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 5810364..2eacafa 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 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 @@
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 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 @@
// 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 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 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 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 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 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 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 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 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 @@
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 fa73fb2..febca5d 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -208,13 +208,16 @@
// - 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 @@
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 0f51cc0..42b42e1 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -145,16 +145,18 @@
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 a666e49..b6061e4 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -42,6 +42,7 @@
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 @@
}),
}})
}
+
+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/bp2build.go b/bp2build/bp2build.go
index 0e3d2a5..a75a84e 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -26,7 +26,7 @@
// Codegen is the backend of bp2build. The code generator is responsible for
// writing .bzl files that are equivalent to Android.bp files that are capable
// of being built with Bazel.
-func Codegen(ctx *CodegenContext) CodegenMetrics {
+func Codegen(ctx *CodegenContext) *CodegenMetrics {
// This directory stores BUILD files that could be eventually checked-in.
bp2buildDir := android.PathForOutput(ctx, "bp2build")
if err := android.RemoveAllOutputDir(bp2buildDir); err != nil {
@@ -48,7 +48,7 @@
soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(ctx.Config(), res.metrics))
- return res.metrics
+ return &res.metrics
}
// Get the output directory and create it if it doesn't exist.
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 82ce115..a06b89e 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -28,7 +28,6 @@
"android/soong/android"
"android/soong/bazel"
"android/soong/starlark_fmt"
-
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -245,12 +244,7 @@
buildFileToTargets := make(map[string]BazelTargets)
// Simple metrics tracking for bp2build
- metrics := CodegenMetrics{
- ruleClassCount: make(map[string]uint64),
- convertedModulePathMap: make(map[string]string),
- convertedModuleTypeCount: make(map[string]uint64),
- totalModuleTypeCount: make(map[string]uint64),
- }
+ metrics := CreateCodegenMetrics()
dirs := make(map[string]bool)
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 4d8b8a4..8ca13b8 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -32,7 +32,7 @@
files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
files = append(files, newFile("apex_toolchain", "constants.bzl", apex.BazelApexToolchainVars()))
- files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
+ files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.Serialize().ConvertedModules, "\n")))
convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
if err != nil {
@@ -55,10 +55,6 @@
return files
}
-func convertedModules(convertedModules []string) string {
- return strings.Join(convertedModules, "\n")
-}
-
func CreateBazelFiles(
cfg android.Config,
ruleShims map[string]RuleShim,
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index b696a98..cfd6128 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -84,7 +84,7 @@
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
- files := CreateSoongInjectionFiles(testConfig, CodegenMetrics{})
+ files := CreateSoongInjectionFiles(testConfig, CreateCodegenMetrics())
expectedFilePaths := []bazelFilepath{
{
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 86f3d42..c860844 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -29,6 +29,7 @@
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 @@
},
})
}
+
+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 05d7142..ac7dfff 100644
--- a/bp2build/java_import_conversion_test.go
+++ b/bp2build/java_import_conversion_test.go
@@ -48,6 +48,10 @@
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 @@
"//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/metrics.go b/bp2build/metrics.go
index 0b45996..bd21629 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -9,25 +9,16 @@
"android/soong/android"
"android/soong/shared"
"android/soong/ui/metrics/bp2build_metrics_proto"
+ "google.golang.org/protobuf/proto"
"github.com/google/blueprint"
)
-// Simple metrics struct to collect information about a Blueprint to BUILD
+// CodegenMetrics represents information about the Blueprint-to-BUILD
// conversion process.
+// Use CreateCodegenMetrics() to get a properly initialized instance
type CodegenMetrics struct {
- // Total number of Soong modules converted to generated targets
- generatedModuleCount uint64
-
- // Total number of Soong modules converted to handcrafted targets
- handCraftedModuleCount uint64
-
- // Total number of unconverted Soong modules
- unconvertedModuleCount uint64
-
- // Counts of generated Bazel targets per Bazel rule class
- ruleClassCount map[string]uint64
-
+ serialized *bp2build_metrics_proto.Bp2BuildMetrics
// List of modules with unconverted deps
// NOTE: NOT in the .proto
moduleWithUnconvertedDepsMsgs []string
@@ -36,40 +27,32 @@
// NOTE: NOT in the .proto
moduleWithMissingDepsMsgs []string
- // List of converted modules
- convertedModules []string
-
// Map of converted modules and paths to call
+ // NOTE: NOT in the .proto
convertedModulePathMap map[string]string
+}
- // Counts of converted modules by module type.
- convertedModuleTypeCount map[string]uint64
-
- // Counts of total modules by module type.
- totalModuleTypeCount map[string]uint64
-
- Events []*bp2build_metrics_proto.Event
+func CreateCodegenMetrics() CodegenMetrics {
+ return CodegenMetrics{
+ serialized: &bp2build_metrics_proto.Bp2BuildMetrics{
+ RuleClassCount: make(map[string]uint64),
+ ConvertedModuleTypeCount: make(map[string]uint64),
+ TotalModuleTypeCount: make(map[string]uint64),
+ },
+ convertedModulePathMap: make(map[string]string),
+ }
}
// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
-func (metrics *CodegenMetrics) Serialize() bp2build_metrics_proto.Bp2BuildMetrics {
- return bp2build_metrics_proto.Bp2BuildMetrics{
- GeneratedModuleCount: metrics.generatedModuleCount,
- HandCraftedModuleCount: metrics.handCraftedModuleCount,
- UnconvertedModuleCount: metrics.unconvertedModuleCount,
- RuleClassCount: metrics.ruleClassCount,
- ConvertedModules: metrics.convertedModules,
- ConvertedModuleTypeCount: metrics.convertedModuleTypeCount,
- TotalModuleTypeCount: metrics.totalModuleTypeCount,
- Events: metrics.Events,
- }
+func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetrics {
+ return metrics.serialized
}
// Print the codegen metrics to stdout.
func (metrics *CodegenMetrics) Print() {
generatedTargetCount := uint64(0)
- for _, ruleClass := range android.SortedStringKeys(metrics.ruleClassCount) {
- count := metrics.ruleClassCount[ruleClass]
+ for _, ruleClass := range android.SortedStringKeys(metrics.serialized.RuleClassCount) {
+ count := metrics.serialized.RuleClassCount[ruleClass]
fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
generatedTargetCount += count
}
@@ -80,9 +63,9 @@
%d converted modules have missing deps:
%s
`,
- metrics.generatedModuleCount,
+ metrics.serialized.GeneratedModuleCount,
generatedTargetCount,
- metrics.handCraftedModuleCount,
+ metrics.serialized.HandCraftedModuleCount,
metrics.TotalModuleCount(),
len(metrics.moduleWithUnconvertedDepsMsgs),
strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
@@ -119,29 +102,67 @@
fail(err, "Error outputting %s", metricsFile)
}
if _, err := os.Stat(metricsFile); err != nil {
- fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile)
+ if os.IsNotExist(err) {
+ fail(err, "MISSING BP2BUILD METRICS OUTPUT: %s", metricsFile)
+ } else {
+ fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
+ }
+ }
+}
+
+// ReadCodegenMetrics loads CodegenMetrics from `dir`
+// returns a nil pointer if the file doesn't exist
+func ReadCodegenMetrics(dir string) *CodegenMetrics {
+ metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
+ if _, err := os.Stat(metricsFile); err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ } else {
+ fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
+ panic("unreachable after fail")
+ }
+ }
+ if buf, err := os.ReadFile(metricsFile); err != nil {
+ fail(err, "FAILED TO READ BP2BUILD METRICS OUTPUT: %s", metricsFile)
+ panic("unreachable after fail")
+ } else {
+ bp2BuildMetrics := bp2build_metrics_proto.Bp2BuildMetrics{
+ RuleClassCount: make(map[string]uint64),
+ ConvertedModuleTypeCount: make(map[string]uint64),
+ TotalModuleTypeCount: make(map[string]uint64),
+ }
+ if err := proto.Unmarshal(buf, &bp2BuildMetrics); err != nil {
+ fail(err, "FAILED TO PARSE BP2BUILD METRICS OUTPUT: %s", metricsFile)
+ }
+ return &CodegenMetrics{
+ serialized: &bp2BuildMetrics,
+ convertedModulePathMap: make(map[string]string),
+ }
}
}
func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
- metrics.ruleClassCount[ruleClass] += 1
+ metrics.serialized.RuleClassCount[ruleClass] += 1
}
+func (metrics *CodegenMetrics) AddEvent(event *bp2build_metrics_proto.Event) {
+ metrics.serialized.Events = append(metrics.serialized.Events, event)
+}
func (metrics *CodegenMetrics) AddUnconvertedModule(moduleType string) {
- metrics.unconvertedModuleCount += 1
- metrics.totalModuleTypeCount[moduleType] += 1
+ metrics.serialized.UnconvertedModuleCount += 1
+ metrics.serialized.TotalModuleTypeCount[moduleType] += 1
}
func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
- return metrics.handCraftedModuleCount +
- metrics.generatedModuleCount +
- metrics.unconvertedModuleCount
+ return metrics.serialized.HandCraftedModuleCount +
+ metrics.serialized.GeneratedModuleCount +
+ metrics.serialized.UnconvertedModuleCount
}
// Dump serializes the metrics to the given filename
func (metrics *CodegenMetrics) dump(filename string) (err error) {
ser := metrics.Serialize()
- return shared.Save(&ser, filename)
+ return shared.Save(ser, filename)
}
type ConversionType int
@@ -154,14 +175,14 @@
func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string, conversionType ConversionType) {
// Undo prebuilt_ module name prefix modifications
moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
- metrics.convertedModules = append(metrics.convertedModules, moduleName)
+ metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
metrics.convertedModulePathMap[moduleName] = "//" + dir
- metrics.convertedModuleTypeCount[moduleType] += 1
- metrics.totalModuleTypeCount[moduleType] += 1
+ metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
+ metrics.serialized.TotalModuleTypeCount[moduleType] += 1
if conversionType == Handcrafted {
- metrics.handCraftedModuleCount += 1
+ metrics.serialized.HandCraftedModuleCount += 1
} else if conversionType == Generated {
- metrics.generatedModuleCount += 1
+ metrics.serialized.GeneratedModuleCount += 1
}
}
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 092b240..45817e3 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -20,8 +20,9 @@
"os"
"path/filepath"
"regexp"
+ "sync"
+ "sync/atomic"
- "android/soong/android"
"android/soong/shared"
)
@@ -31,14 +32,25 @@
// 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 @@
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 @@
// 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 {
@@ -211,7 +228,7 @@
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,69 +247,72 @@
}
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 := sExists && isDir(shared.JoinPath(topdir, srcChild), srcChildEntry)
- bDir := bExists && 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)
+ 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`.
- *acc = append(*acc, srcChild)
- err = mergeBuildFiles(shared.JoinPath(topdir, forestChild), srcBuildFile, generatedBuildFile, cfg.IsEnvTrue("BP2BUILD_VERBOSE"))
+ 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)
}
}
}
@@ -301,14 +321,33 @@
// "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 ae53c14..eda4beb 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -48,8 +48,10 @@
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
diff --git a/cc/binary.go b/cc/binary.go
index a6d7507..d09e744 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -646,6 +646,8 @@
sdkAttributes: bp2BuildParseSdkAttributes(m),
}
+ m.convertTidyAttributes(&attrs.tidyAttributes)
+
return attrs
}
@@ -698,4 +700,6 @@
Features bazel.StringListAttribute
sdkAttributes
+
+ tidyAttributes
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index d6d052f..2f79cae 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -66,6 +66,26 @@
Native_coverage bazel.BoolAttribute
sdkAttributes
+
+ tidyAttributes
+}
+
+type tidyAttributes struct {
+ Tidy *bool
+ Tidy_flags []string
+ Tidy_checks []string
+ Tidy_checks_as_errors []string
+}
+
+func (m *Module) convertTidyAttributes(moduleAttrs *tidyAttributes) {
+ for _, f := range m.features {
+ if tidy, ok := f.(*tidyFeature); ok {
+ moduleAttrs.Tidy = tidy.Properties.Tidy
+ moduleAttrs.Tidy_flags = tidy.Properties.Tidy_flags
+ moduleAttrs.Tidy_checks = tidy.Properties.Tidy_checks
+ moduleAttrs.Tidy_checks_as_errors = tidy.Properties.Tidy_checks_as_errors
+ }
+ }
}
// groupSrcsByExtension partitions `srcs` into groups based on file extension.
diff --git a/cc/builder.go b/cc/builder.go
index 39f7dc3..75e4736 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -946,12 +946,8 @@
}
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 {
diff --git a/cc/config/global.go b/cc/config/global.go
index e6b9459..cf60414 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -293,10 +293,8 @@
}
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/tidy.go b/cc/config/tidy.go
index ad205cf..f32ebf2 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -61,8 +61,8 @@
// The global default tidy checks should include clang-tidy
// default checks and tested groups, but exclude known noisy checks.
// See https://clang.llvm.org/extra/clang-tidy/checks/list.html
- pctx.VariableFunc("TidyDefaultGlobalChecks", func(ctx android.PackageVarContext) string {
- if override := ctx.Config().Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
+ exportedVars.ExportVariableConfigMethod("TidyDefaultGlobalChecks", func(config android.Config) string {
+ if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
return override
}
checks := strings.Join([]string{
@@ -110,7 +110,7 @@
// limit clang-tidy runtime. We allow clang-tidy default clang-analyzer-* checks,
// and add it explicitly when CLANG_ANALYZER_CHECKS is set.
// The insecureAPI.DeprecatedOrUnsafeBufferHandling warning does not apply to Android.
- if ctx.Config().IsEnvTrue("CLANG_ANALYZER_CHECKS") {
+ if config.IsEnvTrue("CLANG_ANALYZER_CHECKS") {
checks += ",clang-analyzer-*,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
} else {
checks += ",-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
@@ -123,8 +123,8 @@
// There are too many clang-tidy warnings in external and vendor projects, so we only
// enable some google checks for these projects. Users can add more checks locally with the
// "tidy_checks" list in .bp files, or the "Checks" list in .clang-tidy config files.
- pctx.VariableFunc("TidyExternalVendorChecks", func(ctx android.PackageVarContext) string {
- if override := ctx.Config().Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
+ exportedVars.ExportVariableConfigMethod("TidyExternalVendorChecks", func(config android.Config) string {
+ if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
return override
}
return strings.Join([]string{
@@ -137,24 +137,24 @@
}, ",")
})
- pctx.VariableFunc("TidyGlobalNoChecks", func(ctx android.PackageVarContext) string {
+ exportedVars.ExportVariableFuncVariable("TidyGlobalNoChecks", func() string {
return strings.Join(globalNoCheckList, ",")
})
- pctx.VariableFunc("TidyGlobalNoErrorChecks", func(ctx android.PackageVarContext) string {
+ exportedVars.ExportVariableFuncVariable("TidyGlobalNoErrorChecks", func() string {
return strings.Join(globalNoErrorCheckList, ",")
})
// To reduce duplicate warnings from the same header files,
// header-filter will contain only the module directory and
// those specified by DEFAULT_TIDY_HEADER_DIRS.
- pctx.VariableFunc("TidyDefaultHeaderDirs", func(ctx android.PackageVarContext) string {
- return ctx.Config().Getenv("DEFAULT_TIDY_HEADER_DIRS")
+ exportedVars.ExportVariableConfigMethod("TidyDefaultHeaderDirs", func(config android.Config) string {
+ return config.Getenv("DEFAULT_TIDY_HEADER_DIRS")
})
// Use WTIH_TIDY_FLAGS to pass extra global default clang-tidy flags.
- pctx.VariableFunc("TidyWithTidyFlags", func(ctx android.PackageVarContext) string {
- return ctx.Config().Getenv("WITH_TIDY_FLAGS")
+ exportedVars.ExportVariableConfigMethod("TidyWithTidyFlags", func(config android.Config) string {
+ return config.Getenv("WITH_TIDY_FLAGS")
})
}
diff --git a/cc/library.go b/cc/library.go
index a590b22..41a68e3 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -2791,6 +2791,8 @@
Runtime_deps: linkerAttrs.runtimeDeps,
}
+ module.convertTidyAttributes(&commonAttrs.tidyAttributes)
+
var attrs interface{}
if isStatic {
commonAttrs.Deps.Add(baseAttributes.protoDependency)
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 1b02330..760d36a 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -106,7 +106,6 @@
d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
- d.libraryDecorator.flagExporter.setProvider(ctx)
if d.properties.Src == nil {
ctx.PropertyErrorf("src", "src is a required property")
@@ -116,6 +115,12 @@
// 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 5cb4e61..54b0ba6 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -278,4 +278,9 @@
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/cc/test.go b/cc/test.go
index 715c537..92055fa 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -643,6 +643,8 @@
Gtest bool
Isolated bool
+
+ tidyAttributes
}
// testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's
@@ -676,6 +678,8 @@
}
}
+ m.convertTidyAttributes(&testBinaryAttrs.tidyAttributes)
+
for _, propIntf := range m.GetProperties() {
if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok {
testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true)
diff --git a/cc/tidy.go b/cc/tidy.go
index 810d089..a3d548b 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -68,6 +68,7 @@
// Then, that old style usage will be obsolete and an error.
const NoWarningsAsErrorsInTidyFlags = true
+// keep this up to date with https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/clang_tidy.bzl
func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 7cb8ab7..d8d5e5d 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -48,6 +48,10 @@
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 @@
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 @@
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 87710c0..1e356e5 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -56,6 +56,7 @@
bazelQueryViewDir string
bazelApiBp2buildDir string
bp2buildMarker string
+ symlinkForestMarker string
cmdlineArgs bootstrap.Args
)
@@ -86,6 +87,7 @@
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")
@@ -130,7 +132,9 @@
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
@@ -254,11 +258,10 @@
// Create the symlink forest
symlinkDeps := bp2build.PlantSymlinkForest(
- configuration,
+ configuration.IsEnvTrue("BP2BUILD_VERBOSE"),
topDir,
workspace,
bazelApiBp2buildDir,
- ".",
excludes)
ninjaDeps = append(ninjaDeps, symlinkDeps...)
@@ -345,7 +348,10 @@
// 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)
@@ -519,12 +525,6 @@
}
}
-func touchIfDoesNotExist(path string) {
- if _, err := os.Stat(path); os.IsNotExist(err) {
- touch(path)
- }
-}
-
// Find BUILD files in the srcDir which are not in the allowlist
// (android.Bp2BuildConversionAllowlist#ShouldKeepExistingBuildFileForDir)
// and return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
@@ -605,11 +605,69 @@
}
}
+// 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))
+ metricsDir := configuration.Getenv("LOG_DIR")
+ codegenMetrics := bp2build.ReadCodegenMetrics(metricsDir)
+ if codegenMetrics == nil {
+ m := bp2build.CreateCodegenMetrics()
+ codegenMetrics = &m
+ } else {
+ //TODO (usta) we cannot determine if we loaded a stale file, i.e. from an unrelated prior
+ //invocation of codegen. We should simply use a separate .pb file
+ }
+ writeBp2BuildMetrics(codegenMetrics, configuration, eventHandler)
+}
+
// 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.
func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
- var codegenMetrics bp2build.CodegenMetrics
+ var codegenMetrics *bp2build.CodegenMetrics
eventHandler := metrics.EventHandler{}
eventHandler.Do("bp2build", func() {
@@ -646,43 +704,10 @@
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, if it does not already exist.
- // Note the relevant rule has `restat = true`
- touchIfDoesNotExist(shared.JoinPath(topDir, bp2buildMarker))
+ touch(shared.JoinPath(topDir, bp2buildMarker))
})
// Only report metrics when in bp2build mode. The metrics aren't relevant
@@ -691,19 +716,18 @@
if configuration.IsEnvTrue("BP2BUILD_VERBOSE") {
codegenMetrics.Print()
}
- writeBp2BuildMetrics(&codegenMetrics, configuration, eventHandler)
+ writeBp2BuildMetrics(codegenMetrics, configuration, eventHandler)
}
// Write Bp2Build metrics into $LOG_DIR
func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics,
configuration android.Config, eventHandler metrics.EventHandler) {
for _, event := range eventHandler.CompletedEvents() {
- codegenMetrics.Events = append(codegenMetrics.Events,
- &bp2build_metrics_proto.Event{
- Name: event.Id,
- StartTime: uint64(event.Start.UnixNano()),
- RealTime: event.RuntimeNanoseconds(),
- })
+ codegenMetrics.AddEvent(&bp2build_metrics_proto.Event{
+ Name: event.Id,
+ StartTime: uint64(event.Start.UnixNano()),
+ RealTime: event.RuntimeNanoseconds(),
+ })
}
metricsDir := configuration.Getenv("LOG_DIR")
if len(metricsDir) < 1 {
diff --git a/go.mod b/go.mod
index 8c1a9f0..5f0b91a 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,12 @@
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 6e603c9..8c1e19c 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -500,7 +500,18 @@
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/dexpreopt_test.go b/java/dexpreopt_test.go
index 1c1070a..3d2c5c3 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -63,6 +63,7 @@
java_binary {
name: "foo",
srcs: ["a.java"],
+ main_class: "foo.bar.jb",
}`,
enabled: true,
},
diff --git a/java/java.go b/java/java.go
index 5091d26..56a5b38 100644
--- a/java/java.go
+++ b/java/java.go
@@ -211,6 +211,14 @@
PropertyName: "java_tests",
},
}
+
+ // Rule for generating device binary default wrapper
+ deviceBinaryWrapper = pctx.StaticRule("deviceBinaryWrapper", blueprint.RuleParams{
+ Command: `echo -e '#!/system/bin/sh\n` +
+ `export CLASSPATH=/system/framework/$jar_name\n` +
+ `exec app_process /$partition/bin $main_class "$$@"'> ${out}`,
+ Description: "Generating device binary wrapper ${jar_name}",
+ }, "jar_name", "partition", "main_class")
)
// JavaInfo contains information about a java module for use by modules that depend on it.
@@ -1398,7 +1406,31 @@
ctx.PropertyErrorf("wrapper", "wrapper is required for Windows")
}
- j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+ if ctx.Device() {
+ // device binary should have a main_class property if it does not
+ // have a specific wrapper, so that a default wrapper can
+ // be generated for it.
+ if j.binaryProperties.Main_class == nil {
+ ctx.PropertyErrorf("main_class", "main_class property "+
+ "is required for device binary if no default wrapper is assigned")
+ } else {
+ wrapper := android.PathForModuleOut(ctx, ctx.ModuleName()+".sh")
+ jarName := j.Stem() + ".jar"
+ partition := j.PartitionTag(ctx.DeviceConfig())
+ ctx.Build(pctx, android.BuildParams{
+ Rule: deviceBinaryWrapper,
+ Output: wrapper,
+ Args: map[string]string{
+ "jar_name": jarName,
+ "partition": partition,
+ "main_class": String(j.binaryProperties.Main_class),
+ },
+ })
+ j.wrapperFile = wrapper
+ }
+ } else {
+ j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+ }
}
ext := ""
@@ -2384,7 +2416,18 @@
}
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 +2452,9 @@
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 +2484,8 @@
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 +2567,8 @@
}
type bazelJavaImportAttributes struct {
- Jars bazel.LabelListAttribute
+ Jars bazel.LabelListAttribute
+ Exports bazel.LabelListAttribute
}
// java_import bp2Build converter.
@@ -2543,7 +2589,17 @@
}
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 3b86f9a..f06b520 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1783,3 +1783,26 @@
t.Errorf("expected flags to be %q; was %q", expectedFlags, flags)
}
}
+
+func TestDeviceBinaryWrapperGeneration(t *testing.T) {
+ // Scenario 1: java_binary has main_class property in its bp
+ ctx, _ := testJava(t, `
+ java_binary {
+ name: "foo",
+ srcs: ["foo.java"],
+ main_class: "foo.bar.jb",
+ }
+ `)
+ wrapperPath := fmt.Sprint(ctx.ModuleForTests("foo", "android_arm64_armv8-a").AllOutputs())
+ if !strings.Contains(wrapperPath, "foo.sh") {
+ t.Errorf("wrapper file foo.sh is not generated")
+ }
+
+ // Scenario 2: java_binary has neither wrapper nor main_class, its build
+ // is expected to be failed.
+ testJavaError(t, "main_class property is required for device binary if no default wrapper is assigned", `
+ java_binary {
+ name: "foo",
+ srcs: ["foo.java"],
+ }`)
+}
diff --git a/java/lint.go b/java/lint.go
index fcd6d31..9827159 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -333,7 +333,7 @@
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/licenses/Android.bp b/licenses/Android.bp
index 61b17bf..2e5c361 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -839,84 +839,84 @@
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/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index e92a561..2331eb1 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -551,8 +551,45 @@
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_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 7dd2bf3..006186a 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -85,6 +85,7 @@
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
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index f6fffad..076ec4b 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -19,4 +19,51 @@
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/config.go b/ui/build/config.go
index cde8d5d..36119f0 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -464,10 +464,11 @@
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...)
@@ -910,7 +911,11 @@
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")
}
@@ -1452,6 +1457,10 @@
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 9ea5110..968544b 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -28,6 +28,7 @@
"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"
@@ -1015,40 +1016,55 @@
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),
},
},
{
@@ -1056,10 +1072,11 @@
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),
},
},
{
@@ -1067,10 +1084,11 @@
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),
},
},
{
@@ -1078,10 +1096,11 @@
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),
},
},
{
@@ -1089,10 +1108,11 @@
environ: Environment{},
bazelStagingMode: 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),
},
},
{
@@ -1101,11 +1121,12 @@
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),
},
},
{
@@ -1114,14 +1135,16 @@
"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),
},
},
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 88e5592..4aded17 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -41,12 +41,13 @@
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 bootstrapGlobFileList(config Config) []string {
return []string{
config.NamedGlobFile(soongBuildTag),
- config.NamedGlobFile(bp2buildTag),
+ config.NamedGlobFile(bp2buildFilesTag),
config.NamedGlobFile(jsonModuleGraphTag),
config.NamedGlobFile(queryviewTag),
config.NamedGlobFile(apiBp2buildTag),
@@ -276,20 +277,33 @@
// 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,
@@ -361,6 +375,7 @@
primaryBuilderInvocations: []bootstrap.PrimaryBuilderInvocation{
mainSoongBuildInvocation,
bp2buildInvocation,
+ bp2buildWorkspaceInvocation,
jsonModuleGraphInvocation,
queryviewInvocation,
apiBp2buildInvocation,
@@ -426,7 +441,7 @@
checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongBuildTag))
if config.BazelBuildEnabled() || config.Bp2Build() {
- checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildTag))
+ checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildFilesTag))
}
if config.JsonModuleGraph() {
@@ -497,7 +512,7 @@
}
if config.Bp2Build() {
- targets = append(targets, config.Bp2BuildMarkerFile())
+ targets = append(targets, config.Bp2BuildWorkspaceMarkerFile())
}
if config.Queryview() {
@@ -517,17 +532,22 @@
targets = append(targets, config.SoongNinjaFile())
}
- ninja("bootstrap", "bootstrap.ninja", targets...)
-
if shouldCollectBuildSoongMetrics(config) {
- soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
- if soongBuildMetrics != nil {
- logSoongBuildMetrics(ctx, soongBuildMetrics)
- if ctx.Metrics != nil {
- ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
- }
+ soongBuildMetricsFile := filepath.Join(config.LogsDir(), "soong_build_metrics.pb")
+ if err := os.Remove(soongBuildMetricsFile); err != nil && !os.IsNotExist(err) {
+ ctx.Verbosef("Failed to remove %s", soongBuildMetricsFile)
}
+ defer func() {
+ soongBuildMetrics := loadSoongBuildMetrics(ctx, soongBuildMetricsFile)
+ if soongBuildMetrics != nil {
+ logSoongBuildMetrics(ctx, soongBuildMetrics)
+ if ctx.Metrics != nil {
+ ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
+ }
+ }
+ }()
}
+ ninja("bootstrap", "bootstrap.ninja", targets...)
distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
distFile(ctx, config, config.SoongVarsFile(), "soong")
@@ -566,8 +586,7 @@
return config.SoongBuildInvocationNeeded()
}
-func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {
- soongBuildMetricsFile := filepath.Join(config.LogsDir(), "soong_build_metrics.pb")
+func loadSoongBuildMetrics(ctx Context, soongBuildMetricsFile string) *soong_metrics_proto.SoongBuildMetrics {
buf, err := os.ReadFile(soongBuildMetricsFile)
if errors.Is(err, fs.ErrNotExist) {
// Soong may not have run during this invocation
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 687f519..9f14bdd 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -18,6 +18,7 @@
// another.
import (
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -56,7 +57,9 @@
}
if fi.IsDir() {
- if l, err := ioutil.ReadDir(p); err == nil {
+ if l, err := ioutil.ReadDir(p); err != nil {
+ _, _ = fmt.Fprintf(os.Stderr, "Failed to find files under %s\n", p)
+ } else {
files := make([]string, 0, len(l))
for _, fi := range l {
files = append(files, filepath.Join(p, fi.Name()))