1use std::fs;
2use std::io::Write;
3use std::process::Command;
4use tempfile::NamedTempFile;
5
6use crate::error::{EchoCommentError, Result};
7
8pub struct ScriptRunner {
10 }
12
13impl ScriptRunner {
14 pub fn new() -> Self {
15 Self {}
16 }
17
18 pub fn run_script(&self, script_content: &str, script_args: &[String]) -> Result<()> {
20 let mut temp_file =
22 NamedTempFile::new().map_err(|e| EchoCommentError::TempFileCreation { source: e })?;
23
24 temp_file
26 .write_all(script_content.as_bytes())
27 .map_err(|e| EchoCommentError::FileWrite { source: e })?;
28
29 temp_file
31 .flush()
32 .map_err(|e| EchoCommentError::FileWrite { source: e })?;
33
34 let temp_path = temp_file.into_temp_path();
36
37 #[cfg(unix)]
39 self.make_executable(&temp_path)?;
40
41 let status = Command::new(&temp_path)
43 .args(script_args)
44 .status()
45 .map_err(|e| EchoCommentError::ScriptExecution {
46 message: "Failed to execute processed script".to_string(),
47 source: e,
48 })?;
49
50 temp_path.close().map_err(|e| EchoCommentError::FileWrite {
52 source: std::io::Error::other(e),
53 })?;
54
55 std::process::exit(status.code().unwrap_or(1));
57 }
58
59 #[cfg(unix)]
60 fn make_executable(&self, path: &std::path::Path) -> Result<()> {
61 use std::os::unix::fs::PermissionsExt;
62
63 let mut perms = fs::metadata(path)
64 .map_err(|e| EchoCommentError::PermissionSet { source: e })?
65 .permissions();
66
67 perms.set_mode(0o755);
68
69 fs::set_permissions(path, perms)
70 .map_err(|e| EchoCommentError::PermissionSet { source: e })?;
71
72 Ok(())
73 }
74}
75
76impl Default for ScriptRunner {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_script_runner_creation() {
88 let _runner = ScriptRunner::new();
89 }
90}