diff --git a/maven-executor/src/main/java/org/apache/maven/executor/support/ProcessBuilderExecutorSupport.java b/maven-executor/src/main/java/org/apache/maven/executor/support/ProcessBuilderExecutorSupport.java index 4f8b29d..cb5b9ed 100644 --- a/maven-executor/src/main/java/org/apache/maven/executor/support/ProcessBuilderExecutorSupport.java +++ b/maven-executor/src/main/java/org/apache/maven/executor/support/ProcessBuilderExecutorSupport.java @@ -75,37 +75,32 @@ protected ExecutorResult doExecuteProcess(ExecutorRequest execution, ProcessBuil stdOut = execution.stdOut().orElse(IOTools.nullOutputStream()); stdErr = execution.stdErr().orElse(IOTools.nullOutputStream()); } + CountDownLatch outputPump = pump(process, stdIn, stdOut, stdErr); + boolean processFinished; if (execution.executionTimeout().isPresent()) { long timeoutMillis = execution .executionTimeout() .orElseThrow(() -> new NoSuchElementException("No such element")) .toMillis(); - if (pump(process, stdIn, stdOut, stdErr).await(timeoutMillis, TimeUnit.MILLISECONDS)) { - int exitCode = process.waitFor(); - String stdOutString = null; - String stdErrString = null; - if (execution.grabOutputAsString()) { - // they are ByteArrayOutputStreams - stdOutString = stdOut.toString(); - stdErrString = stdErr.toString(); - } - return new SimpleExecutionResult(execution, exitCode == 0, exitCode, stdOutString, stdErrString); - } else { + processFinished = process.waitFor(timeoutMillis, TimeUnit.MILLISECONDS); + if (!processFinished) { process.destroyForcibly(); throw new ExecutorException("Process timeout: " + execution); } } else { - pump(process, stdIn, stdOut, stdErr).await(); - int exitCode = process.waitFor(); - String stdOutString = null; - String stdErrString = null; - if (execution.grabOutputAsString()) { - // they are ByteArrayOutputStreams - stdOutString = stdOut.toString(); - stdErrString = stdErr.toString(); - } - return new SimpleExecutionResult(execution, exitCode == 0, exitCode, stdOutString, stdErrString); + process.waitFor(); + } + process.getOutputStream().close(); + outputPump.await(); + int exitCode = process.exitValue(); + String stdOutString = null; + String stdErrString = null; + if (execution.grabOutputAsString()) { + // they are ByteArrayOutputStreams + stdOutString = stdOut.toString(); + stdErrString = stdErr.toString(); } + return new SimpleExecutionResult(execution, exitCode == 0, exitCode, stdOutString, stdErrString); } catch (IOException e) { if (process != null) { process.destroyForcibly(); @@ -118,7 +113,7 @@ protected ExecutorResult doExecuteProcess(ExecutorRequest execution, ProcessBuil } protected CountDownLatch pump(Process p, InputStream stdIn, OutputStream stdOut, OutputStream stdErr) { - CountDownLatch latch = new CountDownLatch(3); + CountDownLatch latch = new CountDownLatch(2); String suffix = "-pump-" + ThreadLocalRandom.current().nextInt(); Thread stdoutPump = new Thread(() -> { try (OutputStream stdout = stdOut) { @@ -152,8 +147,6 @@ protected CountDownLatch pump(Process p, InputStream stdIn, OutputStream stdOut, in.flush(); } catch (IOException e) { throw new UncheckedIOException(e); - } finally { - latch.countDown(); } }); stdinPump.setName("stdin" + suffix); diff --git a/maven-executor/src/test/java/org/apache/maven/executor/forked/ForkedMavenExecutorTest.java b/maven-executor/src/test/java/org/apache/maven/executor/forked/ForkedMavenExecutorTest.java index 28928f6..0c46f92 100644 --- a/maven-executor/src/test/java/org/apache/maven/executor/forked/ForkedMavenExecutorTest.java +++ b/maven-executor/src/test/java/org/apache/maven/executor/forked/ForkedMavenExecutorTest.java @@ -18,16 +18,37 @@ */ package org.apache.maven.executor.forked; +import java.io.PipedInputStream; import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.NoSuchElementException; +import org.apache.maven.executor.Environment; import org.apache.maven.executor.Executor; +import org.apache.maven.executor.ExecutorResult; import org.apache.maven.executor.MavenExecutorTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Forked executor UT */ public class ForkedMavenExecutorTest extends MavenExecutorTestSupport { + @Test + void doesNotWaitForInteractiveStdinAfterProcessExits() throws Exception { + ExecutorResult result = createAndMemoizeExecutor(Paths.get(Environment.MAVEN4_HOME)) + .execute(customizedRequest() + .argument("-version") + .stdIn(new PipedInputStream()) + .executionTimeout(Duration.ofSeconds(10)) + .build()); + + assertEquals(0, result.exitCode().orElseThrow(NoSuchElementException::new)); + } + @Override protected Executor doSelectExecutor(Path installationDirectory) { return new ForkedMavenExecutor(installationDirectory);