diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2009-10-22 22:22:00 +0200 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2009-10-22 22:22:00 +0200 |
commit | b2a14e4b96a0ffc5353733b50266b477539ef899 (patch) | |
tree | ce48feb6d2da2bed92240c0fbd2350e05f7b7519 /lib/git/index.py | |
parent | 20c34a929a8b2871edd4fd44a38688e8977a4be6 (diff) | |
parent | ea33fe8b21d2b02f902b131aba0d14389f2f8715 (diff) | |
download | gitpython-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.py | 118 |
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) |