summaryrefslogtreecommitdiff
path: root/lib/git
diff options
context:
space:
mode:
Diffstat (limited to 'lib/git')
-rw-r--r--lib/git/index.py100
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" )