subprocess/
builder.rs

1#[cfg(unix)]
2mod os {
3    pub const NULL_DEVICE: &str = "/dev/null";
4    pub const SHELL: [&str; 2] = ["sh", "-c"];
5}
6
7#[cfg(windows)]
8mod os {
9    pub const NULL_DEVICE: &str = "nul";
10    pub const SHELL: [&str; 2] = ["cmd.exe", "/c"];
11}
12
13#[cfg(unix)]
14pub use exec::unix::ExecExt;
15#[cfg(windows)]
16pub use exec::windows::ExecExt;
17pub use exec::{CaptureData, Exec, NullFile};
18pub use pipeline::Pipeline;
19
20/// Windows-specific process creation constants and extensions.
21#[cfg(windows)]
22pub mod windows {
23    pub use super::exec::windows::*;
24}
25
26mod exec {
27    use std::borrow::Cow;
28    use std::collections::HashMap;
29    use std::env;
30    use std::ffi::{OsStr, OsString};
31    use std::fmt;
32    use std::fs::{File, OpenOptions};
33    use std::io::ErrorKind;
34    use std::io::{self, Read, Write};
35    use std::ops::BitOr;
36    use std::path::Path;
37    use std::time::Duration;
38
39    use crate::PopenError;
40    use crate::communicate::Communicator;
41    use crate::os_common::ExitStatus;
42    use crate::popen::{Popen, PopenConfig, Redirection, Result as PopenResult};
43
44    use super::Pipeline;
45    use super::os::*;
46
47    /// A builder for [`Popen`] instances, providing control and convenience methods.
48    ///
49    /// `Exec` provides a builder API for [`Popen::create`], and includes convenience methods
50    /// for capturing the output, and for connecting subprocesses into pipelines.
51    ///
52    /// # Examples
53    ///
54    /// Execute an external command and wait for it to complete:
55    ///
56    /// ```no_run
57    /// # use subprocess::*;
58    /// # fn dummy() -> Result<()> {
59    /// # let dirname = "some_dir";
60    /// let exit_status = Exec::cmd("umount").arg(dirname).join()?;
61    /// # Ok(())
62    /// # }
63    /// ```
64    ///
65    /// Execute the command using the OS shell, like C's `system`:
66    ///
67    /// ```no_run
68    /// # use subprocess::*;
69    /// # fn dummy() -> Result<()> {
70    /// Exec::shell("shutdown -h now").join()?;
71    /// # Ok(())
72    /// # }
73    /// ```
74    ///
75    /// Start a subprocess and obtain its output as a `Read` trait object, like C's `popen`:
76    ///
77    /// ```
78    /// # use subprocess::*;
79    /// # fn dummy() -> Result<()> {
80    /// let stream = Exec::cmd("ls").stream_stdout()?;
81    /// // call stream.read_to_string, construct io::BufReader(stream), etc.
82    /// # Ok(())
83    /// # }
84    /// ```
85    ///
86    /// Capture the output of a command:
87    ///
88    /// ```
89    /// # use subprocess::*;
90    /// # fn dummy() -> Result<()> {
91    /// let out = Exec::cmd("ls")
92    ///   .stdout(Redirection::Pipe)
93    ///   .capture()?
94    ///   .stdout_str();
95    /// # Ok(())
96    /// # }
97    /// ```
98    ///
99    /// Redirect standard error to standard output, and capture both in a single stream:
100    ///
101    /// ```
102    /// # use subprocess::*;
103    /// # fn dummy() -> Result<()> {
104    /// let out_and_err = Exec::cmd("ls")
105    ///   .stdout(Redirection::Pipe)
106    ///   .stderr(Redirection::Merge)
107    ///   .capture()?
108    ///   .stdout_str();
109    /// # Ok(())
110    /// # }
111    /// ```
112    ///
113    /// Provide input to the command and read its output:
114    ///
115    /// ```
116    /// # use subprocess::*;
117    /// # fn dummy() -> Result<()> {
118    /// let out = Exec::cmd("sort")
119    ///   .stdin("b\nc\na\n")
120    ///   .stdout(Redirection::Pipe)
121    ///   .capture()?
122    ///   .stdout_str();
123    /// assert!(out == "a\nb\nc\n");
124    /// # Ok(())
125    /// # }
126    /// ```
127    ///
128    /// [`Popen`]: struct.Popen.html
129    /// [`Popen::create`]: struct.Popen.html#method.create
130    #[must_use]
131    pub struct Exec {
132        command: OsString,
133        args: Vec<OsString>,
134        time_limit: Option<Duration>,
135        config: PopenConfig,
136        stdin_data: Option<Vec<u8>>,
137    }
138
139    impl Exec {
140        /// Constructs a new `Exec`, configured to run `command`.
141        ///
142        /// The command will be run directly in the OS, without an intervening shell.  To run
143        /// it through a shell, use [`Exec::shell`] instead.
144        ///
145        /// By default, the command will be run without arguments, and none of the standard
146        /// streams will be modified.
147        ///
148        /// [`Exec::shell`]: struct.Exec.html#method.shell
149        pub fn cmd(command: impl AsRef<OsStr>) -> Exec {
150            Exec {
151                command: command.as_ref().to_owned(),
152                args: vec![],
153                time_limit: None,
154                config: PopenConfig::default(),
155                stdin_data: None,
156            }
157        }
158
159        /// Constructs a new `Exec`, configured to run `cmdstr` with the system shell.
160        ///
161        /// `subprocess` never spawns shells without an explicit request.  This command
162        /// requests the shell to be used; on Unix-like systems, this is equivalent to
163        /// `Exec::cmd("sh").arg("-c").arg(cmdstr)`.  On Windows, it runs
164        /// `Exec::cmd("cmd.exe").arg("/c")`.
165        ///
166        /// `shell` is useful for porting code that uses the C `system` function, which also
167        /// spawns a shell.
168        ///
169        /// When invoking this function, be careful not to interpolate arguments into the
170        /// string run by the shell, such as `Exec::shell(format!("sort {}", filename))`.
171        /// Such code is prone to errors and, if `filename` comes from an untrusted source, to
172        /// shell injection attacks.  Instead, use `Exec::cmd("sort").arg(filename)`.
173        pub fn shell(cmdstr: impl AsRef<OsStr>) -> Exec {
174            Exec::cmd(SHELL[0]).args(&SHELL[1..]).arg(cmdstr)
175        }
176
177        /// Appends `arg` to argument list.
178        pub fn arg(mut self, arg: impl AsRef<OsStr>) -> Exec {
179            self.args.push(arg.as_ref().to_owned());
180            self
181        }
182
183        /// Extends the argument list with `args`.
184        pub fn args(mut self, args: &[impl AsRef<OsStr>]) -> Exec {
185            self.args.extend(args.iter().map(|x| x.as_ref().to_owned()));
186            self
187        }
188
189        /// Specifies that the process is initially detached.
190        ///
191        /// A detached process means that we will not wait for the process to finish when the
192        /// object that owns it goes out of scope.
193        pub fn detached(mut self) -> Exec {
194            self.config.detached = true;
195            self
196        }
197
198        /// Limit the amount of time the next `read()` will spend reading from the
199        /// subprocess.
200        pub fn time_limit(mut self, time: Duration) -> Exec {
201            self.time_limit = Some(time);
202            self
203        }
204
205        fn ensure_env(&mut self) {
206            if self.config.env.is_none() {
207                self.config.env = Some(PopenConfig::current_env());
208            }
209        }
210
211        /// Clears the environment of the subprocess.
212        ///
213        /// When this is invoked, the subprocess will not inherit the environment of this
214        /// process.
215        pub fn env_clear(mut self) -> Exec {
216            self.config.env = Some(vec![]);
217            self
218        }
219
220        /// Sets an environment variable in the child process.
221        ///
222        /// If the same variable is set more than once, the last value is used.
223        ///
224        /// Other environment variables are by default inherited from the current process.  If
225        /// this is undesirable, call `env_clear` first.
226        pub fn env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Exec {
227            self.ensure_env();
228            self.config
229                .env
230                .as_mut()
231                .unwrap()
232                .push((key.as_ref().to_owned(), value.as_ref().to_owned()));
233            self
234        }
235
236        /// Sets multiple environment variables in the child process.
237        ///
238        /// The keys and values of the variables are specified by the slice.  If the same
239        /// variable is set more than once, the last value is used.
240        ///
241        /// Other environment variables are by default inherited from the current process.  If
242        /// this is undesirable, call `env_clear` first.
243        pub fn env_extend(mut self, vars: &[(impl AsRef<OsStr>, impl AsRef<OsStr>)]) -> Exec {
244            self.ensure_env();
245            {
246                let envvec = self.config.env.as_mut().unwrap();
247                envvec.extend(
248                    vars.iter()
249                        .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned())),
250                );
251            }
252            self
253        }
254
255        /// Removes an environment variable from the child process.
256        ///
257        /// Other environment variables are inherited by default.
258        pub fn env_remove(mut self, key: impl AsRef<OsStr>) -> Exec {
259            self.ensure_env();
260            self.config
261                .env
262                .as_mut()
263                .unwrap()
264                .retain(|(k, _v)| k != key.as_ref());
265            self
266        }
267
268        /// Specifies the current working directory of the child process.
269        ///
270        /// If unspecified, the current working directory is inherited from the parent.
271        pub fn cwd(mut self, dir: impl AsRef<Path>) -> Exec {
272            self.config.cwd = Some(dir.as_ref().as_os_str().to_owned());
273            self
274        }
275
276        /// Specifies how to set up the standard input of the child process.
277        ///
278        /// Argument can be:
279        ///
280        /// * a [`Redirection`];
281        /// * a `File`, which is a shorthand for `Redirection::File(file)`;
282        /// * a `Vec<u8>` or `&str`, which will set up a `Redirection::Pipe`
283        ///   for stdin, making sure that `capture` feeds that data into the
284        ///   standard input of the subprocess;
285        /// * [`NullFile`], which will redirect the standard input to read from
286        ///   `/dev/null`.
287        ///
288        /// [`Redirection`]: enum.Redirection.html
289        /// [`NullFile`]: struct.NullFile.html
290        pub fn stdin(mut self, stdin: impl Into<InputRedirection>) -> Exec {
291            match (&self.config.stdin, stdin.into()) {
292                (&Redirection::None, InputRedirection::AsRedirection(new)) => {
293                    self.config.stdin = new
294                }
295                (&Redirection::Pipe, InputRedirection::AsRedirection(Redirection::Pipe)) => (),
296                (&Redirection::None, InputRedirection::FeedData(data)) => {
297                    self.config.stdin = Redirection::Pipe;
298                    self.stdin_data = Some(data);
299                }
300                (_, _) => panic!("stdin is already set"),
301            }
302            self
303        }
304
305        /// Specifies how to set up the standard output of the child process.
306        ///
307        /// Argument can be:
308        ///
309        /// * a [`Redirection`];
310        /// * a `File`, which is a shorthand for `Redirection::File(file)`;
311        /// * [`NullFile`], which will redirect the standard output to go to
312        ///   `/dev/null`.
313        ///
314        /// [`Redirection`]: enum.Redirection.html
315        /// [`NullFile`]: struct.NullFile.html
316        pub fn stdout(mut self, stdout: impl Into<OutputRedirection>) -> Exec {
317            match (&self.config.stdout, stdout.into().into_redirection()) {
318                (&Redirection::None, new) => self.config.stdout = new,
319                (&Redirection::Pipe, Redirection::Pipe) => (),
320                (_, _) => panic!("stdout is already set"),
321            }
322            self
323        }
324
325        /// Specifies how to set up the standard error of the child process.
326        ///
327        /// Argument can be:
328        ///
329        /// * a [`Redirection`];
330        /// * a `File`, which is a shorthand for `Redirection::File(file)`;
331        /// * [`NullFile`], which will redirect the standard error to go to
332        ///   `/dev/null`.
333        ///
334        /// [`Redirection`]: enum.Redirection.html
335        /// [`NullFile`]: struct.NullFile.html
336        pub fn stderr(mut self, stderr: impl Into<OutputRedirection>) -> Exec {
337            match (&self.config.stderr, stderr.into().into_redirection()) {
338                (&Redirection::None, new) => self.config.stderr = new,
339                (&Redirection::Pipe, Redirection::Pipe) => (),
340                (_, _) => panic!("stderr is already set"),
341            }
342            self
343        }
344
345        fn check_no_stdin_data(&self, meth: &str) {
346            if self.stdin_data.is_some() {
347                panic!("{} called with input data specified", meth);
348            }
349        }
350
351        // Terminators
352
353        /// Starts the process, returning a `Popen` for the running process.
354        pub fn popen(mut self) -> PopenResult<Popen> {
355            self.check_no_stdin_data("popen");
356            self.args.insert(0, self.command);
357            let p = Popen::create(&self.args, self.config)?;
358            Ok(p)
359        }
360
361        /// Starts the process, waits for it to finish, and returns the exit status.
362        ///
363        /// This method will wait for as long as necessary for the process to finish.  If a
364        /// timeout is needed, use `<...>.detached().popen()?.wait_timeout(...)` instead.
365        pub fn join(self) -> PopenResult<ExitStatus> {
366            self.check_no_stdin_data("join");
367            self.popen()?.wait()
368        }
369
370        /// Starts the process and returns a value implementing the `Read` trait that reads from
371        /// the standard output of the child process.
372        ///
373        /// This will automatically set up `stdout(Redirection::Pipe)`, so it is not necessary
374        /// to do that beforehand.
375        ///
376        /// When the trait object is dropped, it will wait for the process to finish.  If this
377        /// is undesirable, use `detached()`.
378        pub fn stream_stdout(self) -> PopenResult<impl Read> {
379            self.check_no_stdin_data("stream_stdout");
380            let p = self.stdout(Redirection::Pipe).popen()?;
381            Ok(ReadOutAdapter(p))
382        }
383
384        /// Starts the process and returns a value implementing the `Read` trait that reads from
385        /// the standard error of the child process.
386        ///
387        /// This will automatically set up `stderr(Redirection::Pipe)`, so it is not necessary
388        /// to do that beforehand.
389        ///
390        /// When the trait object is dropped, it will wait for the process to finish.  If this
391        /// is undesirable, use `detached()`.
392        pub fn stream_stderr(self) -> PopenResult<impl Read> {
393            self.check_no_stdin_data("stream_stderr");
394            let p = self.stderr(Redirection::Pipe).popen()?;
395            Ok(ReadErrAdapter(p))
396        }
397
398        /// Starts the process and returns a value implementing the `Write` trait that writes to
399        /// the standard input of the child process.
400        ///
401        /// This will automatically set up `stdin(Redirection::Pipe)`, so it is not necessary
402        /// to do that beforehand.
403        ///
404        /// When the trait object is dropped, it will wait for the process to finish.  If this
405        /// is undesirable, use `detached()`.
406        pub fn stream_stdin(self) -> PopenResult<impl Write> {
407            self.check_no_stdin_data("stream_stdin");
408            let p = self.stdin(Redirection::Pipe).popen()?;
409            Ok(WriteAdapter(p))
410        }
411
412        fn setup_communicate(mut self) -> PopenResult<(Communicator, Popen)> {
413            let stdin_data = self.stdin_data.take();
414            if let (&Redirection::None, &Redirection::None) =
415                (&self.config.stdout, &self.config.stderr)
416            {
417                self = self.stdout(Redirection::Pipe);
418            }
419            let mut p = self.popen()?;
420
421            Ok((p.communicate_start(stdin_data), p))
422        }
423
424        /// Starts the process and returns a `Communicator` handle.
425        ///
426        /// This is a lower-level API that offers more choice in how communication is
427        /// performed, such as read size limit and timeout, equivalent to
428        /// [`Popen::communicate`].
429        ///
430        /// Unlike `capture()`, this method doesn't wait for the process to finish, effectively
431        /// detaching it.
432        ///
433        /// [`Popen::communicate`]: struct.Popen.html#method.communicate
434        pub fn communicate(self) -> PopenResult<Communicator> {
435            let comm = self.detached().setup_communicate()?.0;
436            Ok(comm)
437        }
438
439        /// Starts the process, collects its output, and waits for it to finish.
440        ///
441        /// The return value provides the standard output and standard error as bytes or
442        /// optionally strings, as well as the exit status.
443        ///
444        /// Unlike `Popen::communicate`, this method actually waits for the process to finish,
445        /// rather than simply waiting for its standard streams to close.  If this is
446        /// undesirable, use `detached()`.
447        pub fn capture(self) -> PopenResult<CaptureData> {
448            let timeout = self.time_limit;
449            let (mut comm, mut p) = self.setup_communicate()?;
450            if let Some(t) = timeout {
451                comm = comm.limit_time(t);
452            }
453
454            let (maybe_out, maybe_err) = comm.read()?;
455            Ok(CaptureData {
456                stdout: maybe_out.unwrap_or_else(Vec::new),
457                stderr: maybe_err.unwrap_or_else(Vec::new),
458                exit_status: match timeout {
459                    Some(t) => p
460                        .wait_timeout(t)?
461                        .ok_or(PopenError::IoError(ErrorKind::TimedOut.into()))?,
462                    None => p.wait()?,
463                },
464            })
465        }
466
467        // used for Debug impl
468        fn display_escape(s: &str) -> Cow<'_, str> {
469            fn nice_char(c: char) -> bool {
470                match c {
471                    '-' | '_' | '.' | ',' | '/' => true,
472                    c if c.is_ascii_alphanumeric() => true,
473                    _ => false,
474                }
475            }
476            if !s.chars().all(nice_char) {
477                Cow::Owned(format!("'{}'", s.replace("'", r#"'\''"#)))
478            } else {
479                Cow::Borrowed(s)
480            }
481        }
482
483        /// Show Exec as command-line string quoted in the Unix style.
484        pub fn to_cmdline_lossy(&self) -> String {
485            let mut out = String::new();
486            if let Some(ref cmd_env) = self.config.env {
487                let current: Vec<_> = env::vars_os().collect();
488                let current_map: HashMap<_, _> = current.iter().map(|(x, y)| (x, y)).collect();
489                for (k, v) in cmd_env {
490                    if current_map.get(&k) == Some(&v) {
491                        continue;
492                    }
493                    out.push_str(&Exec::display_escape(&k.to_string_lossy()));
494                    out.push('=');
495                    out.push_str(&Exec::display_escape(&v.to_string_lossy()));
496                    out.push(' ');
497                }
498                let cmd_env: HashMap<_, _> = cmd_env.iter().map(|(k, v)| (k, v)).collect();
499                for (k, _) in current {
500                    if !cmd_env.contains_key(&k) {
501                        out.push_str(&Exec::display_escape(&k.to_string_lossy()));
502                        out.push('=');
503                        out.push(' ');
504                    }
505                }
506            }
507            out.push_str(&Exec::display_escape(&self.command.to_string_lossy()));
508            for arg in &self.args {
509                out.push(' ');
510                out.push_str(&Exec::display_escape(&arg.to_string_lossy()));
511            }
512            out
513        }
514
515        pub(super) fn stdin_is_set(&self) -> bool {
516            !matches!(self.config.stdin, Redirection::None)
517        }
518
519        pub(super) fn stdout_is_set(&self) -> bool {
520            !matches!(self.config.stdout, Redirection::None)
521        }
522    }
523
524    impl Clone for Exec {
525        /// Returns a copy of the value.
526        ///
527        /// This method is guaranteed not to fail as long as none of the `Redirection` values
528        /// contain a `Redirection::File` variant.  If a redirection to `File` is present,
529        /// cloning that field will use `File::try_clone` method, which duplicates a file
530        /// descriptor and can (but is not likely to) fail.  In that scenario, `Exec::clone`
531        /// panics.
532        fn clone(&self) -> Exec {
533            Exec {
534                command: self.command.clone(),
535                args: self.args.clone(),
536                time_limit: self.time_limit,
537                config: self.config.try_clone().unwrap(),
538                stdin_data: self.stdin_data.clone(),
539            }
540        }
541    }
542
543    impl BitOr for Exec {
544        type Output = Pipeline;
545
546        /// Create a `Pipeline` from `self` and `rhs`.
547        fn bitor(self, rhs: Exec) -> Pipeline {
548            Pipeline::new(self, rhs)
549        }
550    }
551
552    impl fmt::Debug for Exec {
553        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
554            write!(f, "Exec {{ {} }}", self.to_cmdline_lossy())
555        }
556    }
557
558    #[derive(Debug)]
559    struct ReadOutAdapter(Popen);
560
561    impl Read for ReadOutAdapter {
562        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
563            self.0.stdout.as_mut().unwrap().read(buf)
564        }
565    }
566
567    #[derive(Debug)]
568    struct ReadErrAdapter(Popen);
569
570    impl Read for ReadErrAdapter {
571        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
572            self.0.stderr.as_mut().unwrap().read(buf)
573        }
574    }
575
576    #[derive(Debug)]
577    struct WriteAdapter(Popen);
578
579    impl Write for WriteAdapter {
580        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
581            self.0.stdin.as_mut().unwrap().write(buf)
582        }
583        fn flush(&mut self) -> io::Result<()> {
584            self.0.stdin.as_mut().unwrap().flush()
585        }
586    }
587
588    // We must implement Drop in order to close the stream.  The typical
589    // use case for stream_stdin() is a process that reads something from
590    // stdin.  WriteAdapter going out of scope invokes Popen::drop(),
591    // which waits for the process to exit.  Without closing stdin, this
592    // deadlocks because the child process hangs reading its stdin.
593
594    impl Drop for WriteAdapter {
595        fn drop(&mut self) {
596            self.0.stdin.take();
597        }
598    }
599
600    /// Data captured by [`Exec::capture`] and [`Pipeline::capture`].
601    ///
602    /// [`Exec::capture`]: struct.Exec.html#method.capture
603    /// [`Pipeline::capture`]: struct.Pipeline.html#method.capture
604    #[derive(Debug)]
605    pub struct CaptureData {
606        /// Standard output as bytes.
607        pub stdout: Vec<u8>,
608        /// Standard error as bytes.
609        pub stderr: Vec<u8>,
610        /// Exit status.
611        pub exit_status: ExitStatus,
612    }
613
614    impl CaptureData {
615        /// Returns the standard output as string, converted from bytes using
616        /// `String::from_utf8_lossy`.
617        pub fn stdout_str(&self) -> String {
618            String::from_utf8_lossy(&self.stdout).into_owned()
619        }
620
621        /// Returns the standard error as string, converted from bytes using
622        /// `String::from_utf8_lossy`.
623        pub fn stderr_str(&self) -> String {
624            String::from_utf8_lossy(&self.stderr).into_owned()
625        }
626
627        /// True if the exit status of the process or pipeline is 0.
628        pub fn success(&self) -> bool {
629            self.exit_status.success()
630        }
631    }
632
633    #[derive(Debug)]
634    pub enum InputRedirection {
635        AsRedirection(Redirection),
636        FeedData(Vec<u8>),
637    }
638
639    impl From<Redirection> for InputRedirection {
640        fn from(r: Redirection) -> Self {
641            if let Redirection::Merge = r {
642                panic!("Redirection::Merge is only allowed for output streams");
643            }
644            InputRedirection::AsRedirection(r)
645        }
646    }
647
648    impl From<File> for InputRedirection {
649        fn from(f: File) -> Self {
650            InputRedirection::AsRedirection(Redirection::File(f))
651        }
652    }
653
654    /// Marker value for [`stdin`], [`stdout`], and [`stderr`] methods of [`Exec`] and
655    /// [`Pipeline`].
656    ///
657    /// Use of this value means that the corresponding stream should be redirected to the
658    /// devnull device.
659    ///
660    /// [`stdin`]: struct.Exec.html#method.stdin
661    /// [`stdout`]: struct.Exec.html#method.stdout
662    /// [`stderr`]: struct.Exec.html#method.stderr
663    /// [`Exec`]: struct.Exec.html
664    /// [`Pipeline`]: struct.Pipeline.html
665    #[derive(Debug)]
666    pub struct NullFile;
667
668    impl From<NullFile> for InputRedirection {
669        fn from(_nf: NullFile) -> Self {
670            let null_file = OpenOptions::new().read(true).open(NULL_DEVICE).unwrap();
671            InputRedirection::AsRedirection(Redirection::File(null_file))
672        }
673    }
674
675    impl From<Vec<u8>> for InputRedirection {
676        fn from(v: Vec<u8>) -> Self {
677            InputRedirection::FeedData(v)
678        }
679    }
680
681    impl<'a> From<&'a str> for InputRedirection {
682        fn from(s: &'a str) -> Self {
683            InputRedirection::FeedData(s.as_bytes().to_vec())
684        }
685    }
686
687    #[derive(Debug)]
688    pub struct OutputRedirection(Redirection);
689
690    impl OutputRedirection {
691        pub fn into_redirection(self) -> Redirection {
692            self.0
693        }
694    }
695
696    impl From<Redirection> for OutputRedirection {
697        fn from(r: Redirection) -> Self {
698            OutputRedirection(r)
699        }
700    }
701
702    impl From<File> for OutputRedirection {
703        fn from(f: File) -> Self {
704            OutputRedirection(Redirection::File(f))
705        }
706    }
707
708    impl From<NullFile> for OutputRedirection {
709        fn from(_nf: NullFile) -> Self {
710            let null_file = OpenOptions::new().write(true).open(NULL_DEVICE).unwrap();
711            OutputRedirection(Redirection::File(null_file))
712        }
713    }
714
715    #[cfg(unix)]
716    pub mod unix {
717        use super::Exec;
718
719        /// Trait allowing for custom implementations of `setuid` and `setgid` behaviors on Unix
720        /// which handle file system permissions (owner or group respectively).
721        pub trait ExecExt {
722            /// sets the access right flag, similar to unix setuid
723            fn setuid(self, uid: u32) -> Self;
724            /// sets the access right flag, similar to unix setgid
725            fn setgid(self, gid: u32) -> Self;
726        }
727
728        impl ExecExt for Exec {
729            fn setuid(mut self, uid: u32) -> Exec {
730                self.config.setuid = Some(uid);
731                self
732            }
733
734            fn setgid(mut self, gid: u32) -> Exec {
735                self.config.setgid = Some(gid);
736                self
737            }
738        }
739    }
740
741    #[cfg(windows)]
742    pub mod windows {
743        use super::Exec;
744
745        /// Process creation flag: The process does not have a console window.
746        ///
747        /// Use this flag when launching GUI applications or background processes to prevent
748        /// a console window from briefly appearing.
749        pub const CREATE_NO_WINDOW: u32 = 0x08000000;
750
751        /// Process creation flag: The new process has a new console.
752        ///
753        /// This flag cannot be used with `DETACHED_PROCESS`.
754        pub const CREATE_NEW_CONSOLE: u32 = 0x00000010;
755
756        /// Process creation flag: The new process is the root of a new process group.
757        ///
758        /// The process group includes all descendant processes. Useful for sending signals
759        /// to a group of related processes.
760        pub const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
761
762        /// Process creation flag: The process does not inherit its parent's console.
763        ///
764        /// The new process can call `AllocConsole` later to create a console.
765        /// This flag cannot be used with `CREATE_NEW_CONSOLE`.
766        pub const DETACHED_PROCESS: u32 = 0x00000008;
767
768        /// Extension trait for Windows-specific process creation options.
769        pub trait ExecExt {
770            /// Set process creation flags for Windows.
771            ///
772            /// This value is passed to the `dwCreationFlags` parameter of `CreateProcessW`.
773            /// Use this to control process creation behavior such as creating the process
774            /// without a console window.
775            ///
776            /// # Example
777            ///
778            /// ```ignore
779            /// use subprocess::{Exec, ExecExt, windows::CREATE_NO_WINDOW};
780            ///
781            /// let popen = Exec::cmd("my_app")
782            ///     .creation_flags(CREATE_NO_WINDOW)
783            ///     .popen()?;
784            /// ```
785            fn creation_flags(self, flags: u32) -> Self;
786        }
787
788        impl ExecExt for Exec {
789            fn creation_flags(mut self, flags: u32) -> Exec {
790                self.config.creation_flags = flags;
791                self
792            }
793        }
794    }
795}
796
797mod pipeline {
798    use std::fmt;
799    use std::fs::File;
800    use std::io::{self, Read, Write};
801    use std::ops::BitOr;
802    use std::rc::Rc;
803
804    use crate::communicate::{self, Communicator};
805    use crate::os_common::ExitStatus;
806    use crate::popen::{Popen, Redirection, Result as PopenResult};
807
808    use super::exec::{CaptureData, Exec, InputRedirection, OutputRedirection};
809
810    /// A builder for multiple [`Popen`] instances connected via pipes.
811    ///
812    /// A pipeline is a sequence of two or more [`Exec`] commands connected via pipes.  Just
813    /// like in a Unix shell pipeline, each command receives standard input from the previous
814    /// command, and passes standard output to the next command.  Optionally, the standard
815    /// input of the first command can be provided from the outside, and the output of the
816    /// last command can be captured.
817    ///
818    /// In most cases you do not need to create [`Pipeline`] instances directly; instead,
819    /// combine [`Exec`] instances using the `|` operator which produces `Pipeline`.
820    ///
821    /// # Examples
822    ///
823    /// Execute a pipeline and return the exit status of the last command:
824    ///
825    /// ```no_run
826    /// # use subprocess::*;
827    /// # fn dummy() -> Result<()> {
828    /// let exit_status =
829    ///   (Exec::shell("ls *.bak") | Exec::cmd("xargs").arg("rm")).join()?;
830    /// # Ok(())
831    /// # }
832    /// ```
833    ///
834    /// Capture the pipeline's output:
835    ///
836    /// ```no_run
837    /// # use subprocess::*;
838    /// # fn dummy() -> Result<()> {
839    /// let dir_checksum = {
840    ///     Exec::cmd("find . -type f") | Exec::cmd("sort") | Exec::cmd("sha1sum")
841    /// }.capture()?.stdout_str();
842    /// # Ok(())
843    /// # }
844    /// ```
845    ///
846    /// [`Popen`]: struct.Popen.html
847    /// [`Exec`]: struct.Exec.html
848    /// [`Pipeline`]: struct.Pipeline.html
849    #[must_use]
850    pub struct Pipeline {
851        cmds: Vec<Exec>,
852        stdin: Redirection,
853        stdout: Redirection,
854        stderr_file: Option<File>,
855        stdin_data: Option<Vec<u8>>,
856    }
857
858    impl Pipeline {
859        /// Creates a new pipeline by combining two commands.
860        ///
861        /// Equivalent to `cmd1 | cmd2`.
862        ///
863        /// # Panics
864        ///
865        /// Panics if `cmd1` has stdin redirected or `cmd2` has stdout redirected.
866        /// Use `Pipeline::stdin()` and `Pipeline::stdout()` to redirect the pipeline's streams.
867        pub fn new(cmd1: Exec, cmd2: Exec) -> Pipeline {
868            if cmd1.stdin_is_set() {
869                panic!(
870                    "stdin of the first command is already redirected; \
871                     use Pipeline::stdin() to redirect pipeline input"
872                );
873            }
874            if cmd2.stdout_is_set() {
875                panic!(
876                    "stdout of the last command is already redirected; \
877                     use Pipeline::stdout() to redirect pipeline output"
878                );
879            }
880            Pipeline {
881                cmds: vec![cmd1, cmd2],
882                stdin: Redirection::None,
883                stdout: Redirection::None,
884                stderr_file: None,
885                stdin_data: None,
886            }
887        }
888
889        /// Creates a new pipeline from a list of commands.  Useful if a pipeline should be
890        /// created dynamically.
891        ///
892        /// # Panics
893        ///
894        /// Panics if:
895        /// - The iterator contains fewer than two commands.
896        /// - The first command has stdin redirected.
897        /// - The last command has stdout redirected.
898        ///
899        /// Use `Pipeline::stdin()` and `Pipeline::stdout()` to redirect the pipeline's streams.
900        ///
901        /// # Example
902        ///
903        /// ```no_run
904        /// use subprocess::Exec;
905        ///
906        /// let commands = vec![
907        ///   Exec::shell("echo tset"),
908        ///   Exec::shell("tr '[:lower:]' '[:upper:]'"),
909        ///   Exec::shell("rev")
910        /// ];
911        ///
912        /// let pipeline = subprocess::Pipeline::from_exec_iter(commands);
913        /// let output = pipeline.capture().unwrap().stdout_str();
914        /// assert_eq!(output, "TEST\n");
915        /// ```
916        pub fn from_exec_iter<I>(iterable: I) -> Pipeline
917        where
918            I: IntoIterator<Item = Exec>,
919        {
920            let cmds: Vec<_> = iterable.into_iter().collect();
921
922            if cmds.len() < 2 {
923                panic!("pipeline requires at least two commands")
924            }
925            if cmds.first().unwrap().stdin_is_set() {
926                panic!(
927                    "stdin of the first command is already redirected; \
928                     use Pipeline::stdin() to redirect pipeline input"
929                );
930            }
931            if cmds.last().unwrap().stdout_is_set() {
932                panic!(
933                    "stdout of the last command is already redirected; \
934                     use Pipeline::stdout() to redirect pipeline output"
935                );
936            }
937
938            Pipeline {
939                cmds,
940                stdin: Redirection::None,
941                stdout: Redirection::None,
942                stderr_file: None,
943                stdin_data: None,
944            }
945        }
946
947        /// Specifies how to set up the standard input of the first command in the pipeline.
948        ///
949        /// Argument can be:
950        ///
951        /// * a [`Redirection`];
952        /// * a `File`, which is a shorthand for `Redirection::File(file)`;
953        /// * a `Vec<u8>` or `&str`, which will set up a `Redirection::Pipe`
954        ///   for stdin, making sure that `capture` feeds that data into the
955        ///   standard input of the subprocess.
956        /// * `NullFile`, which will redirect the standard input to read from
957        ///   /dev/null.
958        ///
959        /// [`Redirection`]: enum.Redirection.html
960        pub fn stdin(mut self, stdin: impl Into<InputRedirection>) -> Pipeline {
961            match stdin.into() {
962                InputRedirection::AsRedirection(r) => self.stdin = r,
963                InputRedirection::FeedData(data) => {
964                    self.stdin = Redirection::Pipe;
965                    self.stdin_data = Some(data);
966                }
967            };
968            self
969        }
970
971        /// Specifies how to set up the standard output of the last command in the pipeline.
972        ///
973        /// Argument can be:
974        ///
975        /// * a [`Redirection`];
976        /// * a `File`, which is a shorthand for `Redirection::File(file)`;
977        /// * `NullFile`, which will redirect the standard output to write to
978        ///   /dev/null.
979        ///
980        /// [`Redirection`]: enum.Redirection.html
981        pub fn stdout(mut self, stdout: impl Into<OutputRedirection>) -> Pipeline {
982            self.stdout = stdout.into().into_redirection();
983            self
984        }
985
986        /// Specifies a file to which to redirect the standard error of all the commands in the
987        /// pipeline.
988        ///
989        /// It is useful for capturing the standard error of the pipeline as a whole.  Unlike
990        /// `stdout()`, which only affects the last command in the pipeline, this affects all
991        /// commands.  The difference is because standard output is piped from one command to
992        /// the next, so only the output of the last command is "free".  In contrast, the
993        /// standard errors are not connected in any way.  This is also the reason only a
994        /// `File` is supported - it allows for efficient sharing of the same file by all
995        /// commands.
996        pub fn stderr_to(mut self, to: File) -> Pipeline {
997            self.stderr_file = Some(to);
998            self
999        }
1000
1001        fn check_no_stdin_data(&self, meth: &str) {
1002            if self.stdin_data.is_some() {
1003                panic!("{} called with input data specified", meth);
1004            }
1005        }
1006
1007        // Terminators:
1008
1009        /// Starts all commands in the pipeline, and returns a `Vec<Popen>` whose members
1010        /// correspond to running commands.
1011        ///
1012        /// If some command fails to start, the remaining commands will not be started, and
1013        /// the appropriate error will be returned.  The commands that have already started
1014        /// will be waited to finish (but will probably exit immediately due to missing
1015        /// output), except for the ones for which `detached()` was called.  This is
1016        /// equivalent to what the shell does.
1017        pub fn popen(mut self) -> PopenResult<Vec<Popen>> {
1018            self.check_no_stdin_data("popen");
1019            assert!(self.cmds.len() >= 2);
1020
1021            if let Some(stderr_to) = self.stderr_file {
1022                let stderr_to = Rc::new(stderr_to);
1023                self.cmds = self
1024                    .cmds
1025                    .into_iter()
1026                    .map(|cmd| cmd.stderr(Redirection::RcFile(Rc::clone(&stderr_to))))
1027                    .collect();
1028            }
1029
1030            let first_cmd = self.cmds.drain(..1).next().unwrap();
1031            self.cmds.insert(0, first_cmd.stdin(self.stdin));
1032
1033            let last_cmd = self.cmds.drain(self.cmds.len() - 1..).next().unwrap();
1034            self.cmds.push(last_cmd.stdout(self.stdout));
1035
1036            let mut ret = Vec::<Popen>::new();
1037            let cnt = self.cmds.len();
1038
1039            for (idx, mut runner) in self.cmds.into_iter().enumerate() {
1040                if idx != 0 {
1041                    let prev_stdout = ret[idx - 1].stdout.take().unwrap();
1042                    runner = runner.stdin(prev_stdout);
1043                }
1044                if idx != cnt - 1 {
1045                    runner = runner.stdout(Redirection::Pipe);
1046                }
1047                ret.push(runner.popen()?);
1048            }
1049            Ok(ret)
1050        }
1051
1052        /// Starts the pipeline, waits for it to finish, and returns the exit status of the
1053        /// last command.
1054        pub fn join(self) -> PopenResult<ExitStatus> {
1055            self.check_no_stdin_data("join");
1056            let mut v = self.popen()?;
1057            // Waiting on a pipeline waits for all commands, but
1058            // returns the status of the last one.  This is how the
1059            // shells do it.  If the caller needs more precise control
1060            // over which status is returned, they can call popen().
1061            v.last_mut().unwrap().wait()
1062        }
1063
1064        /// Starts the pipeline and returns a value implementing the `Read` trait that reads
1065        /// from the standard output of the last command.
1066        ///
1067        /// This will automatically set up `stdout(Redirection::Pipe)`, so it is not necessary
1068        /// to do that beforehand.
1069        ///
1070        /// When the trait object is dropped, it will wait for the pipeline to finish.  If
1071        /// this is undesirable, use `detached()`.
1072        pub fn stream_stdout(self) -> PopenResult<impl Read> {
1073            self.check_no_stdin_data("stream_stdout");
1074            let v = self.stdout(Redirection::Pipe).popen()?;
1075            Ok(ReadPipelineAdapter(v))
1076        }
1077
1078        /// Starts the pipeline and returns a value implementing the `Write` trait that writes
1079        /// to the standard input of the first command.
1080        ///
1081        /// This will automatically set up `stdin(Redirection::Pipe)`, so it is not necessary
1082        /// to do that beforehand.
1083        ///
1084        /// When the trait object is dropped, it will wait for the process to finish.  If this
1085        /// is undesirable, use `detached()`.
1086        pub fn stream_stdin(self) -> PopenResult<impl Write> {
1087            self.check_no_stdin_data("stream_stdin");
1088            let v = self.stdin(Redirection::Pipe).popen()?;
1089            Ok(WritePipelineAdapter(v))
1090        }
1091
1092        fn setup_communicate(mut self) -> PopenResult<(Communicator, Vec<Popen>)> {
1093            assert!(self.cmds.len() >= 2);
1094
1095            let (err_read, err_write) = crate::popen::make_pipe()?;
1096            self = self.stderr_to(err_write);
1097
1098            let stdin_data = self.stdin_data.take();
1099            let mut v = self.stdout(Redirection::Pipe).popen()?;
1100            let vlen = v.len();
1101
1102            let comm = communicate::communicate(
1103                v[0].stdin.take(),
1104                v[vlen - 1].stdout.take(),
1105                Some(err_read),
1106                stdin_data,
1107            );
1108            Ok((comm, v))
1109        }
1110
1111        /// Starts the pipeline and returns a `Communicator` handle.
1112        ///
1113        /// This is a lower-level API that offers more choice in how communication is
1114        /// performed, such as read size limit and timeout, equivalent to
1115        /// [`Popen::communicate`].
1116        ///
1117        /// Unlike `capture()`, this method doesn't wait for the pipeline to finish,
1118        /// effectively detaching it.
1119        ///
1120        /// [`Popen::communicate`]: struct.Popen.html#method.communicate
1121        pub fn communicate(mut self) -> PopenResult<Communicator> {
1122            self.cmds = self.cmds.into_iter().map(|cmd| cmd.detached()).collect();
1123            let comm = self.setup_communicate()?.0;
1124            Ok(comm)
1125        }
1126
1127        /// Starts the pipeline, collects its output, and waits for all commands to finish.
1128        ///
1129        /// The return value provides the standard output of the last command, the combined
1130        /// standard error of all commands, and the exit status of the last command.  The
1131        /// captured outputs can be accessed as bytes or strings.
1132        ///
1133        /// Unlike `Popen::communicate`, this method actually waits for the processes to
1134        /// finish, rather than simply waiting for the output to close.  If this is
1135        /// undesirable, use `detached()`.
1136        pub fn capture(self) -> PopenResult<CaptureData> {
1137            let (mut comm, mut v) = self.setup_communicate()?;
1138            let (out, err) = comm.read()?;
1139            let out = out.unwrap_or_else(Vec::new);
1140            let err = err.unwrap();
1141
1142            let vlen = v.len();
1143            let status = v[vlen - 1].wait()?;
1144
1145            Ok(CaptureData {
1146                stdout: out,
1147                stderr: err,
1148                exit_status: status,
1149            })
1150        }
1151    }
1152
1153    impl Clone for Pipeline {
1154        /// Returns a copy of the value.
1155        ///
1156        /// This method is guaranteed not to fail as long as none of the `Redirection` values
1157        /// contain a `Redirection::File` variant.  If a redirection to `File` is present,
1158        /// cloning that field will use `File::try_clone` method, which duplicates a file
1159        /// descriptor and can (but is not likely to) fail.  In that scenario, `Pipeline::clone`
1160        /// panics.
1161        fn clone(&self) -> Pipeline {
1162            Pipeline {
1163                cmds: self.cmds.clone(),
1164                stdin: self.stdin.try_clone().unwrap(),
1165                stdout: self.stdout.try_clone().unwrap(),
1166                stderr_file: self.stderr_file.as_ref().map(|f| f.try_clone().unwrap()),
1167                stdin_data: self.stdin_data.clone(),
1168            }
1169        }
1170    }
1171
1172    impl BitOr<Exec> for Pipeline {
1173        type Output = Pipeline;
1174
1175        /// Append a command to the pipeline and return a new pipeline.
1176        ///
1177        /// # Panics
1178        ///
1179        /// Panics if the new command has stdout redirected.
1180        fn bitor(mut self, rhs: Exec) -> Pipeline {
1181            if rhs.stdout_is_set() {
1182                panic!(
1183                    "stdout of the last command is already redirected; \
1184                     use Pipeline::stdout() to redirect pipeline output"
1185                );
1186            }
1187            self.cmds.push(rhs);
1188            self
1189        }
1190    }
1191
1192    impl BitOr for Pipeline {
1193        type Output = Pipeline;
1194
1195        /// Append a pipeline to the pipeline and return a new pipeline.
1196        ///
1197        /// # Panics
1198        ///
1199        /// Panics if the last command of `rhs` has stdout redirected.
1200        fn bitor(mut self, rhs: Pipeline) -> Pipeline {
1201            if rhs.cmds.last().unwrap().stdout_is_set() {
1202                panic!(
1203                    "stdout of the last command is already redirected; \
1204                     use Pipeline::stdout() to redirect pipeline output"
1205                );
1206            }
1207            self.cmds.extend(rhs.cmds);
1208            self.stdout = rhs.stdout;
1209            self
1210        }
1211    }
1212
1213    impl fmt::Debug for Pipeline {
1214        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1215            let mut args = vec![];
1216            for cmd in &self.cmds {
1217                args.push(cmd.to_cmdline_lossy());
1218            }
1219            write!(f, "Pipeline {{ {} }}", args.join(" | "))
1220        }
1221    }
1222
1223    #[derive(Debug)]
1224    struct ReadPipelineAdapter(Vec<Popen>);
1225
1226    impl Read for ReadPipelineAdapter {
1227        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1228            let last = self.0.last_mut().unwrap();
1229            last.stdout.as_mut().unwrap().read(buf)
1230        }
1231    }
1232
1233    #[derive(Debug)]
1234    struct WritePipelineAdapter(Vec<Popen>);
1235
1236    impl WritePipelineAdapter {
1237        fn stdin(&mut self) -> &mut File {
1238            let first = self.0.first_mut().unwrap();
1239            first.stdin.as_mut().unwrap()
1240        }
1241    }
1242
1243    impl Write for WritePipelineAdapter {
1244        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1245            self.stdin().write(buf)
1246        }
1247        fn flush(&mut self) -> io::Result<()> {
1248            self.stdin().flush()
1249        }
1250    }
1251
1252    impl Drop for WritePipelineAdapter {
1253        // the same rationale as Drop for WriteAdapter
1254        fn drop(&mut self) {
1255            let first = &mut self.0[0];
1256            first.stdin.take();
1257        }
1258    }
1259}