diff options
author | 2016-06-06 09:49:06 +0000 | |
---|---|---|
committer | 2016-06-06 16:41:40 +0000 | |
commit | 25a98e16731a2a0cbb59449a6e7d395bd204d04c (patch) | |
tree | 8cefb07f14f06fdb837a4f586eeb526ffad50315 /src/main/java/com/google/devtools/build/lib | |
parent | 3ae59125807c2ba1a4a238703b0fc9780f96c32e (diff) |
repository_ctx.execute: execute from the external repository root and allow to override the environment variables.
Fixes #1130
Fixes #1242
--
MOS_MIGRATED_REVID=124118789
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
2 files changed, 77 insertions, 10 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkExecutionResult.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkExecutionResult.java index b4181aa449..ad2e7b60a8 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkExecutionResult.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkExecutionResult.java @@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.bazel.repository.skylark; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.shell.BadExitStatusException; import com.google.devtools.build.lib.shell.Command; @@ -23,9 +24,11 @@ import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.util.Preconditions; +import java.io.File; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * A structure callable from Skylark that stores the result of repository_ctx.execute() method. It @@ -89,9 +92,12 @@ final class SkylarkExecutionResult { /** * Returns a Builder that can be used to execute a command and build an execution result. + * + * @param environment pass through the list of environment variables from the client to be passed + * to the execution environment. */ - public static Builder builder() { - return new Builder(); + public static Builder builder(Map<String, String> environment) { + return new Builder(environment); } /** @@ -100,9 +106,15 @@ final class SkylarkExecutionResult { static final class Builder { private final List<String> args = new ArrayList<>(); + private File directory = null; + private final ImmutableMap.Builder<String, String> envBuilder = ImmutableMap.builder(); private long timeout = -1; private boolean executed = false; + private Builder(Map<String, String> environment) { + envBuilder.putAll(environment); + } + /** * Adds arguments to the list of arguments to pass to the command. The first argument is * expected to be the binary to execute. The subsequent arguments are the arguments passed @@ -125,6 +137,25 @@ final class SkylarkExecutionResult { } /** + * Set the path to the directory to execute the result process. This method must be called + * before calling {@link #execute()}. + */ + Builder setDirectory(File path) throws EvalException { + this.directory = path; + return this; + } + + /** + * Add an environment variables to be added to the list of environment variables. For all + * key <code>k</code> of <code>variables</code>, the resulting process will have the variable + * <code>k=variables.get(k)</code> defined. + */ + Builder addEnvironmentVariables(Map<String, String> variables) { + this.envBuilder.putAll(variables); + return this; + } + + /** * Sets the timeout, in milliseconds, after which the executed command will be terminated. */ Builder setTimeout(long timeout) { @@ -140,6 +171,7 @@ final class SkylarkExecutionResult { Preconditions.checkArgument(timeout > 0, "Timeout must be set prior to calling execute()."); Preconditions.checkArgument(!args.isEmpty(), "No command specified."); Preconditions.checkState(!executed, "Command was already executed, cannot re-use builder."); + Preconditions.checkNotNull(directory, "Directory must be set before calling execute()."); executed = true; try { @@ -147,7 +179,8 @@ final class SkylarkExecutionResult { for (int i = 0; i < args.size(); i++) { argsArray[i] = args.get(i); } - CommandResult result = new Command(argsArray).execute(new byte[]{}, timeout, false); + Command command = new Command(argsArray, envBuilder.build(), directory); + CommandResult result = command.execute(new byte[]{}, timeout, false); return new SkylarkExecutionResult(result); } catch (BadExitStatusException e) { return new SkylarkExecutionResult(e.getResult()); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java index e4dd0293c8..35b4e71556 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java @@ -293,23 +293,57 @@ public class SkylarkRepositoryContext { return osObject; } + private void createOutputDirectory() throws RepositoryFunctionException { + try { + if (!outputDirectory.exists()) { + makeDirectories(outputDirectory); + outputDirectory.createDirectory(); + } + } catch (IOException e) { + throw new RepositoryFunctionException(e, Transience.TRANSIENT); + } + } + @SkylarkCallable( name = "execute", doc = "Executes the command given by the list of arguments. The execution time of the command" + " is limited by <code>timeout</code> (in seconds, default 600 seconds). This method" + " returns an <code>exec_result</code> structure containing the output of the" - + " command." + + " command. The <code>environment</code> map can be used to override some environment" + + " variables to be passed to the process." ) - public SkylarkExecutionResult execute(List<Object> arguments, long timeout) throws EvalException { - return SkylarkExecutionResult.builder() - .addArguments(arguments).setTimeout(timeout / 1000).execute(); + public SkylarkExecutionResult execute(List<Object> arguments, Integer timeout, + Map<String, String> environment) throws EvalException, RepositoryFunctionException { + createOutputDirectory(); + return SkylarkExecutionResult.builder(osObject.getEnvironmentVariables()) + .addArguments(arguments) + .setDirectory(outputDirectory.getPathFile()) + .addEnvironmentVariables(environment) + .setTimeout(timeout.longValue() * 1000) + .execute(); + } + + @SkylarkCallable(name = "execute", documented = false) + public SkylarkExecutionResult execute(List<Object> arguments) + throws EvalException, RepositoryFunctionException { + createOutputDirectory(); + return SkylarkExecutionResult.builder(osObject.getEnvironmentVariables()) + .setDirectory(outputDirectory.getPathFile()) + .addArguments(arguments) + .setTimeout(600000) + .execute(); } @SkylarkCallable(name = "execute", documented = false) - public SkylarkExecutionResult execute(List<Object> arguments) throws EvalException { - return SkylarkExecutionResult.builder() - .addArguments(arguments).setTimeout(600000).execute(); + public SkylarkExecutionResult execute(List<Object> arguments, Integer timeout) + throws EvalException, RepositoryFunctionException { + createOutputDirectory(); + return SkylarkExecutionResult.builder(osObject.getEnvironmentVariables()) + .setDirectory(outputDirectory.getPathFile()) + .addArguments(arguments) + .setTimeout(timeout.longValue() * 1000) + .execute(); } @SkylarkCallable( |