diff options
Diffstat (limited to 'asyncgit/src/sync/hooks.rs')
-rw-r--r-- | asyncgit/src/sync/hooks.rs | 498 |
1 files changed, 249 insertions, 249 deletions
diff --git a/asyncgit/src/sync/hooks.rs b/asyncgit/src/sync/hooks.rs index ac6d567a..fc076f59 100644 --- a/asyncgit/src/sync/hooks.rs +++ b/asyncgit/src/sync/hooks.rs @@ -2,10 +2,10 @@ use super::utils::{repo, work_dir}; use crate::error::{Error, Result}; use scopetime::scope_time; use std::{ - fs::File, - io::{Read, Write}, - path::Path, - process::Command, + fs::File, + io::{Read, Write}, + path::Path, + process::Command, }; const HOOK_POST_COMMIT: &str = ".git/hooks/post-commit"; @@ -18,372 +18,372 @@ const HOOK_COMMIT_MSG_TEMP_FILE: &str = ".git/COMMIT_EDITMSG"; /// the commit message at `.git/COMMIT_EDITMSG` and pass it's relative path as the only /// parameter to the hook script. pub fn hooks_commit_msg( - repo_path: &str, - msg: &mut String, + repo_path: &str, + msg: &mut String, ) -> Result<HookResult> { - scope_time!("hooks_commit_msg"); + scope_time!("hooks_commit_msg"); - let work_dir = work_dir_as_string(repo_path)?; + let work_dir = work_dir_as_string(repo_path)?; - if hook_runable(work_dir.as_str(), HOOK_COMMIT_MSG) { - let temp_file = Path::new(work_dir.as_str()) - .join(HOOK_COMMIT_MSG_TEMP_FILE); - File::create(&temp_file)?.write_all(msg.as_bytes())?; + if hook_runable(work_dir.as_str(), HOOK_COMMIT_MSG) { + let temp_file = Path::new(work_dir.as_str()) + .join(HOOK_COMMIT_MSG_TEMP_FILE); + File::create(&temp_file)?.write_all(msg.as_bytes())?; - let res = run_hook( - work_dir.as_str(), - HOOK_COMMIT_MSG, - &[HOOK_COMMIT_MSG_TEMP_FILE], - )?; + let res = run_hook( + work_dir.as_str(), + HOOK_COMMIT_MSG, + &[HOOK_COMMIT_MSG_TEMP_FILE], + )?; - // load possibly altered msg - msg.clear(); - File::open(temp_file)?.read_to_string(msg)?; + // load possibly altered msg + msg.clear(); + File::open(temp_file)?.read_to_string(msg)?; - Ok(res) - } else { - Ok(HookResult::Ok) - } + Ok(res) + } else { + Ok(HookResult::Ok) + } } /// this hook is documented here <https://git-scm.com/docs/githooks#_pre_commit> /// pub fn hooks_pre_commit(repo_path: &str) -> Result<HookResult> { - scope_time!("hooks_pre_commit"); + scope_time!("hooks_pre_commit"); - let work_dir = work_dir_as_string(repo_path)?; + let work_dir = work_dir_as_string(repo_path)?; - if hook_runable(work_dir.as_str(), HOOK_PRE_COMMIT) { - Ok(run_hook(work_dir.as_str(), HOOK_PRE_COMMIT, &[])?) - } else { - Ok(HookResult::Ok) - } + if hook_runable(work_dir.as_str(), HOOK_PRE_COMMIT) { + Ok(run_hook(work_dir.as_str(), HOOK_PRE_COMMIT, &[])?) + } else { + Ok(HookResult::Ok) + } } /// pub fn hooks_post_commit(repo_path: &str) -> Result<HookResult> { - scope_time!("hooks_post_commit"); + scope_time!("hooks_post_commit"); - let work_dir = work_dir_as_string(repo_path)?; - let work_dir_str = work_dir.as_str(); + let work_dir = work_dir_as_string(repo_path)?; + let work_dir_str = work_dir.as_str(); - if hook_runable(work_dir_str, HOOK_POST_COMMIT) { - Ok(run_hook(work_dir_str, HOOK_POST_COMMIT, &[])?) - } else { - Ok(HookResult::Ok) - } + if hook_runable(work_dir_str, HOOK_POST_COMMIT) { + Ok(run_hook(work_dir_str, HOOK_POST_COMMIT, &[])?) + } else { + Ok(HookResult::Ok) + } } fn work_dir_as_string(repo_path: &str) -> Result<String> { - let repo = repo(repo_path)?; - work_dir(&repo)? - .to_str() - .map(std::string::ToString::to_string) - .ok_or_else(|| { - Error::Generic( - "workdir contains invalid utf8".to_string(), - ) - }) + let repo = repo(repo_path)?; + work_dir(&repo)? + .to_str() + .map(std::string::ToString::to_string) + .ok_or_else(|| { + Error::Generic( + "workdir contains invalid utf8".to_string(), + ) + }) } fn hook_runable(path: &str, hook: &str) -> bool { - let path = Path::new(path); - let path = path.join(hook); + let path = Path::new(path); + let path = path.join(hook); - path.exists() && is_executable(&path) + path.exists() && is_executable(&path) } /// #[derive(Debug, PartialEq)] pub enum HookResult { - /// Everything went fine - Ok, - /// Hook returned error - NotOk(String), + /// Everything went fine + Ok, + /// Hook returned error + NotOk(String), } /// this function calls hook scripts based on conventions documented here /// see <https://git-scm.com/docs/githooks> fn run_hook( - path: &str, - hook_script: &str, - args: &[&str], + path: &str, + hook_script: &str, + args: &[&str], ) -> Result<HookResult> { - let arg_str = format!("{} {}", hook_script, args.join(" ")); - let bash_args = vec!["-c".to_string(), arg_str]; - - let output = Command::new("bash") - .args(bash_args) - .current_dir(path) - // This call forces Command to handle the Path environment correctly on windows, - // the specific env set here does not matter - // see https://github.com/rust-lang/rust/issues/37519 - .env( - "DUMMY_ENV_TO_FIX_WINDOWS_CMD_RUNS", - "FixPathHandlingOnWindows", - ) - .output()?; - - if output.status.success() { - Ok(HookResult::Ok) - } else { - let err = String::from_utf8_lossy(&output.stderr); - let out = String::from_utf8_lossy(&output.stdout); - let formatted = format!("{}{}", out, err); - - Ok(HookResult::NotOk(formatted)) - } + let arg_str = format!("{} {}", hook_script, args.join(" ")); + let bash_args = vec!["-c".to_string(), arg_str]; + + let output = Command::new("bash") + .args(bash_args) + .current_dir(path) + // This call forces Command to handle the Path environment correctly on windows, + // the specific env set here does not matter + // see https://github.com/rust-lang/rust/issues/37519 + .env( + "DUMMY_ENV_TO_FIX_WINDOWS_CMD_RUNS", + "FixPathHandlingOnWindows", + ) + .output()?; + + if output.status.success() { + Ok(HookResult::Ok) + } else { + let err = String::from_utf8_lossy(&output.stderr); + let out = String::from_utf8_lossy(&output.stdout); + let formatted = format!("{}{}", out, err); + + Ok(HookResult::NotOk(formatted)) + } } #[cfg(not(windows))] fn is_executable(path: &Path) -> bool { - use std::os::unix::fs::PermissionsExt; - let metadata = match path.metadata() { - Ok(metadata) => metadata, - Err(_) => return false, - }; - - let permissions = metadata.permissions(); - permissions.mode() & 0o111 != 0 + use std::os::unix::fs::PermissionsExt; + let metadata = match path.metadata() { + Ok(metadata) => metadata, + Err(_) => return false, + }; + + let permissions = metadata.permissions(); + permissions.mode() & 0o111 != 0 } #[cfg(windows)] /// windows does not consider bash scripts to be executable so we consider everything /// to be executable (which is not far from the truth for windows platform.) const fn is_executable(_: &Path) -> bool { - true + true } #[cfg(test)] mod tests { - use super::*; - use crate::sync::tests::repo_init; - use std::fs::{self, File}; - - #[test] - fn test_smoke() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); - - let mut msg = String::from("test"); - let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); - - assert_eq!(res, HookResult::Ok); - - let res = hooks_post_commit(repo_path).unwrap(); - - assert_eq!(res, HookResult::Ok); - } - - fn create_hook(path: &Path, hook_path: &str, hook_script: &[u8]) { - File::create(&path.join(hook_path)) - .unwrap() - .write_all(hook_script) - .unwrap(); - - #[cfg(not(windows))] - { - Command::new("chmod") - .args(&["+x", hook_path]) - .current_dir(path) - .output() - .unwrap(); - } - } - - #[test] - fn test_hooks_commit_msg_ok() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); - - let hook = b"#!/bin/sh + use super::*; + use crate::sync::tests::repo_init; + use std::fs::{self, File}; + + #[test] + fn test_smoke() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); + + let mut msg = String::from("test"); + let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); + + assert_eq!(res, HookResult::Ok); + + let res = hooks_post_commit(repo_path).unwrap(); + + assert_eq!(res, HookResult::Ok); + } + + fn create_hook(path: &Path, hook_path: &str, hook_script: &[u8]) { + File::create(&path.join(hook_path)) + .unwrap() + .write_all(hook_script) + .unwrap(); + + #[cfg(not(windows))] + { + Command::new("chmod") + .args(&["+x", hook_path]) + .current_dir(path) + .output() + .unwrap(); + } + } + + #[test] + fn test_hooks_commit_msg_ok() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); + + let hook = b"#!/bin/sh exit 0 "; - create_hook(root, HOOK_COMMIT_MSG, hook); + create_hook(root, HOOK_COMMIT_MSG, hook); - let mut msg = String::from("test"); - let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); + let mut msg = String::from("test"); + let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); - assert_eq!(res, HookResult::Ok); + assert_eq!(res, HookResult::Ok); - assert_eq!(msg, String::from("test")); - } + assert_eq!(msg, String::from("test")); + } - #[test] - fn test_pre_commit_sh() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_pre_commit_sh() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); - let hook = b"#!/bin/sh + let hook = b"#!/bin/sh exit 0 "; - create_hook(root, HOOK_PRE_COMMIT, hook); - let res = hooks_pre_commit(repo_path).unwrap(); - assert_eq!(res, HookResult::Ok); - } + create_hook(root, HOOK_PRE_COMMIT, hook); + let res = hooks_pre_commit(repo_path).unwrap(); + assert_eq!(res, HookResult::Ok); + } - #[test] - fn test_pre_commit_fail_sh() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_pre_commit_fail_sh() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); - let hook = b"#!/bin/sh + let hook = b"#!/bin/sh echo 'rejected' exit 1 "; - create_hook(root, HOOK_PRE_COMMIT, hook); - let res = hooks_pre_commit(repo_path).unwrap(); - assert!(res != HookResult::Ok); - } + create_hook(root, HOOK_PRE_COMMIT, hook); + let res = hooks_pre_commit(repo_path).unwrap(); + assert!(res != HookResult::Ok); + } - #[test] - fn test_pre_commit_py() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_pre_commit_py() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); - // mirror how python pre-commmit sets itself up - #[cfg(not(windows))] - let hook = b"#!/usr/bin/env python + // mirror how python pre-commmit sets itself up + #[cfg(not(windows))] + let hook = b"#!/usr/bin/env python import sys sys.exit(0) "; - #[cfg(windows)] - let hook = b"#!/bin/env python.exe + #[cfg(windows)] + let hook = b"#!/bin/env python.exe import sys sys.exit(0) "; - create_hook(root, HOOK_PRE_COMMIT, hook); - let res = hooks_pre_commit(repo_path).unwrap(); - assert_eq!(res, HookResult::Ok); - } + create_hook(root, HOOK_PRE_COMMIT, hook); + let res = hooks_pre_commit(repo_path).unwrap(); + assert_eq!(res, HookResult::Ok); + } - #[test] - fn test_pre_commit_fail_py() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_pre_commit_fail_py() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); - // mirror how python pre-commmit sets itself up - #[cfg(not(windows))] - let hook = b"#!/usr/bin/env python + // mirror how python pre-commmit sets itself up + #[cfg(not(windows))] + let hook = b"#!/usr/bin/env python import sys sys.exit(1) "; - #[cfg(windows)] - let hook = b"#!/bin/env python.exe + #[cfg(windows)] + let hook = b"#!/bin/env python.exe import sys sys.exit(1) "; - create_hook(root, HOOK_PRE_COMMIT, hook); - let res = hooks_pre_commit(repo_path).unwrap(); - assert!(res != HookResult::Ok); - } + create_hook(root, HOOK_PRE_COMMIT, hook); + let res = hooks_pre_commit(repo_path).unwrap(); + assert!(res != HookResult::Ok); + } - #[test] - fn test_hooks_commit_msg_reject() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_hooks_commit_msg_reject() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); - let hook = b"#!/bin/sh + let hook = b"#!/bin/sh echo 'msg' > $1 echo 'rejected' exit 1 "; - create_hook(root, HOOK_COMMIT_MSG, hook); + create_hook(root, HOOK_COMMIT_MSG, hook); - let mut msg = String::from("test"); - let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); + let mut msg = String::from("test"); + let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); - assert_eq!( - res, - HookResult::NotOk(String::from("rejected\n")) - ); + assert_eq!( + res, + HookResult::NotOk(String::from("rejected\n")) + ); - assert_eq!(msg, String::from("msg\n")); - } + assert_eq!(msg, String::from("msg\n")); + } - #[test] - fn test_hooks_commit_msg_reject_in_subfolder() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - // let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_hooks_commit_msg_reject_in_subfolder() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + // let repo_path = root.as_os_str().to_str().unwrap(); - let hook = b"#!/bin/sh + let hook = b"#!/bin/sh echo 'msg' > $1 echo 'rejected' exit 1 "; - create_hook(root, HOOK_COMMIT_MSG, hook); + create_hook(root, HOOK_COMMIT_MSG, hook); - let subfolder = root.join("foo/"); - fs::create_dir_all(&subfolder).unwrap(); + let subfolder = root.join("foo/"); + fs::create_dir_all(&subfolder).unwrap(); - let mut msg = String::from("test"); - let res = - hooks_commit_msg(subfolder.to_str().unwrap(), &mut msg) - .unwrap(); + let mut msg = String::from("test"); + let res = + hooks_commit_msg(subfolder.to_str().unwrap(), &mut msg) + .unwrap(); - assert_eq!( - res, - HookResult::NotOk(String::from("rejected\n")) - ); + assert_eq!( + res, + HookResult::NotOk(String::from("rejected\n")) + ); - assert_eq!(msg, String::from("msg\n")); - } + assert_eq!(msg, String::from("msg\n")); + } - #[test] - fn test_commit_msg_no_block_but_alter() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); + #[test] + fn test_commit_msg_no_block_but_alter() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); - let hook = b"#!/bin/sh + let hook = b"#!/bin/sh echo 'msg' > $1 exit 0 "; - create_hook(root, HOOK_COMMIT_MSG, hook); + create_hook(root, HOOK_COMMIT_MSG, hook); - let mut msg = String::from("test"); - let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); + let mut msg = String::from("test"); + let res = hooks_commit_msg(repo_path, &mut msg).unwrap(); - assert_eq!(res, HookResult::Ok); - assert_eq!(msg, String::from("msg\n")); - } + assert_eq!(res, HookResult::Ok); + assert_eq!(msg, String::from("msg\n")); + } - #[test] - fn test_post_commit_hook_reject_in_subfolder() { - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); + #[test] + fn test_post_commit_hook_reject_in_subfolder() { + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); - let hook = b"#!/bin/sh + let hook = b"#!/bin/sh echo 'rejected' exit 1 "; - create_hook(root, HOOK_POST_COMMIT, hook); + create_hook(root, HOOK_POST_COMMIT, hook); - let subfolder = root.join("foo/"); - fs::create_dir_all(&subfolder).unwrap(); + let subfolder = root.join("foo/"); + fs::create_dir_all(&subfolder).unwrap(); - let res = - hooks_post_commit(subfolder.to_str().unwrap()).unwrap(); + let res = + hooks_post_commit(subfolder.to_str().unwrap()).unwrap(); - assert_eq!( - res, - HookResult::NotOk(String::from("rejected\n")) - ); - } + assert_eq!( + res, + HookResult::NotOk(String::from("rejected\n")) + ); + } } |