diff options
author | 2018-05-25 07:58:31 -0700 | |
---|---|---|
committer | 2018-05-25 07:59:44 -0700 | |
commit | 372fbc2f016157b0331f83a20edad10d4b4cf9f7 (patch) | |
tree | 2fa069d6ee91810d9d01b98c17562b2d36b52644 /src/main/java/com/google/devtools/build | |
parent | 79b2c1699d5e332d5e571e425452a34332ed43b3 (diff) |
Automated rollback of commit 9d5c323a6e66842cfeb98462cf949dee58710fb8.
*** Reason for rollback ***
Crashes lots of targets in nightly blaze-2018.05.24-1:
PiperOrigin-RevId: 198049395
Diffstat (limited to 'src/main/java/com/google/devtools/build')
19 files changed, 854 insertions, 385 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java index 1e9f5c58d7..ed24747882 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java @@ -100,7 +100,8 @@ public class AarImport implements RuleConfiguredTargetFactory { final AndroidDataContext dataContext = androidSemantics.makeContextForNative(ruleContext); final ResourceApk resourceApk; if (AndroidResources.decoupleDataProcessing(dataContext)) { - StampedAndroidManifest manifest = AndroidManifest.forAarImport(androidManifestArtifact); + StampedAndroidManifest manifest = + AndroidManifest.forAarImport(androidManifestArtifact); boolean neverlink = JavaCommon.isNeverLink(ruleContext); ValidatedAndroidResources validatedResources = @@ -121,7 +122,6 @@ public class AarImport implements RuleConfiguredTargetFactory { resourceApk = androidManifest.packAarWithDataAndResources( ruleContext, - dataContext, AndroidAssets.forAarImport(assets), AndroidResources.forAarImport(resources), ResourceDependencies.fromRuleDeps(ruleContext, JavaCommon.isNeverLink(ruleContext)), @@ -168,6 +168,8 @@ public class AarImport implements RuleConfiguredTargetFactory { .addCompileTimeJarAsFullJar(mergedJar) .build()); + + JavaConfiguration javaConfig = ruleContext.getFragment(JavaConfiguration.class); // TODO(cnsun): need to pass the transitive classpath too to emit add dep command. NestedSet<Artifact> directDeps = getCompileTimeJarsFromCollection(targets, /*isStrict=*/ true); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java index 96d4fb3e71..0bc24677dd 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java @@ -261,7 +261,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { resourceApk = applicationManifest.packBinaryWithDataAndResources( ruleContext, - dataContext, ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK), resourceDeps, ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT), diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java index b344411ba8..0c8d4cf7cb 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java @@ -101,7 +101,6 @@ public final class AndroidBinaryMobileInstall { .addMobileInstallStubApplication(ruleContext) .packIncrementalBinaryWithDataAndResources( ruleContext, - dataContext, ruleContext.getImplicitOutputArtifact( AndroidRuleClasses.ANDROID_INCREMENTAL_RESOURCES_APK), resourceDeps, @@ -115,7 +114,6 @@ public final class AndroidBinaryMobileInstall { .createSplitManifest(ruleContext, "android_resources", false) .packIncrementalBinaryWithDataAndResources( ruleContext, - dataContext, getMobileInstallArtifact(ruleContext, "android_resources.ap_"), resourceDeps, ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"), diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java index f4ed5d53eb..67dbd5a85e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java @@ -169,7 +169,6 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { resourceApk = applicationManifest.packLibraryWithDataAndResources( ruleContext, - dataContext, resourceDeps, ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT), ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS), diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java index 2dccf13cb6..e32d12c1b2 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java @@ -117,7 +117,6 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor resourceApk = applicationManifest.packBinaryWithDataAndResources( ruleContext, - dataContext, ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK), resourceDependencies, ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT), diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifestMergeHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifestMergeHelper.java index 4d99f6d6d7..be6c9baf15 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifestMergeHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifestMergeHelper.java @@ -71,4 +71,4 @@ public final class AndroidManifestMergeHelper { .addCommandLine(commandLine.build()) .build(context)); } -} +}
\ No newline at end of file diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java index 9d945e2104..1d5256374b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java @@ -14,10 +14,21 @@ package com.google.devtools.build.lib.rules.android; import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.ParamFileInfo; +import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.rules.android.AndroidDataConverter.JoinerType; +import com.google.devtools.build.lib.util.OS; +import java.util.ArrayList; +import java.util.List; import javax.annotation.Nullable; /** @@ -41,6 +52,9 @@ public class AndroidResourceMergingActionBuilder { .withArtifact(CompiledMergableAndroidData::getCompiledSymbols) .build(); + private final RuleContext ruleContext; + private final AndroidSdkProvider sdk; + // Inputs private CompiledMergableAndroidData primary; private ResourceDependencies dependencies; @@ -56,6 +70,12 @@ public class AndroidResourceMergingActionBuilder { private boolean throwOnResourceConflict; private boolean useCompiledMerge; + /** @param ruleContext The RuleContext that was used to create the SpawnAction.Builder. */ + public AndroidResourceMergingActionBuilder(RuleContext ruleContext) { + this.ruleContext = ruleContext; + this.sdk = AndroidSdkProvider.fromRuleContext(ruleContext); + } + /** * The primary resource for merging. This resource will overwrite any resource or data value in * the transitive closure. @@ -112,102 +132,172 @@ public class AndroidResourceMergingActionBuilder { return this; } - private BusyBoxActionBuilder createInputsForBuilder(BusyBoxActionBuilder builder) { - return builder - .addAndroidJar() - .addInput("--primaryManifest", primary.getManifest()) - .maybeAddFlag("--packageForR", customJavaPackage) - .maybeAddFlag("--throwOnResourceConflict", throwOnResourceConflict); + private NestedSetBuilder<Artifact> createInputsForBuilder(CustomCommandLine.Builder builder) { + // Use a FluentIterable to avoid flattening the NestedSets + NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); + + builder.addExecPath("--androidJar", sdk.getAndroidJar()); + inputs.add(sdk.getAndroidJar()); + + Preconditions.checkNotNull(primary.getManifest()); + builder.addExecPath("--primaryManifest", primary.getManifest()); + inputs.add(primary.getManifest()); + + if (!Strings.isNullOrEmpty(customJavaPackage)) { + // Sets an alternative java package for the generated R.java + // this allows android rules to generate resources outside of the java{,tests} tree. + builder.add("--packageForR", customJavaPackage); + } + + if (throwOnResourceConflict) { + builder.add("--throwOnResourceConflict"); + } + + return inputs; } - private void buildCompiledResourceMergingAction(BusyBoxActionBuilder builder) { - Preconditions.checkNotNull(primary); + private void buildCompiledResourceMergingAction( + CustomCommandLine.Builder builder, + List<Artifact> outputs, + ActionConstructionContext context) { + NestedSetBuilder<Artifact> inputs = createInputsForBuilder(builder); - createInputsForBuilder(builder) - .addInput( - "--primaryData", - RESOURCE_CONTAINER_TO_ARG_FOR_COMPILED.map(primary), - Iterables.concat( - primary.getArtifacts(), ImmutableList.of(primary.getCompiledSymbols()))); + Preconditions.checkNotNull(primary); + builder.add("--primaryData", RESOURCE_CONTAINER_TO_ARG_FOR_COMPILED.map(primary)); + inputs.addAll(primary.getArtifacts()); + inputs.add(primary.getCompiledSymbols()); if (dependencies != null) { - builder - .addTransitiveFlag( - "--data", - dependencies.getTransitiveResourceContainers(), - RESOURCE_CONTAINER_TO_ARG_FOR_COMPILED) - .addTransitiveFlag( - "--directData", - dependencies.getDirectResourceContainers(), - RESOURCE_CONTAINER_TO_ARG_FOR_COMPILED) - .addTransitiveInputValues(dependencies.getTransitiveResources()) - .addTransitiveInputValues(dependencies.getTransitiveAssets()) - .addTransitiveInputValues(dependencies.getTransitiveCompiledSymbols()); + RESOURCE_CONTAINER_TO_ARG_FOR_COMPILED.addDepsToCommandLine( + builder, + dependencies.getDirectResourceContainers(), + dependencies.getTransitiveResourceContainers()); + inputs.addTransitive(dependencies.getTransitiveResources()); + inputs.addTransitive(dependencies.getTransitiveAssets()); + inputs.addTransitive(dependencies.getTransitiveCompiledSymbols()); } - builder.buildAndRegister("Merging compiled Android resources", "AndroidCompiledResourceMerger"); + SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); + ParamFileInfo.Builder compiledParamFileInfo = ParamFileInfo.builder(ParameterFileType.UNQUOTED); + compiledParamFileInfo.setUseAlways(OS.getCurrent() == OS.WINDOWS); + // Create the spawn action. + ruleContext.registerAction( + spawnActionBuilder + .useDefaultShellEnvironment() + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.copyOf(outputs)) + .addCommandLine(builder.build(), compiledParamFileInfo.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Merging compiled Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AndroidCompiledResourceMerger") + .build(context)); } - private void buildParsedResourceMergingAction(BusyBoxActionBuilder builder) { - Preconditions.checkNotNull(primary); + private void buildParsedResourceMergingAction( + CustomCommandLine.Builder builder, + List<Artifact> outputs, + ActionConstructionContext context) { + NestedSetBuilder<Artifact> inputs = createInputsForBuilder(builder); - createInputsForBuilder(builder) - .addInput( - "--primaryData", - RESOURCE_CONTAINER_TO_ARG.map(primary), - Iterables.concat(primary.getArtifacts(), ImmutableList.of(primary.getSymbols()))); + Preconditions.checkNotNull(primary); + builder.add("--primaryData", RESOURCE_CONTAINER_TO_ARG.map(primary)); + inputs.addAll(primary.getArtifacts()); + inputs.add(primary.getSymbols()); if (dependencies != null) { - builder - .addTransitiveFlag( - "--data", dependencies.getTransitiveResourceContainers(), RESOURCE_CONTAINER_TO_ARG) - .addTransitiveFlag( - "--directData", dependencies.getDirectResourceContainers(), RESOURCE_CONTAINER_TO_ARG) - .addTransitiveInputValues(dependencies.getTransitiveResources()) - .addTransitiveInputValues(dependencies.getTransitiveAssets()) - .addTransitiveInputValues(dependencies.getTransitiveSymbolsBin()); + RESOURCE_CONTAINER_TO_ARG.addDepsToCommandLine( + builder, + dependencies.getDirectResourceContainers(), + dependencies.getTransitiveResourceContainers()); + inputs.addTransitive(dependencies.getTransitiveResources()); + inputs.addTransitive(dependencies.getTransitiveAssets()); + inputs.addTransitive(dependencies.getTransitiveSymbolsBin()); } - builder.buildAndRegister("Merging Android resources", "AndroidResourceMerger"); + SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); + ParamFileInfo.Builder paramFileInfo = ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED); + // Some flags (e.g. --mainData) may specify lists (or lists of lists) separated by special + // characters (colon, semicolon, hashmark, ampersand) that don't work on Windows, and quoting + // semantics are very complicated (more so than in Bash), so let's just always use a parameter + // file. + // TODO(laszlocsomor), TODO(corysmith): restructure the Android BusyBux's flags by deprecating + // list-type and list-of-list-type flags that use such problematic separators in favor of + // multi-value flags (to remove one level of listing) and by changing all list separators to a + // platform-safe character (= comma). + paramFileInfo.setUseAlways(OS.getCurrent() == OS.WINDOWS); + + // Create the spawn action. + ruleContext.registerAction( + spawnActionBuilder + .useDefaultShellEnvironment() + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.copyOf(outputs)) + .addCommandLine(builder.build(), paramFileInfo.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Merging Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AndroidResourceMerger") + .build(context)); } - private void build(AndroidDataContext dataContext) { - BusyBoxActionBuilder parsedMergeBuilder = BusyBoxActionBuilder.create(dataContext, "MERGE"); - BusyBoxActionBuilder compiledMergeBuilder = - BusyBoxActionBuilder.create(dataContext, "MERGE_COMPILED"); + private void build(RuleContext context) { + CustomCommandLine.Builder parsedMergeBuilder = + new CustomCommandLine.Builder().add("--tool").add("MERGE").add("--"); + CustomCommandLine.Builder compiledMergeBuilder = + new CustomCommandLine.Builder().add("--tool").add("MERGE_COMPILED").add("--"); + List<Artifact> parsedMergeOutputs = new ArrayList<>(); + List<Artifact> compiledMergeOutputs = new ArrayList<>(); - parsedMergeBuilder.addOutput("--resourcesOutput", mergedResourcesOut); + if (mergedResourcesOut != null) { + parsedMergeBuilder.addExecPath("--resourcesOutput", mergedResourcesOut); + parsedMergeOutputs.add(mergedResourcesOut); + } // TODO(corysmith): Move the data binding parsing out of the merging pass to enable faster // aapt2 builds. - parsedMergeBuilder.maybeAddOutput("--dataBindingInfoOut", dataBindingInfoZip); + if (dataBindingInfoZip != null) { + parsedMergeBuilder.addExecPath("--dataBindingInfoOut", dataBindingInfoZip); + parsedMergeOutputs.add(dataBindingInfoZip); + } + + CustomCommandLine.Builder jarAndManifestBuilder = + useCompiledMerge ? compiledMergeBuilder : parsedMergeBuilder; + List<Artifact> jarAndManifestOutputs = + useCompiledMerge ? compiledMergeOutputs : parsedMergeOutputs; - (useCompiledMerge ? compiledMergeBuilder : parsedMergeBuilder) - .addOutput("--classJarOutput", classJarOut) - .addLabelFlag("--targetLabel") + if (classJarOut != null) { + jarAndManifestBuilder.addExecPath("--classJarOutput", classJarOut); + jarAndManifestBuilder.addLabel("--targetLabel", ruleContext.getLabel()); + jarAndManifestOutputs.add(classJarOut); + } - // For now, do manifest processing to remove placeholders that aren't handled by the legacy - // manifest merger. Remove this once enough users migrate over to the new manifest merger. - .maybeAddOutput("--manifestOutput", manifestOut); + // For now, do manifest processing to remove placeholders that aren't handled by the legacy + // manifest merger. Remove this once enough users migrate over to the new manifest merger. + if (manifestOut != null) { + jarAndManifestBuilder.addExecPath("--manifestOutput", manifestOut); + jarAndManifestOutputs.add(manifestOut); + } - if (useCompiledMerge) { - buildCompiledResourceMergingAction(compiledMergeBuilder); + if (!compiledMergeOutputs.isEmpty()) { + buildCompiledResourceMergingAction(compiledMergeBuilder, compiledMergeOutputs, context); } - // Always make an action for merging parsed resources - the merged resources are still created - // this way. - buildParsedResourceMergingAction(parsedMergeBuilder); + if (!parsedMergeOutputs.isEmpty()) { + buildParsedResourceMergingAction(parsedMergeBuilder, parsedMergeOutputs, context); + } } - public ResourceContainer build( - AndroidDataContext dataContext, ResourceContainer resourceContainer) { - withPrimary(resourceContainer).build(dataContext); + public ResourceContainer build(RuleContext ruleContext, ResourceContainer resourceContainer) { + withPrimary(resourceContainer).build(ruleContext); // Return the full set of processed transitive dependencies. ResourceContainer.Builder result = resourceContainer.toBuilder(); - - result.setJavaClassJar(classJarOut); - + if (classJarOut != null) { + // ensure the classJar is propagated if it exists. Otherwise, AndroidCommon tries to make it. + // TODO(corysmith): Centralize the class jar generation. + result.setJavaClassJar(classJarOut); + } if (manifestOut != null) { result.setManifest(manifestOut); } @@ -217,9 +307,8 @@ public class AndroidResourceMergingActionBuilder { return result.build(); } - public MergedAndroidResources build( - AndroidDataContext dataContext, ParsedAndroidResources parsed) { - withPrimary(parsed).build(dataContext); + public MergedAndroidResources build(RuleContext ruleContext, ParsedAndroidResources parsed) { + withPrimary(parsed).build(ruleContext); return MergedAndroidResources.of( parsed, diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java index 13976552ef..a3bd4773d6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceParsingActionBuilder.java @@ -15,16 +15,31 @@ package com.google.devtools.build.lib.rules.android; import static java.util.stream.Collectors.joining; -import com.google.common.collect.Iterables; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Streams; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; +import com.google.devtools.build.lib.actions.ParamFileInfo; +import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.vfs.PathFragment; +import java.util.ArrayList; +import java.util.List; import javax.annotation.Nullable; /** Builder for creating $android_resource_parser action. */ public class AndroidResourceParsingActionBuilder { + private final RuleContext ruleContext; + private final AndroidSdkProvider sdk; + // These are only needed when parsing resources with data binding @Nullable private Artifact manifest; @Nullable private String javaPackage; @@ -39,6 +54,12 @@ public class AndroidResourceParsingActionBuilder { @Nullable private Artifact compiledSymbols; @Nullable private Artifact dataBindingInfoZip; + /** @param ruleContext The RuleContext that was used to create the SpawnAction.Builder. */ + public AndroidResourceParsingActionBuilder(RuleContext ruleContext) { + this.ruleContext = ruleContext; + this.sdk = AndroidSdkProvider.fromRuleContext(ruleContext); + } + /** Set the artifact location for the output protobuf. */ public AndroidResourceParsingActionBuilder setOutput(Artifact output) { this.output = output; @@ -82,32 +103,86 @@ public class AndroidResourceParsingActionBuilder { return Streams.stream(roots).map(Object::toString).collect(joining("#")); } - private void build(AndroidDataContext dataContext) { + private void build(ActionConstructionContext context) { + CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + + // Set the busybox tool. + builder.add("--tool").add("PARSE").add("--"); + + NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); + String resourceDirectories = convertRoots(resources.getResourceRoots()) + ":" + convertRoots(assets.getAssetRoots()); - Iterable<Artifact> resourceArtifacts = - Iterables.concat(assets.getAssets(), resources.getResources()); - - BusyBoxActionBuilder.create(dataContext, "PARSE") - .addInput("--primaryData", resourceDirectories, resourceArtifacts) - .addOutput("--output", output) - .buildAndRegister("Parsing Android resources", "AndroidResourceParser"); + builder.add("--primaryData", resourceDirectories); + inputs.addTransitive( + NestedSetBuilder.<Artifact>naiveLinkOrder() + .addAll(assets.getAssets()) + .addAll(resources.getResources()) + .build()); + + Preconditions.checkNotNull(output); + builder.addExecPath("--output", output); + + SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); + ParamFileInfo.Builder paramFileInfo = ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED); + // Some flags (e.g. --mainData) may specify lists (or lists of lists) separated by special + // characters (colon, semicolon, hashmark, ampersand) that don't work on Windows, and quoting + // semantics are very complicated (more so than in Bash), so let's just always use a parameter + // file. + // TODO(laszlocsomor), TODO(corysmith): restructure the Android BusyBux's flags by deprecating + // list-type and list-of-list-type flags that use such problematic separators in favor of + // multi-value flags (to remove one level of listing) and by changing all list separators to a + // platform-safe character (= comma). + paramFileInfo.setUseAlways(OS.getCurrent() == OS.WINDOWS); + + // Create the spawn action. + ruleContext.registerAction( + spawnActionBuilder + .useDefaultShellEnvironment() + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.of(output)) + .addCommandLine(builder.build(), paramFileInfo.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Parsing Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AndroidResourceParser") + .build(context)); if (compiledSymbols != null) { - BusyBoxActionBuilder compiledBuilder = - BusyBoxActionBuilder.create(dataContext, "COMPILE_LIBRARY_RESOURCES") - .addAapt(AndroidAaptVersion.AAPT2) - .addInput("--resources", resourceDirectories, resourceArtifacts) - .addOutput("--output", compiledSymbols); - + List<Artifact> outs = new ArrayList<>(); + CustomCommandLine.Builder flatFileBuilder = new CustomCommandLine.Builder(); + flatFileBuilder + .add("--tool") + .add("COMPILE_LIBRARY_RESOURCES") + .add("--") + .addExecPath("--aapt2", sdk.getAapt2().getExecutable()) + .add("--resources", resourceDirectories) + .addExecPath("--output", compiledSymbols); + inputs.add(sdk.getAapt2().getExecutable()); + outs.add(compiledSymbols); + + // The databinding needs to be processed before compilation, so the stripping happens here. if (dataBindingInfoZip != null) { - compiledBuilder - .addInput("--manifest", manifest) - .maybeAddFlag("--packagePath", javaPackage) - .addOutput("--dataBindingInfoOut", dataBindingInfoZip); + flatFileBuilder.addExecPath("--manifest", manifest); + inputs.add(manifest); + if (!Strings.isNullOrEmpty(javaPackage)) { + flatFileBuilder.add("--packagePath", javaPackage); + } + flatFileBuilder.addExecPath("--dataBindingInfoOut", dataBindingInfoZip); + outs.add(dataBindingInfoZip); } - - compiledBuilder.buildAndRegister("Compiling Android resources", "AndroidResourceCompiler"); + // Create the spawn action. + ruleContext.registerAction( + new SpawnAction.Builder() + .useDefaultShellEnvironment() + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.copyOf(outs)) + .addCommandLine(flatFileBuilder.build(), paramFileInfo.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Compiling Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AndroidResourceCompiler") + .build(context)); } } @@ -116,9 +191,7 @@ public class AndroidResourceParsingActionBuilder { * parsed and compiled information. */ public ParsedAndroidResources build( - AndroidDataContext dataContext, - AndroidResources androidResources, - StampedAndroidManifest manifest) { + AndroidResources androidResources, StampedAndroidManifest manifest) { if (dataBindingInfoZip != null) { // Manifest information is needed for data binding setManifest(manifest.getManifest()); @@ -126,17 +199,17 @@ public class AndroidResourceParsingActionBuilder { } setResources(androidResources); - build(dataContext); + build(ruleContext); return ParsedAndroidResources.of( - androidResources, output, compiledSymbols, dataContext.getLabel(), manifest); + androidResources, output, compiledSymbols, ruleContext.getLabel(), manifest); } - public ParsedAndroidAssets build(AndroidDataContext dataContext, AndroidAssets assets) { + public ParsedAndroidAssets build(AndroidAssets assets) { setAssets(assets); - build(dataContext); + build(ruleContext); - return ParsedAndroidAssets.of(assets, output, dataContext.getLabel()); + return ParsedAndroidAssets.of(assets, output, ruleContext.getLabel()); } /** @@ -144,8 +217,8 @@ public class AndroidResourceParsingActionBuilder { * symbols. */ public ResourceContainer buildAndUpdate( - AndroidDataContext dataContext, ResourceContainer resourceContainer) { - build(dataContext); + RuleContext ruleContext, ResourceContainer resourceContainer) { + build(ruleContext); ResourceContainer.Builder builder = resourceContainer diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java index 13a7c04753..41abe2f7a3 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceValidatorActionBuilder.java @@ -14,8 +14,19 @@ package com.google.devtools.build.lib.rules.android; import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; +import com.google.devtools.build.lib.actions.ParamFileInfo; +import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; +import java.util.ArrayList; +import java.util.List; /** * Builder for creating $android_resource_validator action. This action validates merged resources @@ -26,6 +37,9 @@ import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidA */ public class AndroidResourceValidatorActionBuilder { + private final RuleContext ruleContext; + private final AndroidSdkProvider sdk; + // Inputs private CompiledMergableAndroidData primary; private Artifact mergedResources; @@ -44,6 +58,12 @@ public class AndroidResourceValidatorActionBuilder { private Artifact compiledSymbols; private Artifact apkOut; + /** @param ruleContext The RuleContext that was used to create the SpawnAction.Builder. */ + public AndroidResourceValidatorActionBuilder(RuleContext ruleContext) { + this.ruleContext = ruleContext; + this.sdk = AndroidSdkProvider.fromRuleContext(ruleContext); + } + public AndroidResourceValidatorActionBuilder setStaticLibraryOut(Artifact staticLibraryOut) { this.staticLibraryOut = staticLibraryOut; return this; @@ -96,19 +116,19 @@ public class AndroidResourceValidatorActionBuilder { return this; } - private void build(AndroidDataContext dataContext) { + private void build(ActionConstructionContext context) { if (rTxtOut != null) { - createValidateAction(dataContext); + createValidateAction(context); } if (compiledSymbols != null) { - createLinkStaticLibraryAction(dataContext); + createLinkStaticLibraryAction(context); } } public ResourceContainer build( - AndroidDataContext dataContext, ResourceContainer resourceContainer) { - withPrimary(resourceContainer).build(dataContext); + ActionConstructionContext context, ResourceContainer resourceContainer) { + withPrimary(resourceContainer).build(context); ResourceContainer.Builder builder = resourceContainer.toBuilder(); if (rTxtOut != null) { @@ -126,11 +146,17 @@ public class AndroidResourceValidatorActionBuilder { } public ValidatedAndroidResources build( - AndroidDataContext dataContext, MergedAndroidResources merged) { - withPrimary(merged).build(dataContext); + ActionConstructionContext context, MergedAndroidResources merged) { + withPrimary(merged).build(context); return ValidatedAndroidResources.of( - merged, rTxtOut, sourceJarOut, apkOut, aapt2RTxtOut, aapt2SourceJarOut, staticLibraryOut); + merged, + rTxtOut, + sourceJarOut, + apkOut, + aapt2RTxtOut, + aapt2SourceJarOut, + staticLibraryOut); } public AndroidResourceValidatorActionBuilder setCompiledSymbols(Artifact compiledSymbols) { @@ -149,47 +175,130 @@ public class AndroidResourceValidatorActionBuilder { * <p>This allows the link action to replace the validate action for builds that use aapt2, as * opposed to executing both actions. */ - private void createLinkStaticLibraryAction(AndroidDataContext dataContext) { + private void createLinkStaticLibraryAction(ActionConstructionContext context) { + Preconditions.checkNotNull(staticLibraryOut); + Preconditions.checkNotNull(aapt2SourceJarOut); + Preconditions.checkNotNull(aapt2RTxtOut); Preconditions.checkNotNull(resourceDeps); - BusyBoxActionBuilder builder = - BusyBoxActionBuilder.create(dataContext, "LINK_STATIC_LIBRARY") - .addAapt(AndroidAaptVersion.AAPT2) - .addInput("--libraries", dataContext.getSdk().getAndroidJar()) - .addInput("--compiled", compiledSymbols) - .addInput("--manifest", primary.getManifest()) + CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + ImmutableList.Builder<Artifact> inputs = ImmutableList.builder(); + ImmutableList.Builder<Artifact> outs = ImmutableList.builder(); + + // Set the busybox tool. + builder.add("--tool").add("LINK_STATIC_LIBRARY").add("--"); + + builder.addExecPath("--aapt2", sdk.getAapt2().getExecutable()); + + builder.add("--libraries").addExecPath(sdk.getAndroidJar()); + inputs.add(sdk.getAndroidJar()); + + builder.addExecPath("--compiled", compiledSymbols); + inputs.add(compiledSymbols); - // Sets an alternative java package for the generated R.java - // this allows android rules to generate resources outside of the java{,tests} tree. - .maybeAddFlag("--packageForR", customJavaPackage); + builder.addExecPath("--manifest", primary.getManifest()); + inputs.add(primary.getManifest()); + + if (!Strings.isNullOrEmpty(customJavaPackage)) { + // Sets an alternative java package for the generated R.java + // this allows android rules to generate resources outside of the java{,tests} tree. + builder.add("--packageForR", customJavaPackage); + } if (!resourceDeps.getTransitiveCompiledSymbols().isEmpty()) { - builder.addTransitiveVectoredInput( - "--compiledDep", resourceDeps.getTransitiveCompiledSymbols()); + builder.addExecPaths( + "--compiledDep", + VectorArg.join(context.getConfiguration().getHostPathSeparator()) + .each(resourceDeps.getTransitiveCompiledSymbols())); + inputs.addAll(resourceDeps.getTransitiveCompiledSymbols()); + } + + builder.addExecPath("--sourceJarOut", aapt2SourceJarOut); + outs.add(aapt2SourceJarOut); + + builder.addExecPath("--rTxtOut", aapt2RTxtOut); + outs.add(aapt2RTxtOut); + + builder.addExecPath("--staticLibraryOut", staticLibraryOut); + outs.add(staticLibraryOut); + + ruleContext.registerAction( + new SpawnAction.Builder() + .useDefaultShellEnvironment() + .addTool(sdk.getAapt2()) + .addInputs(inputs.build()) + .addOutputs(outs.build()) + .addCommandLine( + builder.build(), ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED).build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage( + "Linking static android resource library for %s", ruleContext.getLabel()) + .setMnemonic("AndroidResourceLink") + .build(context)); + } + + private void createValidateAction(ActionConstructionContext context) { + CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + + // Set the busybox tool. + builder.add("--tool").add("VALIDATE").add("--"); + + if (!Strings.isNullOrEmpty(sdk.getBuildToolsVersion())) { + builder.add("--buildToolsVersion", sdk.getBuildToolsVersion()); + } + + builder.addExecPath("--aapt", sdk.getAapt().getExecutable()); + + ImmutableList.Builder<Artifact> inputs = ImmutableList.builder(); + + builder.addExecPath("--androidJar", sdk.getAndroidJar()); + inputs.add(sdk.getAndroidJar()); + + Preconditions.checkNotNull(mergedResources); + builder.addExecPath("--mergedResources", mergedResources); + inputs.add(mergedResources); + + builder.addExecPath("--manifest", primary.getManifest()); + inputs.add(primary.getManifest()); + + if (debug) { + builder.add("--debug"); + } + + if (!Strings.isNullOrEmpty(customJavaPackage)) { + // Sets an alternative java package for the generated R.java + // this allows android rules to generate resources outside of the java{,tests} tree. + builder.add("--packageForR", customJavaPackage); + } + List<Artifact> outs = new ArrayList<>(); + Preconditions.checkNotNull(rTxtOut); + builder.addExecPath("--rOutput", rTxtOut); + outs.add(rTxtOut); + + Preconditions.checkNotNull(sourceJarOut); + builder.addExecPath("--srcJarOutput", sourceJarOut); + outs.add(sourceJarOut); + + if (apkOut != null) { + builder.addExecPath("--packagePath", apkOut); + outs.add(apkOut); } - builder - .addOutput("--sourceJarOut", aapt2SourceJarOut) - .addOutput("--rTxtOut", aapt2RTxtOut) - .addOutput("--staticLibraryOut", staticLibraryOut) - .buildAndRegister("Linking static android resource library", "AndroidResourceLink"); - } - - private void createValidateAction(AndroidDataContext dataContext) { - BusyBoxActionBuilder.create(dataContext, "VALIDATE") - .maybeAddFlag("--buildToolsVersion", dataContext.getSdk().getBuildToolsVersion()) - .addAapt(AndroidAaptVersion.AAPT) - .addAndroidJar() - .addInput("--mergedResources", mergedResources) - .addInput("--manifest", primary.getManifest()) - .maybeAddFlag("--debug", debug) - - // Sets an alternative java package for the generated R.java - // this allows android rules to generate resources outside of the java{,tests} tree. - .maybeAddFlag("--packageForR", customJavaPackage) - .addOutput("--rOutput", rTxtOut) - .addOutput("--srcJarOutput", sourceJarOut) - .maybeAddOutput("--packagePath", apkOut) - .buildAndRegister("Validating Android resources", "AndroidResourceValidator"); + SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); + // Create the spawn action. + ruleContext.registerAction( + spawnActionBuilder + .useDefaultShellEnvironment() + .addTool(sdk.getAapt()) + .addInputs(inputs.build()) + .addOutputs(ImmutableList.copyOf(outs)) + .addCommandLine( + builder.build(), ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED).build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Validating Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AndroidResourceValidator") + .build(context)); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java index a566f045c6..3417f538c6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourcesProcessorBuilder.java @@ -13,45 +13,55 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.ParamFileInfo; +import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; -import com.google.devtools.build.lib.rules.android.AndroidDataConverter.JoinerType; +import com.google.devtools.build.lib.rules.android.ResourceContainerConverter.ToArg; +import com.google.devtools.build.lib.rules.android.ResourceContainerConverter.ToArg.Includes; +import com.google.devtools.build.lib.util.OS; +import java.util.ArrayList; import java.util.Collections; import java.util.List; /** Builder for creating resource processing action. */ public class AndroidResourcesProcessorBuilder { - private static final AndroidDataConverter<ValidatedAndroidData> AAPT2_RESOURCE_DEP_TO_ARG = - AndroidDataConverter.<ValidatedAndroidData>builder(JoinerType.COLON_COMMA) - .withRoots(ValidatedAndroidData::getResourceRoots) - .withRoots(ValidatedAndroidData::getAssetRoots) - .withArtifact(ValidatedAndroidData::getManifest) - .withArtifact(ValidatedAndroidData::getAapt2RTxt) - .withArtifact(ValidatedAndroidData::getCompiledSymbols) - .withArtifact(ValidatedAndroidData::getSymbols) - .build(); - - private static final AndroidDataConverter<ValidatedAndroidData> - AAPT2_RESOURCE_DEP_TO_ARG_NO_PARSE = - AndroidDataConverter.<ValidatedAndroidData>builder(JoinerType.COLON_COMMA) - .withRoots(ValidatedAndroidData::getResourceRoots) - .withRoots(ValidatedAndroidData::getAssetRoots) - .withArtifact(ValidatedAndroidData::getManifest) - .withArtifact(ValidatedAndroidData::getAapt2RTxt) - .withArtifact(ValidatedAndroidData::getCompiledSymbols) - .build(); - - private static final AndroidDataConverter<ValidatedAndroidData> RESOURCE_DEP_TO_ARG = - AndroidDataConverter.<ValidatedAndroidData>builder(JoinerType.COLON_COMMA) - .withRoots(ValidatedAndroidData::getResourceRoots) - .withRoots(ValidatedAndroidData::getAssetRoots) - .withArtifact(ValidatedAndroidData::getManifest) - .withArtifact(ValidatedAndroidData::getRTxt) - .withArtifact(ValidatedAndroidData::getSymbols) - .build(); + private static final ResourceContainerConverter.ToArg AAPT2_RESOURCE_DEP_TO_ARG = + ResourceContainerConverter.builder() + .include(Includes.ResourceRoots) + .include(Includes.Manifest) + .include(Includes.Aapt2RTxt) + .include(Includes.SymbolsBin) + .include(Includes.CompiledSymbols) + .withSeparator(ToArg.SeparatorType.COLON_COMMA) + .toArgConverter(); + + private static final ResourceContainerConverter.ToArg AAPT2_RESOURCE_DEP_TO_ARG_NO_PARSE = + ResourceContainerConverter.builder() + .include(Includes.ResourceRoots) + .include(Includes.Manifest) + .include(Includes.Aapt2RTxt) + .include(Includes.CompiledSymbols) + .withSeparator(ToArg.SeparatorType.COLON_COMMA) + .toArgConverter(); + + private static final ResourceContainerConverter.ToArg RESOURCE_DEP_TO_ARG = + ResourceContainerConverter.builder() + .include(Includes.ResourceRoots) + .include(Includes.Manifest) + .include(Includes.RTxt) + .include(Includes.SymbolsBin) + .withSeparator(ToArg.SeparatorType.COLON_COMMA) + .toArgConverter(); private ResourceDependencies resourceDependencies = ResourceDependencies.empty(); private AssetDependencies assetDependencies = AssetDependencies.empty(); @@ -65,7 +75,10 @@ public class AndroidResourcesProcessorBuilder { private ResourceFilterFactory resourceFilterFactory = ResourceFilterFactory.empty(); private List<String> uncompressedExtensions = Collections.emptyList(); private Artifact apkOut; + private final AndroidSdkProvider sdk; + private SpawnAction.Builder spawnActionBuilder; private String customJavaPackage; + private final RuleContext ruleContext; private String versionCode; private String applicationId; private String versionName; @@ -84,6 +97,13 @@ public class AndroidResourcesProcessorBuilder { private boolean useCompiledResourcesForMerge; private boolean isTestWithResources = false; + /** @param ruleContext The RuleContext that was used to create the SpawnAction.Builder. */ + public AndroidResourcesProcessorBuilder(RuleContext ruleContext) { + this.sdk = AndroidSdkProvider.fromRuleContext(ruleContext); + this.ruleContext = ruleContext; + this.spawnActionBuilder = new SpawnAction.Builder(); + } + /** * The output zip for resource-processed data binding expressions (i.e. a zip of .xml files). * @@ -207,10 +227,9 @@ public class AndroidResourcesProcessorBuilder { * @return a {@link ResourceApk} containing the processed resource, asset, and manifest * information. */ - public ResourceApk buildWithoutLocalResources( - AndroidDataContext dataContext, StampedAndroidManifest manifest) { + public ResourceApk buildWithoutLocalResources(StampedAndroidManifest manifest) { - build(dataContext, AndroidResources.empty(), AndroidAssets.empty(), manifest); + build(AndroidResources.empty(), AndroidAssets.empty(), manifest); return ResourceApk.fromTransitiveResources( resourceDependencies, @@ -219,9 +238,8 @@ public class AndroidResourcesProcessorBuilder { rTxtOut); } - public ResourceContainer build(AndroidDataContext dataContext, ResourceContainer primary) { + public ResourceContainer build(ResourceContainer primary) { build( - dataContext, primary.getAndroidResources(), primary.getAndroidAssets(), ProcessedAndroidManifest.from(primary)); @@ -247,15 +265,14 @@ public class AndroidResourcesProcessorBuilder { } public ProcessedAndroidData build( - AndroidDataContext dataContext, AndroidResources primaryResources, AndroidAssets primaryAssets, StampedAndroidManifest primaryManifest) { if (aaptVersion == AndroidAaptVersion.AAPT2) { - createAapt2ApkAction(dataContext, primaryResources, primaryAssets, primaryManifest); + createAapt2ApkAction(primaryResources, primaryAssets, primaryManifest); } else { - createAaptAction(dataContext, primaryResources, primaryAssets, primaryManifest); + createAaptAction(primaryResources, primaryAssets, primaryManifest); } // Wrap the new manifest, if any @@ -271,12 +288,12 @@ public class AndroidResourcesProcessorBuilder { primaryResources, symbols, /* compiledSymbols = */ null, - dataContext.getLabel(), + ruleContext.getLabel(), processedManifest); // Wrap the parsed and merged assets ParsedAndroidAssets parsedAssets = - ParsedAndroidAssets.of(primaryAssets, symbols, dataContext.getLabel()); + ParsedAndroidAssets.of(primaryAssets, symbols, ruleContext.getLabel()); MergedAndroidAssets mergedAssets = MergedAndroidAssets.of(parsedAssets, mergedResourcesOut, assetDependencies); @@ -332,145 +349,289 @@ public class AndroidResourcesProcessorBuilder { } private void createAapt2ApkAction( - AndroidDataContext dataContext, AndroidResources primaryResources, AndroidAssets primaryAssets, StampedAndroidManifest primaryManifest) { - BusyBoxActionBuilder builder = - BusyBoxActionBuilder.create(dataContext, "AAPT2_PACKAGE").addAapt(AndroidAaptVersion.AAPT2); + List<Artifact> outs = new ArrayList<>(); + // TODO(corysmith): Convert to an immutable list builder, as there is no benefit to a NestedSet + // here, as it will already have been flattened. + NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); + CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + // Set the busybox tool. + builder.add("--tool").add("AAPT2_PACKAGE").add("--"); + + builder.addExecPath("--aapt2", sdk.getAapt2().getExecutable()); if (resourceDependencies != null) { - builder - .addTransitiveFlag( - "--data", - resourceDependencies.getTransitiveResourceContainers(), - useCompiledResourcesForMerge - ? AAPT2_RESOURCE_DEP_TO_ARG_NO_PARSE - : AAPT2_RESOURCE_DEP_TO_ARG) - .addTransitiveFlag( - "--directData", - resourceDependencies.getDirectResourceContainers(), - useCompiledResourcesForMerge - ? AAPT2_RESOURCE_DEP_TO_ARG_NO_PARSE - : AAPT2_RESOURCE_DEP_TO_ARG) - .addTransitiveInputValues(resourceDependencies.getTransitiveResources()) - .addTransitiveInputValues(resourceDependencies.getTransitiveAssets()) - .addTransitiveInputValues(resourceDependencies.getTransitiveManifests()) - .addTransitiveInputValues(resourceDependencies.getTransitiveAapt2RTxt()) - .addTransitiveInputValues(resourceDependencies.getTransitiveCompiledSymbols()); + ResourceContainerConverter.addToCommandLine( + resourceDependencies, + builder, + useCompiledResourcesForMerge + ? AAPT2_RESOURCE_DEP_TO_ARG_NO_PARSE + : AAPT2_RESOURCE_DEP_TO_ARG); + inputs + .addTransitive(resourceDependencies.getTransitiveResources()) + .addTransitive(resourceDependencies.getTransitiveAssets()) + .addTransitive(resourceDependencies.getTransitiveManifests()) + .addTransitive(resourceDependencies.getTransitiveAapt2RTxt()) + .addTransitive(resourceDependencies.getTransitiveCompiledSymbols()); if (!useCompiledResourcesForMerge) { - builder.addTransitiveInputValues(resourceDependencies.getTransitiveSymbolsBin()); + inputs.addTransitive(resourceDependencies.getTransitiveSymbolsBin()); } } - addAssetDeps(builder) - .maybeAddFlag("--useCompiledResourcesForMerge", useCompiledResourcesForMerge) - .maybeAddFlag("--conditionalKeepRules", conditionalKeepRules); + addAssetDeps(builder, inputs); + + if (useCompiledResourcesForMerge) { + builder.add("--useCompiledResourcesForMerge"); + } + + if (conditionalKeepRules) { + builder.add("--conditionalKeepRules"); + } - configureCommonFlags(dataContext, primaryResources, primaryAssets, primaryManifest, builder) - .buildAndRegister("Processing Android resources", "AndroidAapt2"); + configureCommonFlags(primaryResources, primaryAssets, primaryManifest, outs, inputs, builder); + + ParamFileInfo.Builder paramFileInfo = ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED); + // Some flags (e.g. --mainData) may specify lists (or lists of lists) separated by special + // characters (colon, semicolon, hashmark, ampersand) that don't work on Windows, and quoting + // semantics are very complicated (more so than in Bash), so let's just always use a parameter + // file. + // TODO(laszlocsomor), TODO(corysmith): restructure the Android BusyBux's flags by deprecating + // list-type and list-of-list-type flags that use such problematic separators in favor of + // multi-value flags (to remove one level of listing) and by changing all list separators to a + // platform-safe character (= comma). + paramFileInfo.setUseAlways(OS.getCurrent() == OS.WINDOWS); + + // Create the spawn action. + ruleContext.registerAction( + this.spawnActionBuilder + .useDefaultShellEnvironment() + .addTool(sdk.getAapt2()) + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.<Artifact>copyOf(outs)) + .addCommandLine(builder.build(), paramFileInfo.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Processing Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AndroidAapt2") + .build(ruleContext)); } private void createAaptAction( - AndroidDataContext dataContext, AndroidResources primaryResources, AndroidAssets primaryAssets, StampedAndroidManifest primaryManifest) { - BusyBoxActionBuilder builder = BusyBoxActionBuilder.create(dataContext, "PACKAGE"); + List<Artifact> outs = new ArrayList<>(); + // TODO(corysmith): Convert to an immutable list builder, as there is no benefit to a NestedSet + // here, as it will already have been flattened. + NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); + CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + + // Set the busybox tool. + builder.add("--tool").add("PACKAGE").add("--"); if (resourceDependencies != null) { - builder - .addTransitiveFlag( - "--data", resourceDependencies.getTransitiveResourceContainers(), RESOURCE_DEP_TO_ARG) - .addTransitiveFlag( - "--directData", - resourceDependencies.getDirectResourceContainers(), - RESOURCE_DEP_TO_ARG) - .addTransitiveInputValues(resourceDependencies.getTransitiveResources()) - .addTransitiveInputValues(resourceDependencies.getTransitiveAssets()) - .addTransitiveInputValues(resourceDependencies.getTransitiveManifests()) - .addTransitiveInputValues(resourceDependencies.getTransitiveRTxt()) - .addTransitiveInputValues(resourceDependencies.getTransitiveSymbolsBin()); + ResourceContainerConverter.addToCommandLine( + resourceDependencies, builder, RESOURCE_DEP_TO_ARG); + inputs + .addTransitive(resourceDependencies.getTransitiveResources()) + .addTransitive(resourceDependencies.getTransitiveAssets()) + .addTransitive(resourceDependencies.getTransitiveManifests()) + .addTransitive(resourceDependencies.getTransitiveRTxt()) + .addTransitive(resourceDependencies.getTransitiveSymbolsBin()); } - addAssetDeps(builder).addAapt(AndroidAaptVersion.AAPT); + addAssetDeps(builder, inputs); - configureCommonFlags(dataContext, primaryResources, primaryAssets, primaryManifest, builder) - .maybeAddVectoredFlag( - "--prefilteredResources", resourceFilterFactory.getResourcesToIgnoreInExecution()) - .buildAndRegister("Processing Android resources", "AaptPackage"); - } + builder.addExecPath("--aapt", sdk.getAapt().getExecutable()); + configureCommonFlags(primaryResources, primaryAssets, primaryManifest, outs, inputs, builder); + + ImmutableList<String> filteredResources = + resourceFilterFactory.getResourcesToIgnoreInExecution(); + if (!filteredResources.isEmpty()) { + builder.addAll("--prefilteredResources", VectorArg.join(",").each(filteredResources)); + } - private BusyBoxActionBuilder addAssetDeps(BusyBoxActionBuilder builder) { + ParamFileInfo.Builder paramFileInfo = ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED); + // Some flags (e.g. --mainData) may specify lists (or lists of lists) separated by special + // characters (colon, semicolon, hashmark, ampersand) that don't work on Windows, and quoting + // semantics are very complicated (more so than in Bash), so let's just always use a parameter + // file. + // TODO(laszlocsomor), TODO(corysmith): restructure the Android BusyBux's flags by deprecating + // list-type and list-of-list-type flags that use such problematic separators in favor of + // multi-value flags (to remove one level of listing) and by changing all list separators to a + // platform-safe character (= comma). + paramFileInfo.setUseAlways(OS.getCurrent() == OS.WINDOWS); + + // Create the spawn action. + ruleContext.registerAction( + this.spawnActionBuilder + .useDefaultShellEnvironment() + .addTool(sdk.getAapt()) + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.copyOf(outs)) + .addCommandLine(builder.build(), paramFileInfo.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Processing Android resources for %s", ruleContext.getLabel()) + .setMnemonic("AaptPackage") + .build(ruleContext)); + } + + private void addAssetDeps(CustomCommandLine.Builder builder, NestedSetBuilder<Artifact> inputs) { if (assetDependencies == null || assetDependencies.getTransitiveAssets().isEmpty()) { - return builder; + return; } - return builder - .addTransitiveFlag( + builder + .addAll( "--directAssets", - assetDependencies.getDirectParsedAssets(), - AndroidDataConverter.MERGABLE_DATA_CONVERTER) - .addTransitiveFlag( + AndroidDataConverter.MERGABLE_DATA_CONVERTER.getVectorArg( + assetDependencies.getDirectParsedAssets())) + .addAll( "--assets", - assetDependencies.getTransitiveParsedAssets(), - AndroidDataConverter.MERGABLE_DATA_CONVERTER) - .addTransitiveInputValues(assetDependencies.getTransitiveAssets()) - .addTransitiveInputValues(assetDependencies.getTransitiveSymbols()); + AndroidDataConverter.MERGABLE_DATA_CONVERTER.getVectorArg( + assetDependencies.getTransitiveParsedAssets())); + + inputs.addTransitive(assetDependencies.getTransitiveAssets()); + inputs.addTransitive(assetDependencies.getTransitiveSymbols()); } - private BusyBoxActionBuilder configureCommonFlags( - AndroidDataContext dataContext, + private void configureCommonFlags( AndroidResources primaryResources, AndroidAssets primaryAssets, StampedAndroidManifest primaryManifest, - BusyBoxActionBuilder builder) { - - return builder - .addInput( - "--primaryData", - String.format( - "%s:%s:%s", - AndroidDataConverter.rootsToString(primaryResources.getResourceRoots()), - AndroidDataConverter.rootsToString(primaryAssets.getAssetRoots()), - primaryManifest.getManifest().getExecPathString()), - Iterables.concat( - primaryResources.getResources(), - primaryAssets.getAssets(), - ImmutableList.of(primaryManifest.getManifest()))) - .maybeAddFlag("--buildToolsVersion", dataContext.getSdk().getBuildToolsVersion()) - .addAndroidJar() - .maybeAddFlag("--packageType", isLibrary) - .maybeAddFlag("LIBRARY", isLibrary) - .maybeAddOutput("--rOutput", rTxtOut) - .maybeAddOutput("--symbolsOut", symbols) - .maybeAddOutput("--srcJarOutput", sourceJarOut) - .maybeAddOutput("--proguardOutput", proguardOut) - .maybeAddOutput("--mainDexProguardOutput", mainDexProguardOut) - .maybeAddOutput("--manifestOutput", manifestOut) - .maybeAddOutput("--resourcesOutput", mergedResourcesOut) - .maybeAddOutput("--packagePath", apkOut) - - // Always pass density and resource configuration filter strings to execution, even when - // filtering in analysis. Filtering in analysis cannot remove resources from Filesets, and, - // in addition, aapt needs access to resource filters to generate pseudolocalized resources - // and because its resource filtering is somewhat stricter for locales, and resource - // processing needs access to densities to add them to the manifest. - .maybeAddFlag("--resourceConfigs", resourceFilterFactory.getConfigurationFilterString()) - .maybeAddFlag("--densities", resourceFilterFactory.getDensityString()) - .maybeAddVectoredFlag("--uncompressedExtensions", uncompressedExtensions) - .maybeAddFlag("--useAaptCruncher=no", !crunchPng) - .maybeAddFlag("--debug", debug) - .maybeAddFlag("--versionCode", versionCode) - .maybeAddFlag("--versionName", versionName) - .maybeAddFlag("--applicationId", applicationId) - .maybeAddOutput("--dataBindingInfoOut", dataBindingInfoZip) - .maybeAddFlag("--packageForR", customJavaPackage) - .maybeAddInput("--featureOf", featureOf) - .maybeAddInput("--featureAfter", featureAfter) - .maybeAddFlag("--throwOnResourceConflict", throwOnResourceConflict) - .maybeAddFlag("--packageUnderTest", packageUnderTest) - .maybeAddFlag("--isTestWithResources", isTestWithResources); + List<Artifact> outs, + NestedSetBuilder<Artifact> inputs, + CustomCommandLine.Builder builder) { + + // Add data + builder.add( + "--primaryData", + String.format( + "%s:%s:%s", + AndroidDataConverter.rootsToString(primaryResources.getResourceRoots()), + AndroidDataConverter.rootsToString(primaryAssets.getAssetRoots()), + primaryManifest.getManifest().getExecPathString())); + inputs.addAll(primaryResources.getResources()); + inputs.addAll(primaryAssets.getAssets()); + inputs.add(primaryManifest.getManifest()); + + if (!Strings.isNullOrEmpty(sdk.getBuildToolsVersion())) { + builder.add("--buildToolsVersion", sdk.getBuildToolsVersion()); + } + + builder.addExecPath("--androidJar", sdk.getAndroidJar()); + inputs.add(sdk.getAndroidJar()); + + if (isLibrary) { + builder.add("--packageType").add("LIBRARY"); + } + + if (rTxtOut != null) { + builder.addExecPath("--rOutput", rTxtOut); + outs.add(rTxtOut); + } + + if (symbols != null) { + builder.addExecPath("--symbolsOut", symbols); + outs.add(symbols); + } + if (sourceJarOut != null) { + builder.addExecPath("--srcJarOutput", sourceJarOut); + outs.add(sourceJarOut); + } + if (proguardOut != null) { + builder.addExecPath("--proguardOutput", proguardOut); + outs.add(proguardOut); + } + + if (mainDexProguardOut != null) { + builder.addExecPath("--mainDexProguardOutput", mainDexProguardOut); + outs.add(mainDexProguardOut); + } + + if (manifestOut != null) { + builder.addExecPath("--manifestOutput", manifestOut); + outs.add(manifestOut); + } + + if (mergedResourcesOut != null) { + builder.addExecPath("--resourcesOutput", mergedResourcesOut); + outs.add(mergedResourcesOut); + } + + if (apkOut != null) { + builder.addExecPath("--packagePath", apkOut); + outs.add(apkOut); + } + + // Always pass density and resource configuration filter strings to execution, even when + // filtering in analysis. Filtering in analysis cannot remove resources from Filesets, and, in + // addition, aapt needs access to resource filters to generate pseudolocalized resources and + // because its resource filtering is somewhat stricter for locales, and + // resource processing needs access to densities to add them to the manifest. + if (resourceFilterFactory.hasConfigurationFilters()) { + builder.add("--resourceConfigs", resourceFilterFactory.getConfigurationFilterString()); + } + if (resourceFilterFactory.hasDensities()) { + builder.add("--densities", resourceFilterFactory.getDensityString()); + } + if (!uncompressedExtensions.isEmpty()) { + builder.addAll("--uncompressedExtensions", VectorArg.join(",").each(uncompressedExtensions)); + } + if (!crunchPng) { + builder.add("--useAaptCruncher=no"); + } + if (debug) { + builder.add("--debug"); + } + + if (versionCode != null) { + builder.add("--versionCode", versionCode); + } + + if (versionName != null) { + builder.add("--versionName", versionName); + } + + if (applicationId != null) { + builder.add("--applicationId", applicationId); + } + + if (dataBindingInfoZip != null) { + builder.addExecPath("--dataBindingInfoOut", dataBindingInfoZip); + outs.add(dataBindingInfoZip); + } + + if (!Strings.isNullOrEmpty(customJavaPackage)) { + // Sets an alternative java package for the generated R.java + // this allows android rules to generate resources outside of the java{,tests} tree. + builder.add("--packageForR", customJavaPackage); + } + + if (featureOf != null) { + builder.addExecPath("--featureOf", featureOf); + inputs.add(featureOf); + } + + if (featureAfter != null) { + builder.addExecPath("--featureAfter", featureAfter); + inputs.add(featureAfter); + } + + if (throwOnResourceConflict) { + builder.add("--throwOnResourceConflict"); + } + + if (packageUnderTest != null) { + builder.add("--packageUnderTest", packageUnderTest); + } + + if (isTestWithResources) { + builder.add("--isTestWithResources"); + } } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java index d93b8a2b7f..900f1056a9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java @@ -370,7 +370,6 @@ public final class ApplicationManifest { public ResourceApk packTestWithDataAndResources( RuleContext ruleContext, - AndroidDataContext dataContext, Artifact resourceApk, ResourceDependencies resourceDeps, @Nullable Artifact rTxt, @@ -391,7 +390,7 @@ public final class ApplicationManifest { .build(); AndroidResourcesProcessorBuilder builder = - new AndroidResourcesProcessorBuilder() + new AndroidResourcesProcessorBuilder(ruleContext) .setLibrary(false) .setApkOut(resourceContainer.getApk()) .setUncompressedExtensions(ImmutableList.of()) @@ -418,16 +417,16 @@ public final class ApplicationManifest { .setSymbols(resourceContainer.getSymbols()) .setSourceJarOut(resourceContainer.getJavaSourceJar()); } - ResourceContainer processed = builder.build(dataContext, resourceContainer); + ResourceContainer processed = builder.build(resourceContainer); ResourceContainer finalContainer = - new RClassGeneratorActionBuilder() + new RClassGeneratorActionBuilder(ruleContext) .targetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext)) .withDependencies(resourceDeps) .setClassJarOut( ruleContext.getImplicitOutputArtifact( AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR)) - .build(dataContext, processed); + .build(processed); return ResourceApk.of(finalContainer, resourceDeps, proguardCfg, mainDexProguardCfg); } @@ -435,7 +434,6 @@ public final class ApplicationManifest { /** Packages up the manifest with resource and assets from the LocalResourceContainer. */ public ResourceApk packAarWithDataAndResources( RuleContext ruleContext, - AndroidDataContext dataContext, AndroidAssets assets, AndroidResources resources, ResourceDependencies resourceDeps, @@ -457,14 +455,14 @@ public final class ApplicationManifest { ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR); resourceContainer = - new AndroidResourceParsingActionBuilder() + new AndroidResourceParsingActionBuilder(ruleContext) .setAssets(assets) .setResources(resources) .setOutput(symbols) - .buildAndUpdate(dataContext, resourceContainer); + .buildAndUpdate(ruleContext, resourceContainer); ResourceContainer merged = - new AndroidResourceMergingActionBuilder() + new AndroidResourceMergingActionBuilder(ruleContext) .setJavaPackage(resourceContainer.getJavaPackage()) .withDependencies(resourceDeps) .setMergedResourcesOut(mergedResources) @@ -475,10 +473,10 @@ public final class ApplicationManifest { .getConfiguration() .getFragment(AndroidConfiguration.class) .throwOnResourceConflict()) - .build(dataContext, resourceContainer); + .build(ruleContext, resourceContainer); ResourceContainer processed = - new AndroidResourceValidatorActionBuilder() + new AndroidResourceValidatorActionBuilder(ruleContext) .setJavaPackage(merged.getJavaPackage()) .setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT) .setMergedResources(mergedResources) @@ -491,7 +489,7 @@ public final class ApplicationManifest { .setAapt2RTxtOut(merged.getAapt2RTxt()) .setAapt2SourceJarOut(merged.getAapt2JavaSourceJar()) .setStaticLibraryOut(merged.getStaticLibrary()) - .build(dataContext, merged); + .build(ruleContext, merged); return ResourceApk.of(processed, resourceDeps); } @@ -499,7 +497,6 @@ public final class ApplicationManifest { /* Creates an incremental apk from assets and data. */ public ResourceApk packIncrementalBinaryWithDataAndResources( RuleContext ruleContext, - AndroidDataContext dataContext, Artifact resourceApk, ResourceDependencies resourceDeps, List<String> uncompressedExtensions, @@ -528,7 +525,7 @@ public final class ApplicationManifest { .build(); ResourceContainer processed = - new AndroidResourcesProcessorBuilder() + new AndroidResourcesProcessorBuilder(ruleContext) .setLibrary(false) .setApkOut(resourceContainer.getApk()) .setResourceFilterFactory(resourceFilterFactory) @@ -547,7 +544,7 @@ public final class ApplicationManifest { .getFragment(AndroidConfiguration.class) .throwOnResourceConflict()) .setPackageUnderTest(null) - .build(dataContext, resourceContainer); + .build(resourceContainer); // Intentionally skip building an R class JAR - incremental binaries handle this separately. @@ -558,7 +555,6 @@ public final class ApplicationManifest { // TODO(bazel-team): this method calls for some refactoring, 15+ params including some nullables. public ResourceApk packBinaryWithDataAndResources( RuleContext ruleContext, - AndroidDataContext dataContext, Artifact resourceApk, ResourceDependencies resourceDeps, @Nullable Artifact rTxt, @@ -604,7 +600,7 @@ public final class ApplicationManifest { } ResourceContainer processed = - new AndroidResourcesProcessorBuilder() + new AndroidResourcesProcessorBuilder(ruleContext) .setLibrary(false) .setApkOut(resourceContainer.getApk()) .setResourceFilterFactory(resourceFilterFactory) @@ -630,23 +626,22 @@ public final class ApplicationManifest { .setRTxtOut(resourceContainer.getRTxt()) .setSymbols(resourceContainer.getSymbols()) .setSourceJarOut(resourceContainer.getJavaSourceJar()) - .build(dataContext, resourceContainer); + .build(resourceContainer); ResourceContainer finalContainer = - new RClassGeneratorActionBuilder() + new RClassGeneratorActionBuilder(ruleContext) .targetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext)) .withDependencies(resourceDeps) .setClassJarOut( ruleContext.getImplicitOutputArtifact( AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR)) - .build(dataContext, processed); + .build(processed); return ResourceApk.of(finalContainer, resourceDeps, proguardCfg, mainDexProguardCfg); } public ResourceApk packLibraryWithDataAndResources( RuleContext ruleContext, - AndroidDataContext dataContext, ResourceDependencies resourceDeps, Artifact rTxt, Artifact symbols, @@ -694,7 +689,7 @@ public final class ApplicationManifest { targetAaptVersion == AndroidAaptVersion.AAPT2 && androidConfiguration.skipParsingAction(); AndroidResourceParsingActionBuilder parsingBuilder = - new AndroidResourceParsingActionBuilder() + new AndroidResourceParsingActionBuilder(ruleContext) .setAssets(assets) .setResources(resources) .setOutput(resourceContainer.getSymbols()) @@ -713,10 +708,10 @@ public final class ApplicationManifest { .setManifest(resourceContainer.getManifest()) .setJavaPackage(resourceContainer.getJavaPackage()); } - resourceContainer = parsingBuilder.buildAndUpdate(dataContext, resourceContainer); + resourceContainer = parsingBuilder.buildAndUpdate(ruleContext, resourceContainer); ResourceContainer merged = - new AndroidResourceMergingActionBuilder() + new AndroidResourceMergingActionBuilder(ruleContext) .setJavaPackage(resourceContainer.getJavaPackage()) .withDependencies(resourceDeps) .setThrowOnResourceConflict(androidConfiguration.throwOnResourceConflict()) @@ -726,10 +721,10 @@ public final class ApplicationManifest { .setManifestOut(manifestOut) .setClassJarOut(rJavaClassJar) .setDataBindingInfoZip(dataBindingInfoZip) - .build(dataContext, resourceContainer); + .build(ruleContext, resourceContainer); ResourceContainer processed = - new AndroidResourceValidatorActionBuilder() + new AndroidResourceValidatorActionBuilder(ruleContext) .setJavaPackage(merged.getJavaPackage()) .setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT) .setMergedResources(mergedResources) @@ -742,7 +737,7 @@ public final class ApplicationManifest { .setAapt2RTxtOut(merged.getAapt2RTxt()) .setAapt2SourceJarOut(merged.getAapt2JavaSourceJar()) .setStaticLibraryOut(merged.getStaticLibrary()) - .build(dataContext, merged); + .build(ruleContext, merged); return ResourceApk.of(processed, resourceDeps); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java index 16e55f8993..07552fe2c1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java @@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ParamFileInfo; import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; import com.google.devtools.build.lib.analysis.actions.SpawnAction; @@ -50,7 +49,7 @@ public final class BusyBoxActionBuilder { private final AndroidDataContext dataContext; private final NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); private final ImmutableList.Builder<Artifact> outputs = ImmutableList.builder(); - private final SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); + private final ImmutableList.Builder<Artifact> tools = ImmutableList.builder(); private final CustomCommandLine.Builder commandLine = CustomCommandLine.builder(); public static BusyBoxActionBuilder create( @@ -288,16 +287,16 @@ public final class BusyBoxActionBuilder { /** Adds aapt to the command line and inputs. */ public BusyBoxActionBuilder addAapt(AndroidAaptVersion aaptVersion) { - FilesToRunProvider aapt; + Artifact aapt; if (aaptVersion == AndroidAaptVersion.AAPT2) { - aapt = dataContext.getSdk().getAapt2(); - commandLine.addExecPath("--aapt2", aapt.getExecutable()); + aapt = dataContext.getSdk().getAapt2().getExecutable(); + commandLine.addExecPath("--aapt2", aapt); } else { - aapt = dataContext.getSdk().getAapt(); - commandLine.addExecPath("--aapt", aapt.getExecutable()); + aapt = dataContext.getSdk().getAapt().getExecutable(); + commandLine.addExecPath("--aapt", aapt); } - spawnActionBuilder.addTool(aapt); + tools.add(aapt); return this; } @@ -316,10 +315,11 @@ public final class BusyBoxActionBuilder { */ public void buildAndRegister(String message, String mnemonic) { dataContext.registerAction( - spawnActionBuilder + new SpawnAction.Builder() .useDefaultShellEnvironment() .addTransitiveInputs(inputs.build()) .addOutputs(outputs.build()) + .addTools(tools.build()) .addCommandLine(commandLine.build(), FORCED_PARAM_FILE_INFO) .setExecutable(dataContext.getBusybox()) .setProgressMessage("%s for %s", message, dataContext.getLabel()) diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java index 29da58659f..da7ceda7b4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidResources.java @@ -54,7 +54,7 @@ public class MergedAndroidResources extends ParsedAndroidResources { "Should not use compiled merge if no compiled symbols are available!"); AndroidResourceMergingActionBuilder builder = - new AndroidResourceMergingActionBuilder() + new AndroidResourceMergingActionBuilder(dataContext.getRuleContext()) .setJavaPackage(parsed.getJavaPackage()) .withDependencies(resourceDeps) .setThrowOnResourceConflict(androidConfiguration.throwOnResourceConflict()) @@ -72,7 +72,7 @@ public class MergedAndroidResources extends ParsedAndroidResources { dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP)) .setClassJarOut( dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR)) - .build(dataContext, parsed); + .build(dataContext.getRuleContext(), parsed); } public static MergedAndroidResources of( diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidAssets.java b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidAssets.java index b1b2971045..265f22f9d6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidAssets.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidAssets.java @@ -24,9 +24,9 @@ public class ParsedAndroidAssets extends AndroidAssets implements MergableAndroi public static ParsedAndroidAssets parseFrom(AndroidDataContext dataContext, AndroidAssets assets) throws InterruptedException { - return new AndroidResourceParsingActionBuilder() + return new AndroidResourceParsingActionBuilder(dataContext.getRuleContext()) .setOutput(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_ASSET_SYMBOLS)) - .build(dataContext, assets); + .build(assets); } public static ParsedAndroidAssets of(AndroidAssets assets, Artifact symbols, Label label) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java index 83b49b62d1..4ff37879c9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidResources.java @@ -40,14 +40,15 @@ public class ParsedAndroidResources extends AndroidResources boolean isAapt2 = aaptVersion == AndroidAaptVersion.AAPT2; - AndroidResourceParsingActionBuilder builder = new AndroidResourceParsingActionBuilder(); + AndroidResourceParsingActionBuilder builder = + new AndroidResourceParsingActionBuilder(dataContext.getRuleContext()); if (enableDataBinding && isAapt2) { // TODO(corysmith): Centralize the data binding processing and zipping into a single // action. Data binding processing needs to be triggered here as well as the merger to // avoid aapt2 from throwing an error during compilation. builder.setDataBindingInfoZip( - DataBinding.getSuffixedInfoFile(dataContext.getActionConstructionContext(), "_unused")); + DataBinding.getSuffixedInfoFile(dataContext.getRuleContext(), "_unused")); } return builder @@ -56,7 +57,7 @@ public class ParsedAndroidResources extends AndroidResources isAapt2 ? dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_COMPILED_SYMBOLS) : null) - .build(dataContext, resources, manifest); + .build(resources, manifest); } public static ParsedAndroidResources of( diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java index a9d4267978..cbb1034924 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java @@ -95,7 +95,6 @@ public class ProcessedAndroidData { .setFeatureOf(featureOf) .setFeatureAfter(featureAfter); return buildActionForBinary( - dataContext, errorConsumer, builder, manifest, @@ -122,7 +121,6 @@ public class ProcessedAndroidData { .setApkOut(apkOut); return buildActionForBinary( - dataContext, ruleContext, builder, manifest, @@ -136,7 +134,6 @@ public class ProcessedAndroidData { } private static ProcessedAndroidData buildActionForBinary( - AndroidDataContext dataContext, RuleErrorConsumer errorConsumer, AndroidResourcesProcessorBuilder builder, StampedAndroidManifest manifest, @@ -162,7 +159,7 @@ public class ProcessedAndroidData { .setCrunchPng(crunchPng) .withResourceDependencies(resourceDeps) .withAssetDependencies(assetDeps) - .build(dataContext, resources, assets, manifest); + .build(resources, assets, manifest); } /** Processes Android data (assets, resources, and manifest) for android_local_test targets. */ @@ -189,7 +186,7 @@ public class ProcessedAndroidData { .setCrunchPng(false) .withResourceDependencies(resourceDeps) .withAssetDependencies(assetDeps) - .build(dataContext, resources, assets, manifest); + .build(resources, assets, manifest); } /** Processes Android data (assets, resources, and manifest) for android_test targets. */ @@ -216,7 +213,7 @@ public class ProcessedAndroidData { .withResourceDependencies(resourceDeps) .withAssetDependencies(assetDeps); - return builder.build(dataContext, resources, assets, manifest); + return builder.build(resources, assets, manifest); } /** @@ -252,7 +249,7 @@ public class ProcessedAndroidData { StampedAndroidManifest manifest, String proguardPrefix, Map<String, String> manifestValues) { - return new AndroidResourcesProcessorBuilder() + return new AndroidResourcesProcessorBuilder(dataContext.getRuleContext()) // Settings .setDebug(dataContext.useDebug()) .setJavaPackage(manifest.getPackage()) @@ -324,12 +321,12 @@ public class ProcessedAndroidData { */ public ResourceApk generateRClass(AndroidDataContext dataContext, AndroidAaptVersion aaptVersion) throws InterruptedException { - return new RClassGeneratorActionBuilder() + return new RClassGeneratorActionBuilder(dataContext.getRuleContext()) .targetAaptVersion(aaptVersion) .withDependencies(resourceDeps) .setClassJarOut( dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR)) - .build(dataContext, this); + .build(this); } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java index c4e33f1eee..849881297c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/RClassGeneratorActionBuilder.java @@ -13,9 +13,21 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.ParamFileInfo; +import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.Builder; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; import com.google.devtools.build.lib.rules.android.AndroidDataConverter.JoinerType; +import java.util.ArrayList; +import java.util.List; import java.util.function.Function; /** Builds up the spawn action for $android_rclass_generator. */ @@ -30,12 +42,18 @@ public class RClassGeneratorActionBuilder { .with(chooseDepsToArg(AndroidAaptVersion.AAPT2)) .build(); + private final RuleContext ruleContext; private ResourceDependencies dependencies; private Artifact classJarOut; private AndroidAaptVersion version; + /** @param ruleContext The RuleContext that is used to create a SpawnAction.Builder. */ + public RClassGeneratorActionBuilder(RuleContext ruleContext) { + this.ruleContext = ruleContext; + } + public RClassGeneratorActionBuilder withDependencies(ResourceDependencies resourceDeps) { this.dependencies = resourceDeps; return this; @@ -51,43 +69,72 @@ public class RClassGeneratorActionBuilder { return this; } - public ResourceContainer build(AndroidDataContext dataContext, ResourceContainer primary) { - build(dataContext, primary.getRTxt(), ProcessedAndroidManifest.from(primary)); + public ResourceContainer build(ResourceContainer primary) { + build(primary.getRTxt(), ProcessedAndroidManifest.from(primary)); return primary.toBuilder().setJavaClassJar(classJarOut).build(); } - public ResourceApk build(AndroidDataContext dataContext, ProcessedAndroidData data) { - build(dataContext, data.getRTxt(), data.getManifest()); + public ResourceApk build(ProcessedAndroidData data) { + build(data.getRTxt(), data.getManifest()); return data.withValidatedResources(classJarOut); } - private void build( - AndroidDataContext dataContext, Artifact rTxt, ProcessedAndroidManifest manifest) { - BusyBoxActionBuilder builder = - BusyBoxActionBuilder.create(dataContext, "GENERATE_BINARY_R") - .addInput("--primaryRTxt", rTxt) - .addInput("--primaryManifest", manifest.getManifest()) - .maybeAddFlag("--packageForR", manifest.getPackage()); - - if (dependencies != null && !dependencies.getResourceContainers().isEmpty()) { - builder - .addTransitiveFlagForEach( - "--library", - dependencies.getResourceContainers(), - version == AndroidAaptVersion.AAPT2 ? AAPT2_CONVERTER : AAPT_CONVERTER) - .addTransitiveInputValues( - version == AndroidAaptVersion.AAPT2 - ? dependencies.getTransitiveAapt2RTxt() - : dependencies.getTransitiveRTxt()) - .addTransitiveInputValues(dependencies.getTransitiveManifests()); + private void build(Artifact rTxt, ProcessedAndroidManifest manifest) { + Builder builder = new Builder(); + + // Set the busybox tool. + builder.add("--tool").add("GENERATE_BINARY_R").add("--"); + + NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); + inputs.addAll( + ruleContext + .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST) + .getRunfilesSupport() + .getRunfilesArtifacts()); + + List<Artifact> outs = new ArrayList<>(); + builder.addExecPath("--primaryRTxt", rTxt); + inputs.add(rTxt); + builder.addExecPath("--primaryManifest", manifest.getManifest()); + inputs.add(manifest.getManifest()); + if (!Strings.isNullOrEmpty(manifest.getPackage())) { + builder.add("--packageForR", manifest.getPackage()); } - - builder - .addOutput("--classJarOutput", classJarOut) - .addLabelFlag("--targetLabel") - .buildAndRegister("Generating R Classes", "RClassGenerator"); + if (dependencies != null) { + if (!dependencies.getResourceContainers().isEmpty()) { + builder.addAll( + VectorArg.addBefore("--library") + .each(dependencies.getResourceContainers()) + .mapped(version == AndroidAaptVersion.AAPT2 ? AAPT2_CONVERTER : AAPT_CONVERTER)); + if (version == AndroidAaptVersion.AAPT2) { + inputs.addTransitive(dependencies.getTransitiveAapt2RTxt()); + } else { + inputs.addTransitive(dependencies.getTransitiveRTxt()); + } + inputs.addTransitive(dependencies.getTransitiveManifests()); + } + } + builder.addExecPath("--classJarOutput", classJarOut); + outs.add(classJarOut); + builder.addLabel("--targetLabel", ruleContext.getLabel()); + + // Create the spawn action. + SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); + + ruleContext.registerAction( + spawnActionBuilder + .useDefaultShellEnvironment() + .addTransitiveInputs(inputs.build()) + .addOutputs(ImmutableList.<Artifact>copyOf(outs)) + .addCommandLine( + builder.build(), ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED).build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) + .setProgressMessage("Generating R Classes: %s", ruleContext.getLabel()) + .setMnemonic("RClassGenerator") + .build(ruleContext)); } private static Function<ValidatedAndroidData, String> chooseDepsToArg( diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java index 99d545d097..46048e90a1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java @@ -304,7 +304,7 @@ public final class ResourceApk { StampedAndroidManifest manifest) throws InterruptedException { - return new AndroidResourcesProcessorBuilder() + return new AndroidResourcesProcessorBuilder(dataContext.getRuleContext()) .setLibrary(true) .setRTxtOut(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT)) .setManifestOut( @@ -316,6 +316,6 @@ public final class ResourceApk { .withAssetDependencies(assetDeps) .setDebug(dataContext.useDebug()) .setThrowOnResourceConflict(dataContext.getAndroidConfig().throwOnResourceConflict()) - .buildWithoutLocalResources(dataContext, manifest); + .buildWithoutLocalResources(manifest); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java index b84803e4f0..7abd103de8 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ValidatedAndroidResources.java @@ -56,7 +56,7 @@ public class ValidatedAndroidResources extends MergedAndroidResources AndroidDataContext dataContext, MergedAndroidResources merged, AndroidAaptVersion aaptVersion) throws InterruptedException { AndroidResourceValidatorActionBuilder builder = - new AndroidResourceValidatorActionBuilder() + new AndroidResourceValidatorActionBuilder(dataContext.getRuleContext()) .setJavaPackage(merged.getJavaPackage()) .setDebug(dataContext.useDebug()) .setMergedResources(merged.getMergedResources()) @@ -82,7 +82,7 @@ public class ValidatedAndroidResources extends MergedAndroidResources AndroidRuleClasses.ANDROID_RESOURCES_AAPT2_LIBRARY_APK)); } - return builder.build(dataContext, merged); + return builder.build(dataContext.getRuleContext(), merged); } static ValidatedAndroidResources of( |