Skip to content

Adding setup for git executable #640

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Prev Previous commit
Next Next commit
Moved setup function into top level __init__
Discovered that the remote module also relies on the git executable as
such it also needs to be “refreshed” anytime the git executable is
updated or changed. This was best solved by moving the setup function
into the top level __init__ where the setup simply calls
git.cmd.Git.refresh and git.remote.FetchInfo.refresh.
  • Loading branch information
kenodegard committed Jul 9, 2017
commit feed81ea1a332dc415ea9010c8b5204473a51bdf
17 changes: 17 additions & 0 deletions git/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,20 @@ def _init_externals():

__all__ = [name for name, obj in locals().items()
if not (name.startswith('_') or inspect.ismodule(obj))]

#{ Initialize git executable path
def setup(path=None):
"""Convenience method for setting the git executable path."""
if not Git.refresh(path=path):
return
if not FetchInfo.refresh():
return

def refresh(path=None):
"""Convenience method for refreshing the git executable path."""
setup(path=path)
#} END initialize git executable path

#################
setup()
#################
54 changes: 20 additions & 34 deletions git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,61 +190,60 @@ def __setstate__(self, d):
USE_SHELL = False

# Provide the full path to the git executable. Otherwise it assumes git is in the path
@classmethod
def refresh(cls, path=None):
"""Convenience method for refreshing the git executable path."""
cls.setup(path=path)
_git_exec_env_var = "GIT_PYTHON_GIT_EXECUTABLE"
GIT_PYTHON_GIT_EXECUTABLE = None
# note that the git executable is actually found during the setup step in
# the top level __init__

@classmethod
def setup(cls, path=None):
"""Convenience method for setting the git executable path."""
def refresh(cls, path=None):
"""This gets called by the setup function (see the top level __init__).
"""
# discern which path to refresh with
if path is not None:
# use the path the user gave
os.environ[cls._git_exec_env_var] = path
elif cls._git_exec_env_var in os.environ:
# fall back to the environment variable that's already set
pass
new_git = os.path.abspath(path)
else:
# hope that git can be found on the user's $PATH
pass
new_git = os.environ.get(cls._git_exec_env_var, cls.git_exec_name)

# keep track of the old and new git executable path
old_git = cls.GIT_PYTHON_GIT_EXECUTABLE
new_git = os.environ.get(cls._git_exec_env_var, cls.git_exec_name)
cls.GIT_PYTHON_GIT_EXECUTABLE = new_git

# test if the new git executable path is valid
has_git = False
try:
cls().version()
has_git = True
except GitCommandNotFound:
pass

# warn or raise exception if test failed
if not has_git:
err = dedent("""\
Bad git executable. The git executable must be specified in one of the following ways:
(1) be included in your $PATH, or
(2) be set via $GIT_PYTHON_GIT_EXECUTABLE, or
(3) explicitly call git.cmd.setup with the full path.
(3) explicitly set via git.setup (or git.refresh).
""")

if old_git is None:
# on the first setup (when GIT_PYTHON_GIT_EXECUTABLE is
# None) we only warn the user and simply set the default
# executable
cls.GIT_PYTHON_GIT_EXECUTABLE = cls.git_exec_name
print("WARNING: %s" % err)
print(dedent("""\
WARNING: %s
All git commands will error until this is rectified.
""") % err)
else:
# after the first setup (when GIT_PYTHON_GIT_EXECUTABLE
# is no longer None) we raise an exception and reset the
# GIT_PYTHON_GIT_EXECUTABLE to whatever the value was
# previously
cls.GIT_PYTHON_GIT_EXECUTABLE = old_name
cls.GIT_PYTHON_GIT_EXECUTABLE = old_git
raise GitCommandNotFound("git", err)

_git_exec_env_var = "GIT_PYTHON_GIT_EXECUTABLE"
# immediately set with the default value ("git")
GIT_PYTHON_GIT_EXECUTABLE = None
# see the setup performed below
return has_git

@classmethod
def is_cygwin(cls):
Expand Down Expand Up @@ -1024,16 +1023,3 @@ def clear_cache(self):
self.cat_file_all = None
self.cat_file_header = None
return self



# this is where the git executable is setup
def setup(path=None):
Git.setup(path=path)


def refresh(path=None):
Git.refresh(path=path)


setup()
40 changes: 30 additions & 10 deletions git/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,37 @@ class FetchInfo(object):

re_fetch_result = re.compile(r'^\s*(.) (\[?[\w\s\.$@]+\]?)\s+(.+) -> ([^\s]+)( \(.*\)?$)?')

_flag_map = {'!': ERROR,
'+': FORCED_UPDATE,
'*': 0,
'=': HEAD_UPTODATE,
' ': FAST_FORWARD}
_flag_map = {
'!': ERROR,
'+': FORCED_UPDATE,
'*': 0,
'=': HEAD_UPTODATE,
' ': FAST_FORWARD,
'-': TAG_UPDATE,
}

v = Git().version_info[:2]
if v >= (2, 10):
_flag_map['t'] = TAG_UPDATE
else:
_flag_map['-'] = TAG_UPDATE
@classmethod
def refresh(cls):
"""This gets called by the setup function (see the top level __init__).
"""
# clear the old values in _flag_map
try:
del cls._flag_map["t"]
except KeyError:
pass

try:
del cls._flag_map["-"]
except KeyError:
pass

# set the value given the git version
if Git().version_info[:2] >= (2, 10):
cls._flag_map["t"] = cls.TAG_UPDATE
else:
cls._flag_map["-"] = cls.TAG_UPDATE

return True

def __init__(self, ref, flags, note='', old_commit=None, remote_ref_path=None):
"""
Expand Down