blob: 8d9cffc838dbbb2df4df129edae5b335d536fb62 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.shell;
16
17
18import java.io.File;
19import java.io.IOException;
20import java.io.InputStream;
21import java.io.OutputStream;
22import java.util.Collections;
23import java.util.List;
24import java.util.Map;
25import java.util.logging.Level;
26import java.util.logging.Logger;
27
28/**
29 * <p>Represents an executable command, including its arguments and
30 * runtime environment (environment variables, working directory). This class
31 * lets a caller execute a command, get its results, and optionally try to kill
32 * the task during execution.</p>
33 *
34 * <p>The use of "shell" in the full name of this class is a misnomer. In
35 * terms of the way its arguments are interpreted, this class is closer to
36 * {@code execve(2)} than to {@code system(3)}. No Bourne shell is executed.
37 *
38 * <p>The most basic use-case for this class is as follows:
39 * <pre>
40 * String[] args = { "/bin/du", "-s", directory };
41 * CommandResult result = new Command(args).execute();
42 * String output = new String(result.getStdout());
43 * </pre>
44 * which writes the output of the {@code du(1)} command into {@code output}.
45 * More complex cases might inspect the stderr stream, kill the subprocess
46 * asynchronously, feed input to its standard input, handle the exceptions
47 * thrown if the command fails, or print the termination status (exit code or
48 * signal name).
49 *
50 * <h4>Invoking the Bourne shell</h4>
51 *
52 * <p>Perhaps the most common command invoked programmatically is the UNIX
53 * shell, {@code /bin/sh}. Because the shell is a general-purpose programming
54 * language, care must be taken to ensure that variable parts of the shell
55 * command (e.g. strings entered by the user) do not contain shell
56 * metacharacters, as this poses a correctness and/or security risk.
57 *
58 * <p>To execute a shell command directly, use the following pattern:
59 * <pre>
60 * String[] args = { "/bin/sh", "-c", shellCommand };
61 * CommandResult result = new Command(args).execute();
62 * </pre>
63 * {@code shellCommand} is a complete Bourne shell program, possibly containing
64 * all kinds of unescaped metacharacters. For example, here's a shell command
65 * that enumerates the working directories of all processes named "foo":
66 * <pre>ps auxx | grep foo | awk '{print $1}' |
67 * while read pid; do readlink /proc/$pid/cwd; done</pre>
68 * It is the responsibility of the caller to ensure that this string means what
69 * they intend.
70 *
71 * <p>Consider the risk posed by allowing the "foo" part of the previous
72 * command to be some arbitrary (untrusted) string called {@code processName}:
73 * <pre>
74 * // WARNING: unsafe!
75 * String shellCommand = "ps auxx | grep " + processName + " | awk '{print $1}' | "
76 * + "while read pid; do readlink /proc/$pid/cwd; done";</pre>
77 * </pre>
78 * Passing this string to {@link Command} is unsafe because if the string
79 * {@processName} contains shell metacharacters, the meaning of the command can
80 * be arbitrarily changed; consider:
81 * <pre>String processName = ". ; rm -fr $HOME & ";</pre>
82 *
83 * <p>To defend against this possibility, it is essential to properly quote the
84 * variable portions of the shell command so that shell metacharacters are
85 * escaped. Use {@link ShellUtils#shellEscape} for this purpose:
86 * <pre>
87 * // Safe.
88 * String shellCommand = "ps auxx | grep " + ShellUtils.shellEscape(processName)
89 * + " | awk '{print $1}' | while read pid; do readlink /proc/$pid/cwd; done";
90 * </pre>
91 *
92 * <p>Tip: if you are only invoking a single known command, and no shell
93 * features (e.g. $PATH lookup, output redirection, pipelines, etc) are needed,
94 * call it directly without using a shell, as in the {@code du(1)} example
95 * above.
96 *
97 * <h4>Other features</h4>
98 *
99 * <p>A caller can optionally specify bytes to be written to the process's
100 * "stdin". The returned {@link CommandResult} object gives the caller access to
101 * the exit status, as well as output from "stdout" and "stderr". To use
102 * this class with processes that generate very large amounts of input/output,
103 * consider
104 * {@link #execute(InputStream, KillableObserver, OutputStream, OutputStream)}
105 * and
106 * {@link #execute(byte[], KillableObserver, OutputStream, OutputStream)}.
107 * </p>
108 *
109 * <p>This class ensures that stdout and stderr streams are read promptly,
110 * avoiding potential deadlock if the output is large. See <a
111 * href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html"> When
112 * <code>Runtime.exec()</code> won't</a>.</p>
113 *
114 * <p>This class is immutable and therefore thread-safe.</p>
115 */
116public final class Command {
117
118 private static final Logger log =
119 Logger.getLogger("com.google.devtools.build.lib.shell.Command");
120
121 /**
122 * Pass this value to {@link #execute(byte[])} to indicate that no input
123 * should be written to stdin.
124 */
125 public static final byte[] NO_INPUT = new byte[0];
126
127 private static final String[] EMPTY_STRING_ARRAY = new String[0];
128
129 /**
130 * Pass this to {@link #execute(byte[], KillableObserver, boolean)} to
131 * indicate that you do not wish to observe / kill the underlying
132 * process.
133 */
134 public static final KillableObserver NO_OBSERVER = new KillableObserver() {
135 @Override
136 public void startObserving(final Killable killable) {
137 // do nothing
138 }
139 @Override
140 public void stopObserving(final Killable killable) {
141 // do nothing
142 }
143 };
144
145 private final ProcessBuilder processBuilder;
146
147 // Start of public API -----------------------------------------------------
148
149 /**
150 * Creates a new {@link Command} that will execute a command line that
151 * is described by a {@link ProcessBuilder}. Command line elements,
152 * environment, and working directory are taken from this object. The
153 * command line is executed exactly as given, without a shell.
154 *
155 * @param processBuilder {@link ProcessBuilder} describing command line
156 * to execute
157 */
158 public Command(final ProcessBuilder processBuilder) {
159 this(processBuilder.command().toArray(EMPTY_STRING_ARRAY),
160 processBuilder.environment(),
161 processBuilder.directory());
162 }
163
164 /**
165 * Creates a new {@link Command} for the given command line elements. The
166 * command line is executed exactly as given, without a shell.
167 * Subsequent calls to {@link #execute()} will use the JVM's working
168 * directory and environment.
169 *
170 * @param commandLineElements elements of raw command line to execute
171 * @throws IllegalArgumentException if commandLine is null or empty
172 */
173 /* TODO(bazel-team): Use varargs here
174 */
175 public Command(final String[] commandLineElements) {
176 this(commandLineElements, null, null);
177 }
178
179 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100180 * Creates a new {@link Command} for the given command line elements. The
181 * command line is executed exactly as given, without a shell. The given
182 * environment variables and working directory are used in subsequent
183 * calls to {@link #execute()}.
184 *
185 * @param commandLineElements elements of raw command line to execute
186 * @param environmentVariables environment variables to replace JVM's
187 * environment variables; may be null
188 * @param workingDirectory working directory for execution; if null, current
189 * working directory is used
190 * @throws IllegalArgumentException if commandLine is null or empty
191 */
192 public Command(final String[] commandLineElements,
193 final Map<String, String> environmentVariables,
194 final File workingDirectory) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100195 if (commandLineElements == null || commandLineElements.length == 0) {
196 throw new IllegalArgumentException("command line is null or empty");
197 }
198 this.processBuilder =
Han-Wen Nienhuysefe7f662015-02-16 13:34:57 +0000199 new ProcessBuilder(commandLineElements);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100200 if (environmentVariables != null) {
201 // TODO(bazel-team) remove next line eventually; it is here to mimic old
202 // Runtime.exec() behavior
203 this.processBuilder.environment().clear();
204 this.processBuilder.environment().putAll(environmentVariables);
205 }
206 this.processBuilder.directory(workingDirectory);
207 }
208
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100209 /**
210 * @return raw command line elements to be executed
211 */
212 public String[] getCommandLineElements() {
213 final List<String> elements = processBuilder.command();
214 return elements.toArray(new String[elements.size()]);
215 }
216
217 /**
218 * @return (unmodifiable) {@link Map} view of command's environment variables
219 */
220 public Map<String, String> getEnvironmentVariables() {
221 return Collections.unmodifiableMap(processBuilder.environment());
222 }
223
224 /**
225 * @return working directory used for execution, or null if the current
226 * working directory is used
227 */
228 public File getWorkingDirectory() {
229 return processBuilder.directory();
230 }
231
232 /**
233 * Execute this command with no input to stdin. This call will block until the
234 * process completes or an error occurs.
235 *
236 * @return {@link CommandResult} representing result of the execution
237 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
238 * reason
239 * @throws AbnormalTerminationException if an {@link IOException} is
240 * encountered while reading from the process, or the process was terminated
241 * due to a signal.
242 * @throws BadExitStatusException if the process exits with a
243 * non-zero status
244 */
245 public CommandResult execute() throws CommandException {
246 return execute(NO_INPUT);
247 }
248
249 /**
250 * Execute this command with given input to stdin. This call will block until
251 * the process completes or an error occurs.
252 *
253 * @param stdinInput bytes to be written to process's stdin
254 * @return {@link CommandResult} representing result of the execution
255 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
256 * reason
257 * @throws AbnormalTerminationException if an {@link IOException} is
258 * encountered while reading from the process, or the process was terminated
259 * due to a signal.
260 * @throws BadExitStatusException if the process exits with a
261 * non-zero status
262 * @throws NullPointerException if stdin is null
263 */
264 public CommandResult execute(final byte[] stdinInput)
265 throws CommandException {
266 nullCheck(stdinInput, "stdinInput");
267 return doExecute(new ByteArrayInputSource(stdinInput),
268 NO_OBSERVER,
269 Consumers.createAccumulatingConsumers(),
270 /*killSubprocess=*/false, /*closeOutput=*/false).get();
271 }
272
273 /**
274 * <p>Execute this command with given input to stdin. This call will block
275 * until the process completes or an error occurs. Caller may specify
276 * whether the method should ignore stdout/stderr output. If the
277 * given number of milliseconds elapses before the command has
278 * completed, this method will attempt to kill the command.</p>
279 *
280 * @param stdinInput bytes to be written to process's stdin, or
281 * {@link #NO_INPUT} if no bytes should be written
282 * @param timeout number of milliseconds to wait for command completion
283 * before attempting to kill the command
284 * @param ignoreOutput if true, method will ignore stdout/stderr output
285 * and return value will not contain this data
286 * @return {@link CommandResult} representing result of the execution
287 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
288 * reason
289 * @throws AbnormalTerminationException if an {@link IOException} is
290 * encountered while reading from the process, or the process was terminated
291 * due to a signal.
292 * @throws BadExitStatusException if the process exits with a
293 * non-zero status
294 * @throws NullPointerException if stdin is null
295 */
296 public CommandResult execute(final byte[] stdinInput,
297 final long timeout,
298 final boolean ignoreOutput)
299 throws CommandException {
300 return execute(stdinInput,
301 new TimeoutKillableObserver(timeout),
302 ignoreOutput);
303 }
304
305 /**
306 * <p>Execute this command with given input to stdin. This call will block
307 * until the process completes or an error occurs. Caller may specify
308 * whether the method should ignore stdout/stderr output. The given {@link
309 * KillableObserver} may also terminate the process early while running.</p>
310 *
311 * @param stdinInput bytes to be written to process's stdin, or
312 * {@link #NO_INPUT} if no bytes should be written
313 * @param observer {@link KillableObserver} that should observe the running
314 * process, or {@link #NO_OBSERVER} if caller does not wish to kill
315 * the process
316 * @param ignoreOutput if true, method will ignore stdout/stderr output
317 * and return value will not contain this data
318 * @return {@link CommandResult} representing result of the execution
319 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
320 * reason
321 * @throws AbnormalTerminationException if the process is interrupted (or
322 * killed) before completion, if an {@link IOException} is encountered while
323 * reading from the process, or the process was terminated due to a signal.
324 * @throws BadExitStatusException if the process exits with a
325 * non-zero status
326 * @throws NullPointerException if stdin is null
327 */
328 public CommandResult execute(final byte[] stdinInput,
329 final KillableObserver observer,
330 final boolean ignoreOutput)
331 throws CommandException {
332 // supporting "null" here for backwards compatibility
333 final KillableObserver theObserver =
334 observer == null ? NO_OBSERVER : observer;
335 return doExecute(new ByteArrayInputSource(stdinInput),
336 theObserver,
337 ignoreOutput ? Consumers.createDiscardingConsumers()
338 : Consumers.createAccumulatingConsumers(),
339 /*killSubprocess=*/false, /*closeOutput=*/false).get();
340 }
341
342 /**
343 * <p>Execute this command with given input to stdin. This call blocks
344 * until the process completes or an error occurs. The caller provides
345 * {@link OutputStream} instances into which the process writes its
346 * stdout/stderr output; these streams are <em>not</em> closed when the
347 * process terminates. The given {@link KillableObserver} may also
348 * terminate the process early while running.</p>
349 *
350 * <p>Note that stdout and stderr are written concurrently. If these are
351 * aliased to each other, it is the caller's duty to ensure thread safety.
352 * </p>
353 *
354 * @param stdinInput bytes to be written to process's stdin, or
355 * {@link #NO_INPUT} if no bytes should be written
356 * @param observer {@link KillableObserver} that should observe the running
357 * process, or {@link #NO_OBSERVER} if caller does not wish to kill the
358 * process
359 * @param stdOut the process will write its standard output into this stream.
360 * E.g., you could pass {@link System#out} as <code>stdOut</code>.
361 * @param stdErr the process will write its standard error into this stream.
362 * E.g., you could pass {@link System#err} as <code>stdErr</code>.
363 * @return {@link CommandResult} representing result of the execution. Note
364 * that {@link CommandResult#getStdout()} and
365 * {@link CommandResult#getStderr()} will yield {@link IllegalStateException}
366 * in this case, as the output is written to <code>stdOut/stdErr</code>
367 * instead.
368 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
369 * reason
370 * @throws AbnormalTerminationException if the process is interrupted (or
371 * killed) before completion, if an {@link IOException} is encountered while
372 * reading from the process, or the process was terminated due to a signal.
373 * @throws BadExitStatusException if the process exits with a
374 * non-zero status
375 * @throws NullPointerException if any argument is null.
376 */
377 public CommandResult execute(final byte[] stdinInput,
378 final KillableObserver observer,
379 final OutputStream stdOut,
380 final OutputStream stdErr)
381 throws CommandException {
382 return execute(stdinInput, observer, stdOut, stdErr, false);
383 }
384
385 /**
386 * Like {@link #execute(byte[], KillableObserver, OutputStream, OutputStream)}
387 * but enables setting of the killSubprocessOnInterrupt attribute.
388 *
389 * @param killSubprocessOnInterrupt if set to true, the execution of
390 * this command is <i>interruptible</i>: in other words, if this thread is
391 * interrupted during a call to execute, the subprocess will be terminated
392 * and the call will return in a timely manner. If false, the subprocess
393 * will run to completion; this is the default value use by all other
394 * constructors. The thread's interrupted status is preserved in all cases,
395 * however.
396 */
397 public CommandResult execute(final byte[] stdinInput,
398 final KillableObserver observer,
399 final OutputStream stdOut,
400 final OutputStream stdErr,
401 final boolean killSubprocessOnInterrupt)
402 throws CommandException {
403 nullCheck(stdinInput, "stdinInput");
404 nullCheck(observer, "observer");
405 nullCheck(stdOut, "stdOut");
406 nullCheck(stdErr, "stdErr");
407 return doExecute(new ByteArrayInputSource(stdinInput),
408 observer,
409 Consumers.createStreamingConsumers(stdOut, stdErr),
410 killSubprocessOnInterrupt, false).get();
411 }
412
413 /**
414 * <p>Execute this command with given input to stdin; this stream is closed
415 * when the process terminates, and exceptions raised when closing this
416 * stream are ignored. This call blocks
417 * until the process completes or an error occurs. The caller provides
418 * {@link OutputStream} instances into which the process writes its
419 * stdout/stderr output; these streams are <em>not</em> closed when the
420 * process terminates. The given {@link KillableObserver} may also
421 * terminate the process early while running.</p>
422 *
423 * @param stdinInput The input to this process's stdin
424 * @param observer {@link KillableObserver} that should observe the running
425 * process, or {@link #NO_OBSERVER} if caller does not wish to kill the
426 * process
427 * @param stdOut the process will write its standard output into this stream.
428 * E.g., you could pass {@link System#out} as <code>stdOut</code>.
429 * @param stdErr the process will write its standard error into this stream.
430 * E.g., you could pass {@link System#err} as <code>stdErr</code>.
431 * @return {@link CommandResult} representing result of the execution. Note
432 * that {@link CommandResult#getStdout()} and
433 * {@link CommandResult#getStderr()} will yield {@link IllegalStateException}
434 * in this case, as the output is written to <code>stdOut/stdErr</code>
435 * instead.
436 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
437 * reason
438 * @throws AbnormalTerminationException if the process is interrupted (or
439 * killed) before completion, if an {@link IOException} is encountered while
440 * reading from the process, or the process was terminated due to a signal.
441 * @throws BadExitStatusException if the process exits with a
442 * non-zero status
443 * @throws NullPointerException if any argument is null.
444 */
445 public CommandResult execute(final InputStream stdinInput,
446 final KillableObserver observer,
447 final OutputStream stdOut,
448 final OutputStream stdErr)
449 throws CommandException {
450 nullCheck(stdinInput, "stdinInput");
451 nullCheck(observer, "observer");
452 nullCheck(stdOut, "stdOut");
453 nullCheck(stdErr, "stdErr");
454 return doExecute(new InputStreamInputSource(stdinInput),
455 observer,
456 Consumers.createStreamingConsumers(stdOut, stdErr),
457 /*killSubprocess=*/false, /*closeOutput=*/false).get();
458 }
459
460 /**
461 * <p>Execute this command with given input to stdin; this stream is closed
462 * when the process terminates, and exceptions raised when closing this
463 * stream are ignored. This call blocks
464 * until the process completes or an error occurs. The caller provides
465 * {@link OutputStream} instances into which the process writes its
466 * stdout/stderr output; these streams are closed when the process terminates
467 * if closeOut is set. The given {@link KillableObserver} may also
468 * terminate the process early while running.</p>
469 *
470 * @param stdinInput The input to this process's stdin
471 * @param observer {@link KillableObserver} that should observe the running
472 * process, or {@link #NO_OBSERVER} if caller does not wish to kill the
473 * process
474 * @param stdOut the process will write its standard output into this stream.
475 * E.g., you could pass {@link System#out} as <code>stdOut</code>.
476 * @param stdErr the process will write its standard error into this stream.
477 * E.g., you could pass {@link System#err} as <code>stdErr</code>.
478 * @param closeOut whether to close the output streams when the subprocess
479 * terminates.
480 * @return {@link CommandResult} representing result of the execution. Note
481 * that {@link CommandResult#getStdout()} and
482 * {@link CommandResult#getStderr()} will yield {@link IllegalStateException}
483 * in this case, as the output is written to <code>stdOut/stdErr</code>
484 * instead.
485 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
486 * reason
487 * @throws AbnormalTerminationException if the process is interrupted (or
488 * killed) before completion, if an {@link IOException} is encountered while
489 * reading from the process, or the process was terminated due to a signal.
490 * @throws BadExitStatusException if the process exits with a
491 * non-zero status
492 * @throws NullPointerException if any argument is null.
493 */
494 public CommandResult execute(final InputStream stdinInput,
495 final KillableObserver observer,
496 final OutputStream stdOut,
497 final OutputStream stdErr,
498 boolean closeOut)
499 throws CommandException {
500 nullCheck(stdinInput, "stdinInput");
501 nullCheck(observer, "observer");
502 nullCheck(stdOut, "stdOut");
503 nullCheck(stdErr, "stdErr");
504 return doExecute(new InputStreamInputSource(stdinInput),
505 observer,
506 Consumers.createStreamingConsumers(stdOut, stdErr),
507 false, closeOut).get();
508 }
509
510 /**
511 * <p>Executes this command with the given stdinInput, but does not
512 * wait for it to complete. The caller may choose to observe the status
513 * of the launched process by calling methods on the returned object.
514 *
515 * @param stdinInput bytes to be written to process's stdin, or
516 * {@link #NO_INPUT} if no bytes should be written
517 * @return An object that can be used to check if the process terminated and
518 * obtain the process results.
519 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
520 * reason
521 * @throws NullPointerException if stdin is null
522 */
523 public FutureCommandResult executeAsynchronously(final byte[] stdinInput)
524 throws CommandException {
525 return executeAsynchronously(stdinInput, NO_OBSERVER);
526 }
527
528 /**
529 * <p>Executes this command with the given input to stdin, but does
530 * not wait for it to complete. The caller may choose to observe the
531 * status of the launched process by calling methods on the returned
532 * object. This method performs the minimum cleanup after the
533 * process terminates: It closes the input stream, and it ignores
534 * exceptions that result from closing it. The given {@link
535 * KillableObserver} may also terminate the process early while
536 * running.</p>
537 *
538 * <p>Note that in this case the {@link KillableObserver} will be assigned
539 * to start observing the process via
540 * {@link KillableObserver#startObserving(Killable)} but will only be
541 * unassigned via {@link KillableObserver#stopObserving(Killable)}, if
542 * {@link FutureCommandResult#get()} is called. If the
543 * {@link KillableObserver} implementation used with this method will
544 * not work correctly without calls to
545 * {@link KillableObserver#stopObserving(Killable)} then a new instance
546 * should be used for each call to this method.</p>
547 *
548 * @param stdinInput bytes to be written to process's stdin, or
549 * {@link #NO_INPUT} if no bytes should be written
550 * @param observer {@link KillableObserver} that should observe the running
551 * process, or {@link #NO_OBSERVER} if caller does not wish to kill
552 * the process
553 * @return An object that can be used to check if the process terminated and
554 * obtain the process results.
555 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
556 * reason
557 * @throws NullPointerException if stdin is null
558 */
559 public FutureCommandResult executeAsynchronously(final byte[] stdinInput,
560 final KillableObserver observer)
561 throws CommandException {
562 // supporting "null" here for backwards compatibility
563 final KillableObserver theObserver =
564 observer == null ? NO_OBSERVER : observer;
565 nullCheck(stdinInput, "stdinInput");
566 return doExecute(new ByteArrayInputSource(stdinInput),
567 theObserver,
568 Consumers.createDiscardingConsumers(),
569 /*killSubprocess=*/false, /*closeOutput=*/false);
570 }
571
572 /**
573 * <p>Executes this command with the given input to stdin, but does
574 * not wait for it to complete. The caller may choose to observe the
575 * status of the launched process by calling methods on the returned
576 * object. This method performs the minimum cleanup after the
577 * process terminates: It closes the input stream, and it ignores
578 * exceptions that result from closing it. The caller provides
579 * {@link OutputStream} instances into which the process writes its
580 * stdout/stderr output; these streams are <em>not</em> closed when
581 * the process terminates. The given {@link KillableObserver} may
582 * also terminate the process early while running.</p>
583 *
584 * <p>Note that stdout and stderr are written concurrently. If these are
585 * aliased to each other, or if the caller continues to write to these
586 * streams, it is the caller's duty to ensure thread safety.
587 * </p>
588 *
589 * <p>Note that in this case the {@link KillableObserver} will be assigned
590 * to start observing the process via
591 * {@link KillableObserver#startObserving(Killable)} but will only be
592 * unassigned via {@link KillableObserver#stopObserving(Killable)}, if
593 * {@link FutureCommandResult#get()} is called. If the
594 * {@link KillableObserver} implementation used with this method will
595 * not work correctly without calls to
596 * {@link KillableObserver#stopObserving(Killable)} then a new instance
597 * should be used for each call to this method.</p>
598 *
599 * @param stdinInput The input to this process's stdin
600 * @param observer {@link KillableObserver} that should observe the running
601 * process, or {@link #NO_OBSERVER} if caller does not wish to kill
602 * the process
603 * @param stdOut the process will write its standard output into this stream.
604 * E.g., you could pass {@link System#out} as <code>stdOut</code>.
605 * @param stdErr the process will write its standard error into this stream.
606 * E.g., you could pass {@link System#err} as <code>stdErr</code>.
607 * @return An object that can be used to check if the process terminated and
608 * obtain the process results.
609 * @throws ExecFailedException if {@link Runtime#exec(String[])} fails for any
610 * reason
611 * @throws NullPointerException if stdin is null
612 */
613 public FutureCommandResult executeAsynchronously(final InputStream stdinInput,
614 final KillableObserver observer,
615 final OutputStream stdOut,
616 final OutputStream stdErr)
617 throws CommandException {
618 // supporting "null" here for backwards compatibility
619 final KillableObserver theObserver =
620 observer == null ? NO_OBSERVER : observer;
621 nullCheck(stdinInput, "stdinInput");
622 return doExecute(new InputStreamInputSource(stdinInput),
623 theObserver,
624 Consumers.createStreamingConsumers(stdOut, stdErr),
625 /*killSubprocess=*/false, /*closeOutput=*/false);
626 }
627
628 // End of public API -------------------------------------------------------
629
630 private void nullCheck(Object argument, String argumentName) {
631 if (argument == null) {
632 String message = argumentName + " argument must not be null.";
633 throw new NullPointerException(message);
634 }
635 }
636
637 private FutureCommandResult doExecute(final InputSource stdinInput,
638 final KillableObserver observer,
639 final Consumers.OutErrConsumers outErrConsumers,
640 final boolean killSubprocessOnInterrupt,
641 final boolean closeOutputStreams)
642 throws CommandException {
643
644 logCommand();
645
646 final Process process = startProcess();
647
648 outErrConsumers.logConsumptionStrategy();
649
650 outErrConsumers.registerInputs(process.getInputStream(),
651 process.getErrorStream(),
652 closeOutputStreams);
653
654 processInput(stdinInput, process);
655
656 // TODO(bazel-team): if the input stream is unbounded, observers will not get start
657 // notification in a timely manner!
658 final Killable processKillable = observeProcess(process, observer);
659
660 return new FutureCommandResult() {
661 @Override
662 public CommandResult get() throws AbnormalTerminationException {
663 return waitForProcessToComplete(process,
664 observer,
665 processKillable,
666 outErrConsumers,
667 killSubprocessOnInterrupt);
668 }
669
670 @Override
671 public boolean isDone() {
672 try {
673 // exitValue seems to be the only non-blocking call for
674 // checking process liveness.
675 process.exitValue();
676 return true;
677 } catch (IllegalThreadStateException e) {
678 return false;
679 }
680 }
681 };
682 }
683
684 private Process startProcess()
685 throws ExecFailedException {
686 try {
687 return processBuilder.start();
688 } catch (IOException ioe) {
689 throw new ExecFailedException(this, ioe);
690 }
691 }
692
693 private static interface InputSource {
694 void copyTo(OutputStream out) throws IOException;
695 boolean isEmpty();
696 String toLogString(String sourceName);
697 }
698
699 private static class ByteArrayInputSource implements InputSource {
700 private byte[] bytes;
701 ByteArrayInputSource(byte[] bytes){
702 this.bytes = bytes;
703 }
704 @Override
705 public void copyTo(OutputStream out) throws IOException {
706 out.write(bytes);
707 out.flush();
708 }
709 @Override
710 public boolean isEmpty() {
711 return bytes.length == 0;
712 }
713 @Override
714 public String toLogString(String sourceName) {
715 if (isEmpty()) {
716 return "No input to " + sourceName;
717 } else {
718 return "Input to " + sourceName + ": " +
719 LogUtil.toTruncatedString(bytes);
720 }
721 }
722 }
723
724 private static class InputStreamInputSource implements InputSource {
725 private InputStream inputStream;
726 InputStreamInputSource(InputStream inputStream){
727 this.inputStream = inputStream;
728 }
729 @Override
730 public void copyTo(OutputStream out) throws IOException {
731 byte[] buf = new byte[4096];
732 int r;
733 while ((r = inputStream.read(buf)) != -1) {
734 out.write(buf, 0, r);
735 out.flush();
736 }
737 }
738 @Override
739 public boolean isEmpty() {
740 return false;
741 }
742 @Override
743 public String toLogString(String sourceName) {
744 return "Input to " + sourceName + " is a stream.";
745 }
746 }
747
748 private static void processInput(final InputSource stdinInput,
749 final Process process) {
750 if (log.isLoggable(Level.FINER)) {
751 log.finer(stdinInput.toLogString("stdin"));
752 }
753 try {
754 if (stdinInput.isEmpty()) {
755 return;
756 }
757 stdinInput.copyTo(process.getOutputStream());
758 } catch (IOException ioe) {
759 // Note: this is not an error! Perhaps the command just isn't hungry for
760 // our input and exited with success. Process.waitFor (later) will tell
761 // us.
762 //
763 // (Unlike out/err streams, which are read asynchronously, the input stream is written
764 // synchronously, in its entirety, before processInput returns. If the input is
765 // infinite, and is passed through e.g. "cat" subprocess and back into the
766 // ByteArrayOutputStream, that will eventually run out of memory, causing the output stream
767 // to be closed, "cat" to terminate with SIGPIPE, and processInput to receive an IOException.
768 } finally {
769 // if this statement is ever deleted, the process's outputStream
770 // must be closed elsewhere -- it is not closed automatically
771 Command.silentClose(process.getOutputStream());
772 }
773 }
774
775 private static Killable observeProcess(final Process process,
776 final KillableObserver observer) {
777 final Killable processKillable = new ProcessKillable(process);
778 observer.startObserving(processKillable);
779 return processKillable;
780 }
781
782 private CommandResult waitForProcessToComplete(
783 final Process process,
784 final KillableObserver observer,
785 final Killable processKillable,
786 final Consumers.OutErrConsumers outErr,
787 final boolean killSubprocessOnInterrupt)
788 throws AbnormalTerminationException {
789
790 log.finer("Waiting for process...");
791
792 TerminationStatus status =
793 waitForProcess(process, killSubprocessOnInterrupt);
794
795 observer.stopObserving(processKillable);
796
797 log.finer(status.toString());
798
799 try {
800 outErr.waitForCompletion();
801 } catch (IOException ioe) {
802 CommandResult noOutputResult =
803 new CommandResult(CommandResult.EMPTY_OUTPUT,
804 CommandResult.EMPTY_OUTPUT,
805 status);
806 if (status.success()) {
807 // If command was otherwise successful, throw an exception about this
808 throw new AbnormalTerminationException(this, noOutputResult, ioe);
809 } else {
810 // Otherwise, throw the more important exception -- command
811 // was not successful
812 String message = status
813 + "; also encountered an error while attempting to retrieve output";
814 throw status.exited()
815 ? new BadExitStatusException(this, noOutputResult, message, ioe)
816 : new AbnormalTerminationException(this,
817 noOutputResult, message, ioe);
818 }
819 }
820
821 CommandResult result = new CommandResult(outErr.getAccumulatedOut(),
822 outErr.getAccumulatedErr(),
823 status);
824 result.logThis();
825 if (status.success()) {
826 return result;
827 } else if (status.exited()) {
828 throw new BadExitStatusException(this, result, status.toString());
829 } else {
830 throw new AbnormalTerminationException(this, result, status.toString());
831 }
832 }
833
834 private static TerminationStatus waitForProcess(Process process,
835 boolean killSubprocessOnInterrupt) {
836 boolean wasInterrupted = false;
837 try {
838 while (true) {
839 try {
840 return new TerminationStatus(process.waitFor());
841 } catch (InterruptedException ie) {
842 wasInterrupted = true;
843 if (killSubprocessOnInterrupt) {
844 process.destroy();
845 }
846 }
847 }
848 } finally {
Philipp Wollermann28f08f12015-09-21 13:42:01 +0000849 // Read this for detailed explanation: http://www.ibm.com/developerworks/library/j-jtp05236/
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100850 if (wasInterrupted) {
851 Thread.currentThread().interrupt(); // preserve interrupted status
852 }
853 }
854 }
855
856 private void logCommand() {
857 if (!log.isLoggable(Level.FINE)) {
858 return;
859 }
860 log.fine(toDebugString());
861 }
862
863 /**
864 * A string representation of this command object which includes
865 * the arguments, the environment, and the working directory. Avoid
866 * relying on the specifics of this format. Note that the size
867 * of the result string will reflect the size of the command.
868 */
869 public String toDebugString() {
870 StringBuilder message = new StringBuilder(128);
871 message.append("Executing (without brackets):");
872 for (final String arg : processBuilder.command()) {
873 message.append(" [");
874 message.append(arg);
875 message.append(']');
876 }
877 message.append("; environment: ");
Ulf Adams07dba942015-03-05 14:47:37 +0000878 message.append(processBuilder.environment());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100879 final File workingDirectory = processBuilder.directory();
880 message.append("; working dir: ");
881 message.append(workingDirectory == null ?
882 "(current)" :
883 workingDirectory.toString());
884 return message.toString();
885 }
886
887 /**
888 * Close the <code>out</code> stream and log a warning if anything happens.
889 */
890 private static void silentClose(final OutputStream out) {
891 try {
892 out.close();
893 } catch (IOException ioe) {
894 String message = "Unexpected exception while closing output stream";
895 log.log(Level.WARNING, message, ioe);
896 }
897 }
898}