aboutsummaryrefslogtreecommitdiff
path: root/hooked/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'hooked/src/main.rs')
-rw-r--r--hooked/src/main.rs181
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(())
}