hooked/hooked-cli/source/main.rs

96 lines
2.3 KiB
Rust

//! # Hooked
//!
//! > **Git hooks manager.**
#![forbid(unsafe_code)]
#![warn(missing_docs, clippy::missing_docs_in_private_items)]
use std::{
fs::{read_to_string, remove_file, set_permissions, write, Permissions},
os::unix::fs::PermissionsExt,
path::PathBuf,
};
use {
clap::Parser,
color_eyre::{eyre::eyre, install, Result},
hooked_library::Config,
tera::{Context, Tera},
};
use crate::cli::{Args, MainSubcommands};
/// The default template for all hooks.
pub const DEFAULT_TEMPLATE: &str = include_str!("templates/default.sh");
/// All supported hook types.
pub const HOOK_TYPES: [&str; 1] = ["pre-commit"];
mod cli;
fn main() -> Result<()> {
install()?;
let args = Args::parse();
let config = Config::from_toml_file(args.config)?;
let git_hooks_dir = PathBuf::from(".git/hooks/");
match args.command {
MainSubcommands::Install { overwrite } => {
if !git_hooks_dir.exists() {
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
}
for hook_type in HOOK_TYPES {
let mut context = Context::new();
context.insert("hook_type", hook_type);
let hook_path = git_hooks_dir.join(hook_type);
if hook_path.exists() && !overwrite {
println!(
"{:?} exists, use --overwrite to replace the existing file",
hook_path
);
continue;
}
write(
&hook_path,
Tera::one_off(DEFAULT_TEMPLATE, &context, false)?,
)?;
set_permissions(hook_path, Permissions::from_mode(0o775))?;
}
}
MainSubcommands::Uninstall { all } => {
if !git_hooks_dir.exists() {
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
}
for hook_type in HOOK_TYPES {
let hook_path = git_hooks_dir.join(hook_type);
if !hook_path.exists() {
continue;
}
let hook_contents = read_to_string(&hook_path)?;
if all || hook_contents.contains("# Installed by Hooked.") {
remove_file(hook_path)?;
} else {
println!(
"{:?} wasn't installed by Hooked, use --all to remove it",
hook_path
);
}
}
}
MainSubcommands::Run { hook_type } => {
cli::hooked_run(config, hook_type)?;
}
}
Ok(())
}