Skip to main content

bare_script/proc/
builder.rs

1//! Asynchronous command execution module.
2//!
3//! This module provides a type-safe interface for executing shell commands
4//! using Tokio's `tokio::process::Command`.
5
6use std::ffi::OsStr;
7use std::process::Stdio;
8
9use tokio::process::Command;
10
11use crate::error::{ScriptError, ScriptResult};
12use crate::output::Output;
13
14/// Command builder for asynchronous execution.
15#[derive(Debug)]
16pub struct CommandBuilder {
17    cmd: Command,
18}
19
20impl CommandBuilder {
21    /// Creates a new command builder for the specified program.
22    pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
23        Self {
24            cmd: Command::new(program),
25        }
26    }
27
28    /// Adds a single argument to the command.
29    pub fn arg<S: AsRef<OsStr>>(mut self, arg: S) -> Self {
30        let _ = self.cmd.arg(arg);
31        self
32    }
33
34    /// Adds multiple arguments to the command.
35    pub fn args<I, S>(mut self, args: I) -> Self
36    where
37        I: IntoIterator<Item = S>,
38        S: AsRef<OsStr>,
39    {
40        let _ = self.cmd.args(args);
41        self
42    }
43
44    /// Sets an environment variable for the command.
45    pub fn env<K, V>(mut self, key: K, value: V) -> Self
46    where
47        K: AsRef<OsStr>,
48        V: AsRef<OsStr>,
49    {
50        let _ = self.cmd.env(key, value);
51        self
52    }
53
54    /// Sets multiple environment variables for the command.
55    pub fn envs<I, K, V>(mut self, vars: I) -> Self
56    where
57        I: IntoIterator<Item = (K, V)>,
58        K: AsRef<OsStr>,
59        V: AsRef<OsStr>,
60    {
61        let _ = self.cmd.envs(vars);
62        self
63    }
64
65    /// Clears all environment variables inherited from the parent process.
66    pub fn env_clear(mut self) -> Self {
67        let _ = self.cmd.env_clear();
68        self
69    }
70
71    /// Removes an environment variable from the command's environment.
72    pub fn env_remove<K>(mut self, key: K) -> Self
73    where
74        K: AsRef<OsStr>,
75    {
76        let _ = self.cmd.env_remove(key);
77        self
78    }
79
80    /// Sets the working directory for the command.
81    pub fn current_dir<D>(mut self, dir: D) -> Self
82    where
83        D: AsRef<std::path::Path>,
84    {
85        let _ = self.cmd.current_dir(dir);
86        self
87    }
88
89    /// Configures the stdin handle for the command.
90    pub fn stdin<T: Into<Stdio>>(mut self, stdin: T) -> Self {
91        let _ = self.cmd.stdin(stdin);
92        self
93    }
94
95    /// Configures the stdout handle for the command.
96    pub fn stdout<T: Into<Stdio>>(mut self, stdout: T) -> Self {
97        let _ = self.cmd.stdout(stdout);
98        self
99    }
100
101    /// Configures the stderr handle for the command.
102    pub fn stderr<T: Into<Stdio>>(mut self, stderr: T) -> Self {
103        let _ = self.cmd.stderr(stderr);
104        self
105    }
106
107    /// Configures the command to capture both stdout and stderr.
108    pub fn capture_output(mut self) -> Self {
109        let _ = self.cmd.stdout(Stdio::piped());
110        let _ = self.cmd.stderr(Stdio::piped());
111        self
112    }
113
114    /// Configures the command to inherit stdin from the parent process.
115    pub fn inherit_stdin(mut self) -> Self {
116        let _ = self.cmd.stdin(Stdio::inherit());
117        self
118    }
119
120    /// Configures the command to inherit stdout from the parent process.
121    pub fn inherit_stdout(mut self) -> Self {
122        let _ = self.cmd.stdout(Stdio::inherit());
123        self
124    }
125
126    /// Configures the command to inherit stderr from the parent process.
127    pub fn inherit_stderr(mut self) -> Self {
128        let _ = self.cmd.stderr(Stdio::inherit());
129        self
130    }
131
132    /// Configures the command to read from null stdin.
133    pub fn null_stdin(mut self) -> Self {
134        let _ = self.cmd.stdin(Stdio::null());
135        self
136    }
137
138    /// Configures the command to write to null stdout.
139    pub fn null_stdout(mut self) -> Self {
140        let _ = self.cmd.stdout(Stdio::null());
141        self
142    }
143
144    /// Configures the command to write to null stderr.
145    pub fn null_stderr(mut self) -> Self {
146        let _ = self.cmd.stderr(Stdio::null());
147        self
148    }
149
150    /// Sets whether to kill the child process when the handle is dropped.
151    pub fn kill_on_drop(mut self, kill: bool) -> Self {
152        let _ = self.cmd.kill_on_drop(kill);
153        self
154    }
155
156    /// Spawns the command as a child process.
157    pub async fn spawn(&mut self) -> std::io::Result<tokio::process::Child> {
158        self.cmd.spawn()
159    }
160
161    /// Executes the command and captures its output.
162    pub async fn output(&mut self) -> std::io::Result<Output> {
163        let output = self.cmd.output().await?;
164        Ok(Output::new(output.stdout, output.stderr, output.status))
165    }
166
167    /// Executes the command and captures its output, returning a ScriptResult.
168    pub async fn execute(&mut self) -> ScriptResult<Output> {
169        self.output().await.map_err(ScriptError::IoError)
170    }
171
172    /// Executes the command with a timeout.
173    pub async fn execute_with_timeout(
174        mut self,
175        timeout: std::time::Duration,
176    ) -> ScriptResult<Output> {
177        use tokio::time;
178
179        match time::timeout(timeout, self.cmd.output()).await {
180            Ok(Ok(output)) => Ok(Output::new(output.stdout, output.stderr, output.status)),
181            Ok(Err(e)) => Err(ScriptError::IoError(e)),
182            Err(_) => Err(ScriptError::Timeout(timeout)),
183        }
184    }
185
186    /// Waits for the command to complete and returns its exit status.
187    pub async fn status(&mut self) -> std::io::Result<std::process::ExitStatus> {
188        self.cmd.status().await
189    }
190}