Skip to content

Commit 9f59ca4

Browse files
seraphiregitster
authored andcommitted
git-p4: create new function run_git_hook
This commit is in preparation of introducing new p4 submit hooks. The current code in the python script git-p4.py makes the assumption that the git hooks can be executed by subprocess.call() function. However, when git is run on Windows, this may not work as expected. The subprocess.call() does not cover all the use cases for properly executing the various types of executable files on Windows. Prepare for remediation by adding a new function, run_git_hook, that takes 2 parameters: * the short filename of an optionally registered git hook * an optional list of parameters The run_git_hook function will honor the existing behavior seen in the current code for executing the p4-pre-submit hook: * Hooks are looked for in core.hooksPath directory. * If core.hooksPath is not set, then the current .git/hooks directory is checked. * If the hook does not exist, the function returns True. * If the hook file is not accessible, the function returns True. * If the hook returns a zero exit code when executed, the function return True. * If the hook returns a non-zero exit code, the function returns False. Add the following additional functionality if git-p4.py is run on Windows. * If hook file is not located without an extension, search for any file in the associated hook directory (from the list above) that has the same name but with an extension. * If the file is still not found, return True (the hook is missing) Add a new function run_hook_command() that wraps the OS dependent functionality for actually running the subprocess.call() with OS dependent behavior: If a hook file exists on Windows: * If there is no extension, set the launch executable to be SH.EXE - Look for SH.EXE under the environmental variable EXEPATH in the bin/ directory. - If %EXEPATH%/bin/sh.exe exists, use this as the actual executable. - If %EXEPATH%/bin/sh.exe does not exist, use sh.exe - Execute subprocess.call() without the shell (shell=False) * If there is an extension, execute subprocess.call() with teh shell (shell=True) and consider the file to be the executable. The return value from run_hook_command() is the subprocess.call() return value. These functions are added in this commit, but are only staged and not yet used. Signed-off-by: Ben Keene <seraphire@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 6b602a2 commit 9f59ca4

File tree

1 file changed

+69
-7
lines changed

1 file changed

+69
-7
lines changed

git-p4.py

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import zlib
2727
import ctypes
2828
import errno
29+
import glob
2930

3031
# support basestring in python3
3132
try:
@@ -185,6 +186,73 @@ def prompt(prompt_text):
185186
if response in choices:
186187
return response
187188

189+
def run_git_hook(cmd, param=[]):
190+
"""Execute a hook if the hook exists."""
191+
if verbose:
192+
sys.stderr.write("Looking for hook: %s\n" % cmd)
193+
sys.stderr.flush()
194+
195+
hooks_path = gitConfig("core.hooksPath")
196+
if len(hooks_path) <= 0:
197+
hooks_path = os.path.join(os.environ["GIT_DIR"], "hooks")
198+
199+
if not isinstance(param, list):
200+
param=[param]
201+
202+
# resolve hook file name, OS depdenent
203+
hook_file = os.path.join(hooks_path, cmd)
204+
if platform.system() == 'Windows':
205+
if not os.path.isfile(hook_file):
206+
# look for the file with an extension
207+
files = glob.glob(hook_file + ".*")
208+
if not files:
209+
return True
210+
files.sort()
211+
hook_file = files.pop()
212+
while hook_file.upper().endswith(".SAMPLE"):
213+
# The file is a sample hook. We don't want it
214+
if len(files) > 0:
215+
hook_file = files.pop()
216+
else:
217+
return True
218+
219+
if not os.path.isfile(hook_file) or not os.access(hook_file, os.X_OK):
220+
return True
221+
222+
return run_hook_command(hook_file, param) == 0
223+
224+
def run_hook_command(cmd, param):
225+
"""Executes a git hook command
226+
cmd = the command line file to be executed. This can be
227+
a file that is run by OS association.
228+
229+
param = a list of parameters to pass to the cmd command
230+
231+
On windows, the extension is checked to see if it should
232+
be run with the Git for Windows Bash shell. If there
233+
is no file extension, the file is deemed a bash shell
234+
and will be handed off to sh.exe. Otherwise, Windows
235+
will be called with the shell to handle the file assocation.
236+
237+
For non Windows operating systems, the file is called
238+
as an executable.
239+
"""
240+
cli = [cmd] + param
241+
use_shell = False
242+
if platform.system() == 'Windows':
243+
(root,ext) = os.path.splitext(cmd)
244+
if ext == "":
245+
exe_path = os.environ.get("EXEPATH")
246+
if exe_path is None:
247+
exe_path = ""
248+
else:
249+
exe_path = os.path.join(exe_path, "bin")
250+
cli = [os.path.join(exe_path, "SH.EXE")] + cli
251+
else:
252+
use_shell = True
253+
return subprocess.call(cli, shell=use_shell)
254+
255+
188256
def write_pipe(c, stdin):
189257
if verbose:
190258
sys.stderr.write('Writing pipe: %s\n' % str(c))
@@ -2337,12 +2405,7 @@ def run(self, args):
23372405
sys.exit("number of commits (%d) must match number of shelved changelist (%d)" %
23382406
(len(commits), num_shelves))
23392407

2340-
hooks_path = gitConfig("core.hooksPath")
2341-
if len(hooks_path) <= 0:
2342-
hooks_path = os.path.join(os.environ.get("GIT_DIR", ".git"), "hooks")
2343-
2344-
hook_file = os.path.join(hooks_path, "p4-pre-submit")
2345-
if os.path.isfile(hook_file) and os.access(hook_file, os.X_OK) and subprocess.call([hook_file]) != 0:
2408+
if not run_git_hook("p4-pre-submit"):
23462409
sys.exit(1)
23472410

23482411
#
@@ -4124,7 +4187,6 @@ def printUsage(commands):
41244187
"unshelve" : P4Unshelve,
41254188
}
41264189

4127-
41284190
def main():
41294191
if len(sys.argv[1:]) == 0:
41304192
printUsage(commands.keys())

0 commit comments

Comments
 (0)