openrunner_rs/types.rs
1//! Type definitions for OpenRunner script execution.
2
3use std::collections::HashMap;
4use std::path::PathBuf;
5use std::time::Duration;
6use tempfile::NamedTempFile;
7use tokio::process::Child;
8
9/// Configuration options for script execution.
10///
11/// This struct provides fine-grained control over how OpenScript code is executed,
12/// including environment variables, I/O redirection, timeouts, and more.
13///
14/// # Examples
15///
16/// ```rust
17/// use openrunner_rs::ScriptOptions;
18/// use std::time::Duration;
19///
20/// let options = ScriptOptions::new()
21/// .timeout(Duration::from_secs(30))
22/// .env("DEBUG", "1")
23/// .args(vec!["arg1".to_string(), "arg2".to_string()]);
24/// ```
25#[derive(Debug, Clone)]
26pub struct ScriptOptions {
27 pub(crate) openscript_path: Option<PathBuf>,
28 pub(crate) working_directory: Option<PathBuf>,
29 pub(crate) env_vars: HashMap<String, String>,
30 pub(crate) args: Vec<String>,
31 pub(crate) stdin: IoOptions,
32 pub(crate) stdout: IoOptions,
33 pub(crate) stderr: IoOptions,
34 pub(crate) timeout: Option<Duration>,
35 pub(crate) exit_on_error: bool,
36 pub(crate) print_commands: bool,
37 pub(crate) ai_enabled: bool,
38 pub(crate) clear_env: bool,
39}
40
41impl ScriptOptions {
42 /// Create a new `ScriptOptions` with default values.
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 /// Set the path to the OpenScript interpreter.
48 ///
49 /// If not set, the system will look for `openscript` in the PATH.
50 ///
51 /// # Examples
52 ///
53 /// ```rust
54 /// use openrunner_rs::ScriptOptions;
55 ///
56 /// let options = ScriptOptions::new()
57 /// .openscript_path("/usr/local/bin/openscript");
58 /// ```
59 pub fn openscript_path(mut self, path: impl Into<PathBuf>) -> Self {
60 self.openscript_path = Some(path.into());
61 self
62 }
63
64 /// Set the working directory for script execution.
65 ///
66 /// # Examples
67 ///
68 /// ```rust
69 /// use openrunner_rs::ScriptOptions;
70 ///
71 /// let options = ScriptOptions::new()
72 /// .working_directory("/tmp");
73 /// ```
74 pub fn working_directory(mut self, path: impl Into<PathBuf>) -> Self {
75 self.working_directory = Some(path.into());
76 self
77 }
78
79 /// Add an environment variable for script execution.
80 ///
81 /// # Examples
82 ///
83 /// ```rust
84 /// use openrunner_rs::ScriptOptions;
85 ///
86 /// let options = ScriptOptions::new()
87 /// .env("DEBUG", "1")
88 /// .env("LOG_LEVEL", "info");
89 /// ```
90 pub fn env(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
91 self.env_vars.insert(key.into(), val.into());
92 self
93 }
94
95 /// Set command-line arguments for the script.
96 ///
97 /// # Examples
98 ///
99 /// ```rust
100 /// use openrunner_rs::ScriptOptions;
101 ///
102 /// let options = ScriptOptions::new()
103 /// .args(vec!["--verbose".to_string(), "input.txt".to_string()]);
104 /// ```
105 pub fn args(mut self, args: Vec<String>) -> Self {
106 self.args = args;
107 self
108 }
109
110 /// Configure stdin handling.
111 ///
112 /// # Examples
113 ///
114 /// ```rust
115 /// use openrunner_rs::{types::IoOptions, ScriptOptions};
116 ///
117 /// let options = ScriptOptions::new()
118 /// .stdin(IoOptions::Null);
119 /// ```
120 pub fn stdin(mut self, opt: IoOptions) -> Self {
121 self.stdin = opt;
122 self
123 }
124
125 /// Configure stdout handling.
126 pub fn stdout(mut self, opt: IoOptions) -> Self {
127 self.stdout = opt;
128 self
129 }
130
131 /// Configure stderr handling.
132 pub fn stderr(mut self, opt: IoOptions) -> Self {
133 self.stderr = opt;
134 self
135 }
136
137 /// Set a timeout for script execution.
138 ///
139 /// If the script runs longer than the specified duration, it will be terminated.
140 ///
141 /// # Examples
142 ///
143 /// ```rust
144 /// use openrunner_rs::ScriptOptions;
145 /// use std::time::Duration;
146 ///
147 /// let options = ScriptOptions::new()
148 /// .timeout(Duration::from_secs(60));
149 /// ```
150 pub fn timeout(mut self, duration: Duration) -> Self {
151 self.timeout = Some(duration);
152 self
153 }
154
155 /// Configure whether to exit on script errors.
156 pub fn exit_on_error(mut self, exit: bool) -> Self {
157 self.exit_on_error = exit;
158 self
159 }
160
161 /// Configure whether to print commands before execution.
162 pub fn print_commands(mut self, print: bool) -> Self {
163 self.print_commands = print;
164 self
165 }
166
167 /// Configure whether AI features are enabled.
168 pub fn ai_enabled(mut self, enabled: bool) -> Self {
169 self.ai_enabled = enabled;
170 self
171 }
172
173 /// Configure whether to clear the environment before execution.
174 ///
175 /// If true, only explicitly set environment variables will be available.
176 pub fn clear_env(mut self, clear: bool) -> Self {
177 self.clear_env = clear;
178 self
179 }
180}
181
182impl Default for ScriptOptions {
183 fn default() -> Self {
184 Self {
185 openscript_path: None,
186 working_directory: None,
187 env_vars: HashMap::new(),
188 args: Vec::new(),
189 stdin: IoOptions::Inherit,
190 stdout: IoOptions::Pipe,
191 stderr: IoOptions::Pipe,
192 timeout: None,
193 exit_on_error: true,
194 print_commands: false,
195 ai_enabled: false,
196 clear_env: false,
197 }
198 }
199}
200
201/// Result of script execution.
202///
203/// Contains all information about the completed script execution, including
204/// exit code, captured output, execution duration, and timeout status.
205///
206/// # Examples
207///
208/// ```rust
209/// use openrunner_rs::{run, ScriptOptions};
210///
211/// # #[tokio::main]
212/// # async fn main() -> openrunner_rs::Result<()> {
213/// let options = ScriptOptions::new().openscript_path("/bin/sh");
214/// let result = run("echo 'test'", options).await?;
215///
216/// println!("Exit code: {}", result.exit_code);
217/// println!("Output: {}", result.stdout);
218/// println!("Duration: {:?}", result.duration);
219///
220/// if result.timed_out {
221/// println!("Script was terminated due to timeout");
222/// }
223/// # Ok(())
224/// # }
225/// ```
226#[derive(Debug, Clone, Default)]
227pub struct ExecResult {
228 /// The exit code of the script process.
229 pub exit_code: i32,
230 /// Captured stdout from the script execution.
231 pub stdout: String,
232 /// Captured stderr from the script execution.
233 pub stderr: String,
234 /// Total duration of script execution.
235 pub duration: Duration,
236 /// Whether the script was terminated due to timeout.
237 pub timed_out: bool,
238}
239
240/// I/O redirection options for script execution.
241///
242/// Controls how stdin, stdout, and stderr are handled during script execution.
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
244pub enum IoOptions {
245 /// Inherit from the parent process.
246 ///
247 /// The script will use the same stdin/stdout/stderr as the calling process.
248 Inherit,
249 /// Pipe to the parent process.
250 ///
251 /// The script's I/O will be captured and made available in the `ExecResult`.
252 #[default]
253 Pipe,
254 /// Discard the output.
255 ///
256 /// The script's I/O will be redirected to /dev/null (or equivalent).
257 Null,
258}
259
260/// Result of a spawn operation.
261///
262/// This struct holds the `Child` process handle and ensures that any temporary
263/// files created for the script live as long as the handle.
264#[derive(Debug)]
265pub struct SpawnResult {
266 pub child: Child,
267 pub(crate) _temp_file: Option<NamedTempFile>,
268}