You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/10/14 17:46:51 UTC
(maven-mvnd) 01/01: [#1834] Pump forked process output when only one stream is inherited
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch agent/agent-single-inherit-1x
in repository https://gitbox.apache.org/repos/asf/maven-mvnd.git
commit 7cbc61357dda6f021eaffe2b92b93cd07731bf4f
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Wed Oct 14 17:03:43 2026 +0200
[#1834] Pump forked process output when only one stream is inherited
The agent only switched INHERIT to PIPE when both stdout and stderr
inherited, so a child inheriting a single stream wrote to the daemon log.
It now works on a copy of the redirects, so the ProcessBuilder keeps
reporting what the caller set.
(cherry picked from commit 3279a4b715d2cec4e781ca7491925486e3ec1683)
---
.../main/java/org/mvndaemon/mvnd/agent/Agent.java | 17 +++++---
.../java/org/mvndaemon/mvnd/pump/AgentHelper.java | 9 +++--
.../java/org/mvndaemon/mvnd/it/ExecOutputTest.java | 12 ++++++
.../src/test/projects/exec-output/pom.xml | 10 +++++
.../org/mvndaemon/mvnd/test/InheritStderrOnly.java | 46 ++++++++++++++++++++++
.../java/org/mvndaemon/mvnd/test/StderrChild.java | 16 ++------
6 files changed, 88 insertions(+), 22 deletions(-)
diff --git a/agent/src/main/java/org/mvndaemon/mvnd/agent/Agent.java b/agent/src/main/java/org/mvndaemon/mvnd/agent/Agent.java
index 2109f5b3..bad0b037 100644
--- a/agent/src/main/java/org/mvndaemon/mvnd/agent/Agent.java
+++ b/agent/src/main/java/org/mvndaemon/mvnd/agent/Agent.java
@@ -28,12 +28,17 @@ import javassist.CtClass;
public class Agent {
public static final String START_WITH_PIPES = "if (redirects != null\n"
- + " && redirects[1] == ProcessBuilder$Redirect.INHERIT\n"
- + " && redirects[2] == ProcessBuilder$Redirect.INHERIT) {\n"
- + " redirects[1] = redirects[2] = ProcessBuilder$Redirect.PIPE;"
- + " Process p = start(redirects);\n"
- + " AgentHelper.pump(p.getInputStream(), System.out);\n"
- + " AgentHelper.pump(p.getErrorStream(), System.err);\n"
+ + " && (redirects[1] == ProcessBuilder$Redirect.INHERIT\n"
+ + " || redirects[2] == ProcessBuilder$Redirect.INHERIT)) {\n"
+ + " ProcessBuilder$Redirect[] piped = (ProcessBuilder$Redirect[])\n"
+ + " java.util.Arrays.copyOf(redirects, redirects.length);\n"
+ + " boolean pumpOut = piped[1] == ProcessBuilder$Redirect.INHERIT;\n"
+ + " boolean pumpErr = piped[2] == ProcessBuilder$Redirect.INHERIT;\n"
+ + " if (pumpOut) piped[1] = ProcessBuilder$Redirect.PIPE;\n"
+ + " if (pumpErr) piped[2] = ProcessBuilder$Redirect.PIPE;\n"
+ + " Process p = start(piped);\n"
+ + " if (pumpOut) AgentHelper.pump(p.getInputStream(), System.out);\n"
+ + " if (pumpErr) AgentHelper.pump(p.getErrorStream(), System.err);\n"
+ " return p;\n"
+ "}";
diff --git a/helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java b/helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java
index 95cf5534..d1a61d2f 100644
--- a/helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java
+++ b/helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java
@@ -26,9 +26,10 @@ import java.io.PrintStream;
public class AgentHelper {
public static void pump(InputStream stream, PrintStream out) {
- new Thread(() -> new BufferedReader(new InputStreamReader(stream))
- .lines()
- .forEach(out::println))
- .start();
+ Thread pump = new Thread(
+ () -> new BufferedReader(new InputStreamReader(stream)).lines().forEach(out::println),
+ "mvnd-process-pump");
+ pump.setDaemon(true);
+ pump.start();
}
}
diff --git a/integration-tests/src/test/java/org/mvndaemon/mvnd/it/ExecOutputTest.java b/integration-tests/src/test/java/org/mvndaemon/mvnd/it/ExecOutputTest.java
index 0bc94bd0..07e8d86b 100644
--- a/integration-tests/src/test/java/org/mvndaemon/mvnd/it/ExecOutputTest.java
+++ b/integration-tests/src/test/java/org/mvndaemon/mvnd/it/ExecOutputTest.java
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.mvndaemon.mvnd.assertj.TestClientOutput;
import org.mvndaemon.mvnd.client.Client;
import org.mvndaemon.mvnd.client.DaemonParameters;
+import org.mvndaemon.mvnd.common.Message;
import org.mvndaemon.mvnd.junit.MvndTest;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -48,4 +49,15 @@ class ExecOutputTest {
assertTrue(output.messagesToString()
.contains("ProjectLogMessage{projectId='exec-output', message='[INFO] [stdout] Hello world!'}"));
}
+
+ @Test
+ void cleanTestInheritStderrOnly() throws InterruptedException {
+
+ final TestClientOutput output = new TestClientOutput();
+ client.execute(output, "clean", "test", "-e", "-Dmvnd.log.level=DEBUG").assertSuccess();
+ assertTrue(output.getMessages().stream()
+ .filter(Message.ProjectEvent.class::isInstance)
+ .map(Message.ProjectEvent.class::cast)
+ .anyMatch(it -> it.getMessage().contains("From child stderr")));
+ }
}
diff --git a/integration-tests/src/test/projects/exec-output/pom.xml b/integration-tests/src/test/projects/exec-output/pom.xml
index 393768fa..e243345c 100644
--- a/integration-tests/src/test/projects/exec-output/pom.xml
+++ b/integration-tests/src/test/projects/exec-output/pom.xml
@@ -93,6 +93,16 @@
</arguments>
</configuration>
</execution>
+ <execution>
+ <id>run-inherit-stderr-only</id>
+ <phase>test</phase>
+ <goals>
+ <goal>java</goal>
+ </goals>
+ <configuration>
+ <mainClass>org.mvndaemon.mvnd.test.InheritStderrOnly</mainClass>
+ </configuration>
+ </execution>
</executions>
</plugin>
</plugins>
diff --git a/integration-tests/src/test/projects/exec-output/src/main/java/org/mvndaemon/mvnd/test/InheritStderrOnly.java b/integration-tests/src/test/projects/exec-output/src/main/java/org/mvndaemon/mvnd/test/InheritStderrOnly.java
new file mode 100644
index 00000000..cd375cb3
--- /dev/null
+++ b/integration-tests/src/test/projects/exec-output/src/main/java/org/mvndaemon/mvnd/test/InheritStderrOnly.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.mvndaemon.mvnd.test;
+
+import java.io.File;
+
+/**
+ * Forks a JVM that inherits only stderr, so the daemon must pump that one stream to the client.
+ */
+public class InheritStderrOnly {
+
+ public static void main(String[] args) throws Exception {
+ String java = new File(new File(System.getProperty("java.home"), "bin"), "java").getPath();
+ String classes = new File(InheritStderrOnly.class
+ .getProtectionDomain()
+ .getCodeSource()
+ .getLocation()
+ .toURI())
+ .getPath();
+ Process child = new ProcessBuilder(java, "-cp", classes, StderrChild.class.getName())
+ .redirectError(ProcessBuilder.Redirect.INHERIT)
+ .start();
+ int exit = child.waitFor();
+ if (exit != 0) {
+ throw new IllegalStateException("Child exited with " + exit);
+ }
+ // the pump thread forwards the child's output asynchronously
+ Thread.sleep(1000);
+ }
+}
diff --git a/helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java b/integration-tests/src/test/projects/exec-output/src/main/java/org/mvndaemon/mvnd/test/StderrChild.java
similarity index 65%
copy from helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java
copy to integration-tests/src/test/projects/exec-output/src/main/java/org/mvndaemon/mvnd/test/StderrChild.java
index 95cf5534..290a291a 100644
--- a/helper/src/main/java/org/mvndaemon/mvnd/pump/AgentHelper.java
+++ b/integration-tests/src/test/projects/exec-output/src/main/java/org/mvndaemon/mvnd/test/StderrChild.java
@@ -16,19 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.mvndaemon.mvnd.pump;
+package org.mvndaemon.mvnd.test;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
+public class StderrChild {
-public class AgentHelper {
-
- public static void pump(InputStream stream, PrintStream out) {
- new Thread(() -> new BufferedReader(new InputStreamReader(stream))
- .lines()
- .forEach(out::println))
- .start();
+ public static void main(String[] args) {
+ System.err.println("From child stderr");
}
}