12
12
import java .util .concurrent .ExecutorService ;
13
13
import java .util .concurrent .Executors ;
14
14
import java .util .concurrent .TimeUnit ;
15
+ import java .util .stream .Collectors ;
15
16
16
17
import static java .lang .String .format ;
17
18
import static java .lang .String .join ;
@@ -25,7 +26,7 @@ public class CommandExecutor implements Serializable {
25
26
private static final int READER_SHUTDOWN_TIMEOUT_SECONDS = 30 ;
26
27
private static final int PROCESS_TERMINATION_TIMEOUT_SECONDS = 30 ;
27
28
private static final int EXECUTION_TIMEOUT_MINUTES = 120 ;
28
- private final String [] env ;
29
+ private Map < String , String > env ;
29
30
private final String executablePath ;
30
31
31
32
/**
@@ -40,7 +41,7 @@ public CommandExecutor(String executablePath, Map<String, String> env) {
40
41
fixPathEnv (fixedEnvMap );
41
42
finalEnvMap .putAll (fixedEnvMap );
42
43
}
43
- this .env = finalEnvMap . entrySet (). stream (). map ( entry -> entry . getKey () + "=" + entry . getValue ()). toArray ( String []:: new );
44
+ this .env = new HashMap <>( finalEnvMap );
44
45
}
45
46
46
47
/**
@@ -62,19 +63,6 @@ private void fixPathEnv(Map<String, String> env) {
62
63
env .replace ("PATH" , path );
63
64
}
64
65
65
- /**
66
- * Escape spaces in the input executable path and trim leading and trailing whitespaces.
67
- *
68
- * @param executablePath - the executable path to process
69
- * @return escaped and trimmed executable path.
70
- */
71
- private static String escapeSpacesInPath (String executablePath ) {
72
- if (executablePath == null ) {
73
- return null ;
74
- }
75
- return executablePath .trim ().replaceAll (" " , SystemUtils .IS_OS_WINDOWS ? "^ " : "\\ \\ " );
76
- }
77
-
78
66
/**
79
67
* Fix the PATH value to be valid for execution on a Windows machine.
80
68
* Take care of a case when either non-Windows or Windows environment-variables are received.
@@ -144,10 +132,11 @@ public CommandResults exeCommand(File execDir, List<String> args, List<String> c
144
132
* @return CommandResults object
145
133
*/
146
134
public CommandResults exeCommand (File execDir , List <String > args , List <String > credentials , Log logger , long timeout , TimeUnit unit ) throws InterruptedException , IOException {
147
- args .add (0 , executablePath );
135
+ List <String > command = new ArrayList <>(args );
136
+ command .add (0 , executablePath );
148
137
ExecutorService service = Executors .newFixedThreadPool (2 );
149
138
try {
150
- Process process = runProcess (execDir , args , credentials , env , logger );
139
+ Process process = runProcess (execDir , command , credentials , env , logger );
151
140
// The output stream is not necessary in non-interactive scenarios, therefore we can close it now.
152
141
process .getOutputStream ().close ();
153
142
try (InputStream inputStream = process .getInputStream (); InputStream errorStream = process .getErrorStream ()) {
@@ -159,7 +148,7 @@ public CommandResults exeCommand(File execDir, List<String> args, List<String> c
159
148
service .shutdown ();
160
149
boolean outputReaderTerminatedProperly = service .awaitTermination (READER_SHUTDOWN_TIMEOUT_SECONDS , TimeUnit .SECONDS );
161
150
boolean terminatedProperly = executionTerminatedProperly && outputReaderTerminatedProperly ;
162
- return getCommandResults (terminatedProperly , args , inputStreamReader .getOutput (), errorStreamReader .getOutput (), process .exitValue ());
151
+ return getCommandResults (terminatedProperly , command , inputStreamReader .getOutput (), errorStreamReader .getOutput (), process .exitValue ());
163
152
} finally {
164
153
// Ensure termination of the subprocess we have created.
165
154
if (process .isAlive ()) {
@@ -177,6 +166,7 @@ public CommandResults exeCommand(File execDir, List<String> args, List<String> c
177
166
}
178
167
}
179
168
169
+
180
170
private CommandResults getCommandResults (boolean terminatedProperly , List <String > args , String output , String error , int exitValue ) {
181
171
CommandResults commandRes = new CommandResults ();
182
172
if (!terminatedProperly ) {
@@ -189,7 +179,7 @@ private CommandResults getCommandResults(boolean terminatedProperly, List<String
189
179
return commandRes ;
190
180
}
191
181
192
- private static Process runProcess (File execDir , List <String > args , List <String > credentials , String [] env , Log logger ) throws IOException {
182
+ private static Process runProcess (File execDir , List <String > args , List <String > credentials , Map < String , String > env , Log logger ) throws IOException {
193
183
if (credentials != null ) {
194
184
args .addAll (credentials );
195
185
}
@@ -204,7 +194,23 @@ private static Process runProcess(File execDir, List<String> args, List<String>
204
194
}};
205
195
}
206
196
logCommand (logger , args , credentials );
207
- return Runtime .getRuntime ().exec (args .toArray (new String [0 ]), env , execDir );
197
+ ProcessBuilder processBuilder = new ProcessBuilder (args )
198
+ .directory (execDir );
199
+ processBuilder .environment ().putAll (env );
200
+ return processBuilder .start ();
201
+ }
202
+
203
+ /**
204
+ * Escape spaces in the input executable path and trim leading and trailing whitespaces.
205
+ *
206
+ * @param executablePath - the executable path to process
207
+ * @return escaped and trimmed executable path.
208
+ */
209
+ private static String escapeSpacesInPath (String executablePath ) {
210
+ if (executablePath == null ) {
211
+ return null ;
212
+ }
213
+ return executablePath .trim ().replaceAll (" " , SystemUtils .IS_OS_WINDOWS ? "^ " : "\\ \\ " );
208
214
}
209
215
210
216
private static void logCommand (Log logger , List <String > args , List <String > credentials ) {
0 commit comments