diff options
Diffstat (limited to 'lib/git/index.py')
-rw-r--r-- | lib/git/index.py | 100 |
1 files changed, 99 insertions, 1 deletions
diff --git a/lib/git/index.py b/lib/git/index.py index 1c531712..1e67d6d1 100644 --- a/lib/git/index.py +++ b/lib/git/index.py @@ -7,11 +7,109 @@ Module containing Index implementation, allowing to perform all kinds of index manipulations such as querying and merging. """ +import struct +import binascii +import mmap + +class IndexEntry(tuple): + """ + Allows convenient access to IndexEntry data without completely unpacking it. + + Attributes usully accessed often are cached in the tuple whereas others are + unpacked on demand. + """ class Index(object): """ Implements an Index that can be manipulated using a native implementation in - order to safe git command function calls wherever possible. + order to save git command function calls wherever possible. It provides custom merging facilities and to create custom commits. """ + __slots__ = ( "version", "entries" ) + + def __init__(self, stream = None): + """ + Initialize this Index instance, optionally from the given ``stream`` + + Note + Reading is based on the dulwich project. + """ + self.entries = dict() + self.version = -1 + if stream is not None: + self._read_from_stream(stream) + + def _read_entry(self, stream): + """Return: One entry of the given stream""" + beginoffset = stream.tell() + ctime = struct.unpack(">8s", stream.read(8))[0] + mtime = struct.unpack(">8s", stream.read(8))[0] + (dev, ino, mode, uid, gid, size, sha, flags) = \ + struct.unpack(">LLLLLL20sH", stream.read(20 + 4 * 6 + 2)) + path_size = flags & 0x0fff + path = stream.read(path_size) + + real_size = ((stream.tell() - beginoffset + 8) & ~7) + data = stream.read((beginoffset + real_size) - stream.tell()) + return IndexEntry((path, ctime, mtime, dev, ino, mode, uid, gid, size, + binascii.hexlify(sha), path_size)) + + + def _read_header(self, stream): + """Return tuple(version_long, num_entries) from the given stream""" + type_id = stream.read(4) + if type_id != "DIRC": + raise AssertionError("Invalid index file header: %r" % type_id) + version, num_entries = struct.unpack(">LL", stream.read(4 * 2)) + assert version in (1, 2) + return version, num_entries + + def _read_from_stream(self, stream): + """ + Initialize this instance with index values read from the given stream + """ + self.version, num_entries = self._read_header(stream) + self.entries = dict() + count = 0 + while count < num_entries: + entry = self._read_entry(stream) + self.entries[entry[0]] = entry[1:] + count += 1 + # END for each entry + + @classmethod + def from_file(cls, file_path): + """ + Returns + Index instance as recreated from the given stream. + + ``file_pa `` + File path pointing to git index file + """ + fp = open(file_path, "r") + + # try memory map for speed + stream = fp + try: + stream = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) + except Exception: + pass + # END memory mapping + + try: + return cls(stream) + finally: + fp.close() + + def write(self, stream): + """ + Write the current state to the given stream + + ``stream`` + File-like object + + Returns + self + """ + raise NotImplementedError( "TODO" ) |