diff options
-rw-r--r-- | lib/git/index/base.py | 23 | ||||
-rw-r--r-- | lib/git/index/util.py | 18 | ||||
-rw-r--r-- | lib/git/utils.py | 1 | ||||
-rw-r--r-- | test/git/test_index.py | 6 | ||||
-rw-r--r-- | test/testlib/helper.py | 17 |
5 files changed, 47 insertions, 18 deletions
diff --git a/lib/git/index/base.py b/lib/git/index/base.py index af45171b..771f1710 100644 --- a/lib/git/index/base.py +++ b/lib/git/index/base.py @@ -31,6 +31,7 @@ from util import ( TemporaryFileSwap, post_clear_cache, default_index, + git_working_dir ) import git.objects @@ -122,7 +123,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): # END exception handling stream = file_contents_ro(fd, stream=True, allow_mmap=True) - + try: self._deserialize(stream) finally: @@ -192,6 +193,10 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): automatically :return: self""" + # make sure we have our entries read before getting a write lock + # else it would be done when streaming. This can happen + # if one doesn't change the index, but writes it right away + self.entries lfd = LockedFD(file_path or self._file_path) stream = lfd.open(write=True, stream=True) @@ -345,7 +350,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): return S_IFLNK if S_ISDIR(mode) or S_IFMT(mode) == cls.S_IFGITLINK: # submodules return cls.S_IFGITLINK - return S_IFREG | 644 | (mode & 0100) # blobs with or without executable bit + return S_IFREG | 0644 | (mode & 0100) # blobs with or without executable bit # UTILITIES def _iter_expand_paths(self, paths): @@ -577,6 +582,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): # END for each item return (paths, entries) + @git_working_dir def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=None): """Add files from the working tree, specific blobs or BaseIndexEntries to the index. The underlying index file will be written immediately, hence @@ -688,7 +694,6 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): fprogress(filepath, False, filepath) istream = self.repo.odb.store(IStream(Blob.type, st.st_size, stream)) fprogress(filepath, True, filepath) - return BaseIndexEntry((self._stat_mode_to_index_mode(st.st_mode), istream.binsha, 0, filepath)) # END utility method @@ -706,8 +711,6 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): # HANDLE ENTRIES if entries: - # TODO: Add proper IndexEntries to ourselves, and write the index - # just once. Currently its done twice at least null_mode_entries = [ e for e in entries if e.mode == 0 ] if null_mode_entries: raise ValueError("At least one Entry has a null-mode - please use index.remove to remove files for clarity") @@ -750,6 +753,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): # add the new entries to this instance, and write it for entry in entries_added: self.entries[(entry.path, 0)] = IndexEntry.from_base(entry) + self.write() return entries_added @@ -902,8 +906,8 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): Returns Commit object representing the new commit """ - tree_sha = self.repo.git.write_tree() - return Commit.create_from_tree(self.repo, tree_sha, message, parent_commits, head) + tree = self.write_tree() + return Commit.create_from_tree(self.repo, tree, message, parent_commits, head) @classmethod def _flush_stdin_and_wait(cls, proc, ignore_stdout = False): @@ -1012,6 +1016,11 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): if isinstance(paths, basestring): paths = [paths] + # make sure we have our entries loaded before we start checkout_index + # which will hold a lock on it. We try to get the lock as well during + # our entries initialization + self.entries + args.append("--stdin") kwargs['as_process'] = True kwargs['istream'] = subprocess.PIPE diff --git a/lib/git/index/util.py b/lib/git/index/util.py index c9fb1922..bd5fcc03 100644 --- a/lib/git/index/util.py +++ b/lib/git/index/util.py @@ -3,7 +3,7 @@ import struct import tempfile import os -__all__ = ( 'TemporaryFileSwap', 'post_clear_cache', 'default_index' ) +__all__ = ( 'TemporaryFileSwap', 'post_clear_cache', 'default_index', 'git_working_dir' ) #{ Aliases pack = struct.pack @@ -67,4 +67,20 @@ def default_index(func): check_default_index.__name__ = func.__name__ return check_default_index +def git_working_dir(func): + """Decorator which changes the current working dir to the one of the git + repository in order to assure relative paths are handled correctly""" + def set_git_working_dir(self, *args, **kwargs): + cur_wd = os.getcwd() + os.chdir(self.repo.working_tree_dir) + try: + return func(self, *args, **kwargs) + finally: + os.chdir(cur_wd) + # END handle working dir + # END wrapper + + set_git_working_dir.__name__ = func.__name__ + return set_git_working_dir + #} END decorators diff --git a/lib/git/utils.py b/lib/git/utils.py index 38501292..7dd50621 100644 --- a/lib/git/utils.py +++ b/lib/git/utils.py @@ -11,7 +11,6 @@ import tempfile from gitdb.util import ( make_sha, - FDStreamWrapper, LockedFD, file_contents_ro, LazyMixin, diff --git a/test/git/test_index.py b/test/git/test_index.py index 35580135..929d40a3 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -182,6 +182,9 @@ class TestIndex(TestBase): index.write() assert rw_repo.index.entries[manifest_key].hexsha == Diff.NULL_HEX_SHA + # write an unchanged index ( just for the fun of it ) + rw_repo.index.write() + # a three way merge would result in a conflict and fails as the command will # not overwrite any entries in our index and hence leave them unmerged. This is # mainly a protection feature as the current index is not yet in a tree @@ -432,6 +435,7 @@ class TestIndex(TestBase): # same file entries = index.reset(new_commit).add(['lib/git/head.py']*2, fprogress=self._fprogress_add) + assert entries[0].mode & 0644 == 0644 # would fail, test is too primitive to handle this case # self._assert_fprogress(entries) self._reset_progress() @@ -574,7 +578,7 @@ class TestIndex(TestBase): @with_rw_repo('HEAD') def test_compare_write_tree(self, rw_repo): def write_tree(index): - tree_sha = index.repo.git.write_tree(missing_ok=True) + tree_sha = index.write_tree().sha return Tree(index.repo, tree_sha, 0, '') # END git cmd write tree diff --git a/test/testlib/helper.py b/test/testlib/helper.py index ebff57f6..3a5d7b8f 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -70,7 +70,7 @@ def with_bare_rw_repo(func): Use this if you want to make purely index based adjustments, change refs, create heads, generally operations that do not need a working tree.""" def bare_repo_creator(self): - repo_dir = tempfile.mktemp("bare_repo") + repo_dir = tempfile.mktemp("bare_repo_%s" % func.__name__) rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=True) prev_cwd = os.getcwd() try: @@ -96,7 +96,7 @@ def with_rw_repo(working_tree_ref): assert isinstance(working_tree_ref, basestring), "Decorator requires ref name for working tree checkout" def argument_passer(func): def repo_creator(self): - repo_dir = tempfile.mktemp("non_bare_repo") + repo_dir = tempfile.mktemp("non_bare_%s" % func.__name__) rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=False, n=True) rw_repo.head.commit = working_tree_ref @@ -105,11 +105,12 @@ def with_rw_repo(working_tree_ref): prev_cwd = os.getcwd() os.chdir(rw_repo.working_dir) try: - return func(self, rw_repo) - except: - print >> sys.stderr, "Keeping repo after failure: %s" % repo_dir - raise - else: + try: + return func(self, rw_repo) + except: + print >> sys.stderr, "Keeping repo after failure: %s" % repo_dir + raise + finally: os.chdir(prev_cwd) rw_repo.git.clear_cache() shutil.rmtree(repo_dir, onerror=_rmtree_onerror) @@ -146,7 +147,7 @@ def with_rw_and_rw_remote_repo(working_tree_ref): assert isinstance(working_tree_ref, basestring), "Decorator requires ref name for working tree checkout" def argument_passer(func): def remote_repo_creator(self): - remote_repo_dir = tempfile.mktemp("remote_repo") + remote_repo_dir = tempfile.mktemp("remote_repo_%s" % func.__name__) repo_dir = tempfile.mktemp("remote_clone_non_bare_repo") rw_remote_repo = self.rorepo.clone(remote_repo_dir, shared=True, bare=True) |