use crate::config::{CustomCommand, DevConfig, Hook, RunnerConfig};
use crate::env::{fatal, log};
use std::path::Path;
use std::process::{self, Command};
pub fn run_hooks(root: &Path, hooks: &[Hook]) {
for hook in hooks {
if let Some(condition) = &hook.condition {
if let Some(missing) = &condition.missing {
if root.join(missing).exists() {
continue;
}
}
}
let dir = match &hook.cwd {
Some(cwd) => root.join(cwd),
None => root.to_path_buf(),
};
log(&format!("Running hook: {}", hook.cmd));
run_shell(&dir, &hook.cmd);
}
}
pub fn launch_runner(root: &Path, config: &DevConfig) -> Option<process::ExitStatus> {
match &config.runner {
Some(RunnerConfig::Mprocs) => Some(launch_mprocs(root, config)),
Some(RunnerConfig::Shell { cmd }) => Some(launch_shell(root, cmd)),
Some(RunnerConfig::None) => {
block_until_ctrlc();
None
}
None => Some(launch_mprocs(root, config)),
}
}
pub fn launch_mprocs(root: &Path, config: &DevConfig) -> process::ExitStatus {
log("Launching mprocs...");
let config_path = root.join(&config.mprocs_config);
match Command::new("mprocs")
.arg("--config")
.arg(&config_path)
.current_dir(root)
.status()
{
Ok(status) => status,
Err(e) => fatal(&format!("Failed to run mprocs: {e}")),
}
}
pub fn run_custom(root: &Path, command: &CustomCommand) {
if command.cmd.is_empty() {
fatal(&format!("Command '{}' has an empty cmd", command.name));
}
log(&format!("Running: {}", command.name));
let status = Command::new(&command.cmd[0])
.args(&command.cmd[1..])
.current_dir(root)
.status();
match status {
Ok(s) if s.success() => {}
Ok(s) => process::exit(s.code().unwrap_or(1)),
Err(e) => fatal(&format!("Failed to run {}: {e}", command.name)),
}
}
fn launch_shell(root: &Path, cmd: &str) -> process::ExitStatus {
log(&format!("Launching: {cmd}"));
match Command::new("sh")
.args(["-c", cmd])
.current_dir(root)
.status()
{
Ok(status) => status,
Err(e) => fatal(&format!("Failed to run shell command: {e}")),
}
}
fn block_until_ctrlc() {
log("Running. Press Ctrl+C to stop.");
let (tx, rx) = std::sync::mpsc::channel();
ctrlc::set_handler(move || {
let _ = tx.send(());
})
.expect("failed to set Ctrl+C handler");
let _ = rx.recv();
}
fn run_shell(dir: &Path, cmd: &str) {
let status = Command::new("sh")
.args(["-c", cmd])
.current_dir(dir)
.status();
match status {
Ok(s) if s.success() => {}
Ok(s) => fatal(&format!("Hook `{cmd}` exited with {s}")),
Err(e) => fatal(&format!("Failed to run hook `{cmd}`: {e}")),
}
}