Skip to main content

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}