diff options
6 files changed, 166 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java index d0bac081e9..0d9fbb7d50 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java @@ -948,6 +948,11 @@ public final class AndroidRuleClasses { .undocumented("blocked by android_instrumentation_test") .allowedRuleClasses("android_binary") .allowedFileTypes(NO_FILE)) + .add( + attr("$zip_filter", LABEL) + .cfg(HOST) + .exec() + .value(env.getToolsLabel("//tools/android:zip_filter"))) .advertiseSkylarkProvider(SkylarkProviderIdentifier.forKey(JavaInfo.PROVIDER.getKey())) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ZipFilterBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ZipFilterBuilder.java new file mode 100644 index 0000000000..e3e83a3ffb --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ZipFilterBuilder.java @@ -0,0 +1,135 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.rules.android; + +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.actions.Artifact; +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; + +/** + * Builder for creating a zip filter action. + */ +public class ZipFilterBuilder { + /** + * Type of compression to apply to output archive. + */ + public enum Compression { + /** Output should be compressed. */ + COMPRESSED, + /** Output should not be compressed. */ + UNCOMPRESSED, + /** Compression should not change from input Zip. */ + DONT_CHANGE; + } + + private final RuleContext ruleContext; + private Artifact inputZip; + private Artifact outputZip; + private final ImmutableSet.Builder<Artifact> filterZipsBuilder; + private final ImmutableSet.Builder<String> filterFileTypesBuilder; + private final ImmutableSet.Builder<String> explicitFilterBuilder; + private Compression outputMode = Compression.DONT_CHANGE; + + /** Creates a builder using the configuration of the rule as the action configuration. */ + public ZipFilterBuilder(RuleContext ruleContext) { + this.ruleContext = ruleContext; + filterZipsBuilder = new ImmutableSet.Builder<>(); + filterFileTypesBuilder = new ImmutableSet.Builder<>(); + explicitFilterBuilder = new ImmutableSet.Builder<>(); + } + + /** Sets the Zip file to be filtered. */ + public ZipFilterBuilder setInputZip(Artifact inputZip) { + this.inputZip = inputZip; + return this; + } + + /** Sets the artifact to create with the action. */ + public ZipFilterBuilder setOutputZip(Artifact outputZip) { + this.outputZip = outputZip; + return this; + } + + /** + * Adds to the Zip files to use as filters. Contents in these files will be omitted from the + * output. + */ + public ZipFilterBuilder addFilterZips(Iterable<Artifact> filterZips) { + this.filterZipsBuilder.addAll(filterZips); + return this; + } + + /** + * Adds to the file types to use as filters. Only contents in the filter Zip files with these + * extensions will be filtered out. + */ + public ZipFilterBuilder addFileTypeToFilter(String filterFileType) { + this.filterFileTypesBuilder.add(filterFileType); + return this; + } + + /** Adds filterRegex to the set of filters to always check for and remove. */ + public ZipFilterBuilder addExplicitFilter(String filterRegex) { + this.explicitFilterBuilder.add(filterRegex); + return this; + } + + /** Builds the action as configured. */ + public void build() { + ImmutableSet<Artifact> filterZips = filterZipsBuilder.build(); + ImmutableSet<String> filterFileTypes = filterFileTypesBuilder.build(); + ImmutableSet<String> explicitFilters = explicitFilterBuilder.build(); + + CustomCommandLine.Builder args = CustomCommandLine.builder(); + args.addExecPath("--inputZip", inputZip); + args.addExecPath("--outputZip", outputZip); + if (!filterZips.isEmpty()) { + args.addExecPaths("--filterZips", VectorArg.join(",").each(filterZips)); + } + if (!filterFileTypes.isEmpty()) { + args.addAll("--filterTypes", VectorArg.join(",").each(filterFileTypes)); + } + if (!explicitFilters.isEmpty()) { + args.addAll("--explicitFilters", VectorArg.join(",").each(explicitFilters)); + } + args.add("--outputMode"); + switch (outputMode) { + case COMPRESSED: + args.add("FORCE_DEFLATE"); + break; + case UNCOMPRESSED: + args.add("FORCE_STORED"); + break; + case DONT_CHANGE: + default: + args.add("DONT_CARE"); + break; + } + + ruleContext.registerAction( + new SpawnAction.Builder() + .addInput(inputZip) + .addInputs(filterZips) + .addOutput(outputZip) + .setExecutable(ruleContext.getExecutablePrerequisite("$zip_filter", Mode.HOST)) + .addCommandLine(args.build()) + .setProgressMessage("Filtering Zip %s", inputZip.prettyPrint()) + .setMnemonic("ZipFilter") + .build(ruleContext)); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java index 423f20c290..626bbdcceb 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java @@ -238,6 +238,11 @@ public final class BazelAnalysisMock extends AnalysisMock { .add("java_binary(name = 'IdlClass',") .add(" runtime_deps = [ ':idlclass_import' ],") .add(" main_class = 'com.google.devtools.build.android.idlclass.IdlClass')") + .add("java_binary(name = 'zip_filter',") + .add(" main_class = 'com.google.devtools.build.android.ZipFilterAction',") + .add(" runtime_deps = [ ':ZipFilterAction_import' ])") + .add("java_import(name = 'ZipFilterAction_import',") + .add(" jars = [ 'ZipFilterAction_deploy.jar' ])") .add("sh_binary(name = 'aar_resources_extractor', srcs = ['empty.sh'])") .add("sh_binary(name = 'aar_embedded_jars_extractor', srcs = ['empty.sh'])") .add("java_import(name = 'idlclass_import',") diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD b/src/tools/android/java/com/google/devtools/build/android/BUILD index 6bf42f53e3..d563c772df 100644 --- a/src/tools/android/java/com/google/devtools/build/android/BUILD +++ b/src/tools/android/java/com/google/devtools/build/android/BUILD @@ -40,6 +40,10 @@ java_binary( java_binary( name = "ZipFilterAction", + # Memory consumption of SingleJar is about 250 bytes per entry in the output file. Unfortunately, + # the JVM tends to kill the process with an OOM long before we're at the limit. In the most + # recent example, 400 MB of memory was enough for about 500,000 entries. + jvm_flags = ["-Xmx1600m"], main_class = "com.google.devtools.build.android.ZipFilterAction", visibility = ["//visibility:private"], runtime_deps = [":android_builder_lib"], diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD.tools b/src/tools/android/java/com/google/devtools/build/android/BUILD.tools index f0f858b6db..26b66d2496 100644 --- a/src/tools/android/java/com/google/devtools/build/android/BUILD.tools +++ b/src/tools/android/java/com/google/devtools/build/android/BUILD.tools @@ -17,3 +17,15 @@ java_binary( ":all_android_tools", ], ) + +java_binary( + name = "ZipFilterAction", + # Memory consumption of SingleJar is about 250 bytes per entry in the output file. Unfortunately, + # the JVM tends to kill the process with an OOM long before we're at the limit. In the most + # recent example, 400 MB of memory was enough for about 500,000 entries. + jvm_flags = ["-Xmx1600m"], + main_class = "com.google.devtools.build.android.ZipFilterAction", + runtime_deps = [ + ":all_android_tools" + ], +) diff --git a/tools/android/BUILD.tools b/tools/android/BUILD.tools index 8459ff3d9b..6826d52235 100644 --- a/tools/android/BUILD.tools +++ b/tools/android/BUILD.tools @@ -50,6 +50,11 @@ alias( actual = "//src/tools/android/java/com/google/devtools/build/android/desugar:Desugar", ) +alias( + name = "zip_filter", + actual = "//src/tools/android/java/com/google/devtools/build/android:ZipFilterAction", +) + # Bazel puts this on the bootclasspath of android_* targets to support Java 8 # if requested. filegroup( |