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

93 statements  

1# This module is part of GitPython and is released under the 

2# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/ 

3 

4"""Additional types used by the index.""" 

5 

6__all__ = ["BlobFilter", "BaseIndexEntry", "IndexEntry", "StageType"] 

7 

8from binascii import b2a_hex 

9from pathlib import Path 

10 

11from git.objects import Blob 

12from git.objects.base import IndexObject 

13 

14from .util import pack, unpack 

15 

16# typing ---------------------------------------------------------------------- 

17 

18from typing import NamedTuple, Sequence, TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast 

19 

20from git.types import PathLike 

21 

22if TYPE_CHECKING: 

23 from git.repo import Repo 

24 

25StageType = int 

26_T_IndexEntry = TypeVar("_T_IndexEntry", bound="BaseIndexEntry") 

27 

28# --------------------------------------------------------------------------------- 

29 

30# { Invariants 

31CE_NAMEMASK = 0x0FFF 

32CE_STAGEMASK = 0x3000 

33CE_EXTENDED = 0x4000 

34CE_VALID = 0x8000 

35CE_STAGESHIFT = 12 

36 

37CE_EXT_SKIP_WORKTREE = 0x4000 

38CE_EXT_INTENT_TO_ADD = 0x2000 

39 

40# } END invariants 

41 

42 

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. 

47 

48 The given paths are given relative to the repository. 

49 """ 

50 

51 __slots__ = ("paths",) 

52 

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 

60 

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 

75 

76 

77class BaseIndexEntryHelper(NamedTuple): 

78 """Typed named tuple to provide named attribute access for :class:`BaseIndexEntry`. 

79 

80 This is needed to allow overriding ``__new__`` in child class to preserve backwards 

81 compatibility. 

82 """ 

83 

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 

97 

98 

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. 

102 

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 """ 

107 

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) 

123 

124 def __str__(self) -> str: 

125 return "%o %s %i\t%s" % (self.mode, self.hexsha, self.stage, self.path) 

126 

127 def __repr__(self) -> str: 

128 return "(%o, %s, %i, %s)" % (self.mode, self.hexsha, self.stage, self.path) 

129 

130 @property 

131 def hexsha(self) -> str: 

132 """hex version of our sha""" 

133 return b2a_hex(self.binsha).decode("ascii") 

134 

135 @property 

136 def stage(self) -> int: 

137 """Stage of the entry, either: 

138 

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 

143 

144 :note: 

145 For more information, see :manpage:`git-read-tree(1)`. 

146 """ 

147 return (self.flags & CE_STAGEMASK) >> CE_STAGESHIFT 

148 

149 @property 

150 def skip_worktree(self) -> bool: 

151 return (self.extended_flags & CE_EXT_SKIP_WORKTREE) > 0 

152 

153 @property 

154 def intent_to_add(self) -> bool: 

155 return (self.extended_flags & CE_EXT_INTENT_TO_ADD) > 0 

156 

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)) 

161 

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) 

165 

166 

167class IndexEntry(BaseIndexEntry): 

168 """Allows convenient access to index entry data as defined in 

169 :class:`BaseIndexEntry` without completely unpacking it. 

170 

171 Attributes usually accessed often are cached in the tuple whereas others are 

172 unpacked on demand. 

173 

174 See the properties for a mapping between names and tuple indices. 

175 """ 

176 

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)) 

185 

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)) 

190 

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. 

197 

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)) 

203 

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 )