mk_rs_core/shell.rs
1use std::collections::HashMap;
2use std::path::Path;
3
4/// Result of executing a recipe through a shell.
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct ShellResult {
7 /// Exit code. 0 = success.
8 pub exit_code: i32,
9 /// Captured stdout.
10 pub stdout: String,
11 /// Captured stderr.
12 pub stderr: String,
13}
14
15pub use crate::error::ShellError;
16
17/// Abstraction for executing recipe scripts.
18/// Implementations: sh (POSIX /bin/sh), rc (Plan 9 rc), duckscript (future).
19pub trait Shell: Send + Sync {
20 /// Human-readable shell name (e.g. "sh", "rc").
21 fn name(&self) -> &str;
22
23 /// Execute a recipe script.
24 /// `recipe` — the full script text (multiline string).
25 /// `env` — environment variables to pass to the shell process.
26 /// `dir` — working directory for the recipe.
27 fn execute(
28 &self,
29 recipe: &str,
30 env: &HashMap<String, String>,
31 dir: &Path,
32 ) -> Result<ShellResult, ShellError>;
33
34 /// Find unescaped instances of a character in a string.
35 /// Used by the parser to detect assignment attributes.
36 /// E.g. find unescaped '=' to separate attr from value.
37 fn find_unescaped(&self, input: &str, ch: char) -> Vec<usize>;
38
39 /// Shell-quote a string so it's safe as a shell argument.
40 fn quote(&self, token: &str) -> String;
41}
42
43#[cfg(test)]
44mod tests {
45 // Shell trait tests are in mk-shell's ShShell tests.
46}