Show More
@@ -1,5 +1,13 | |||||
1 | from __future__ import annotations |
|
1 | from __future__ import annotations | |
2 |
|
2 | |||
|
3 | import typing | |||
|
4 | ||||
|
5 | from typing import ( | |||
|
6 | Any, | |||
|
7 | Iterator, | |||
|
8 | Set, | |||
|
9 | ) | |||
|
10 | ||||
3 | from mercurial import ( |
|
11 | from mercurial import ( | |
4 | match as matchmod, |
|
12 | match as matchmod, | |
5 | pathutil, |
|
13 | pathutil, | |
@@ -12,6 +20,10 from mercurial.interfaces import ( | |||||
12 | ) |
|
20 | ) | |
13 | from . import gitutil |
|
21 | from . import gitutil | |
14 |
|
22 | |||
|
23 | if typing.TYPE_CHECKING: | |||
|
24 | from typing import ( | |||
|
25 | ByteString, # TODO: change to Buffer for 3.14 | |||
|
26 | ) | |||
15 |
|
27 | |||
16 | pygit2 = gitutil.get_pygit2() |
|
28 | pygit2 = gitutil.get_pygit2() | |
17 |
|
29 | |||
@@ -71,16 +83,16 class gittreemanifest: | |||||
71 | raise ValueError('unsupported mode %s' % oct(ent.filemode)) |
|
83 | raise ValueError('unsupported mode %s' % oct(ent.filemode)) | |
72 | return ent.id.raw, flags |
|
84 | return ent.id.raw, flags | |
73 |
|
85 | |||
74 | def __getitem__(self, path): |
|
86 | def __getitem__(self, path: bytes) -> bytes: | |
75 | return self._resolve_entry(path)[0] |
|
87 | return self._resolve_entry(path)[0] | |
76 |
|
88 | |||
77 | def find(self, path): |
|
89 | def find(self, path: bytes) -> tuple[bytes, bytes]: | |
78 | return self._resolve_entry(path) |
|
90 | return self._resolve_entry(path) | |
79 |
|
91 | |||
80 | def __len__(self): |
|
92 | def __len__(self) -> int: | |
81 | return len(list(self.walk(matchmod.always()))) |
|
93 | return len(list(self.walk(matchmod.always()))) | |
82 |
|
94 | |||
83 | def __nonzero__(self): |
|
95 | def __nonzero__(self) -> bool: | |
84 | try: |
|
96 | try: | |
85 | next(iter(self)) |
|
97 | next(iter(self)) | |
86 | return True |
|
98 | return True | |
@@ -89,30 +101,30 class gittreemanifest: | |||||
89 |
|
101 | |||
90 | __bool__ = __nonzero__ |
|
102 | __bool__ = __nonzero__ | |
91 |
|
103 | |||
92 | def __contains__(self, path): |
|
104 | def __contains__(self, path: bytes) -> bool: | |
93 | try: |
|
105 | try: | |
94 | self._resolve_entry(path) |
|
106 | self._resolve_entry(path) | |
95 | return True |
|
107 | return True | |
96 | except KeyError: |
|
108 | except KeyError: | |
97 | return False |
|
109 | return False | |
98 |
|
110 | |||
99 | def iterkeys(self): |
|
111 | def iterkeys(self) -> Iterator[bytes]: | |
100 | return self.walk(matchmod.always()) |
|
112 | return self.walk(matchmod.always()) | |
101 |
|
113 | |||
102 | def keys(self): |
|
114 | def keys(self) -> list[bytes]: | |
103 | return list(self.iterkeys()) |
|
115 | return list(self.iterkeys()) | |
104 |
|
116 | |||
105 | def __iter__(self): |
|
117 | def __iter__(self) -> Iterator[bytes]: | |
106 | return self.iterkeys() |
|
118 | return self.iterkeys() | |
107 |
|
119 | |||
108 | def __setitem__(self, path, node): |
|
120 | def __setitem__(self, path: bytes, node: bytes) -> None: | |
109 | self._pending_changes[path] = node, self.flags(path) |
|
121 | self._pending_changes[path] = node, self.flags(path) | |
110 |
|
122 | |||
111 | def __delitem__(self, path): |
|
123 | def __delitem__(self, path: bytes) -> None: | |
112 | # TODO: should probably KeyError for already-deleted files? |
|
124 | # TODO: should probably KeyError for already-deleted files? | |
113 | self._pending_changes[path] = None |
|
125 | self._pending_changes[path] = None | |
114 |
|
126 | |||
115 | def filesnotin(self, other, match=None): |
|
127 | def filesnotin(self, other, match=None) -> Set[bytes]: | |
116 | if match is not None: |
|
128 | if match is not None: | |
117 | match = matchmod.badmatch(match, lambda path, msg: None) |
|
129 | match = matchmod.badmatch(match, lambda path, msg: None) | |
118 | sm2 = set(other.walk(match)) |
|
130 | sm2 = set(other.walk(match)) | |
@@ -123,10 +135,18 class gittreemanifest: | |||||
123 | def _dirs(self): |
|
135 | def _dirs(self): | |
124 | return pathutil.dirs(self) |
|
136 | return pathutil.dirs(self) | |
125 |
|
137 | |||
126 | def hasdir(self, dir): |
|
138 | def hasdir(self, dir: bytes) -> bool: | |
127 | return dir in self._dirs |
|
139 | return dir in self._dirs | |
128 |
|
140 | |||
129 | def diff(self, other, match=lambda x: True, clean=False): |
|
141 | def diff( | |
|
142 | self, | |||
|
143 | other: Any, # TODO: 'manifestdict' or (better) equivalent interface | |||
|
144 | match: Any = lambda x: True, # TODO: Optional[matchmod.basematcher] = None, | |||
|
145 | clean: bool = False, | |||
|
146 | ) -> dict[ | |||
|
147 | bytes, | |||
|
148 | tuple[tuple[bytes | None, bytes], tuple[bytes | None, bytes]] | None, | |||
|
149 | ]: | |||
130 | """Finds changes between the current manifest and m2. |
|
150 | """Finds changes between the current manifest and m2. | |
131 |
|
151 | |||
132 | The result is returned as a dict with filename as key and |
|
152 | The result is returned as a dict with filename as key and | |
@@ -200,42 +220,43 class gittreemanifest: | |||||
200 |
|
220 | |||
201 | return result |
|
221 | return result | |
202 |
|
222 | |||
203 | def setflag(self, path, flag): |
|
223 | def setflag(self, path: bytes, flag: bytes) -> None: | |
204 | node, unused_flag = self._resolve_entry(path) |
|
224 | node, unused_flag = self._resolve_entry(path) | |
205 | self._pending_changes[path] = node, flag |
|
225 | self._pending_changes[path] = node, flag | |
206 |
|
226 | |||
207 | def get(self, path, default=None): |
|
227 | def get(self, path: bytes, default=None) -> bytes | None: | |
208 | try: |
|
228 | try: | |
209 | return self._resolve_entry(path)[0] |
|
229 | return self._resolve_entry(path)[0] | |
210 | except KeyError: |
|
230 | except KeyError: | |
211 | return default |
|
231 | return default | |
212 |
|
232 | |||
213 | def flags(self, path): |
|
233 | def flags(self, path: bytes) -> bytes: | |
214 | try: |
|
234 | try: | |
215 | return self._resolve_entry(path)[1] |
|
235 | return self._resolve_entry(path)[1] | |
216 | except KeyError: |
|
236 | except KeyError: | |
217 | return b'' |
|
237 | return b'' | |
218 |
|
238 | |||
219 | def copy(self): |
|
239 | def copy(self) -> 'gittreemanifest': | |
220 | return gittreemanifest( |
|
240 | return gittreemanifest( | |
221 | self._git_repo, self._tree, dict(self._pending_changes) |
|
241 | self._git_repo, self._tree, dict(self._pending_changes) | |
222 | ) |
|
242 | ) | |
223 |
|
243 | |||
224 | def items(self): |
|
244 | def items(self) -> Iterator[tuple[bytes, bytes]]: | |
225 | for f in self: |
|
245 | for f in self: | |
226 | # TODO: build a proper iterator version of this |
|
246 | # TODO: build a proper iterator version of this | |
227 | yield f, self[f] |
|
247 | yield f, self[f] | |
228 |
|
248 | |||
229 | def iteritems(self): |
|
249 | def iteritems(self) -> Iterator[tuple[bytes, bytes]]: | |
230 | return self.items() |
|
250 | return self.items() | |
231 |
|
251 | |||
232 | def iterentries(self): |
|
252 | def iterentries(self) -> Iterator[tuple[bytes, bytes, bytes]]: | |
233 | for f in self: |
|
253 | for f in self: | |
234 | # TODO: build a proper iterator version of this |
|
254 | # TODO: build a proper iterator version of this | |
235 | yield f, *self._resolve_entry(f) |
|
255 | yield f, *self._resolve_entry(f) | |
236 |
|
256 | |||
237 | def text(self): |
|
257 | def text(self) -> ByteString: | |
238 |
|
|
258 | # TODO can this method move out of the manifest iface? | |
|
259 | raise NotImplementedError | |||
239 |
|
260 | |||
240 | def _walkonetree(self, tree, match, subdir): |
|
261 | def _walkonetree(self, tree, match, subdir): | |
241 | for te in tree: |
|
262 | for te in tree: | |
@@ -249,7 +270,7 class gittreemanifest: | |||||
249 | elif match(realname): |
|
270 | elif match(realname): | |
250 | yield pycompat.fsencode(realname) |
|
271 | yield pycompat.fsencode(realname) | |
251 |
|
272 | |||
252 | def walk(self, match): |
|
273 | def walk(self, match: matchmod.basematcher) -> Iterator[bytes]: | |
253 | # TODO: this is a very lazy way to merge in the pending |
|
274 | # TODO: this is a very lazy way to merge in the pending | |
254 | # changes. There is absolutely room for optimization here by |
|
275 | # changes. There is absolutely room for optimization here by | |
255 | # being clever about walking over the sets... |
|
276 | # being clever about walking over the sets... |
@@ -19,15 +19,22 from typing import ( | |||||
19 | Iterator, |
|
19 | Iterator, | |
20 | Mapping, |
|
20 | Mapping, | |
21 | Protocol, |
|
21 | Protocol, | |
|
22 | Set, | |||
22 | ) |
|
23 | ) | |
23 |
|
24 | |||
24 | from ..i18n import _ |
|
25 | from ..i18n import _ | |
25 | from .. import error |
|
26 | from .. import error | |
26 |
|
27 | |||
27 | if typing.TYPE_CHECKING: |
|
28 | if typing.TYPE_CHECKING: | |
|
29 | from typing import ( | |||
|
30 | ByteString, # TODO: change to Buffer for 3.14 | |||
|
31 | ) | |||
|
32 | ||||
28 | # Almost all mercurial modules are only imported in the type checking phase |
|
33 | # Almost all mercurial modules are only imported in the type checking phase | |
29 | # to avoid circular imports |
|
34 | # to avoid circular imports | |
30 | from .. import ( |
|
35 | from .. import ( | |
|
36 | match as matchmod, | |||
|
37 | pathutil, | |||
31 | util, |
|
38 | util, | |
32 | ) |
|
39 | ) | |
33 | from ..utils import ( |
|
40 | from ..utils import ( | |
@@ -1052,7 +1059,7 class imanifestdict(Protocol): | |||||
1052 | consists of a binary node and extra flags affecting that entry. |
|
1059 | consists of a binary node and extra flags affecting that entry. | |
1053 | """ |
|
1060 | """ | |
1054 |
|
1061 | |||
1055 |
def __getitem__(self, |
|
1062 | def __getitem__(self, key: bytes) -> bytes: | |
1056 | """Returns the binary node value for a path in the manifest. |
|
1063 | """Returns the binary node value for a path in the manifest. | |
1057 |
|
1064 | |||
1058 | Raises ``KeyError`` if the path does not exist in the manifest. |
|
1065 | Raises ``KeyError`` if the path does not exist in the manifest. | |
@@ -1060,7 +1067,7 class imanifestdict(Protocol): | |||||
1060 | Equivalent to ``self.find(path)[0]``. |
|
1067 | Equivalent to ``self.find(path)[0]``. | |
1061 | """ |
|
1068 | """ | |
1062 |
|
1069 | |||
1063 | def find(self, path): |
|
1070 | def find(self, path: bytes) -> tuple[bytes, bytes]: | |
1064 | """Returns the entry for a path in the manifest. |
|
1071 | """Returns the entry for a path in the manifest. | |
1065 |
|
1072 | |||
1066 | Returns a 2-tuple of (node, flags). |
|
1073 | Returns a 2-tuple of (node, flags). | |
@@ -1068,46 +1075,46 class imanifestdict(Protocol): | |||||
1068 | Raises ``KeyError`` if the path does not exist in the manifest. |
|
1075 | Raises ``KeyError`` if the path does not exist in the manifest. | |
1069 | """ |
|
1076 | """ | |
1070 |
|
1077 | |||
1071 | def __len__(self): |
|
1078 | def __len__(self) -> int: | |
1072 | """Return the number of entries in the manifest.""" |
|
1079 | """Return the number of entries in the manifest.""" | |
1073 |
|
1080 | |||
1074 | def __nonzero__(self): |
|
1081 | def __nonzero__(self) -> bool: | |
1075 | """Returns True if the manifest has entries, False otherwise.""" |
|
1082 | """Returns True if the manifest has entries, False otherwise.""" | |
1076 |
|
1083 | |||
1077 | __bool__ = __nonzero__ |
|
1084 | __bool__ = __nonzero__ | |
1078 |
|
1085 | |||
1079 | def set(self, path, node, flags): |
|
1086 | def set(self, path: bytes, node: bytes, flags: bytes) -> None: | |
1080 | """Define the node value and flags for a path in the manifest. |
|
1087 | """Define the node value and flags for a path in the manifest. | |
1081 |
|
1088 | |||
1082 | Equivalent to __setitem__ followed by setflag, but can be more efficient. |
|
1089 | Equivalent to __setitem__ followed by setflag, but can be more efficient. | |
1083 | """ |
|
1090 | """ | |
1084 |
|
1091 | |||
1085 | def __setitem__(self, path, node): |
|
1092 | def __setitem__(self, path: bytes, node: bytes) -> None: | |
1086 | """Define the node value for a path in the manifest. |
|
1093 | """Define the node value for a path in the manifest. | |
1087 |
|
1094 | |||
1088 | If the path is already in the manifest, its flags will be copied to |
|
1095 | If the path is already in the manifest, its flags will be copied to | |
1089 | the new entry. |
|
1096 | the new entry. | |
1090 | """ |
|
1097 | """ | |
1091 |
|
1098 | |||
1092 | def __contains__(self, path): |
|
1099 | def __contains__(self, path: bytes) -> bool: | |
1093 | """Whether a path exists in the manifest.""" |
|
1100 | """Whether a path exists in the manifest.""" | |
1094 |
|
1101 | |||
1095 | def __delitem__(self, path): |
|
1102 | def __delitem__(self, path: bytes) -> None: | |
1096 | """Remove a path from the manifest. |
|
1103 | """Remove a path from the manifest. | |
1097 |
|
1104 | |||
1098 | Raises ``KeyError`` if the path is not in the manifest. |
|
1105 | Raises ``KeyError`` if the path is not in the manifest. | |
1099 | """ |
|
1106 | """ | |
1100 |
|
1107 | |||
1101 | def __iter__(self): |
|
1108 | def __iter__(self) -> Iterator[bytes]: | |
1102 | """Iterate over paths in the manifest.""" |
|
1109 | """Iterate over paths in the manifest.""" | |
1103 |
|
1110 | |||
1104 | def iterkeys(self): |
|
1111 | def iterkeys(self) -> Iterator[bytes]: | |
1105 | """Iterate over paths in the manifest.""" |
|
1112 | """Iterate over paths in the manifest.""" | |
1106 |
|
1113 | |||
1107 | def keys(self): |
|
1114 | def keys(self) -> list[bytes]: | |
1108 | """Obtain a list of paths in the manifest.""" |
|
1115 | """Obtain a list of paths in the manifest.""" | |
1109 |
|
1116 | |||
1110 | def filesnotin(self, other, match=None): |
|
1117 | def filesnotin(self, other, match=None) -> Set[bytes]: | |
1111 | """Obtain the set of paths in this manifest but not in another. |
|
1118 | """Obtain the set of paths in this manifest but not in another. | |
1112 |
|
1119 | |||
1113 | ``match`` is an optional matcher function to be applied to both |
|
1120 | ``match`` is an optional matcher function to be applied to both | |
@@ -1116,20 +1123,28 class imanifestdict(Protocol): | |||||
1116 | Returns a set of paths. |
|
1123 | Returns a set of paths. | |
1117 | """ |
|
1124 | """ | |
1118 |
|
1125 | |||
1119 | def dirs(self): |
|
1126 | def dirs(self) -> pathutil.dirs: | |
1120 | """Returns an object implementing the ``idirs`` interface.""" |
|
1127 | """Returns an object implementing the ``idirs`` interface.""" | |
1121 |
|
1128 | |||
1122 | def hasdir(self, dir): |
|
1129 | def hasdir(self, dir: bytes) -> bool: | |
1123 | """Returns a bool indicating if a directory is in this manifest.""" |
|
1130 | """Returns a bool indicating if a directory is in this manifest.""" | |
1124 |
|
1131 | |||
1125 | def walk(self, match): |
|
1132 | def walk(self, match: matchmod.basematcher) -> Iterator[bytes]: | |
1126 | """Generator of paths in manifest satisfying a matcher. |
|
1133 | """Generator of paths in manifest satisfying a matcher. | |
1127 |
|
1134 | |||
1128 | If the matcher has explicit files listed and they don't exist in |
|
1135 | If the matcher has explicit files listed and they don't exist in | |
1129 | the manifest, ``match.bad()`` is called for each missing file. |
|
1136 | the manifest, ``match.bad()`` is called for each missing file. | |
1130 | """ |
|
1137 | """ | |
1131 |
|
1138 | |||
1132 | def diff(self, other, match=None, clean=False): |
|
1139 | def diff( | |
|
1140 | self, | |||
|
1141 | other: Any, # TODO: 'manifestdict' or (better) equivalent interface | |||
|
1142 | match: matchmod.basematcher | None = None, | |||
|
1143 | clean: bool = False, | |||
|
1144 | ) -> dict[ | |||
|
1145 | bytes, | |||
|
1146 | tuple[tuple[bytes | None, bytes], tuple[bytes | None, bytes]] | None, | |||
|
1147 | ]: | |||
1133 | """Find differences between this manifest and another. |
|
1148 | """Find differences between this manifest and another. | |
1134 |
|
1149 | |||
1135 | This manifest is compared to ``other``. |
|
1150 | This manifest is compared to ``other``. | |
@@ -1146,41 +1161,43 class imanifestdict(Protocol): | |||||
1146 | are the same for the other manifest. |
|
1161 | are the same for the other manifest. | |
1147 | """ |
|
1162 | """ | |
1148 |
|
1163 | |||
1149 | def setflag(self, path, flag): |
|
1164 | def setflag(self, path: bytes, flag: bytes) -> None: | |
1150 | """Set the flag value for a given path. |
|
1165 | """Set the flag value for a given path. | |
1151 |
|
1166 | |||
1152 | Raises ``KeyError`` if the path is not already in the manifest. |
|
1167 | Raises ``KeyError`` if the path is not already in the manifest. | |
1153 | """ |
|
1168 | """ | |
1154 |
|
1169 | |||
1155 | def get(self, path, default=None): |
|
1170 | def get(self, path: bytes, default=None) -> bytes | None: | |
1156 | """Obtain the node value for a path or a default value if missing.""" |
|
1171 | """Obtain the node value for a path or a default value if missing.""" | |
1157 |
|
1172 | |||
1158 | def flags(self, path): |
|
1173 | def flags(self, path: bytes) -> bytes: | |
1159 | """Return the flags value for a path (default: empty bytestring).""" |
|
1174 | """Return the flags value for a path (default: empty bytestring).""" | |
1160 |
|
1175 | |||
1161 | def copy(self): |
|
1176 | def copy(self) -> 'imanifestdict': | |
1162 | """Return a copy of this manifest.""" |
|
1177 | """Return a copy of this manifest.""" | |
1163 |
|
1178 | |||
1164 | def items(self): |
|
1179 | def items(self) -> Iterator[tuple[bytes, bytes]]: | |
1165 | """Returns an iterable of (path, node) for items in this manifest.""" |
|
1180 | """Returns an iterable of (path, node) for items in this manifest.""" | |
1166 |
|
1181 | |||
1167 | def iteritems(self): |
|
1182 | def iteritems(self) -> Iterator[tuple[bytes, bytes]]: | |
1168 | """Identical to items().""" |
|
1183 | """Identical to items().""" | |
1169 |
|
1184 | |||
1170 | def iterentries(self): |
|
1185 | def iterentries(self) -> Iterator[tuple[bytes, bytes, bytes]]: | |
1171 | """Returns an iterable of (path, node, flags) for this manifest. |
|
1186 | """Returns an iterable of (path, node, flags) for this manifest. | |
1172 |
|
1187 | |||
1173 | Similar to ``iteritems()`` except items are a 3-tuple and include |
|
1188 | Similar to ``iteritems()`` except items are a 3-tuple and include | |
1174 | flags. |
|
1189 | flags. | |
1175 | """ |
|
1190 | """ | |
1176 |
|
1191 | |||
1177 | def text(self): |
|
1192 | def text(self) -> ByteString: | |
1178 | """Obtain the raw data representation for this manifest. |
|
1193 | """Obtain the raw data representation for this manifest. | |
1179 |
|
1194 | |||
1180 | Result is used to create a manifest revision. |
|
1195 | Result is used to create a manifest revision. | |
1181 | """ |
|
1196 | """ | |
1182 |
|
1197 | |||
1183 |
def fastdelta( |
|
1198 | def fastdelta( | |
|
1199 | self, base: ByteString, changes: Iterable[tuple[bytes, bool]] | |||
|
1200 | ) -> tuple[ByteString, ByteString]: | |||
1184 | """Obtain a delta between this manifest and another given changes. |
|
1201 | """Obtain a delta between this manifest and another given changes. | |
1185 |
|
1202 | |||
1186 | ``base`` in the raw data representation for another manifest. |
|
1203 | ``base`` in the raw data representation for another manifest. |
General Comments 0
You need to be logged in to leave comments.
Login now