use colored::Colorize;
use std::path::Path;
use std::process::{Command, Stdio};
use crate::config::GitWorktreeConfig;
use crate::error::{Error, Result};
pub fn execute_hooks(hook_type: &str, working_directory: &Path, variables: &[(&str, &str)]) -> Result<()> {
let config = match GitWorktreeConfig::find_config()? {
Some((_, config)) => config,
None => {
return Ok(());
}
};
let hooks = match &config.hooks {
Some(hooks) => hooks,
None => return Ok(()),
};
let hook_commands = match hook_type {
"postAdd" => &hooks.post_add,
"preRemove" => &hooks.pre_remove,
"postRemove" => &hooks.post_remove,
_ => return Ok(()),
};
let hook_commands = match hook_commands {
Some(commands) => commands,
None => return Ok(()),
};
if hook_commands.is_empty() {
return Ok(());
}
println!("{}", format!("🪝 Running {} hooks...", hook_type).cyan());
for hook in hook_commands {
let mut command = hook.clone();
for (var_name, var_value) in variables {
let placeholder = format!("${{{}}}", var_name);
command = command.replace(&placeholder, var_value);
}
println!(" {}", format!("Executing: {}", command).blue());
match execute_command_streaming(&command, working_directory) {
Ok(()) => {
println!(" {}", "✓ Hook completed successfully".green());
}
Err(e) => {
println!(" {}", format!("⚠️ Hook failed: {}", e).yellow());
}
}
}
Ok(())
}
fn execute_command_streaming(command: &str, working_directory: &Path) -> Result<()> {
let mut cmd = Command::new("sh");
cmd.arg("-c")
.arg(command)
.current_dir(working_directory)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.env("FORCE_COLOR", "1");
let status = cmd
.status()
.map_err(|e| Error::hook(format!("Failed to execute hook command: {}", e)))?;
if !status.success() {
return Err(Error::hook(format!(
"Command failed with exit code: {:?}",
status.code()
)));
}
Ok(())
}