Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/git/objects/base.py: 42%

89 statements  

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

1# base.py 

2# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors 

3# 

4# This module is part of GitPython and is released under 

5# the BSD License: http://www.opensource.org/licenses/bsd-license.php 

6 

7from git.exc import WorkTreeRepositoryUnsupported 

8from git.util import LazyMixin, join_path_native, stream_copy, bin_to_hex 

9 

10import gitdb.typ as dbtyp 

11import os.path as osp 

12 

13from .util import get_object_type_by_name 

14 

15 

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

17 

18from typing import Any, TYPE_CHECKING, Union 

19 

20from git.types import PathLike, Commit_ish, Lit_commit_ish 

21 

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

23 from git.repo import Repo 

24 from gitdb.base import OStream 

25 from .tree import Tree 

26 from .blob import Blob 

27 from .submodule.base import Submodule 

28 from git.refs.reference import Reference 

29 

30IndexObjUnion = Union["Tree", "Blob", "Submodule"] 

31 

32# -------------------------------------------------------------------------- 

33 

34 

35_assertion_msg_format = "Created object %r whose python type %r disagrees with the actual git object type %r" 

36 

37__all__ = ("Object", "IndexObject") 

38 

39 

40class Object(LazyMixin): 

41 

42 """Implements an Object which may be Blobs, Trees, Commits and Tags""" 

43 

44 NULL_HEX_SHA = "0" * 40 

45 NULL_BIN_SHA = b"\0" * 20 

46 

47 TYPES = ( 

48 dbtyp.str_blob_type, 

49 dbtyp.str_tree_type, 

50 dbtyp.str_commit_type, 

51 dbtyp.str_tag_type, 

52 ) 

53 __slots__ = ("repo", "binsha", "size") 

54 type: Union[Lit_commit_ish, None] = None 

55 

56 def __init__(self, repo: "Repo", binsha: bytes): 

57 """Initialize an object by identifying it by its binary sha. 

58 All keyword arguments will be set on demand if None. 

59 

60 :param repo: repository this object is located in 

61 

62 :param binsha: 20 byte SHA1""" 

63 super(Object, self).__init__() 

64 self.repo = repo 

65 self.binsha = binsha 

66 assert len(binsha) == 20, "Require 20 byte binary sha, got %r, len = %i" % ( 

67 binsha, 

68 len(binsha), 

69 ) 

70 

71 @classmethod 

72 def new(cls, repo: "Repo", id: Union[str, "Reference"]) -> Commit_ish: 

73 """ 

74 :return: New Object instance of a type appropriate to the object type behind 

75 id. The id of the newly created object will be a binsha even though 

76 the input id may have been a Reference or Rev-Spec 

77 

78 :param id: reference, rev-spec, or hexsha 

79 

80 :note: This cannot be a __new__ method as it would always call __init__ 

81 with the input id which is not necessarily a binsha.""" 

82 return repo.rev_parse(str(id)) 

83 

84 @classmethod 

85 def new_from_sha(cls, repo: "Repo", sha1: bytes) -> Commit_ish: 

86 """ 

87 :return: new object instance of a type appropriate to represent the given 

88 binary sha1 

89 :param sha1: 20 byte binary sha1""" 

90 if sha1 == cls.NULL_BIN_SHA: 

91 # the NULL binsha is always the root commit 

92 return get_object_type_by_name(b"commit")(repo, sha1) 

93 # END handle special case 

94 oinfo = repo.odb.info(sha1) 

95 inst = get_object_type_by_name(oinfo.type)(repo, oinfo.binsha) 

96 inst.size = oinfo.size 

97 return inst 

98 

99 def _set_cache_(self, attr: str) -> None: 

100 """Retrieve object information""" 

101 if attr == "size": 

102 oinfo = self.repo.odb.info(self.binsha) 

103 self.size = oinfo.size # type: int 

104 # assert oinfo.type == self.type, _assertion_msg_format % (self.binsha, oinfo.type, self.type) 

105 else: 

106 super(Object, self)._set_cache_(attr) 

107 

108 def __eq__(self, other: Any) -> bool: 

109 """:return: True if the objects have the same SHA1""" 

110 if not hasattr(other, "binsha"): 

111 return False 

112 return self.binsha == other.binsha 

113 

114 def __ne__(self, other: Any) -> bool: 

115 """:return: True if the objects do not have the same SHA1""" 

116 if not hasattr(other, "binsha"): 

117 return True 

118 return self.binsha != other.binsha 

119 

120 def __hash__(self) -> int: 

121 """:return: Hash of our id allowing objects to be used in dicts and sets""" 

122 return hash(self.binsha) 

123 

124 def __str__(self) -> str: 

125 """:return: string of our SHA1 as understood by all git commands""" 

126 return self.hexsha 

127 

128 def __repr__(self) -> str: 

129 """:return: string with pythonic representation of our object""" 

130 return '<git.%s "%s">' % (self.__class__.__name__, self.hexsha) 

131 

132 @property 

133 def hexsha(self) -> str: 

134 """:return: 40 byte hex version of our 20 byte binary sha""" 

135 # b2a_hex produces bytes 

136 return bin_to_hex(self.binsha).decode("ascii") 

137 

138 @property 

139 def data_stream(self) -> "OStream": 

140 """:return: File Object compatible stream to the uncompressed raw data of the object 

141 :note: returned streams must be read in order""" 

142 return self.repo.odb.stream(self.binsha) 

143 

144 def stream_data(self, ostream: "OStream") -> "Object": 

145 """Writes our data directly to the given output stream 

146 :param ostream: File object compatible stream object. 

147 :return: self""" 

148 istream = self.repo.odb.stream(self.binsha) 

149 stream_copy(istream, ostream) 

150 return self 

151 

152 

153class IndexObject(Object): 

154 

155 """Base for all objects that can be part of the index file , namely Tree, Blob and 

156 SubModule objects""" 

157 

158 __slots__ = ("path", "mode") 

159 

160 # for compatibility with iterable lists 

161 _id_attribute_ = "path" 

162 

163 def __init__( 

164 self, 

165 repo: "Repo", 

166 binsha: bytes, 

167 mode: Union[None, int] = None, 

168 path: Union[None, PathLike] = None, 

169 ) -> None: 

170 """Initialize a newly instanced IndexObject 

171 

172 :param repo: is the Repo we are located in 

173 :param binsha: 20 byte sha1 

174 :param mode: 

175 is the stat compatible file mode as int, use the stat module 

176 to evaluate the information 

177 :param path: 

178 is the path to the file in the file system, relative to the git repository root, i.e. 

179 file.ext or folder/other.ext 

180 :note: 

181 Path may not be set of the index object has been created directly as it cannot 

182 be retrieved without knowing the parent tree.""" 

183 super(IndexObject, self).__init__(repo, binsha) 

184 if mode is not None: 

185 self.mode = mode 

186 if path is not None: 

187 self.path = path 

188 

189 def __hash__(self) -> int: 

190 """ 

191 :return: 

192 Hash of our path as index items are uniquely identifiable by path, not 

193 by their data !""" 

194 return hash(self.path) 

195 

196 def _set_cache_(self, attr: str) -> None: 

197 if attr in IndexObject.__slots__: 

198 # they cannot be retrieved lateron ( not without searching for them ) 

199 raise AttributeError( 

200 "Attribute '%s' unset: path and mode attributes must have been set during %s object creation" 

201 % (attr, type(self).__name__) 

202 ) 

203 else: 

204 super(IndexObject, self)._set_cache_(attr) 

205 # END handle slot attribute 

206 

207 @property 

208 def name(self) -> str: 

209 """:return: Name portion of the path, effectively being the basename""" 

210 return osp.basename(self.path) 

211 

212 @property 

213 def abspath(self) -> PathLike: 

214 """ 

215 :return: 

216 Absolute path to this index object in the file system ( as opposed to the 

217 .path field which is a path relative to the git repository ). 

218 

219 The returned path will be native to the system and contains '\' on windows.""" 

220 if self.repo.working_tree_dir is not None: 

221 return join_path_native(self.repo.working_tree_dir, self.path) 

222 else: 

223 raise WorkTreeRepositoryUnsupported("Working_tree_dir was None or empty")