diff options
Diffstat (limited to 'hooked/src/main.rs')
-rw-r--r-- | hooked/src/main.rs | 181 |
1 files changed, 154 insertions, 27 deletions
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(()) } |