Fix commit hooks error and "no such file" error on Windows with wsl2 installed. (#1532)

* use git bash instead of wsl bash
* add unittest for some simple shell commands.
* fix incompatible unitest with macOS
This commit is contained in:
hamflx 2023-02-02 17:33:57 +08:00 committed by GitHub
parent 0e0cdb327b
commit 5411397f9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 2 deletions

View file

@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* crash on branches popup in small terminal ([#1470](https://github.com/extrawurst/gitui/issues/1470))
* `edit` command duplication ([#1489](https://github.com/extrawurst/gitui/issues/1489))
* syntax errors in `key_bindings.ron` will be logged ([#1491](https://github.com/extrawurst/gitui/issues/1491))
* commit hooks report "command not found" on Windows with wsl2 installed ([#1528](https://github.com/extrawurst/gitui/issues/1528))
### Changed
* minimum supported rust version bumped to 1.64 (thank you `clap`)

View file

@ -66,11 +66,15 @@ impl HookPaths {
/// see <https://git-scm.com/docs/githooks>
pub fn run_hook(&self, args: &[&str]) -> Result<HookResult> {
let arg_str = format!("{:?} {}", self.hook, args.join(" "));
let bash_args = vec!["-c".to_string(), arg_str];
// Use -l to avoid "command not found" on Windows.
let bash_args =
vec!["-l".to_string(), "-c".to_string(), arg_str];
log::trace!("run hook '{:?}' in '{:?}'", self.hook, self.pwd);
let output = Command::new("bash")
let git_bash = find_bash_executable()
.unwrap_or_else(|| PathBuf::from("bash"));
let output = Command::new(git_bash)
.args(bash_args)
.current_dir(&self.pwd)
// This call forces Command to handle the Path environment correctly on windows,
@ -184,6 +188,29 @@ const fn is_executable(_: &Path) -> bool {
true
}
// Find bash.exe, and avoid finding wsl's bash.exe on Windows.
// None for non-Windows.
fn find_bash_executable() -> Option<PathBuf> {
if cfg!(windows) {
Command::new("where.exe")
.arg("git")
.output()
.ok()
.map(|out| {
PathBuf::from(Into::<String>::into(
String::from_utf8_lossy(&out.stdout),
))
})
.as_deref()
.and_then(Path::parent)
.and_then(Path::parent)
.map(|p| p.join("usr/bin/bash.exe"))
.filter(|p| p.exists())
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -257,6 +284,29 @@ exit 0
assert_eq!(msg, String::from("test"));
}
#[test]
fn test_hooks_commit_msg_with_shell_command_ok() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path: &RepoPath =
&root.as_os_str().to_str().unwrap().into();
let hook = br#"#!/bin/sh
COMMIT_MSG="$(cat "$1")"
printf "$COMMIT_MSG" | sed 's/sth/shell_command/g' >"$1"
exit 0
"#;
create_hook(repo_path, HOOK_COMMIT_MSG, hook);
let mut msg = String::from("test_sth");
let res = hooks_commit_msg(repo_path, &mut msg).unwrap();
assert_eq!(res, HookResult::Ok);
assert_eq!(msg, String::from("test_shell_command"));
}
#[test]
fn test_pre_commit_sh() {
let (_td, repo) = repo_init().unwrap();