summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2014-11-17 11:48:04 +0100
committerSebastian Thiel <byronimo@gmail.com>2014-11-17 11:48:13 +0100
commita40d848794133de7b6e028f2513c939d823767cb (patch)
tree49e2591530014913d40e66bbea77ee150cf7be46
parent9eb902eee03806db5868fc84afb23aa28802e841 (diff)
parent81223de22691e2df7b81cd384ad23be25cfd999c (diff)
downloadgitpython-a40d848794133de7b6e028f2513c939d823767cb.tar.gz
Merge branch 'moshevds-0.3' into 0.3
Backport of https://github.com/gitpython-developers/GitPython/pull/131
-rw-r--r--git/index/base.py117
-rw-r--r--git/test/test_index.py34
2 files changed, 99 insertions, 52 deletions
diff --git a/git/index/base.py b/git/index/base.py
index 47c32dc6..bbbe3028 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -559,11 +559,51 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# END for each item
return (paths, entries)
+ def _store_path(self, filepath, fprogress):
+ """Store file at filepath in the database and return the base index entry
+ Needs the git_working_dir decorator active ! This must be assured in the calling code"""
+ st = os.lstat(filepath) # handles non-symlinks as well
+ stream = None
+ if S_ISLNK(st.st_mode):
+ stream = StringIO(os.readlink(filepath))
+ else:
+ stream = open(filepath, 'rb')
+ # END handle stream
+ fprogress(filepath, False, filepath)
+ istream = self.repo.odb.store(IStream(Blob.type, st.st_size, stream))
+ fprogress(filepath, True, filepath)
+ return BaseIndexEntry((stat_mode_to_index_mode(st.st_mode),
+ istream.binsha, 0, to_native_path_linux(filepath)))
+
@git_working_dir
- def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=None,
+ def _entries_for_paths(self, paths, path_rewriter, fprogress, entries):
+ entries_added = list()
+ if path_rewriter:
+ for path in paths:
+ abspath = os.path.abspath(path)
+ gitrelative_path = abspath[len(self.repo.working_tree_dir)+1:]
+ blob = Blob(self.repo, Blob.NULL_BIN_SHA,
+ stat_mode_to_index_mode(os.stat(abspath).st_mode),
+ to_native_path_linux(gitrelative_path))
+ # TODO: variable undefined
+ entries.append(BaseIndexEntry.from_blob(blob))
+ # END for each path
+ del(paths[:])
+ # END rewrite paths
+
+ # HANDLE PATHS
+ assert len(entries_added) == 0
+ for filepath in self._iter_expand_paths(paths):
+ entries_added.append(self._store_path(filepath, fprogress))
+ # END for each filepath
+ # END path handling
+ return entries_added
+
+
+ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=None,
write=True):
"""Add files from the working tree, specific blobs or BaseIndexEntries
- to the index.
+ to the index.
:param items:
Multiple types of items are supported, types can be mixed within one call.
@@ -591,7 +631,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
must be a path relative to our repository.
If their sha is null ( 40*0 ), their path must exist in the file system
- relative to the git repository as an object will be created from
+ relative to the git repository as an object will be created from
the data at the path.
The handling now very much equals the way string paths are processed, except that
the mode you have set will be kept. This allows you to create symlinks
@@ -636,7 +676,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
:param write:
If True, the index will be written once it was altered. Otherwise
the changes only exist in memory and are not available to git commands.
-
+
:return:
List(BaseIndexEntries) representing the entries just actually added.
@@ -648,70 +688,43 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# sort the entries into strings and Entries, Blobs are converted to entries
# automatically
# paths can be git-added, for everything else we use git-update-index
- entries_added = list()
paths, entries = self._preprocess_add_items(items)
- if paths and path_rewriter:
- for path in paths:
- abspath = os.path.abspath(path)
- gitrelative_path = abspath[len(self.repo.working_tree_dir) + 1:]
- blob = Blob(self.repo, Blob.NULL_BIN_SHA,
- stat_mode_to_index_mode(os.stat(abspath).st_mode),
- to_native_path_linux(gitrelative_path))
- entries.append(BaseIndexEntry.from_blob(blob))
- # END for each path
- del(paths[:])
- # END rewrite paths
-
- def store_path(filepath):
- """Store file at filepath in the database and return the base index entry"""
- st = os.lstat(filepath) # handles non-symlinks as well
- stream = None
- if S_ISLNK(st.st_mode):
- stream = StringIO(os.readlink(filepath))
- else:
- stream = open(filepath, 'rb')
- # END handle stream
- fprogress(filepath, False, filepath)
- istream = self.repo.odb.store(IStream(Blob.type, st.st_size, stream))
- fprogress(filepath, True, filepath)
- return BaseIndexEntry((stat_mode_to_index_mode(st.st_mode),
- istream.binsha, 0, to_native_path_linux(filepath)))
- # END utility method
-
- # HANDLE PATHS
+ entries_added = list()
+ # This code needs a working tree, therefore we try not to run it unless required.
+ # That way, we are OK on a bare repository as well.
+ # If there are no paths, the rewriter has nothing to do either
if paths:
- assert len(entries_added) == 0
- added_files = list()
- for filepath in self._iter_expand_paths(paths):
- entries_added.append(store_path(filepath))
- # END for each filepath
- # END path handling
+ entries_added.extend(self._entries_for_paths(paths, path_rewriter, fprogress, entries))
# HANDLE ENTRIES
if entries:
- null_mode_entries = [e for e in entries if e.mode == 0]
+ 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")
# END null mode should be remove
# HANLDE ENTRY OBJECT CREATION
# create objects if required, otherwise go with the existing shas
- null_entries_indices = [i for i, e in enumerate(entries) if e.binsha == Object.NULL_BIN_SHA]
+ null_entries_indices = [ i for i,e in enumerate(entries) if e.binsha == Object.NULL_BIN_SHA ]
if null_entries_indices:
- for ei in null_entries_indices:
- null_entry = entries[ei]
- new_entry = store_path(null_entry.path)
-
- # update null entry
- entries[ei] = BaseIndexEntry((null_entry.mode, new_entry.binsha, null_entry.stage, null_entry.path))
- # END for each entry index
+ @git_working_dir
+ def handle_null_entries(self):
+ for ei in null_entries_indices:
+ null_entry = entries[ei]
+ new_entry = self._store_path(null_entry.path, fprogress)
+
+ # update null entry
+ entries[ei] = BaseIndexEntry((null_entry.mode, new_entry.binsha, null_entry.stage, null_entry.path))
+ # END for each entry index
+ # end closure
+ handle_null_entries(self)
# END null_entry handling
# REWRITE PATHS
# If we have to rewrite the entries, do so now, after we have generated
# all object sha's
if path_rewriter:
- for i, e in enumerate(entries):
+ for i,e in enumerate(entries):
entries[i] = BaseIndexEntry((e.mode, e.binsha, e.stage, path_rewriter(e)))
# END for each entry
# END handle path rewriting
@@ -731,11 +744,11 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# add the new entries to this instance
for entry in entries_added:
self.entries[(entry.path, 0)] = IndexEntry.from_base(entry)
-
+
if write:
self.write()
# END handle write
-
+
return entries_added
def _items_to_rela_paths(self, items):
diff --git a/git/test/test_index.py b/git/test/test_index.py
index f1f718cd..3440c5be 100644
--- a/git/test/test_index.py
+++ b/git/test/test_index.py
@@ -14,6 +14,10 @@ import glob
import shutil
from stat import *
+from StringIO import StringIO
+from gitdb.base import IStream
+from git.objects import Blob
+from git.index.typ import BaseIndexEntry
class TestIndex(TestBase):
@@ -661,3 +665,33 @@ class TestIndex(TestBase):
index = IndexFile.new(self.rorepo, *args)
assert isinstance(index, IndexFile)
# END for each arg tuple
+
+ @with_rw_repo('HEAD', bare=True)
+ def test_index_bare_add(self, rw_bare_repo):
+ # Something is wrong after cloning to a bare repo, reading the
+ # property rw_bare_repo.working_tree_dir will return '/tmp'
+ # instead of throwing the Exception we are expecting. This is
+ # a quick hack to make this test fail when expected.
+ rw_bare_repo._working_tree_dir = None
+ contents = 'This is a StringIO file'
+ filesize = len(contents)
+ fileobj = StringIO(contents)
+ filename = 'my-imaginary-file'
+ istream = rw_bare_repo.odb.store(
+ IStream(Blob.type, filesize, fileobj))
+ entry = BaseIndexEntry((100644, istream.binsha, 0, filename))
+ try:
+ rw_bare_repo.index.add([entry])
+ except AssertionError, e:
+ self.fail("Adding to the index of a bare repo is not allowed.")
+
+ # Adding using a path should still require a non-bare repository.
+ asserted = False
+ path = os.path.join('git', 'test', 'test_index.py')
+ try:
+ rw_bare_repo.index.add([path])
+ except Exception, e:
+ asserted = "does not have a working tree" in e.message
+ assert asserted, "Adding using a filename is not correctly asserted."
+
+