use crate::commands::{Command, CommandResult, CommandError};
use crate::app::AppState;
use crate::services::GitService;
use std::process::Command as StdCommand;
use tracing::instrument;
pub struct CustomCommand {
pub name: String,
pub command: String,
}
impl Command for CustomCommand {
#[instrument(skip(self, _git, state), fields(name = %self.name, command = %self.command))]
fn execute(
&self,
_git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let output = if cfg!(target_os = "windows") {
StdCommand::new("cmd")
.args(["/C", &self.command])
.current_dir(&state.repo_path)
.output()
} else {
StdCommand::new("sh")
.args(["-c", &self.command])
.current_dir(&state.repo_path)
.output()
};
let new_state = match output {
Ok(output) => {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
if output.status.success() {
let message = if !stdout.trim().is_empty() {
format!("{}: {}", self.name, stdout.trim())
} else {
format!("{} completed", self.name)
};
crate::app::reducer(state.clone(), crate::app::Action::SetFeedback(Some(message)))
} else {
let error_msg = if !stderr.trim().is_empty() {
format!("{} failed: {}", self.name, stderr.trim())
} else {
format!("{} failed (exit code: {})", self.name, output.status.code().unwrap_or(-1))
};
crate::app::reducer(state.clone(), crate::app::Action::SetStatusError(Some(error_msg)))
}
}
Err(e) => {
crate::app::reducer(state.clone(), crate::app::Action::SetStatusError(Some(
format!("Failed to execute '{}': {}", self.name, e)
)))
}
};
Ok(CommandResult::StateUpdate(new_state))
}
}