summaryrefslogtreecommitdiff
path: root/lib/git/index.py
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2009-10-22 22:22:00 +0200
committerSebastian Thiel <byronimo@gmail.com>2009-10-22 22:22:00 +0200
commitb2a14e4b96a0ffc5353733b50266b477539ef899 (patch)
treece48feb6d2da2bed92240c0fbd2350e05f7b7519 /lib/git/index.py
parent20c34a929a8b2871edd4fd44a38688e8977a4be6 (diff)
parentea33fe8b21d2b02f902b131aba0d14389f2f8715 (diff)
downloadgitpython-b2a14e4b96a0ffc5353733b50266b477539ef899.tar.gz
Merge branch 'index' into improvements
* index: Index: Is now diffable and appears to properly implement diffing against other items as well as the working tree default index writing now writes the index of the current repository in a fashion comparable to the native implementation Added test for ConcurrentWriteOperation utils: Added LockFile including test Index now behaves more like the default index if no explicit stream is given. It will lazily read its data on first access
Diffstat (limited to 'lib/git/index.py')
-rw-r--r--lib/git/index.py118
1 files changed, 105 insertions, 13 deletions
diff --git a/lib/git/index.py b/lib/git/index.py
index 9a55da15..4217c9a2 100644
--- a/lib/git/index.py
+++ b/lib/git/index.py
@@ -14,8 +14,11 @@ import objects
import tempfile
import os
import stat
-from git.objects import Blob, Tree
-from git.utils import SHA1Writer
+import git.diff as diff
+
+from git.objects import Blob, Tree, Object
+from git.utils import SHA1Writer, LazyMixin, ConcurrentWriteOperation
+
class _TemporaryFileSwap(object):
"""
@@ -139,7 +142,7 @@ class IndexEntry(tuple):
return IndexEntry((time, time, 0, 0, blob.mode, 0, 0, blob.size, blob.id, 0, blob.path))
-class Index(object):
+class Index(LazyMixin, diff.Diffable):
"""
Implements an Index that can be manipulated using a native implementation in
order to save git command function calls wherever possible.
@@ -153,20 +156,53 @@ class Index(object):
The index contains an entries dict whose keys are tuples of type IndexEntry
to facilitate access.
"""
- __slots__ = ( "repo", "version", "entries", "_extension_data" )
+ __slots__ = ( "repo", "version", "entries", "_extension_data", "_is_default_index" )
_VERSION = 2 # latest version we support
S_IFGITLINK = 0160000
def __init__(self, repo, stream = None):
"""
Initialize this Index instance, optionally from the given ``stream``
+
+ If a stream is not given, the stream will be initialized from the current
+ repository's index on demand.
"""
self.repo = repo
- self.entries = dict()
self.version = self._VERSION
self._extension_data = ''
+ self._is_default_index = True
if stream is not None:
+ self._is_default_index = False
self._read_from_stream(stream)
+ # END read from stream immediatly
+
+
+ def _set_cache_(self, attr):
+ if attr == "entries":
+ # read the current index
+ fp = open(self._index_path(), "r")
+ try:
+ self._read_from_stream(fp)
+ finally:
+ fp.close()
+ # END read from default index on demand
+ else:
+ super(Index, self)._set_cache_(attr)
+
+ def _index_path(self):
+ return os.path.join(self.repo.path, "index")
+
+
+ @property
+ def path(self):
+ """
+ Returns
+ Path to the index file we are representing or None if we are
+ a loose index that was read from a stream.
+ """
+ if self._is_default_index:
+ return self._index_path()
+ return None
@classmethod
def _read_entry(cls, stream):
@@ -197,13 +233,10 @@ class Index(object):
def _read_from_stream(self, stream):
"""
Initialize this instance with index values read from the given stream
-
- Note
- We explicitly do not clear the entries dict here to allow for reading
- multiple chunks from multiple streams into the same Index instance
"""
self.version, num_entries = self._read_header(stream)
count = 0
+ self.entries = dict()
while count < num_entries:
entry = self._read_entry(stream)
self.entries[(entry.path, entry.stage)] = entry
@@ -293,12 +326,14 @@ class Index(object):
real_size = ((stream.tell() - beginoffset + 8) & ~7)
stream.write("\0" * ((beginoffset + real_size) - stream.tell()))
- def write(self, stream):
+ def write(self, stream=None):
"""
- Write the current state to the given stream
+ Write the current state to the given stream or to the default repository
+ index.
``stream``
- File-like object
+ File-like object or None.
+ If None, the default repository index will be overwritten.
Returns
self
@@ -306,6 +341,13 @@ class Index(object):
Note
Index writing based on the dulwich implementation
"""
+ write_op = None
+ if stream is None:
+ write_op = ConcurrentWriteOperation(self._index_path())
+ stream = write_op._begin_writing()
+ # stream = open(self._index_path()
+ # END stream handling
+
stream = SHA1Writer(stream)
# header
@@ -325,6 +367,9 @@ class Index(object):
# write the sha over the content
stream.write_sha()
+ if write_op is not None:
+ write_op._end_writing()
+
@classmethod
def from_tree(cls, repo, *treeish, **kwargs):
@@ -491,7 +536,7 @@ class Index(object):
Returns
Tree object representing this index
"""
- index_path = os.path.join(self.repo.path, "index")
+ index_path = self._index_path()
tmp_index_mover = _TemporaryFileSwap(index_path)
self.to_file(self, index_path)
@@ -507,4 +552,51 @@ class Index(object):
# END write tree handling
return Tree(self.repo, tree_sha, 0, '')
+
+ def _process_diff_args(self, args):
+ try:
+ args.pop(args.index(self))
+ except IndexError:
+ pass
+ # END remove self
+ return args
+
+ def diff(self, other=diff.Diffable.Index, paths=None, create_patch=False, **kwargs):
+ """
+ Diff this index against the working copy or a Tree or Commit object
+
+ For a documentation of the parameters and return values, see
+ Diffable.diff
+
+ Note
+ Will only work with indices that represent the default git index as
+ they have not been initialized with a stream.
+ """
+ if not self._is_default_index:
+ raise AssertionError( "Cannot diff custom indices as they do not represent the default git index" )
+
+ # index against index is always empty
+ if other is self.Index:
+ return diff.DiffIndex()
+
+ # index against anything but None is a reverse diff with the respective
+ # item. Handle existing -R flags properly. Transform strings to the object
+ # so that we can call diff on it
+ if isinstance(other, basestring):
+ other = Object.new(self.repo, other)
+ # END object conversion
+
+ if isinstance(other, Object):
+ # invert the existing R flag
+ cur_val = kwargs.get('R', False)
+ kwargs['R'] = not cur_val
+ return other.diff(self.Index, paths, create_patch, **kwargs)
+ # END diff against other item handlin
+
+ # if other is not None here, something is wrong
+ if other is not None:
+ raise ValueError( "other must be None, Diffable.Index, a Tree or Commit, was %r" % other )
+
+ # diff against working copy - can be handled by superclass natively
+ return super(Index, self).diff(other, paths, create_patch, **kwargs)