diff --git a/doc/source/changes.rst b/doc/source/changes.rst index 35c2f15c3..99b578bd8 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -12,6 +12,11 @@ Changelog these operations to never raise. However, that behavious is undesirable as it would effectively hide the fact that there was an error. See `this issue `_ for more information. +* If the git executable can't be found in the PATH or at the path provided by `GIT_PYTHON_GIT_EXECUTABLE`, this is made + obvious by throwing `GitCommandNotFound`, both on unix and on windows. + + - Those who support **GUI on windows** will now have to set `git.Git.USE_SHELL = True` to get the previous behaviour. + 0.3.6 - Features ================ * **DOCS** diff --git a/git/cmd.py b/git/cmd.py index 911bb9f36..429046be1 100644 --- a/git/cmd.py +++ b/git/cmd.py @@ -26,7 +26,10 @@ stream_copy, WaitGroup ) -from .exc import GitCommandError +from .exc import ( + GitCommandError, + GitCommandNotFound +) from git.compat import ( string_types, defenc, @@ -241,6 +244,12 @@ class Git(LazyMixin): _git_exec_env_var = "GIT_PYTHON_GIT_EXECUTABLE" GIT_PYTHON_GIT_EXECUTABLE = os.environ.get(_git_exec_env_var, git_exec_name) + # If True, a shell will be used when executing git commands. + # This should only be desirable on windows, see https://github.com/gitpython-developers/GitPython/pull/126 + # for more information + # Override this value using `Git.USE_SHELL = True` + USE_SHELL = False + class AutoInterrupt(object): """Kill/Interrupt the stored process instance once this instance goes out of scope. It is @@ -543,18 +552,29 @@ def execute(self, command, env["LC_MESSAGES"] = "C" env.update(self._environment) - proc = Popen(command, - env=env, - cwd=cwd, - stdin=istream, - stderr=PIPE, - stdout=PIPE, - # Prevent cmd prompt popups on windows by using a shell ... . - # See https://github.com/gitpython-developers/GitPython/pull/126 - shell=sys.platform == 'win32', - close_fds=(os.name == 'posix'), # unsupported on windows - **subprocess_kwargs - ) + if sys.platform == 'win32': + cmd_not_found_exception = WindowsError + else: + if sys.version_info[0] > 2: + cmd_not_found_exception = FileNotFoundError # NOQA # this is defined, but flake8 doesn't know + else: + cmd_not_found_exception = OSError + # end handle + + try: + proc = Popen(command, + env=env, + cwd=cwd, + stdin=istream, + stderr=PIPE, + stdout=PIPE, + shell=self.USE_SHELL, + close_fds=(os.name == 'posix'), # unsupported on windows + **subprocess_kwargs + ) + except cmd_not_found_exception as err: + raise GitCommandNotFound(str(err)) + if as_process: return self.AutoInterrupt(proc, command) diff --git a/git/exc.py b/git/exc.py index 7ee6726e8..f5b52374b 100644 --- a/git/exc.py +++ b/git/exc.py @@ -18,6 +18,12 @@ class NoSuchPathError(OSError): """ Thrown if a path could not be access by the system. """ +class GitCommandNotFound(Exception): + """Thrown if we cannot find the `git` executable in the PATH or at the path given by + the GIT_PYTHON_GIT_EXECUTABLE environment variable""" + pass + + class GitCommandError(Exception): """ Thrown if execution of the git command fails with non-zero status code. """