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;