aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/actions
diff options
context:
space:
mode:
authorGravatar tomlu <tomlu@google.com>2017-09-14 23:24:06 +0200
committerGravatar Philipp Wollermann <philwo@google.com>2017-09-15 11:29:04 +0200
commit7df9198a771ef2eabef396dcb7a21e6cbb3cabb0 (patch)
treee8929823a7012639db9a560589b89beacecdb757 /src/main/java/com/google/devtools/build/lib/analysis/actions
parent2e7b804d29f3c1fa979d8a226d62d970dada64e2 (diff)
Support multiple command lines / params files in SpawnAction.
This is necessary for the upcoming Skylark implementation of param files. PiperOrigin-RevId: 168744486
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/actions')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java152
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileInfo.java46
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java298
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java10
5 files changed, 249 insertions, 266 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java
index bfc88bea31..e3139b4ab0 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java
@@ -715,15 +715,6 @@ public final class CustomCommandLine extends CommandLine {
}
/**
- * Concatenates the passed prefix string and the object's string representation.
- *
- * <p>Prefer {@link Builder#addPrefixed}, as it will be more memory efficient.
- */
- Builder addWithDynamicPrefix(String prefix, @Nullable Object arg) {
- return addPrefixedInternal(prefix, arg);
- }
-
- /**
* Adds the passed strings to the command line.
*
* <p>If you are converting long lists or nested sets of a different type to string lists,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java
deleted file mode 100644
index 01781d422c..0000000000
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileHelper.java
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2014 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.analysis.actions;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.devtools.build.lib.actions.ActionOwner;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.CommandLineExpansionException;
-import com.google.devtools.build.lib.actions.ParameterFile;
-import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.util.Preconditions;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.List;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-
-/**
- * A command-line implementation that wraps another command line and puts the arguments in a
- * parameter file if necessary
- *
- * <p>The Linux kernel has a limit for the command line length, and that can be easily reached
- * if, for example, a command is listing all its inputs on the command line.
- */
-@Immutable
-public final class ParamFileHelper {
-
- /**
- * Returns a params file artifact or null for a given command description.
- *
- * <p>Returns null if parameter files are not to be used according to paramFileInfo, or if the
- * command line is short enough that a parameter file is not needed.
- *
- * <p>Make sure to add the returned artifact (if not null) as an input of the corresponding
- * action.
- *
- * @param executableArgs leading arguments that should never be wrapped in a parameter file
- * @param commandLine a {@link CommandLine} that provides the arguments (in addition to
- * executableArgs)
- * @param paramFileInfo parameter file information
- * @param configuration the configuration
- * @param analysisEnvironment the analysis environment
- * @param outputs outputs of the action (used to construct a filename for the params file)
- */
- static Artifact getParamsFileMaybe(
- List<String> executableArgs,
- CommandLine commandLine,
- @Nullable ParamFileInfo paramFileInfo,
- BuildConfiguration configuration,
- AnalysisEnvironment analysisEnvironment,
- Iterable<Artifact> outputs) {
- if (paramFileInfo == null) {
- return null;
- }
- if (!paramFileInfo.always()
- && getParamFileSize(executableArgs, commandLine) < configuration.getMinParamFileSize()) {
- return null;
- }
-
- Artifact output = Iterables.getFirst(outputs, null);
- Preconditions.checkNotNull(output);
- PathFragment paramFilePath = ParameterFile.derivePath(output.getRootRelativePath());
- return analysisEnvironment.getDerivedArtifact(paramFilePath, output.getRoot());
- }
-
- /**
- * Creates a command line using an external params file.
- *
- * <p>Call this with the result of {@link #getParamsFileMaybe} if it is not null.
- *
- * @param executableArgs leading arguments that should never be wrapped in a parameter file
- * @param paramFileInfo parameter file information
- * @param parameterFile the output parameter file artifact
- */
- public static CommandLine createWithParamsFile(
- ImmutableList<String> executableArgs, ParamFileInfo paramFileInfo, Artifact parameterFile) {
- return CustomCommandLine.builder()
- .addAll(executableArgs)
- // This is actually a constant, but there is no way to suppress the warning
- .addWithDynamicPrefix(paramFileInfo.getFlag(), parameterFile)
- .build();
- }
-
- /**
- * Creates an action to write the parameter file.
- *
- * @param commandLine a {@link CommandLine} that provides the arguments (in addition to
- * executableArgs)
- * @param owner owner of the action
- * @param parameterFile the output parameter file artifact
- * @param paramFileInfo parameter file information
- */
- public static ParameterFileWriteAction createParameterFileWriteAction(
- CommandLine commandLine,
- ActionOwner owner,
- Artifact parameterFile,
- ParamFileInfo paramFileInfo) {
- return new ParameterFileWriteAction(
- owner, parameterFile, commandLine, paramFileInfo.getFileType(), paramFileInfo.getCharset());
- }
-
- /**
- * Creates a command line without using a params file.
- *
- * <p>Call this if {@link #getParamsFileMaybe} returns null.
- *
- * @param executableArgs leading arguments that should never be wrapped in a parameter file
- * @param commandLine a {@link CommandLine} that provides the arguments (in addition to
- * executableArgs)
- */
- public static CommandLine createWithoutParamsFile(
- List<String> executableArgs, CommandLine commandLine) {
- if (executableArgs.isEmpty()) {
- return commandLine;
- }
- return CommandLine.concat(ImmutableList.copyOf(executableArgs), commandLine);
- }
-
- /** Estimates the params file size for the given arguments. */
- private static int getParamFileSize(List<String> executableArgs, CommandLine commandLine) {
- try {
- Iterable<String> actualArguments = commandLine.arguments();
- return getParamFileSize(executableArgs) + getParamFileSize(actualArguments);
- } catch (CommandLineExpansionException e) {
- // CommandLineExpansionException is thrown deterministically. We can ignore
- // it here and pretend that a params file is not necessary at this stage,
- // and an error will be thrown later at execution time.
- return 0;
- }
- }
-
- private static int getParamFileSize(Iterable<String> args) {
- int size = 0;
- for (String s : args) {
- size += s.length() + 1;
- }
- return size;
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileInfo.java
index 32ec7a8506..33a9245c2b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParamFileInfo.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.analysis.actions;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.errorprone.annotations.CompileTimeConstant;
@@ -32,11 +34,7 @@ public final class ParamFileInfo {
private final String flag;
private final boolean always;
- public ParamFileInfo(
- ParameterFileType fileType,
- Charset charset,
- @CompileTimeConstant String flag,
- boolean always) {
+ private ParamFileInfo(ParameterFileType fileType, Charset charset, String flag, boolean always) {
this.fileType = Preconditions.checkNotNull(fileType);
this.charset = Preconditions.checkNotNull(charset);
this.flag = Preconditions.checkNotNull(flag);
@@ -88,4 +86,42 @@ public final class ParamFileInfo {
&& flag.equals(other.flag)
&& always == other.always;
}
+
+ public static Builder builder(ParameterFileType parameterFileType) {
+ return new Builder(parameterFileType);
+ }
+
+ /** Builder for a ParamFileInfo. */
+ public static class Builder {
+ private final ParameterFileType fileType;
+ private Charset charset = ISO_8859_1;
+ private String flag = "@";
+ private boolean always;
+
+ private Builder(ParameterFileType fileType) {
+ this.fileType = fileType;
+ }
+
+ /** Sets the encoding to write the parameter file with. */
+ public Builder setCharset(Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ /** Sets a prefix to use for the flag that is passed to original command. */
+ public Builder setFlag(@CompileTimeConstant String flag) {
+ this.flag = flag;
+ return this;
+ }
+
+ /** Set whether the parameter file is always used, regardless of parameter file length. */
+ public Builder setUseAlways(boolean always) {
+ this.always = always;
+ return this;
+ }
+
+ public ParamFileInfo build() {
+ return new ParamFileInfo(fileType, charset, flag, always);
+ }
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
index 8f690a47a4..ac9aa7266a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
@@ -14,8 +14,6 @@
package com.google.devtools.build.lib.analysis.actions;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
@@ -31,6 +29,7 @@ import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.ActionInputHelper;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
import com.google.devtools.build.lib.actions.BaseSpawn;
import com.google.devtools.build.lib.actions.CommandAction;
import com.google.devtools.build.lib.actions.CommandLineExpansionException;
@@ -38,7 +37,7 @@ import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.ExecutionInfoSpecifier;
-import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
+import com.google.devtools.build.lib.actions.ParameterFile;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.actions.Spawn;
@@ -62,7 +61,6 @@ import com.google.errorprone.annotations.CompileTimeConstant;
import com.google.errorprone.annotations.FormatMethod;
import com.google.errorprone.annotations.FormatString;
import com.google.protobuf.GeneratedMessage.GeneratedExtension;
-import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -521,6 +519,17 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
*/
public static class Builder {
+ private static class CommandLineAndParamFileInfo {
+ private final CommandLine commandLine;
+ @Nullable private final ParamFileInfo paramFileInfo;
+
+ private CommandLineAndParamFileInfo(
+ CommandLine commandLine, @Nullable ParamFileInfo paramFileInfo) {
+ this.commandLine = commandLine;
+ this.paramFileInfo = paramFileInfo;
+ }
+ }
+
private final NestedSetBuilder<Artifact> toolsBuilder = NestedSetBuilder.stableOrder();
private final NestedSetBuilder<Artifact> inputsBuilder = NestedSetBuilder.stableOrder();
private final List<Artifact> outputs = new ArrayList<>();
@@ -535,10 +544,9 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
private PathFragment executable;
// executableArgs does not include the executable itself.
private List<String> executableArgs;
- @Nullable private CommandLine commandLine;
+ private List<CommandLineAndParamFileInfo> commandLines = new ArrayList<>();
private CharSequence progressMessage;
- private ParamFileInfo paramFileInfo = null;
private String mnemonic = "Unknown";
protected ExtraActionInfoSupplier<?> extraActionInfoSupplier = null;
private boolean disableSandboxing = false;
@@ -566,9 +574,8 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
this.executableArgs = (other.executableArgs != null)
? Lists.newArrayList(other.executableArgs)
: null;
- this.commandLine = other.commandLine;
+ this.commandLines = Lists.newArrayList(other.commandLines);
this.progressMessage = other.progressMessage;
- this.paramFileInfo = other.paramFileInfo;
this.mnemonic = other.mnemonic;
}
@@ -598,37 +605,91 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
@VisibleForTesting @CheckReturnValue
public Action[] build(ActionOwner owner, AnalysisEnvironment analysisEnvironment,
BuildConfiguration configuration) {
- CommandLine commandLine = this.commandLine != null ? this.commandLine : CommandLine.EMPTY;
- // Check to see if we need to use param file.
- Artifact paramsFile = ParamFileHelper.getParamsFileMaybe(
- buildExecutableArgs(configuration.getShellExecutable()),
- commandLine,
- paramFileInfo,
- configuration,
- analysisEnvironment,
- outputs);
-
- // If param file is to be used, set up the param file write action as well.
- ParameterFileWriteAction paramFileWriteAction = null;
- if (paramsFile != null) {
- paramFileWriteAction =
- ParamFileHelper.createParameterFileWriteAction(
- commandLine, owner, paramsFile, paramFileInfo);
+ List<Action> paramFileActions = new ArrayList<>(commandLines.size());
+ CommandLine actualCommandLine =
+ buildCommandLine(owner, analysisEnvironment, configuration, paramFileActions);
+ Action[] actions = new Action[1 + paramFileActions.size()];
+ Action spawnAction =
+ buildSpawnAction(owner, actualCommandLine, configuration.getActionEnvironment());
+ actions[0] = spawnAction;
+ for (int i = 0; i < paramFileActions.size(); ++i) {
+ actions[i + 1] = paramFileActions.get(i);
}
+ return actions;
+ }
- List<Action> actions = new ArrayList<>(2);
- actions.add(
- buildSpawnAction(
- owner,
- commandLine,
- configuration.getActionEnvironment(),
- configuration.getShellExecutable(),
- paramsFile));
- if (paramFileWriteAction != null) {
- actions.add(paramFileWriteAction);
+ private CommandLine buildCommandLine(
+ ActionOwner owner,
+ AnalysisEnvironment analysisEnvironment,
+ BuildConfiguration configuration,
+ List<Action> paramFileActions) {
+ ImmutableList<String> executableArgs =
+ buildExecutableArgs(configuration.getShellExecutable());
+ boolean hasConditionalParamFile =
+ commandLines.stream().anyMatch(c -> c.paramFileInfo != null && !c.paramFileInfo.always());
+ boolean spillToParamFiles = false;
+ if (hasConditionalParamFile) {
+ int totalLen = getParamFileSize(executableArgs);
+ for (CommandLineAndParamFileInfo commandLineAndParamFileInfo : commandLines) {
+ totalLen += getCommandLineSize(commandLineAndParamFileInfo.commandLine);
+ }
+ // To reduce implementation complexity we either spill all or none of the param files.
+ spillToParamFiles = totalLen > configuration.getMinParamFileSize();
}
+ // We a name based on the output, starting at <output>-2.params
+ // and then incrementing
+ int paramFileNameSuffix = 2;
+ SpawnActionCommandLine.Builder result = new SpawnActionCommandLine.Builder();
+ result.addExecutableArguments(executableArgs);
+ for (CommandLineAndParamFileInfo commandLineAndParamFileInfo : commandLines) {
+ CommandLine commandLine = commandLineAndParamFileInfo.commandLine;
+ ParamFileInfo paramFileInfo = commandLineAndParamFileInfo.paramFileInfo;
+ boolean useParamsFile =
+ paramFileInfo != null && (paramFileInfo.always() || spillToParamFiles);
+ if (useParamsFile) {
+ Artifact output = Iterables.getFirst(outputs, null);
+ Preconditions.checkNotNull(output);
+ PathFragment paramFilePath =
+ ParameterFile.derivePath(
+ output.getRootRelativePath(), Integer.toString(paramFileNameSuffix));
+ Artifact paramFile =
+ analysisEnvironment.getDerivedArtifact(paramFilePath, output.getRoot());
+ inputsBuilder.add(paramFile);
+ ParameterFileWriteAction paramFileWriteAction =
+ new ParameterFileWriteAction(
+ owner,
+ paramFile,
+ commandLine,
+ paramFileInfo.getFileType(),
+ paramFileInfo.getCharset());
+ paramFileActions.add(paramFileWriteAction);
+ ++paramFileNameSuffix;
+ result.addParamFile(paramFile, paramFileInfo);
+ } else {
+ result.addCommandLine(commandLine);
+ }
+ }
+ return result.build();
+ }
+
+ private static int getCommandLineSize(CommandLine commandLine) {
+ try {
+ Iterable<String> actualArguments = commandLine.arguments();
+ return getParamFileSize(actualArguments);
+ } catch (CommandLineExpansionException e) {
+ // CommandLineExpansionException is thrown deterministically. We can ignore
+ // it here and pretend that a params file is not necessary at this stage,
+ // and an error will be thrown later at execution time.
+ return 0;
+ }
+ }
- return actions.toArray(new Action[actions.size()]);
+ private static int getParamFileSize(Iterable<String> args) {
+ int size = 0;
+ for (String s : args) {
+ size += s.length() + 1; // Account for the space character
+ }
+ return size;
}
/**
@@ -643,26 +704,11 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
*
* @param owner the {@link ActionOwner} for the SpawnAction
* @param configEnv the config's action environment to use. May be null if not used.
- * @param defaultShellExecutable the default shell executable path. May be null if not used.
- * @param paramsFile the parameter file for the SpawnAction. May be null if not used.
* @return the SpawnAction and any actions required by it, with the first item always being the
* SpawnAction itself.
*/
SpawnAction buildSpawnAction(
- ActionOwner owner,
- CommandLine commandLine,
- @Nullable ActionEnvironment configEnv,
- @Nullable PathFragment defaultShellExecutable,
- @Nullable Artifact paramsFile) {
- ImmutableList<String> argv = buildExecutableArgs(defaultShellExecutable);
- CommandLine actualCommandLine;
- if (paramsFile != null) {
- inputsBuilder.add(paramsFile);
- actualCommandLine = ParamFileHelper.createWithParamsFile(argv, paramFileInfo, paramsFile);
- } else {
- actualCommandLine = ParamFileHelper.createWithoutParamsFile(argv, commandLine);
- }
-
+ ActionOwner owner, CommandLine commandLine, @Nullable ActionEnvironment configEnv) {
NestedSet<Artifact> tools = toolsBuilder.build();
// Tools are by definition a subset of the inputs, so make sure they're present there, too.
@@ -692,7 +738,7 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
inputsAndTools,
ImmutableList.copyOf(outputs),
resourceSet,
- actualCommandLine,
+ commandLine,
isShellCommand,
env,
ImmutableMap.copyOf(executionInfo),
@@ -702,6 +748,21 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
mnemonic);
}
+ /**
+ * Builds the command line, forcing no params file.
+ *
+ * <p>This method is invoked by {@link SpawnActionTemplate} in the execution phase.
+ */
+ CommandLine buildCommandLineWithoutParamsFiles() {
+ SpawnActionCommandLine.Builder result = new SpawnActionCommandLine.Builder();
+ ImmutableList<String> executableArgs = buildExecutableArgs(null);
+ result.addExecutableArguments(executableArgs);
+ for (CommandLineAndParamFileInfo commandLineAndParamFileInfo : commandLines) {
+ result.addCommandLine(commandLineAndParamFileInfo.commandLine);
+ }
+ return result.build();
+ }
+
/** Creates a SpawnAction. */
protected SpawnAction createSpawnAction(
ActionOwner owner,
@@ -1062,15 +1123,36 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
}
/**
- * Sets a delegate to compute the command line at a later time.
+ * Adds a delegate to compute the command line at a later time.
+ *
+ * <p>The arguments are added after the executable arguments. If you add multiple command lines,
+ * they are expanded in the corresponding order.
+ *
+ * <p>The main intention of this method is to save memory by allowing client-controlled sharing
+ * between actions and configured targets. Objects passed to this method MUST be immutable.
+ *
+ * <p>See also {@link CustomCommandLine}.
+ */
+ public Builder addCommandLine(CommandLine commandLine) {
+ this.commandLines.add(new CommandLineAndParamFileInfo(commandLine, null));
+ return this;
+ }
+
+ /**
+ * Adds a delegate to compute the command line at a later time, optionally spilled to a params
+ * file.
+ *
+ * <p>The arguments are added after the executable arguments. If you add multiple command lines,
+ * they are expanded in the corresponding order. If the command line is spilled to a params
+ * file, it is replaced with an argument pointing to the param file.
*
* <p>The main intention of this method is to save memory by allowing client-controlled sharing
* between actions and configured targets. Objects passed to this method MUST be immutable.
*
* <p>See also {@link CustomCommandLine}.
*/
- public Builder setCommandLine(CommandLine commandLine) {
- this.commandLine = commandLine;
+ public Builder addCommandLine(CommandLine commandLine, @Nullable ParamFileInfo paramFileInfo) {
+ this.commandLines.add(new CommandLineAndParamFileInfo(commandLine, paramFileInfo));
return this;
}
@@ -1207,50 +1289,80 @@ public class SpawnAction extends AbstractAction implements ExecutionInfoSpecifie
return this;
}
- /**
- * Enable use of a parameter file and set the encoding to ISO-8859-1 (latin1).
- *
- * <p>In order to use parameter files, at least one output artifact must be specified.
- */
- public Builder useParameterFile(ParameterFileType parameterFileType) {
- return useParameterFile(parameterFileType, ISO_8859_1, "@");
+ public Builder disableSandboxing() {
+ this.disableSandboxing = true;
+ return this;
}
+ }
- /**
- * Force the use of a parameter file and set the encoding to ISO-8859-1 (latin1).
- *
- * <p>In order to use parameter files, at least one output artifact must be specified.
- */
- public Builder alwaysUseParameterFile(ParameterFileType parameterFileType) {
- return useParameterFile(parameterFileType, ISO_8859_1, "@", /*always=*/ true);
+ /**
+ * Command line implementation that optimises for containing executable args, command lines, and
+ * command lines spilled to param files.
+ */
+ private static class SpawnActionCommandLine extends CommandLine {
+ private final Object[] values;
+
+ SpawnActionCommandLine(Object[] values) {
+ this.values = values;
}
- /**
- * Enable or disable the use of a parameter file, set the encoding to the given value, and
- * specify the argument prefix to use in passing the parameter file name to the tool.
- *
- * <p>The default argument prefix is "@". In order to use parameter files, at least one output
- * artifact must be specified.
- */
- public Builder useParameterFile(
- ParameterFileType parameterFileType,
- Charset charset,
- @CompileTimeConstant String flagPrefix) {
- return useParameterFile(parameterFileType, charset, flagPrefix, /*always=*/ false);
- }
-
- private Builder useParameterFile(
- ParameterFileType parameterFileType,
- Charset charset,
- @CompileTimeConstant String flagPrefix,
- boolean always) {
- paramFileInfo = new ParamFileInfo(parameterFileType, charset, flagPrefix, always);
- return this;
+ @Override
+ public Iterable<String> arguments() throws CommandLineExpansionException {
+ return expandArguments(null);
}
- public Builder disableSandboxing() {
- this.disableSandboxing = true;
- return this;
+ @Override
+ public Iterable<String> arguments(ArtifactExpander artifactExpander)
+ throws CommandLineExpansionException {
+ return expandArguments(artifactExpander);
+ }
+
+ private Iterable<String> expandArguments(@Nullable ArtifactExpander artifactExpander)
+ throws CommandLineExpansionException {
+ ImmutableList.Builder<String> result = ImmutableList.builder();
+ int count = values.length;
+ for (int i = 0; i < count; ++i) {
+ Object value = values[i];
+ if (value instanceof String) {
+ result.add((String) value);
+ } else if (value instanceof Artifact) {
+ Artifact paramFile = (Artifact) value;
+ String flag = (String) values[++i];
+ result.add(flag + paramFile.getExecPathString());
+ } else if (value instanceof CommandLine) {
+ CommandLine commandLine = (CommandLine) value;
+ if (artifactExpander != null) {
+ result.addAll(commandLine.arguments(artifactExpander));
+ } else {
+ result.addAll(commandLine.arguments());
+ }
+ }
+ }
+ return result.build();
+ }
+
+ private static class Builder {
+ private List<Object> values = new ArrayList<>();
+
+ Builder addExecutableArguments(ImmutableList<String> executableArguments) {
+ values.addAll(executableArguments);
+ return this;
+ }
+
+ Builder addParamFile(Artifact paramFile, ParamFileInfo paramFileInfo) {
+ values.add(paramFile);
+ values.add(paramFileInfo.getFlag());
+ return this;
+ }
+
+ Builder addCommandLine(CommandLine commandLine) {
+ values.add(commandLine);
+ return this;
+ }
+
+ SpawnActionCommandLine build() {
+ return new SpawnActionCommandLine(values.toArray());
+ }
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
index db40f23f51..0b35944581 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
@@ -121,17 +121,13 @@ public final class SpawnActionTemplate implements ActionTemplate<SpawnAction> {
CommandLine commandLine = commandLineTemplate.evaluateTreeFileArtifacts(
ImmutableList.of(inputTreeFileArtifact, outputTreeFileArtifact));
- actionBuilder.setCommandLine(commandLine);
+ actionBuilder.addCommandLine(commandLine);
// Note that we pass in nulls below because SpawnActionTemplate does not support param file, and
// it does not use any default value for executable or shell environment. They must be set
// explicitly via builder method #setExecutable and #setEnvironment.
return actionBuilder.buildSpawnAction(
- getOwner(),
- commandLine,
- /*configEnv=*/ null,
- /*defaultShellExecutable=*/ null,
- /*paramsFile=*/ null);
+ getOwner(), actionBuilder.buildCommandLineWithoutParamsFiles(), /*configEnv=*/ null);
}
/**
@@ -206,7 +202,7 @@ public final class SpawnActionTemplate implements ActionTemplate<SpawnAction> {
@Override
public Iterable<String> getClientEnvironmentVariables() {
return spawnActionBuilder
- .buildSpawnAction(getOwner(), CommandLine.of(ImmutableList.of()), null, null, null)
+ .buildSpawnAction(getOwner(), CommandLine.of(ImmutableList.of()), null)
.getClientEnvironmentVariables();
}