Compare commits
4 Commits
aed22fad90
...
a4d0431a32
Author | SHA1 | Date |
---|---|---|
Bauke | a4d0431a32 | |
Bauke | 8d1baaf57f | |
Bauke | 1a79f9e051 | |
Bauke | 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 hook type to run.
|
}
|
||||||
#[clap(value_parser = crate::HOOK_TYPES)]
|
|
||||||
hook_type: String,
|
/// 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.
|
||||||
|
#[clap(value_parser = crate::HOOK_TYPES)]
|
||||||
|
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 {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
write(
|
|
||||||
&hook_path,
|
|
||||||
Tera::one_off(DEFAULT_TEMPLATE, &context, false)?,
|
|
||||||
)?;
|
|
||||||
set_permissions(hook_path, Permissions::from_mode(0o775))?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainSubcommands::Uninstall { all } => {
|
MainSubcommands::Uninstall(sub_args) => {
|
||||||
if !git_hooks_dir.exists() {
|
cli::hooked_uninstall(config, sub_args)?;
|
||||||
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 } => {
|
MainSubcommands::Run(sub_args) => {
|
||||||
cli::hooked_run(config, hook_type)?;
|
cli::hooked_run(config, sub_args.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