Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/git/index/typ.py: 72%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This module is part of GitPython and is released under the
2# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
4"""Additional types used by the index."""
6__all__ = ["BlobFilter", "BaseIndexEntry", "IndexEntry", "StageType"]
8from binascii import b2a_hex
9from pathlib import Path
11from git.objects import Blob
13from .util import pack, unpack
15# typing ----------------------------------------------------------------------
17from typing import NamedTuple, Sequence, TYPE_CHECKING, Tuple, Union, cast
19from git.types import PathLike
21if TYPE_CHECKING:
22 from git.repo import Repo
24StageType = int
26# ---------------------------------------------------------------------------------
28# { Invariants
29CE_NAMEMASK = 0x0FFF
30CE_STAGEMASK = 0x3000
31CE_EXTENDED = 0x4000
32CE_VALID = 0x8000
33CE_STAGESHIFT = 12
35CE_EXT_SKIP_WORKTREE = 0x4000
36CE_EXT_INTENT_TO_ADD = 0x2000
38# } END invariants
41class BlobFilter:
42 """Predicate to be used by
43 :meth:`IndexFile.iter_blobs <git.index.base.IndexFile.iter_blobs>` allowing to
44 filter only return blobs which match the given list of directories or files.
46 The given paths are given relative to the repository.
47 """
49 __slots__ = ("paths",)
51 def __init__(self, paths: Sequence[PathLike]) -> None:
52 """
53 :param paths:
54 Tuple or list of paths which are either pointing to directories or to files
55 relative to the current repository.
56 """
57 self.paths = paths
59 def __call__(self, stage_blob: Tuple[StageType, Blob]) -> bool:
60 blob_pathlike: PathLike = stage_blob[1].path
61 blob_path: Path = blob_pathlike if isinstance(blob_pathlike, Path) else Path(blob_pathlike)
62 for pathlike in self.paths:
63 path: Path = pathlike if isinstance(pathlike, Path) else Path(pathlike)
64 # TODO: Change to use `PosixPath.is_relative_to` once Python 3.8 is no
65 # longer supported.
66 filter_parts = path.parts
67 blob_parts = blob_path.parts
68 if len(filter_parts) > len(blob_parts):
69 continue
70 if all(i == j for i, j in zip(filter_parts, blob_parts)):
71 return True
72 return False
75class BaseIndexEntryHelper(NamedTuple):
76 """Typed named tuple to provide named attribute access for :class:`BaseIndexEntry`.
78 This is needed to allow overriding ``__new__`` in child class to preserve backwards
79 compatibility.
80 """
82 mode: int
83 binsha: bytes
84 flags: int
85 path: PathLike
86 ctime_bytes: bytes = pack(">LL", 0, 0)
87 mtime_bytes: bytes = pack(">LL", 0, 0)
88 dev: int = 0
89 inode: int = 0
90 uid: int = 0
91 gid: int = 0
92 size: int = 0
93 # version 3 extended flags, only when (flags & CE_EXTENDED) is set
94 extended_flags: int = 0
97class BaseIndexEntry(BaseIndexEntryHelper):
98 R"""Small brother of an index entry which can be created to describe changes
99 done to the index in which case plenty of additional information is not required.
101 As the first 4 data members match exactly to the :class:`IndexEntry` type, methods
102 expecting a :class:`BaseIndexEntry` can also handle full :class:`IndexEntry`\s even
103 if they use numeric indices for performance reasons.
104 """
106 def __new__(
107 cls,
108 inp_tuple: Union[
109 Tuple[int, bytes, int, PathLike],
110 Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int, int],
111 ],
112 ) -> "BaseIndexEntry":
113 """Override ``__new__`` to allow construction from a tuple for backwards
114 compatibility."""
115 return super().__new__(cls, *inp_tuple)
117 def __str__(self) -> str:
118 return "%o %s %i\t%s" % (self.mode, self.hexsha, self.stage, self.path)
120 def __repr__(self) -> str:
121 return "(%o, %s, %i, %s)" % (self.mode, self.hexsha, self.stage, self.path)
123 @property
124 def hexsha(self) -> str:
125 """hex version of our sha"""
126 return b2a_hex(self.binsha).decode("ascii")
128 @property
129 def stage(self) -> int:
130 """Stage of the entry, either:
132 * 0 = default stage
133 * 1 = stage before a merge or common ancestor entry in case of a 3 way merge
134 * 2 = stage of entries from the 'left' side of the merge
135 * 3 = stage of entries from the 'right' side of the merge
137 :note:
138 For more information, see :manpage:`git-read-tree(1)`.
139 """
140 return (self.flags & CE_STAGEMASK) >> CE_STAGESHIFT
142 @property
143 def skip_worktree(self) -> bool:
144 return (self.extended_flags & CE_EXT_SKIP_WORKTREE) > 0
146 @property
147 def intent_to_add(self) -> bool:
148 return (self.extended_flags & CE_EXT_INTENT_TO_ADD) > 0
150 @classmethod
151 def from_blob(cls, blob: Blob, stage: int = 0) -> "BaseIndexEntry":
152 """:return: Fully equipped BaseIndexEntry at the given stage"""
153 return cls((blob.mode, blob.binsha, stage << CE_STAGESHIFT, blob.path))
155 def to_blob(self, repo: "Repo") -> Blob:
156 """:return: Blob using the information of this index entry"""
157 return Blob(repo, self.binsha, self.mode, self.path)
160class IndexEntry(BaseIndexEntry):
161 """Allows convenient access to index entry data as defined in
162 :class:`BaseIndexEntry` without completely unpacking it.
164 Attributes usually accessed often are cached in the tuple whereas others are
165 unpacked on demand.
167 See the properties for a mapping between names and tuple indices.
168 """
170 @property
171 def ctime(self) -> Tuple[int, int]:
172 """
173 :return:
174 Tuple(int_time_seconds_since_epoch, int_nano_seconds) of the
175 file's creation time
176 """
177 return cast(Tuple[int, int], unpack(">LL", self.ctime_bytes))
179 @property
180 def mtime(self) -> Tuple[int, int]:
181 """See :attr:`ctime` property, but returns modification time."""
182 return cast(Tuple[int, int], unpack(">LL", self.mtime_bytes))
184 @classmethod
185 def from_base(cls, base: "BaseIndexEntry") -> "IndexEntry":
186 """
187 :return:
188 Minimal entry as created from the given :class:`BaseIndexEntry` instance.
189 Missing values will be set to null-like values.
191 :param base:
192 Instance of type :class:`BaseIndexEntry`.
193 """
194 time = pack(">LL", 0, 0)
195 return IndexEntry((base.mode, base.binsha, base.flags, base.path, time, time, 0, 0, 0, 0, 0))
197 @classmethod
198 def from_blob(cls, blob: Blob, stage: int = 0) -> "IndexEntry":
199 """:return: Minimal entry resembling the given blob object"""
200 time = pack(">LL", 0, 0)
201 return IndexEntry(
202 (
203 blob.mode,
204 blob.binsha,
205 stage << CE_STAGESHIFT,
206 blob.path,
207 time,
208 time,
209 0,
210 0,
211 0,
212 0,
213 blob.size,
214 )
215 )