77import org .slf4j .event .Level ;
88
99import java .io .IOException ;
10+ import java .io .UncheckedIOException ;
1011import java .util .StringJoiner ;
1112import java .util .concurrent .Semaphore ;
1213import java .util .concurrent .TimeUnit ;
@@ -22,7 +23,7 @@ public final class ProcessHelper {
2223 * environment variable (defaults to 4).
2324 *
2425 * @param command the command to be executed
25- * @return the merged stdout/stderr of the command
26+ * @return the standard output of the command
2627 * @throws ProcessException either if:
2728 * <ul>
2829 * <li>the command was unsuccessful
@@ -35,30 +36,44 @@ public final class ProcessHelper {
3536 public static String executeCommand (final String ... command ) throws ProcessException , InterruptedException {
3637 SEMAPHORE .acquire ();
3738
38- try (var process = new ProcessBuilder (command ).redirectErrorStream ( true ). start ()) {
39- var output = new StringJoiner ("\n " );
40- var readerThread = Thread .ofVirtual ().start (() -> {
39+ try (var process = new ProcessBuilder (command ).start ()) {
40+ var standardOutput = new StringJoiner ("\n " );
41+ var outputThread = Thread .ofVirtual ().start (() -> {
4142 try (var reader = process .inputReader (UTF_8 )) {
42- reader .lines ().forEach (output ::add );
43- } catch (IOException e ) {
44- LOGGER .at (Level .ERROR ).setCause (e ).log ("Error while closing process output reader" );
43+ reader .lines ().forEach (standardOutput ::add );
44+ } catch (IOException | UncheckedIOException e ) {
45+ LOGGER .at (Level .ERROR ).setCause (e ).log ("An error occurred using process output reader" );
46+ }
47+ });
48+
49+ var standardError = new StringJoiner ("\n " );
50+ var errorThread = Thread .ofVirtual ().start (() -> {
51+ try (var reader = process .errorReader (UTF_8 )) {
52+ reader .lines ().forEach (standardError ::add );
53+ } catch (IOException | UncheckedIOException e ) {
54+ LOGGER .at (Level .ERROR ).setCause (e ).log ("An error occurred using process error reader" );
4555 }
4656 });
4757
4858 var finished = process .waitFor (1 , TimeUnit .MINUTES );
4959 if (!finished ) {
5060 process .destroyForcibly ();
51- readerThread .join ();
52- throw new ProcessException ("The command {} timed out after 1m\n {}" , command [0 ], output .toString ());
61+ outputThread .join ();
62+ errorThread .join ();
63+ LOGGER .at (Level .WARN ).log ("The command {} timed out after 1m: {}" , command [0 ], standardError .toString ());
64+ throw new ProcessException ("The command {} timed out after 1m" , command [0 ]);
5365 }
5466
55- readerThread .join ();
67+ outputThread .join ();
68+ errorThread .join ();
69+
5670 var exitCode = process .exitValue ();
5771 if (exitCode != 0 ) {
58- throw new ProcessException ("The command {} exited with code {}\n {}" , command [0 ], exitCode , output .toString ());
72+ LOGGER .at (Level .WARN ).log ("The command {} exited with code {}: {}" , command [0 ], exitCode , standardError .toString ());
73+ throw new ProcessException ("The command {} exited with code {}" , command [0 ], exitCode );
5974 }
6075
61- return output .toString ();
76+ return standardOutput .toString ();
6277 } catch (IOException e ) {
6378 throw new ProcessException (e );
6479 } finally {
0 commit comments