From 85481459968bea0d45851dc16b8fb69c07c592be Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Wed, 12 Jan 2022 23:39:10 -0800 Subject: [PATCH] Use bash to open extensionless hooks on windows Fix #971. If the hook doesn't have a file extension, then Windows won't know how to run it and you'll get "[WinError 193] %1 is not a valid Win32 application". It's very likely that it's a shell script of some kind, so use bash.exe (commonly installed via Windows Subsystem for Linux). We don't want to run all hooks with bash because they could be .bat files. os.name [seems to be the best way to check for Windows][1] and it should certainly ensure we don't do this on other platforms. [1]: https://stackoverflow.com/questions/1325581/how-do-i-check-if-im-running-on-windows-in-python --- git/index/fun.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/git/index/fun.py b/git/index/fun.py index 16ec744e2..6093359b1 100644 --- a/git/index/fun.py +++ b/git/index/fun.py @@ -3,6 +3,7 @@ # NOTE: Autodoc hates it if this is a docstring from io import BytesIO +from pathlib import Path import os from stat import ( S_IFDIR, @@ -76,6 +77,10 @@ def hook_path(name: str, git_dir: PathLike) -> str: return osp.join(git_dir, 'hooks', name) +def _has_file_extension(path): + return osp.splitext(path)[1] + + def run_commit_hook(name: str, index: 'IndexFile', *args: str) -> None: """Run the commit hook of the given name. Silently ignores hooks that do not exist. :param name: name of hook, like 'pre-commit' @@ -89,8 +94,15 @@ def run_commit_hook(name: str, index: 'IndexFile', *args: str) -> None: env = os.environ.copy() env['GIT_INDEX_FILE'] = safe_decode(str(index.path)) env['GIT_EDITOR'] = ':' + cmd = [hp] try: - cmd = subprocess.Popen([hp] + list(args), + if os.name == "nt" and not _has_file_extension(hp): + # Windows only uses extensions to determine how to open files + # (doesn't understand shebangs). Try using bash to run the hook. + relative_hp = Path(hp).relative_to(index.repo.working_dir).as_posix() + cmd = ["bash.exe", relative_hp] + + cmd = subprocess.Popen(cmd + list(args), env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE,