summaryrefslogtreecommitdiff
path: root/lib/git/cmd.py
diff options
context:
space:
mode:
authorFlorian Apolloner <florian@apolloner.eu>2008-06-20 22:46:11 +0200
committerFlorian Apolloner <florian@apolloner.eu>2008-06-20 22:46:11 +0200
commit66beac619ba944afeca9d15c56ccc60d5276a799 (patch)
treeb73e11c8fb9c91785fceb022759660d12d373b78 /lib/git/cmd.py
parent93e19791659c279f4f7e33a433771beca65bf9ea (diff)
parent3980f11a9411d0b487b73279346cfae938845e7a (diff)
downloadgitpython-66beac619ba944afeca9d15c56ccc60d5276a799.tar.gz
Merge branch 'master' of git://gitorious.org/git-python/david into bisect
Diffstat (limited to 'lib/git/cmd.py')
-rw-r--r--lib/git/cmd.py114
1 files changed, 81 insertions, 33 deletions
diff --git a/lib/git/cmd.py b/lib/git/cmd.py
index cf0f066d..029fcbc9 100644
--- a/lib/git/cmd.py
+++ b/lib/git/cmd.py
@@ -12,46 +12,72 @@ class Git(MethodMissingMixin):
"""
The Git class manages communication with the Git binary
"""
- def __init__(self, git_dir=None):
+ def __init__(self, git_dir=None, bare_repo=False):
super(Git, self).__init__()
if git_dir:
- self.find_git_dir(git_dir)
+ self._location = os.path.abspath(git_dir)
else:
- self.find_git_dir(os.getcwd())
-
- def find_git_dir(self, path):
- """Find the best value for self.git_dir.
- For bare repositories, this is the path to the bare repository.
- For repositories with work trees, this is the work tree path.
-
- When barerepo.git is passed in, self.git_dir = barerepo.git
- When worktree/.git is passed in, self.git_dir = worktree
- When worktree is passed in, self.git_dir = worktree
- """
-
- path = os.path.abspath(path)
- self.git_dir = path
-
- cdup = self.execute(["git", "rev-parse", "--show-cdup"])
- if cdup:
- path = os.path.abspath(os.path.join(self.git_dir, cdup))
- else:
- is_bare_repository =\
- self.rev_parse(is_bare_repository=True) == "true"
- is_inside_git_dir =\
- self.rev_parse(is_inside_git_dir=True) == "true"
-
- if not is_bare_repository and is_inside_git_dir:
- path = os.path.dirname(self.git_dir)
-
- self.git_dir = path
+ self._location = os.getcwd()
+ self._is_bare_repo = bare_repo
+ self.refresh()
+
+ def refresh(self):
+ self._git_dir = None
+ self._is_in_repo = not not self.get_git_dir()
+ self._work_tree = None
+ self._cwd = self._git_dir
+ if self._git_dir and not self._is_bare_repo:
+ self._cwd = self.get_work_tree()
+
+ def _is_git_dir(self, d):
+ """ This is taken from the git setup.c:is_git_directory
+ function."""
+
+ if os.path.isdir(d) and \
+ os.path.isdir(os.path.join(d, 'objects')) and \
+ os.path.isdir(os.path.join(d, 'refs')):
+ headref = os.path.join(d, 'HEAD')
+ return os.path.isfile(headref) or \
+ (os.path.islink(headref) and
+ os.readlink(headref).startswith('refs'))
+ return False
+
+ def get_git_dir(self):
+ if not self._git_dir:
+ self._git_dir = os.getenv('GIT_DIR')
+ if self._git_dir and self._is_git_dir(self._git_dir):
+ return self._git_dir
+ curpath = self._location
+ while curpath:
+ if self._is_git_dir(curpath):
+ self._git_dir = curpath
+ break
+ gitpath = os.path.join(curpath, '.git')
+ if self._is_git_dir(gitpath):
+ self._git_dir = gitpath
+ break
+ curpath, dummy = os.path.split(curpath)
+ if not dummy:
+ break
+ return self._git_dir
+
+ def get_work_tree(self):
+ if self._is_bare_repo:
+ return None
+ if not self._work_tree:
+ self._work_tree = os.getenv('GIT_WORK_TREE')
+ if not self._work_tree or not os.path.isdir(self._work_tree):
+ self._work_tree = os.path.abspath(
+ os.path.join(self._git_dir, '..'))
+ return self._work_tree
@property
def get_dir(self):
- return self.git_dir
+ return self._git_dir
def execute(self, command,
istream=None,
+ keep_cwd=False,
with_status=False,
with_stderr=False,
with_exceptions=False,
@@ -67,6 +93,11 @@ class Git(MethodMissingMixin):
``istream``
Standard input filehandle passed to subprocess.Popen.
+ ``keep_cwd``
+ Whether to use the current working directory from os.getcwd().
+ GitPython uses get_work_tree() as its working directory by
+ default and get_git_dir() for bare repositories.
+
``with_status``
Whether to return a (status, str) tuple.
@@ -94,9 +125,15 @@ class Git(MethodMissingMixin):
else:
stderr = subprocess.PIPE
+ # Allow the user to have the command executed in their working dir.
+ if keep_cwd:
+ cwd = os.getcwd()
+ else:
+ cwd=self._cwd
+
# Start the process
proc = subprocess.Popen(command,
- cwd=self.git_dir,
+ cwd=cwd,
stdin=istream,
stderr=stderr,
stdout=subprocess.PIPE
@@ -107,6 +144,10 @@ class Git(MethodMissingMixin):
status = proc.wait()
proc.stdout.close()
+ if proc.stderr:
+ stderr_value = proc.stderr.read()
+ proc.stderr.close()
+
# Strip off trailing whitespace by default
if not with_raw_output:
stdout_value = stdout_value.rstrip()
@@ -118,7 +159,12 @@ class Git(MethodMissingMixin):
% (str(command), status))
if GIT_PYTHON_TRACE == 'full':
- print "%s %d: '%s'" % (command, status, stdout_value)
+ if stderr_value:
+ print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value)
+ elif stdout_value:
+ print "%s -> %d: '%s'" % (command, status, stdout_value)
+ else:
+ print "%s -> %d" % (command, status)
# Allow access to the command's status code
if with_status:
@@ -170,6 +216,7 @@ class Git(MethodMissingMixin):
# Handle optional arguments prior to calling transform_kwargs
# otherwise these'll end up in args, which is bad.
istream = kwargs.pop("istream", None)
+ keep_cwd = kwargs.pop("keep_cwd", None)
with_status = kwargs.pop("with_status", None)
with_stderr = kwargs.pop("with_stderr", None)
with_exceptions = kwargs.pop("with_exceptions", None)
@@ -185,6 +232,7 @@ class Git(MethodMissingMixin):
return self.execute(call,
istream = istream,
+ keep_cwd = keep_cwd,
with_status = with_status,
with_stderr = with_stderr,
with_exceptions = with_exceptions,