aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules
diff options
context:
space:
mode:
authorGravatar asteinb <asteinb@google.com>2018-04-17 07:09:31 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-04-17 07:11:07 -0700
commitb701530ca8beaf190143b502828f4d91132981b1 (patch)
tree573ce823952eb297fe4e65aa9ca3511bedc57c9d /src/main/java/com/google/devtools/build/lib/rules
parent451cfecf840c1148aae557f9f133f6a884d8411a (diff)
Independently merge assets
Merges assets using the newly created action. Also, add BusyBoxActionBuilder to collect common boilerplate for spawning an action that invokes the Android busybox. RELNOTES: none PiperOrigin-RevId: 193192621
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataConverter.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidResourceMergingActionBuilder.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java137
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidAssets.java102
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ParsedAndroidAssets.java10
7 files changed, 270 insertions, 6 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java
index f7e0273694..a20b818cc1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java
@@ -128,6 +128,12 @@ public class AndroidAssets {
return ParsedAndroidAssets.parseFrom(ruleContext, this);
}
+ /** Convenience method to do all of asset processing - parsing and merging. */
+ public MergedAndroidAssets process(RuleContext ruleContext, boolean neverlink)
+ throws InterruptedException {
+ return parse(ruleContext).merge(ruleContext, neverlink);
+ }
+
@Override
public boolean equals(Object object) {
if (object == null || getClass() != object.getClass()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataConverter.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataConverter.java
index a7ecccd2e2..c6f2d5cc26 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataConverter.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataConverter.java
@@ -32,6 +32,18 @@ import java.util.stream.Collectors;
*/
public class AndroidDataConverter<T> extends ParametrizedMapFn<T> {
+ /**
+ * Converts Android data to the "SerializedAndroidData" format used by the Android data processing
+ * actions.
+ */
+ static final AndroidDataConverter<MergableAndroidData> MERGABLE_DATA_CONVERTER =
+ AndroidDataConverter.<MergableAndroidData>builder(JoinerType.SEMICOLON_AMPERSAND)
+ .withRoots(MergableAndroidData::getResourceRoots)
+ .withRoots(MergableAndroidData::getAssetRoots)
+ .withLabel(MergableAndroidData::getLabel)
+ .withArtifact(MergableAndroidData::getSymbols)
+ .build();
+
/** Indicates the type of joiner between options expected by the command line. */
public enum JoinerType {
COLON_COMMA(":", ","),
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 328ba14ed6..c1b1239467 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
@@ -41,12 +41,7 @@ import javax.annotation.Nullable;
public class AndroidResourceMergingActionBuilder {
private static final AndroidDataConverter<MergableAndroidData> RESOURCE_CONTAINER_TO_ARG =
- AndroidDataConverter.<MergableAndroidData>builder(JoinerType.SEMICOLON_AMPERSAND)
- .withRoots(MergableAndroidData::getResourceRoots)
- .withRoots(MergableAndroidData::getAssetRoots)
- .withLabel(MergableAndroidData::getLabel)
- .withArtifact(MergableAndroidData::getSymbols)
- .build();
+ AndroidDataConverter.MERGABLE_DATA_CONVERTER;
private static final AndroidDataConverter<CompiledMergableAndroidData>
RESOURCE_CONTAINER_TO_ARG_FOR_COMPILED =
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 433fc7f562..b40413e116 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
@@ -111,6 +111,8 @@ public final class AndroidRuleClasses {
fromTemplates("%{name}_shrunk.ap_");
public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_ZIP =
fromTemplates("%{name}_files/resource_files.zip");
+ public static final SafeImplicitOutputsFunction ANDROID_ASSETS_ZIP =
+ fromTemplates("%{name}_files/assets.zip");
public static final SafeImplicitOutputsFunction ANDROID_RESOURCES_SHRUNK_ZIP =
fromTemplates("%{name}_files/resource_files_shrunk.zip");
public static final SafeImplicitOutputsFunction ANDROID_RESOURCE_SHRINKER_LOG =
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
new file mode 100644
index 0000000000..463022c295
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
@@ -0,0 +1,137 @@
+// Copyright 2018 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.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;
+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.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.util.OS;
+import com.google.errorprone.annotations.CompileTimeConstant;
+
+/** Builder for actions that invoke the Android BusyBox. */
+public final class BusyBoxActionBuilder {
+
+ // 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).
+ private static final ParamFileInfo FORCED_PARAM_FILE_INFO =
+ ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED)
+ .setUseAlways(OS.getCurrent() == OS.WINDOWS)
+ .build();
+
+ private final RuleContext ruleContext;
+ private final NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
+ private final ImmutableList.Builder<Artifact> outputs = ImmutableList.builder();
+ private final CustomCommandLine.Builder commandLine = CustomCommandLine.builder();
+
+ public static BusyBoxActionBuilder create(
+ RuleContext ruleContext, @CompileTimeConstant String toolName) {
+ BusyBoxActionBuilder builder = new BusyBoxActionBuilder(ruleContext);
+ builder.commandLine.add("--tool").add(toolName).add("--");
+ return builder;
+ }
+
+ private BusyBoxActionBuilder(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ }
+
+ public BusyBoxActionBuilder addInput(@CompileTimeConstant String arg, Artifact value) {
+ commandLine.addExecPath(arg, value);
+ inputs.add(value);
+ return this;
+ }
+
+ /**
+ * Adds a series of input artifacts. For efficiency, when adding a NestedSet of artifacts, use
+ * {@link #addTransitiveFlag(String, NestedSet, AndroidDataConverter)} and {@link
+ * #addTransitiveInputValues(NestedSet)} instead.
+ */
+ public BusyBoxActionBuilder addInput(
+ @CompileTimeConstant String arg, String value, Iterable<Artifact> valueArtifacts) {
+ commandLine.add(arg, value);
+ inputs.addAll(valueArtifacts);
+ return this;
+ }
+
+ public BusyBoxActionBuilder addOutput(@CompileTimeConstant String arg, Artifact value) {
+ commandLine.addExecPath(arg, value);
+ outputs.add(value);
+ return this;
+ }
+
+ /**
+ * Adds a series of transitive input artifacts.
+ *
+ * <p>These artifacts will not be mentioned on the command line - use {@link
+ * #addTransitiveFlag(String, NestedSet, AndroidDataConverter)} for that.
+ */
+ public BusyBoxActionBuilder addTransitiveInputValues(NestedSet<Artifact> values) {
+ inputs.addTransitive(values);
+ return this;
+ }
+
+ /**
+ * Adds an efficient flag based on transitive values.
+ *
+ * <p>The values will only be collapsed and turned into a flag at execution time.
+ *
+ * <p>The values will not be added as inputs - use {@link #addTransitiveInputValues(NestedSet)}
+ * for that.
+ */
+ public <T> BusyBoxActionBuilder addTransitiveFlag(
+ @CompileTimeConstant String arg,
+ NestedSet<? extends T> transitiveValues,
+ AndroidDataConverter<T> converter) {
+ commandLine.addAll(arg, converter.getVectorArg(transitiveValues));
+ return this;
+ }
+
+ public BusyBoxActionBuilder addFlag(@CompileTimeConstant String value) {
+ commandLine.add(value);
+ return this;
+ }
+
+ /**
+ * Builds and registers this action.
+ *
+ * @param message a progress message (visible in Bazel output), for example "Running tool". The
+ * current label will be appended to this message.
+ * @param mnemonic a mnemonic used to indicate the tool being run, for example, "BusyBoxTool".
+ */
+ public void buildAndRegister(String message, String mnemonic) {
+ ruleContext.registerAction(
+ new SpawnAction.Builder()
+ .useDefaultShellEnvironment()
+ .addTransitiveInputs(inputs.build())
+ .addOutputs(outputs.build())
+ .addCommandLine(commandLine.build(), FORCED_PARAM_FILE_INFO)
+ .setExecutable(
+ ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST))
+ .setProgressMessage("%s for %s", message, ruleContext.getLabel())
+ .setMnemonic(mnemonic)
+ .build(ruleContext));
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidAssets.java b/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidAssets.java
new file mode 100644
index 0000000000..ccffbc3d25
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/MergedAndroidAssets.java
@@ -0,0 +1,102 @@
+// Copyright 2018 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.annotations.VisibleForTesting;
+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.analysis.RuleContext;
+import java.util.Objects;
+
+/** Android assets that have been merged together with their dependencies. */
+public class MergedAndroidAssets extends ParsedAndroidAssets {
+ private final Artifact mergedAssets;
+ private final AssetDependencies assetDependencies;
+
+ public static MergedAndroidAssets mergeFrom(
+ RuleContext ruleContext, ParsedAndroidAssets parsed, boolean neverlink)
+ throws InterruptedException {
+ return mergeFrom(ruleContext, parsed, AssetDependencies.fromRuleDeps(ruleContext, neverlink));
+ }
+
+ @VisibleForTesting
+ static MergedAndroidAssets mergeFrom(
+ RuleContext ruleContext, ParsedAndroidAssets parsed, AssetDependencies deps)
+ throws InterruptedException {
+
+ Artifact mergedAssets =
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_ASSETS_ZIP);
+
+ BusyBoxActionBuilder builder = BusyBoxActionBuilder.create(ruleContext, "MERGE_ASSETS");
+ if (AndroidCommon.getAndroidConfig(ruleContext).throwOnResourceConflict()) {
+ builder.addFlag("--throwOnAssetConflict");
+ }
+
+ builder
+ .addOutput("--assetsOutput", mergedAssets)
+ .addInput("--androidJar", AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar())
+ .addInput(
+ "--primaryData",
+ AndroidDataConverter.MERGABLE_DATA_CONVERTER.map(parsed),
+ Iterables.concat(parsed.getAssets(), ImmutableList.of(parsed.getSymbols())))
+ .addTransitiveFlag(
+ "--directData",
+ deps.getDirectParsedAssets(),
+ AndroidDataConverter.MERGABLE_DATA_CONVERTER)
+ .addTransitiveFlag(
+ "--data",
+ deps.getTransitiveParsedAssets(),
+ AndroidDataConverter.MERGABLE_DATA_CONVERTER)
+ .addTransitiveInputValues(deps.getTransitiveAssets())
+ .addTransitiveInputValues(deps.getTransitiveSymbols())
+ .buildAndRegister("Merging Android assets", "AndroidAssetMerger");
+
+ return new MergedAndroidAssets(parsed, mergedAssets, deps);
+ }
+
+ private MergedAndroidAssets(
+ ParsedAndroidAssets parsed, Artifact mergedAssets, AssetDependencies assetDependencies) {
+ super(parsed);
+ this.mergedAssets = mergedAssets;
+ this.assetDependencies = assetDependencies;
+ }
+
+ AndroidAssetsInfo toProvider() {
+ // Create a new object to avoid passing around unwanted merge information to the provider
+ ParsedAndroidAssets parsed = new ParsedAndroidAssets(this);
+ return assetDependencies.toInfo(parsed);
+ }
+
+ public Artifact getMergedAssets() {
+ return mergedAssets;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!super.equals(object)) {
+ return false;
+ }
+
+ MergedAndroidAssets other = (MergedAndroidAssets) object;
+
+ return mergedAssets.equals(other.mergedAssets)
+ && assetDependencies.equals(other.assetDependencies);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mergedAssets, assetDependencies);
+ }
+}
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 6a83642483..3419ceeca5 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
@@ -34,12 +34,22 @@ public class ParsedAndroidAssets extends AndroidAssets implements MergableAndroi
return new ParsedAndroidAssets(assets, symbols, label);
}
+ ParsedAndroidAssets(ParsedAndroidAssets other) {
+ this(other, other.symbols, other.label);
+ }
+
private ParsedAndroidAssets(AndroidAssets other, Artifact symbols, Label label) {
super(other);
this.symbols = symbols;
this.label = label;
}
+ /** Merges these assets with assets from dependencies. */
+ public MergedAndroidAssets merge(RuleContext ruleContext, boolean neverlink)
+ throws InterruptedException {
+ return MergedAndroidAssets.mergeFrom(ruleContext, this, neverlink);
+ }
+
@Override
public Label getLabel() {
return label;