diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java | 137 |
1 files changed, 137 insertions, 0 deletions
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)); + } +} |