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