Compare commits
	
		
			4 Commits
		
	
	
		
			aed22fad90
			...
			a4d0431a32
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | a4d0431a32 | |
|  | 8d1baaf57f | |
|  | 1a79f9e051 | |
|  | 9c11ae3db6 | 
|  | @ -20,3 +20,7 @@ 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 | ||||||
|  |  | ||||||
|  | @ -10,11 +10,13 @@ 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 | ||||||
|  | @ -43,5 +45,6 @@ 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 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,50 @@ | ||||||
|  | //! 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(()) | ||||||
|  | } | ||||||
|  | @ -2,11 +2,15 @@ | ||||||
| 
 | 
 | ||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
| 
 | 
 | ||||||
| use clap::{Parser, Subcommand}; | use clap::{Args as Arguments, 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)] | ||||||
|  | @ -26,23 +30,35 @@ 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 { |   Install(InstallArgs), | ||||||
|     /// Overwrite existing files.
 |  | ||||||
|     #[clap(long)] |  | ||||||
|     overwrite: bool, |  | ||||||
|   }, |  | ||||||
| 
 | 
 | ||||||
|   /// Remove installed hooks.
 |   /// Remove installed hooks.
 | ||||||
|   Uninstall { |   Uninstall(UninstallArgs), | ||||||
|     /// Remove hooks not installed by Hooked.
 |  | ||||||
|     #[clap(long)] |  | ||||||
|     all: bool, |  | ||||||
|   }, |  | ||||||
| 
 | 
 | ||||||
|   /// Manually run hooks.
 |   /// Manually run hooks.
 | ||||||
|   Run { |   Run(RunArgs), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// The `install` subcommand arguments.
 | ||||||
|  | #[derive(Debug, Arguments)] | ||||||
|  | pub struct InstallArgs { | ||||||
|  |   /// Overwrite existing files.
 | ||||||
|  |   #[clap(long)] | ||||||
|  |   pub overwrite: bool, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// The `uninstall` subcommand arguments.
 | ||||||
|  | #[derive(Debug, Arguments)] | ||||||
|  | pub struct UninstallArgs { | ||||||
|  |   /// Remove hooks not installed by Hooked.
 | ||||||
|  |   #[clap(long)] | ||||||
|  |   pub all: bool, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// The `run` subcommand arguments.
 | ||||||
|  | #[derive(Debug, Arguments)] | ||||||
|  | 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)] | ||||||
|     hook_type: String, |   pub hook_type: String, | ||||||
|   }, |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,40 @@ | ||||||
|  | //! 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(()) | ||||||
|  | } | ||||||
|  | @ -5,17 +5,10 @@ | ||||||
| #![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::{eyre::eyre, install, Result}, |   color_eyre::{install, Result}, | ||||||
|   hooked_config::Config, |   hooked_config::Config, | ||||||
|   tera::{Context, Tera}, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::cli::{Args, MainSubcommands}; | use crate::cli::{Args, MainSubcommands}; | ||||||
|  | @ -35,61 +28,17 @@ 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 { overwrite } => { |     MainSubcommands::Install(sub_args) => { | ||||||
|       if !git_hooks_dir.exists() { |       cli::hooked_install(config, sub_args)?; | ||||||
|         return Err(eyre!("The \".git/hooks/\" directory does not exist")); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|       for hook_type in HOOK_TYPES { |     MainSubcommands::Uninstall(sub_args) => { | ||||||
|         let mut context = Context::new(); |       cli::hooked_uninstall(config, sub_args)?; | ||||||
|         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; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|         write( |     MainSubcommands::Run(sub_args) => { | ||||||
|           &hook_path, |       cli::hooked_run(config, sub_args.hook_type)?; | ||||||
|           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)?; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,9 @@ 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 { | ||||||
|  | @ -20,6 +23,7 @@ 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, | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| [general] | [general] | ||||||
| directory = "hooked" | directory = "hooked" | ||||||
|  | template = "test.sh" | ||||||
| 
 | 
 | ||||||
| [[pre_commit]] | [[pre_commit]] | ||||||
| name = "Pre Commit 1" | name = "Pre Commit 1" | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ Config { | ||||||
|     general: General { |     general: General { | ||||||
|         config: "Hooked.toml", |         config: "Hooked.toml", | ||||||
|         directory: "hooks", |         directory: "hooks", | ||||||
|  |         template: None, | ||||||
|     }, |     }, | ||||||
|     pre_commit: [ |     pre_commit: [ | ||||||
|         PreCommit { |         PreCommit { | ||||||
|  |  | ||||||
|  | @ -6,6 +6,9 @@ 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 { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue