Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/git/index/typ.py: 64%

74 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1"""Module with additional types used by the index""" 

2 

3from binascii import b2a_hex 

4from pathlib import Path 

5 

6from .util import pack, unpack 

7from git.objects import Blob 

8 

9 

10# typing ---------------------------------------------------------------------- 

11 

12from typing import NamedTuple, Sequence, TYPE_CHECKING, Tuple, Union, cast, List 

13 

14from git.types import PathLike 

15 

16if TYPE_CHECKING: 16 ↛ 17line 16 didn't jump to line 17, because the condition on line 16 was never true

17 from git.repo import Repo 

18 

19StageType = int 

20 

21# --------------------------------------------------------------------------------- 

22 

23__all__ = ("BlobFilter", "BaseIndexEntry", "IndexEntry", "StageType") 

24 

25# { Invariants 

26CE_NAMEMASK = 0x0FFF 

27CE_STAGEMASK = 0x3000 

28CE_EXTENDED = 0x4000 

29CE_VALID = 0x8000 

30CE_STAGESHIFT = 12 

31 

32# } END invariants 

33 

34 

35class BlobFilter(object): 

36 

37 """ 

38 Predicate to be used by iter_blobs allowing to filter only return blobs which 

39 match the given list of directories or files. 

40 

41 The given paths are given relative to the repository. 

42 """ 

43 

44 __slots__ = "paths" 

45 

46 def __init__(self, paths: Sequence[PathLike]) -> None: 

47 """ 

48 :param paths: 

49 tuple or list of paths which are either pointing to directories or 

50 to files relative to the current repository 

51 """ 

52 self.paths = paths 

53 

54 def __call__(self, stage_blob: Tuple[StageType, Blob]) -> bool: 

55 blob_pathlike: PathLike = stage_blob[1].path 

56 blob_path: Path = blob_pathlike if isinstance(blob_pathlike, Path) else Path(blob_pathlike) 

57 for pathlike in self.paths: 

58 path: Path = pathlike if isinstance(pathlike, Path) else Path(pathlike) 

59 # TODO: Change to use `PosixPath.is_relative_to` once Python 3.8 is no longer supported. 

60 filter_parts: List[str] = path.parts 

61 blob_parts: List[str] = blob_path.parts 

62 if len(filter_parts) > len(blob_parts): 

63 continue 

64 if all(i == j for i, j in zip(filter_parts, blob_parts)): 

65 return True 

66 return False 

67 

68 

69class BaseIndexEntryHelper(NamedTuple): 

70 """Typed namedtuple to provide named attribute access for BaseIndexEntry. 

71 Needed to allow overriding __new__ in child class to preserve backwards compat.""" 

72 

73 mode: int 

74 binsha: bytes 

75 flags: int 

76 path: PathLike 

77 ctime_bytes: bytes = pack(">LL", 0, 0) 

78 mtime_bytes: bytes = pack(">LL", 0, 0) 

79 dev: int = 0 

80 inode: int = 0 

81 uid: int = 0 

82 gid: int = 0 

83 size: int = 0 

84 

85 

86class BaseIndexEntry(BaseIndexEntryHelper): 

87 

88 """Small Brother of an index entry which can be created to describe changes 

89 done to the index in which case plenty of additional information is not required. 

90 

91 As the first 4 data members match exactly to the IndexEntry type, methods 

92 expecting a BaseIndexEntry can also handle full IndexEntries even if they 

93 use numeric indices for performance reasons. 

94 """ 

95 

96 def __new__( 

97 cls, 

98 inp_tuple: Union[ 

99 Tuple[int, bytes, int, PathLike], 

100 Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int], 

101 ], 

102 ) -> "BaseIndexEntry": 

103 """Override __new__ to allow construction from a tuple for backwards compatibility""" 

104 return super().__new__(cls, *inp_tuple) 

105 

106 def __str__(self) -> str: 

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

108 

109 def __repr__(self) -> str: 

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

111 

112 @property 

113 def hexsha(self) -> str: 

114 """hex version of our sha""" 

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

116 

117 @property 

118 def stage(self) -> int: 

119 """Stage of the entry, either: 

120 

121 * 0 = default stage 

122 * 1 = stage before a merge or common ancestor entry in case of a 3 way merge 

123 * 2 = stage of entries from the 'left' side of the merge 

124 * 3 = stage of entries from the right side of the merge 

125 

126 :note: For more information, see http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html 

127 """ 

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

129 

130 @classmethod 

131 def from_blob(cls, blob: Blob, stage: int = 0) -> "BaseIndexEntry": 

132 """:return: Fully equipped BaseIndexEntry at the given stage""" 

133 return cls((blob.mode, blob.binsha, stage << CE_STAGESHIFT, blob.path)) 

134 

135 def to_blob(self, repo: "Repo") -> Blob: 

136 """:return: Blob using the information of this index entry""" 

137 return Blob(repo, self.binsha, self.mode, self.path) 

138 

139 

140class IndexEntry(BaseIndexEntry): 

141 

142 """Allows convenient access to IndexEntry data without completely unpacking it. 

143 

144 Attributes usully accessed often are cached in the tuple whereas others are 

145 unpacked on demand. 

146 

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

148 

149 @property 

150 def ctime(self) -> Tuple[int, int]: 

151 """ 

152 :return: 

153 Tuple(int_time_seconds_since_epoch, int_nano_seconds) of the 

154 file's creation time""" 

155 return cast(Tuple[int, int], unpack(">LL", self.ctime_bytes)) 

156 

157 @property 

158 def mtime(self) -> Tuple[int, int]: 

159 """See ctime property, but returns modification time""" 

160 return cast(Tuple[int, int], unpack(">LL", self.mtime_bytes)) 

161 

162 @classmethod 

163 def from_base(cls, base: "BaseIndexEntry") -> "IndexEntry": 

164 """ 

165 :return: 

166 Minimal entry as created from the given BaseIndexEntry instance. 

167 Missing values will be set to null-like values 

168 

169 :param base: Instance of type BaseIndexEntry""" 

170 time = pack(">LL", 0, 0) 

171 return IndexEntry((base.mode, base.binsha, base.flags, base.path, time, time, 0, 0, 0, 0, 0)) 

172 

173 @classmethod 

174 def from_blob(cls, blob: Blob, stage: int = 0) -> "IndexEntry": 

175 """:return: Minimal entry resembling the given blob object""" 

176 time = pack(">LL", 0, 0) 

177 return IndexEntry( 

178 ( 

179 blob.mode, 

180 blob.binsha, 

181 stage << CE_STAGESHIFT, 

182 blob.path, 

183 time, 

184 time, 

185 0, 

186 0, 

187 0, 

188 0, 

189 blob.size, 

190 ) 

191 )