Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/git/index/typ.py: 74%
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
12from git.objects.base import IndexObject
14from .util import pack, unpack
16# typing ----------------------------------------------------------------------
18from typing import NamedTuple, Sequence, TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast
20from git.types import PathLike
22if TYPE_CHECKING:
23 from git.repo import Repo
25StageType = int
26_T_IndexEntry = TypeVar("_T_IndexEntry", bound="BaseIndexEntry")
28# ---------------------------------------------------------------------------------
30# { Invariants
31CE_NAMEMASK = 0x0FFF
32CE_STAGEMASK = 0x3000
33CE_EXTENDED = 0x4000
34CE_VALID = 0x8000
35CE_STAGESHIFT = 12
37CE_EXT_SKIP_WORKTREE = 0x4000
38CE_EXT_INTENT_TO_ADD = 0x2000
40# } END invariants
43class BlobFilter:
44 """Predicate to be used by
45 :meth:`IndexFile.iter_blobs <git.index.base.IndexFile.iter_blobs>` allowing to
46 filter only return blobs which match the given list of directories or files.
48 The given paths are given relative to the repository.
49 """
51 __slots__ = ("paths",)
53 def __init__(self, paths: Sequence[PathLike]) -> None:
54 """
55 :param paths:
56 Tuple or list of paths which are either pointing to directories or to files
57 relative to the current repository.
58 """
59 self.paths = paths
61 def __call__(self, stage_blob: Tuple[StageType, Blob]) -> bool:
62 blob_pathlike: PathLike = stage_blob[1].path
63 blob_path: Path = blob_pathlike if isinstance(blob_pathlike, Path) else Path(blob_pathlike)
64 for pathlike in self.paths:
65 path: Path = pathlike if isinstance(pathlike, Path) else Path(pathlike)
66 # TODO: Change to use `PosixPath.is_relative_to` once Python 3.8 is no
67 # longer supported.
68 filter_parts = path.parts
69 blob_parts = blob_path.parts
70 if len(filter_parts) > len(blob_parts):
71 continue
72 if all(i == j for i, j in zip(filter_parts, blob_parts)):
73 return True
74 return False
77class BaseIndexEntryHelper(NamedTuple):
78 """Typed named tuple to provide named attribute access for :class:`BaseIndexEntry`.
80 This is needed to allow overriding ``__new__`` in child class to preserve backwards
81 compatibility.
82 """
84 mode: int
85 binsha: bytes
86 flags: int
87 path: PathLike
88 ctime_bytes: bytes = pack(">LL", 0, 0)
89 mtime_bytes: bytes = pack(">LL", 0, 0)
90 dev: int = 0
91 inode: int = 0
92 uid: int = 0
93 gid: int = 0
94 size: int = 0
95 # version 3 extended flags, only when (flags & CE_EXTENDED) is set
96 extended_flags: int = 0
99class BaseIndexEntry(BaseIndexEntryHelper):
100 R"""Small brother of an index entry which can be created to describe changes
101 done to the index in which case plenty of additional information is not required.
103 As the first 4 data members match exactly to the :class:`IndexEntry` type, methods
104 expecting a :class:`BaseIndexEntry` can also handle full :class:`IndexEntry`\s even
105 if they use numeric indices for performance reasons.
106 """
108 def __new__(
109 cls: Type[_T_IndexEntry],
110 inp_tuple: Union[
111 Tuple[int, bytes, int, PathLike],
112 Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int],
113 Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int, int],
114 ],
115 ) -> _T_IndexEntry:
116 """Override ``__new__`` to allow construction from a tuple for backwards
117 compatibility."""
118 if len(inp_tuple) == 4:
119 return BaseIndexEntryHelper.__new__(cls, *inp_tuple)
120 if len(inp_tuple) == 11:
121 return BaseIndexEntryHelper.__new__(cls, *inp_tuple)
122 return BaseIndexEntryHelper.__new__(cls, *inp_tuple)
124 def __str__(self) -> str:
125 return "%o %s %i\t%s" % (self.mode, self.hexsha, self.stage, self.path)
127 def __repr__(self) -> str:
128 return "(%o, %s, %i, %s)" % (self.mode, self.hexsha, self.stage, self.path)
130 @property
131 def hexsha(self) -> str:
132 """hex version of our sha"""
133 return b2a_hex(self.binsha).decode("ascii")
135 @property
136 def stage(self) -> int:
137 """Stage of the entry, either:
139 * 0 = default stage
140 * 1 = stage before a merge or common ancestor entry in case of a 3 way merge
141 * 2 = stage of entries from the 'left' side of the merge
142 * 3 = stage of entries from the 'right' side of the merge
144 :note:
145 For more information, see :manpage:`git-read-tree(1)`.
146 """
147 return (self.flags & CE_STAGEMASK) >> CE_STAGESHIFT
149 @property
150 def skip_worktree(self) -> bool:
151 return (self.extended_flags & CE_EXT_SKIP_WORKTREE) > 0
153 @property
154 def intent_to_add(self) -> bool:
155 return (self.extended_flags & CE_EXT_INTENT_TO_ADD) > 0
157 @classmethod
158 def from_blob(cls, blob: IndexObject, stage: int = 0) -> "BaseIndexEntry":
159 """:return: Fully equipped BaseIndexEntry at the given stage"""
160 return cls((blob.mode, blob.binsha, stage << CE_STAGESHIFT, blob.path))
162 def to_blob(self, repo: "Repo") -> Blob:
163 """:return: Blob using the information of this index entry"""
164 return Blob(repo, self.binsha, self.mode, self.path)
167class IndexEntry(BaseIndexEntry):
168 """Allows convenient access to index entry data as defined in
169 :class:`BaseIndexEntry` without completely unpacking it.
171 Attributes usually accessed often are cached in the tuple whereas others are
172 unpacked on demand.
174 See the properties for a mapping between names and tuple indices.
175 """
177 @property
178 def ctime(self) -> Tuple[int, int]:
179 """
180 :return:
181 Tuple(int_time_seconds_since_epoch, int_nano_seconds) of the
182 file's creation time
183 """
184 return cast(Tuple[int, int], unpack(">LL", self.ctime_bytes))
186 @property
187 def mtime(self) -> Tuple[int, int]:
188 """See :attr:`ctime` property, but returns modification time."""
189 return cast(Tuple[int, int], unpack(">LL", self.mtime_bytes))
191 @classmethod
192 def from_base(cls, base: "BaseIndexEntry") -> "IndexEntry":
193 """
194 :return:
195 Minimal entry as created from the given :class:`BaseIndexEntry` instance.
196 Missing values will be set to null-like values.
198 :param base:
199 Instance of type :class:`BaseIndexEntry`.
200 """
201 time = pack(">LL", 0, 0)
202 return IndexEntry((base.mode, base.binsha, base.flags, base.path, time, time, 0, 0, 0, 0, 0))
204 @classmethod
205 def from_blob(cls, blob: IndexObject, stage: int = 0) -> "IndexEntry":
206 """:return: Minimal entry resembling the given blob object"""
207 time = pack(">LL", 0, 0)
208 return IndexEntry(
209 (
210 blob.mode,
211 blob.binsha,
212 stage << CE_STAGESHIFT,
213 blob.path,
214 time,
215 time,
216 0,
217 0,
218 0,
219 0,
220 blob.size,
221 )
222 )