Changes to 8 files · Browse files at 684b4ba58ae9 Showing diff from parent f58dc961489a Diff from another changeset...
@@ -37,40 +37,39 @@
class WrongObjectException(Exception):
"""Baseclass for all the _ is not a _ exceptions on objects.
-
+
Do not instantiate directly.
-
- Subclasses should define a _type attribute that indicates what
+
+ Subclasses should define a type_name attribute that indicates what
was expected if they were raised.
"""
-
+
def __init__(self, sha, *args, **kwargs):
- string = "%s is not a %s" % (sha, self._type)
- Exception.__init__(self, string)
+ Exception.__init__(self, "%s is not a %s" % (sha, self.type_name))
class NotCommitError(WrongObjectException):
"""Indicates that the sha requested does not point to a commit."""
-
- _type = 'commit'
+
+ type_name = 'commit'
class NotTreeError(WrongObjectException):
"""Indicates that the sha requested does not point to a tree."""
-
- _type = 'tree'
+
+ type_name = 'tree'
class NotTagError(WrongObjectException):
"""Indicates that the sha requested does not point to a tag."""
- _type = 'tag'
+ type_name = 'tag'
class NotBlobError(WrongObjectException):
"""Indicates that the sha requested does not point to a blob."""
-
- _type = 'blob'
+
+ type_name = 'blob'
class MissingCommitError(Exception):
|
@@ -92,14 +92,14 @@ """Obtain the raw text for an object.
:param name: sha for the object.
- :return: tuple with object type and object contents.
+ :return: tuple with numeric type and object contents.
"""
raise NotImplementedError(self.get_raw)
def __getitem__(self, sha):
"""Obtain an object by SHA1."""
- type, uncomp = self.get_raw(sha)
- return ShaFile.from_raw_string(type, uncomp)
+ type_num, uncomp = self.get_raw(sha)
+ return ShaFile.from_raw_string(type_num, uncomp)
def __iter__(self):
"""Iterate over the SHAs that are present in this store."""
@@ -284,9 +284,9 @@
def get_raw(self, name):
"""Obtain the raw text for an object.
-
+
:param name: sha for the object.
- :return: tuple with object type and object contents.
+ :return: tuple with numeric type and object contents.
"""
if len(name) == 40:
sha = hex_to_sha(name)
@@ -305,7 +305,7 @@ hexsha = sha_to_hex(name)
ret = self._get_loose_object(hexsha)
if ret is not None:
- return ret.type, ret.as_raw_string()
+ return ret.type_num, ret.as_raw_string()
raise KeyError(hexsha)
def add_objects(self, objects):
@@ -503,9 +503,9 @@
def get_raw(self, name):
"""Obtain the raw text for an object.
-
+
:param name: sha for the object.
- :return: tuple with object type and object contents.
+ :return: tuple with numeric type and object contents.
"""
return self[name].as_raw_string()
@@ -621,7 +621,7 @@ mode = None
for p in parts:
obj = lookup_obj(sha)
- if type(obj) is not Tree:
+ if not isinstance(obj, Tree):
raise NotTreeError(sha)
if p == '':
continue
|
|
|
@@ -41,22 +41,27 @@ make_sha,
)
-BLOB_ID = "blob"
-TAG_ID = "tag"
-TREE_ID = "tree"
-COMMIT_ID = "commit"
-PARENT_ID = "parent"
-AUTHOR_ID = "author"
-COMMITTER_ID = "committer"
-OBJECT_ID = "object"
-TYPE_ID = "type"
-TAGGER_ID = "tagger"
-ENCODING_ID = "encoding"
+
+# Header fields for commits
+_TREE_HEADER = "tree"
+_PARENT_HEADER = "parent"
+_AUTHOR_HEADER = "author"
+_COMMITTER_HEADER = "committer"
+_ENCODING_HEADER = "encoding"
+
+
+# Header fields for objects
+_OBJECT_HEADER = "object"
+_TYPE_HEADER = "type"
+_TAG_HEADER = "tag"
+_TAGGER_HEADER = "tagger"
+
S_IFGITLINK = 0160000
def S_ISGITLINK(m):
return (stat.S_IFMT(m) == S_IFGITLINK)
+
def _decompress(string):
dcomp = zlib.decompressobj()
@@ -89,6 +94,15 @@ return property(get, set, doc=docstring)
+def object_class(type):
+ """Get the object class corresponding to the given type.
+
+ :param type: Either a type name string or a numeric type.
+ :return: The ShaFile subclass corresponding to the given type.
+ """
+ return _TYPE_MAP[type]
+
+
class ShaFile(object):
"""A git SHA file."""
@@ -97,10 +111,10 @@ """Parse a legacy object, creating it and setting object._text"""
text = _decompress(map)
object = None
- for posstype in type_map.keys():
- if text.startswith(posstype):
- object = type_map[posstype]()
- text = text[len(posstype):]
+ for cls in OBJECT_CLASSES:
+ if text.startswith(cls.type_name):
+ object = cls()
+ text = text[len(cls.type_name):]
break
assert object is not None, "%s is not a known object type" % text[:9]
assert text[0] == ' ', "%s is not a space" % text[0]
@@ -121,7 +135,7 @@
def as_legacy_object(self):
text = self.as_raw_string()
- return zlib.compress("%s %d\0%s" % (self._type, len(text), text))
+ return zlib.compress("%s %d\0%s" % (self.type_name, len(text), text))
def as_raw_chunks(self):
if self._needs_serialization:
@@ -163,11 +177,11 @@ used = 0
byte = ord(map[used])
used += 1
- num_type = (byte >> 4) & 7
+ type_num = (byte >> 4) & 7
try:
- object = num_type_map[num_type]()
+ object = object_class(type_num)()
except KeyError:
- raise AssertionError("Not a known type: %d" % num_type)
+ raise AssertionError("Not a known type: %d" % type_num)
while (byte & 0x80) != 0:
byte = ord(map[used])
used += 1
@@ -205,41 +219,37 @@ finally:
f.close()
- @classmethod
- def from_raw_string(cls, type, string):
+ @staticmethod
+ def from_raw_string(type_num, string):
"""Creates an object of the indicated type from the raw string given.
- Type is the numeric type of an object. String is the raw uncompressed
- contents.
+ :param type_num: The numeric type of the object.
+ :param string: The raw uncompressed contents.
"""
- real_class = num_type_map[type]
- obj = real_class()
- obj.type = type
+ obj = object_class(type_num)()
obj.set_raw_string(string)
return obj
- @classmethod
- def from_raw_chunks(cls, type, chunks):
+ @staticmethod
+ def from_raw_chunks(type_num, chunks):
"""Creates an object of the indicated type from the raw chunks given.
- Type is the numeric type of an object. Chunks is a sequence of the raw
- uncompressed contents.
+ :param type_num: The numeric type of the object.
+ :param chunks: An iterable of the raw uncompressed contents.
"""
- real_class = num_type_map[type]
- obj = real_class()
- obj.type = type
+ obj = object_class(type_num)()
obj.set_raw_chunks(chunks)
return obj
@classmethod
def from_string(cls, string):
"""Create a blob from a string."""
- shafile = cls()
- shafile.set_raw_string(string)
- return shafile
+ obj = cls()
+ obj.set_raw_string(string)
+ return obj
def _header(self):
- return "%s %lu\0" % (self._type, self.raw_length())
+ return "%s %lu\0" % (self.type_name, self.raw_length())
def raw_length(self):
"""Returns the length of the raw string of this object."""
@@ -266,11 +276,12 @@ return self.sha().hexdigest()
def get_type(self):
- return self._num_type
+ return self.type_num
def set_type(self, type):
- self._num_type = type
-
+ self.type_num = type
+
+ # DEPRECATED: use type_num or type_name as needed.
type = property(get_type, set_type)
def __repr__(self):
@@ -291,8 +302,8 @@class Blob(ShaFile):
"""A Git Blob object."""
- _type = BLOB_ID
- _num_type = 3
+ type_name = 'blob'
+ type_num = 3
def __init__(self):
super(Blob, self).__init__()
@@ -321,7 +332,7 @@ @classmethod
def from_file(cls, filename):
blob = ShaFile.from_file(filename)
- if blob._type != cls._type:
+ if not isinstance(blob, cls):
raise NotBlobError(filename)
return blob
@@ -329,8 +340,8 @@class Tag(ShaFile):
"""A Git Tag object."""
- _type = TAG_ID
- _num_type = 4
+ type_name = 'tag'
+ type_num = 4
def __init__(self):
super(Tag, self).__init__()
@@ -339,10 +350,10 @@
@classmethod
def from_file(cls, filename):
- blob = ShaFile.from_file(filename)
- if blob._type != cls._type:
- raise NotBlobError(filename)
- return blob
+ tag = ShaFile.from_file(filename)
+ if not isinstance(tag, cls):
+ raise NotTagError(filename)
+ return tag
@classmethod
def from_string(cls, string):
@@ -353,14 +364,16 @@
def _serialize(self):
chunks = []
- chunks.append("%s %s\n" % (OBJECT_ID, self._object_sha))
- chunks.append("%s %s\n" % (TYPE_ID, num_type_map[self._object_type]._type))
- chunks.append("%s %s\n" % (TAG_ID, self._name))
+ chunks.append("%s %s\n" % (_OBJECT_HEADER, self._object_sha))
+ chunks.append("%s %s\n" % (_TYPE_HEADER, self._object_class.type_name))
+ chunks.append("%s %s\n" % (_TAG_HEADER, self._name))
if self._tagger:
if self._tag_time is None:
- chunks.append("%s %s\n" % (TAGGER_ID, self._tagger))
+ chunks.append("%s %s\n" % (_TAGGER_HEADER, self._tagger))
else:
- chunks.append("%s %s %d %s\n" % (TAGGER_ID, self._tagger, self._tag_time, format_timezone(self._tag_timezone)))
+ chunks.append("%s %s %d %s\n" % (
+ _TAGGER_HEADER, self._tagger, self._tag_time,
+ format_timezone(self._tag_timezone)))
chunks.append("\n") # To close headers
chunks.append(self._message)
return chunks
@@ -374,13 +387,13 @@ if l == "":
break # empty line indicates end of headers
(field, value) = l.split(" ", 1)
- if field == OBJECT_ID:
+ if field == _OBJECT_HEADER:
self._object_sha = value
- elif field == TYPE_ID:
- self._object_type = type_map[value]
- elif field == TAG_ID:
+ elif field == _TYPE_HEADER:
+ self._object_class = object_class(value)
+ elif field == _TAG_HEADER:
self._name = value
- elif field == TAGGER_ID:
+ elif field == _TAGGER_HEADER:
try:
sep = value.index("> ")
except ValueError:
@@ -400,13 +413,16 @@ self._message = f.read()
def _get_object(self):
- """Returns the object pointed by this tag, represented as a tuple(type, sha)"""
- self._ensure_parsed()
- return (self._object_type, self._object_sha)
+ """Get the object pointed to by this tag.
+
+ :return: tuple of (object class, sha).
+ """
+ self._ensure_parsed()
+ return (self._object_class, self._object_sha)
def _set_object(self, value):
self._ensure_parsed()
- (self._object_type, self._object_sha) = value
+ (self._object_class, self._object_sha) = value
self._needs_serialization = True
object = property(_get_object, _set_object)
@@ -471,8 +487,8 @@class Tree(ShaFile):
"""A Git tree object"""
- _type = TREE_ID
- _num_type = 2
+ type_name = 'tree'
+ type_num = 2
def __init__(self):
super(Tree, self).__init__()
@@ -483,7 +499,7 @@ @classmethod
def from_file(cls, filename):
tree = ShaFile.from_file(filename)
- if tree._type != cls._type:
+ if not isinstance(tree, cls):
raise NotTreeError(filename)
return tree
@@ -574,8 +590,8 @@class Commit(ShaFile):
"""A git commit object"""
- _type = COMMIT_ID
- _num_type = 1
+ type_name = 'commit'
+ type_num = 1
def __init__(self):
super(Commit, self).__init__()
@@ -588,7 +604,7 @@ @classmethod
def from_file(cls, filename):
commit = ShaFile.from_file(filename)
- if commit._type != cls._type:
+ if not isinstance(commit, cls):
raise NotCommitError(filename)
return commit
@@ -603,19 +619,19 @@ # Empty line indicates end of headers
break
(field, value) = l.split(" ", 1)
- if field == TREE_ID:
+ if field == _TREE_HEADER:
self._tree = value
- elif field == PARENT_ID:
+ elif field == _PARENT_HEADER:
self._parents.append(value)
- elif field == AUTHOR_ID:
+ elif field == _AUTHOR_HEADER:
self._author, timetext, timezonetext = value.rsplit(" ", 2)
self._author_time = int(timetext)
self._author_timezone = parse_timezone(timezonetext)
- elif field == COMMITTER_ID:
+ elif field == _COMMITTER_HEADER:
self._committer, timetext, timezonetext = value.rsplit(" ", 2)
self._commit_time = int(timetext)
self._commit_timezone = parse_timezone(timezonetext)
- elif field == ENCODING_ID:
+ elif field == _ENCODING_HEADER:
self._encoding = value
else:
self._extra.append((field, value))
@@ -623,13 +639,17 @@
def _serialize(self):
chunks = []
- chunks.append("%s %s\n" % (TREE_ID, self._tree))
+ chunks.append("%s %s\n" % (_TREE_HEADER, self._tree))
for p in self._parents:
- chunks.append("%s %s\n" % (PARENT_ID, p))
- chunks.append("%s %s %s %s\n" % (AUTHOR_ID, self._author, str(self._author_time), format_timezone(self._author_timezone)))
- chunks.append("%s %s %s %s\n" % (COMMITTER_ID, self._committer, str(self._commit_time), format_timezone(self._commit_timezone)))
+ chunks.append("%s %s\n" % (_PARENT_HEADER, p))
+ chunks.append("%s %s %s %s\n" % (
+ _AUTHOR_HEADER, self._author, str(self._author_time),
+ format_timezone(self._author_timezone)))
+ chunks.append("%s %s %s %s\n" % (
+ _COMMITTER_HEADER, self._committer, str(self._commit_time),
+ format_timezone(self._commit_timezone)))
if self.encoding:
- chunks.append("%s %s\n" % (ENCODING_ID, self.encoding))
+ chunks.append("%s %s\n" % (_ENCODING_HEADER, self.encoding))
for k, v in self.extra:
if "\n" in k or "\n" in v:
raise AssertionError("newline in extra data: %r -> %r" % (k, v))
@@ -685,21 +705,19 @@ "Encoding of the commit message.")
-type_map = {
- BLOB_ID : Blob,
- TREE_ID : Tree,
- COMMIT_ID : Commit,
- TAG_ID: Tag,
-}
-
-num_type_map = {
- 0: None,
- 1: Commit,
- 2: Tree,
- 3: Blob,
- 4: Tag,
- # 5 Is reserved for further expansion
-}
+OBJECT_CLASSES = (
+ Commit,
+ Tree,
+ Blob,
+ Tag,
+ )
+
+_TYPE_MAP = {}
+
+for cls in OBJECT_CLASSES:
+ _TYPE_MAP[cls.type_name] = cls
+ _TYPE_MAP[cls.type_num] = cls
+
try:
# Try to import C versions
|
@@ -833,7 +833,7 @@ # This helps us find good objects to diff against us
magic = []
for obj, path in recency:
- magic.append( (obj.type, path, 1, -obj.raw_length(), obj) )
+ magic.append( (obj.type_num, path, 1, -obj.raw_length(), obj) )
magic.sort()
# Build a map of objects and their index in magic - so we can find preceeding objects
# to diff against
@@ -848,14 +848,14 @@ f.write(struct.pack(">L", num_objects)) # Number of objects in pack
for o, path in recency:
sha1 = o.sha().digest()
- orig_t = o.type
+ orig_t = o.type_num
raw = o.as_raw_string()
winner = raw
t = orig_t
#for i in range(offs[o]-window, window):
# if i < 0 or i >= len(offs): continue
# b = magic[i][4]
- # if b.type != orig_t: continue
+ # if b.type_num != orig_t: continue
# base = b.as_raw_string()
# delta = create_delta(base, raw)
# if len(delta) < len(winner):
|
@@ -49,7 +49,7 @@ Tag,
Tree,
hex_to_sha,
- num_type_map,
+ object_class,
)
import warnings
@@ -698,7 +698,7 @@ def _get_object(self, sha, cls):
assert len(sha) in (20, 40)
ret = self.get_object(sha)
- if ret._type != cls._type:
+ if not isinstance(ret, cls):
if cls is Commit:
raise NotCommitError(ret)
elif cls is Blob:
@@ -708,7 +708,8 @@ elif cls is Tag:
raise NotTagError(ret)
else:
- raise Exception("Type invalid: %r != %r" % (ret._type, cls._type))
+ raise Exception("Type invalid: %r != %r" % (
+ ret.type_name, cls.type_name))
return ret
def get_object(self, sha):
@@ -784,9 +785,9 @@ if cached is not None:
return cached
obj = self[ref]
- obj_type = num_type_map[obj.type]
- while obj_type == Tag:
- obj_type, sha = obj.object
+ obj_class = object_class(obj.type_name)
+ while obj_class is Tag:
+ obj_class, sha = obj.object
obj = self.get_object(sha)
return obj.id
|
@@ -183,13 +183,13 @@ """Tests random access for non-delta objects"""
p = self.get_pack(pack1_sha)
obj = p[a_sha]
- self.assertEqual(obj._type, 'blob')
+ self.assertEqual(obj.type_name, 'blob')
self.assertEqual(obj.sha().hexdigest(), a_sha)
obj = p[tree_sha]
- self.assertEqual(obj._type, 'tree')
+ self.assertEqual(obj.type_name, 'tree')
self.assertEqual(obj.sha().hexdigest(), tree_sha)
obj = p[commit_sha]
- self.assertEqual(obj._type, 'commit')
+ self.assertEqual(obj.type_name, 'commit')
self.assertEqual(obj.sha().hexdigest(), commit_sha)
def test_copy(self):
@@ -285,4 +285,3 @@ def test_simple_decompress(self):
self.assertEquals((["tree 4ada885c9196b6b6fa08744b5862bf92896fc002\nparent None\nauthor Jelmer Vernooij <jelmer@samba.org> 1228980214 +0000\ncommitter Jelmer Vernooij <jelmer@samba.org> 1228980214 +0000\n\nProvide replacement for mmap()'s offset argument."], 158, 'Z'),
read_zlib_chunks(StringIO(TEST_COMP1).read, 229))
-
|
@@ -92,16 +92,16 @@ def test_head(self):
r = self._repo = open_repo('a.git')
self.assertEqual(r.head(), 'a90fa2d900a17e99b433217e988c4eb4a2e9a097')
-
+
def test_get_object(self):
r = self._repo = open_repo('a.git')
obj = r.get_object(r.head())
- self.assertEqual(obj._type, 'commit')
-
+ self.assertEqual(obj.type_name, 'commit')
+
def test_get_object_non_existant(self):
r = self._repo = open_repo('a.git')
self.assertRaises(KeyError, r.get_object, missing_sha)
-
+
def test_commit(self):
r = self._repo = open_repo('a.git')
warnings.simplefilter("ignore", DeprecationWarning)
@@ -109,8 +109,8 @@ obj = r.commit(r.head())
finally:
warnings.resetwarnings()
- self.assertEqual(obj._type, 'commit')
-
+ self.assertEqual(obj.type_name, 'commit')
+
def test_commit_not_commit(self):
r = self._repo = open_repo('a.git')
warnings.simplefilter("ignore", DeprecationWarning)
@@ -119,7 +119,7 @@ r.commit, '4f2e6529203aa6d44b5af6e3292c837ceda003f9')
finally:
warnings.resetwarnings()
-
+
def test_tree(self):
r = self._repo = open_repo('a.git')
commit = r[r.head()]
@@ -128,9 +128,9 @@ tree = r.tree(commit.tree)
finally:
warnings.resetwarnings()
- self.assertEqual(tree._type, 'tree')
+ self.assertEqual(tree.type_name, 'tree')
self.assertEqual(tree.sha().hexdigest(), commit.tree)
-
+
def test_tree_not_tree(self):
r = self._repo = open_repo('a.git')
warnings.simplefilter("ignore", DeprecationWarning)
@@ -147,10 +147,10 @@ tag = r.tag(tag_sha)
finally:
warnings.resetwarnings()
- self.assertEqual(tag._type, 'tag')
+ self.assertEqual(tag.type_name, 'tag')
self.assertEqual(tag.sha().hexdigest(), tag_sha)
- obj_type, obj_sha = tag.object
- self.assertEqual(obj_type, objects.Commit)
+ obj_class, obj_sha = tag.object
+ self.assertEqual(obj_class, objects.Commit)
self.assertEqual(obj_sha, r.head())
def test_tag_not_tag(self):
@@ -190,9 +190,9 @@ blob = r.get_blob(blob_sha)
finally:
warnings.resetwarnings()
- self.assertEqual(blob._type, 'blob')
+ self.assertEqual(blob.type_name, 'blob')
self.assertEqual(blob.sha().hexdigest(), blob_sha)
-
+
def test_get_blob_notblob(self):
r = self._repo = open_repo('a.git')
warnings.simplefilter("ignore", DeprecationWarning)
|
@@ -96,15 +96,11 @@ self._environ['QUERY_STRING'] = ''
class TestTag(object):
- type = Tag().type
-
- def __init__(self, sha, obj_type, obj_sha):
+ def __init__(self, sha, obj_class, obj_sha):
self.sha = lambda: sha
- self.object = (obj_type, obj_sha)
+ self.object = (obj_class, obj_sha)
class TestBlob(object):
- type = Blob().type
-
def __init__(self, sha):
self.sha = lambda: sha
@@ -112,7 +108,7 @@ blob2 = TestBlob('222')
blob3 = TestBlob('333')
- tag1 = TestTag('aaa', TestBlob.type, '222')
+ tag1 = TestTag('aaa', Blob, '222')
class TestRepo(object):
def __init__(self, objects, peeled):
|
Loading...