mirror of https://github.com/morpheus65535/bazarr
183 lines
6.5 KiB
Python
183 lines
6.5 KiB
Python
|
# base.py
|
||
|
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
|
||
|
#
|
||
|
# This module is part of GitPython and is released under
|
||
|
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
|
||
|
from git.util import LazyMixin, join_path_native, stream_copy, bin_to_hex
|
||
|
|
||
|
import gitdb.typ as dbtyp
|
||
|
import os.path as osp
|
||
|
|
||
|
from .util import get_object_type_by_name
|
||
|
|
||
|
|
||
|
_assertion_msg_format = "Created object %r whose python type %r disagrees with the acutal git object type %r"
|
||
|
|
||
|
__all__ = ("Object", "IndexObject")
|
||
|
|
||
|
|
||
|
class Object(LazyMixin):
|
||
|
|
||
|
"""Implements an Object which may be Blobs, Trees, Commits and Tags"""
|
||
|
NULL_HEX_SHA = '0' * 40
|
||
|
NULL_BIN_SHA = b'\0' * 20
|
||
|
|
||
|
TYPES = (dbtyp.str_blob_type, dbtyp.str_tree_type, dbtyp.str_commit_type, dbtyp.str_tag_type)
|
||
|
__slots__ = ("repo", "binsha", "size")
|
||
|
type = None # to be set by subclass
|
||
|
|
||
|
def __init__(self, repo, binsha):
|
||
|
"""Initialize an object by identifying it by its binary sha.
|
||
|
All keyword arguments will be set on demand if None.
|
||
|
|
||
|
:param repo: repository this object is located in
|
||
|
|
||
|
:param binsha: 20 byte SHA1"""
|
||
|
super(Object, self).__init__()
|
||
|
self.repo = repo
|
||
|
self.binsha = binsha
|
||
|
assert len(binsha) == 20, "Require 20 byte binary sha, got %r, len = %i" % (binsha, len(binsha))
|
||
|
|
||
|
@classmethod
|
||
|
def new(cls, repo, id): # @ReservedAssignment
|
||
|
"""
|
||
|
:return: New Object instance of a type appropriate to the object type behind
|
||
|
id. The id of the newly created object will be a binsha even though
|
||
|
the input id may have been a Reference or Rev-Spec
|
||
|
|
||
|
:param id: reference, rev-spec, or hexsha
|
||
|
|
||
|
:note: This cannot be a __new__ method as it would always call __init__
|
||
|
with the input id which is not necessarily a binsha."""
|
||
|
return repo.rev_parse(str(id))
|
||
|
|
||
|
@classmethod
|
||
|
def new_from_sha(cls, repo, sha1):
|
||
|
"""
|
||
|
:return: new object instance of a type appropriate to represent the given
|
||
|
binary sha1
|
||
|
:param sha1: 20 byte binary sha1"""
|
||
|
if sha1 == cls.NULL_BIN_SHA:
|
||
|
# the NULL binsha is always the root commit
|
||
|
return get_object_type_by_name(b'commit')(repo, sha1)
|
||
|
# END handle special case
|
||
|
oinfo = repo.odb.info(sha1)
|
||
|
inst = get_object_type_by_name(oinfo.type)(repo, oinfo.binsha)
|
||
|
inst.size = oinfo.size
|
||
|
return inst
|
||
|
|
||
|
def _set_cache_(self, attr):
|
||
|
"""Retrieve object information"""
|
||
|
if attr == "size":
|
||
|
oinfo = self.repo.odb.info(self.binsha)
|
||
|
self.size = oinfo.size
|
||
|
# assert oinfo.type == self.type, _assertion_msg_format % (self.binsha, oinfo.type, self.type)
|
||
|
else:
|
||
|
super(Object, self)._set_cache_(attr)
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
""":return: True if the objects have the same SHA1"""
|
||
|
if not hasattr(other, 'binsha'):
|
||
|
return False
|
||
|
return self.binsha == other.binsha
|
||
|
|
||
|
def __ne__(self, other):
|
||
|
""":return: True if the objects do not have the same SHA1 """
|
||
|
if not hasattr(other, 'binsha'):
|
||
|
return True
|
||
|
return self.binsha != other.binsha
|
||
|
|
||
|
def __hash__(self):
|
||
|
""":return: Hash of our id allowing objects to be used in dicts and sets"""
|
||
|
return hash(self.binsha)
|
||
|
|
||
|
def __str__(self):
|
||
|
""":return: string of our SHA1 as understood by all git commands"""
|
||
|
return self.hexsha
|
||
|
|
||
|
def __repr__(self):
|
||
|
""":return: string with pythonic representation of our object"""
|
||
|
return '<git.%s "%s">' % (self.__class__.__name__, self.hexsha)
|
||
|
|
||
|
@property
|
||
|
def hexsha(self):
|
||
|
""":return: 40 byte hex version of our 20 byte binary sha"""
|
||
|
# b2a_hex produces bytes
|
||
|
return bin_to_hex(self.binsha).decode('ascii')
|
||
|
|
||
|
@property
|
||
|
def data_stream(self):
|
||
|
""" :return: File Object compatible stream to the uncompressed raw data of the object
|
||
|
:note: returned streams must be read in order"""
|
||
|
return self.repo.odb.stream(self.binsha)
|
||
|
|
||
|
def stream_data(self, ostream):
|
||
|
"""Writes our data directly to the given output stream
|
||
|
:param ostream: File object compatible stream object.
|
||
|
:return: self"""
|
||
|
istream = self.repo.odb.stream(self.binsha)
|
||
|
stream_copy(istream, ostream)
|
||
|
return self
|
||
|
|
||
|
|
||
|
class IndexObject(Object):
|
||
|
|
||
|
"""Base for all objects that can be part of the index file , namely Tree, Blob and
|
||
|
SubModule objects"""
|
||
|
__slots__ = ("path", "mode")
|
||
|
|
||
|
# for compatibility with iterable lists
|
||
|
_id_attribute_ = 'path'
|
||
|
|
||
|
def __init__(self, repo, binsha, mode=None, path=None):
|
||
|
"""Initialize a newly instanced IndexObject
|
||
|
|
||
|
:param repo: is the Repo we are located in
|
||
|
:param binsha: 20 byte sha1
|
||
|
:param mode:
|
||
|
is the stat compatible file mode as int, use the stat module
|
||
|
to evaluate the information
|
||
|
:param path:
|
||
|
is the path to the file in the file system, relative to the git repository root, i.e.
|
||
|
file.ext or folder/other.ext
|
||
|
:note:
|
||
|
Path may not be set of the index object has been created directly as it cannot
|
||
|
be retrieved without knowing the parent tree."""
|
||
|
super(IndexObject, self).__init__(repo, binsha)
|
||
|
if mode is not None:
|
||
|
self.mode = mode
|
||
|
if path is not None:
|
||
|
self.path = path
|
||
|
|
||
|
def __hash__(self):
|
||
|
"""
|
||
|
:return:
|
||
|
Hash of our path as index items are uniquely identifiable by path, not
|
||
|
by their data !"""
|
||
|
return hash(self.path)
|
||
|
|
||
|
def _set_cache_(self, attr):
|
||
|
if attr in IndexObject.__slots__:
|
||
|
# they cannot be retrieved lateron ( not without searching for them )
|
||
|
raise AttributeError(
|
||
|
"Attribute '%s' unset: path and mode attributes must have been set during %s object creation"
|
||
|
% (attr, type(self).__name__))
|
||
|
else:
|
||
|
super(IndexObject, self)._set_cache_(attr)
|
||
|
# END handle slot attribute
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
""":return: Name portion of the path, effectively being the basename"""
|
||
|
return osp.basename(self.path)
|
||
|
|
||
|
@property
|
||
|
def abspath(self):
|
||
|
"""
|
||
|
:return:
|
||
|
Absolute path to this index object in the file system ( as opposed to the
|
||
|
.path field which is a path relative to the git repository ).
|
||
|
|
||
|
The returned path will be native to the system and contains '\' on windows. """
|
||
|
return join_path_native(self.repo.working_tree_dir, self.path)
|