Skip to content

Commit 6dadc59

Browse files
committed
fix: Processes.builder(...).withInput(String) not working correctly
1 parent 455fd33 commit 6dadc59

3 files changed

Lines changed: 92 additions & 15 deletions

File tree

jstuff-core/src/main/java/net/sf/jstuff/core/io/Processes.java

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -154,25 +154,38 @@ public ProcessWrapper start() throws IOException {
154154
pb.directory(workDir);
155155
}
156156

157+
/*
158+
* Configure ProcessBuilder redirects that must be set before start().
159+
*/
160+
if (input instanceof final File f) {
161+
pb.redirectInput(f);
162+
}
163+
if (redirectErrorToOutput) {
164+
pb.redirectErrorStream(true);
165+
} else if (redirectError instanceof final File f) {
166+
pb.redirectError(f);
167+
}
168+
if (redirectOutput instanceof final File f) {
169+
pb.redirectOutput(f);
170+
}
171+
157172
final Process proc = pb.start();
158173

159-
if (input != null) {
174+
/*
175+
* Handle stdin/output redirection that uses the process streams.
176+
*/
177+
if (input != null && !(input instanceof File)) {
160178
final var input = this.input;
161-
if (input instanceof final File f) {
162-
pb.redirectInput(f);
163-
} else if (input instanceof final InputStream is) {
179+
if (input instanceof final InputStream is) {
164180
writeToStdIn(is, proc);
165181
} else if (input instanceof final CharSequence cs) {
166182
writeToStdIn(cs, proc);
167183
}
168184
}
169-
if (redirectErrorToOutput) {
170-
pb.redirectError();
171-
} else if (redirectError != null) {
185+
186+
if (!redirectErrorToOutput && redirectError != null && !(redirectError instanceof File)) {
172187
final var redirectError = this.redirectError;
173-
if (redirectError instanceof final File f) {
174-
pb.redirectError(f);
175-
} else if (redirectError instanceof final OutputStream os) {
188+
if (redirectError instanceof final OutputStream os) {
176189
redirect(proc.getErrorStream(), os);
177190
} else if (redirectError instanceof final Appendable appendable) {
178191
redirect(proc.getErrorStream(), appendable);
@@ -181,11 +194,9 @@ public ProcessWrapper start() throws IOException {
181194
}
182195
}
183196

184-
if (redirectOutput != null) {
197+
if (redirectOutput != null && !(redirectOutput instanceof File)) {
185198
final var redirectOutput = this.redirectOutput;
186-
if (redirectOutput instanceof final File f) {
187-
pb.redirectOutput(f);
188-
} else if (redirectOutput instanceof final OutputStream os) {
199+
if (redirectOutput instanceof final OutputStream os) {
189200
redirect(proc.getInputStream(), os);
190201
} else if (redirectOutput instanceof final Appendable appendable) {
191202
redirect(proc.getInputStream(), appendable);
@@ -286,6 +297,7 @@ public Builder withRedirectError(final @Nullable PrintStream target) {
286297
public Builder withRedirectErrorToOutput() {
287298
if (redirectError != null)
288299
throw new IllegalArgumentException("withRedirectErrorToOutput() and withRedirectError() are mutually exclusive.");
300+
redirectErrorToOutput = true;
289301
return this;
290302
}
291303

jstuff-core/src/test/java/net/sf/jstuff/core/io/ProcessesTest.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import static org.assertj.core.api.Assertions.assertThat;
88

99
import java.io.IOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.util.List;
1013
import java.util.concurrent.CountDownLatch;
1114
import java.util.concurrent.TimeUnit;
1215

@@ -103,4 +106,66 @@ void testProgrammaticTermination() throws IOException, InterruptedException {
103106
Threads.sleep(1000);
104107
assertThat(signal.await(5, TimeUnit.SECONDS)).isTrue();
105108
}
109+
110+
@Test
111+
void testRedirectOutputToFile() throws IOException, InterruptedException {
112+
final Path outFile = Files.createTempFile("jstuff-processes-out", ".txt");
113+
try {
114+
final String exe;
115+
final List<String> args;
116+
if (SystemUtils.IS_OS_WINDOWS) {
117+
exe = "cmd";
118+
args = List.of("/c", "echo OUT-FILE");
119+
} else {
120+
exe = "sh";
121+
args = List.of("-c", "echo OUT-FILE");
122+
}
123+
124+
final ProcessWrapper prc = Processes.builder(exe) //
125+
.withArgs(args) //
126+
.withRedirectOutput(outFile) //
127+
.start() //
128+
.waitForExit(5, TimeUnit.SECONDS);
129+
130+
assertThat(prc.getState()).isEqualTo(Processes.ProcessState.SUCCEEDED);
131+
assertThat(prc.exitStatus()).isZero();
132+
133+
final String content = Files.readString(outFile);
134+
assertThat(content).contains("OUT-FILE");
135+
} finally {
136+
Files.deleteIfExists(outFile);
137+
}
138+
}
139+
140+
@Test
141+
void testRedirectErrorToOutputFile() throws IOException, InterruptedException {
142+
final Path outFile = Files.createTempFile("jstuff-processes-errout", ".txt");
143+
try {
144+
final String exe;
145+
final List<String> args;
146+
if (SystemUtils.IS_OS_WINDOWS) {
147+
exe = "cmd";
148+
args = List.of("/c", "echo OUT-LINE & echo ERR-LINE 1>&2");
149+
} else {
150+
exe = "sh";
151+
args = List.of("-c", "echo OUT-LINE; echo ERR-LINE 1>&2");
152+
}
153+
154+
final ProcessWrapper prc = Processes.builder(exe) //
155+
.withArgs(args) //
156+
.withRedirectErrorToOutput() //
157+
.withRedirectOutput(outFile) //
158+
.start() //
159+
.waitForExit(5, TimeUnit.SECONDS);
160+
161+
assertThat(prc.getState()).isEqualTo(Processes.ProcessState.SUCCEEDED);
162+
assertThat(prc.exitStatus()).isZero();
163+
164+
final String content = Files.readString(outFile);
165+
assertThat(content).contains("OUT-LINE");
166+
assertThat(content).contains("ERR-LINE");
167+
} finally {
168+
Files.deleteIfExists(outFile);
169+
}
170+
}
106171
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<parent>
1212
<groupId>com.vegardit.maven</groupId>
1313
<artifactId>vegardit-maven-parent</artifactId>
14-
<version>6.1.13</version>
14+
<version>6.1.14</version>
1515
</parent>
1616

1717
<groupId>net.sf.jstuff</groupId>

0 commit comments

Comments
 (0)