|
|
|
|
|
|
|
|
|
"""Module with basic data structures - they are designed to be lightweight and fast""" |
|
from gitdb.util import bin_to_hex |
|
|
|
from gitdb.fun import ( |
|
type_id_to_type_map, |
|
type_to_type_id_map |
|
) |
|
|
|
__all__ = ('OInfo', 'OPackInfo', 'ODeltaPackInfo', |
|
'OStream', 'OPackStream', 'ODeltaPackStream', |
|
'IStream', 'InvalidOInfo', 'InvalidOStream') |
|
|
|
|
|
|
|
|
|
class OInfo(tuple): |
|
|
|
"""Carries information about an object in an ODB, providing information |
|
about the binary sha of the object, the type_string as well as the uncompressed size |
|
in bytes. |
|
|
|
It can be accessed using tuple notation and using attribute access notation:: |
|
|
|
assert dbi[0] == dbi.binsha |
|
assert dbi[1] == dbi.type |
|
assert dbi[2] == dbi.size |
|
|
|
The type is designed to be as lightweight as possible.""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, sha, type, size): |
|
return tuple.__new__(cls, (sha, type, size)) |
|
|
|
def __init__(self, *args): |
|
tuple.__init__(self) |
|
|
|
|
|
@property |
|
def binsha(self): |
|
""":return: our sha as binary, 20 bytes""" |
|
return self[0] |
|
|
|
@property |
|
def hexsha(self): |
|
""":return: our sha, hex encoded, 40 bytes""" |
|
return bin_to_hex(self[0]) |
|
|
|
@property |
|
def type(self): |
|
return self[1] |
|
|
|
@property |
|
def type_id(self): |
|
return type_to_type_id_map[self[1]] |
|
|
|
@property |
|
def size(self): |
|
return self[2] |
|
|
|
|
|
|
|
class OPackInfo(tuple): |
|
|
|
"""As OInfo, but provides a type_id property to retrieve the numerical type id, and |
|
does not include a sha. |
|
|
|
Additionally, the pack_offset is the absolute offset into the packfile at which |
|
all object information is located. The data_offset property points to the absolute |
|
location in the pack at which that actual data stream can be found.""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, packoffset, type, size): |
|
return tuple.__new__(cls, (packoffset, type, size)) |
|
|
|
def __init__(self, *args): |
|
tuple.__init__(self) |
|
|
|
|
|
|
|
@property |
|
def pack_offset(self): |
|
return self[0] |
|
|
|
@property |
|
def type(self): |
|
return type_id_to_type_map[self[1]] |
|
|
|
@property |
|
def type_id(self): |
|
return self[1] |
|
|
|
@property |
|
def size(self): |
|
return self[2] |
|
|
|
|
|
|
|
|
|
class ODeltaPackInfo(OPackInfo): |
|
|
|
"""Adds delta specific information, |
|
Either the 20 byte sha which points to some object in the database, |
|
or the negative offset from the pack_offset, so that pack_offset - delta_info yields |
|
the pack offset of the base object""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, packoffset, type, size, delta_info): |
|
return tuple.__new__(cls, (packoffset, type, size, delta_info)) |
|
|
|
|
|
@property |
|
def delta_info(self): |
|
return self[3] |
|
|
|
|
|
|
|
class OStream(OInfo): |
|
|
|
"""Base for object streams retrieved from the database, providing additional |
|
information about the stream. |
|
Generally, ODB streams are read-only as objects are immutable""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, sha, type, size, stream, *args, **kwargs): |
|
"""Helps with the initialization of subclasses""" |
|
return tuple.__new__(cls, (sha, type, size, stream)) |
|
|
|
def __init__(self, *args, **kwargs): |
|
tuple.__init__(self) |
|
|
|
|
|
|
|
def read(self, size=-1): |
|
return self[3].read(size) |
|
|
|
@property |
|
def stream(self): |
|
return self[3] |
|
|
|
|
|
|
|
|
|
class ODeltaStream(OStream): |
|
|
|
"""Uses size info of its stream, delaying reads""" |
|
|
|
def __new__(cls, sha, type, size, stream, *args, **kwargs): |
|
"""Helps with the initialization of subclasses""" |
|
return tuple.__new__(cls, (sha, type, size, stream)) |
|
|
|
|
|
|
|
@property |
|
def size(self): |
|
return self[3].size |
|
|
|
|
|
|
|
|
|
class OPackStream(OPackInfo): |
|
|
|
"""Next to pack object information, a stream outputting an undeltified base object |
|
is provided""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, packoffset, type, size, stream, *args): |
|
"""Helps with the initialization of subclasses""" |
|
return tuple.__new__(cls, (packoffset, type, size, stream)) |
|
|
|
|
|
def read(self, size=-1): |
|
return self[3].read(size) |
|
|
|
@property |
|
def stream(self): |
|
return self[3] |
|
|
|
|
|
|
|
class ODeltaPackStream(ODeltaPackInfo): |
|
|
|
"""Provides a stream outputting the uncompressed offset delta information""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, packoffset, type, size, delta_info, stream): |
|
return tuple.__new__(cls, (packoffset, type, size, delta_info, stream)) |
|
|
|
|
|
def read(self, size=-1): |
|
return self[4].read(size) |
|
|
|
@property |
|
def stream(self): |
|
return self[4] |
|
|
|
|
|
|
|
class IStream(list): |
|
|
|
"""Represents an input content stream to be fed into the ODB. It is mutable to allow |
|
the ODB to record information about the operations outcome right in this instance. |
|
|
|
It provides interfaces for the OStream and a StreamReader to allow the instance |
|
to blend in without prior conversion. |
|
|
|
The only method your content stream must support is 'read'""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, type, size, stream, sha=None): |
|
return list.__new__(cls, (sha, type, size, stream, None)) |
|
|
|
def __init__(self, type, size, stream, sha=None): |
|
list.__init__(self, (sha, type, size, stream, None)) |
|
|
|
|
|
@property |
|
def hexsha(self): |
|
""":return: our sha, hex encoded, 40 bytes""" |
|
return bin_to_hex(self[0]) |
|
|
|
def _error(self): |
|
""":return: the error that occurred when processing the stream, or None""" |
|
return self[4] |
|
|
|
def _set_error(self, exc): |
|
"""Set this input stream to the given exc, may be None to reset the error""" |
|
self[4] = exc |
|
|
|
error = property(_error, _set_error) |
|
|
|
|
|
|
|
|
|
|
|
def read(self, size=-1): |
|
"""Implements a simple stream reader interface, passing the read call on |
|
to our internal stream""" |
|
return self[3].read(size) |
|
|
|
|
|
|
|
|
|
|
|
def _set_binsha(self, binsha): |
|
self[0] = binsha |
|
|
|
def _binsha(self): |
|
return self[0] |
|
|
|
binsha = property(_binsha, _set_binsha) |
|
|
|
def _type(self): |
|
return self[1] |
|
|
|
def _set_type(self, type): |
|
self[1] = type |
|
|
|
type = property(_type, _set_type) |
|
|
|
def _size(self): |
|
return self[2] |
|
|
|
def _set_size(self, size): |
|
self[2] = size |
|
|
|
size = property(_size, _set_size) |
|
|
|
def _stream(self): |
|
return self[3] |
|
|
|
def _set_stream(self, stream): |
|
self[3] = stream |
|
|
|
stream = property(_stream, _set_stream) |
|
|
|
|
|
|
|
|
|
class InvalidOInfo(tuple): |
|
|
|
"""Carries information about a sha identifying an object which is invalid in |
|
the queried database. The exception attribute provides more information about |
|
the cause of the issue""" |
|
__slots__ = tuple() |
|
|
|
def __new__(cls, sha, exc): |
|
return tuple.__new__(cls, (sha, exc)) |
|
|
|
def __init__(self, sha, exc): |
|
tuple.__init__(self, (sha, exc)) |
|
|
|
@property |
|
def binsha(self): |
|
return self[0] |
|
|
|
@property |
|
def hexsha(self): |
|
return bin_to_hex(self[0]) |
|
|
|
@property |
|
def error(self): |
|
""":return: exception instance explaining the failure""" |
|
return self[1] |
|
|
|
|
|
class InvalidOStream(InvalidOInfo): |
|
|
|
"""Carries information about an invalid ODB stream""" |
|
__slots__ = tuple() |
|
|
|
|
|
|