duct/lib.rs
1//! Duct is a library for running child processes. Duct makes it easy to build
2//! pipelines and redirect IO like a shell. At the same time, Duct helps you
3//! write correct, portable code: whitespace is never significant, errors from
4//! child processes get reported by default, and a variety of [gotchas, bugs,
5//! and platform
6//! inconsistencies](https://github.com/oconnor663/duct.py/blob/master/gotchas.md)
7//! are handled for you the Right Way™.
8//!
9//! - [Documentation](https://docs.rs/duct)
10//! - [Crate](https://crates.io/crates/duct)
11//! - [GitHub repo](https://github.com/oconnor663/duct.rs)
12//! - [the same library, in Python](https://github.com/oconnor663/duct.py)
13//!
14//! Examples
15//! --------
16//!
17//! Run a command without capturing any output. Here "hi" is printed directly
18//! to the terminal:
19//!
20//! ```
21//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
22//! # if cfg!(not(windows)) {
23//! use duct::cmd;
24//! cmd!("echo", "hi").run()?;
25//! # }
26//! # Ok(())
27//! # }
28//! ```
29//!
30//! Capture the standard output of a command. Here "hi" is returned as a
31//! `String`:
32//!
33//! ```
34//! # use duct::cmd;
35//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
36//! # if cfg!(not(windows)) {
37//! let stdout = cmd!("echo", "hi").read()?;
38//! assert_eq!(stdout, "hi");
39//! # }
40//! # Ok(())
41//! # }
42//! ```
43//!
44//! Capture the standard output of a pipeline:
45//!
46//! ```
47//! # use duct::cmd;
48//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
49//! # if cfg!(not(windows)) {
50//! let stdout = cmd!("echo", "hi").pipe(cmd!("sed", "s/i/o/")).read()?;
51//! assert_eq!(stdout, "ho");
52//! # }
53//! # Ok(())
54//! # }
55//! ```
56//!
57//! Merge standard error into standard output and read both incrementally:
58//!
59//! ```
60//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
61//! # if cfg!(not(windows)) {
62//! use duct::cmd;
63//! use std::io::prelude::*;
64//! use std::io::BufReader;
65//!
66//! let big_cmd = cmd!("bash", "-c", "echo out && echo err 1>&2");
67//! let reader = big_cmd.stderr_to_stdout().reader()?;
68//! let mut lines = BufReader::new(reader).lines();
69//! assert_eq!(lines.next().unwrap()?, "out");
70//! assert_eq!(lines.next().unwrap()?, "err");
71//! # }
72//! # Ok(())
73//! # }
74//! ```
75//!
76//! Children that exit with a non-zero status return an error by default:
77//!
78//! ```
79//! # use duct::cmd;
80//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
81//! # if cfg!(not(windows)) {
82//! let result = cmd!("false").run();
83//! assert!(result.is_err());
84//! let result = cmd!("false").unchecked().run();
85//! assert!(result.is_ok());
86//! # }
87//! # Ok(())
88//! # }
89//! ```
90
91use once_cell::sync::OnceCell;
92use shared_child::SharedChild;
93use std::collections::HashMap;
94use std::ffi::{OsStr, OsString};
95use std::fmt;
96use std::fs::File;
97use std::io;
98use std::io::prelude::*;
99use std::mem;
100use std::path::{Path, PathBuf};
101use std::process::{Command, ExitStatus, Output, Stdio};
102use std::sync::{Arc, Mutex};
103use std::thread::JoinHandle;
104
105#[cfg(not(windows))]
106use std::os::unix::prelude::*;
107#[cfg(windows)]
108use std::os::windows::prelude::*;
109
110/// Unix-specific extensions to duct, for sending signals.
111#[cfg(unix)]
112pub mod unix;
113
114// enums defined below
115use ExpressionInner::*;
116use IoExpressionInner::*;
117
118/// Create a command given a program name and a collection of arguments. See
119/// also the [`cmd!`](macro.cmd.html) macro, which doesn't require a collection.
120///
121/// # Example
122///
123/// ```
124/// use duct::cmd;
125///
126/// let args = vec!["foo", "bar", "baz"];
127///
128/// # // NOTE: Normally this wouldn't work on Windows, but we have an "echo"
129/// # // binary that gets built for our main tests, and it's sitting around by
130/// # // the time we get here. If this ever stops working, then we can disable
131/// # // the tests that depend on it.
132/// let output = cmd("echo", &args).read();
133///
134/// assert_eq!("foo bar baz", output.unwrap());
135/// ```
136pub fn cmd<T, U>(program: T, args: U) -> Expression
137where
138 T: IntoExecutablePath,
139 U: IntoIterator,
140 U::Item: Into<OsString>,
141{
142 let mut argv_vec = Vec::new();
143 argv_vec.push(program.to_executable());
144 argv_vec.extend(args.into_iter().map(Into::<OsString>::into));
145 Expression::new(Cmd(argv_vec))
146}
147
148/// Create a command with any number of of positional arguments, which may be
149/// different types (anything that implements
150/// [`Into<OsString>`](https://doc.rust-lang.org/std/convert/trait.From.html)).
151/// See also the [`cmd`](fn.cmd.html) function, which takes a collection of
152/// arguments.
153///
154/// # Example
155///
156/// ```
157/// use duct::cmd;
158/// use std::path::Path;
159///
160/// let arg1 = "foo";
161/// let arg2 = "bar".to_owned();
162/// let arg3 = Path::new("baz");
163///
164/// let output = cmd!("echo", arg1, arg2, arg3).read();
165///
166/// assert_eq!("foo bar baz", output.unwrap());
167/// ```
168#[macro_export]
169macro_rules! cmd {
170 ( $program:expr $(, $arg:expr )* $(,)? ) => {
171 {
172 use std::ffi::OsString;
173 let args: std::vec::Vec<OsString> = std::vec![$( Into::<OsString>::into($arg) ),*];
174 $crate::cmd($program, args)
175 }
176 };
177}
178
179/// The central objects in Duct, Expressions are created with
180/// [`cmd`](fn.cmd.html) or [`cmd!`](macro.cmd.html), combined with
181/// [`pipe`](struct.Expression.html#method.pipe), and finally executed with
182/// [`run`](struct.Expression.html#method.run),
183/// [`read`](struct.Expression.html#method.read),
184/// [`start`](struct.Expression.html#method.start), or
185/// [`reader`](struct.Expression.html#method.reader). They also support several
186/// methods to control their execution, like
187/// [`stdin_bytes`](struct.Expression.html#method.stdin_bytes),
188/// [`stdout_capture`](struct.Expression.html#method.stdout_capture),
189/// [`env`](struct.Expression.html#method.env), and
190/// [`unchecked`](struct.Expression.html#method.unchecked).
191///
192/// Expressions are immutable, and they do a lot of
193/// [`Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) sharing
194/// internally, so all of the methods below take `&self` and return a new
195/// `Expression` cheaply.
196///
197/// Expressions using `pipe` form trees, and the order in which you call
198/// different methods can matter, just like it matters where you put
199/// redirections in Bash. For example, each of these expressions suppresses
200/// output differently:
201///
202/// ```no_run
203/// # use duct::cmd;
204/// # fn main() -> std::io::Result<()> {
205/// // Only suppress stderr on the left side.
206/// cmd!("foo").stderr_null().pipe(cmd!("bar")).run()?;
207///
208/// // Only suppress stderr on the right side.
209/// cmd!("foo").pipe(cmd!("bar").stderr_null()).run()?;
210///
211/// // Suppress stderr on both sides.
212/// cmd!("foo").pipe(cmd!("bar")).stderr_null().run()?;
213/// # Ok(())
214/// # }
215/// ```
216#[derive(Clone)]
217#[must_use]
218pub struct Expression(Arc<ExpressionInner>);
219
220impl Expression {
221 /// Execute an expression, wait for it to complete, and return a
222 /// [`std::process::Output`](https://doc.rust-lang.org/std/process/struct.Output.html)
223 /// object containing the results. Nothing is captured by default, but if
224 /// you build the expression with
225 /// [`stdout_capture`](struct.Expression.html#method.stdout_capture) or
226 /// [`stderr_capture`](struct.Expression.html#method.stderr_capture) then
227 /// the `Output` will hold those captured bytes.
228 ///
229 /// # Errors
230 ///
231 /// In addition to all the IO errors possible with
232 /// [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html),
233 /// `run` will return an
234 /// [`ErrorKind::Other`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html)
235 /// IO error if child returns a non-zero exit status. To suppress this error
236 /// and return an `Output` even when the exit status is non-zero, use the
237 /// [`unchecked`](struct.Expression.html#method.unchecked) method.
238 ///
239 /// # Example
240 ///
241 /// ```
242 /// # use duct::cmd;
243 /// # fn main() {
244 /// # if cfg!(not(windows)) {
245 /// let output = cmd!("echo", "hi").stdout_capture().run().unwrap();
246 /// assert_eq!(b"hi\n".to_vec(), output.stdout);
247 /// # }
248 /// # }
249 /// ```
250 pub fn run(&self) -> io::Result<Output> {
251 // This could be optimized to avoid creating a background threads, by
252 // using the current thread to read stdout or stderr if only one of
253 // them is captured, or by using async IO to read both.
254 self.start()?.into_output()
255 }
256
257 /// Execute an expression, capture its standard output, and return the
258 /// captured output as a `String`. This is a convenience wrapper around
259 /// [`reader`](struct.Expression.html#method.reader). Like backticks and
260 /// `$()` in the shell, `read` trims trailing newlines.
261 ///
262 /// # Errors
263 ///
264 /// In addition to all the errors possible with
265 /// [`run`](struct.Expression.html#method.run), `read` will return an error
266 /// if the captured bytes aren't valid UTF-8.
267 ///
268 /// # Example
269 ///
270 /// ```
271 /// # use duct::cmd;
272 /// # fn main() {
273 /// # if cfg!(not(windows)) {
274 /// let output = cmd!("echo", "hi").stdout_capture().read().unwrap();
275 /// assert_eq!("hi", output);
276 /// # }
277 /// # }
278 /// ```
279 pub fn read(&self) -> io::Result<String> {
280 let mut reader = self.reader()?;
281 let mut output = String::new();
282 reader.read_to_string(&mut output)?;
283 while output.ends_with('\n') || output.ends_with('\r') {
284 output.truncate(output.len() - 1);
285 }
286 Ok(output)
287 }
288
289 /// Start running an expression, and immediately return a
290 /// [`Handle`](struct.Handle.html) that represents all the child processes.
291 /// This is analogous to the
292 /// [`spawn`](https://doc.rust-lang.org/std/process/struct.Command.html#method.spawn)
293 /// method in the standard library. The `Handle` may be shared between
294 /// multiple threads.
295 ///
296 /// # Example
297 ///
298 /// ```
299 /// # use duct::cmd;
300 /// # fn main() {
301 /// # if cfg!(not(windows)) {
302 /// let handle = cmd!("echo", "hi").stdout_capture().start().unwrap();
303 /// let output = handle.wait().unwrap();
304 /// assert_eq!(b"hi\n".to_vec(), output.stdout);
305 /// # }
306 /// # }
307 /// ```
308 pub fn start(&self) -> io::Result<Handle> {
309 let stdout_capture = OutputCaptureContext::new();
310 let stderr_capture = OutputCaptureContext::new();
311 let context = IoContext::new(&stdout_capture, &stderr_capture);
312
313 Ok(Handle {
314 inner: self.0.start(context)?,
315 result: OnceCell::new(),
316 readers: Mutex::new((
317 stdout_capture.maybe_read_thread(),
318 stderr_capture.maybe_read_thread(),
319 )),
320 })
321 }
322
323 /// Start running an expression, and immediately return a
324 /// [`ReaderHandle`](struct.ReaderHandle.html) attached to the child's
325 /// stdout. This is similar to `.stdout_capture().start()`, but it returns
326 /// the reader to the caller rather than reading from a background thread.
327 ///
328 /// Note that because this method doesn't read child output on a background
329 /// thread, it's a best practice to only create one `ReaderHandle` at a
330 /// time. Child processes with a lot of output will eventually block if
331 /// their stdout pipe isn't read from. If you have multiple children
332 /// running, but you're only reading from one of them at a time, that could
333 /// block the others and lead to performance issues or deadlocks. For
334 /// reading from multiple children at once, prefer
335 /// `.stdout_capture().start()`.
336 ///
337 /// # Example
338 ///
339 /// ```
340 /// # use duct::cmd;
341 /// # use std::io::prelude::*;
342 /// # fn main() {
343 /// # if cfg!(not(windows)) {
344 /// let mut reader = cmd!("echo", "hi").reader().unwrap();
345 /// let mut stdout = Vec::new();
346 /// reader.read_to_end(&mut stdout).unwrap();
347 /// assert_eq!(b"hi\n".to_vec(), stdout);
348 /// # }
349 /// # }
350 /// ```
351 pub fn reader(&self) -> io::Result<ReaderHandle> {
352 let stdout_capture = OutputCaptureContext::new();
353 let stderr_capture = OutputCaptureContext::new();
354 let context = IoContext::new(&stdout_capture, &stderr_capture);
355 let handle = Handle {
356 inner: self.stdout_capture().0.start(context)?,
357 result: OnceCell::new(),
358 readers: Mutex::new((None, stderr_capture.maybe_read_thread())),
359 };
360 Ok(ReaderHandle {
361 handle,
362 reader: stdout_capture.pair.into_inner().expect("pipe opened").0,
363 })
364 }
365
366 /// Join two expressions into a pipe expression, where the standard output
367 /// of the left will be hooked up to the standard input of the right, like
368 /// `|` in the shell.
369 ///
370 /// # Errors
371 ///
372 /// During execution, if one side of the pipe returns a non-zero exit
373 /// status, that becomes the status of the whole pipe, similar to Bash's
374 /// `pipefail` option. If both sides return non-zero, and one of them is
375 /// [`unchecked`](struct.Expression.html#method.unchecked), then the checked
376 /// side wins. Otherwise the right side wins.
377 ///
378 /// During spawning, if the left side of the pipe spawns successfully, but
379 /// the right side fails to spawn, the left side will be killed and
380 /// awaited. That's necessary to return the spawn error immediately,
381 /// without leaking the left side as a zombie.
382 ///
383 /// # Example
384 ///
385 /// ```
386 /// # use duct::cmd;
387 /// # fn main() {
388 /// # if cfg!(not(windows)) {
389 /// let output = cmd!("echo", "hi").pipe(cmd!("sed", "s/h/p/")).read();
390 /// assert_eq!("pi", output.unwrap());
391 /// # }
392 /// # }
393 /// ```
394 pub fn pipe<T: Into<Expression>>(&self, right: T) -> Expression {
395 Self::new(Pipe(self.clone(), right.into()))
396 }
397
398 /// Use bytes or a string as input for an expression, like `<<<` in the
399 /// shell. A worker thread will write the input at runtime.
400 ///
401 /// # Example
402 ///
403 /// ```
404 /// # use duct::cmd;
405 /// # fn main() {
406 /// # if cfg!(not(windows)) {
407 /// // Many types implement Into<Vec<u8>>. Here's a string.
408 /// let output = cmd!("cat").stdin_bytes("foo").read().unwrap();
409 /// assert_eq!("foo", output);
410 ///
411 /// // And here's a byte slice.
412 /// let output = cmd!("cat").stdin_bytes(&b"foo"[..]).read().unwrap();
413 /// assert_eq!("foo", output);
414 /// # }
415 /// # }
416 /// ```
417 pub fn stdin_bytes<T: Into<Vec<u8>>>(&self, bytes: T) -> Expression {
418 Self::new(Io(StdinBytes(Arc::new(bytes.into())), self.clone()))
419 }
420
421 /// Open a file at the given path and use it as input for an expression,
422 /// like `<` in the shell.
423 ///
424 /// # Example
425 ///
426 /// ```
427 /// # use duct::cmd;
428 /// # fn main() {
429 /// # if cfg!(not(windows)) {
430 /// // Many types implement Into<PathBuf>, including &str.
431 /// let output = cmd!("head", "-c", "3").stdin_path("/dev/zero").read().unwrap();
432 /// assert_eq!("\0\0\0", output);
433 /// # }
434 /// # }
435 /// ```
436 pub fn stdin_path<T: Into<PathBuf>>(&self, path: T) -> Expression {
437 Self::new(Io(StdinPath(path.into()), self.clone()))
438 }
439
440 /// Use an already opened file or pipe as input for an expression.
441 ///
442 /// # Example
443 ///
444 /// ```
445 /// # use duct::cmd;
446 /// # fn main() {
447 /// # if cfg!(not(windows)) {
448 /// let input_file = std::fs::File::open("/dev/zero").unwrap();
449 /// let output = cmd!("head", "-c", "3").stdin_file(input_file).read().unwrap();
450 /// assert_eq!("\0\0\0", output);
451 /// # }
452 /// # }
453 /// ```
454 #[cfg(not(windows))]
455 pub fn stdin_file<T: IntoRawFd>(&self, file: T) -> Expression {
456 Self::new(Io(StdinFile(into_file(file)), self.clone()))
457 }
458 #[cfg(windows)]
459 pub fn stdin_file<T: IntoRawHandle>(&self, file: T) -> Expression {
460 Self::new(Io(StdinFile(into_file(file)), self.clone()))
461 }
462
463 /// Use `/dev/null` (or `NUL` on Windows) as input for an expression.
464 ///
465 /// # Example
466 ///
467 /// ```
468 /// # use duct::cmd;
469 /// # fn main() {
470 /// # if cfg!(not(windows)) {
471 /// let output = cmd!("cat").stdin_null().read().unwrap();
472 /// assert_eq!("", output);
473 /// # }
474 /// # }
475 /// ```
476 pub fn stdin_null(&self) -> Expression {
477 Self::new(Io(StdinNull, self.clone()))
478 }
479
480 /// Open a file at the given path and use it as output for an expression,
481 /// like `>` in the shell.
482 ///
483 /// # Example
484 ///
485 /// ```
486 /// # use duct::cmd;
487 /// # fn main() {
488 /// # use std::io::prelude::*;
489 /// # if cfg!(not(windows)) {
490 /// // Many types implement Into<PathBuf>, including &str.
491 /// let path = cmd!("mktemp").read().unwrap();
492 /// cmd!("echo", "wee").stdout_path(&path).run().unwrap();
493 /// let mut output = String::new();
494 /// std::fs::File::open(&path).unwrap().read_to_string(&mut output).unwrap();
495 /// assert_eq!("wee\n", output);
496 /// # }
497 /// # }
498 /// ```
499 pub fn stdout_path<T: Into<PathBuf>>(&self, path: T) -> Expression {
500 Self::new(Io(StdoutPath(path.into()), self.clone()))
501 }
502
503 /// Use an already opened file or pipe as output for an expression.
504 ///
505 /// # Example
506 ///
507 /// ```
508 /// # use duct::cmd;
509 /// # fn main() {
510 /// # use std::io::prelude::*;
511 /// # if cfg!(not(windows)) {
512 /// let path = cmd!("mktemp").read().unwrap();
513 /// let file = std::fs::File::create(&path).unwrap();
514 /// cmd!("echo", "wee").stdout_file(file).run().unwrap();
515 /// let mut output = String::new();
516 /// std::fs::File::open(&path).unwrap().read_to_string(&mut output).unwrap();
517 /// assert_eq!("wee\n", output);
518 /// # }
519 /// # }
520 /// ```
521 #[cfg(not(windows))]
522 pub fn stdout_file<T: IntoRawFd>(&self, file: T) -> Expression {
523 Self::new(Io(StdoutFile(into_file(file)), self.clone()))
524 }
525 #[cfg(windows)]
526 pub fn stdout_file<T: IntoRawHandle>(&self, file: T) -> Expression {
527 Self::new(Io(StdoutFile(into_file(file)), self.clone()))
528 }
529
530 /// Use `/dev/null` (or `NUL` on Windows) as output for an expression.
531 ///
532 /// # Example
533 ///
534 /// ```
535 /// # use duct::cmd;
536 /// # fn main() {
537 /// // This echo command won't print anything.
538 /// cmd!("echo", "foo", "bar", "baz").stdout_null().run().unwrap();
539 ///
540 /// // And you won't get anything even if you try to read its output! The
541 /// // null redirect happens farther down in the expression tree than the
542 /// // implicit `stdout_capture`, and so it takes precedence.
543 /// let output = cmd!("echo", "foo", "bar", "baz").stdout_null().read().unwrap();
544 /// assert_eq!("", output);
545 /// # }
546 /// ```
547 pub fn stdout_null(&self) -> Expression {
548 Self::new(Io(StdoutNull, self.clone()))
549 }
550
551 /// Capture the standard output of an expression. The captured bytes will
552 /// be available on the `stdout` field of the
553 /// [`std::process::Output`](https://doc.rust-lang.org/std/process/struct.Output.html)
554 /// object returned by [`run`](struct.Expression.html#method.run) or
555 /// [`wait`](struct.Handle.html#method.wait). Output is read by a
556 /// background thread, so the child will never block writing to stdout. But
557 /// note that [`read`](struct.Expression.html#method.read) and
558 /// [`reader`](struct.Expression.html#method.reader) can be more
559 /// convenient, and they don't require the background thread.
560 ///
561 /// # Example
562 ///
563 /// ```
564 /// # use duct::cmd;
565 /// # fn main() {
566 /// # if cfg!(not(windows)) {
567 /// // The most direct way to read stdout bytes is `stdout_capture`.
568 /// let output1 = cmd!("echo", "foo").stdout_capture().run().unwrap().stdout;
569 /// assert_eq!(&b"foo\n"[..], &output1[..]);
570 ///
571 /// // The `read` method is a shorthand for `stdout_capture`, and it also
572 /// // does string parsing and newline trimming.
573 /// let output2 = cmd!("echo", "foo").read().unwrap();
574 /// assert_eq!("foo", output2)
575 /// # }
576 /// # }
577 /// ```
578 pub fn stdout_capture(&self) -> Expression {
579 Self::new(Io(StdoutCapture, self.clone()))
580 }
581
582 /// Join the standard output of an expression to its standard error pipe,
583 /// similar to `1>&2` in the shell.
584 ///
585 /// # Example
586 ///
587 /// ```
588 /// # use duct::cmd;
589 /// # fn main() {
590 /// # if cfg!(not(windows)) {
591 /// let output = cmd!("echo", "foo").stdout_to_stderr().stderr_capture().run().unwrap();
592 /// assert_eq!(&b"foo\n"[..], &output.stderr[..]);
593 /// # }
594 /// # }
595 /// ```
596 pub fn stdout_to_stderr(&self) -> Expression {
597 Self::new(Io(StdoutToStderr, self.clone()))
598 }
599
600 /// Open a file at the given path and use it as error output for an
601 /// expression, like `2>` in the shell.
602 ///
603 /// # Example
604 ///
605 /// ```
606 /// # use duct::cmd;
607 /// # fn main() {
608 /// # use std::io::prelude::*;
609 /// # if cfg!(not(windows)) {
610 /// // Many types implement Into<PathBuf>, including &str.
611 /// let path = cmd!("mktemp").read().unwrap();
612 /// cmd!("sh", "-c", "echo wee >&2").stderr_path(&path).run().unwrap();
613 /// let mut error_output = String::new();
614 /// std::fs::File::open(&path).unwrap().read_to_string(&mut error_output).unwrap();
615 /// assert_eq!("wee\n", error_output);
616 /// # }
617 /// # }
618 /// ```
619 pub fn stderr_path<T: Into<PathBuf>>(&self, path: T) -> Expression {
620 Self::new(Io(StderrPath(path.into()), self.clone()))
621 }
622
623 /// Use an already opened file or pipe as error output for an expression.
624 ///
625 /// # Example
626 ///
627 /// ```
628 /// # use duct::cmd;
629 /// # fn main() {
630 /// # use std::io::prelude::*;
631 /// # if cfg!(not(windows)) {
632 /// let path = cmd!("mktemp").read().unwrap();
633 /// let file = std::fs::File::create(&path).unwrap();
634 /// cmd!("sh", "-c", "echo wee >&2").stderr_file(file).run().unwrap();
635 /// let mut error_output = String::new();
636 /// std::fs::File::open(&path).unwrap().read_to_string(&mut error_output).unwrap();
637 /// assert_eq!("wee\n", error_output);
638 /// # }
639 /// # }
640 /// ```
641 #[cfg(not(windows))]
642 pub fn stderr_file<T: IntoRawFd>(&self, file: T) -> Expression {
643 Self::new(Io(StderrFile(into_file(file)), self.clone()))
644 }
645 #[cfg(windows)]
646 pub fn stderr_file<T: IntoRawHandle>(&self, file: T) -> Expression {
647 Self::new(Io(StderrFile(into_file(file)), self.clone()))
648 }
649
650 /// Use `/dev/null` (or `NUL` on Windows) as error output for an expression.
651 ///
652 /// # Example
653 ///
654 /// ```
655 /// # use duct::cmd;
656 /// # fn main() {
657 /// # if cfg!(not(windows)) {
658 /// // This echo-to-stderr command won't print anything.
659 /// cmd!("sh", "-c", "echo foo bar baz >&2").stderr_null().run().unwrap();
660 /// # }
661 /// # }
662 /// ```
663 pub fn stderr_null(&self) -> Expression {
664 Self::new(Io(StderrNull, self.clone()))
665 }
666
667 /// Capture the error output of an expression. The captured bytes will be
668 /// available on the `stderr` field of the `Output` object returned by
669 /// [`run`](struct.Expression.html#method.run) or
670 /// [`wait`](struct.Handle.html#method.wait). Output is read by a
671 /// background thread, so the child will never block writing to stderr.
672 ///
673 /// # Example
674 ///
675 /// ```
676 /// # use duct::cmd;
677 /// # fn main() {
678 /// # if cfg!(not(windows)) {
679 /// let output_obj = cmd!("sh", "-c", "echo foo >&2").stderr_capture().run().unwrap();
680 /// assert_eq!(&b"foo\n"[..], &output_obj.stderr[..]);
681 /// # }
682 /// # }
683 /// ```
684 pub fn stderr_capture(&self) -> Expression {
685 Self::new(Io(StderrCapture, self.clone()))
686 }
687
688 /// Join the standard error of an expression to its standard output pipe,
689 /// similar to `2>&1` in the shell.
690 ///
691 /// # Example
692 ///
693 /// ```
694 /// # use duct::cmd;
695 /// # fn main() {
696 /// # if cfg!(not(windows)) {
697 /// let error_output = cmd!("sh", "-c", "echo foo >&2").stderr_to_stdout().read().unwrap();
698 /// assert_eq!("foo", error_output);
699 /// # }
700 /// # }
701 /// ```
702 pub fn stderr_to_stdout(&self) -> Expression {
703 Self::new(Io(StderrToStdout, self.clone()))
704 }
705
706 /// Swap the stdout and stderr of an expression.
707 ///
708 /// # Example
709 ///
710 /// ```
711 /// # use duct::cmd;
712 /// # fn main() {
713 /// # if cfg!(not(windows)) {
714 /// let output = cmd!("sh", "-c", "echo foo && echo bar >&2")
715 /// .stdout_stderr_swap()
716 /// .stdout_capture()
717 /// .stderr_capture()
718 /// .run()
719 /// .unwrap();
720 /// assert_eq!(b"bar\n", &*output.stdout);
721 /// assert_eq!(b"foo\n", &*output.stderr);
722 /// # }
723 /// # }
724 /// ```
725 pub fn stdout_stderr_swap(&self) -> Expression {
726 Self::new(Io(StdoutStderrSwap, self.clone()))
727 }
728
729 /// Set the working directory where the expression will execute.
730 ///
731 /// Note that in some languages (Rust and Python at least), there are
732 /// tricky platform differences in the way relative exe paths interact with
733 /// child working directories. In particular, the exe path will be
734 /// interpreted relative to the child dir on Unix, but relative to the
735 /// parent dir on Windows. Duct prefers the Windows behavior, and in order
736 /// to get that behavior on all platforms it calls
737 /// [`std::fs::canonicalize`](https://doc.rust-lang.org/std/fs/fn.canonicalize.html)
738 /// on relative exe paths when `dir` is in use. Paths in this sense are any
739 /// program name containing a path separator, regardless of the type. (Note
740 /// also that `Path` and `PathBuf` program names get a `./` prepended to
741 /// them automatically by the
742 /// [`IntoExecutablePath`](trait.IntoExecutablePath.html) trait, and so
743 /// will always contain a separator.)
744 ///
745 /// # Errors
746 ///
747 /// Canonicalization can fail on some filesystems, or if the current
748 /// directory has been removed, and
749 /// [`run`](struct.Expression.html#method.run) will return those errors
750 /// rather than trying any sneaky workarounds.
751 ///
752 /// # Example
753 ///
754 /// ```
755 /// # use duct::cmd;
756 /// # fn main() {
757 /// # if cfg!(not(windows)) {
758 /// let output = cmd!("pwd").dir("/").read().unwrap();
759 /// assert_eq!("/", output);
760 /// # }
761 /// # }
762 /// ```
763 pub fn dir<T: Into<PathBuf>>(&self, path: T) -> Expression {
764 Self::new(Io(Dir(path.into()), self.clone()))
765 }
766
767 /// Set a variable in the expression's environment.
768 ///
769 /// # Example
770 ///
771 /// ```
772 /// # use duct::cmd;
773 /// # fn main() {
774 /// # if cfg!(not(windows)) {
775 /// let output = cmd!("sh", "-c", "echo $FOO").env("FOO", "bar").read().unwrap();
776 /// assert_eq!("bar", output);
777 /// # }
778 /// # }
779 /// ```
780 pub fn env<T, U>(&self, name: T, val: U) -> Expression
781 where
782 T: Into<OsString>,
783 U: Into<OsString>,
784 {
785 Self::new(Io(
786 Env(canonicalize_env_var_name(name.into()), val.into()),
787 self.clone(),
788 ))
789 }
790
791 /// Remove a variable from the expression's environment.
792 ///
793 /// Note that all the environment functions try to do whatever the platform
794 /// does with respect to case sensitivity. That means that
795 /// `env_remove("foo")` will unset the uppercase variable `FOO` on Windows,
796 /// but not on Unix.
797 ///
798 /// # Example
799 ///
800 /// ```
801 /// # use duct::cmd;
802 /// # fn main() {
803 /// # if cfg!(not(windows)) {
804 /// std::env::set_var("TESTING", "true");
805 /// let output = cmd!("sh", "-c", "echo a${TESTING}b")
806 /// .env_remove("TESTING")
807 /// .read()
808 /// .unwrap();
809 /// assert_eq!("ab", output);
810 /// # }
811 /// # }
812 /// ```
813 pub fn env_remove<T>(&self, name: T) -> Expression
814 where
815 T: Into<OsString>,
816 {
817 Self::new(Io(
818 EnvRemove(canonicalize_env_var_name(name.into())),
819 self.clone(),
820 ))
821 }
822
823 /// Set the expression's entire environment, from a collection of
824 /// name-value pairs (like a `HashMap`). Note that some environment
825 /// variables are required for normal program execution (like `SystemRoot`
826 /// on Windows), so copying the parent's environment is usually preferable
827 /// to starting with an empty one.
828 ///
829 /// # Example
830 ///
831 /// ```
832 /// # use duct::cmd;
833 /// # fn main() {
834 /// # use std::collections::HashMap;
835 /// # if cfg!(not(windows)) {
836 /// let mut env_map: HashMap<_, _> = std::env::vars().collect();
837 /// env_map.insert("FOO".into(), "bar".into());
838 /// let output = cmd!("sh", "-c", "echo $FOO").full_env(&env_map).read().unwrap();
839 /// assert_eq!("bar", output);
840 /// // The IntoIterator/Into<OsString> bounds are pretty flexible. Passing
841 /// // by value works here too.
842 /// let output = cmd!("sh", "-c", "echo $FOO").full_env(env_map).read().unwrap();
843 /// assert_eq!("bar", output);
844 /// # }
845 /// # }
846 /// ```
847 pub fn full_env<T, U, V>(&self, name_vals: T) -> Expression
848 where
849 T: IntoIterator<Item = (U, V)>,
850 U: Into<OsString>,
851 V: Into<OsString>,
852 {
853 let env_map = name_vals
854 .into_iter()
855 .map(|(k, v)| (canonicalize_env_var_name(k.into()), v.into()))
856 .collect();
857 Self::new(Io(FullEnv(env_map), self.clone()))
858 }
859
860 /// Prevent a non-zero exit status from causing
861 /// [`run`](struct.Expression.html#method.run) or
862 /// [`read`](struct.Expression.html#method.read) to return an error. The
863 /// unchecked exit code will still be there on the `Output` returned by
864 /// `run`; its value doesn't change.
865 ///
866 /// "Uncheckedness" sticks to an exit code as it bubbles up through
867 /// complicated pipelines, but it doesn't "infect" other exit codes. So for
868 /// example, if only one sub-expression in a pipe has `unchecked`, then
869 /// errors returned by the other side will still be checked. That said,
870 /// most commonly you'll just call `unchecked` right before `run`, and
871 /// it'll apply to an entire expression.
872 ///
873 /// # Example
874 ///
875 /// Note the differences among these three cases:
876 ///
877 /// ```no_run
878 /// # use duct::cmd;
879 /// # fn main() -> std::io::Result<()> {
880 /// // Don't check errors on the left side.
881 /// cmd!("foo").unchecked().pipe(cmd!("bar")).run()?;
882 ///
883 /// // Don't check errors on the right side.
884 /// cmd!("foo").pipe(cmd!("bar").unchecked()).run()?;
885 ///
886 /// // Don't check errors on either side.
887 /// cmd!("foo").pipe(cmd!("bar")).unchecked().run()?;
888 /// # Ok(())
889 /// # }
890 /// ```
891 pub fn unchecked(&self) -> Expression {
892 Self::new(Io(Unchecked, self.clone()))
893 }
894
895 /// Add a hook for modifying
896 /// [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html)
897 /// objects immediately before they're executed.
898 ///
899 /// The hook is called for each command in its sub-expression, and each time the expression is
900 /// executed. The call happens after other features like `stdout` and `env` have been applied,
901 /// so any changes made by the hook take priority. More than one hook can be added, in which
902 /// case the innermost is executed last. For example, if one call to `before_spawn` is applied
903 /// to an entire pipe expression, and another call is applied to just one command within the
904 /// pipe, the hook for the entire pipeline will be called first over the command where both
905 /// hooks apply.
906 ///
907 /// This is intended for rare and tricky cases, like callers who want to change the group ID of
908 /// their child processes, or who want to run code in `before_exec`. Most callers shouldn't
909 /// need to use it.
910 ///
911 /// # Example
912 ///
913 /// ```
914 /// # use duct::cmd;
915 /// # fn main() {
916 /// let output = cmd!("echo", "foo")
917 /// .before_spawn(|cmd| {
918 /// // Sneakily add an extra argument.
919 /// cmd.arg("bar");
920 /// Ok(())
921 /// })
922 /// .read()
923 /// .unwrap();
924 /// assert_eq!("foo bar", output);
925 /// # }
926 /// ```
927 pub fn before_spawn<F>(&self, hook: F) -> Expression
928 where
929 F: Fn(&mut Command) -> io::Result<()> + Send + Sync + 'static,
930 {
931 Self::new(Io(BeforeSpawn(BeforeSpawnHook::new(hook)), self.clone()))
932 }
933
934 fn new(inner: ExpressionInner) -> Expression {
935 Expression(Arc::new(inner))
936 }
937}
938
939// Delegate to the ExpressionInner for debug formatting. This avoids printing
940// redundant Expression() constructors around everything.
941impl fmt::Debug for Expression {
942 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943 self.0.fmt(f)
944 }
945}
946
947// Implementing Into<Expression> for references lets us accept both references
948// and values in `pipe`.
949impl<'a> From<&'a Expression> for Expression {
950 fn from(expr: &Expression) -> Expression {
951 expr.clone()
952 }
953}
954
955/// A handle to a running expression, returned by the
956/// [`start`](struct.Expression.html#method.start) method.
957///
958/// Calling `start` followed by
959/// [`into_output`](struct.Handle.html#method.into_output) on the handle is
960/// equivalent to [`run`](struct.Expression.html#method.run). Note that unlike
961/// [`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html),
962/// most of the methods on `Handle` take `&self` rather than `&mut self`, and a
963/// `Handle` may be shared between multiple threads.
964///
965/// Like `std::process::Child`, `Handle` doesn't do anything special in its
966/// destructor. If you drop a handle without waiting on it, child processes and
967/// background IO threads will keep running, and the children will become
968/// [zombie processes](https://en.wikipedia.org/wiki/Zombie_process) when they
969/// exit. That's a resource leak, similar to leaking memory or file handles.
970/// Note that in contrast to `Handle`, a
971/// [`ReaderHandle`](struct.ReaderHandle.html) kills child processes in its
972/// destructor, to avoid creating zombies.
973///
974/// See the [`shared_child`](https://github.com/oconnor663/shared_child.rs)
975/// crate for implementation details behind making handles thread safe.
976#[derive(Debug)]
977pub struct Handle {
978 inner: HandleInner,
979 result: OnceCell<(ExpressionStatus, Output)>,
980 readers: Mutex<(Option<ReaderThread>, Option<ReaderThread>)>,
981}
982
983impl Handle {
984 /// Wait for the running expression to finish, and return a reference to its
985 /// [`std::process::Output`](https://doc.rust-lang.org/std/process/struct.Output.html).
986 /// Multiple threads may wait at the same time.
987 ///
988 /// # Errors
989 ///
990 /// In addition to all the IO errors possible with
991 /// [`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html),
992 /// `wait` will return an
993 /// [`ErrorKind::Other`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html)
994 /// IO error if child returns a non-zero exit status. To suppress this
995 /// error and return an `Output` even when the exit status is non-zero, use
996 /// the [`unchecked`](struct.Expression.html#method.unchecked) method.
997 pub fn wait(&self) -> io::Result<&Output> {
998 // Await the children and any threads that are reading their output.
999 // Another caller may already have done this.
1000 let (expression_status, output) = wait_on_handle_and_output(self)?;
1001 // If the child returned a non-zero exit status, and that's a checked
1002 // error, return the error.
1003 if expression_status.is_checked_error() {
1004 return Err(io::Error::new(
1005 io::ErrorKind::Other,
1006 expression_status.message(),
1007 ));
1008 }
1009 Ok(output)
1010 }
1011
1012 /// Check whether the running expression is finished. If it is, return a
1013 /// reference to its
1014 /// [`std::process::Output`](https://doc.rust-lang.org/std/process/struct.Output.html).
1015 /// If it's still running, return `Ok(None)`.
1016 ///
1017 /// # Errors
1018 ///
1019 /// In addition to all the IO errors possible with
1020 /// [`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html),
1021 /// `try_wait` will return an
1022 /// [`ErrorKind::Other`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html)
1023 /// IO error if child returns a non-zero exit status. To suppress this
1024 /// error and return an `Output` even when the exit status is non-zero, use
1025 /// the [`unchecked`](struct.Expression.html#method.unchecked) method.
1026 pub fn try_wait(&self) -> io::Result<Option<&Output>> {
1027 if self.inner.wait(WaitMode::Nonblocking)?.is_none() {
1028 Ok(None)
1029 } else {
1030 self.wait().map(Some)
1031 }
1032 }
1033
1034 /// Wait for the running expression to finish, and then return a
1035 /// [`std::process::Output`](https://doc.rust-lang.org/std/process/struct.Output.html)
1036 /// object containing the results, including any captured output. This
1037 /// consumes the `Handle`. Calling
1038 /// [`start`](struct.Expression.html#method.start) followed by
1039 /// `into_output` is equivalent to
1040 /// [`run`](struct.Expression.html#method.run).
1041 ///
1042 /// # Errors
1043 ///
1044 /// In addition to all the IO errors possible with
1045 /// [`std::process::Child`](https://doc.rust-lang.org/std/process/struct.Child.html),
1046 /// `into_output` will return an
1047 /// [`ErrorKind::Other`](https://doc.rust-lang.org/std/io/enum.ErrorKind.html)
1048 /// IO error if child returns a non-zero exit status. To suppress this
1049 /// error and return an `Output` even when the exit status is non-zero, use
1050 /// the [`unchecked`](struct.Expression.html#method.unchecked) method.
1051 pub fn into_output(self) -> io::Result<Output> {
1052 self.wait()?;
1053 let (_, output) = self.result.into_inner().expect("result missing");
1054 Ok(output)
1055 }
1056
1057 /// Kill the running expression and await all the child processes. Any
1058 /// errors that would normally result from a non-zero exit status are
1059 /// ignored, as with
1060 /// [`unchecked`](struct.Expression.html#method.unchecked).
1061 ///
1062 /// Note that as with
1063 /// [`std::process::Child::kill`](https://doc.rust-lang.org/beta/std/process/struct.Child.html#method.kill),
1064 /// this does not kill any grandchild processes that the children have
1065 /// spawned on their own. It only kills the child processes that Duct
1066 /// spawned itself. See
1067 /// [`gotchas.md`](https://github.com/oconnor663/duct.py/blob/master/gotchas.md)
1068 /// for an extensive discussion of this behavior.
1069 pub fn kill(&self) -> io::Result<()> {
1070 self.inner.kill()?;
1071 // This wait cleans up the child but does not return an error for a
1072 // non-zero exit status.
1073 //
1074 // Note that we *must not* call wait_on_handle_and_output here. There
1075 // might be un-signaled grandchild processes holding the output pipe,
1076 // and we can't expect them to exit promptly. We only want to reap our
1077 // immediate zombie children here. See gotchas.md for more on why we
1078 // can't do better.
1079 self.inner.wait(WaitMode::Blocking)?;
1080 Ok(())
1081 }
1082
1083 /// Return a `Vec<u32>` containing the PIDs of all of the child processes.
1084 /// The PIDs are given in pipeline order, from left to right.
1085 pub fn pids(&self) -> Vec<u32> {
1086 self.inner.pids()
1087 }
1088}
1089
1090// Does a blocking wait on the handle, if it hasn't been awaited yet. This
1091// includes collection the output results from reader threads. After calling
1092// this function, the result cell is guaranteed to be populated. This does not
1093// do any status checking.
1094fn wait_on_handle_and_output(handle: &Handle) -> io::Result<&(ExpressionStatus, Output)> {
1095 // Take the reader threads lock and then see if a result has already been
1096 // collected. Doing this check inside the lock avoids racing to fill the
1097 // result if it's empty.
1098 let mut readers_lock = handle.readers.lock().expect("readers lock poisoned");
1099 if let Some(result) = handle.result.get() {
1100 // This handle has already been waited on. Return the same result
1101 // again.
1102 Ok(result)
1103 } else {
1104 // This handle hasn't been waited on yet. Do that now. If waiting on
1105 // the children returns an error, just short-circuit with that. This
1106 // shouldn't really happen.
1107 let status = handle
1108 .inner
1109 .wait(WaitMode::Blocking)?
1110 .expect("blocking wait can't return None");
1111 // Now that we have an exit status, we need to join the output reader
1112 // threads, if any. We're already holding the lock that we need.
1113 let (stdout_reader, stderr_reader) = &mut *readers_lock;
1114 // If either of the reader threads returned an error, just
1115 // short-circuit with that. Future calls to this function will panic.
1116 // But this really shouldn't happen.
1117 let stdout = stdout_reader
1118 .take()
1119 .map(|t| t.join().expect("stdout reader error"))
1120 .unwrap_or(Ok(Vec::new()))?;
1121 let stderr = stderr_reader
1122 .take()
1123 .map(|t| t.join().expect("stderr reader error"))
1124 .unwrap_or(Ok(Vec::new()))?;
1125 let output = Output {
1126 status: status.status,
1127 stdout,
1128 stderr,
1129 };
1130 Ok(handle.result.get_or_init(|| (status, output)))
1131 }
1132}
1133
1134#[derive(Debug)]
1135enum ExpressionInner {
1136 Cmd(Vec<OsString>),
1137 Pipe(Expression, Expression),
1138 Io(IoExpressionInner, Expression),
1139}
1140
1141impl ExpressionInner {
1142 fn start(&self, context: IoContext) -> io::Result<HandleInner> {
1143 Ok(match self {
1144 Cmd(argv) => HandleInner::Child(start_argv(argv, context)?),
1145 Pipe(left, right) => {
1146 HandleInner::Pipe(Box::new(PipeHandle::start(left, right, context)?))
1147 }
1148 Io(io_inner, expr) => start_io(io_inner, expr, context)?,
1149 })
1150 }
1151}
1152
1153#[derive(Debug)]
1154enum HandleInner {
1155 Child(ChildHandle),
1156 // If the left side of a pipe fails to start, there's nothing to wait for,
1157 // and we return an error immediately. But if the right side fails to start,
1158 // the caller still needs to wait on the left, and we must return a handle.
1159 // Thus the handle preserves the right side's errors here.
1160 Pipe(Box<PipeHandle>),
1161 StdinBytes(Box<StdinBytesHandle>),
1162 Unchecked(Box<HandleInner>),
1163}
1164
1165impl HandleInner {
1166 fn wait(&self, mode: WaitMode) -> io::Result<Option<ExpressionStatus>> {
1167 match self {
1168 HandleInner::Child(child_handle) => child_handle.wait(mode),
1169 HandleInner::Pipe(pipe_handle) => pipe_handle.wait(mode),
1170 HandleInner::StdinBytes(stdin_bytes_handle) => stdin_bytes_handle.wait(mode),
1171 HandleInner::Unchecked(inner_handle) => {
1172 Ok(inner_handle.wait(mode)?.map(|mut status| {
1173 status.checked = false;
1174 status
1175 }))
1176 }
1177 }
1178 }
1179
1180 fn kill(&self) -> io::Result<()> {
1181 match self {
1182 HandleInner::Child(child_handle) => child_handle.kill(),
1183 HandleInner::Pipe(pipe_handle) => pipe_handle.kill(),
1184 HandleInner::StdinBytes(stdin_bytes_handle) => stdin_bytes_handle.kill(),
1185 HandleInner::Unchecked(inner_handle) => inner_handle.kill(),
1186 }
1187 }
1188
1189 fn pids(&self) -> Vec<u32> {
1190 match self {
1191 HandleInner::Child(child_handle) => vec![child_handle.child.id()],
1192 HandleInner::Pipe(pipe_handle) => pipe_handle.pids(),
1193 HandleInner::StdinBytes(stdin_bytes_handle) => stdin_bytes_handle.inner_handle.pids(),
1194 HandleInner::Unchecked(inner_handle) => inner_handle.pids(),
1195 }
1196 }
1197}
1198
1199fn start_argv(argv: &[OsString], context: IoContext) -> io::Result<ChildHandle> {
1200 let exe = canonicalize_exe_path_for_dir(&argv[0], &context)?;
1201 let mut command = Command::new(exe);
1202 command.args(&argv[1..]);
1203 if !matches!(context.stdin, IoValue::ParentStdin) {
1204 command.stdin(context.stdin.into_stdio()?);
1205 }
1206 if !matches!(context.stdout, IoValue::ParentStdout) {
1207 command.stdout(context.stdout.into_stdio()?);
1208 }
1209 if !matches!(context.stderr, IoValue::ParentStderr) {
1210 command.stderr(context.stderr.into_stdio()?);
1211 }
1212 if let Some(dir) = context.dir {
1213 command.current_dir(dir);
1214 }
1215 command.env_clear();
1216 for (name, val) in context.env {
1217 command.env(name, val);
1218 }
1219 // The innermost hooks are pushed last, and we execute them last.
1220 for hook in context.before_spawn_hooks.iter() {
1221 hook.call(&mut command)?;
1222 }
1223 let shared_child = SharedChild::spawn(&mut command)?;
1224 let command_string = format!("{:?}", argv);
1225 Ok(ChildHandle {
1226 child: shared_child,
1227 command_string,
1228 })
1229}
1230
1231#[derive(Debug)]
1232struct ChildHandle {
1233 child: shared_child::SharedChild,
1234 command_string: String,
1235}
1236
1237impl ChildHandle {
1238 fn wait(&self, mode: WaitMode) -> io::Result<Option<ExpressionStatus>> {
1239 let maybe_status = match mode {
1240 WaitMode::Blocking => Some(self.child.wait()?),
1241 WaitMode::Nonblocking => self.child.try_wait()?,
1242 };
1243 if let Some(status) = maybe_status {
1244 Ok(Some(ExpressionStatus {
1245 status,
1246 checked: true,
1247 command: self.command_string.clone(),
1248 }))
1249 } else {
1250 Ok(None)
1251 }
1252 }
1253
1254 fn kill(&self) -> io::Result<()> {
1255 self.child.kill()
1256 }
1257}
1258
1259#[derive(Debug)]
1260struct PipeHandle {
1261 left_handle: HandleInner,
1262 right_handle: HandleInner,
1263}
1264
1265impl PipeHandle {
1266 fn start(left: &Expression, right: &Expression, context: IoContext) -> io::Result<PipeHandle> {
1267 let (reader, writer) = os_pipe::pipe()?;
1268 // dup'ing stdin/stdout isn't strictly necessary, but no big deal
1269 let mut left_context = context.try_clone()?;
1270 left_context.stdout = IoValue::Handle(into_file(writer));
1271 let mut right_context = context;
1272 right_context.stdin = IoValue::Handle(into_file(reader));
1273
1274 // Errors starting the left side just short-circuit us.
1275 let left_handle = left.0.start(left_context)?;
1276
1277 // Now the left side is started. If the right side fails to start, we
1278 // can't let the left side turn into a zombie. We have to await it, and
1279 // that means we have to kill it first.
1280 let right_result = right.0.start(right_context);
1281 match right_result {
1282 Ok(right_handle) => Ok(PipeHandle {
1283 left_handle,
1284 right_handle,
1285 }),
1286 Err(e) => {
1287 // Realistically, kill should never return an error. If it
1288 // does, it's probably due to some bug in this library or one
1289 // of its dependencies. If that happens just propagate the
1290 // error and accept that we're probably leaking something.
1291 left_handle.kill()?;
1292 // Similarly, this private API wait should never return an
1293 // error. It might return a non-zero status, but here that's
1294 // still an Ok result.
1295 left_handle.wait(WaitMode::Blocking)?;
1296 Err(e)
1297 }
1298 }
1299 }
1300
1301 fn wait(&self, mode: WaitMode) -> io::Result<Option<ExpressionStatus>> {
1302 // Wait on both sides first, without propagating any errors.
1303 let left_wait_result = self.left_handle.wait(mode);
1304 let right_wait_result = self.right_handle.wait(mode);
1305
1306 // Now we deal with errors from either of those waits. The left wait
1307 // happened first, so that one takes precedence. Note that this is the
1308 // reverse order of exit status precedence.
1309 let left_status = left_wait_result?;
1310 let right_status = right_wait_result?;
1311
1312 // If both waits succeeded, return one of the two statuses.
1313 Ok(pipe_status_precedence(left_status, right_status))
1314 }
1315
1316 // As with wait, we need to call kill on both sides even if the left side
1317 // returns an error.
1318 fn kill(&self) -> io::Result<()> {
1319 let left_kill_result = self.left_handle.kill();
1320 let right_kill_result = self.right_handle.kill();
1321 // As with wait, the left side happened first, so its errors take
1322 // precedence.
1323 left_kill_result.and(right_kill_result)
1324 }
1325
1326 fn pids(&self) -> Vec<u32> {
1327 let mut pids = self.left_handle.pids();
1328 pids.extend_from_slice(&self.right_handle.pids());
1329 pids
1330 }
1331}
1332
1333// The rules of precedence are:
1334// 1) If either side unfinished, the result is unfinished.
1335// 2) Checked errors trump unchecked errors.
1336// 3) Any errors trump success.
1337// 4) All else equal, the right side wins.
1338fn pipe_status_precedence(
1339 left_maybe_status: Option<ExpressionStatus>,
1340 right_maybe_status: Option<ExpressionStatus>,
1341) -> Option<ExpressionStatus> {
1342 let (left_status, right_status) = match (left_maybe_status, right_maybe_status) {
1343 (Some(left), Some(right)) => (left, right),
1344 _ => return None,
1345 };
1346 Some(if right_status.is_checked_error() {
1347 right_status
1348 } else if left_status.is_checked_error() {
1349 left_status
1350 } else if !right_status.status.success() {
1351 right_status
1352 } else {
1353 left_status
1354 })
1355}
1356
1357fn start_io(
1358 io_inner: &IoExpressionInner,
1359 expr_inner: &Expression,
1360 mut context: IoContext,
1361) -> io::Result<HandleInner> {
1362 match io_inner {
1363 StdinBytes(v) => {
1364 return Ok(HandleInner::StdinBytes(Box::new(StdinBytesHandle::start(
1365 expr_inner,
1366 context,
1367 Arc::clone(v),
1368 )?)));
1369 }
1370 StdinPath(p) => {
1371 context.stdin = IoValue::Handle(File::open(p)?);
1372 }
1373 StdinFile(f) => {
1374 context.stdin = IoValue::Handle(f.try_clone()?);
1375 }
1376 StdinNull => {
1377 context.stdin = IoValue::Null;
1378 }
1379 StdoutPath(p) => {
1380 context.stdout = IoValue::Handle(File::create(p)?);
1381 }
1382 StdoutFile(f) => {
1383 context.stdout = IoValue::Handle(f.try_clone()?);
1384 }
1385 StdoutNull => {
1386 context.stdout = IoValue::Null;
1387 }
1388 StdoutCapture => {
1389 context.stdout = IoValue::Handle(into_file(context.stdout_capture.write_pipe()?));
1390 }
1391 StdoutToStderr => {
1392 context.stdout = context.stderr.try_clone()?;
1393 }
1394 StderrPath(p) => {
1395 context.stderr = IoValue::Handle(File::create(p)?);
1396 }
1397 StderrFile(f) => {
1398 context.stderr = IoValue::Handle(f.try_clone()?);
1399 }
1400 StderrNull => {
1401 context.stderr = IoValue::Null;
1402 }
1403 StderrCapture => {
1404 context.stderr = IoValue::Handle(into_file(context.stderr_capture.write_pipe()?));
1405 }
1406 StderrToStdout => {
1407 context.stderr = context.stdout.try_clone()?;
1408 }
1409 StdoutStderrSwap => {
1410 mem::swap(&mut context.stdout, &mut context.stderr);
1411 }
1412 Dir(p) => {
1413 context.dir = Some(p.clone());
1414 }
1415 Env(name, val) => {
1416 context.env.insert(name.clone(), val.clone());
1417 }
1418 EnvRemove(name) => {
1419 context.env.remove(name);
1420 }
1421 FullEnv(map) => {
1422 context.env = map.clone();
1423 }
1424 Unchecked => {
1425 let inner_handle = expr_inner.0.start(context)?;
1426 return Ok(HandleInner::Unchecked(Box::new(inner_handle)));
1427 }
1428 BeforeSpawn(hook) => {
1429 context.before_spawn_hooks.push(hook.clone());
1430 }
1431 }
1432 expr_inner.0.start(context)
1433}
1434
1435#[derive(Debug)]
1436struct StdinBytesHandle {
1437 inner_handle: HandleInner,
1438 writer_thread: SharedThread<io::Result<()>>,
1439}
1440
1441impl StdinBytesHandle {
1442 fn start(
1443 expression: &Expression,
1444 mut context: IoContext,
1445 input: Arc<Vec<u8>>,
1446 ) -> io::Result<StdinBytesHandle> {
1447 let (reader, mut writer) = os_pipe::pipe()?;
1448 context.stdin = IoValue::Handle(into_file(reader));
1449 let inner = expression.0.start(context)?;
1450 // We only spawn the writer thread if the expression started
1451 // successfully, so that start errors won't leak a zombie thread.
1452 let thread = std::thread::spawn(move || writer.write_all(&input));
1453 Ok(StdinBytesHandle {
1454 inner_handle: inner,
1455 writer_thread: SharedThread::new(thread),
1456 })
1457 }
1458
1459 fn wait(&self, mode: WaitMode) -> io::Result<Option<ExpressionStatus>> {
1460 // We're responsible for joining the writer thread and not leaving a zombie.
1461 // But waiting on the inner child can return an error, and in that case we
1462 // don't know whether the child is still running or not. The rule in
1463 // nonblocking mode is "clean up as much as we can, but never block," so we
1464 // can't wait on the writer thread. But the rule in blocking mode is "clean
1465 // up everything, even if some cleanup returns errors," so we must wait
1466 // regardless of what's going on with the child.
1467 let wait_res = self.inner_handle.wait(mode);
1468 if mode.should_join_background_thread(&wait_res) {
1469 // Join the writer thread. Broken pipe errors here are expected if
1470 // the child exited without reading all of its input, so we suppress
1471 // them. Return other errors though.
1472 match self.writer_thread.join() {
1473 Err(err) if err.kind() != io::ErrorKind::BrokenPipe => {
1474 return Err(clone_io_error(err));
1475 }
1476 _ => {}
1477 }
1478 }
1479 wait_res
1480 }
1481
1482 fn kill(&self) -> io::Result<()> {
1483 self.inner_handle.kill()
1484 }
1485}
1486
1487#[derive(Debug)]
1488enum IoExpressionInner {
1489 StdinBytes(Arc<Vec<u8>>),
1490 StdinPath(PathBuf),
1491 StdinFile(File),
1492 StdinNull,
1493 StdoutPath(PathBuf),
1494 StdoutFile(File),
1495 StdoutNull,
1496 StdoutCapture,
1497 StdoutToStderr,
1498 StderrPath(PathBuf),
1499 StderrFile(File),
1500 StderrNull,
1501 StderrCapture,
1502 StderrToStdout,
1503 StdoutStderrSwap,
1504 Dir(PathBuf),
1505 Env(OsString, OsString),
1506 EnvRemove(OsString),
1507 FullEnv(HashMap<OsString, OsString>),
1508 Unchecked,
1509 BeforeSpawn(BeforeSpawnHook),
1510}
1511
1512type HookFn = Arc<dyn Fn(&mut Command) -> io::Result<()> + Send + Sync>;
1513
1514#[derive(Clone)]
1515struct BeforeSpawnHook {
1516 inner: HookFn,
1517}
1518
1519impl BeforeSpawnHook {
1520 fn new<F>(hook: F) -> Self
1521 where
1522 F: Fn(&mut Command) -> io::Result<()> + Send + Sync + 'static,
1523 {
1524 Self {
1525 inner: Arc::new(hook),
1526 }
1527 }
1528
1529 fn call(&self, command: &mut Command) -> io::Result<()> {
1530 (self.inner)(command)
1531 }
1532}
1533
1534impl fmt::Debug for BeforeSpawnHook {
1535 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1536 write!(f, "<closure>")
1537 }
1538}
1539
1540// An IoContext represents the file descriptors child processes are talking to at execution time.
1541// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
1542// sub-expressions. Compound expressions will clone() it, and redirections will modify it.
1543#[derive(Debug)]
1544struct IoContext<'a> {
1545 stdin: IoValue,
1546 stdout: IoValue,
1547 stderr: IoValue,
1548 stdout_capture: &'a OutputCaptureContext,
1549 stderr_capture: &'a OutputCaptureContext,
1550 dir: Option<PathBuf>,
1551 env: HashMap<OsString, OsString>,
1552 before_spawn_hooks: Vec<BeforeSpawnHook>,
1553}
1554
1555impl<'a> IoContext<'a> {
1556 // Returns (context, stdout_reader, stderr_reader).
1557 fn new(
1558 stdout_capture: &'a OutputCaptureContext,
1559 stderr_capture: &'a OutputCaptureContext,
1560 ) -> Self {
1561 Self {
1562 stdin: IoValue::ParentStdin,
1563 stdout: IoValue::ParentStdout,
1564 stderr: IoValue::ParentStderr,
1565 stdout_capture,
1566 stderr_capture,
1567 dir: None,
1568 env: std::env::vars_os().collect(),
1569 before_spawn_hooks: Vec::new(),
1570 }
1571 }
1572
1573 fn try_clone(&self) -> io::Result<IoContext<'a>> {
1574 Ok(IoContext {
1575 stdin: self.stdin.try_clone()?,
1576 stdout: self.stdout.try_clone()?,
1577 stderr: self.stderr.try_clone()?,
1578 stdout_capture: self.stdout_capture,
1579 stderr_capture: self.stderr_capture,
1580 dir: self.dir.clone(),
1581 env: self.env.clone(),
1582 before_spawn_hooks: self.before_spawn_hooks.clone(),
1583 })
1584 }
1585}
1586
1587#[derive(Debug)]
1588enum IoValue {
1589 ParentStdin,
1590 ParentStdout,
1591 ParentStderr,
1592 Null,
1593 // We store all handles as File, even when they're e.g. anonymous pipes,
1594 // using the into_file() conversion below. The File type is a very thin
1595 // wrapper around the raw handle, but it gives us try_clone() and drop().
1596 Handle(File),
1597}
1598
1599impl IoValue {
1600 fn try_clone(&self) -> io::Result<IoValue> {
1601 Ok(match self {
1602 IoValue::ParentStdin => IoValue::ParentStdin,
1603 IoValue::ParentStdout => IoValue::ParentStdout,
1604 IoValue::ParentStderr => IoValue::ParentStderr,
1605 IoValue::Null => IoValue::Null,
1606 IoValue::Handle(f) => IoValue::Handle(f.try_clone()?),
1607 })
1608 }
1609
1610 fn into_stdio(self) -> io::Result<Stdio> {
1611 Ok(match self {
1612 IoValue::ParentStdin => os_pipe::dup_stdin()?.into(),
1613 IoValue::ParentStdout => os_pipe::dup_stdout()?.into(),
1614 IoValue::ParentStderr => os_pipe::dup_stderr()?.into(),
1615 IoValue::Null => Stdio::null(),
1616 IoValue::Handle(f) => f.into(),
1617 })
1618 }
1619}
1620
1621// We would rather convert an fd-owning object directly into a
1622// std::process::Stdio, since all you can do with that is give it to a
1623// std::process::Command. Unfortunately, Stdio doesn't provide a try_clone
1624// method, and we need that in order to pass the object to multiple children.
1625// As a workaround, convert the object to a std::fs::File. All we will use this
1626// File for is try_clone and Into<Stdio>, which should be sound on any type of
1627// descriptor. (Some types will lead to an error, like a TcpStream, but that's
1628// not unsound.) If we discover any unsound cases, we might have to replace
1629// this with a new trait.
1630#[cfg(not(windows))]
1631fn into_file<T: IntoRawFd>(handle: T) -> File {
1632 unsafe { File::from_raw_fd(handle.into_raw_fd()) }
1633}
1634#[cfg(windows)]
1635fn into_file<T: IntoRawHandle>(handle: T) -> File {
1636 unsafe { File::from_raw_handle(handle.into_raw_handle()) }
1637}
1638
1639// This struct keeps track of a child exit status, whether or not it's been
1640// unchecked(), and what the command was that gave it (for error messages).
1641#[derive(Clone, Debug)]
1642struct ExpressionStatus {
1643 status: ExitStatus,
1644 checked: bool,
1645 command: String,
1646}
1647
1648impl ExpressionStatus {
1649 fn is_checked_error(&self) -> bool {
1650 self.checked && !self.status.success()
1651 }
1652
1653 fn message(&self) -> String {
1654 format!(
1655 "command {} exited with code {}",
1656 self.command,
1657 self.exit_code_string()
1658 )
1659 }
1660
1661 #[cfg(not(windows))]
1662 fn exit_code_string(&self) -> String {
1663 if self.status.code().is_none() {
1664 return format!("<signal {}>", self.status.signal().unwrap());
1665 }
1666 self.status.code().unwrap().to_string()
1667 }
1668
1669 #[cfg(windows)]
1670 fn exit_code_string(&self) -> String {
1671 self.status.code().unwrap().to_string()
1672 }
1673}
1674
1675fn canonicalize_exe_path_for_dir(exe_name: &OsStr, context: &IoContext) -> io::Result<OsString> {
1676 // There's a tricky interaction between exe paths and `dir`. Exe paths can
1677 // be relative, and so we have to ask: Is an exe path interpreted relative
1678 // to the parent's cwd, or the child's? The answer is that it's platform
1679 // dependent! >.< (Windows uses the parent's cwd, but because of the
1680 // fork-chdir-exec pattern, Unix usually uses the child's.)
1681 //
1682 // We want to use the parent's cwd consistently, because that saves the
1683 // caller from having to worry about whether `dir` will have side effects,
1684 // and because it's easy for the caller to use Path::join if they want to.
1685 // That means that when `dir` is in use, we need to detect exe names that
1686 // are relative paths, and absolutify them. We want to do that as little as
1687 // possible though, both because canonicalization can fail, and because we
1688 // prefer to let the caller control the child's argv[0].
1689 //
1690 // We never want to absolutify a name like "emacs", because that's probably
1691 // a program in the PATH rather than a local file. So we look for slashes
1692 // in the name to determine what's a filepath and what isn't. Note that
1693 // anything given as a std::path::Path will always have a slash by the time
1694 // we get here, because we specialize the IntoExecutablePath trait to
1695 // prepend a ./ to them when they're relative. This leaves the case where
1696 // Windows users might pass a local file like "foo.bat" as a string, which
1697 // we can't distinguish from a global program name. However, because the
1698 // Windows has the preferred "relative to parent's cwd" behavior already,
1699 // this case actually works without our help. (The thing Windows users have
1700 // to watch out for instead is local files shadowing global program names,
1701 // which I don't think we can or should prevent.)
1702
1703 let has_separator = exe_name
1704 .to_string_lossy()
1705 .chars()
1706 .any(std::path::is_separator);
1707 let is_relative = Path::new(exe_name).is_relative();
1708 if context.dir.is_some() && has_separator && is_relative {
1709 Path::new(exe_name).canonicalize().map(Into::into)
1710 } else {
1711 Ok(exe_name.to_owned())
1712 }
1713}
1714
1715// We want to allow Path("foo") to refer to the local file "./foo" on
1716// Unix, and we want to *prevent* Path("echo") from referring to the
1717// global "echo" command on either Unix or Windows. Prepend a dot to all
1718// relative paths to accomplish both of those.
1719fn dotify_relative_exe_path(path: &Path) -> PathBuf {
1720 // This is a no-op if path is absolute or begins with a Windows prefix.
1721 Path::new(".").join(path)
1722}
1723
1724/// An implementation detail of [`cmd`](fn.cmd.html), to distinguish paths from
1725/// other string types.
1726///
1727/// `Path("foo.sh")` means the file named `foo.sh` in the current directory.
1728/// However if you try to execute that path with
1729/// [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html),
1730/// Unix will get upset that it doesn't have a leading `./`. Rust knows that the
1731/// string is a path, but that distinction gets lost by the time execution
1732/// happens.
1733///
1734/// To execute relative paths correctly, duct prepends the `./` to them
1735/// automatically. This trait captures the distinction between the path types
1736/// and other types of strings, which don't get modified. See the trait bounds
1737/// on [`cmd`](fn.cmd.html).
1738pub trait IntoExecutablePath {
1739 fn to_executable(self) -> OsString;
1740}
1741
1742// TODO: Get rid of most of these impls once specialization lands.
1743
1744impl<'a> IntoExecutablePath for &'a Path {
1745 fn to_executable(self) -> OsString {
1746 dotify_relative_exe_path(self).into()
1747 }
1748}
1749
1750impl IntoExecutablePath for PathBuf {
1751 fn to_executable(self) -> OsString {
1752 dotify_relative_exe_path(&self).into()
1753 }
1754}
1755
1756impl<'a> IntoExecutablePath for &'a PathBuf {
1757 fn to_executable(self) -> OsString {
1758 dotify_relative_exe_path(self).into()
1759 }
1760}
1761
1762impl<'a> IntoExecutablePath for &'a str {
1763 fn to_executable(self) -> OsString {
1764 self.into()
1765 }
1766}
1767
1768impl IntoExecutablePath for String {
1769 fn to_executable(self) -> OsString {
1770 self.into()
1771 }
1772}
1773
1774impl<'a> IntoExecutablePath for &'a String {
1775 fn to_executable(self) -> OsString {
1776 self.into()
1777 }
1778}
1779
1780impl<'a> IntoExecutablePath for &'a OsStr {
1781 fn to_executable(self) -> OsString {
1782 self.into()
1783 }
1784}
1785
1786impl IntoExecutablePath for OsString {
1787 fn to_executable(self) -> OsString {
1788 self
1789 }
1790}
1791
1792impl<'a> IntoExecutablePath for &'a OsString {
1793 fn to_executable(self) -> OsString {
1794 self.into()
1795 }
1796}
1797
1798// io::Error doesn't implement clone directly, so we kind of hack it together.
1799fn clone_io_error(error: &io::Error) -> io::Error {
1800 if let Some(code) = error.raw_os_error() {
1801 io::Error::from_raw_os_error(code)
1802 } else {
1803 io::Error::new(error.kind(), error.to_string())
1804 }
1805}
1806
1807#[derive(Debug)]
1808struct SharedThread<T> {
1809 result: OnceCell<T>,
1810 handle: Mutex<Option<JoinHandle<T>>>,
1811}
1812
1813// A thread that sticks its result in a lazy cell, so that multiple callers can see it.
1814impl<T> SharedThread<T> {
1815 fn new(handle: JoinHandle<T>) -> Self {
1816 SharedThread {
1817 result: OnceCell::new(),
1818 handle: Mutex::new(Some(handle)),
1819 }
1820 }
1821
1822 // If the other thread panicked, this will panic.
1823 fn join(&self) -> &T {
1824 let mut handle_lock = self.handle.lock().expect("shared thread handle poisoned");
1825 if let Some(handle) = handle_lock.take() {
1826 let ret = handle.join().expect("panic on shared thread");
1827 self.result
1828 .set(ret)
1829 .map_err(|_| "result cell unexpectedly full")
1830 .unwrap();
1831 }
1832 self.result.get().expect("result cell unexpectedly empty")
1833 }
1834}
1835
1836#[derive(Clone, Copy, Debug)]
1837enum WaitMode {
1838 Blocking,
1839 Nonblocking,
1840}
1841
1842impl WaitMode {
1843 fn should_join_background_thread(
1844 &self,
1845 expression_result: &io::Result<Option<ExpressionStatus>>,
1846 ) -> bool {
1847 // Nonblocking waits can only join associated background threads if the
1848 // running expression is finished (that is, when the thread is
1849 // guaranteed to finish soon). Blocking waits should always join, even
1850 // in the presence of errors.
1851 matches!(self, WaitMode::Blocking) || matches!(expression_result, Ok(Some(_)))
1852 }
1853}
1854
1855#[cfg(windows)]
1856fn canonicalize_env_var_name(name: OsString) -> OsString {
1857 // On Windows, because env vars are case-insensitive, we uppercase all env
1858 // var names. That makes assignments and deletions in our internal map work
1859 // the same way they would on the real environment.
1860 match name.into_string() {
1861 Ok(name) => name.to_uppercase().into(),
1862 // If the name isn't valid Unicode then just leave it as is.
1863 Err(name) => name,
1864 }
1865}
1866
1867#[cfg(not(windows))]
1868fn canonicalize_env_var_name(name: OsString) -> OsString {
1869 // No-op on all other platforms.
1870 name
1871}
1872
1873type ReaderThread = JoinHandle<io::Result<Vec<u8>>>;
1874
1875#[derive(Debug)]
1876struct OutputCaptureContext {
1877 pair: OnceCell<(os_pipe::PipeReader, os_pipe::PipeWriter)>,
1878}
1879
1880impl OutputCaptureContext {
1881 fn new() -> Self {
1882 Self {
1883 pair: OnceCell::new(),
1884 }
1885 }
1886
1887 fn write_pipe(&self) -> io::Result<os_pipe::PipeWriter> {
1888 let (_, writer) = self.pair.get_or_try_init(os_pipe::pipe)?;
1889 writer.try_clone()
1890 }
1891
1892 // Only spawn a read thread if the write pipe was used.
1893 fn maybe_read_thread(self) -> Option<ReaderThread> {
1894 if let Some((mut reader, _)) = self.pair.into_inner() {
1895 Some(std::thread::spawn(move || {
1896 let mut output = Vec::new();
1897 reader.read_to_end(&mut output)?;
1898 Ok(output)
1899 }))
1900 } else {
1901 None
1902 }
1903 }
1904}
1905
1906/// An incremental reader created with the
1907/// [`Expression::reader`](struct.Expression.html#method.reader) method.
1908///
1909/// When this reader reaches EOF, it automatically calls
1910/// [`wait`](struct.Handle.html#method.wait) on the inner handle. If the child
1911/// returns a non-zero exit status, the read at EOF will return an error,
1912/// unless you use [`unchecked`](struct.Expression.html#method.unchecked).
1913///
1914/// If the reader is dropped before reaching EOF, it calls
1915/// [`kill`](struct.ReaderHandle.html#method.kill) in its destructor.
1916///
1917/// Both `ReaderHandle` and `&ReaderHandle` implement
1918/// [`std::io::Read`](https://doc.rust-lang.org/std/io/trait.Read.html). That
1919/// makes it possible for one thread to
1920/// [`kill`](struct.ReaderHandle.html#method.kill) the `ReaderHandle` while
1921/// another thread is reading it. That can be useful for effectively canceling
1922/// the read and unblocking the reader thread. However, note that killed child
1923/// processes return a non-zero exit status, which is an error for the reader
1924/// by default, unless you use
1925/// [`unchecked`](struct.Expression.html#method.unchecked).
1926///
1927/// # Example
1928///
1929/// ```
1930/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1931/// # if cfg!(not(windows)) {
1932/// use duct::cmd;
1933/// use duct::ReaderHandle;
1934/// use std::sync::Arc;
1935/// use std::io::prelude::*;
1936///
1937/// // This child process prints a single byte and then sleeps.
1938/// //
1939/// // CAUTION: Using Bash for this example would probably hang, because Bash
1940/// // would spawn a `sleep` grandchild processes, and that grandchild wouldn't
1941/// // receive the kill signal.
1942/// let python_child = "\
1943/// import sys
1944/// import time
1945/// print()
1946/// sys.stdout.flush()
1947/// time.sleep(24 * 60 * 60)
1948/// ";
1949/// let reader: ReaderHandle = cmd!("python3", "-c", python_child)
1950/// .unchecked()
1951/// .reader()?;
1952///
1953/// // Spawn two threads that both try to read the single byte. Whichever one
1954/// // succeeds then calls kill() to unblock the other.
1955/// let arc_reader: Arc<ReaderHandle> = Arc::new(reader);
1956/// let mut threads = Vec::new();
1957/// for _ in 0..2 {
1958/// let arc_reader = arc_reader.clone();
1959/// threads.push(std::thread::spawn(move || -> std::io::Result<()> {
1960/// let mut single_byte = [0u8];
1961/// (&*arc_reader).read(&mut single_byte)?;
1962/// arc_reader.kill()?;
1963/// Ok(())
1964/// }));
1965/// }
1966///
1967/// // Join both threads. Because of the kill() above, both threads will exit
1968/// // quickly.
1969/// for thread in threads {
1970/// thread.join().unwrap()?;
1971/// }
1972/// # }
1973/// # Ok(())
1974/// # }
1975/// ```
1976#[derive(Debug)]
1977pub struct ReaderHandle {
1978 handle: Handle,
1979 reader: os_pipe::PipeReader,
1980}
1981
1982impl ReaderHandle {
1983 /// Check whether the underlying expression is finished. This is equivalent
1984 /// to [`Handle::try_wait`](struct.Handle.html#method.try_wait). If the
1985 /// `ReaderHandle` has indicated EOF successfully, then it's guaranteed
1986 /// that this method will return `Ok(Some(_))`.
1987 ///
1988 /// Note that the
1989 /// [`stdout`](https://doc.rust-lang.org/std/process/struct.Output.html#structfield.stdout)
1990 /// field of the returned
1991 /// [`Output`](https://doc.rust-lang.org/std/process/struct.Output.html)
1992 /// will always be empty, because the `ReaderHandle` itself owns the
1993 /// child's stdout pipe.
1994 pub fn try_wait(&self) -> io::Result<Option<&Output>> {
1995 self.handle.try_wait()
1996 }
1997
1998 /// Kill the underlying expression and await all the child processes.
1999 ///
2000 /// Any errors that would normally result from a non-zero exit status are
2001 /// ignored during this wait, as with
2002 /// [`Handle::kill`](struct.Handle.html#method.kill).
2003 ///
2004 /// Note that as with
2005 /// [`std::process::Child::kill`](https://doc.rust-lang.org/beta/std/process/struct.Child.html#method.kill),
2006 /// this does not kill any grandchild processes that the children have
2007 /// spawned on their own. It only kills the child processes that Duct
2008 /// spawned itself. This is **especially relevant** for `ReaderHandle`,
2009 /// because if you're using `kill` to unblock another thread that's
2010 /// reading, an unkilled grandchild process might keep the child's stdout
2011 /// pipe open and keep your reader thread blocked. For that use case, you
2012 /// need to ensure that any grandchild processes your child might spawn are
2013 /// going to be short-lived. See
2014 /// [`gotchas.md`](https://github.com/oconnor663/duct.py/blob/master/gotchas.md)
2015 /// for an extensive discussion of these issues.
2016 pub fn kill(&self) -> io::Result<()> {
2017 self.handle.kill()
2018 }
2019
2020 /// Return a `Vec<u32>` containing the PIDs of all of the child processes.
2021 /// The PIDs are given in pipeline order, from left to right.
2022 pub fn pids(&self) -> Vec<u32> {
2023 self.handle.pids()
2024 }
2025}
2026
2027impl<'a> Read for &'a ReaderHandle {
2028 /// Note that if you don't use
2029 /// [`unchecked`](struct.Expression.html#method.unchecked), and the child
2030 /// returns a non-zero exit status, the final call to `read` will return an
2031 /// error, just as [`run`](struct.Expression.html#method.run) would.
2032 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2033 let n = (&self.reader).read(buf)?;
2034 if n == 0 && !buf.is_empty() {
2035 // EOF detected. Wait on the child to clean it up before returning.
2036 self.handle.wait()?;
2037 }
2038 Ok(n)
2039 }
2040}
2041
2042impl Read for ReaderHandle {
2043 /// Note that if you don't use
2044 /// [`unchecked`](struct.Expression.html#method.unchecked), and the child
2045 /// returns a non-zero exit status, the final call to `read` will return an
2046 /// error, just as [`run`](struct.Expression.html#method.run) would.
2047 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2048 (&*self).read(buf)
2049 }
2050}
2051
2052impl Drop for ReaderHandle {
2053 fn drop(&mut self) {
2054 // Just call kill() unconditionally. If wait() has already happened,
2055 // this has no effect.
2056 let _ = self.handle.kill();
2057 }
2058}
2059
2060#[cfg(test)]
2061mod test;