diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java | 179 |
1 files changed, 84 insertions, 95 deletions
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); } } |