diff options
Diffstat (limited to 'lib/git')
-rw-r--r-- | lib/git/cmd.py | 20 | ||||
-rw-r--r-- | lib/git/index.py | 14 | ||||
-rw-r--r-- | lib/git/objects/base.py | 2 | ||||
-rw-r--r-- | lib/git/refs.py | 12 | ||||
-rw-r--r-- | lib/git/remote.py | 2 | ||||
-rw-r--r-- | lib/git/repo.py | 64 | ||||
-rw-r--r-- | lib/git/utils.py | 15 |
7 files changed, 86 insertions, 43 deletions
diff --git a/lib/git/cmd.py b/lib/git/cmd.py index b97381f4..9095eb34 100644 --- a/lib/git/cmd.py +++ b/lib/git/cmd.py @@ -43,6 +43,8 @@ class Git(object): of the command to stdout. Set its value to 'full' to see details about the returned values. """ + __slots__ = ("_working_dir", "cat_file_all", "cat_file_header") + class AutoInterrupt(object): """ Kill/Interrupt the stored process instance once this instance goes out of scope. It is @@ -92,18 +94,18 @@ class Git(object): - def __init__(self, git_dir=None): + def __init__(self, working_dir=None): """ Initialize this instance with: - ``git_dir`` + ``working_dir`` Git directory we should work in. If None, we always work in the current directory as returned by os.getcwd(). It is meant to be the working tree directory if available, or the .git directory in case of bare repositories. """ super(Git, self).__init__() - self.git_dir = git_dir + self._working_dir = working_dir # cached command slots self.cat_file_header = None @@ -121,12 +123,12 @@ class Git(object): return lambda *args, **kwargs: self._call_process(name, *args, **kwargs) @property - def get_dir(self): + def working_dir(self): """ Returns Git directory we are working on """ - return self.git_dir + return self._working_dir def execute(self, command, istream=None, @@ -150,8 +152,8 @@ class Git(object): ``with_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. + The cmd otherwise uses its own working_dir that it has been initialized + with if possible. ``with_extended_output`` Whether to return a (status, stdout, stderr) tuple. @@ -198,10 +200,10 @@ class Git(object): print ' '.join(command) # Allow the user to have the command executed in their working dir. - if with_keep_cwd or self.git_dir is None: + if with_keep_cwd or self._working_dir is None: cwd = os.getcwd() else: - cwd=self.git_dir + cwd=self._working_dir # Start the process proc = subprocess.Popen(command, diff --git a/lib/git/index.py b/lib/git/index.py index 9effd3cd..3c895a78 100644 --- a/lib/git/index.py +++ b/lib/git/index.py @@ -325,7 +325,7 @@ class IndexFile(LazyMixin, diff.Diffable): super(IndexFile, self)._set_cache_(attr) def _index_path(self): - return join_path_native(self.repo.path, "index") + return join_path_native(self.repo.git_dir, "index") @property @@ -539,7 +539,7 @@ class IndexFile(LazyMixin, diff.Diffable): # tmp file created in git home directory to be sure renaming # works - /tmp/ dirs could be on another device - tmp_index = tempfile.mktemp('','',repo.path) + tmp_index = tempfile.mktemp('','',repo.git_dir) arg_list.append("--index-output=%s" % tmp_index) arg_list.extend(treeish) @@ -547,7 +547,7 @@ class IndexFile(LazyMixin, diff.Diffable): # as it considers existing entries. moving it essentially clears the index. # Unfortunately there is no 'soft' way to do it. # The _TemporaryFileSwap assure the original file get put back - index_handler = _TemporaryFileSwap(join_path_native(repo.path, 'index')) + index_handler = _TemporaryFileSwap(join_path_native(repo.git_dir, 'index')) try: repo.git.read_tree(*arg_list, **kwargs) index = cls(repo, tmp_index) @@ -579,7 +579,7 @@ class IndexFile(LazyMixin, diff.Diffable): return ret - # UTILITIES + # UTILITIES def _iter_expand_paths(self, paths): """Expand the directories in list of paths to the corresponding paths accordingly, @@ -588,7 +588,7 @@ class IndexFile(LazyMixin, diff.Diffable): times - we respect that and do not prune""" def raise_exc(e): raise e - r = self.repo.git.git_dir + r = self.repo.working_tree_dir rs = r + '/' for path in paths: abs_path = path @@ -798,9 +798,9 @@ class IndexFile(LazyMixin, diff.Diffable): """ if not os.path.isabs(path): return path - relative_path = path.replace(self.repo.git.git_dir+os.sep, "") + relative_path = path.replace(self.repo.working_tree_dir+os.sep, "") if relative_path == path: - raise ValueError("Absolute path %r is not in git repository at %r" % (path,self.repo.git.git_dir)) + raise ValueError("Absolute path %r is not in git repository at %r" % (path,self.repo.working_tree_dir)) return relative_path def _preprocess_add_items(self, items): diff --git a/lib/git/objects/base.py b/lib/git/objects/base.py index ddd03400..8d6860de 100644 --- a/lib/git/objects/base.py +++ b/lib/git/objects/base.py @@ -223,5 +223,5 @@ class IndexObject(Object): The returned path will be native to the system and contains '\' on windows. """ - return join_path_native(self.repo.git.git_dir, self.path) + return join_path_native(self.repo.working_tree_dir, self.path) diff --git a/lib/git/refs.py b/lib/git/refs.py index cf829cb6..f826691d 100644 --- a/lib/git/refs.py +++ b/lib/git/refs.py @@ -52,7 +52,7 @@ class SymbolicReference(object): return self.path def _get_path(self): - return join_path_native(self.repo.path, self.path) + return join_path_native(self.repo.git_dir, self.path) @classmethod def _iter_packed_refs(cls, repo): @@ -60,7 +60,7 @@ class SymbolicReference(object): refs. NOTE: The packed refs file will be kept open as long as we iterate""" try: - fp = open(os.path.join(repo.path, 'packed-refs'), 'r') + fp = open(os.path.join(repo.git_dir, 'packed-refs'), 'r') for line in fp: line = line.strip() if not line: @@ -258,7 +258,7 @@ class SymbolicReference(object): Alternatively the symbolic reference to be deleted """ full_ref_path = cls._to_full_path(repo, path) - abs_path = os.path.join(repo.path, full_ref_path) + abs_path = os.path.join(repo.git_dir, full_ref_path) if os.path.exists(abs_path): os.remove(abs_path) @@ -271,7 +271,7 @@ class SymbolicReference(object): instead""" full_ref_path = cls._to_full_path(repo, path) - abs_ref_path = os.path.join(repo.path, full_ref_path) + abs_ref_path = os.path.join(repo.git_dir, full_ref_path) if not force and os.path.isfile(abs_ref_path): raise OSError("Reference at %s does already exist" % full_ref_path) @@ -401,10 +401,10 @@ class Reference(SymbolicReference, LazyMixin, Iterable): # walk loose refs # Currently we do not follow links - for root, dirs, files in os.walk(join_path_native(repo.path, common_path)): + for root, dirs, files in os.walk(join_path_native(repo.git_dir, common_path)): for f in files: abs_path = to_native_path_linux(join_path(root, f)) - rela_paths.add(abs_path.replace(to_native_path_linux(repo.path) + '/', "")) + rela_paths.add(abs_path.replace(to_native_path_linux(repo.git_dir) + '/', "")) # END for each file in root directory # END for each directory to walk diff --git a/lib/git/remote.py b/lib/git/remote.py index 5eddfa2d..e1d0d743 100644 --- a/lib/git/remote.py +++ b/lib/git/remote.py @@ -575,7 +575,7 @@ class Remote(LazyMixin, Iterable): err_info = stderr.splitlines()[1:] # read head information - fp = open(os.path.join(self.repo.path, 'FETCH_HEAD'),'r') + fp = open(os.path.join(self.repo.git_dir, 'FETCH_HEAD'),'r') fetch_head_info = fp.readlines() fp.close() diff --git a/lib/git/repo.py b/lib/git/repo.py index 3250230e..333b71de 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -41,9 +41,19 @@ class Repo(object): Represents a git repository and allows you to query references, gather commit information, generate diffs, create and clone repositories query the log. + + The following attributes are worth using: + + 'working_dir' is the working directory of the git command, wich is the working tree + directory if available or the .git directory in case of bare repositories + + 'working_tree_dir' is the working tree directory, but will raise AssertionError + if we are a bare repository. + + 'git_dir' is the .git repository directoy, which is always set. """ DAEMON_EXPORT_FILE = 'git-daemon-export-ok' - __slots__ = ( "wd", "path", "_bare", "git" ) + __slots__ = ( "working_dir", "_working_tree_dir", "git_dir", "_bare", "git" ) # precompiled regex re_whitespace = re.compile(r'\s+') @@ -81,26 +91,28 @@ class Repo(object): if not os.path.exists(epath): raise NoSuchPathError(epath) - self.path = None + self.working_dir = None + self._working_tree_dir = None + self.git_dir = None curpath = epath # walk up the path to find the .git dir while curpath: if is_git_dir(curpath): - self.path = curpath - self.wd = os.path.dirname(curpath) + self.git_dir = curpath + self._working_tree_dir = os.path.dirname(curpath) break gitpath = os.path.join(curpath, '.git') if is_git_dir(gitpath): - self.path = gitpath - self.wd = curpath + self.git_dir = gitpath + self._working_tree_dir = curpath break curpath, dummy = os.path.split(curpath) if not dummy: break # END while curpath - if self.path is None: + if self.git_dir is None: raise InvalidGitRepositoryError(epath) self._bare = False @@ -113,17 +125,19 @@ class Repo(object): # adjust the wd in case we are actually bare - we didn't know that # in the first place if self._bare: - self.wd = self.path - - self.git = Git(self.wd) + self._working_tree_dir = None + # END working dir handling + + self.working_dir = self._working_tree_dir or self.git_dir + self.git = Git(self.working_dir) # Description property def _get_description(self): - filename = os.path.join(self.path, 'description') + filename = os.path.join(self.git_dir, 'description') return file(filename).read().rstrip() def _set_description(self, descr): - filename = os.path.join(self.path, 'description') + filename = os.path.join(self.git_dir, 'description') file(filename, 'w').write(descr+'\n') description = property(_get_description, _set_description, @@ -131,6 +145,18 @@ class Repo(object): del _get_description del _set_description + @property + def working_tree_dir(self): + """ + Returns + The working tree directory of our git repository + + Raises AssertionError + If we are a bare repository + """ + if self._working_tree_dir is None: + raise AssertionError( "Repository at %r is bare and does not have a working tree directory" % self.git_dir ) + return self._working_tree_dir @property def bare(self): @@ -286,7 +312,7 @@ class Repo(object): elif config_level == "global": return os.path.expanduser("~/.gitconfig") elif config_level == "repository": - return "%s/config" % self.path + return "%s/config" % self.git_dir raise ValueError( "Invalid configuration level: %r" % config_level ) @@ -413,11 +439,11 @@ class Repo(object): return Commit.iter_items(self, rev, paths, **kwargs) def _get_daemon_export(self): - filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) + filename = os.path.join(self.git_dir, self.DAEMON_EXPORT_FILE) return os.path.exists(filename) def _set_daemon_export(self, value): - filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) + filename = os.path.join(self.git_dir, self.DAEMON_EXPORT_FILE) fileexists = os.path.exists(filename) if value and not fileexists: touch(filename) @@ -436,7 +462,7 @@ class Repo(object): Returns list of strings being pathnames of alternates """ - alternates_path = os.path.join(self.path, 'objects', 'info', 'alternates') + alternates_path = os.path.join(self.git_dir, 'objects', 'info', 'alternates') if os.path.exists(alternates_path): try: @@ -466,7 +492,7 @@ class Repo(object): Returns None """ - alternates_path = os.path.join(self.path, 'objects', 'info', 'alternates') + alternates_path = os.path.join(self.git_dir, 'objects', 'info', 'alternates') if not alts: if os.path.isfile(alternates_path): os.remove(alternates_path) @@ -706,7 +732,7 @@ class Repo(object): # END windows handling try: - self.git.clone(self.path, path, **kwargs) + self.git.clone(self.git_dir, path, **kwargs) finally: if prev_cwd is not None: os.chdir(prev_cwd) @@ -754,4 +780,4 @@ class Repo(object): return self def __repr__(self): - return '<git.Repo "%s">' % self.path + return '<git.Repo "%s">' % self.git_dir diff --git a/lib/git/utils.py b/lib/git/utils.py index 5deed556..433f96d5 100644 --- a/lib/git/utils.py +++ b/lib/git/utils.py @@ -362,3 +362,18 @@ class Iterable(object): """ raise NotImplementedError("To be implemented by Subclass") +def needs_working_tree(func): + """ + Decorator assuring the wrapped method may only run if the repository has a + working tree, hence it is not bare. + """ + def check_default_index(self, *args, **kwargs): + if self.repo.working_tree_dir is None: + raise AssertionError( "Cannot call %r bare git repositories" % func.__name__ ) + return func(self, *args, **kwargs) + # END wrpaper method + + check_default_index.__name__ = func.__name__ + return check_default_index + + |