Skip to main content

solti_model/domain/kind/
runtime.rs

1//! # Script runtime resolution.
2//!
3//! [`Runtime`] maps script languages to interpreter paths for subprocess `Script` mode.
4
5use serde::{Deserialize, Serialize};
6
7/// Script interpreter for subprocess script execution.
8///
9/// [`Custom`](Runtime::Custom) allows arbitrary interpreter configuration.
10#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub enum Runtime {
13    /// Bash shell: resolves to `("bash", "-c")`.
14    Bash,
15    /// Python 3 interpreter: resolves to `("python3", "-c")`.
16    Python,
17    /// Node.js runtime: resolves to `("node", "-e")`.
18    Node,
19    /// Custom interpreter with explicit command and flag.
20    Custom {
21        /// Interpreter binary (e.g. `"ruby"`, `"/usr/bin/perl"`).
22        command: String,
23        /// Flag that precedes the script body (e.g. `"-e"`).
24        flag: String,
25    },
26}
27
28impl Runtime {
29    /// Resolve runtime to `(command, flag)` pair used to build the OS command.
30    ///
31    /// ```rust
32    /// use solti_model::Runtime;
33    /// let (cmd, flag) = Runtime::Bash.resolve();
34    /// assert_eq!(cmd, "bash");
35    /// assert_eq!(flag, "-c");
36    /// ```
37    #[inline]
38    pub fn resolve(&self) -> (&str, &str) {
39        match self {
40            Runtime::Bash => ("bash", "-c"),
41            Runtime::Node => ("node", "-e"),
42            Runtime::Python => ("python3", "-c"),
43
44            Runtime::Custom { command, flag } => (command.as_str(), flag.as_str()),
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn resolve_bash() {
55        let (cmd, flag) = Runtime::Bash.resolve();
56        assert_eq!(cmd, "bash");
57        assert_eq!(flag, "-c");
58    }
59
60    #[test]
61    fn resolve_python() {
62        let (cmd, flag) = Runtime::Python.resolve();
63        assert_eq!(cmd, "python3");
64        assert_eq!(flag, "-c");
65    }
66
67    #[test]
68    fn resolve_node() {
69        let (cmd, flag) = Runtime::Node.resolve();
70        assert_eq!(cmd, "node");
71        assert_eq!(flag, "-e");
72    }
73
74    #[test]
75    fn resolve_custom() {
76        let rt = Runtime::Custom {
77            command: "ruby".into(),
78            flag: "-e".into(),
79        };
80        let (cmd, flag) = rt.resolve();
81        assert_eq!(cmd, "ruby");
82        assert_eq!(flag, "-e");
83    }
84
85    #[test]
86    fn serde_roundtrip_bash() {
87        let rt = Runtime::Bash;
88        let json = serde_json::to_string(&rt).unwrap();
89        assert_eq!(json, r#""bash""#);
90        let back: Runtime = serde_json::from_str(&json).unwrap();
91        assert_eq!(back, rt);
92    }
93
94    #[test]
95    fn serde_roundtrip_custom() {
96        let rt = Runtime::Custom {
97            command: "perl".into(),
98            flag: "-e".into(),
99        };
100        let json = serde_json::to_string(&rt).unwrap();
101        let back: Runtime = serde_json::from_str(&json).unwrap();
102        assert_eq!(back, rt);
103    }
104}