use crate::core::engine::TaskResult;
use crate::core::{error::JormError, task::TaskType};
use std::process::Stdio;
use tokio::process::Command;
use tokio::time::{timeout, Duration};
pub struct RustExecutor;
impl Default for RustExecutor {
fn default() -> Self {
Self::new()
}
}
impl RustExecutor {
pub fn new() -> Self {
Self
}
pub async fn execute(
&self,
task_name: &str,
task_type: &TaskType,
) -> Result<TaskResult, JormError> {
match task_type {
TaskType::Rust {
command,
working_dir,
} => {
self.execute_cargo_command(task_name, command, working_dir.as_deref())
.await
}
_ => Err(JormError::ExecutionError(format!(
"Rust executor cannot handle task type: {:?}",
task_type
))),
}
}
async fn execute_cargo_command(
&self,
task_name: &str,
command: &str,
working_dir: Option<&str>,
) -> Result<TaskResult, JormError> {
let parts: Vec<&str> = command.split_whitespace().collect();
if parts.is_empty() {
return Err(JormError::ExecutionError("Empty cargo command".to_string()));
}
let (program, args) = if parts[0] == "cargo" {
("cargo", &parts[1..])
} else {
("cargo", &parts[..])
};
let mut cmd = Command::new(program);
cmd.args(args).stdout(Stdio::piped()).stderr(Stdio::piped());
if let Some(dir) = working_dir {
cmd.current_dir(dir);
}
let timeout_duration = Duration::from_secs(300);
match timeout(timeout_duration, cmd.output()).await {
Ok(Ok(output)) => {
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let success = output.status.success();
let combined_output = if !stdout.is_empty() && !stderr.is_empty() {
format!("{}\n{}", stdout, stderr)
} else if !stdout.is_empty() {
stdout
} else {
stderr.clone()
};
let error = if !success {
Some(format!("Cargo command failed: {}", stderr))
} else {
None
};
Ok(TaskResult {
task_name: task_name.to_string(),
success,
output: combined_output,
error,
})
}
Ok(Err(e)) => Err(JormError::ExecutionError(format!(
"Failed to execute cargo command '{}': {}",
command, e
))),
Err(_) => Err(JormError::ExecutionError(format!(
"Cargo command '{}' timed out after {} seconds",
command,
timeout_duration.as_secs()
))),
}
}
}