Compare commits

..

No commits in common. "a4d0431a32fc9e6f0d41e164bea6e34b66cbe9cd" and "aed22fad90b488e587d2f583c63f59de2c30313c" have entirely different histories.

10 changed files with 74 additions and 145 deletions

View File

@ -20,7 +20,3 @@ Below is the default script template that Hooked uses, where `hook_type` is the
```sh ```sh
{{#include ../../../hooked-cli/source/templates/default.sh}} {{#include ../../../hooked-cli/source/templates/default.sh}}
``` ```
You can provide your own template by using the `general.template` configuration setting. If you do, make sure you include a line somewhere that says `# Installed by Hooked.` for the [uninstall CLI command][cli-uninstall].
[cli-uninstall]: ./uninstall.md

View File

@ -10,13 +10,11 @@ The `general` [table][toml-table] is for main Hooked configuration.
|-----|------|---------|-------------| |-----|------|---------|-------------|
| config | String | Hooked.toml | The configuration file to use. If your configuration file isn't `Hooked.toml` you should set this accordingly. | | config | String | Hooked.toml | The configuration file to use. If your configuration file isn't `Hooked.toml` you should set this accordingly. |
| directory | String | hooks | The directory Hooked looks in for anything related to files. For example: scripts, templates, etc. | | directory | String | hooks | The directory Hooked looks in for anything related to files. For example: scripts, templates, etc. |
| template | Optional string | | Path to a custom template to be used when installing scripts. See the [install CLI command][cli-install] for more details. |
```toml ```toml
[general] [general]
config = "Hooked.toml" config = "Hooked.toml"
directory = "hooks" directory = "hooks"
template = "template.sh"
``` ```
## Pre-commit ## Pre-commit
@ -45,6 +43,5 @@ on_failure = "continue"
[^command-and-script]: When both a command and script are defined in a hook, *only* the command will be run. [^command-and-script]: When both a command and script are defined in a hook, *only* the command will be run.
[cli-install]: ../cli/install.md
[toml-table]: https://toml.io/en/v1.0.0#table [toml-table]: https://toml.io/en/v1.0.0#table
[toml-arrays-of-tables]: https://toml.io/en/v1.0.0#array-of-tables [toml-arrays-of-tables]: https://toml.io/en/v1.0.0#array-of-tables

View File

@ -1,50 +0,0 @@
//! The `install` subcommand.
use std::{
fs::{read_to_string, set_permissions, write, Permissions},
os::unix::fs::PermissionsExt,
path::PathBuf,
};
use {
color_eyre::{eyre::eyre, Result},
hooked_config::Config,
tera::{Context, Tera},
};
use crate::{cli::InstallArgs, DEFAULT_TEMPLATE, HOOK_TYPES};
/// The `install` subcommand.
pub fn hooked_install(config: Config, args: InstallArgs) -> Result<()> {
let git_hooks_dir = PathBuf::from(".git/hooks/");
if !git_hooks_dir.exists() {
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
}
let hooked_directory = config.general.directory;
for hook_type in HOOK_TYPES {
let mut context = Context::new();
context.insert("config_path", &config.general.config);
context.insert("hook_type", hook_type);
let hook_path = git_hooks_dir.join(hook_type);
if hook_path.exists() && !args.overwrite {
println!(
"{:?} exists, use --overwrite to replace the existing file",
hook_path
);
continue;
}
let template = match config.general.template.as_ref() {
Some(template_path) => {
read_to_string(hooked_directory.join(template_path))?
}
None => DEFAULT_TEMPLATE.to_string(),
};
write(&hook_path, Tera::one_off(&template, &context, false)?)?;
set_permissions(hook_path, Permissions::from_mode(0o775))?;
}
Ok(())
}

View File

@ -2,15 +2,11 @@
use std::path::PathBuf; use std::path::PathBuf;
use clap::{Args as Arguments, Parser, Subcommand}; use clap::{Parser, Subcommand};
mod install;
mod run; mod run;
mod uninstall;
pub use install::hooked_install;
pub use run::hooked_run; pub use run::hooked_run;
pub use uninstall::hooked_uninstall;
/// CLI arguments struct using [`clap::Parser`]. /// CLI arguments struct using [`clap::Parser`].
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -30,35 +26,23 @@ pub struct Args {
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum MainSubcommands { pub enum MainSubcommands {
/// Install Hooked into ".git/hooks". /// Install Hooked into ".git/hooks".
Install(InstallArgs), Install {
/// Remove installed hooks.
Uninstall(UninstallArgs),
/// Manually run hooks.
Run(RunArgs),
}
/// The `install` subcommand arguments.
#[derive(Debug, Arguments)]
pub struct InstallArgs {
/// Overwrite existing files. /// Overwrite existing files.
#[clap(long)] #[clap(long)]
pub overwrite: bool, overwrite: bool,
} },
/// The `uninstall` subcommand arguments. /// Remove installed hooks.
#[derive(Debug, Arguments)] Uninstall {
pub struct UninstallArgs {
/// Remove hooks not installed by Hooked. /// Remove hooks not installed by Hooked.
#[clap(long)] #[clap(long)]
pub all: bool, all: bool,
} },
/// The `run` subcommand arguments. /// Manually run hooks.
#[derive(Debug, Arguments)] Run {
pub struct RunArgs {
/// The hook type to run. /// The hook type to run.
#[clap(value_parser = crate::HOOK_TYPES)] #[clap(value_parser = crate::HOOK_TYPES)]
pub hook_type: String, hook_type: String,
},
} }

View File

@ -1,40 +0,0 @@
//! The `uninstall` subcommand.
use std::{
fs::{read_to_string, remove_file},
path::PathBuf,
};
use {
color_eyre::{eyre::eyre, Result},
hooked_config::Config,
};
use crate::{cli::UninstallArgs, HOOK_TYPES};
/// The `uninstall` subcommand.
pub fn hooked_uninstall(_config: Config, args: UninstallArgs) -> Result<()> {
let git_hooks_dir = PathBuf::from(".git/hooks/");
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 args.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
);
}
}
Ok(())
}

View File

@ -5,10 +5,17 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![warn(missing_docs, clippy::missing_docs_in_private_items)] #![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 { use {
clap::Parser, clap::Parser,
color_eyre::{install, Result}, color_eyre::{eyre::eyre, install, Result},
hooked_config::Config, hooked_config::Config,
tera::{Context, Tera},
}; };
use crate::cli::{Args, MainSubcommands}; use crate::cli::{Args, MainSubcommands};
@ -28,17 +35,61 @@ fn main() -> Result<()> {
let args = Args::parse(); let args = Args::parse();
let config = Config::from_toml_file(args.config)?; let config = Config::from_toml_file(args.config)?;
let git_hooks_dir = PathBuf::from(".git/hooks/");
match args.command { match args.command {
MainSubcommands::Install(sub_args) => { MainSubcommands::Install { overwrite } => {
cli::hooked_install(config, sub_args)?; if !git_hooks_dir.exists() {
return Err(eyre!("The \".git/hooks/\" directory does not exist"));
} }
MainSubcommands::Uninstall(sub_args) => { for hook_type in HOOK_TYPES {
cli::hooked_uninstall(config, sub_args)?; let mut context = Context::new();
context.insert("config_path", &config.general.config);
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;
} }
MainSubcommands::Run(sub_args) => { write(
cli::hooked_run(config, sub_args.hook_type)?; &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)?;
} }
} }

View File

@ -13,9 +13,6 @@ pub struct General {
/// The directory to use for hooks. /// The directory to use for hooks.
pub directory: PathBuf, pub directory: PathBuf,
/// Path to a script template for use with the install subcommand.
pub template: Option<PathBuf>,
} }
impl Default for General { impl Default for General {
@ -23,7 +20,6 @@ impl Default for General {
Self { Self {
config: PathBuf::from("Hooked.toml"), config: PathBuf::from("Hooked.toml"),
directory: PathBuf::from("hooks"), directory: PathBuf::from("hooks"),
template: None,
} }
} }
} }

View File

@ -1,6 +1,5 @@
[general] [general]
directory = "hooked" directory = "hooked"
template = "test.sh"
[[pre_commit]] [[pre_commit]]
name = "Pre Commit 1" name = "Pre Commit 1"

View File

@ -6,7 +6,6 @@ Config {
general: General { general: General {
config: "Hooked.toml", config: "Hooked.toml",
directory: "hooks", directory: "hooks",
template: None,
}, },
pre_commit: [ pre_commit: [
PreCommit { PreCommit {

View File

@ -6,9 +6,6 @@ Config {
general: General { general: General {
config: "Hooked.toml", config: "Hooked.toml",
directory: "hooked", directory: "hooked",
template: Some(
"test.sh",
),
}, },
pre_commit: [ pre_commit: [
PreCommit { PreCommit {