Skip to main content

command_stream/
process_argv.rs

1//! Exact-argv construction for [`ProcessRunner`] (issue #230).
2
3use std::ffi::OsString;
4
5use crate::stream_process::StreamingCommand;
6use crate::{ProcessRunner, RunOptions};
7
8impl ProcessRunner {
9    /// Create a runner that executes `program` with exactly `args`, without a
10    /// shell.
11    ///
12    /// Nothing is parsed, expanded or quoted, and built-in virtual commands
13    /// are never used, so `from_argv("echo", ["$HOME"])` prints `$HOME`. Every
14    /// other option behaves as with [`ProcessRunner::new`], including
15    /// [`StdinOption::Pipe`](crate::StdinOption::Pipe) with
16    /// [`write_stdin`](Self::write_stdin) and [`close_stdin`](Self::close_stdin).
17    /// [`command`](Self::command) reports the argv as a shell-quoted string.
18    ///
19    /// ```
20    /// use command_stream::{ProcessRunner, RunOptions, StdinOption};
21    ///
22    /// # #[tokio::main]
23    /// # async fn main() -> command_stream::Result<()> {
24    /// let mut runner = ProcessRunner::from_argv(
25    ///     "cat",
26    ///     Vec::<String>::new(),
27    ///     RunOptions { stdin: StdinOption::Pipe, mirror: false, ..Default::default() },
28    /// );
29    /// runner.start().await?;
30    /// runner.write_stdin(b"{\"type\":\"user\"}\n").await?;
31    /// runner.close_stdin().await?;
32    /// let result = runner.run().await?;
33    /// assert_eq!(result.stdout, "{\"type\":\"user\"}\n");
34    /// # Ok(())
35    /// # }
36    /// ```
37    pub fn from_argv<P, I, S>(program: P, args: I, options: RunOptions) -> Self
38    where
39        P: Into<OsString>,
40        I: IntoIterator<Item = S>,
41        S: Into<OsString>,
42    {
43        let program = program.into();
44        let args: Vec<OsString> = args.into_iter().map(Into::into).collect();
45        let display = std::iter::once(&program)
46            .chain(&args)
47            .map(|part| crate::quote::quote(&part.to_string_lossy()))
48            .collect::<Vec<_>>()
49            .join(" ");
50        let mut runner = Self::new(display, options);
51        runner.argv = Some(StreamingCommand::Argv { program, args });
52        runner
53    }
54}