summaryrefslogtreecommitdiff
path: root/lib/git/index.py
diff options
context:
space:
mode:
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)