diff options
56 files changed, 271 insertions, 64 deletions
diff --git a/.dev-suite/hooked/applypatch-msg b/.dev-suite/hooked/applypatch-msg deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/applypatch-msg +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/applypatch-msg.py b/.dev-suite/hooked/applypatch-msg.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/applypatch-msg.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/commit-msg b/.dev-suite/hooked/commit-msg deleted file mode 100755 index cc072bf..0000000 --- a/.dev-suite/hooked/commit-msg +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/bash - -# Check that the commit message is up to spec -hooked-commit-msg $@ diff --git a/.dev-suite/hooked/commit-msg.py b/.dev-suite/hooked/commit-msg.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/commit-msg.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-applypatch b/.dev-suite/hooked/post-applypatch deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/post-applypatch +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/post-applypatch.py b/.dev-suite/hooked/post-applypatch.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-applypatch.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-checkout b/.dev-suite/hooked/post-checkout deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/post-checkout +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/post-checkout.py b/.dev-suite/hooked/post-checkout.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-checkout.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-commit b/.dev-suite/hooked/post-commit deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/post-commit +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/post-commit.py b/.dev-suite/hooked/post-commit.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-commit.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-merge b/.dev-suite/hooked/post-merge deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/post-merge +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/post-merge.py b/.dev-suite/hooked/post-merge.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-merge.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-receive b/.dev-suite/hooked/post-receive deleted file mode 100755 index fb6b709..0000000 --- a/.dev-suite/hooked/post-receive +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/bash -git push github --all --force diff --git a/.dev-suite/hooked/post-receive.py b/.dev-suite/hooked/post-receive.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-receive.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-rewrite b/.dev-suite/hooked/post-rewrite deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/post-rewrite +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/post-rewrite.py b/.dev-suite/hooked/post-rewrite.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-rewrite.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/post-update b/.dev-suite/hooked/post-update deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/post-update +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/post-update.py b/.dev-suite/hooked/post-update.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/post-update.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-auto-gc b/.dev-suite/hooked/pre-auto-gc deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/pre-auto-gc +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-auto-gc.py b/.dev-suite/hooked/pre-auto-gc.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/pre-auto-gc.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-commit b/.dev-suite/hooked/pre-commit deleted file mode 100755 index 4229848..0000000 --- a/.dev-suite/hooked/pre-commit +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash -set -eu -o pipefail - -cargo build --all -cargo test --all -rustup run nightly cargo fmt --all -- --check -cargo clippy --all --all-targets -- -W clippy::pedantic diff --git a/.dev-suite/hooked/pre-commit.py b/.dev-suite/hooked/pre-commit.py new file mode 100755 index 0000000..5ddbc42 --- /dev/null +++ b/.dev-suite/hooked/pre-commit.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +import subprocess + +subprocess.run("cargo build --all", shell=True, check=True) +subprocess.run("cargo test --all -- --test-threads=1", shell=True, check=True) +subprocess.run("rustup run nightly cargo fmt --all -- --check", shell=True, check=True) +subprocess.run("cargo clippy --all --all-targets -- -W clippy::pedantic", shell=True, check=True) diff --git a/.dev-suite/hooked/pre-push b/.dev-suite/hooked/pre-push deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/pre-push +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-push.py b/.dev-suite/hooked/pre-push.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/pre-push.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-rebase b/.dev-suite/hooked/pre-rebase deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/pre-rebase +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-rebase.py b/.dev-suite/hooked/pre-rebase.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/pre-rebase.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-receive b/.dev-suite/hooked/pre-receive deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/pre-receive +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/pre-receive.py b/.dev-suite/hooked/pre-receive.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/pre-receive.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/prepare-commit-msg b/.dev-suite/hooked/prepare-commit-msg deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/prepare-commit-msg +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/prepare-commit-msg.py b/.dev-suite/hooked/prepare-commit-msg.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/prepare-commit-msg.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/push-to-checkout b/.dev-suite/hooked/push-to-checkout deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/push-to-checkout +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/push-to-checkout.py b/.dev-suite/hooked/push-to-checkout.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/push-to-checkout.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/sendemail-validate b/.dev-suite/hooked/sendemail-validate deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/sendemail-validate +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/sendemail-validate.py b/.dev-suite/hooked/sendemail-validate.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/sendemail-validate.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/update b/.dev-suite/hooked/update deleted file mode 100755 index efcbaec..0000000 --- a/.dev-suite/hooked/update +++ /dev/null @@ -1 +0,0 @@ -#! /bin/bash
\ No newline at end of file diff --git a/.dev-suite/hooked/update.py b/.dev-suite/hooked/update.py new file mode 100755 index 0000000..5f7ce86 --- /dev/null +++ b/.dev-suite/hooked/update.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/.dev-suite/hooked/wrapper/applypatch-msg.sh b/.dev-suite/hooked/wrapper/applypatch-msg.sh new file mode 100755 index 0000000..9719401 --- /dev/null +++ b/.dev-suite/hooked/wrapper/applypatch-msg.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/applypatch-msg.py diff --git a/.dev-suite/hooked/wrapper/commit-msg.sh b/.dev-suite/hooked/wrapper/commit-msg.sh new file mode 100755 index 0000000..b1a3623 --- /dev/null +++ b/.dev-suite/hooked/wrapper/commit-msg.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/commit-msg.py diff --git a/.dev-suite/hooked/wrapper/post-applypatch.sh b/.dev-suite/hooked/wrapper/post-applypatch.sh new file mode 100755 index 0000000..741c689 --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-applypatch.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-applypatch.py diff --git a/.dev-suite/hooked/wrapper/post-checkout.sh b/.dev-suite/hooked/wrapper/post-checkout.sh new file mode 100755 index 0000000..a2b99fa --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-checkout.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-checkout.py diff --git a/.dev-suite/hooked/wrapper/post-commit.sh b/.dev-suite/hooked/wrapper/post-commit.sh new file mode 100755 index 0000000..6e392a4 --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-commit.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-commit.py diff --git a/.dev-suite/hooked/wrapper/post-merge.sh b/.dev-suite/hooked/wrapper/post-merge.sh new file mode 100755 index 0000000..8a6eda9 --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-merge.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-merge.py diff --git a/.dev-suite/hooked/wrapper/post-receive.sh b/.dev-suite/hooked/wrapper/post-receive.sh new file mode 100755 index 0000000..c8b87f9 --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-receive.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-receive.py diff --git a/.dev-suite/hooked/wrapper/post-rewrite.sh b/.dev-suite/hooked/wrapper/post-rewrite.sh new file mode 100755 index 0000000..fb41a73 --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-rewrite.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-rewrite.py diff --git a/.dev-suite/hooked/wrapper/post-update.sh b/.dev-suite/hooked/wrapper/post-update.sh new file mode 100755 index 0000000..f9e816d --- /dev/null +++ b/.dev-suite/hooked/wrapper/post-update.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/post-update.py diff --git a/.dev-suite/hooked/wrapper/pre-auto-gc.sh b/.dev-suite/hooked/wrapper/pre-auto-gc.sh new file mode 100755 index 0000000..2e1400c --- /dev/null +++ b/.dev-suite/hooked/wrapper/pre-auto-gc.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/pre-auto-gc.py diff --git a/.dev-suite/hooked/wrapper/pre-commit.sh b/.dev-suite/hooked/wrapper/pre-commit.sh new file mode 100755 index 0000000..196c797 --- /dev/null +++ b/.dev-suite/hooked/wrapper/pre-commit.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/pre-commit.py diff --git a/.dev-suite/hooked/wrapper/pre-push.sh b/.dev-suite/hooked/wrapper/pre-push.sh new file mode 100755 index 0000000..0d760d0 --- /dev/null +++ b/.dev-suite/hooked/wrapper/pre-push.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/pre-push.py diff --git a/.dev-suite/hooked/wrapper/pre-rebase.sh b/.dev-suite/hooked/wrapper/pre-rebase.sh new file mode 100755 index 0000000..642be35 --- /dev/null +++ b/.dev-suite/hooked/wrapper/pre-rebase.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/pre-rebase.py diff --git a/.dev-suite/hooked/wrapper/pre-receive.sh b/.dev-suite/hooked/wrapper/pre-receive.sh new file mode 100755 index 0000000..b33366f --- /dev/null +++ b/.dev-suite/hooked/wrapper/pre-receive.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/pre-receive.py diff --git a/.dev-suite/hooked/wrapper/prepare-commit-msg.sh b/.dev-suite/hooked/wrapper/prepare-commit-msg.sh new file mode 100755 index 0000000..e04c27b --- /dev/null +++ b/.dev-suite/hooked/wrapper/prepare-commit-msg.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/prepare-commit-msg.py diff --git a/.dev-suite/hooked/wrapper/push-to-checkout.sh b/.dev-suite/hooked/wrapper/push-to-checkout.sh new file mode 100755 index 0000000..47718bf --- /dev/null +++ b/.dev-suite/hooked/wrapper/push-to-checkout.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/push-to-checkout.py diff --git a/.dev-suite/hooked/wrapper/sendemail-validate.sh b/.dev-suite/hooked/wrapper/sendemail-validate.sh new file mode 100755 index 0000000..389deb1 --- /dev/null +++ b/.dev-suite/hooked/wrapper/sendemail-validate.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/sendemail-validate.py diff --git a/.dev-suite/hooked/wrapper/update.sh b/.dev-suite/hooked/wrapper/update.sh new file mode 100755 index 0000000..0d42ffd --- /dev/null +++ b/.dev-suite/hooked/wrapper/update.sh @@ -0,0 +1,2 @@ +#!C:\Program Files\Git\bin\sh.exe +py.exe .dev-suite/hooked/update.py diff --git a/hooked/src/main.rs b/hooked/src/main.rs index 7e33499..1c8388e 100644 --- a/hooked/src/main.rs +++ b/hooked/src/main.rs @@ -1,8 +1,9 @@ //! git hook manager tool -#[cfg(windows)] -use anyhow::bail; -use anyhow::Result; +use anyhow::{ + bail, + Result, +}; use log::*; use shared::find_root; #[cfg(not(windows))] @@ -16,6 +17,7 @@ use std::{ env, fs, io::Write, + path::Path, }; const HOOKS: [&str; 18] = [ @@ -41,8 +43,21 @@ const HOOKS: [&str; 18] = [ #[derive(structopt::StructOpt)] enum Args { - /// Initialize the repo to use ticket - Init, + /// Initialize the repo to use hooked + Init(Language), + /// Link pre existing hooks to your .git folder + Link, +} + +/// Which language the repo should be initialized with for hooks +#[derive(Clone, Copy, structopt::StructOpt)] +enum Language { + /// Use Bash for your git hooks + Bash, + /// Use Python 3 for your git hooks + Python, + /// Use Ruby for your git hooks + Ruby, } #[paw::main] @@ -52,60 +67,172 @@ fn main(args: Args) { .map_or_else(|| env::set_var("RUST_LOG", "info"), drop); pretty_env_logger::init(); if let Err(e) = match args { - Args::Init => init(), + Args::Init(lang) => init(lang), + Args::Link => link(), } { error!("{}", e); std::process::exit(1); } } -fn init() -> Result<()> { - #[cfg(windows)] - bail!("Windows is currently unsupported!"); - +fn init(lang: Language) -> Result<()> { let root = find_root()?; let git_hooks = &root.join(".git").join("hooks"); debug!("git_hooks base path: {}", git_hooks.display()); let root = root.join(".dev-suite").join("hooked"); debug!("root base path: {}", root.display()); - fs::create_dir_all(&root)?; + let wrapper_dir = &root.join("wrapper"); + fs::create_dir_all(&wrapper_dir)?; for hook in &HOOKS { - let path = &root.join(hook); + let mut path = (&root).join(hook); debug!("dev-suite hook path: {}", path.display()); let git_hook = &git_hooks.join(hook); debug!("git_hook path: {}", git_hook.display()); + let mut wrapper_hook = (&wrapper_dir).join(hook); + let _ = wrapper_hook.set_extension("sh"); + let _ = match lang { + Language::Bash => path.set_extension("sh"), + Language::Python => path.set_extension("py"), + Language::Ruby => path.set_extension("rb"), + }; if path.exists() { debug!("git hook {} already exists. Skipping creation.", hook); } else { debug!("Creating dev-suite hook."); let mut file = fs::File::create(&path)?; + let mut wrapper = fs::File::create(&wrapper_hook)?; trace!("File created."); - let mut perms = file.metadata()?.permissions(); - debug!("Setting dev-suite hook to be executable."); - perms.set_mode(0o755); - file.set_permissions(perms)?; - trace!("Permissions were set."); - file.write_all(b"#! /bin/bash")?; + #[cfg(not(windows))] + { + let mut perms = file.metadata()?.permissions(); + let mut wrapper_perms = wrapper.metadata()?.permissions(); + debug!("Setting dev-suite hook to be executable."); + perms.set_mode(0o755); + wrapper_perms.set_mode(0o755); + file.set_permissions(perms)?; + wrapper.set_permissions(wrapper_perms)?; + trace!("Permissions were set."); + } + match lang { + Language::Bash => { + file.write_all(b"#!/usr/bin/env bash")?; + wrapper.write_all( + format!( + "#!C:\\Program Files\\Git\\bin\\sh.exe\n\ + bash.exe .dev-suite/hooked/{}.sh\n", + hook + ) + .as_bytes(), + )?; + } + Language::Python => { + file.write_all(b"#!/usr/bin/env python3")?; + wrapper.write_all( + format!( + "#!C:\\Program Files\\Git\\bin\\sh.exe\n\ + py.exe .dev-suite/hooked/{}.py\n", + hook + ) + .as_bytes(), + )?; + } + Language::Ruby => { + file.write_all(b"#!/usr/bin/env ruby")?; + wrapper.write_all( + format!( + "#!C:\\Program Files\\Git\\bin\\sh.exe\n\ + ruby.exe .dev-suite/hooked/{}.rb\n", + hook + ) + .as_bytes(), + )?; + } + } debug!("Writing data to file."); debug!("Created git hook {}.", hook); } - let path = path.canonicalize()?; - if !git_hook.exists() { - debug!("Symlinking git hook {}.", hook); - #[cfg(not(windows))] - symlink(&path, &git_hook)?; - #[cfg(windows)] - symlink_file(&path, &git_hook)?; - trace!("Symlinked git hook {} to .dev-suite/hooked/{}.", hook, hook); - } + #[cfg(not(windows))] + let link_path = path.canonicalize()?; + #[cfg(windows)] + let link_path = wrapper_hook.canonicalize()?; + + inner_link(&link_path, &git_hook, hook)?; } info!( "Created and symlinked tickets to .git/hooks from {}.", root.display() ); + #[cfg(windows)] + { + warn!("Make sure to add the hooks into git with 'git add --chmod=+x .dev-suite\\hooked'"); + warn!("If you don't they won't be set as executable on unix systems"); + } + + Ok(()) +} + +fn link() -> Result<()> { + let root = find_root()?; + let git_hooks = &root.join(".git").join("hooks"); + debug!("git_hooks base path: {}", git_hooks.display()); + let root = root.join(".dev-suite").join("hooked"); + debug!("root base path: {}", root.display()); + + for hook in &HOOKS { + let path = { + #[cfg(windows)] + let mut path = root.join("wrapper").join(hook); + #[cfg(not(windows))] + let mut path = root.join(hook); + debug!("PATH: {}", path.display()); + let mut path_python = path.clone(); + let _ = path_python.set_extension("py"); + let mut path_ruby = path.clone(); + let _ = path_ruby.set_extension("rb"); + let mut path_bash = path.clone(); + let _ = path_bash.set_extension("sh"); + + if path_python.exists() { + path_python + } else if path_ruby.exists() { + path_ruby + } else if path_bash.exists() { + path_bash + } else { + let _ = path.set_extension(""); + bail!( + "The path {} does not exist. Have you initialized the repo to use hooked?", + path.display() + ); + } + }; + let path = path.canonicalize()?; + debug!("dev-suite hook path: {}", path.display()); + let git_hook = &git_hooks.join(hook); + debug!("git_hook path: {}", git_hook.display()); + inner_link(&path, &git_hook, hook)?; + } + + info!("Successfully symlinked all githooks to .git/hooks"); + Ok(()) +} + +fn inner_link(path: &Path, git_hook: &Path, hook: &str) -> Result<()> { + if !git_hook.exists() { + debug!("Symlinking git hook {}.", hook); + #[cfg(not(windows))] + symlink(&path, &git_hook)?; + #[cfg(windows)] + symlink_file(&path, &git_hook)?; + debug!( + "Symlinked git hook {} to {}", + git_hook.display(), + path.display() + ); + } Ok(()) } diff --git a/hooked/tests/init.rs b/hooked/tests/init.rs index 65c4aab..9c68ff3 100644 --- a/hooked/tests/init.rs +++ b/hooked/tests/init.rs @@ -1,10 +1,10 @@ use assert_cmd::prelude::*; use git2::Repository; +#[cfg(not(windows))] +use std::os::unix::fs::PermissionsExt; use std::{ - env, error::Error, fs, - os::unix::fs::PermissionsExt, process::Command, }; use tempfile::tempdir; @@ -30,19 +30,36 @@ const HOOKS: [&str; 18] = [ "sendemail-validate", ]; -#[test] -fn init() -> Result<(), Box<dyn Error>> { +fn lang(lang: &str) -> Result<(), Box<dyn Error>> { let dir = tempdir()?; let _ = Repository::init(&dir)?; - let mut cmd = Command::cargo_bin("hooked")?; - env::set_current_dir(&dir)?; - let _ = cmd.arg("init").assert().success(); + let _ = Command::cargo_bin("hooked")? + .arg("init") + .arg(lang) + .current_dir(&dir) + .assert() + .success(); let git = &dir.path().join(".git").join("hooks"); let dev = &dir.path().join(".dev-suite").join("hooked"); for hook in &HOOKS { let git_hook = git.join(hook); - let dev_hook = dev.join(hook); + #[cfg(not(windows))] + let mut dev_hook = dev.join(hook); + #[cfg(windows)] + let mut dev_hook = dev.join("wrapper").join(hook); + + #[cfg(not(windows))] + let _ = match lang { + "bash" => dev_hook.set_extension("sh"), + "python" => dev_hook.set_extension("py"), + "ruby" => dev_hook.set_extension("rb"), + _ => unreachable!(), + }; + + #[cfg(windows)] + let _ = dev_hook.set_extension("sh"); + assert!(&git_hook.exists()); assert!(&dev_hook.exists()); assert!(fs::symlink_metadata(&git_hook)?.file_type().is_symlink()); @@ -54,8 +71,39 @@ fn init() -> Result<(), Box<dyn Error>> { // numbers essentially, allowing us to test the actual value we wanted to // test, and making this test work without special casing it if git ever // changes. + #[cfg(not(windows))] assert_eq!(dev_hook.metadata()?.permissions().mode() & 511, 0o755); - } + let shebang = fs::read_to_string(&dev_hook)? + .lines() + .nth(0) + .ok_or_else(|| "File is empty and has no shebang line")? + .to_owned(); + + #[cfg(not(windows))] + match lang { + "bash" => assert_eq!(shebang, "#!/usr/bin/env bash"), + "python" => assert_eq!(shebang, "#!/usr/bin/env python3"), + "ruby" => assert_eq!(shebang, "#!/usr/bin/env ruby"), + _ => unreachable!(), + } + #[cfg(windows)] + assert_eq!(shebang, "#!C:\\Program Files\\Git\\bin\\sh.exe") + } Ok(()) } + +#[test] +fn init_bash() -> Result<(), Box<dyn Error>> { + lang("bash") +} + +#[test] +fn init_python() -> Result<(), Box<dyn Error>> { + lang("python") +} + +#[test] +fn init_ruby() -> Result<(), Box<dyn Error>> { + lang("ruby") +} |