Use separate function for tree parsing, allow C extension for tree parsing.
authorJelmer Vernooij <jelmer@samba.org>
Thu, 30 Apr 2009 09:57:10 +0000 (09:59 +0002)
committerJelmer Vernooij <jelmer@samba.org>
Thu, 30 Apr 2009 09:57:10 +0000 (09:59 +0002)
1  2 
dulwich/objects.py

diff --combined dulwich/objects.py
index c43bd0a82c1766d93843251d9d28760f8d596a67,3ae73b9fb80941802b0ac2d12c1de78bb3714072..3657029035db975c20b41b6699eee0c13a7b6da6
@@@ -1,4 -1,4 +1,4 @@@
 -# objects.py -- Acces to base git objects
 +# objects.py -- Access to base git objects
  # Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
  # Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
  # 
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  # MA  02110-1301, USA.
  
 +
 +"""Access to base git objects."""
 +
 +
  import mmap
  import os
  import sha
@@@ -49,20 -45,17 +49,20 @@@ def _decompress(string)
      dcomped += dcomp.flush()
      return dcomped
  
 +
  def sha_to_hex(sha):
      """Takes a string and returns the hex of the sha within"""
      hexsha = "".join(["%02x" % ord(c) for c in sha])
      assert len(hexsha) == 40, "Incorrect length of sha1 string: %d" % hexsha
      return hexsha
  
 +
  def hex_to_sha(hex):
      """Takes a hex sha and returns a binary sha"""
      assert len(hex) == 40, "Incorrent length of hexsha: %s" % hex
      return ''.join([chr(int(hex[i:i+2], 16)) for i in xrange(0, len(hex), 2)])
  
 +
  class ShaFile(object):
      """A git SHA file."""
    
@@@ -92,9 -85,6 +92,9 @@@
          text = text[1:]
          object._text = text
          return object
 +
 +    def as_legacy_object(self):
 +        return zlib.compress("%s %d\0%s" % (self._type, len(self._text), self._text))
    
      def as_raw_string(self):
          return self._num_type, self._text
          try:
              object = num_type_map[num_type]()
          except KeyError:
 -            assert False, "Not a known type: %d" % num_type
 -        while((byte & 0x80) != 0):
 +            raise AssertionError("Not a known type: %d" % num_type)
 +        while (byte & 0x80) != 0:
              byte = ord(map[used])
              used += 1
          raw = map[used:]
@@@ -328,6 -318,33 +328,33 @@@ class Tag(ShaFile)
          return self._message
  
  
+ def parse_tree(text):
+     ret = []
+     count = 0
+     while count < len(text):
+         mode = 0
+         chr = text[count]
+         while chr != ' ':
+             assert chr >= '0' and chr <= '7', "%s is not a valid mode char" % chr
+             mode = (mode << 3) + (ord(chr) - ord('0'))
+             count += 1
+             chr = text[count]
+         count += 1
+         chr = text[count]
+         name = ''
+         while chr != '\0':
+             name += chr
+             count += 1
+             chr = text[count]
+         count += 1
+         chr = text[count]
+         sha = text[count:count+20]
+         hexsha = sha_to_hex(sha)
+         ret.append((mode, name, hexsha))
+         count = count + 20
+     return ret
  class Tree(ShaFile):
      """A Git tree object"""
  
      _num_type = 2
  
      def __init__(self):
 -        self._entries = []
 +        self._entries = {}
  
      @classmethod
      def from_file(cls, filename):
              raise NotTreeError(filename)
          return tree
  
 +    def __getitem__(self, name):
 +        return self._entries[name]
 +
 +    def __setitem__(self, name, value):
 +        assert isinstance(value, tuple)
 +        assert len(value) == 2
 +        self._entries[name] = value
 +
 +    def __delitem__(self, name):
 +        del self._entries[name]
 +
      def add(self, mode, name, hexsha):
 -        self._entries.append((mode, name, hexsha))
 +        self._entries[name] = mode, hexsha
  
      def entries(self):
          """Return a list of tuples describing the tree entries"""
 -        return self._entries
 +        return [(mode, name, hexsha) for (name, (mode, hexsha)) in self._entries.iteritems()]
  
 -    def __getitem__(self, name):
 -        for mode, entry, hexsha in self.entries():
 -            if entry == name:
 -                return mode, hexsha
 -        raise KeyError(name)
 +    def iteritems(self):
 +        for name in sorted(self._entries.keys()):
 +            yield name, self._entries[name][0], self._entries[name][1]
  
      def _parse_text(self):
          """Grab the entries in the tree"""
-         count = 0
-         while count < len(self._text):
-             mode = 0
-             chr = self._text[count]
-             while chr != ' ':
-                 assert chr >= '0' and chr <= '7', "%s is not a valid mode char" % chr
-                 mode = (mode << 3) + (ord(chr) - ord('0'))
-                 count += 1
-                 chr = self._text[count]
-             count += 1
-             chr = self._text[count]
-             name = ''
-             while chr != '\0':
-                 name += chr
-                 count += 1
-                 chr = self._text[count]
-             count += 1
-             chr = self._text[count]
-             sha = self._text[count:count+20]
-             hexsha = sha_to_hex(sha)
-             self.add(mode, name, hexsha)
-             count = count + 20
+         self._entries = parse_tree(self._text)
  
      def serialize(self):
          self._text = ""
 -        for mode, name, hexsha in self._entries:
 +        for name, mode, hexsha in self.iteritems():
              self._text += "%04o %s\0%s" % (mode, name, hex_to_sha(hexsha))
  
  
@@@ -456,6 -443,7 +462,7 @@@ class Commit(ShaFile)
              count += 1
              self._author_time = int(text[count:count+10])
              while text[count] != ' ':
+                 assert text[count] != '\n', "Malformed author information"
                  count += 1
              self._author_timezone = int(text[count:count+6])
              count += 1
              count += 1
              self._commit_time = int(text[count:count+10])
              while text[count] != ' ':
+                 assert text[count] != '\n', "Malformed committer information"
                  count += 1
              self._commit_timezone = int(text[count:count+6])
              count += 1
@@@ -573,7 -562,7 +581,7 @@@ num_type_map = 
  
  try:
      # Try to import C versions
-     from dulwich._objects import hex_to_sha, sha_to_hex
+     from dulwich._objects import hex_to_sha, sha_to_hex, parse_tree
  except ImportError:
      pass