Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/dulwich/object_format.py: 57%

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

49 statements  

1# hash.py -- Object format abstraction layer for Git 

2# Copyright (C) 2024 The Dulwich contributors 

3# 

4# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 

5# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU 

6# General Public License as published by the Free Software Foundation; version 2.0 

7# or (at your option) any later version. You can redistribute it and/or 

8# modify it under the terms of either of these two licenses. 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, 

12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

13# See the License for the specific language governing permissions and 

14# limitations under the License. 

15# 

16# You should have received a copy of the licenses; if not, see 

17# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License 

18# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache 

19# License, Version 2.0. 

20# 

21 

22"""Object format abstraction for Git objects. 

23 

24This module provides an abstraction layer for different object formats 

25used in Git repositories (SHA-1 and SHA-256). 

26""" 

27 

28__all__ = [ 

29 "DEFAULT_OBJECT_FORMAT", 

30 "OBJECT_FORMATS", 

31 "OBJECT_FORMAT_TYPE_NUMS", 

32 "SHA1", 

33 "SHA256", 

34 "ObjectFormat", 

35 "get_object_format", 

36 "verify_same_object_format", 

37] 

38 

39from collections.abc import Callable 

40from hashlib import sha1, sha256 

41from typing import TYPE_CHECKING 

42 

43if TYPE_CHECKING: 

44 from _hashlib import HASH 

45 

46 

47class ObjectFormat: 

48 """Object format (hash algorithm) used in Git.""" 

49 

50 def __init__( 

51 self, 

52 name: str, 

53 type_num: int, 

54 oid_length: int, 

55 hex_length: int, 

56 hash_func: Callable[[], "HASH"], 

57 ) -> None: 

58 """Initialize an object format. 

59 

60 Args: 

61 name: Name of the format (e.g., "sha1", "sha256") 

62 type_num: Format type number used in Git 

63 oid_length: Length of the binary object ID in bytes 

64 hex_length: Length of the hexadecimal object ID in characters 

65 hash_func: Hash function from hashlib 

66 """ 

67 self.name = name 

68 self.type_num = type_num 

69 self.oid_length = oid_length 

70 self.hex_length = hex_length 

71 self.hash_func = hash_func 

72 

73 def __str__(self) -> str: 

74 """Return string representation.""" 

75 return self.name 

76 

77 def __repr__(self) -> str: 

78 """Return repr.""" 

79 return f"ObjectFormat({self.name!r})" 

80 

81 def new_hash(self) -> "HASH": 

82 """Create a new hash object.""" 

83 return self.hash_func() 

84 

85 def hash_object(self, data: bytes) -> bytes: 

86 """Hash data and return the digest. 

87 

88 Args: 

89 data: Data to hash 

90 

91 Returns: 

92 Binary digest 

93 """ 

94 h = self.new_hash() 

95 h.update(data) 

96 return h.digest() 

97 

98 def hash_object_hex(self, data: bytes) -> bytes: 

99 """Hash data and return the hexadecimal digest. 

100 

101 Args: 

102 data: Data to hash 

103 

104 Returns: 

105 Hexadecimal digest as bytes 

106 """ 

107 h = self.new_hash() 

108 h.update(data) 

109 return h.hexdigest().encode("ascii") 

110 

111 

112# Define the supported object formats 

113SHA1 = ObjectFormat("sha1", type_num=1, oid_length=20, hex_length=40, hash_func=sha1) 

114SHA256 = ObjectFormat( 

115 "sha256", type_num=20, oid_length=32, hex_length=64, hash_func=sha256 

116) 

117 

118# Map of format names to ObjectFormat instances 

119OBJECT_FORMATS = { 

120 "sha1": SHA1, 

121 "sha256": SHA256, 

122} 

123 

124# Map of format numbers to ObjectFormat instances 

125OBJECT_FORMAT_TYPE_NUMS = { 

126 1: SHA1, 

127 2: SHA256, 

128} 

129 

130# Default format for backward compatibility 

131DEFAULT_OBJECT_FORMAT = SHA1 

132 

133 

134def get_object_format(name: str | None = None) -> ObjectFormat: 

135 """Get an object format by name. 

136 

137 Args: 

138 name: Format name ("sha1" or "sha256"). If None, returns default. 

139 

140 Returns: 

141 ObjectFormat instance 

142 

143 Raises: 

144 ValueError: If the format name is not supported 

145 """ 

146 if name is None: 

147 return DEFAULT_OBJECT_FORMAT 

148 try: 

149 return OBJECT_FORMATS[name.lower()] 

150 except KeyError: 

151 raise ValueError(f"Unsupported object format: {name}") 

152 

153 

154def verify_same_object_format(*formats: ObjectFormat) -> ObjectFormat: 

155 """Verify that all provided object formats are the same. 

156 

157 Args: 

158 *formats: Object format instances to verify 

159 

160 Returns: 

161 The common object format 

162 

163 Raises: 

164 ValueError: If formats don't match or no formats provided 

165 """ 

166 if not formats: 

167 raise ValueError("At least one object format must be provided") 

168 

169 first = formats[0] 

170 for fmt in formats[1:]: 

171 if fmt != first: 

172 raise ValueError(f"Object format mismatch: {first.name} != {fmt.name}") 

173 

174 return first