diff options
author | ulfjack <ulfjack@google.com> | 2017-06-16 15:25:42 +0200 |
---|---|---|
committer | Philipp Wollermann <philwo@google.com> | 2017-06-19 18:23:00 +0200 |
commit | acd291a520d392977a2efff17949b75c2fa80eef (patch) | |
tree | a3da9f3eda8844425cdbb28d291eedee400c8069 /src/main/java/com/google/devtools/build/lib/standalone | |
parent | 560bcb8653947d5d38fa9710c25b7eff6596b2fc (diff) |
Rewrite StandaloneSpawnStrategy to use LocalSpawnRunner
PiperOrigin-RevId: 159221067
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/standalone')
3 files changed, 116 insertions, 117 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java index 12e508dbe0..c1dbbac6f5 100644 --- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java +++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java @@ -13,20 +13,23 @@ // limitations under the License. package com.google.devtools.build.lib.standalone; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.ActionExecutionContext; +import com.google.devtools.build.lib.actions.ActionInputFileCache; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ArtifactResolver; import com.google.devtools.build.lib.actions.ExecutionStrategy; import com.google.devtools.build.lib.actions.Executor.ActionContext; -import com.google.devtools.build.lib.buildtool.BuildRequest; +import com.google.devtools.build.lib.actions.ResourceManager; import com.google.devtools.build.lib.exec.ActionContextProvider; +import com.google.devtools.build.lib.exec.ActionInputPrefetcher; import com.google.devtools.build.lib.exec.ExecutionOptions; import com.google.devtools.build.lib.exec.FileWriteStrategy; import com.google.devtools.build.lib.exec.StandaloneTestStrategy; import com.google.devtools.build.lib.exec.TestStrategy; +import com.google.devtools.build.lib.exec.local.LocalExecutionOptions; import com.google.devtools.build.lib.rules.cpp.IncludeScanningContext; import com.google.devtools.build.lib.rules.cpp.SpawnGccStrategy; import com.google.devtools.build.lib.rules.test.ExclusiveTestStrategy; @@ -64,39 +67,46 @@ public class StandaloneActionContextProvider extends ActionContextProvider { } private final CommandEnvironment env; - private final ImmutableList<ActionContext> strategies; + private ActionInputPrefetcher actionInputPrefetcher; - public StandaloneActionContextProvider(CommandEnvironment env, BuildRequest buildRequest) { + public StandaloneActionContextProvider(CommandEnvironment env) { this.env = env; - ExecutionOptions options = buildRequest.getOptions(ExecutionOptions.class); - boolean verboseFailures = options.verboseFailures; + } - Path testTmpRoot = TestStrategy.getTmpRoot(env.getWorkspace(), env.getExecRoot(), options); - TestActionContext testStrategy = - new StandaloneTestStrategy( - buildRequest, env.getBlazeWorkspace().getBinTools(), testTmpRoot); + @Override + public void init( + ActionInputFileCache actionInputFileCache, ActionInputPrefetcher actionInputPrefetcher) { + this.actionInputPrefetcher = Preconditions.checkNotNull(actionInputPrefetcher); + } - Builder<ActionContext> strategiesBuilder = ImmutableList.builder(); + @Override + public Iterable<? extends ActionContext> getActionContexts() { + ExecutionOptions executionOptions = env.getOptions().getOptions(ExecutionOptions.class); + LocalExecutionOptions localExecutionOptions = + env.getOptions().getOptions(LocalExecutionOptions.class); + Path testTmpRoot = + TestStrategy.getTmpRoot(env.getWorkspace(), env.getExecRoot(), executionOptions); + TestActionContext testStrategy = + new StandaloneTestStrategy( + executionOptions, + env.getBlazeWorkspace().getBinTools(), + testTmpRoot); // Order of strategies passed to builder is significant - when there are many strategies that // could potentially be used and a spawnActionContext doesn't specify which one it wants, the // last one from strategies list will be used - strategiesBuilder.add( + return ImmutableList.of( new StandaloneSpawnStrategy( env.getExecRoot(), - verboseFailures, - env.getRuntime().getProductName()), + actionInputPrefetcher, + localExecutionOptions, + executionOptions.verboseFailures, + env.getRuntime().getProductName(), + ResourceManager.instance()), new DummyIncludeScanningContext(), new SpawnGccStrategy(), testStrategy, new ExclusiveTestStrategy(testStrategy), new FileWriteStrategy()); - - this.strategies = strategiesBuilder.build(); - } - - @Override - public Iterable<ActionContext> getActionContexts() { - return strategies; } } diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java index b60f47aa1e..6f299fa616 100644 --- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java +++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java @@ -24,7 +24,7 @@ import com.google.devtools.build.lib.runtime.CommandEnvironment; public class StandaloneModule extends BlazeModule { @Override public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) { - builder.addActionContextProvider(new StandaloneActionContextProvider(env, request)); + builder.addActionContextProvider(new StandaloneActionContextProvider(env)); builder.addActionContextConsumer(new StandaloneActionContextConsumer()); } } diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java index 724542ff1b..de47fe42d2 100644 --- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java @@ -15,32 +15,36 @@ package com.google.devtools.build.lib.standalone; import com.google.common.eventbus.EventBus; import com.google.devtools.build.lib.actions.ActionExecutionContext; -import com.google.devtools.build.lib.actions.ActionExecutionMetadata; +import com.google.devtools.build.lib.actions.ActionInput; +import com.google.devtools.build.lib.actions.ActionInputFileCache; import com.google.devtools.build.lib.actions.ActionStatusMessage; import com.google.devtools.build.lib.actions.ExecException; import com.google.devtools.build.lib.actions.ExecutionStrategy; import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.ResourceManager; -import com.google.devtools.build.lib.actions.ResourceManager.ResourceHandle; import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.actions.SpawnActionContext; import com.google.devtools.build.lib.actions.Spawns; import com.google.devtools.build.lib.actions.UserExecException; +import com.google.devtools.build.lib.exec.ActionInputPrefetcher; +import com.google.devtools.build.lib.exec.SpawnExecException; +import com.google.devtools.build.lib.exec.SpawnInputExpander; +import com.google.devtools.build.lib.exec.SpawnResult; +import com.google.devtools.build.lib.exec.SpawnResult.Status; +import com.google.devtools.build.lib.exec.SpawnRunner.ProgressStatus; +import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionPolicy; import com.google.devtools.build.lib.exec.apple.XCodeLocalEnvProvider; import com.google.devtools.build.lib.exec.local.LocalEnvProvider; -import com.google.devtools.build.lib.shell.AbnormalTerminationException; -import com.google.devtools.build.lib.shell.Command; -import com.google.devtools.build.lib.shell.CommandException; -import com.google.devtools.build.lib.shell.TerminationStatus; +import com.google.devtools.build.lib.exec.local.LocalExecutionOptions; +import com.google.devtools.build.lib.exec.local.LocalSpawnRunner; +import com.google.devtools.build.lib.rules.fileset.FilesetActionContext; import com.google.devtools.build.lib.util.CommandFailureUtils; import com.google.devtools.build.lib.util.OS; -import com.google.devtools.build.lib.util.OsUtils; import com.google.devtools.build.lib.util.io.FileOutErr; import com.google.devtools.build.lib.vfs.Path; -import java.io.File; +import com.google.devtools.build.lib.vfs.PathFragment; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.util.SortedMap; /** * Strategy that uses subprocessing to execute a process. @@ -48,112 +52,97 @@ import java.util.List; @ExecutionStrategy(name = { "standalone", "local" }, contextType = SpawnActionContext.class) public class StandaloneSpawnStrategy implements SpawnActionContext { private final boolean verboseFailures; - private final Path processWrapper; - private final Path execRoot; - private final String productName; - private final ResourceManager resourceManager; - private final LocalEnvProvider localEnvProvider; - - public StandaloneSpawnStrategy(Path execRoot, boolean verboseFailures, String productName) { - this(execRoot, verboseFailures, productName, ResourceManager.instance()); - } + private final LocalSpawnRunner localSpawnRunner; public StandaloneSpawnStrategy( - Path execRoot, boolean verboseFailures, String productName, ResourceManager resourceManager) { + Path execRoot, ActionInputPrefetcher actionInputPrefetcher, + LocalExecutionOptions localExecutionOptions, boolean verboseFailures, String productName, + ResourceManager resourceManager) { this.verboseFailures = verboseFailures; - this.execRoot = execRoot; - this.processWrapper = execRoot.getRelative( - "_bin/process-wrapper" + OsUtils.executableExtension()); - this.productName = productName; - this.resourceManager = resourceManager; - this.localEnvProvider = OS.getCurrent() == OS.DARWIN + LocalEnvProvider localEnvProvider = OS.getCurrent() == OS.DARWIN ? new XCodeLocalEnvProvider() : LocalEnvProvider.UNMODIFIED; + this.localSpawnRunner = new LocalSpawnRunner( + execRoot, + actionInputPrefetcher, + localExecutionOptions, + resourceManager, + productName, + localEnvProvider); } /** * Executes the given {@code spawn}. */ @Override - public void exec(Spawn spawn, - ActionExecutionContext actionExecutionContext) + public void exec(final Spawn spawn, final ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException { - EventBus eventBus = actionExecutionContext.getExecutor().getEventBus(); - ActionExecutionMetadata owner = spawn.getResourceOwner(); - eventBus.post(ActionStatusMessage.schedulingStrategy(owner)); - try (ResourceHandle handle = - resourceManager.acquireResources(owner, spawn.getLocalResources())) { - eventBus.post(ActionStatusMessage.runningStrategy(owner, "standalone")); - try { - actuallyExec(spawn, actionExecutionContext); - } catch (IOException e) { - throw new UserExecException("I/O exception during local execution", e); + final int timeoutSeconds = Spawns.getTimeoutSeconds(spawn); + final EventBus eventBus = actionExecutionContext.getExecutor().getEventBus(); + SpawnExecutionPolicy policy = new SpawnExecutionPolicy() { + @Override + public ActionInputFileCache getActionInputFileCache() { + return actionExecutionContext.getActionInputFileCache(); } - } - } - /** - * Executes the given {@code spawn}. - */ - private void actuallyExec(Spawn spawn, - ActionExecutionContext actionExecutionContext) - throws ExecException, IOException { - Executor executor = actionExecutionContext.getExecutor(); + @Override + public void lockOutputFiles() throws InterruptedException { + // Do nothing for now. + } - if (executor.reportsSubcommands()) { - executor.reportSubcommand(spawn); - } + @Override + public long getTimeoutMillis() { + return timeoutSeconds * 1000L; + } - int timeoutSeconds = Spawns.getTimeoutSeconds(spawn); + @Override + public FileOutErr getFileOutErr() { + return actionExecutionContext.getFileOutErr(); + } - // We must wrap the subprocess with process-wrapper to kill the process tree. - // All actions therefore depend on the process-wrapper file. Since it's embedded, - // we don't bother with declaring it as an input. - List<String> args = new ArrayList<>(); - if (OS.getCurrent() != OS.WINDOWS) { - // TODO(bazel-team): process-wrapper seems to work on Windows, but requires - // additional setup as it is an msys2 binary, so it needs msys2 DLLs on %PATH%. - // Disable it for now to make the setup easier and to avoid further PATH hacks. - // Ideally we should have a native implementation of process-wrapper for Windows. - args.add(processWrapper.getPathString()); - args.add(Integer.toString(timeoutSeconds)); - args.add("5"); /* kill delay: give some time to print stacktraces and whatnot. */ + @Override + public SortedMap<PathFragment, ActionInput> getInputMapping() throws IOException { + return new SpawnInputExpander(/*strict*/false) + .getInputMapping( + spawn, + actionExecutionContext.getArtifactExpander(), + actionExecutionContext.getActionInputFileCache(), + actionExecutionContext.getExecutor().getContext(FilesetActionContext.class)); + } - // TODO(bazel-team): use process-wrapper redirection so we don't have to - // pass test logs through the Java heap. - args.add("-"); /* stdout. */ - args.add("-"); /* stderr. */ - } - args.addAll(spawn.getArguments()); + @Override + public void report(ProgressStatus state) { + switch (state) { + case EXECUTING: + String strategyName = "local"; + eventBus.post( + ActionStatusMessage.runningStrategy(spawn.getResourceOwner(), strategyName)); + break; + case SCHEDULING: + eventBus.post(ActionStatusMessage.schedulingStrategy(spawn.getResourceOwner())); + break; + default: + break; + } + } + }; - String cwd = executor.getExecRoot().getPathString(); - Command cmd = - new Command( - args.toArray(new String[] {}), - localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, productName), - new File(cwd), - OS.getCurrent() == OS.WINDOWS && timeoutSeconds >= 0 ? timeoutSeconds * 1000 : -1); + Executor executor = actionExecutionContext.getExecutor(); + if (executor.reportsSubcommands()) { + executor.reportSubcommand(spawn); + } - FileOutErr outErr = actionExecutionContext.getFileOutErr(); try { - cmd.execute( - /* stdin */ new byte[] {}, - Command.NO_OBSERVER, - outErr.getOutputStream(), - outErr.getErrorStream(), - /*killSubprocessOnInterrupt*/ true); - } catch (AbnormalTerminationException e) { - TerminationStatus status = e.getResult().getTerminationStatus(); - boolean timedOut = !status.exited() && ( - status.timedout() || status.getTerminatingSignal() == 14 /* SIGALRM */); - String message = - CommandFailureUtils.describeCommandFailure( - verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd); - throw new UserExecException(String.format("%s: %s", message, e), timedOut); - } catch (CommandException e) { - String message = CommandFailureUtils.describeCommandFailure( - verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd); - throw new UserExecException(message, e); + SpawnResult result = localSpawnRunner.exec(spawn, policy); + if (result.status() != Status.SUCCESS || result.exitCode() != 0) { + String message = + CommandFailureUtils.describeCommandFailure( + verboseFailures, spawn.getArguments(), spawn.getEnvironment(), null); + throw new SpawnExecException( + message, result, /*forciblyRunRemotely=*/false, /*catastrophe=*/false); + } + } catch (IOException e) { + throw new UserExecException("I/O exception during local execution", e); } } |