From 3d9e7f1121d3bdbb08291c7164ad622350544a21 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 18:01:52 +0200 Subject: Index now behaves more like the default index if no explicit stream is given. It will lazily read its data on first access --- lib/git/index.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'lib/git/index.py') diff --git a/lib/git/index.py b/lib/git/index.py index 9a55da15..fd5081ce 100644 --- a/lib/git/index.py +++ b/lib/git/index.py @@ -15,7 +15,8 @@ import tempfile import os import stat from git.objects import Blob, Tree -from git.utils import SHA1Writer +from git.utils import SHA1Writer, LazyMixin +from git.diff import Diffable class _TemporaryFileSwap(object): """ @@ -139,7 +140,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): """ Implements an Index that can be manipulated using a native implementation in order to save git command function calls wherever possible. @@ -160,13 +161,28 @@ class Index(object): 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 = '' if stream is not None: self._read_from_stream(stream) + # END read from stream immediatly + + def _set_cache_(self, attr): + if attr == "entries": + # read the current index + fp = open(os.path.join(self.repo.path, "index"), "r") + try: + self._read_from_stream(fp) + finally: + fp.close() + # END read from default index on demand + else: + super(Index, self)._set_cache_(attr) @classmethod def _read_entry(cls, stream): @@ -197,13 +213,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 @@ -298,7 +311,7 @@ class Index(object): Write the current state to the given stream ``stream`` - File-like object + File-like object. Returns self -- cgit v1.2.1 From 1496979cf7e9692ef869d2f99da6141756e08d25 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 19:43:01 +0200 Subject: default index writing now writes the index of the current repository in a fashion comparable to the native implementation --- lib/git/index.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'lib/git/index.py') diff --git a/lib/git/index.py b/lib/git/index.py index fd5081ce..4eabab15 100644 --- a/lib/git/index.py +++ b/lib/git/index.py @@ -15,7 +15,7 @@ import tempfile import os import stat from git.objects import Blob, Tree -from git.utils import SHA1Writer, LazyMixin +from git.utils import SHA1Writer, LazyMixin, ConcurrentWriteOperation from git.diff import Diffable class _TemporaryFileSwap(object): @@ -175,7 +175,7 @@ class Index(LazyMixin): def _set_cache_(self, attr): if attr == "entries": # read the current index - fp = open(os.path.join(self.repo.path, "index"), "r") + fp = open(self._index_path(), "r") try: self._read_from_stream(fp) finally: @@ -184,6 +184,9 @@ class Index(LazyMixin): else: super(Index, self)._set_cache_(attr) + def _index_path(self): + return os.path.join(self.repo.path, "index") + @classmethod def _read_entry(cls, stream): """Return: One entry of the given stream""" @@ -306,12 +309,14 @@ class Index(LazyMixin): 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 @@ -319,6 +324,13 @@ class Index(LazyMixin): 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 @@ -338,6 +350,9 @@ class Index(LazyMixin): # 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): @@ -504,7 +519,7 @@ class Index(LazyMixin): 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) -- cgit v1.2.1 From ea33fe8b21d2b02f902b131aba0d14389f2f8715 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 22:14:02 +0200 Subject: Index: Is now diffable and appears to properly implement diffing against other items as well as the working tree Diff.Diffable: added callback allowing superclasses to preprocess diff arguments Diff.Diff: added eq, ne and hash methods, string methods would be nice --- lib/git/index.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 4 deletions(-) (limited to 'lib/git/index.py') diff --git a/lib/git/index.py b/lib/git/index.py index 4eabab15..4217c9a2 100644 --- a/lib/git/index.py +++ b/lib/git/index.py @@ -14,9 +14,11 @@ import objects import tempfile import os import stat -from git.objects import Blob, Tree +import git.diff as diff + +from git.objects import Blob, Tree, Object from git.utils import SHA1Writer, LazyMixin, ConcurrentWriteOperation -from git.diff import Diffable + class _TemporaryFileSwap(object): """ @@ -140,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(LazyMixin): +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. @@ -154,7 +156,7 @@ class Index(LazyMixin): 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 @@ -168,10 +170,13 @@ class Index(LazyMixin): self.repo = repo 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 @@ -187,6 +192,18 @@ class Index(LazyMixin): 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): """Return: One entry of the given stream""" @@ -535,4 +552,51 @@ class Index(LazyMixin): # 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) -- cgit v1.2.1