use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;
#[cfg(test)]
use crate::command_runner::TestCommandRunner;
use crate::command_runner::{Command, CommandRunner};
use crate::errors::*;
#[cfg(test)]
use crate::project::Project;
use crate::util::ToStrOrErr;
#[derive(Debug)]
pub struct HookManager {
hooks_dir: PathBuf,
root_dir: PathBuf,
}
impl HookManager {
pub fn new<P>(root_dir: P) -> Result<HookManager>
where
P: Into<PathBuf>,
{
let root_dir: PathBuf = root_dir.into();
Ok(HookManager {
hooks_dir: root_dir.join("config").join("hooks"),
root_dir,
})
}
pub fn invoke<CR>(
&self,
runner: &CR,
hook_name: &str,
env: &BTreeMap<String, String>,
) -> Result<()>
where
CR: CommandRunner,
{
let d_dir = self.hooks_dir.join(format!("{}.d", hook_name));
if !d_dir.exists() {
debug!(
"No hooks for '{}' because {} does not exist",
hook_name,
&d_dir.display()
);
return Ok(());
}
let mkerr = || ErrorKind::CouldNotReadDirectory(d_dir.clone());
let mut scripts = vec![];
for entry in fs::read_dir(&d_dir).chain_err(&mkerr)? {
let entry = entry.chain_err(&mkerr)?;
let path = entry.path();
trace!("Checking {} to see if it's a hook", path.display());
let ty = entry
.file_type()
.chain_err(|| ErrorKind::CouldNotReadFile(path.clone()))?;
let os_name = entry.file_name();
let name = os_name.to_str_or_err()?;
if ty.is_file() && !name.starts_with('.') && name.ends_with(".hook") {
trace!("Found hook {}", path.display());
scripts.push(path)
}
}
scripts.sort();
for script in scripts {
let mut cmd = runner.build(&script);
cmd.current_dir(&self.root_dir);
for (name, val) in env {
cmd.env(name, val);
}
cmd.exec()?;
}
Ok(())
}
}
#[test]
fn runs_requested_hook_scripts() {
let _ = env_logger::try_init();
let proj = Project::from_example("hello").unwrap();
let runner = TestCommandRunner::new();
proj.output("pull").unwrap();
proj.hooks()
.invoke(&runner, "pull", &BTreeMap::default())
.unwrap();
assert_ran!(runner, {
[proj
.root_dir()
.join("config")
.join("hooks")
.join("pull.d")
.join("hello.hook")]
});
proj.remove_test_output().unwrap();
}