use std::path::Path;
use std::process::Command;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CommandResult {
pub exit_code: i32,
pub stdout: String,
pub stderr: String,
}
impl CommandResult {
#[allow(dead_code)]
pub fn success(&self) -> bool {
self.exit_code == 0
}
}
#[allow(dead_code)]
pub fn execute_command(
program: &str,
args: &[&str],
working_dir: Option<&Path>,
) -> std::io::Result<CommandResult> {
let mut cmd = Command::new(program);
cmd.args(args);
if let Some(dir) = working_dir {
cmd.current_dir(dir);
}
let output = cmd.output()?;
Ok(CommandResult {
exit_code: output.status.code().unwrap_or(-1),
stdout: String::from_utf8_lossy(&output.stdout).trim().to_string(),
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
})
}
#[allow(dead_code)]
pub fn execute_command_checked(
program: &str,
args: &[&str],
working_dir: Option<&Path>,
) -> Result<String, String> {
let result = execute_command(program, args, working_dir)
.map_err(|e| format!("Failed to execute '{}': {}", program, e))?;
if result.success() {
Ok(result.stdout)
} else {
Err(format!(
"'{}' failed with exit code {}: {}",
program, result.exit_code, result.stderr
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_execute_command_success() {
let result = execute_command("echo", &["hello"], None).unwrap();
assert!(result.success());
assert_eq!(result.stdout, "hello");
assert_eq!(result.exit_code, 0);
}
#[test]
fn test_execute_command_failure() {
let result = execute_command("false", &[], None).unwrap();
assert!(!result.success());
assert_eq!(result.exit_code, 1);
}
#[test]
fn test_execute_command_checked_success() {
let stdout = execute_command_checked("echo", &["test"], None).unwrap();
assert_eq!(stdout, "test");
}
#[test]
fn test_execute_command_checked_failure() {
let result = execute_command_checked("false", &[], None);
assert!(result.is_err());
}
#[test]
fn test_execute_command_not_found() {
let result = execute_command("nonexistent_command_xyz", &[], None);
assert!(result.is_err());
}
}