| | |
| | |
| |
|
| | """Additional types used by the index.""" |
| |
|
| | __all__ = ["BlobFilter", "BaseIndexEntry", "IndexEntry", "StageType"] |
| |
|
| | from binascii import b2a_hex |
| | from pathlib import Path |
| |
|
| | from git.objects import Blob |
| |
|
| | from .util import pack, unpack |
| |
|
| | |
| |
|
| | from typing import NamedTuple, Sequence, TYPE_CHECKING, Tuple, Union, cast |
| |
|
| | from git.types import PathLike |
| |
|
| | if TYPE_CHECKING: |
| | from git.repo import Repo |
| |
|
| | StageType = int |
| |
|
| | |
| |
|
| | |
| | CE_NAMEMASK = 0x0FFF |
| | CE_STAGEMASK = 0x3000 |
| | CE_EXTENDED = 0x4000 |
| | CE_VALID = 0x8000 |
| | CE_STAGESHIFT = 12 |
| |
|
| | |
| |
|
| |
|
| | class BlobFilter: |
| | """Predicate to be used by |
| | :meth:`IndexFile.iter_blobs <git.index.base.IndexFile.iter_blobs>` allowing to |
| | filter only return blobs which match the given list of directories or files. |
| | |
| | The given paths are given relative to the repository. |
| | """ |
| |
|
| | __slots__ = ("paths",) |
| |
|
| | def __init__(self, paths: Sequence[PathLike]) -> None: |
| | """ |
| | :param paths: |
| | Tuple or list of paths which are either pointing to directories or to files |
| | relative to the current repository. |
| | """ |
| | self.paths = paths |
| |
|
| | def __call__(self, stage_blob: Tuple[StageType, Blob]) -> bool: |
| | blob_pathlike: PathLike = stage_blob[1].path |
| | blob_path: Path = blob_pathlike if isinstance(blob_pathlike, Path) else Path(blob_pathlike) |
| | for pathlike in self.paths: |
| | path: Path = pathlike if isinstance(pathlike, Path) else Path(pathlike) |
| | |
| | |
| | filter_parts = path.parts |
| | blob_parts = blob_path.parts |
| | if len(filter_parts) > len(blob_parts): |
| | continue |
| | if all(i == j for i, j in zip(filter_parts, blob_parts)): |
| | return True |
| | return False |
| |
|
| |
|
| | class BaseIndexEntryHelper(NamedTuple): |
| | """Typed named tuple to provide named attribute access for :class:`BaseIndexEntry`. |
| | |
| | This is needed to allow overriding ``__new__`` in child class to preserve backwards |
| | compatibility. |
| | """ |
| |
|
| | mode: int |
| | binsha: bytes |
| | flags: int |
| | path: PathLike |
| | ctime_bytes: bytes = pack(">LL", 0, 0) |
| | mtime_bytes: bytes = pack(">LL", 0, 0) |
| | dev: int = 0 |
| | inode: int = 0 |
| | uid: int = 0 |
| | gid: int = 0 |
| | size: int = 0 |
| |
|
| |
|
| | class BaseIndexEntry(BaseIndexEntryHelper): |
| | R"""Small brother of an index entry which can be created to describe changes |
| | done to the index in which case plenty of additional information is not required. |
| | |
| | As the first 4 data members match exactly to the :class:`IndexEntry` type, methods |
| | expecting a :class:`BaseIndexEntry` can also handle full :class:`IndexEntry`\s even |
| | if they use numeric indices for performance reasons. |
| | """ |
| |
|
| | def __new__( |
| | cls, |
| | inp_tuple: Union[ |
| | Tuple[int, bytes, int, PathLike], |
| | Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int], |
| | ], |
| | ) -> "BaseIndexEntry": |
| | """Override ``__new__`` to allow construction from a tuple for backwards |
| | compatibility.""" |
| | return super().__new__(cls, *inp_tuple) |
| |
|
| | def __str__(self) -> str: |
| | return "%o %s %i\t%s" % (self.mode, self.hexsha, self.stage, self.path) |
| |
|
| | def __repr__(self) -> str: |
| | return "(%o, %s, %i, %s)" % (self.mode, self.hexsha, self.stage, self.path) |
| |
|
| | @property |
| | def hexsha(self) -> str: |
| | """hex version of our sha""" |
| | return b2a_hex(self.binsha).decode("ascii") |
| |
|
| | @property |
| | def stage(self) -> int: |
| | """Stage of the entry, either: |
| | |
| | * 0 = default stage |
| | * 1 = stage before a merge or common ancestor entry in case of a 3 way merge |
| | * 2 = stage of entries from the 'left' side of the merge |
| | * 3 = stage of entries from the 'right' side of the merge |
| | |
| | :note: |
| | For more information, see :manpage:`git-read-tree(1)`. |
| | """ |
| | return (self.flags & CE_STAGEMASK) >> CE_STAGESHIFT |
| |
|
| | @classmethod |
| | def from_blob(cls, blob: Blob, stage: int = 0) -> "BaseIndexEntry": |
| | """:return: Fully equipped BaseIndexEntry at the given stage""" |
| | return cls((blob.mode, blob.binsha, stage << CE_STAGESHIFT, blob.path)) |
| |
|
| | def to_blob(self, repo: "Repo") -> Blob: |
| | """:return: Blob using the information of this index entry""" |
| | return Blob(repo, self.binsha, self.mode, self.path) |
| |
|
| |
|
| | class IndexEntry(BaseIndexEntry): |
| | """Allows convenient access to index entry data as defined in |
| | :class:`BaseIndexEntry` without completely unpacking it. |
| | |
| | Attributes usually accessed often are cached in the tuple whereas others are |
| | unpacked on demand. |
| | |
| | See the properties for a mapping between names and tuple indices. |
| | """ |
| |
|
| | @property |
| | def ctime(self) -> Tuple[int, int]: |
| | """ |
| | :return: |
| | Tuple(int_time_seconds_since_epoch, int_nano_seconds) of the |
| | file's creation time |
| | """ |
| | return cast(Tuple[int, int], unpack(">LL", self.ctime_bytes)) |
| |
|
| | @property |
| | def mtime(self) -> Tuple[int, int]: |
| | """See :attr:`ctime` property, but returns modification time.""" |
| | return cast(Tuple[int, int], unpack(">LL", self.mtime_bytes)) |
| |
|
| | @classmethod |
| | def from_base(cls, base: "BaseIndexEntry") -> "IndexEntry": |
| | """ |
| | :return: |
| | Minimal entry as created from the given :class:`BaseIndexEntry` instance. |
| | Missing values will be set to null-like values. |
| | |
| | :param base: |
| | Instance of type :class:`BaseIndexEntry`. |
| | """ |
| | time = pack(">LL", 0, 0) |
| | return IndexEntry((base.mode, base.binsha, base.flags, base.path, time, time, 0, 0, 0, 0, 0)) |
| |
|
| | @classmethod |
| | def from_blob(cls, blob: Blob, stage: int = 0) -> "IndexEntry": |
| | """:return: Minimal entry resembling the given blob object""" |
| | time = pack(">LL", 0, 0) |
| | return IndexEntry( |
| | ( |
| | blob.mode, |
| | blob.binsha, |
| | stage << CE_STAGESHIFT, |
| | blob.path, |
| | time, |
| | time, |
| | 0, |
| | 0, |
| | 0, |
| | 0, |
| | blob.size, |
| | ) |
| | ) |
| |
|