use std::env;
use std::process::Command;
use std::thread;
use std::time::Instant;
use log::debug;
use miette::{IntoDiagnostic, Result};
use workon::{WorkonConfig, WorktreeDescriptor};
use crate::output;
pub fn execute_post_create_hooks(
worktree: &WorktreeDescriptor,
base_branch: Option<&str>,
config: &WorkonConfig,
) -> Result<()> {
let hooks = config.post_create_hooks()?;
if hooks.is_empty() {
debug!("No post-create hooks configured");
return Ok(());
}
debug!("Found {} post-create hook(s)", hooks.len());
for (i, hook_cmd) in hooks.iter().enumerate() {
let pb = output::create_spinner();
pb.set_message(format!("Hook {}/{}: {}", i + 1, hooks.len(), hook_cmd));
debug!("Setting WORKON_WORKTREE_PATH={}", worktree.path().display());
env::set_var("WORKON_WORKTREE_PATH", worktree.path());
if let Ok(Some(branch)) = worktree.branch() {
debug!("Setting WORKON_BRANCH_NAME={}", branch);
env::set_var("WORKON_BRANCH_NAME", branch);
}
if let Some(base) = base_branch {
debug!("Setting WORKON_BASE_BRANCH={}", base);
env::set_var("WORKON_BASE_BRANCH", base);
}
debug!(
"Executing in working directory: {}",
worktree.path().display()
);
let mut child = if cfg!(target_os = "windows") {
Command::new("cmd")
.args(["/C", hook_cmd])
.current_dir(worktree.path())
.spawn()
} else {
Command::new("sh")
.args(["-c", hook_cmd])
.current_dir(worktree.path())
.spawn()
}
.into_diagnostic()?;
let timeout = config.hook_timeout()?;
if timeout.is_zero() {
let status = child.wait().into_diagnostic()?;
if !status.success() {
pb.finish_and_clear();
return Err(miette::miette!(
"Hook failed with exit code: {:?}",
status.code()
));
}
} else {
let start = Instant::now();
loop {
match child.try_wait().into_diagnostic()? {
Some(status) if status.success() => break,
Some(status) => {
pb.finish_and_clear();
return Err(miette::miette!(
"Hook failed with exit code: {:?}",
status.code()
));
}
None if start.elapsed() >= timeout => {
let _ = child.kill();
let _ = child.wait();
pb.finish_and_clear();
return Err(miette::miette!(
"Hook timed out after {}s: {}",
timeout.as_secs(),
hook_cmd
));
}
None => thread::sleep(std::time::Duration::from_millis(100)),
}
}
}
pb.finish_and_clear();
output::success("✓ Hook completed successfully");
}
Ok(())
}