##// END OF EJS Templates
interfaces: convert `imanifestrevisionwritable` to a Protocol class...
Matt Harbison -
r53377:01818a59 default
parent child Browse files
Show More
@@ -1,2208 +1,2209
1 # repository.py - Interfaces and base classes for repositories and peers.
1 # repository.py - Interfaces and base classes for repositories and peers.
2 # coding: utf-8
2 # coding: utf-8
3 #
3 #
4 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
4 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import annotations
9 from __future__ import annotations
10
10
11 import abc
11 import abc
12 import typing
12 import typing
13
13
14 from typing import (
14 from typing import (
15 Any,
15 Any,
16 Collection,
16 Collection,
17 Protocol,
17 Protocol,
18 )
18 )
19
19
20 from ..i18n import _
20 from ..i18n import _
21 from .. import error
21 from .. import error
22 from . import util as interfaceutil
22 from . import util as interfaceutil
23
23
24 if typing.TYPE_CHECKING:
24 if typing.TYPE_CHECKING:
25 # Almost all mercurial modules are only imported in the type checking phase
25 # Almost all mercurial modules are only imported in the type checking phase
26 # to avoid circular imports
26 # to avoid circular imports
27 from ..utils import (
27 from ..utils import (
28 urlutil,
28 urlutil,
29 )
29 )
30
30
31 # TODO: make a protocol class for this
31 # TODO: make a protocol class for this
32 NodeConstants = Any
32 NodeConstants = Any
33
33
34 # TODO: create a Protocol class, since importing uimod here causes a cycle
34 # TODO: create a Protocol class, since importing uimod here causes a cycle
35 # that confuses pytype.
35 # that confuses pytype.
36 Ui = Any
36 Ui = Any
37
37
38 # TODO: make a protocol class for this
38 # TODO: make a protocol class for this
39 Vfs = Any
39 Vfs = Any
40
40
41 # Local repository feature string.
41 # Local repository feature string.
42
42
43 # Revlogs are being used for file storage.
43 # Revlogs are being used for file storage.
44 REPO_FEATURE_REVLOG_FILE_STORAGE = b'revlogfilestorage'
44 REPO_FEATURE_REVLOG_FILE_STORAGE = b'revlogfilestorage'
45 # The storage part of the repository is shared from an external source.
45 # The storage part of the repository is shared from an external source.
46 REPO_FEATURE_SHARED_STORAGE = b'sharedstore'
46 REPO_FEATURE_SHARED_STORAGE = b'sharedstore'
47 # LFS supported for backing file storage.
47 # LFS supported for backing file storage.
48 REPO_FEATURE_LFS = b'lfs'
48 REPO_FEATURE_LFS = b'lfs'
49 # Repository supports being stream cloned.
49 # Repository supports being stream cloned.
50 REPO_FEATURE_STREAM_CLONE = b'streamclone'
50 REPO_FEATURE_STREAM_CLONE = b'streamclone'
51 # Repository supports (at least) some sidedata to be stored
51 # Repository supports (at least) some sidedata to be stored
52 REPO_FEATURE_SIDE_DATA = b'side-data'
52 REPO_FEATURE_SIDE_DATA = b'side-data'
53 # Files storage may lack data for all ancestors.
53 # Files storage may lack data for all ancestors.
54 REPO_FEATURE_SHALLOW_FILE_STORAGE = b'shallowfilestorage'
54 REPO_FEATURE_SHALLOW_FILE_STORAGE = b'shallowfilestorage'
55
55
56 REVISION_FLAG_CENSORED = 1 << 15
56 REVISION_FLAG_CENSORED = 1 << 15
57 REVISION_FLAG_ELLIPSIS = 1 << 14
57 REVISION_FLAG_ELLIPSIS = 1 << 14
58 REVISION_FLAG_EXTSTORED = 1 << 13
58 REVISION_FLAG_EXTSTORED = 1 << 13
59 REVISION_FLAG_HASCOPIESINFO = 1 << 12
59 REVISION_FLAG_HASCOPIESINFO = 1 << 12
60
60
61 REVISION_FLAGS_KNOWN = (
61 REVISION_FLAGS_KNOWN = (
62 REVISION_FLAG_CENSORED
62 REVISION_FLAG_CENSORED
63 | REVISION_FLAG_ELLIPSIS
63 | REVISION_FLAG_ELLIPSIS
64 | REVISION_FLAG_EXTSTORED
64 | REVISION_FLAG_EXTSTORED
65 | REVISION_FLAG_HASCOPIESINFO
65 | REVISION_FLAG_HASCOPIESINFO
66 )
66 )
67
67
68 CG_DELTAMODE_STD = b'default'
68 CG_DELTAMODE_STD = b'default'
69 CG_DELTAMODE_PREV = b'previous'
69 CG_DELTAMODE_PREV = b'previous'
70 CG_DELTAMODE_FULL = b'fulltext'
70 CG_DELTAMODE_FULL = b'fulltext'
71 CG_DELTAMODE_P1 = b'p1'
71 CG_DELTAMODE_P1 = b'p1'
72
72
73
73
74 ## Cache related constants:
74 ## Cache related constants:
75 #
75 #
76 # Used to control which cache should be warmed in a repo.updatecaches(…) call.
76 # Used to control which cache should be warmed in a repo.updatecaches(…) call.
77
77
78 # Warm branchmaps of all known repoview's filter-level
78 # Warm branchmaps of all known repoview's filter-level
79 CACHE_BRANCHMAP_ALL = b"branchmap-all"
79 CACHE_BRANCHMAP_ALL = b"branchmap-all"
80 # Warm branchmaps of repoview's filter-level used by server
80 # Warm branchmaps of repoview's filter-level used by server
81 CACHE_BRANCHMAP_SERVED = b"branchmap-served"
81 CACHE_BRANCHMAP_SERVED = b"branchmap-served"
82 # Warm internal changelog cache (eg: persistent nodemap)
82 # Warm internal changelog cache (eg: persistent nodemap)
83 CACHE_CHANGELOG_CACHE = b"changelog-cache"
83 CACHE_CHANGELOG_CACHE = b"changelog-cache"
84 # check of a branchmap can use the "pure topo" mode
84 # check of a branchmap can use the "pure topo" mode
85 CACHE_BRANCHMAP_DETECT_PURE_TOPO = b"branchmap-detect-pure-topo"
85 CACHE_BRANCHMAP_DETECT_PURE_TOPO = b"branchmap-detect-pure-topo"
86 # Warm full manifest cache
86 # Warm full manifest cache
87 CACHE_FULL_MANIFEST = b"full-manifest"
87 CACHE_FULL_MANIFEST = b"full-manifest"
88 # Warm file-node-tags cache
88 # Warm file-node-tags cache
89 CACHE_FILE_NODE_TAGS = b"file-node-tags"
89 CACHE_FILE_NODE_TAGS = b"file-node-tags"
90 # Warm internal manifestlog cache (eg: persistent nodemap)
90 # Warm internal manifestlog cache (eg: persistent nodemap)
91 CACHE_MANIFESTLOG_CACHE = b"manifestlog-cache"
91 CACHE_MANIFESTLOG_CACHE = b"manifestlog-cache"
92 # Warn rev branch cache
92 # Warn rev branch cache
93 CACHE_REV_BRANCH = b"rev-branch-cache"
93 CACHE_REV_BRANCH = b"rev-branch-cache"
94 # Warm tags' cache for default repoview'
94 # Warm tags' cache for default repoview'
95 CACHE_TAGS_DEFAULT = b"tags-default"
95 CACHE_TAGS_DEFAULT = b"tags-default"
96 # Warm tags' cache for repoview's filter-level used by server
96 # Warm tags' cache for repoview's filter-level used by server
97 CACHE_TAGS_SERVED = b"tags-served"
97 CACHE_TAGS_SERVED = b"tags-served"
98
98
99 # the cache to warm by default after a simple transaction
99 # the cache to warm by default after a simple transaction
100 # (this is a mutable set to let extension update it)
100 # (this is a mutable set to let extension update it)
101 CACHES_DEFAULT = {
101 CACHES_DEFAULT = {
102 CACHE_BRANCHMAP_SERVED,
102 CACHE_BRANCHMAP_SERVED,
103 }
103 }
104
104
105 # the caches to warm when warming all of them
105 # the caches to warm when warming all of them
106 # (this is a mutable set to let extension update it)
106 # (this is a mutable set to let extension update it)
107 CACHES_ALL = {
107 CACHES_ALL = {
108 CACHE_BRANCHMAP_SERVED,
108 CACHE_BRANCHMAP_SERVED,
109 CACHE_BRANCHMAP_ALL,
109 CACHE_BRANCHMAP_ALL,
110 CACHE_BRANCHMAP_DETECT_PURE_TOPO,
110 CACHE_BRANCHMAP_DETECT_PURE_TOPO,
111 CACHE_REV_BRANCH,
111 CACHE_REV_BRANCH,
112 CACHE_CHANGELOG_CACHE,
112 CACHE_CHANGELOG_CACHE,
113 CACHE_FILE_NODE_TAGS,
113 CACHE_FILE_NODE_TAGS,
114 CACHE_FULL_MANIFEST,
114 CACHE_FULL_MANIFEST,
115 CACHE_MANIFESTLOG_CACHE,
115 CACHE_MANIFESTLOG_CACHE,
116 CACHE_TAGS_DEFAULT,
116 CACHE_TAGS_DEFAULT,
117 CACHE_TAGS_SERVED,
117 CACHE_TAGS_SERVED,
118 }
118 }
119
119
120 # the cache to warm by default on simple call
120 # the cache to warm by default on simple call
121 # (this is a mutable set to let extension update it)
121 # (this is a mutable set to let extension update it)
122 CACHES_POST_CLONE = CACHES_ALL.copy()
122 CACHES_POST_CLONE = CACHES_ALL.copy()
123 CACHES_POST_CLONE.discard(CACHE_FILE_NODE_TAGS)
123 CACHES_POST_CLONE.discard(CACHE_FILE_NODE_TAGS)
124 CACHES_POST_CLONE.discard(CACHE_REV_BRANCH)
124 CACHES_POST_CLONE.discard(CACHE_REV_BRANCH)
125
125
126
126
127 class _ipeerconnection(Protocol):
127 class _ipeerconnection(Protocol):
128 """Represents a "connection" to a repository.
128 """Represents a "connection" to a repository.
129
129
130 This is the base interface for representing a connection to a repository.
130 This is the base interface for representing a connection to a repository.
131 It holds basic properties and methods applicable to all peer types.
131 It holds basic properties and methods applicable to all peer types.
132
132
133 This is not a complete interface definition and should not be used
133 This is not a complete interface definition and should not be used
134 outside of this module.
134 outside of this module.
135 """
135 """
136
136
137 ui: Ui
137 ui: Ui
138 """ui.ui instance"""
138 """ui.ui instance"""
139
139
140 path: urlutil.path | None
140 path: urlutil.path | None
141 """a urlutil.path instance or None"""
141 """a urlutil.path instance or None"""
142
142
143 def url(self):
143 def url(self):
144 """Returns a URL string representing this peer.
144 """Returns a URL string representing this peer.
145
145
146 Currently, implementations expose the raw URL used to construct the
146 Currently, implementations expose the raw URL used to construct the
147 instance. It may contain credentials as part of the URL. The
147 instance. It may contain credentials as part of the URL. The
148 expectations of the value aren't well-defined and this could lead to
148 expectations of the value aren't well-defined and this could lead to
149 data leakage.
149 data leakage.
150
150
151 TODO audit/clean consumers and more clearly define the contents of this
151 TODO audit/clean consumers and more clearly define the contents of this
152 value.
152 value.
153 """
153 """
154
154
155 def local(self):
155 def local(self):
156 """Returns a local repository instance.
156 """Returns a local repository instance.
157
157
158 If the peer represents a local repository, returns an object that
158 If the peer represents a local repository, returns an object that
159 can be used to interface with it. Otherwise returns ``None``.
159 can be used to interface with it. Otherwise returns ``None``.
160 """
160 """
161
161
162 def canpush(self):
162 def canpush(self):
163 """Returns a boolean indicating if this peer can be pushed to."""
163 """Returns a boolean indicating if this peer can be pushed to."""
164
164
165 def close(self):
165 def close(self):
166 """Close the connection to this peer.
166 """Close the connection to this peer.
167
167
168 This is called when the peer will no longer be used. Resources
168 This is called when the peer will no longer be used. Resources
169 associated with the peer should be cleaned up.
169 associated with the peer should be cleaned up.
170 """
170 """
171
171
172
172
173 class ipeercapabilities(Protocol):
173 class ipeercapabilities(Protocol):
174 """Peer sub-interface related to capabilities."""
174 """Peer sub-interface related to capabilities."""
175
175
176 def capable(self, name):
176 def capable(self, name):
177 """Determine support for a named capability.
177 """Determine support for a named capability.
178
178
179 Returns ``False`` if capability not supported.
179 Returns ``False`` if capability not supported.
180
180
181 Returns ``True`` if boolean capability is supported. Returns a string
181 Returns ``True`` if boolean capability is supported. Returns a string
182 if capability support is non-boolean.
182 if capability support is non-boolean.
183
183
184 Capability strings may or may not map to wire protocol capabilities.
184 Capability strings may or may not map to wire protocol capabilities.
185 """
185 """
186
186
187 def requirecap(self, name, purpose):
187 def requirecap(self, name, purpose):
188 """Require a capability to be present.
188 """Require a capability to be present.
189
189
190 Raises a ``CapabilityError`` if the capability isn't present.
190 Raises a ``CapabilityError`` if the capability isn't present.
191 """
191 """
192
192
193
193
194 class ipeercommands(Protocol):
194 class ipeercommands(Protocol):
195 """Client-side interface for communicating over the wire protocol.
195 """Client-side interface for communicating over the wire protocol.
196
196
197 This interface is used as a gateway to the Mercurial wire protocol.
197 This interface is used as a gateway to the Mercurial wire protocol.
198 methods commonly call wire protocol commands of the same name.
198 methods commonly call wire protocol commands of the same name.
199 """
199 """
200
200
201 def branchmap(self):
201 def branchmap(self):
202 """Obtain heads in named branches.
202 """Obtain heads in named branches.
203
203
204 Returns a dict mapping branch name to an iterable of nodes that are
204 Returns a dict mapping branch name to an iterable of nodes that are
205 heads on that branch.
205 heads on that branch.
206 """
206 """
207
207
208 def capabilities(self):
208 def capabilities(self):
209 """Obtain capabilities of the peer.
209 """Obtain capabilities of the peer.
210
210
211 Returns a set of string capabilities.
211 Returns a set of string capabilities.
212 """
212 """
213
213
214 def get_cached_bundle_inline(self, path):
214 def get_cached_bundle_inline(self, path):
215 """Retrieve a clonebundle across the wire.
215 """Retrieve a clonebundle across the wire.
216
216
217 Returns a chunkbuffer
217 Returns a chunkbuffer
218 """
218 """
219
219
220 def clonebundles(self):
220 def clonebundles(self):
221 """Obtains the clone bundles manifest for the repo.
221 """Obtains the clone bundles manifest for the repo.
222
222
223 Returns the manifest as unparsed bytes.
223 Returns the manifest as unparsed bytes.
224 """
224 """
225
225
226 def debugwireargs(self, one, two, three=None, four=None, five=None):
226 def debugwireargs(self, one, two, three=None, four=None, five=None):
227 """Used to facilitate debugging of arguments passed over the wire."""
227 """Used to facilitate debugging of arguments passed over the wire."""
228
228
229 def getbundle(self, source, **kwargs):
229 def getbundle(self, source, **kwargs):
230 """Obtain remote repository data as a bundle.
230 """Obtain remote repository data as a bundle.
231
231
232 This command is how the bulk of repository data is transferred from
232 This command is how the bulk of repository data is transferred from
233 the peer to the local repository
233 the peer to the local repository
234
234
235 Returns a generator of bundle data.
235 Returns a generator of bundle data.
236 """
236 """
237
237
238 def heads(self):
238 def heads(self):
239 """Determine all known head revisions in the peer.
239 """Determine all known head revisions in the peer.
240
240
241 Returns an iterable of binary nodes.
241 Returns an iterable of binary nodes.
242 """
242 """
243
243
244 def known(self, nodes):
244 def known(self, nodes):
245 """Determine whether multiple nodes are known.
245 """Determine whether multiple nodes are known.
246
246
247 Accepts an iterable of nodes whose presence to check for.
247 Accepts an iterable of nodes whose presence to check for.
248
248
249 Returns an iterable of booleans indicating of the corresponding node
249 Returns an iterable of booleans indicating of the corresponding node
250 at that index is known to the peer.
250 at that index is known to the peer.
251 """
251 """
252
252
253 def listkeys(self, namespace):
253 def listkeys(self, namespace):
254 """Obtain all keys in a pushkey namespace.
254 """Obtain all keys in a pushkey namespace.
255
255
256 Returns an iterable of key names.
256 Returns an iterable of key names.
257 """
257 """
258
258
259 def lookup(self, key):
259 def lookup(self, key):
260 """Resolve a value to a known revision.
260 """Resolve a value to a known revision.
261
261
262 Returns a binary node of the resolved revision on success.
262 Returns a binary node of the resolved revision on success.
263 """
263 """
264
264
265 def pushkey(self, namespace, key, old, new):
265 def pushkey(self, namespace, key, old, new):
266 """Set a value using the ``pushkey`` protocol.
266 """Set a value using the ``pushkey`` protocol.
267
267
268 Arguments correspond to the pushkey namespace and key to operate on and
268 Arguments correspond to the pushkey namespace and key to operate on and
269 the old and new values for that key.
269 the old and new values for that key.
270
270
271 Returns a string with the peer result. The value inside varies by the
271 Returns a string with the peer result. The value inside varies by the
272 namespace.
272 namespace.
273 """
273 """
274
274
275 def stream_out(self):
275 def stream_out(self):
276 """Obtain streaming clone data.
276 """Obtain streaming clone data.
277
277
278 Successful result should be a generator of data chunks.
278 Successful result should be a generator of data chunks.
279 """
279 """
280
280
281 def unbundle(self, bundle, heads, url):
281 def unbundle(self, bundle, heads, url):
282 """Transfer repository data to the peer.
282 """Transfer repository data to the peer.
283
283
284 This is how the bulk of data during a push is transferred.
284 This is how the bulk of data during a push is transferred.
285
285
286 Returns the integer number of heads added to the peer.
286 Returns the integer number of heads added to the peer.
287 """
287 """
288
288
289
289
290 class ipeerlegacycommands(Protocol):
290 class ipeerlegacycommands(Protocol):
291 """Interface for implementing support for legacy wire protocol commands.
291 """Interface for implementing support for legacy wire protocol commands.
292
292
293 Wire protocol commands transition to legacy status when they are no longer
293 Wire protocol commands transition to legacy status when they are no longer
294 used by modern clients. To facilitate identifying which commands are
294 used by modern clients. To facilitate identifying which commands are
295 legacy, the interfaces are split.
295 legacy, the interfaces are split.
296 """
296 """
297
297
298 def between(self, pairs):
298 def between(self, pairs):
299 """Obtain nodes between pairs of nodes.
299 """Obtain nodes between pairs of nodes.
300
300
301 ``pairs`` is an iterable of node pairs.
301 ``pairs`` is an iterable of node pairs.
302
302
303 Returns an iterable of iterables of nodes corresponding to each
303 Returns an iterable of iterables of nodes corresponding to each
304 requested pair.
304 requested pair.
305 """
305 """
306
306
307 def branches(self, nodes):
307 def branches(self, nodes):
308 """Obtain ancestor changesets of specific nodes back to a branch point.
308 """Obtain ancestor changesets of specific nodes back to a branch point.
309
309
310 For each requested node, the peer finds the first ancestor node that is
310 For each requested node, the peer finds the first ancestor node that is
311 a DAG root or is a merge.
311 a DAG root or is a merge.
312
312
313 Returns an iterable of iterables with the resolved values for each node.
313 Returns an iterable of iterables with the resolved values for each node.
314 """
314 """
315
315
316 def changegroup(self, nodes, source):
316 def changegroup(self, nodes, source):
317 """Obtain a changegroup with data for descendants of specified nodes."""
317 """Obtain a changegroup with data for descendants of specified nodes."""
318
318
319 def changegroupsubset(self, bases, heads, source):
319 def changegroupsubset(self, bases, heads, source):
320 pass
320 pass
321
321
322
322
323 class ipeercommandexecutor(Protocol):
323 class ipeercommandexecutor(Protocol):
324 """Represents a mechanism to execute remote commands.
324 """Represents a mechanism to execute remote commands.
325
325
326 This is the primary interface for requesting that wire protocol commands
326 This is the primary interface for requesting that wire protocol commands
327 be executed. Instances of this interface are active in a context manager
327 be executed. Instances of this interface are active in a context manager
328 and have a well-defined lifetime. When the context manager exits, all
328 and have a well-defined lifetime. When the context manager exits, all
329 outstanding requests are waited on.
329 outstanding requests are waited on.
330 """
330 """
331
331
332 def callcommand(self, name, args):
332 def callcommand(self, name, args):
333 """Request that a named command be executed.
333 """Request that a named command be executed.
334
334
335 Receives the command name and a dictionary of command arguments.
335 Receives the command name and a dictionary of command arguments.
336
336
337 Returns a ``concurrent.futures.Future`` that will resolve to the
337 Returns a ``concurrent.futures.Future`` that will resolve to the
338 result of that command request. That exact value is left up to
338 result of that command request. That exact value is left up to
339 the implementation and possibly varies by command.
339 the implementation and possibly varies by command.
340
340
341 Not all commands can coexist with other commands in an executor
341 Not all commands can coexist with other commands in an executor
342 instance: it depends on the underlying wire protocol transport being
342 instance: it depends on the underlying wire protocol transport being
343 used and the command itself.
343 used and the command itself.
344
344
345 Implementations MAY call ``sendcommands()`` automatically if the
345 Implementations MAY call ``sendcommands()`` automatically if the
346 requested command can not coexist with other commands in this executor.
346 requested command can not coexist with other commands in this executor.
347
347
348 Implementations MAY call ``sendcommands()`` automatically when the
348 Implementations MAY call ``sendcommands()`` automatically when the
349 future's ``result()`` is called. So, consumers using multiple
349 future's ``result()`` is called. So, consumers using multiple
350 commands with an executor MUST ensure that ``result()`` is not called
350 commands with an executor MUST ensure that ``result()`` is not called
351 until all command requests have been issued.
351 until all command requests have been issued.
352 """
352 """
353
353
354 def sendcommands(self):
354 def sendcommands(self):
355 """Trigger submission of queued command requests.
355 """Trigger submission of queued command requests.
356
356
357 Not all transports submit commands as soon as they are requested to
357 Not all transports submit commands as soon as they are requested to
358 run. When called, this method forces queued command requests to be
358 run. When called, this method forces queued command requests to be
359 issued. It will no-op if all commands have already been sent.
359 issued. It will no-op if all commands have already been sent.
360
360
361 When called, no more new commands may be issued with this executor.
361 When called, no more new commands may be issued with this executor.
362 """
362 """
363
363
364 def close(self):
364 def close(self):
365 """Signal that this command request is finished.
365 """Signal that this command request is finished.
366
366
367 When called, no more new commands may be issued. All outstanding
367 When called, no more new commands may be issued. All outstanding
368 commands that have previously been issued are waited on before
368 commands that have previously been issued are waited on before
369 returning. This not only includes waiting for the futures to resolve,
369 returning. This not only includes waiting for the futures to resolve,
370 but also waiting for all response data to arrive. In other words,
370 but also waiting for all response data to arrive. In other words,
371 calling this waits for all on-wire state for issued command requests
371 calling this waits for all on-wire state for issued command requests
372 to finish.
372 to finish.
373
373
374 When used as a context manager, this method is called when exiting the
374 When used as a context manager, this method is called when exiting the
375 context manager.
375 context manager.
376
376
377 This method may call ``sendcommands()`` if there are buffered commands.
377 This method may call ``sendcommands()`` if there are buffered commands.
378 """
378 """
379
379
380
380
381 class ipeerrequests(Protocol):
381 class ipeerrequests(Protocol):
382 """Interface for executing commands on a peer."""
382 """Interface for executing commands on a peer."""
383
383
384 limitedarguments: bool
384 limitedarguments: bool
385 """True if the peer cannot receive large argument value for commands."""
385 """True if the peer cannot receive large argument value for commands."""
386
386
387 def commandexecutor(self):
387 def commandexecutor(self):
388 """A context manager that resolves to an ipeercommandexecutor.
388 """A context manager that resolves to an ipeercommandexecutor.
389
389
390 The object this resolves to can be used to issue command requests
390 The object this resolves to can be used to issue command requests
391 to the peer.
391 to the peer.
392
392
393 Callers should call its ``callcommand`` method to issue command
393 Callers should call its ``callcommand`` method to issue command
394 requests.
394 requests.
395
395
396 A new executor should be obtained for each distinct set of commands
396 A new executor should be obtained for each distinct set of commands
397 (possibly just a single command) that the consumer wants to execute
397 (possibly just a single command) that the consumer wants to execute
398 as part of a single operation or round trip. This is because some
398 as part of a single operation or round trip. This is because some
399 peers are half-duplex and/or don't support persistent connections.
399 peers are half-duplex and/or don't support persistent connections.
400 e.g. in the case of HTTP peers, commands sent to an executor represent
400 e.g. in the case of HTTP peers, commands sent to an executor represent
401 a single HTTP request. While some peers may support multiple command
401 a single HTTP request. While some peers may support multiple command
402 sends over the wire per executor, consumers need to code to the least
402 sends over the wire per executor, consumers need to code to the least
403 capable peer. So it should be assumed that command executors buffer
403 capable peer. So it should be assumed that command executors buffer
404 called commands until they are told to send them and that each
404 called commands until they are told to send them and that each
405 command executor could result in a new connection or wire-level request
405 command executor could result in a new connection or wire-level request
406 being issued.
406 being issued.
407 """
407 """
408
408
409
409
410 class peer(_ipeerconnection, ipeercapabilities, ipeerrequests, Protocol):
410 class peer(_ipeerconnection, ipeercapabilities, ipeerrequests, Protocol):
411 """Unified interface for peer repositories.
411 """Unified interface for peer repositories.
412
412
413 All peer instances must conform to this interface.
413 All peer instances must conform to this interface.
414 """
414 """
415
415
416 limitedarguments: bool = False
416 limitedarguments: bool = False
417
417
418 def __init__(self, ui, path=None, remotehidden=False):
418 def __init__(self, ui, path=None, remotehidden=False):
419 self.ui = ui
419 self.ui = ui
420 self.path = path
420 self.path = path
421
421
422 def capable(self, name):
422 def capable(self, name):
423 # TODO: this class should maybe subclass ipeercommands too, otherwise it
423 # TODO: this class should maybe subclass ipeercommands too, otherwise it
424 # is assuming whatever uses this as a mixin also has this interface.
424 # is assuming whatever uses this as a mixin also has this interface.
425 caps = self.capabilities() # pytype: disable=attribute-error
425 caps = self.capabilities() # pytype: disable=attribute-error
426 if name in caps:
426 if name in caps:
427 return True
427 return True
428
428
429 name = b'%s=' % name
429 name = b'%s=' % name
430 for cap in caps:
430 for cap in caps:
431 if cap.startswith(name):
431 if cap.startswith(name):
432 return cap[len(name) :]
432 return cap[len(name) :]
433
433
434 return False
434 return False
435
435
436 def requirecap(self, name, purpose):
436 def requirecap(self, name, purpose):
437 if self.capable(name):
437 if self.capable(name):
438 return
438 return
439
439
440 raise error.CapabilityError(
440 raise error.CapabilityError(
441 _(
441 _(
442 b'cannot %s; remote repository does not support the '
442 b'cannot %s; remote repository does not support the '
443 b'\'%s\' capability'
443 b'\'%s\' capability'
444 )
444 )
445 % (purpose, name)
445 % (purpose, name)
446 )
446 )
447
447
448
448
449 class iverifyproblem(Protocol):
449 class iverifyproblem(Protocol):
450 """Represents a problem with the integrity of the repository.
450 """Represents a problem with the integrity of the repository.
451
451
452 Instances of this interface are emitted to describe an integrity issue
452 Instances of this interface are emitted to describe an integrity issue
453 with a repository (e.g. corrupt storage, missing data, etc).
453 with a repository (e.g. corrupt storage, missing data, etc).
454
454
455 Instances are essentially messages associated with severity.
455 Instances are essentially messages associated with severity.
456 """
456 """
457
457
458 warning: bytes | None
458 warning: bytes | None
459 """Message indicating a non-fatal problem."""
459 """Message indicating a non-fatal problem."""
460
460
461 error: bytes | None
461 error: bytes | None
462 """Message indicating a fatal problem."""
462 """Message indicating a fatal problem."""
463
463
464 node: bytes | None
464 node: bytes | None
465 """Revision encountering the problem.
465 """Revision encountering the problem.
466
466
467 ``None`` means the problem doesn't apply to a single revision.
467 ``None`` means the problem doesn't apply to a single revision.
468 """
468 """
469
469
470
470
471 class irevisiondelta(Protocol):
471 class irevisiondelta(Protocol):
472 """Represents a delta between one revision and another.
472 """Represents a delta between one revision and another.
473
473
474 Instances convey enough information to allow a revision to be exchanged
474 Instances convey enough information to allow a revision to be exchanged
475 with another repository.
475 with another repository.
476
476
477 Instances represent the fulltext revision data or a delta against
477 Instances represent the fulltext revision data or a delta against
478 another revision. Therefore the ``revision`` and ``delta`` attributes
478 another revision. Therefore the ``revision`` and ``delta`` attributes
479 are mutually exclusive.
479 are mutually exclusive.
480
480
481 Typically used for changegroup generation.
481 Typically used for changegroup generation.
482 """
482 """
483
483
484 node: bytes
484 node: bytes
485 """20 byte node of this revision."""
485 """20 byte node of this revision."""
486
486
487 p1node: bytes
487 p1node: bytes
488 """20 byte node of 1st parent of this revision."""
488 """20 byte node of 1st parent of this revision."""
489
489
490 p2node: bytes
490 p2node: bytes
491 """20 byte node of 2nd parent of this revision."""
491 """20 byte node of 2nd parent of this revision."""
492
492
493 # TODO: is this really optional? revlog.revlogrevisiondelta defaults to None
493 # TODO: is this really optional? revlog.revlogrevisiondelta defaults to None
494 linknode: bytes | None
494 linknode: bytes | None
495 """20 byte node of the changelog revision this node is linked to."""
495 """20 byte node of the changelog revision this node is linked to."""
496
496
497 flags: int
497 flags: int
498 """2 bytes of integer flags that apply to this revision.
498 """2 bytes of integer flags that apply to this revision.
499
499
500 This is a bitwise composition of the ``REVISION_FLAG_*`` constants.
500 This is a bitwise composition of the ``REVISION_FLAG_*`` constants.
501 """
501 """
502
502
503 basenode: bytes
503 basenode: bytes
504 """20 byte node of the revision this data is a delta against.
504 """20 byte node of the revision this data is a delta against.
505
505
506 ``nullid`` indicates that the revision is a full revision and not
506 ``nullid`` indicates that the revision is a full revision and not
507 a delta.
507 a delta.
508 """
508 """
509
509
510 baserevisionsize: int | None
510 baserevisionsize: int | None
511 """Size of base revision this delta is against.
511 """Size of base revision this delta is against.
512
512
513 May be ``None`` if ``basenode`` is ``nullid``.
513 May be ``None`` if ``basenode`` is ``nullid``.
514 """
514 """
515
515
516 # TODO: is this really optional? (Seems possible in
516 # TODO: is this really optional? (Seems possible in
517 # storageutil.emitrevisions()).
517 # storageutil.emitrevisions()).
518 revision: bytes | None
518 revision: bytes | None
519 """Raw fulltext of revision data for this node."""
519 """Raw fulltext of revision data for this node."""
520
520
521 delta: bytes | None
521 delta: bytes | None
522 """Delta between ``basenode`` and ``node``.
522 """Delta between ``basenode`` and ``node``.
523
523
524 Stored in the bdiff delta format.
524 Stored in the bdiff delta format.
525 """
525 """
526
526
527 sidedata: bytes | None
527 sidedata: bytes | None
528 """Raw sidedata bytes for the given revision."""
528 """Raw sidedata bytes for the given revision."""
529
529
530 protocol_flags: int
530 protocol_flags: int
531 """Single byte of integer flags that can influence the protocol.
531 """Single byte of integer flags that can influence the protocol.
532
532
533 This is a bitwise composition of the ``storageutil.CG_FLAG*`` constants.
533 This is a bitwise composition of the ``storageutil.CG_FLAG*`` constants.
534 """
534 """
535
535
536
536
537 class ifilerevisionssequence(Protocol):
537 class ifilerevisionssequence(Protocol):
538 """Contains index data for all revisions of a file.
538 """Contains index data for all revisions of a file.
539
539
540 Types implementing this behave like lists of tuples. The index
540 Types implementing this behave like lists of tuples. The index
541 in the list corresponds to the revision number. The values contain
541 in the list corresponds to the revision number. The values contain
542 index metadata.
542 index metadata.
543
543
544 The *null* revision (revision number -1) is always the last item
544 The *null* revision (revision number -1) is always the last item
545 in the index.
545 in the index.
546 """
546 """
547
547
548 def __len__(self):
548 def __len__(self):
549 """The total number of revisions."""
549 """The total number of revisions."""
550
550
551 def __getitem__(self, rev):
551 def __getitem__(self, rev):
552 """Returns the object having a specific revision number.
552 """Returns the object having a specific revision number.
553
553
554 Returns an 8-tuple with the following fields:
554 Returns an 8-tuple with the following fields:
555
555
556 offset+flags
556 offset+flags
557 Contains the offset and flags for the revision. 64-bit unsigned
557 Contains the offset and flags for the revision. 64-bit unsigned
558 integer where first 6 bytes are the offset and the next 2 bytes
558 integer where first 6 bytes are the offset and the next 2 bytes
559 are flags. The offset can be 0 if it is not used by the store.
559 are flags. The offset can be 0 if it is not used by the store.
560 compressed size
560 compressed size
561 Size of the revision data in the store. It can be 0 if it isn't
561 Size of the revision data in the store. It can be 0 if it isn't
562 needed by the store.
562 needed by the store.
563 uncompressed size
563 uncompressed size
564 Fulltext size. It can be 0 if it isn't needed by the store.
564 Fulltext size. It can be 0 if it isn't needed by the store.
565 base revision
565 base revision
566 Revision number of revision the delta for storage is encoded
566 Revision number of revision the delta for storage is encoded
567 against. -1 indicates not encoded against a base revision.
567 against. -1 indicates not encoded against a base revision.
568 link revision
568 link revision
569 Revision number of changelog revision this entry is related to.
569 Revision number of changelog revision this entry is related to.
570 p1 revision
570 p1 revision
571 Revision number of 1st parent. -1 if no 1st parent.
571 Revision number of 1st parent. -1 if no 1st parent.
572 p2 revision
572 p2 revision
573 Revision number of 2nd parent. -1 if no 1st parent.
573 Revision number of 2nd parent. -1 if no 1st parent.
574 node
574 node
575 Binary node value for this revision number.
575 Binary node value for this revision number.
576
576
577 Negative values should index off the end of the sequence. ``-1``
577 Negative values should index off the end of the sequence. ``-1``
578 should return the null revision. ``-2`` should return the most
578 should return the null revision. ``-2`` should return the most
579 recent revision.
579 recent revision.
580 """
580 """
581
581
582 def __contains__(self, rev):
582 def __contains__(self, rev):
583 """Whether a revision number exists."""
583 """Whether a revision number exists."""
584
584
585 def insert(self, i, entry):
585 def insert(self, i, entry):
586 """Add an item to the index at specific revision."""
586 """Add an item to the index at specific revision."""
587
587
588
588
589 class ifileindex(Protocol):
589 class ifileindex(Protocol):
590 """Storage interface for index data of a single file.
590 """Storage interface for index data of a single file.
591
591
592 File storage data is divided into index metadata and data storage.
592 File storage data is divided into index metadata and data storage.
593 This interface defines the index portion of the interface.
593 This interface defines the index portion of the interface.
594
594
595 The index logically consists of:
595 The index logically consists of:
596
596
597 * A mapping between revision numbers and nodes.
597 * A mapping between revision numbers and nodes.
598 * DAG data (storing and querying the relationship between nodes).
598 * DAG data (storing and querying the relationship between nodes).
599 * Metadata to facilitate storage.
599 * Metadata to facilitate storage.
600 """
600 """
601
601
602 nullid: bytes
602 nullid: bytes
603 """node for the null revision for use as delta base."""
603 """node for the null revision for use as delta base."""
604
604
605 def __len__(self):
605 def __len__(self):
606 """Obtain the number of revisions stored for this file."""
606 """Obtain the number of revisions stored for this file."""
607
607
608 def __iter__(self):
608 def __iter__(self):
609 """Iterate over revision numbers for this file."""
609 """Iterate over revision numbers for this file."""
610
610
611 def hasnode(self, node):
611 def hasnode(self, node):
612 """Returns a bool indicating if a node is known to this store.
612 """Returns a bool indicating if a node is known to this store.
613
613
614 Implementations must only return True for full, binary node values:
614 Implementations must only return True for full, binary node values:
615 hex nodes, revision numbers, and partial node matches must be
615 hex nodes, revision numbers, and partial node matches must be
616 rejected.
616 rejected.
617
617
618 The null node is never present.
618 The null node is never present.
619 """
619 """
620
620
621 def revs(self, start=0, stop=None):
621 def revs(self, start=0, stop=None):
622 """Iterate over revision numbers for this file, with control."""
622 """Iterate over revision numbers for this file, with control."""
623
623
624 def parents(self, node):
624 def parents(self, node):
625 """Returns a 2-tuple of parent nodes for a revision.
625 """Returns a 2-tuple of parent nodes for a revision.
626
626
627 Values will be ``nullid`` if the parent is empty.
627 Values will be ``nullid`` if the parent is empty.
628 """
628 """
629
629
630 def parentrevs(self, rev):
630 def parentrevs(self, rev):
631 """Like parents() but operates on revision numbers."""
631 """Like parents() but operates on revision numbers."""
632
632
633 def rev(self, node):
633 def rev(self, node):
634 """Obtain the revision number given a node.
634 """Obtain the revision number given a node.
635
635
636 Raises ``error.LookupError`` if the node is not known.
636 Raises ``error.LookupError`` if the node is not known.
637 """
637 """
638
638
639 def node(self, rev):
639 def node(self, rev):
640 """Obtain the node value given a revision number.
640 """Obtain the node value given a revision number.
641
641
642 Raises ``IndexError`` if the node is not known.
642 Raises ``IndexError`` if the node is not known.
643 """
643 """
644
644
645 def lookup(self, node):
645 def lookup(self, node):
646 """Attempt to resolve a value to a node.
646 """Attempt to resolve a value to a node.
647
647
648 Value can be a binary node, hex node, revision number, or a string
648 Value can be a binary node, hex node, revision number, or a string
649 that can be converted to an integer.
649 that can be converted to an integer.
650
650
651 Raises ``error.LookupError`` if a node could not be resolved.
651 Raises ``error.LookupError`` if a node could not be resolved.
652 """
652 """
653
653
654 def linkrev(self, rev):
654 def linkrev(self, rev):
655 """Obtain the changeset revision number a revision is linked to."""
655 """Obtain the changeset revision number a revision is linked to."""
656
656
657 def iscensored(self, rev):
657 def iscensored(self, rev):
658 """Return whether a revision's content has been censored."""
658 """Return whether a revision's content has been censored."""
659
659
660 def commonancestorsheads(self, node1, node2):
660 def commonancestorsheads(self, node1, node2):
661 """Obtain an iterable of nodes containing heads of common ancestors.
661 """Obtain an iterable of nodes containing heads of common ancestors.
662
662
663 See ``ancestor.commonancestorsheads()``.
663 See ``ancestor.commonancestorsheads()``.
664 """
664 """
665
665
666 def descendants(self, revs):
666 def descendants(self, revs):
667 """Obtain descendant revision numbers for a set of revision numbers.
667 """Obtain descendant revision numbers for a set of revision numbers.
668
668
669 If ``nullrev`` is in the set, this is equivalent to ``revs()``.
669 If ``nullrev`` is in the set, this is equivalent to ``revs()``.
670 """
670 """
671
671
672 def heads(self, start=None, stop=None):
672 def heads(self, start=None, stop=None):
673 """Obtain a list of nodes that are DAG heads, with control.
673 """Obtain a list of nodes that are DAG heads, with control.
674
674
675 The set of revisions examined can be limited by specifying
675 The set of revisions examined can be limited by specifying
676 ``start`` and ``stop``. ``start`` is a node. ``stop`` is an
676 ``start`` and ``stop``. ``start`` is a node. ``stop`` is an
677 iterable of nodes. DAG traversal starts at earlier revision
677 iterable of nodes. DAG traversal starts at earlier revision
678 ``start`` and iterates forward until any node in ``stop`` is
678 ``start`` and iterates forward until any node in ``stop`` is
679 encountered.
679 encountered.
680 """
680 """
681
681
682 def children(self, node):
682 def children(self, node):
683 """Obtain nodes that are children of a node.
683 """Obtain nodes that are children of a node.
684
684
685 Returns a list of nodes.
685 Returns a list of nodes.
686 """
686 """
687
687
688
688
689 class ifiledata(Protocol):
689 class ifiledata(Protocol):
690 """Storage interface for data storage of a specific file.
690 """Storage interface for data storage of a specific file.
691
691
692 This complements ``ifileindex`` and provides an interface for accessing
692 This complements ``ifileindex`` and provides an interface for accessing
693 data for a tracked file.
693 data for a tracked file.
694 """
694 """
695
695
696 def size(self, rev):
696 def size(self, rev):
697 """Obtain the fulltext size of file data.
697 """Obtain the fulltext size of file data.
698
698
699 Any metadata is excluded from size measurements.
699 Any metadata is excluded from size measurements.
700 """
700 """
701
701
702 def revision(self, node):
702 def revision(self, node):
703 """Obtain fulltext data for a node.
703 """Obtain fulltext data for a node.
704
704
705 By default, any storage transformations are applied before the data
705 By default, any storage transformations are applied before the data
706 is returned. If ``raw`` is True, non-raw storage transformations
706 is returned. If ``raw`` is True, non-raw storage transformations
707 are not applied.
707 are not applied.
708
708
709 The fulltext data may contain a header containing metadata. Most
709 The fulltext data may contain a header containing metadata. Most
710 consumers should use ``read()`` to obtain the actual file data.
710 consumers should use ``read()`` to obtain the actual file data.
711 """
711 """
712
712
713 def rawdata(self, node):
713 def rawdata(self, node):
714 """Obtain raw data for a node."""
714 """Obtain raw data for a node."""
715
715
716 def read(self, node):
716 def read(self, node):
717 """Resolve file fulltext data.
717 """Resolve file fulltext data.
718
718
719 This is similar to ``revision()`` except any metadata in the data
719 This is similar to ``revision()`` except any metadata in the data
720 headers is stripped.
720 headers is stripped.
721 """
721 """
722
722
723 def renamed(self, node):
723 def renamed(self, node):
724 """Obtain copy metadata for a node.
724 """Obtain copy metadata for a node.
725
725
726 Returns ``False`` if no copy metadata is stored or a 2-tuple of
726 Returns ``False`` if no copy metadata is stored or a 2-tuple of
727 (path, node) from which this revision was copied.
727 (path, node) from which this revision was copied.
728 """
728 """
729
729
730 def cmp(self, node, fulltext):
730 def cmp(self, node, fulltext):
731 """Compare fulltext to another revision.
731 """Compare fulltext to another revision.
732
732
733 Returns True if the fulltext is different from what is stored.
733 Returns True if the fulltext is different from what is stored.
734
734
735 This takes copy metadata into account.
735 This takes copy metadata into account.
736
736
737 TODO better document the copy metadata and censoring logic.
737 TODO better document the copy metadata and censoring logic.
738 """
738 """
739
739
740 def emitrevisions(
740 def emitrevisions(
741 self,
741 self,
742 nodes,
742 nodes,
743 nodesorder=None,
743 nodesorder=None,
744 revisiondata=False,
744 revisiondata=False,
745 assumehaveparentrevisions=False,
745 assumehaveparentrevisions=False,
746 deltamode=CG_DELTAMODE_STD,
746 deltamode=CG_DELTAMODE_STD,
747 ):
747 ):
748 """Produce ``irevisiondelta`` for revisions.
748 """Produce ``irevisiondelta`` for revisions.
749
749
750 Given an iterable of nodes, emits objects conforming to the
750 Given an iterable of nodes, emits objects conforming to the
751 ``irevisiondelta`` interface that describe revisions in storage.
751 ``irevisiondelta`` interface that describe revisions in storage.
752
752
753 This method is a generator.
753 This method is a generator.
754
754
755 The input nodes may be unordered. Implementations must ensure that a
755 The input nodes may be unordered. Implementations must ensure that a
756 node's parents are emitted before the node itself. Transitively, this
756 node's parents are emitted before the node itself. Transitively, this
757 means that a node may only be emitted once all its ancestors in
757 means that a node may only be emitted once all its ancestors in
758 ``nodes`` have also been emitted.
758 ``nodes`` have also been emitted.
759
759
760 By default, emits "index" data (the ``node``, ``p1node``, and
760 By default, emits "index" data (the ``node``, ``p1node``, and
761 ``p2node`` attributes). If ``revisiondata`` is set, revision data
761 ``p2node`` attributes). If ``revisiondata`` is set, revision data
762 will also be present on the emitted objects.
762 will also be present on the emitted objects.
763
763
764 With default argument values, implementations can choose to emit
764 With default argument values, implementations can choose to emit
765 either fulltext revision data or a delta. When emitting deltas,
765 either fulltext revision data or a delta. When emitting deltas,
766 implementations must consider whether the delta's base revision
766 implementations must consider whether the delta's base revision
767 fulltext is available to the receiver.
767 fulltext is available to the receiver.
768
768
769 The base revision fulltext is guaranteed to be available if any of
769 The base revision fulltext is guaranteed to be available if any of
770 the following are met:
770 the following are met:
771
771
772 * Its fulltext revision was emitted by this method call.
772 * Its fulltext revision was emitted by this method call.
773 * A delta for that revision was emitted by this method call.
773 * A delta for that revision was emitted by this method call.
774 * ``assumehaveparentrevisions`` is True and the base revision is a
774 * ``assumehaveparentrevisions`` is True and the base revision is a
775 parent of the node.
775 parent of the node.
776
776
777 ``nodesorder`` can be used to control the order that revisions are
777 ``nodesorder`` can be used to control the order that revisions are
778 emitted. By default, revisions can be reordered as long as they are
778 emitted. By default, revisions can be reordered as long as they are
779 in DAG topological order (see above). If the value is ``nodes``,
779 in DAG topological order (see above). If the value is ``nodes``,
780 the iteration order from ``nodes`` should be used. If the value is
780 the iteration order from ``nodes`` should be used. If the value is
781 ``storage``, then the native order from the backing storage layer
781 ``storage``, then the native order from the backing storage layer
782 is used. (Not all storage layers will have strong ordering and behavior
782 is used. (Not all storage layers will have strong ordering and behavior
783 of this mode is storage-dependent.) ``nodes`` ordering can force
783 of this mode is storage-dependent.) ``nodes`` ordering can force
784 revisions to be emitted before their ancestors, so consumers should
784 revisions to be emitted before their ancestors, so consumers should
785 use it with care.
785 use it with care.
786
786
787 The ``linknode`` attribute on the returned ``irevisiondelta`` may not
787 The ``linknode`` attribute on the returned ``irevisiondelta`` may not
788 be set and it is the caller's responsibility to resolve it, if needed.
788 be set and it is the caller's responsibility to resolve it, if needed.
789
789
790 If ``deltamode`` is CG_DELTAMODE_PREV and revision data is requested,
790 If ``deltamode`` is CG_DELTAMODE_PREV and revision data is requested,
791 all revision data should be emitted as deltas against the revision
791 all revision data should be emitted as deltas against the revision
792 emitted just prior. The initial revision should be a delta against its
792 emitted just prior. The initial revision should be a delta against its
793 1st parent.
793 1st parent.
794 """
794 """
795
795
796
796
797 class ifilemutation(Protocol):
797 class ifilemutation(Protocol):
798 """Storage interface for mutation events of a tracked file."""
798 """Storage interface for mutation events of a tracked file."""
799
799
800 def add(self, filedata, meta, transaction, linkrev, p1, p2):
800 def add(self, filedata, meta, transaction, linkrev, p1, p2):
801 """Add a new revision to the store.
801 """Add a new revision to the store.
802
802
803 Takes file data, dictionary of metadata, a transaction, linkrev,
803 Takes file data, dictionary of metadata, a transaction, linkrev,
804 and parent nodes.
804 and parent nodes.
805
805
806 Returns the node that was added.
806 Returns the node that was added.
807
807
808 May no-op if a revision matching the supplied data is already stored.
808 May no-op if a revision matching the supplied data is already stored.
809 """
809 """
810
810
811 def addrevision(
811 def addrevision(
812 self,
812 self,
813 revisiondata,
813 revisiondata,
814 transaction,
814 transaction,
815 linkrev,
815 linkrev,
816 p1,
816 p1,
817 p2,
817 p2,
818 node=None,
818 node=None,
819 flags=0,
819 flags=0,
820 cachedelta=None,
820 cachedelta=None,
821 ):
821 ):
822 """Add a new revision to the store and return its number.
822 """Add a new revision to the store and return its number.
823
823
824 This is similar to ``add()`` except it operates at a lower level.
824 This is similar to ``add()`` except it operates at a lower level.
825
825
826 The data passed in already contains a metadata header, if any.
826 The data passed in already contains a metadata header, if any.
827
827
828 ``node`` and ``flags`` can be used to define the expected node and
828 ``node`` and ``flags`` can be used to define the expected node and
829 the flags to use with storage. ``flags`` is a bitwise value composed
829 the flags to use with storage. ``flags`` is a bitwise value composed
830 of the various ``REVISION_FLAG_*`` constants.
830 of the various ``REVISION_FLAG_*`` constants.
831
831
832 ``add()`` is usually called when adding files from e.g. the working
832 ``add()`` is usually called when adding files from e.g. the working
833 directory. ``addrevision()`` is often called by ``add()`` and for
833 directory. ``addrevision()`` is often called by ``add()`` and for
834 scenarios where revision data has already been computed, such as when
834 scenarios where revision data has already been computed, such as when
835 applying raw data from a peer repo.
835 applying raw data from a peer repo.
836 """
836 """
837
837
838 def addgroup(
838 def addgroup(
839 self,
839 self,
840 deltas,
840 deltas,
841 linkmapper,
841 linkmapper,
842 transaction,
842 transaction,
843 addrevisioncb=None,
843 addrevisioncb=None,
844 duplicaterevisioncb=None,
844 duplicaterevisioncb=None,
845 maybemissingparents=False,
845 maybemissingparents=False,
846 ):
846 ):
847 """Process a series of deltas for storage.
847 """Process a series of deltas for storage.
848
848
849 ``deltas`` is an iterable of 7-tuples of
849 ``deltas`` is an iterable of 7-tuples of
850 (node, p1, p2, linknode, deltabase, delta, flags) defining revisions
850 (node, p1, p2, linknode, deltabase, delta, flags) defining revisions
851 to add.
851 to add.
852
852
853 The ``delta`` field contains ``mpatch`` data to apply to a base
853 The ``delta`` field contains ``mpatch`` data to apply to a base
854 revision, identified by ``deltabase``. The base node can be
854 revision, identified by ``deltabase``. The base node can be
855 ``nullid``, in which case the header from the delta can be ignored
855 ``nullid``, in which case the header from the delta can be ignored
856 and the delta used as the fulltext.
856 and the delta used as the fulltext.
857
857
858 ``alwayscache`` instructs the lower layers to cache the content of the
858 ``alwayscache`` instructs the lower layers to cache the content of the
859 newly added revision, even if it needs to be explicitly computed.
859 newly added revision, even if it needs to be explicitly computed.
860 This used to be the default when ``addrevisioncb`` was provided up to
860 This used to be the default when ``addrevisioncb`` was provided up to
861 Mercurial 5.8.
861 Mercurial 5.8.
862
862
863 ``addrevisioncb`` should be called for each new rev as it is committed.
863 ``addrevisioncb`` should be called for each new rev as it is committed.
864 ``duplicaterevisioncb`` should be called for all revs with a
864 ``duplicaterevisioncb`` should be called for all revs with a
865 pre-existing node.
865 pre-existing node.
866
866
867 ``maybemissingparents`` is a bool indicating whether the incoming
867 ``maybemissingparents`` is a bool indicating whether the incoming
868 data may reference parents/ancestor revisions that aren't present.
868 data may reference parents/ancestor revisions that aren't present.
869 This flag is set when receiving data into a "shallow" store that
869 This flag is set when receiving data into a "shallow" store that
870 doesn't hold all history.
870 doesn't hold all history.
871
871
872 Returns a list of nodes that were processed. A node will be in the list
872 Returns a list of nodes that were processed. A node will be in the list
873 even if it existed in the store previously.
873 even if it existed in the store previously.
874 """
874 """
875
875
876 def censorrevision(self, tr, node, tombstone=b''):
876 def censorrevision(self, tr, node, tombstone=b''):
877 """Remove the content of a single revision.
877 """Remove the content of a single revision.
878
878
879 The specified ``node`` will have its content purged from storage.
879 The specified ``node`` will have its content purged from storage.
880 Future attempts to access the revision data for this node will
880 Future attempts to access the revision data for this node will
881 result in failure.
881 result in failure.
882
882
883 A ``tombstone`` message can optionally be stored. This message may be
883 A ``tombstone`` message can optionally be stored. This message may be
884 displayed to users when they attempt to access the missing revision
884 displayed to users when they attempt to access the missing revision
885 data.
885 data.
886
886
887 Storage backends may have stored deltas against the previous content
887 Storage backends may have stored deltas against the previous content
888 in this revision. As part of censoring a revision, these storage
888 in this revision. As part of censoring a revision, these storage
889 backends are expected to rewrite any internally stored deltas such
889 backends are expected to rewrite any internally stored deltas such
890 that they no longer reference the deleted content.
890 that they no longer reference the deleted content.
891 """
891 """
892
892
893 def getstrippoint(self, minlink):
893 def getstrippoint(self, minlink):
894 """Find the minimum revision that must be stripped to strip a linkrev.
894 """Find the minimum revision that must be stripped to strip a linkrev.
895
895
896 Returns a 2-tuple containing the minimum revision number and a set
896 Returns a 2-tuple containing the minimum revision number and a set
897 of all revisions numbers that would be broken by this strip.
897 of all revisions numbers that would be broken by this strip.
898
898
899 TODO this is highly revlog centric and should be abstracted into
899 TODO this is highly revlog centric and should be abstracted into
900 a higher-level deletion API. ``repair.strip()`` relies on this.
900 a higher-level deletion API. ``repair.strip()`` relies on this.
901 """
901 """
902
902
903 def strip(self, minlink, transaction):
903 def strip(self, minlink, transaction):
904 """Remove storage of items starting at a linkrev.
904 """Remove storage of items starting at a linkrev.
905
905
906 This uses ``getstrippoint()`` to determine the first node to remove.
906 This uses ``getstrippoint()`` to determine the first node to remove.
907 Then it effectively truncates storage for all revisions after that.
907 Then it effectively truncates storage for all revisions after that.
908
908
909 TODO this is highly revlog centric and should be abstracted into a
909 TODO this is highly revlog centric and should be abstracted into a
910 higher-level deletion API.
910 higher-level deletion API.
911 """
911 """
912
912
913
913
914 class ifilestorage(ifileindex, ifiledata, ifilemutation):
914 class ifilestorage(ifileindex, ifiledata, ifilemutation):
915 """Complete storage interface for a single tracked file."""
915 """Complete storage interface for a single tracked file."""
916
916
917 def files(self):
917 def files(self):
918 """Obtain paths that are backing storage for this file.
918 """Obtain paths that are backing storage for this file.
919
919
920 TODO this is used heavily by verify code and there should probably
920 TODO this is used heavily by verify code and there should probably
921 be a better API for that.
921 be a better API for that.
922 """
922 """
923
923
924 def storageinfo(
924 def storageinfo(
925 self,
925 self,
926 exclusivefiles=False,
926 exclusivefiles=False,
927 sharedfiles=False,
927 sharedfiles=False,
928 revisionscount=False,
928 revisionscount=False,
929 trackedsize=False,
929 trackedsize=False,
930 storedsize=False,
930 storedsize=False,
931 ):
931 ):
932 """Obtain information about storage for this file's data.
932 """Obtain information about storage for this file's data.
933
933
934 Returns a dict describing storage for this tracked path. The keys
934 Returns a dict describing storage for this tracked path. The keys
935 in the dict map to arguments of the same. The arguments are bools
935 in the dict map to arguments of the same. The arguments are bools
936 indicating whether to calculate and obtain that data.
936 indicating whether to calculate and obtain that data.
937
937
938 exclusivefiles
938 exclusivefiles
939 Iterable of (vfs, path) describing files that are exclusively
939 Iterable of (vfs, path) describing files that are exclusively
940 used to back storage for this tracked path.
940 used to back storage for this tracked path.
941
941
942 sharedfiles
942 sharedfiles
943 Iterable of (vfs, path) describing files that are used to back
943 Iterable of (vfs, path) describing files that are used to back
944 storage for this tracked path. Those files may also provide storage
944 storage for this tracked path. Those files may also provide storage
945 for other stored entities.
945 for other stored entities.
946
946
947 revisionscount
947 revisionscount
948 Number of revisions available for retrieval.
948 Number of revisions available for retrieval.
949
949
950 trackedsize
950 trackedsize
951 Total size in bytes of all tracked revisions. This is a sum of the
951 Total size in bytes of all tracked revisions. This is a sum of the
952 length of the fulltext of all revisions.
952 length of the fulltext of all revisions.
953
953
954 storedsize
954 storedsize
955 Total size in bytes used to store data for all tracked revisions.
955 Total size in bytes used to store data for all tracked revisions.
956 This is commonly less than ``trackedsize`` due to internal usage
956 This is commonly less than ``trackedsize`` due to internal usage
957 of deltas rather than fulltext revisions.
957 of deltas rather than fulltext revisions.
958
958
959 Not all storage backends may support all queries are have a reasonable
959 Not all storage backends may support all queries are have a reasonable
960 value to use. In that case, the value should be set to ``None`` and
960 value to use. In that case, the value should be set to ``None`` and
961 callers are expected to handle this special value.
961 callers are expected to handle this special value.
962 """
962 """
963
963
964 def verifyintegrity(self, state):
964 def verifyintegrity(self, state):
965 """Verifies the integrity of file storage.
965 """Verifies the integrity of file storage.
966
966
967 ``state`` is a dict holding state of the verifier process. It can be
967 ``state`` is a dict holding state of the verifier process. It can be
968 used to communicate data between invocations of multiple storage
968 used to communicate data between invocations of multiple storage
969 primitives.
969 primitives.
970
970
971 If individual revisions cannot have their revision content resolved,
971 If individual revisions cannot have their revision content resolved,
972 the method is expected to set the ``skipread`` key to a set of nodes
972 the method is expected to set the ``skipread`` key to a set of nodes
973 that encountered problems. If set, the method can also add the node(s)
973 that encountered problems. If set, the method can also add the node(s)
974 to ``safe_renamed`` in order to indicate nodes that may perform the
974 to ``safe_renamed`` in order to indicate nodes that may perform the
975 rename checks with currently accessible data.
975 rename checks with currently accessible data.
976
976
977 The method yields objects conforming to the ``iverifyproblem``
977 The method yields objects conforming to the ``iverifyproblem``
978 interface.
978 interface.
979 """
979 """
980
980
981
981
982 class idirs(Protocol):
982 class idirs(Protocol):
983 """Interface representing a collection of directories from paths.
983 """Interface representing a collection of directories from paths.
984
984
985 This interface is essentially a derived data structure representing
985 This interface is essentially a derived data structure representing
986 directories from a collection of paths.
986 directories from a collection of paths.
987 """
987 """
988
988
989 def addpath(self, path):
989 def addpath(self, path):
990 """Add a path to the collection.
990 """Add a path to the collection.
991
991
992 All directories in the path will be added to the collection.
992 All directories in the path will be added to the collection.
993 """
993 """
994
994
995 def delpath(self, path):
995 def delpath(self, path):
996 """Remove a path from the collection.
996 """Remove a path from the collection.
997
997
998 If the removal was the last path in a particular directory, the
998 If the removal was the last path in a particular directory, the
999 directory is removed from the collection.
999 directory is removed from the collection.
1000 """
1000 """
1001
1001
1002 def __iter__(self):
1002 def __iter__(self):
1003 """Iterate over the directories in this collection of paths."""
1003 """Iterate over the directories in this collection of paths."""
1004
1004
1005 def __contains__(self, path):
1005 def __contains__(self, path):
1006 """Whether a specific directory is in this collection."""
1006 """Whether a specific directory is in this collection."""
1007
1007
1008
1008
1009 class imanifestdict(Protocol):
1009 class imanifestdict(Protocol):
1010 """Interface representing a manifest data structure.
1010 """Interface representing a manifest data structure.
1011
1011
1012 A manifest is effectively a dict mapping paths to entries. Each entry
1012 A manifest is effectively a dict mapping paths to entries. Each entry
1013 consists of a binary node and extra flags affecting that entry.
1013 consists of a binary node and extra flags affecting that entry.
1014 """
1014 """
1015
1015
1016 def __getitem__(self, path):
1016 def __getitem__(self, path):
1017 """Returns the binary node value for a path in the manifest.
1017 """Returns the binary node value for a path in the manifest.
1018
1018
1019 Raises ``KeyError`` if the path does not exist in the manifest.
1019 Raises ``KeyError`` if the path does not exist in the manifest.
1020
1020
1021 Equivalent to ``self.find(path)[0]``.
1021 Equivalent to ``self.find(path)[0]``.
1022 """
1022 """
1023
1023
1024 def find(self, path):
1024 def find(self, path):
1025 """Returns the entry for a path in the manifest.
1025 """Returns the entry for a path in the manifest.
1026
1026
1027 Returns a 2-tuple of (node, flags).
1027 Returns a 2-tuple of (node, flags).
1028
1028
1029 Raises ``KeyError`` if the path does not exist in the manifest.
1029 Raises ``KeyError`` if the path does not exist in the manifest.
1030 """
1030 """
1031
1031
1032 def __len__(self):
1032 def __len__(self):
1033 """Return the number of entries in the manifest."""
1033 """Return the number of entries in the manifest."""
1034
1034
1035 def __nonzero__(self):
1035 def __nonzero__(self):
1036 """Returns True if the manifest has entries, False otherwise."""
1036 """Returns True if the manifest has entries, False otherwise."""
1037
1037
1038 __bool__ = __nonzero__
1038 __bool__ = __nonzero__
1039
1039
1040 def set(self, path, node, flags):
1040 def set(self, path, node, flags):
1041 """Define the node value and flags for a path in the manifest.
1041 """Define the node value and flags for a path in the manifest.
1042
1042
1043 Equivalent to __setitem__ followed by setflag, but can be more efficient.
1043 Equivalent to __setitem__ followed by setflag, but can be more efficient.
1044 """
1044 """
1045
1045
1046 def __setitem__(self, path, node):
1046 def __setitem__(self, path, node):
1047 """Define the node value for a path in the manifest.
1047 """Define the node value for a path in the manifest.
1048
1048
1049 If the path is already in the manifest, its flags will be copied to
1049 If the path is already in the manifest, its flags will be copied to
1050 the new entry.
1050 the new entry.
1051 """
1051 """
1052
1052
1053 def __contains__(self, path):
1053 def __contains__(self, path):
1054 """Whether a path exists in the manifest."""
1054 """Whether a path exists in the manifest."""
1055
1055
1056 def __delitem__(self, path):
1056 def __delitem__(self, path):
1057 """Remove a path from the manifest.
1057 """Remove a path from the manifest.
1058
1058
1059 Raises ``KeyError`` if the path is not in the manifest.
1059 Raises ``KeyError`` if the path is not in the manifest.
1060 """
1060 """
1061
1061
1062 def __iter__(self):
1062 def __iter__(self):
1063 """Iterate over paths in the manifest."""
1063 """Iterate over paths in the manifest."""
1064
1064
1065 def iterkeys(self):
1065 def iterkeys(self):
1066 """Iterate over paths in the manifest."""
1066 """Iterate over paths in the manifest."""
1067
1067
1068 def keys(self):
1068 def keys(self):
1069 """Obtain a list of paths in the manifest."""
1069 """Obtain a list of paths in the manifest."""
1070
1070
1071 def filesnotin(self, other, match=None):
1071 def filesnotin(self, other, match=None):
1072 """Obtain the set of paths in this manifest but not in another.
1072 """Obtain the set of paths in this manifest but not in another.
1073
1073
1074 ``match`` is an optional matcher function to be applied to both
1074 ``match`` is an optional matcher function to be applied to both
1075 manifests.
1075 manifests.
1076
1076
1077 Returns a set of paths.
1077 Returns a set of paths.
1078 """
1078 """
1079
1079
1080 def dirs(self):
1080 def dirs(self):
1081 """Returns an object implementing the ``idirs`` interface."""
1081 """Returns an object implementing the ``idirs`` interface."""
1082
1082
1083 def hasdir(self, dir):
1083 def hasdir(self, dir):
1084 """Returns a bool indicating if a directory is in this manifest."""
1084 """Returns a bool indicating if a directory is in this manifest."""
1085
1085
1086 def walk(self, match):
1086 def walk(self, match):
1087 """Generator of paths in manifest satisfying a matcher.
1087 """Generator of paths in manifest satisfying a matcher.
1088
1088
1089 If the matcher has explicit files listed and they don't exist in
1089 If the matcher has explicit files listed and they don't exist in
1090 the manifest, ``match.bad()`` is called for each missing file.
1090 the manifest, ``match.bad()`` is called for each missing file.
1091 """
1091 """
1092
1092
1093 def diff(self, other, match=None, clean=False):
1093 def diff(self, other, match=None, clean=False):
1094 """Find differences between this manifest and another.
1094 """Find differences between this manifest and another.
1095
1095
1096 This manifest is compared to ``other``.
1096 This manifest is compared to ``other``.
1097
1097
1098 If ``match`` is provided, the two manifests are filtered against this
1098 If ``match`` is provided, the two manifests are filtered against this
1099 matcher and only entries satisfying the matcher are compared.
1099 matcher and only entries satisfying the matcher are compared.
1100
1100
1101 If ``clean`` is True, unchanged files are included in the returned
1101 If ``clean`` is True, unchanged files are included in the returned
1102 object.
1102 object.
1103
1103
1104 Returns a dict with paths as keys and values of 2-tuples of 2-tuples of
1104 Returns a dict with paths as keys and values of 2-tuples of 2-tuples of
1105 the form ``((node1, flag1), (node2, flag2))`` where ``(node1, flag1)``
1105 the form ``((node1, flag1), (node2, flag2))`` where ``(node1, flag1)``
1106 represents the node and flags for this manifest and ``(node2, flag2)``
1106 represents the node and flags for this manifest and ``(node2, flag2)``
1107 are the same for the other manifest.
1107 are the same for the other manifest.
1108 """
1108 """
1109
1109
1110 def setflag(self, path, flag):
1110 def setflag(self, path, flag):
1111 """Set the flag value for a given path.
1111 """Set the flag value for a given path.
1112
1112
1113 Raises ``KeyError`` if the path is not already in the manifest.
1113 Raises ``KeyError`` if the path is not already in the manifest.
1114 """
1114 """
1115
1115
1116 def get(self, path, default=None):
1116 def get(self, path, default=None):
1117 """Obtain the node value for a path or a default value if missing."""
1117 """Obtain the node value for a path or a default value if missing."""
1118
1118
1119 def flags(self, path):
1119 def flags(self, path):
1120 """Return the flags value for a path (default: empty bytestring)."""
1120 """Return the flags value for a path (default: empty bytestring)."""
1121
1121
1122 def copy(self):
1122 def copy(self):
1123 """Return a copy of this manifest."""
1123 """Return a copy of this manifest."""
1124
1124
1125 def items(self):
1125 def items(self):
1126 """Returns an iterable of (path, node) for items in this manifest."""
1126 """Returns an iterable of (path, node) for items in this manifest."""
1127
1127
1128 def iteritems(self):
1128 def iteritems(self):
1129 """Identical to items()."""
1129 """Identical to items()."""
1130
1130
1131 def iterentries(self):
1131 def iterentries(self):
1132 """Returns an iterable of (path, node, flags) for this manifest.
1132 """Returns an iterable of (path, node, flags) for this manifest.
1133
1133
1134 Similar to ``iteritems()`` except items are a 3-tuple and include
1134 Similar to ``iteritems()`` except items are a 3-tuple and include
1135 flags.
1135 flags.
1136 """
1136 """
1137
1137
1138 def text(self):
1138 def text(self):
1139 """Obtain the raw data representation for this manifest.
1139 """Obtain the raw data representation for this manifest.
1140
1140
1141 Result is used to create a manifest revision.
1141 Result is used to create a manifest revision.
1142 """
1142 """
1143
1143
1144 def fastdelta(self, base, changes):
1144 def fastdelta(self, base, changes):
1145 """Obtain a delta between this manifest and another given changes.
1145 """Obtain a delta between this manifest and another given changes.
1146
1146
1147 ``base`` in the raw data representation for another manifest.
1147 ``base`` in the raw data representation for another manifest.
1148
1148
1149 ``changes`` is an iterable of ``(path, to_delete)``.
1149 ``changes`` is an iterable of ``(path, to_delete)``.
1150
1150
1151 Returns a 2-tuple containing ``bytearray(self.text())`` and the
1151 Returns a 2-tuple containing ``bytearray(self.text())`` and the
1152 delta between ``base`` and this manifest.
1152 delta between ``base`` and this manifest.
1153
1153
1154 If this manifest implementation can't support ``fastdelta()``,
1154 If this manifest implementation can't support ``fastdelta()``,
1155 raise ``mercurial.manifest.FastdeltaUnavailable``.
1155 raise ``mercurial.manifest.FastdeltaUnavailable``.
1156 """
1156 """
1157
1157
1158
1158
1159 class imanifestrevisionbase(Protocol):
1159 class imanifestrevisionbase(Protocol):
1160 """Base interface representing a single revision of a manifest.
1160 """Base interface representing a single revision of a manifest.
1161
1161
1162 Should not be used as a primary interface: should always be inherited
1162 Should not be used as a primary interface: should always be inherited
1163 as part of a larger interface.
1163 as part of a larger interface.
1164 """
1164 """
1165
1165
1166 def copy(self):
1166 def copy(self):
1167 """Obtain a copy of this manifest instance.
1167 """Obtain a copy of this manifest instance.
1168
1168
1169 Returns an object conforming to the ``imanifestrevisionwritable``
1169 Returns an object conforming to the ``imanifestrevisionwritable``
1170 interface. The instance will be associated with the same
1170 interface. The instance will be associated with the same
1171 ``imanifestlog`` collection as this instance.
1171 ``imanifestlog`` collection as this instance.
1172 """
1172 """
1173
1173
1174 def read(self):
1174 def read(self):
1175 """Obtain the parsed manifest data structure.
1175 """Obtain the parsed manifest data structure.
1176
1176
1177 The returned object conforms to the ``imanifestdict`` interface.
1177 The returned object conforms to the ``imanifestdict`` interface.
1178 """
1178 """
1179
1179
1180
1180
1181 class imanifestrevisionstored(imanifestrevisionbase, Protocol):
1181 class imanifestrevisionstored(imanifestrevisionbase, Protocol):
1182 """Interface representing a manifest revision committed to storage."""
1182 """Interface representing a manifest revision committed to storage."""
1183
1183
1184 @abc.abstractmethod
1184 @abc.abstractmethod
1185 def node(self) -> bytes:
1185 def node(self) -> bytes:
1186 """The binary node for this manifest."""
1186 """The binary node for this manifest."""
1187
1187
1188 parents: list[bytes]
1188 parents: list[bytes]
1189 """List of binary nodes that are parents for this manifest revision."""
1189 """List of binary nodes that are parents for this manifest revision."""
1190
1190
1191 @abc.abstractmethod
1191 @abc.abstractmethod
1192 def readdelta(self, shallow: bool = False):
1192 def readdelta(self, shallow: bool = False):
1193 """Obtain the manifest data structure representing changes from parent.
1193 """Obtain the manifest data structure representing changes from parent.
1194
1194
1195 This manifest is compared to its 1st parent. A new manifest
1195 This manifest is compared to its 1st parent. A new manifest
1196 representing those differences is constructed.
1196 representing those differences is constructed.
1197
1197
1198 If `shallow` is True, this will read the delta for this directory,
1198 If `shallow` is True, this will read the delta for this directory,
1199 without recursively reading subdirectory manifests. Instead, any
1199 without recursively reading subdirectory manifests. Instead, any
1200 subdirectory entry will be reported as it appears in the manifest, i.e.
1200 subdirectory entry will be reported as it appears in the manifest, i.e.
1201 the subdirectory will be reported among files and distinguished only by
1201 the subdirectory will be reported among files and distinguished only by
1202 its 't' flag. This only apply if the underlying manifest support it.
1202 its 't' flag. This only apply if the underlying manifest support it.
1203
1203
1204 The returned object conforms to the ``imanifestdict`` interface.
1204 The returned object conforms to the ``imanifestdict`` interface.
1205 """
1205 """
1206
1206
1207 @abc.abstractmethod
1207 @abc.abstractmethod
1208 def read_any_fast_delta(
1208 def read_any_fast_delta(
1209 self,
1209 self,
1210 valid_bases: Collection[int] | None = None,
1210 valid_bases: Collection[int] | None = None,
1211 *,
1211 *,
1212 shallow: bool = False,
1212 shallow: bool = False,
1213 ):
1213 ):
1214 """read some manifest information as fast if possible
1214 """read some manifest information as fast if possible
1215
1215
1216 This might return a "delta", a manifest object containing only file
1216 This might return a "delta", a manifest object containing only file
1217 changed compared to another revisions. The `valid_bases` argument
1217 changed compared to another revisions. The `valid_bases` argument
1218 control the set of revision that might be used as a base.
1218 control the set of revision that might be used as a base.
1219
1219
1220 If no delta can be retrieved quickly, a full read of the manifest will
1220 If no delta can be retrieved quickly, a full read of the manifest will
1221 be performed instead.
1221 be performed instead.
1222
1222
1223 The function return a tuple with two elements. The first one is the
1223 The function return a tuple with two elements. The first one is the
1224 delta base used (or None if we did a full read), the second one is the
1224 delta base used (or None if we did a full read), the second one is the
1225 manifest information.
1225 manifest information.
1226
1226
1227 If `shallow` is True, this will read the delta for this directory,
1227 If `shallow` is True, this will read the delta for this directory,
1228 without recursively reading subdirectory manifests. Instead, any
1228 without recursively reading subdirectory manifests. Instead, any
1229 subdirectory entry will be reported as it appears in the manifest, i.e.
1229 subdirectory entry will be reported as it appears in the manifest, i.e.
1230 the subdirectory will be reported among files and distinguished only by
1230 the subdirectory will be reported among files and distinguished only by
1231 its 't' flag. This only apply if the underlying manifest support it.
1231 its 't' flag. This only apply if the underlying manifest support it.
1232
1232
1233 The returned object conforms to the ``imanifestdict`` interface.
1233 The returned object conforms to the ``imanifestdict`` interface.
1234 """
1234 """
1235
1235
1236 @abc.abstractmethod
1236 @abc.abstractmethod
1237 def read_delta_parents(self, *, shallow: bool = False, exact: bool = True):
1237 def read_delta_parents(self, *, shallow: bool = False, exact: bool = True):
1238 """return a diff from this revision against both parents.
1238 """return a diff from this revision against both parents.
1239
1239
1240 If `exact` is False, this might return a superset of the diff, containing
1240 If `exact` is False, this might return a superset of the diff, containing
1241 files that are actually present as is in one of the parents.
1241 files that are actually present as is in one of the parents.
1242
1242
1243 If `shallow` is True, this will read the delta for this directory,
1243 If `shallow` is True, this will read the delta for this directory,
1244 without recursively reading subdirectory manifests. Instead, any
1244 without recursively reading subdirectory manifests. Instead, any
1245 subdirectory entry will be reported as it appears in the manifest, i.e.
1245 subdirectory entry will be reported as it appears in the manifest, i.e.
1246 the subdirectory will be reported among files and distinguished only by
1246 the subdirectory will be reported among files and distinguished only by
1247 its 't' flag. This only apply if the underlying manifest support it.
1247 its 't' flag. This only apply if the underlying manifest support it.
1248
1248
1249 The returned object conforms to the ``imanifestdict`` interface."""
1249 The returned object conforms to the ``imanifestdict`` interface."""
1250
1250
1251 @abc.abstractmethod
1251 @abc.abstractmethod
1252 def read_delta_new_entries(self, *, shallow: bool = False):
1252 def read_delta_new_entries(self, *, shallow: bool = False):
1253 """Return a manifest containing just the entries that might be new to
1253 """Return a manifest containing just the entries that might be new to
1254 the repository.
1254 the repository.
1255
1255
1256 This is often equivalent to a diff against both parents, but without
1256 This is often equivalent to a diff against both parents, but without
1257 garantee. For performance reason, It might contains more files in some cases.
1257 garantee. For performance reason, It might contains more files in some cases.
1258
1258
1259 If `shallow` is True, this will read the delta for this directory,
1259 If `shallow` is True, this will read the delta for this directory,
1260 without recursively reading subdirectory manifests. Instead, any
1260 without recursively reading subdirectory manifests. Instead, any
1261 subdirectory entry will be reported as it appears in the manifest, i.e.
1261 subdirectory entry will be reported as it appears in the manifest, i.e.
1262 the subdirectory will be reported among files and distinguished only by
1262 the subdirectory will be reported among files and distinguished only by
1263 its 't' flag. This only apply if the underlying manifest support it.
1263 its 't' flag. This only apply if the underlying manifest support it.
1264
1264
1265 The returned object conforms to the ``imanifestdict`` interface."""
1265 The returned object conforms to the ``imanifestdict`` interface."""
1266
1266
1267 @abc.abstractmethod
1267 @abc.abstractmethod
1268 def readfast(self, shallow: bool = False):
1268 def readfast(self, shallow: bool = False):
1269 """Calls either ``read()`` or ``readdelta()``.
1269 """Calls either ``read()`` or ``readdelta()``.
1270
1270
1271 The faster of the two options is called.
1271 The faster of the two options is called.
1272 """
1272 """
1273
1273
1274 @abc.abstractmethod
1274 @abc.abstractmethod
1275 def find(self, key: bytes) -> tuple[bytes, bytes]:
1275 def find(self, key: bytes) -> tuple[bytes, bytes]:
1276 """Calls ``self.read().find(key)``.
1276 """Calls ``self.read().find(key)``.
1277
1277
1278 Returns a 2-tuple of ``(node, flags)`` or raises ``KeyError``.
1278 Returns a 2-tuple of ``(node, flags)`` or raises ``KeyError``.
1279 """
1279 """
1280
1280
1281
1281
1282 class imanifestrevisionwritable(imanifestrevisionbase):
1282 class imanifestrevisionwritable(imanifestrevisionbase, Protocol):
1283 """Interface representing a manifest revision that can be committed."""
1283 """Interface representing a manifest revision that can be committed."""
1284
1284
1285 @abc.abstractmethod
1285 def write(
1286 def write(
1286 self, transaction, linkrev, p1node, p2node, added, removed, match=None
1287 self, transaction, linkrev, p1node, p2node, added, removed, match=None
1287 ):
1288 ):
1288 """Add this revision to storage.
1289 """Add this revision to storage.
1289
1290
1290 Takes a transaction object, the changeset revision number it will
1291 Takes a transaction object, the changeset revision number it will
1291 be associated with, its parent nodes, and lists of added and
1292 be associated with, its parent nodes, and lists of added and
1292 removed paths.
1293 removed paths.
1293
1294
1294 If match is provided, storage can choose not to inspect or write out
1295 If match is provided, storage can choose not to inspect or write out
1295 items that do not match. Storage is still required to be able to provide
1296 items that do not match. Storage is still required to be able to provide
1296 the full manifest in the future for any directories written (these
1297 the full manifest in the future for any directories written (these
1297 manifests should not be "narrowed on disk").
1298 manifests should not be "narrowed on disk").
1298
1299
1299 Returns the binary node of the created revision.
1300 Returns the binary node of the created revision.
1300 """
1301 """
1301
1302
1302
1303
1303 class imanifeststorage(Protocol):
1304 class imanifeststorage(Protocol):
1304 """Storage interface for manifest data."""
1305 """Storage interface for manifest data."""
1305
1306
1306 nodeconstants: NodeConstants
1307 nodeconstants: NodeConstants
1307 """nodeconstants used by the current repository."""
1308 """nodeconstants used by the current repository."""
1308
1309
1309 tree: bytes
1310 tree: bytes
1310 """The path to the directory this manifest tracks.
1311 """The path to the directory this manifest tracks.
1311
1312
1312 The empty bytestring represents the root manifest.
1313 The empty bytestring represents the root manifest.
1313 """
1314 """
1314
1315
1315 index: ifilerevisionssequence
1316 index: ifilerevisionssequence
1316 """An ``ifilerevisionssequence`` instance."""
1317 """An ``ifilerevisionssequence`` instance."""
1317
1318
1318 opener: Vfs
1319 opener: Vfs
1319 """VFS opener to use to access underlying files used for storage.
1320 """VFS opener to use to access underlying files used for storage.
1320
1321
1321 TODO this is revlog specific and should not be exposed.
1322 TODO this is revlog specific and should not be exposed.
1322 """
1323 """
1323
1324
1324 # TODO: finish type hints
1325 # TODO: finish type hints
1325 fulltextcache: dict
1326 fulltextcache: dict
1326 """Dict with cache of fulltexts.
1327 """Dict with cache of fulltexts.
1327
1328
1328 TODO this doesn't feel appropriate for the storage interface.
1329 TODO this doesn't feel appropriate for the storage interface.
1329 """
1330 """
1330
1331
1331 @abc.abstractmethod
1332 @abc.abstractmethod
1332 def __len__(self):
1333 def __len__(self):
1333 """Obtain the number of revisions stored for this manifest."""
1334 """Obtain the number of revisions stored for this manifest."""
1334
1335
1335 @abc.abstractmethod
1336 @abc.abstractmethod
1336 def __iter__(self):
1337 def __iter__(self):
1337 """Iterate over revision numbers for this manifest."""
1338 """Iterate over revision numbers for this manifest."""
1338
1339
1339 @abc.abstractmethod
1340 @abc.abstractmethod
1340 def rev(self, node):
1341 def rev(self, node):
1341 """Obtain the revision number given a binary node.
1342 """Obtain the revision number given a binary node.
1342
1343
1343 Raises ``error.LookupError`` if the node is not known.
1344 Raises ``error.LookupError`` if the node is not known.
1344 """
1345 """
1345
1346
1346 @abc.abstractmethod
1347 @abc.abstractmethod
1347 def node(self, rev):
1348 def node(self, rev):
1348 """Obtain the node value given a revision number.
1349 """Obtain the node value given a revision number.
1349
1350
1350 Raises ``error.LookupError`` if the revision is not known.
1351 Raises ``error.LookupError`` if the revision is not known.
1351 """
1352 """
1352
1353
1353 @abc.abstractmethod
1354 @abc.abstractmethod
1354 def lookup(self, value):
1355 def lookup(self, value):
1355 """Attempt to resolve a value to a node.
1356 """Attempt to resolve a value to a node.
1356
1357
1357 Value can be a binary node, hex node, revision number, or a bytes
1358 Value can be a binary node, hex node, revision number, or a bytes
1358 that can be converted to an integer.
1359 that can be converted to an integer.
1359
1360
1360 Raises ``error.LookupError`` if a ndoe could not be resolved.
1361 Raises ``error.LookupError`` if a ndoe could not be resolved.
1361 """
1362 """
1362
1363
1363 @abc.abstractmethod
1364 @abc.abstractmethod
1364 def parents(self, node):
1365 def parents(self, node):
1365 """Returns a 2-tuple of parent nodes for a node.
1366 """Returns a 2-tuple of parent nodes for a node.
1366
1367
1367 Values will be ``nullid`` if the parent is empty.
1368 Values will be ``nullid`` if the parent is empty.
1368 """
1369 """
1369
1370
1370 @abc.abstractmethod
1371 @abc.abstractmethod
1371 def parentrevs(self, rev):
1372 def parentrevs(self, rev):
1372 """Like parents() but operates on revision numbers."""
1373 """Like parents() but operates on revision numbers."""
1373
1374
1374 @abc.abstractmethod
1375 @abc.abstractmethod
1375 def linkrev(self, rev):
1376 def linkrev(self, rev):
1376 """Obtain the changeset revision number a revision is linked to."""
1377 """Obtain the changeset revision number a revision is linked to."""
1377
1378
1378 @abc.abstractmethod
1379 @abc.abstractmethod
1379 def revision(self, node):
1380 def revision(self, node):
1380 """Obtain fulltext data for a node."""
1381 """Obtain fulltext data for a node."""
1381
1382
1382 @abc.abstractmethod
1383 @abc.abstractmethod
1383 def rawdata(self, node):
1384 def rawdata(self, node):
1384 """Obtain raw data for a node."""
1385 """Obtain raw data for a node."""
1385
1386
1386 @abc.abstractmethod
1387 @abc.abstractmethod
1387 def revdiff(self, rev1, rev2):
1388 def revdiff(self, rev1, rev2):
1388 """Obtain a delta between two revision numbers.
1389 """Obtain a delta between two revision numbers.
1389
1390
1390 The returned data is the result of ``bdiff.bdiff()`` on the raw
1391 The returned data is the result of ``bdiff.bdiff()`` on the raw
1391 revision data.
1392 revision data.
1392 """
1393 """
1393
1394
1394 @abc.abstractmethod
1395 @abc.abstractmethod
1395 def cmp(self, node, fulltext):
1396 def cmp(self, node, fulltext):
1396 """Compare fulltext to another revision.
1397 """Compare fulltext to another revision.
1397
1398
1398 Returns True if the fulltext is different from what is stored.
1399 Returns True if the fulltext is different from what is stored.
1399 """
1400 """
1400
1401
1401 @abc.abstractmethod
1402 @abc.abstractmethod
1402 def emitrevisions(
1403 def emitrevisions(
1403 self,
1404 self,
1404 nodes,
1405 nodes,
1405 nodesorder=None,
1406 nodesorder=None,
1406 revisiondata=False,
1407 revisiondata=False,
1407 assumehaveparentrevisions=False,
1408 assumehaveparentrevisions=False,
1408 ):
1409 ):
1409 """Produce ``irevisiondelta`` describing revisions.
1410 """Produce ``irevisiondelta`` describing revisions.
1410
1411
1411 See the documentation for ``ifiledata`` for more.
1412 See the documentation for ``ifiledata`` for more.
1412 """
1413 """
1413
1414
1414 @abc.abstractmethod
1415 @abc.abstractmethod
1415 def addgroup(
1416 def addgroup(
1416 self,
1417 self,
1417 deltas,
1418 deltas,
1418 linkmapper,
1419 linkmapper,
1419 transaction,
1420 transaction,
1420 addrevisioncb=None,
1421 addrevisioncb=None,
1421 duplicaterevisioncb=None,
1422 duplicaterevisioncb=None,
1422 ):
1423 ):
1423 """Process a series of deltas for storage.
1424 """Process a series of deltas for storage.
1424
1425
1425 See the documentation in ``ifilemutation`` for more.
1426 See the documentation in ``ifilemutation`` for more.
1426 """
1427 """
1427
1428
1428 @abc.abstractmethod
1429 @abc.abstractmethod
1429 def rawsize(self, rev):
1430 def rawsize(self, rev):
1430 """Obtain the size of tracked data.
1431 """Obtain the size of tracked data.
1431
1432
1432 Is equivalent to ``len(m.rawdata(node))``.
1433 Is equivalent to ``len(m.rawdata(node))``.
1433
1434
1434 TODO this method is only used by upgrade code and may be removed.
1435 TODO this method is only used by upgrade code and may be removed.
1435 """
1436 """
1436
1437
1437 @abc.abstractmethod
1438 @abc.abstractmethod
1438 def getstrippoint(self, minlink):
1439 def getstrippoint(self, minlink):
1439 """Find minimum revision that must be stripped to strip a linkrev.
1440 """Find minimum revision that must be stripped to strip a linkrev.
1440
1441
1441 See the documentation in ``ifilemutation`` for more.
1442 See the documentation in ``ifilemutation`` for more.
1442 """
1443 """
1443
1444
1444 @abc.abstractmethod
1445 @abc.abstractmethod
1445 def strip(self, minlink, transaction):
1446 def strip(self, minlink, transaction):
1446 """Remove storage of items starting at a linkrev.
1447 """Remove storage of items starting at a linkrev.
1447
1448
1448 See the documentation in ``ifilemutation`` for more.
1449 See the documentation in ``ifilemutation`` for more.
1449 """
1450 """
1450
1451
1451 @abc.abstractmethod
1452 @abc.abstractmethod
1452 def checksize(self):
1453 def checksize(self):
1453 """Obtain the expected sizes of backing files.
1454 """Obtain the expected sizes of backing files.
1454
1455
1455 TODO this is used by verify and it should not be part of the interface.
1456 TODO this is used by verify and it should not be part of the interface.
1456 """
1457 """
1457
1458
1458 @abc.abstractmethod
1459 @abc.abstractmethod
1459 def files(self):
1460 def files(self):
1460 """Obtain paths that are backing storage for this manifest.
1461 """Obtain paths that are backing storage for this manifest.
1461
1462
1462 TODO this is used by verify and there should probably be a better API
1463 TODO this is used by verify and there should probably be a better API
1463 for this functionality.
1464 for this functionality.
1464 """
1465 """
1465
1466
1466 @abc.abstractmethod
1467 @abc.abstractmethod
1467 def deltaparent(self, rev):
1468 def deltaparent(self, rev):
1468 """Obtain the revision that a revision is delta'd against.
1469 """Obtain the revision that a revision is delta'd against.
1469
1470
1470 TODO delta encoding is an implementation detail of storage and should
1471 TODO delta encoding is an implementation detail of storage and should
1471 not be exposed to the storage interface.
1472 not be exposed to the storage interface.
1472 """
1473 """
1473
1474
1474 @abc.abstractmethod
1475 @abc.abstractmethod
1475 def clone(self, tr, dest, **kwargs):
1476 def clone(self, tr, dest, **kwargs):
1476 """Clone this instance to another."""
1477 """Clone this instance to another."""
1477
1478
1478 @abc.abstractmethod
1479 @abc.abstractmethod
1479 def clearcaches(self, clear_persisted_data=False):
1480 def clearcaches(self, clear_persisted_data=False):
1480 """Clear any caches associated with this instance."""
1481 """Clear any caches associated with this instance."""
1481
1482
1482 @abc.abstractmethod
1483 @abc.abstractmethod
1483 def dirlog(self, d):
1484 def dirlog(self, d):
1484 """Obtain a manifest storage instance for a tree."""
1485 """Obtain a manifest storage instance for a tree."""
1485
1486
1486 @abc.abstractmethod
1487 @abc.abstractmethod
1487 def add(
1488 def add(
1488 self,
1489 self,
1489 m,
1490 m,
1490 transaction,
1491 transaction,
1491 link,
1492 link,
1492 p1,
1493 p1,
1493 p2,
1494 p2,
1494 added,
1495 added,
1495 removed,
1496 removed,
1496 readtree=None,
1497 readtree=None,
1497 match=None,
1498 match=None,
1498 ):
1499 ):
1499 """Add a revision to storage.
1500 """Add a revision to storage.
1500
1501
1501 ``m`` is an object conforming to ``imanifestdict``.
1502 ``m`` is an object conforming to ``imanifestdict``.
1502
1503
1503 ``link`` is the linkrev revision number.
1504 ``link`` is the linkrev revision number.
1504
1505
1505 ``p1`` and ``p2`` are the parent revision numbers.
1506 ``p1`` and ``p2`` are the parent revision numbers.
1506
1507
1507 ``added`` and ``removed`` are iterables of added and removed paths,
1508 ``added`` and ``removed`` are iterables of added and removed paths,
1508 respectively.
1509 respectively.
1509
1510
1510 ``readtree`` is a function that can be used to read the child tree(s)
1511 ``readtree`` is a function that can be used to read the child tree(s)
1511 when recursively writing the full tree structure when using
1512 when recursively writing the full tree structure when using
1512 treemanifets.
1513 treemanifets.
1513
1514
1514 ``match`` is a matcher that can be used to hint to storage that not all
1515 ``match`` is a matcher that can be used to hint to storage that not all
1515 paths must be inspected; this is an optimization and can be safely
1516 paths must be inspected; this is an optimization and can be safely
1516 ignored. Note that the storage must still be able to reproduce a full
1517 ignored. Note that the storage must still be able to reproduce a full
1517 manifest including files that did not match.
1518 manifest including files that did not match.
1518 """
1519 """
1519
1520
1520 @abc.abstractmethod
1521 @abc.abstractmethod
1521 def storageinfo(
1522 def storageinfo(
1522 self,
1523 self,
1523 exclusivefiles=False,
1524 exclusivefiles=False,
1524 sharedfiles=False,
1525 sharedfiles=False,
1525 revisionscount=False,
1526 revisionscount=False,
1526 trackedsize=False,
1527 trackedsize=False,
1527 storedsize=False,
1528 storedsize=False,
1528 ):
1529 ):
1529 """Obtain information about storage for this manifest's data.
1530 """Obtain information about storage for this manifest's data.
1530
1531
1531 See ``ifilestorage.storageinfo()`` for a description of this method.
1532 See ``ifilestorage.storageinfo()`` for a description of this method.
1532 This one behaves the same way, except for manifest data.
1533 This one behaves the same way, except for manifest data.
1533 """
1534 """
1534
1535
1535 @abc.abstractmethod
1536 @abc.abstractmethod
1536 def get_revlog(self):
1537 def get_revlog(self):
1537 """return an actual revlog instance if any
1538 """return an actual revlog instance if any
1538
1539
1539 This exist because a lot of code leverage the fact the underlying
1540 This exist because a lot of code leverage the fact the underlying
1540 storage is a revlog for optimization, so giving simple way to access
1541 storage is a revlog for optimization, so giving simple way to access
1541 the revlog instance helps such code.
1542 the revlog instance helps such code.
1542 """
1543 """
1543
1544
1544
1545
1545 class imanifestlog(Protocol):
1546 class imanifestlog(Protocol):
1546 """Interface representing a collection of manifest snapshots.
1547 """Interface representing a collection of manifest snapshots.
1547
1548
1548 Represents the root manifest in a repository.
1549 Represents the root manifest in a repository.
1549
1550
1550 Also serves as a means to access nested tree manifests and to cache
1551 Also serves as a means to access nested tree manifests and to cache
1551 tree manifests.
1552 tree manifests.
1552 """
1553 """
1553
1554
1554 nodeconstants = interfaceutil.Attribute(
1555 nodeconstants = interfaceutil.Attribute(
1555 """nodeconstants used by the current repository."""
1556 """nodeconstants used by the current repository."""
1556 )
1557 )
1557
1558
1558 narrowed = interfaceutil.Attribute(
1559 narrowed = interfaceutil.Attribute(
1559 """True, is the manifest is narrowed by a matcher"""
1560 """True, is the manifest is narrowed by a matcher"""
1560 )
1561 )
1561
1562
1562 def __getitem__(self, node):
1563 def __getitem__(self, node):
1563 """Obtain a manifest instance for a given binary node.
1564 """Obtain a manifest instance for a given binary node.
1564
1565
1565 Equivalent to calling ``self.get('', node)``.
1566 Equivalent to calling ``self.get('', node)``.
1566
1567
1567 The returned object conforms to the ``imanifestrevisionstored``
1568 The returned object conforms to the ``imanifestrevisionstored``
1568 interface.
1569 interface.
1569 """
1570 """
1570
1571
1571 def get(self, tree, node, verify=True):
1572 def get(self, tree, node, verify=True):
1572 """Retrieve the manifest instance for a given directory and binary node.
1573 """Retrieve the manifest instance for a given directory and binary node.
1573
1574
1574 ``node`` always refers to the node of the root manifest (which will be
1575 ``node`` always refers to the node of the root manifest (which will be
1575 the only manifest if flat manifests are being used).
1576 the only manifest if flat manifests are being used).
1576
1577
1577 If ``tree`` is the empty string, the root manifest is returned.
1578 If ``tree`` is the empty string, the root manifest is returned.
1578 Otherwise the manifest for the specified directory will be returned
1579 Otherwise the manifest for the specified directory will be returned
1579 (requires tree manifests).
1580 (requires tree manifests).
1580
1581
1581 If ``verify`` is True, ``LookupError`` is raised if the node is not
1582 If ``verify`` is True, ``LookupError`` is raised if the node is not
1582 known.
1583 known.
1583
1584
1584 The returned object conforms to the ``imanifestrevisionstored``
1585 The returned object conforms to the ``imanifestrevisionstored``
1585 interface.
1586 interface.
1586 """
1587 """
1587
1588
1588 def getstorage(self, tree):
1589 def getstorage(self, tree):
1589 """Retrieve an interface to storage for a particular tree.
1590 """Retrieve an interface to storage for a particular tree.
1590
1591
1591 If ``tree`` is the empty bytestring, storage for the root manifest will
1592 If ``tree`` is the empty bytestring, storage for the root manifest will
1592 be returned. Otherwise storage for a tree manifest is returned.
1593 be returned. Otherwise storage for a tree manifest is returned.
1593
1594
1594 TODO formalize interface for returned object.
1595 TODO formalize interface for returned object.
1595 """
1596 """
1596
1597
1597 def clearcaches(self, clear_persisted_data: bool = False) -> None:
1598 def clearcaches(self, clear_persisted_data: bool = False) -> None:
1598 """Clear caches associated with this collection."""
1599 """Clear caches associated with this collection."""
1599
1600
1600 def rev(self, node):
1601 def rev(self, node):
1601 """Obtain the revision number for a binary node.
1602 """Obtain the revision number for a binary node.
1602
1603
1603 Raises ``error.LookupError`` if the node is not known.
1604 Raises ``error.LookupError`` if the node is not known.
1604 """
1605 """
1605
1606
1606 def update_caches(self, transaction):
1607 def update_caches(self, transaction):
1607 """update whatever cache are relevant for the used storage."""
1608 """update whatever cache are relevant for the used storage."""
1608
1609
1609
1610
1610 class ilocalrepositoryfilestorage(Protocol):
1611 class ilocalrepositoryfilestorage(Protocol):
1611 """Local repository sub-interface providing access to tracked file storage.
1612 """Local repository sub-interface providing access to tracked file storage.
1612
1613
1613 This interface defines how a repository accesses storage for a single
1614 This interface defines how a repository accesses storage for a single
1614 tracked file path.
1615 tracked file path.
1615 """
1616 """
1616
1617
1617 def file(self, f):
1618 def file(self, f):
1618 """Obtain a filelog for a tracked path.
1619 """Obtain a filelog for a tracked path.
1619
1620
1620 The returned type conforms to the ``ifilestorage`` interface.
1621 The returned type conforms to the ``ifilestorage`` interface.
1621 """
1622 """
1622
1623
1623
1624
1624 class ilocalrepositorymain(Protocol):
1625 class ilocalrepositorymain(Protocol):
1625 """Main interface for local repositories.
1626 """Main interface for local repositories.
1626
1627
1627 This currently captures the reality of things - not how things should be.
1628 This currently captures the reality of things - not how things should be.
1628 """
1629 """
1629
1630
1630 nodeconstants = interfaceutil.Attribute(
1631 nodeconstants = interfaceutil.Attribute(
1631 """Constant nodes matching the hash function used by the repository."""
1632 """Constant nodes matching the hash function used by the repository."""
1632 )
1633 )
1633 nullid = interfaceutil.Attribute(
1634 nullid = interfaceutil.Attribute(
1634 """null revision for the hash function used by the repository."""
1635 """null revision for the hash function used by the repository."""
1635 )
1636 )
1636
1637
1637 supported = interfaceutil.Attribute(
1638 supported = interfaceutil.Attribute(
1638 """Set of requirements that this repo is capable of opening."""
1639 """Set of requirements that this repo is capable of opening."""
1639 )
1640 )
1640
1641
1641 requirements = interfaceutil.Attribute(
1642 requirements = interfaceutil.Attribute(
1642 """Set of requirements this repo uses."""
1643 """Set of requirements this repo uses."""
1643 )
1644 )
1644
1645
1645 features = interfaceutil.Attribute(
1646 features = interfaceutil.Attribute(
1646 """Set of "features" this repository supports.
1647 """Set of "features" this repository supports.
1647
1648
1648 A "feature" is a loosely-defined term. It can refer to a feature
1649 A "feature" is a loosely-defined term. It can refer to a feature
1649 in the classical sense or can describe an implementation detail
1650 in the classical sense or can describe an implementation detail
1650 of the repository. For example, a ``readonly`` feature may denote
1651 of the repository. For example, a ``readonly`` feature may denote
1651 the repository as read-only. Or a ``revlogfilestore`` feature may
1652 the repository as read-only. Or a ``revlogfilestore`` feature may
1652 denote that the repository is using revlogs for file storage.
1653 denote that the repository is using revlogs for file storage.
1653
1654
1654 The intent of features is to provide a machine-queryable mechanism
1655 The intent of features is to provide a machine-queryable mechanism
1655 for repo consumers to test for various repository characteristics.
1656 for repo consumers to test for various repository characteristics.
1656
1657
1657 Features are similar to ``requirements``. The main difference is that
1658 Features are similar to ``requirements``. The main difference is that
1658 requirements are stored on-disk and represent requirements to open the
1659 requirements are stored on-disk and represent requirements to open the
1659 repository. Features are more run-time capabilities of the repository
1660 repository. Features are more run-time capabilities of the repository
1660 and more granular capabilities (which may be derived from requirements).
1661 and more granular capabilities (which may be derived from requirements).
1661 """
1662 """
1662 )
1663 )
1663
1664
1664 filtername = interfaceutil.Attribute(
1665 filtername = interfaceutil.Attribute(
1665 """Name of the repoview that is active on this repo."""
1666 """Name of the repoview that is active on this repo."""
1666 )
1667 )
1667
1668
1668 vfs_map = interfaceutil.Attribute(
1669 vfs_map = interfaceutil.Attribute(
1669 """a bytes-key β†’ vfs mapping used by transaction and others"""
1670 """a bytes-key β†’ vfs mapping used by transaction and others"""
1670 )
1671 )
1671
1672
1672 wvfs = interfaceutil.Attribute(
1673 wvfs = interfaceutil.Attribute(
1673 """VFS used to access the working directory."""
1674 """VFS used to access the working directory."""
1674 )
1675 )
1675
1676
1676 vfs = interfaceutil.Attribute(
1677 vfs = interfaceutil.Attribute(
1677 """VFS rooted at the .hg directory.
1678 """VFS rooted at the .hg directory.
1678
1679
1679 Used to access repository data not in the store.
1680 Used to access repository data not in the store.
1680 """
1681 """
1681 )
1682 )
1682
1683
1683 svfs = interfaceutil.Attribute(
1684 svfs = interfaceutil.Attribute(
1684 """VFS rooted at the store.
1685 """VFS rooted at the store.
1685
1686
1686 Used to access repository data in the store. Typically .hg/store.
1687 Used to access repository data in the store. Typically .hg/store.
1687 But can point elsewhere if the store is shared.
1688 But can point elsewhere if the store is shared.
1688 """
1689 """
1689 )
1690 )
1690
1691
1691 root = interfaceutil.Attribute(
1692 root = interfaceutil.Attribute(
1692 """Path to the root of the working directory."""
1693 """Path to the root of the working directory."""
1693 )
1694 )
1694
1695
1695 path = interfaceutil.Attribute("""Path to the .hg directory.""")
1696 path = interfaceutil.Attribute("""Path to the .hg directory.""")
1696
1697
1697 origroot = interfaceutil.Attribute(
1698 origroot = interfaceutil.Attribute(
1698 """The filesystem path that was used to construct the repo."""
1699 """The filesystem path that was used to construct the repo."""
1699 )
1700 )
1700
1701
1701 auditor = interfaceutil.Attribute(
1702 auditor = interfaceutil.Attribute(
1702 """A pathauditor for the working directory.
1703 """A pathauditor for the working directory.
1703
1704
1704 This checks if a path refers to a nested repository.
1705 This checks if a path refers to a nested repository.
1705
1706
1706 Operates on the filesystem.
1707 Operates on the filesystem.
1707 """
1708 """
1708 )
1709 )
1709
1710
1710 nofsauditor = interfaceutil.Attribute(
1711 nofsauditor = interfaceutil.Attribute(
1711 """A pathauditor for the working directory.
1712 """A pathauditor for the working directory.
1712
1713
1713 This is like ``auditor`` except it doesn't do filesystem checks.
1714 This is like ``auditor`` except it doesn't do filesystem checks.
1714 """
1715 """
1715 )
1716 )
1716
1717
1717 baseui = interfaceutil.Attribute(
1718 baseui = interfaceutil.Attribute(
1718 """Original ui instance passed into constructor."""
1719 """Original ui instance passed into constructor."""
1719 )
1720 )
1720
1721
1721 ui = interfaceutil.Attribute("""Main ui instance for this instance.""")
1722 ui = interfaceutil.Attribute("""Main ui instance for this instance.""")
1722
1723
1723 sharedpath = interfaceutil.Attribute(
1724 sharedpath = interfaceutil.Attribute(
1724 """Path to the .hg directory of the repo this repo was shared from."""
1725 """Path to the .hg directory of the repo this repo was shared from."""
1725 )
1726 )
1726
1727
1727 store = interfaceutil.Attribute("""A store instance.""")
1728 store = interfaceutil.Attribute("""A store instance.""")
1728
1729
1729 spath = interfaceutil.Attribute("""Path to the store.""")
1730 spath = interfaceutil.Attribute("""Path to the store.""")
1730
1731
1731 sjoin = interfaceutil.Attribute("""Alias to self.store.join.""")
1732 sjoin = interfaceutil.Attribute("""Alias to self.store.join.""")
1732
1733
1733 cachevfs = interfaceutil.Attribute(
1734 cachevfs = interfaceutil.Attribute(
1734 """A VFS used to access the cache directory.
1735 """A VFS used to access the cache directory.
1735
1736
1736 Typically .hg/cache.
1737 Typically .hg/cache.
1737 """
1738 """
1738 )
1739 )
1739
1740
1740 wcachevfs = interfaceutil.Attribute(
1741 wcachevfs = interfaceutil.Attribute(
1741 """A VFS used to access the cache directory dedicated to working copy
1742 """A VFS used to access the cache directory dedicated to working copy
1742
1743
1743 Typically .hg/wcache.
1744 Typically .hg/wcache.
1744 """
1745 """
1745 )
1746 )
1746
1747
1747 filteredrevcache = interfaceutil.Attribute(
1748 filteredrevcache = interfaceutil.Attribute(
1748 """Holds sets of revisions to be filtered."""
1749 """Holds sets of revisions to be filtered."""
1749 )
1750 )
1750
1751
1751 names = interfaceutil.Attribute("""A ``namespaces`` instance.""")
1752 names = interfaceutil.Attribute("""A ``namespaces`` instance.""")
1752
1753
1753 filecopiesmode = interfaceutil.Attribute(
1754 filecopiesmode = interfaceutil.Attribute(
1754 """The way files copies should be dealt with in this repo."""
1755 """The way files copies should be dealt with in this repo."""
1755 )
1756 )
1756
1757
1757 def close(self):
1758 def close(self):
1758 """Close the handle on this repository."""
1759 """Close the handle on this repository."""
1759
1760
1760 def peer(self, path=None):
1761 def peer(self, path=None):
1761 """Obtain an object conforming to the ``peer`` interface."""
1762 """Obtain an object conforming to the ``peer`` interface."""
1762
1763
1763 def unfiltered(self):
1764 def unfiltered(self):
1764 """Obtain an unfiltered/raw view of this repo."""
1765 """Obtain an unfiltered/raw view of this repo."""
1765
1766
1766 def filtered(self, name, visibilityexceptions=None):
1767 def filtered(self, name, visibilityexceptions=None):
1767 """Obtain a named view of this repository."""
1768 """Obtain a named view of this repository."""
1768
1769
1769 obsstore = interfaceutil.Attribute("""A store of obsolescence data.""")
1770 obsstore = interfaceutil.Attribute("""A store of obsolescence data.""")
1770
1771
1771 changelog = interfaceutil.Attribute("""A handle on the changelog revlog.""")
1772 changelog = interfaceutil.Attribute("""A handle on the changelog revlog.""")
1772
1773
1773 manifestlog = interfaceutil.Attribute(
1774 manifestlog = interfaceutil.Attribute(
1774 """An instance conforming to the ``imanifestlog`` interface.
1775 """An instance conforming to the ``imanifestlog`` interface.
1775
1776
1776 Provides access to manifests for the repository.
1777 Provides access to manifests for the repository.
1777 """
1778 """
1778 )
1779 )
1779
1780
1780 dirstate = interfaceutil.Attribute("""Working directory state.""")
1781 dirstate = interfaceutil.Attribute("""Working directory state.""")
1781
1782
1782 narrowpats = interfaceutil.Attribute(
1783 narrowpats = interfaceutil.Attribute(
1783 """Matcher patterns for this repository's narrowspec."""
1784 """Matcher patterns for this repository's narrowspec."""
1784 )
1785 )
1785
1786
1786 def narrowmatch(self, match=None, includeexact=False):
1787 def narrowmatch(self, match=None, includeexact=False):
1787 """Obtain a matcher for the narrowspec."""
1788 """Obtain a matcher for the narrowspec."""
1788
1789
1789 def setnarrowpats(self, newincludes, newexcludes):
1790 def setnarrowpats(self, newincludes, newexcludes):
1790 """Define the narrowspec for this repository."""
1791 """Define the narrowspec for this repository."""
1791
1792
1792 def __getitem__(self, changeid):
1793 def __getitem__(self, changeid):
1793 """Try to resolve a changectx."""
1794 """Try to resolve a changectx."""
1794
1795
1795 def __contains__(self, changeid):
1796 def __contains__(self, changeid):
1796 """Whether a changeset exists."""
1797 """Whether a changeset exists."""
1797
1798
1798 def __nonzero__(self):
1799 def __nonzero__(self):
1799 """Always returns True."""
1800 """Always returns True."""
1800 return True
1801 return True
1801
1802
1802 __bool__ = __nonzero__
1803 __bool__ = __nonzero__
1803
1804
1804 def __len__(self):
1805 def __len__(self):
1805 """Returns the number of changesets in the repo."""
1806 """Returns the number of changesets in the repo."""
1806
1807
1807 def __iter__(self):
1808 def __iter__(self):
1808 """Iterate over revisions in the changelog."""
1809 """Iterate over revisions in the changelog."""
1809
1810
1810 def revs(self, expr, *args):
1811 def revs(self, expr, *args):
1811 """Evaluate a revset.
1812 """Evaluate a revset.
1812
1813
1813 Emits revisions.
1814 Emits revisions.
1814 """
1815 """
1815
1816
1816 def set(self, expr, *args):
1817 def set(self, expr, *args):
1817 """Evaluate a revset.
1818 """Evaluate a revset.
1818
1819
1819 Emits changectx instances.
1820 Emits changectx instances.
1820 """
1821 """
1821
1822
1822 def anyrevs(self, specs, user=False, localalias=None):
1823 def anyrevs(self, specs, user=False, localalias=None):
1823 """Find revisions matching one of the given revsets."""
1824 """Find revisions matching one of the given revsets."""
1824
1825
1825 def url(self):
1826 def url(self):
1826 """Returns a string representing the location of this repo."""
1827 """Returns a string representing the location of this repo."""
1827
1828
1828 def hook(self, name, throw=False, **args):
1829 def hook(self, name, throw=False, **args):
1829 """Call a hook."""
1830 """Call a hook."""
1830
1831
1831 def tags(self):
1832 def tags(self):
1832 """Return a mapping of tag to node."""
1833 """Return a mapping of tag to node."""
1833
1834
1834 def tagtype(self, tagname):
1835 def tagtype(self, tagname):
1835 """Return the type of a given tag."""
1836 """Return the type of a given tag."""
1836
1837
1837 def tagslist(self):
1838 def tagslist(self):
1838 """Return a list of tags ordered by revision."""
1839 """Return a list of tags ordered by revision."""
1839
1840
1840 def nodetags(self, node):
1841 def nodetags(self, node):
1841 """Return the tags associated with a node."""
1842 """Return the tags associated with a node."""
1842
1843
1843 def nodebookmarks(self, node):
1844 def nodebookmarks(self, node):
1844 """Return the list of bookmarks pointing to the specified node."""
1845 """Return the list of bookmarks pointing to the specified node."""
1845
1846
1846 def branchmap(self):
1847 def branchmap(self):
1847 """Return a mapping of branch to heads in that branch."""
1848 """Return a mapping of branch to heads in that branch."""
1848
1849
1849 def revbranchcache(self):
1850 def revbranchcache(self):
1850 pass
1851 pass
1851
1852
1852 def register_changeset(self, rev, changelogrevision):
1853 def register_changeset(self, rev, changelogrevision):
1853 """Extension point for caches for new nodes.
1854 """Extension point for caches for new nodes.
1854
1855
1855 Multiple consumers are expected to need parts of the changelogrevision,
1856 Multiple consumers are expected to need parts of the changelogrevision,
1856 so it is provided as optimization to avoid duplicate lookups. A simple
1857 so it is provided as optimization to avoid duplicate lookups. A simple
1857 cache would be fragile when other revisions are accessed, too."""
1858 cache would be fragile when other revisions are accessed, too."""
1858 pass
1859 pass
1859
1860
1860 def branchtip(self, branchtip, ignoremissing=False):
1861 def branchtip(self, branchtip, ignoremissing=False):
1861 """Return the tip node for a given branch."""
1862 """Return the tip node for a given branch."""
1862
1863
1863 def lookup(self, key):
1864 def lookup(self, key):
1864 """Resolve the node for a revision."""
1865 """Resolve the node for a revision."""
1865
1866
1866 def lookupbranch(self, key):
1867 def lookupbranch(self, key):
1867 """Look up the branch name of the given revision or branch name."""
1868 """Look up the branch name of the given revision or branch name."""
1868
1869
1869 def known(self, nodes):
1870 def known(self, nodes):
1870 """Determine whether a series of nodes is known.
1871 """Determine whether a series of nodes is known.
1871
1872
1872 Returns a list of bools.
1873 Returns a list of bools.
1873 """
1874 """
1874
1875
1875 def local(self):
1876 def local(self):
1876 """Whether the repository is local."""
1877 """Whether the repository is local."""
1877 return True
1878 return True
1878
1879
1879 def publishing(self):
1880 def publishing(self):
1880 """Whether the repository is a publishing repository."""
1881 """Whether the repository is a publishing repository."""
1881
1882
1882 def cancopy(self):
1883 def cancopy(self):
1883 pass
1884 pass
1884
1885
1885 def shared(self):
1886 def shared(self):
1886 """The type of shared repository or None."""
1887 """The type of shared repository or None."""
1887
1888
1888 def wjoin(self, f, *insidef):
1889 def wjoin(self, f, *insidef):
1889 """Calls self.vfs.reljoin(self.root, f, *insidef)"""
1890 """Calls self.vfs.reljoin(self.root, f, *insidef)"""
1890
1891
1891 def setparents(self, p1, p2):
1892 def setparents(self, p1, p2):
1892 """Set the parent nodes of the working directory."""
1893 """Set the parent nodes of the working directory."""
1893
1894
1894 def filectx(self, path, changeid=None, fileid=None):
1895 def filectx(self, path, changeid=None, fileid=None):
1895 """Obtain a filectx for the given file revision."""
1896 """Obtain a filectx for the given file revision."""
1896
1897
1897 def getcwd(self):
1898 def getcwd(self):
1898 """Obtain the current working directory from the dirstate."""
1899 """Obtain the current working directory from the dirstate."""
1899
1900
1900 def pathto(self, f, cwd=None):
1901 def pathto(self, f, cwd=None):
1901 """Obtain the relative path to a file."""
1902 """Obtain the relative path to a file."""
1902
1903
1903 def adddatafilter(self, name, fltr):
1904 def adddatafilter(self, name, fltr):
1904 pass
1905 pass
1905
1906
1906 def wread(self, filename):
1907 def wread(self, filename):
1907 """Read a file from wvfs, using data filters."""
1908 """Read a file from wvfs, using data filters."""
1908
1909
1909 def wwrite(self, filename, data, flags, backgroundclose=False, **kwargs):
1910 def wwrite(self, filename, data, flags, backgroundclose=False, **kwargs):
1910 """Write data to a file in the wvfs, using data filters."""
1911 """Write data to a file in the wvfs, using data filters."""
1911
1912
1912 def wwritedata(self, filename, data):
1913 def wwritedata(self, filename, data):
1913 """Resolve data for writing to the wvfs, using data filters."""
1914 """Resolve data for writing to the wvfs, using data filters."""
1914
1915
1915 def currenttransaction(self):
1916 def currenttransaction(self):
1916 """Obtain the current transaction instance or None."""
1917 """Obtain the current transaction instance or None."""
1917
1918
1918 def transaction(self, desc, report=None):
1919 def transaction(self, desc, report=None):
1919 """Open a new transaction to write to the repository."""
1920 """Open a new transaction to write to the repository."""
1920
1921
1921 def undofiles(self):
1922 def undofiles(self):
1922 """Returns a list of (vfs, path) for files to undo transactions."""
1923 """Returns a list of (vfs, path) for files to undo transactions."""
1923
1924
1924 def recover(self):
1925 def recover(self):
1925 """Roll back an interrupted transaction."""
1926 """Roll back an interrupted transaction."""
1926
1927
1927 def rollback(self, dryrun=False, force=False):
1928 def rollback(self, dryrun=False, force=False):
1928 """Undo the last transaction.
1929 """Undo the last transaction.
1929
1930
1930 DANGEROUS.
1931 DANGEROUS.
1931 """
1932 """
1932
1933
1933 def updatecaches(self, tr=None, full=False, caches=None):
1934 def updatecaches(self, tr=None, full=False, caches=None):
1934 """Warm repo caches."""
1935 """Warm repo caches."""
1935
1936
1936 def invalidatecaches(self):
1937 def invalidatecaches(self):
1937 """Invalidate cached data due to the repository mutating."""
1938 """Invalidate cached data due to the repository mutating."""
1938
1939
1939 def invalidatevolatilesets(self):
1940 def invalidatevolatilesets(self):
1940 pass
1941 pass
1941
1942
1942 def invalidatedirstate(self):
1943 def invalidatedirstate(self):
1943 """Invalidate the dirstate."""
1944 """Invalidate the dirstate."""
1944
1945
1945 def invalidate(self, clearfilecache=False):
1946 def invalidate(self, clearfilecache=False):
1946 pass
1947 pass
1947
1948
1948 def invalidateall(self):
1949 def invalidateall(self):
1949 pass
1950 pass
1950
1951
1951 def lock(self, wait=True):
1952 def lock(self, wait=True):
1952 """Lock the repository store and return a lock instance."""
1953 """Lock the repository store and return a lock instance."""
1953
1954
1954 def currentlock(self):
1955 def currentlock(self):
1955 """Return the lock if it's held or None."""
1956 """Return the lock if it's held or None."""
1956
1957
1957 def wlock(self, wait=True):
1958 def wlock(self, wait=True):
1958 """Lock the non-store parts of the repository."""
1959 """Lock the non-store parts of the repository."""
1959
1960
1960 def currentwlock(self):
1961 def currentwlock(self):
1961 """Return the wlock if it's held or None."""
1962 """Return the wlock if it's held or None."""
1962
1963
1963 def checkcommitpatterns(self, wctx, match, status, fail):
1964 def checkcommitpatterns(self, wctx, match, status, fail):
1964 pass
1965 pass
1965
1966
1966 def commit(
1967 def commit(
1967 self,
1968 self,
1968 text=b'',
1969 text=b'',
1969 user=None,
1970 user=None,
1970 date=None,
1971 date=None,
1971 match=None,
1972 match=None,
1972 force=False,
1973 force=False,
1973 editor=False,
1974 editor=False,
1974 extra=None,
1975 extra=None,
1975 ):
1976 ):
1976 """Add a new revision to the repository."""
1977 """Add a new revision to the repository."""
1977
1978
1978 def commitctx(self, ctx, error=False, origctx=None):
1979 def commitctx(self, ctx, error=False, origctx=None):
1979 """Commit a commitctx instance to the repository."""
1980 """Commit a commitctx instance to the repository."""
1980
1981
1981 def destroying(self):
1982 def destroying(self):
1982 """Inform the repository that nodes are about to be destroyed."""
1983 """Inform the repository that nodes are about to be destroyed."""
1983
1984
1984 def destroyed(self):
1985 def destroyed(self):
1985 """Inform the repository that nodes have been destroyed."""
1986 """Inform the repository that nodes have been destroyed."""
1986
1987
1987 def status(
1988 def status(
1988 self,
1989 self,
1989 node1=b'.',
1990 node1=b'.',
1990 node2=None,
1991 node2=None,
1991 match=None,
1992 match=None,
1992 ignored=False,
1993 ignored=False,
1993 clean=False,
1994 clean=False,
1994 unknown=False,
1995 unknown=False,
1995 listsubrepos=False,
1996 listsubrepos=False,
1996 ):
1997 ):
1997 """Convenience method to call repo[x].status()."""
1998 """Convenience method to call repo[x].status()."""
1998
1999
1999 def addpostdsstatus(self, ps):
2000 def addpostdsstatus(self, ps):
2000 pass
2001 pass
2001
2002
2002 def postdsstatus(self):
2003 def postdsstatus(self):
2003 pass
2004 pass
2004
2005
2005 def clearpostdsstatus(self):
2006 def clearpostdsstatus(self):
2006 pass
2007 pass
2007
2008
2008 def heads(self, start=None):
2009 def heads(self, start=None):
2009 """Obtain list of nodes that are DAG heads."""
2010 """Obtain list of nodes that are DAG heads."""
2010
2011
2011 def branchheads(self, branch=None, start=None, closed=False):
2012 def branchheads(self, branch=None, start=None, closed=False):
2012 pass
2013 pass
2013
2014
2014 def branches(self, nodes):
2015 def branches(self, nodes):
2015 pass
2016 pass
2016
2017
2017 def between(self, pairs):
2018 def between(self, pairs):
2018 pass
2019 pass
2019
2020
2020 def checkpush(self, pushop):
2021 def checkpush(self, pushop):
2021 pass
2022 pass
2022
2023
2023 prepushoutgoinghooks = interfaceutil.Attribute("""util.hooks instance.""")
2024 prepushoutgoinghooks = interfaceutil.Attribute("""util.hooks instance.""")
2024
2025
2025 def pushkey(self, namespace, key, old, new):
2026 def pushkey(self, namespace, key, old, new):
2026 pass
2027 pass
2027
2028
2028 def listkeys(self, namespace):
2029 def listkeys(self, namespace):
2029 pass
2030 pass
2030
2031
2031 def debugwireargs(self, one, two, three=None, four=None, five=None):
2032 def debugwireargs(self, one, two, three=None, four=None, five=None):
2032 pass
2033 pass
2033
2034
2034 def savecommitmessage(self, text):
2035 def savecommitmessage(self, text):
2035 pass
2036 pass
2036
2037
2037 def register_sidedata_computer(
2038 def register_sidedata_computer(
2038 self, kind, category, keys, computer, flags, replace=False
2039 self, kind, category, keys, computer, flags, replace=False
2039 ):
2040 ):
2040 pass
2041 pass
2041
2042
2042 def register_wanted_sidedata(self, category):
2043 def register_wanted_sidedata(self, category):
2043 pass
2044 pass
2044
2045
2045
2046
2046 class completelocalrepository(
2047 class completelocalrepository(
2047 ilocalrepositorymain, ilocalrepositoryfilestorage
2048 ilocalrepositorymain, ilocalrepositoryfilestorage
2048 ):
2049 ):
2049 """Complete interface for a local repository."""
2050 """Complete interface for a local repository."""
2050
2051
2051
2052
2052 class iwireprotocolcommandcacher(Protocol):
2053 class iwireprotocolcommandcacher(Protocol):
2053 """Represents a caching backend for wire protocol commands.
2054 """Represents a caching backend for wire protocol commands.
2054
2055
2055 Wire protocol version 2 supports transparent caching of many commands.
2056 Wire protocol version 2 supports transparent caching of many commands.
2056 To leverage this caching, servers can activate objects that cache
2057 To leverage this caching, servers can activate objects that cache
2057 command responses. Objects handle both cache writing and reading.
2058 command responses. Objects handle both cache writing and reading.
2058 This interface defines how that response caching mechanism works.
2059 This interface defines how that response caching mechanism works.
2059
2060
2060 Wire protocol version 2 commands emit a series of objects that are
2061 Wire protocol version 2 commands emit a series of objects that are
2061 serialized and sent to the client. The caching layer exists between
2062 serialized and sent to the client. The caching layer exists between
2062 the invocation of the command function and the sending of its output
2063 the invocation of the command function and the sending of its output
2063 objects to an output layer.
2064 objects to an output layer.
2064
2065
2065 Instances of this interface represent a binding to a cache that
2066 Instances of this interface represent a binding to a cache that
2066 can serve a response (in place of calling a command function) and/or
2067 can serve a response (in place of calling a command function) and/or
2067 write responses to a cache for subsequent use.
2068 write responses to a cache for subsequent use.
2068
2069
2069 When a command request arrives, the following happens with regards
2070 When a command request arrives, the following happens with regards
2070 to this interface:
2071 to this interface:
2071
2072
2072 1. The server determines whether the command request is cacheable.
2073 1. The server determines whether the command request is cacheable.
2073 2. If it is, an instance of this interface is spawned.
2074 2. If it is, an instance of this interface is spawned.
2074 3. The cacher is activated in a context manager (``__enter__`` is called).
2075 3. The cacher is activated in a context manager (``__enter__`` is called).
2075 4. A cache *key* for that request is derived. This will call the
2076 4. A cache *key* for that request is derived. This will call the
2076 instance's ``adjustcachekeystate()`` method so the derivation
2077 instance's ``adjustcachekeystate()`` method so the derivation
2077 can be influenced.
2078 can be influenced.
2078 5. The cacher is informed of the derived cache key via a call to
2079 5. The cacher is informed of the derived cache key via a call to
2079 ``setcachekey()``.
2080 ``setcachekey()``.
2080 6. The cacher's ``lookup()`` method is called to test for presence of
2081 6. The cacher's ``lookup()`` method is called to test for presence of
2081 the derived key in the cache.
2082 the derived key in the cache.
2082 7. If ``lookup()`` returns a hit, that cached result is used in place
2083 7. If ``lookup()`` returns a hit, that cached result is used in place
2083 of invoking the command function. ``__exit__`` is called and the instance
2084 of invoking the command function. ``__exit__`` is called and the instance
2084 is discarded.
2085 is discarded.
2085 8. The command function is invoked.
2086 8. The command function is invoked.
2086 9. ``onobject()`` is called for each object emitted by the command
2087 9. ``onobject()`` is called for each object emitted by the command
2087 function.
2088 function.
2088 10. After the final object is seen, ``onfinished()`` is called.
2089 10. After the final object is seen, ``onfinished()`` is called.
2089 11. ``__exit__`` is called to signal the end of use of the instance.
2090 11. ``__exit__`` is called to signal the end of use of the instance.
2090
2091
2091 Cache *key* derivation can be influenced by the instance.
2092 Cache *key* derivation can be influenced by the instance.
2092
2093
2093 Cache keys are initially derived by a deterministic representation of
2094 Cache keys are initially derived by a deterministic representation of
2094 the command request. This includes the command name, arguments, protocol
2095 the command request. This includes the command name, arguments, protocol
2095 version, etc. This initial key derivation is performed by CBOR-encoding a
2096 version, etc. This initial key derivation is performed by CBOR-encoding a
2096 data structure and feeding that output into a hasher.
2097 data structure and feeding that output into a hasher.
2097
2098
2098 Instances of this interface can influence this initial key derivation
2099 Instances of this interface can influence this initial key derivation
2099 via ``adjustcachekeystate()``.
2100 via ``adjustcachekeystate()``.
2100
2101
2101 The instance is informed of the derived cache key via a call to
2102 The instance is informed of the derived cache key via a call to
2102 ``setcachekey()``. The instance must store the key locally so it can
2103 ``setcachekey()``. The instance must store the key locally so it can
2103 be consulted on subsequent operations that may require it.
2104 be consulted on subsequent operations that may require it.
2104
2105
2105 When constructed, the instance has access to a callable that can be used
2106 When constructed, the instance has access to a callable that can be used
2106 for encoding response objects. This callable receives as its single
2107 for encoding response objects. This callable receives as its single
2107 argument an object emitted by a command function. It returns an iterable
2108 argument an object emitted by a command function. It returns an iterable
2108 of bytes chunks representing the encoded object. Unless the cacher is
2109 of bytes chunks representing the encoded object. Unless the cacher is
2109 caching native Python objects in memory or has a way of reconstructing
2110 caching native Python objects in memory or has a way of reconstructing
2110 the original Python objects, implementations typically call this function
2111 the original Python objects, implementations typically call this function
2111 to produce bytes from the output objects and then store those bytes in
2112 to produce bytes from the output objects and then store those bytes in
2112 the cache. When it comes time to re-emit those bytes, they are wrapped
2113 the cache. When it comes time to re-emit those bytes, they are wrapped
2113 in a ``wireprototypes.encodedresponse`` instance to tell the output
2114 in a ``wireprototypes.encodedresponse`` instance to tell the output
2114 layer that they are pre-encoded.
2115 layer that they are pre-encoded.
2115
2116
2116 When receiving the objects emitted by the command function, instances
2117 When receiving the objects emitted by the command function, instances
2117 can choose what to do with those objects. The simplest thing to do is
2118 can choose what to do with those objects. The simplest thing to do is
2118 re-emit the original objects. They will be forwarded to the output
2119 re-emit the original objects. They will be forwarded to the output
2119 layer and will be processed as if the cacher did not exist.
2120 layer and will be processed as if the cacher did not exist.
2120
2121
2121 Implementations could also choose to not emit objects - instead locally
2122 Implementations could also choose to not emit objects - instead locally
2122 buffering objects or their encoded representation. They could then emit
2123 buffering objects or their encoded representation. They could then emit
2123 a single "coalesced" object when ``onfinished()`` is called. In
2124 a single "coalesced" object when ``onfinished()`` is called. In
2124 this way, the implementation would function as a filtering layer of
2125 this way, the implementation would function as a filtering layer of
2125 sorts.
2126 sorts.
2126
2127
2127 When caching objects, typically the encoded form of the object will
2128 When caching objects, typically the encoded form of the object will
2128 be stored. Keep in mind that if the original object is forwarded to
2129 be stored. Keep in mind that if the original object is forwarded to
2129 the output layer, it will need to be encoded there as well. For large
2130 the output layer, it will need to be encoded there as well. For large
2130 output, this redundant encoding could add overhead. Implementations
2131 output, this redundant encoding could add overhead. Implementations
2131 could wrap the encoded object data in ``wireprototypes.encodedresponse``
2132 could wrap the encoded object data in ``wireprototypes.encodedresponse``
2132 instances to avoid this overhead.
2133 instances to avoid this overhead.
2133 """
2134 """
2134
2135
2135 def __enter__(self):
2136 def __enter__(self):
2136 """Marks the instance as active.
2137 """Marks the instance as active.
2137
2138
2138 Should return self.
2139 Should return self.
2139 """
2140 """
2140
2141
2141 def __exit__(self, exctype, excvalue, exctb):
2142 def __exit__(self, exctype, excvalue, exctb):
2142 """Called when cacher is no longer used.
2143 """Called when cacher is no longer used.
2143
2144
2144 This can be used by implementations to perform cleanup actions (e.g.
2145 This can be used by implementations to perform cleanup actions (e.g.
2145 disconnecting network sockets, aborting a partially cached response.
2146 disconnecting network sockets, aborting a partially cached response.
2146 """
2147 """
2147
2148
2148 def adjustcachekeystate(self, state):
2149 def adjustcachekeystate(self, state):
2149 """Influences cache key derivation by adjusting state to derive key.
2150 """Influences cache key derivation by adjusting state to derive key.
2150
2151
2151 A dict defining the state used to derive the cache key is passed.
2152 A dict defining the state used to derive the cache key is passed.
2152
2153
2153 Implementations can modify this dict to record additional state that
2154 Implementations can modify this dict to record additional state that
2154 is wanted to influence key derivation.
2155 is wanted to influence key derivation.
2155
2156
2156 Implementations are *highly* encouraged to not modify or delete
2157 Implementations are *highly* encouraged to not modify or delete
2157 existing keys.
2158 existing keys.
2158 """
2159 """
2159
2160
2160 def setcachekey(self, key):
2161 def setcachekey(self, key):
2161 """Record the derived cache key for this request.
2162 """Record the derived cache key for this request.
2162
2163
2163 Instances may mutate the key for internal usage, as desired. e.g.
2164 Instances may mutate the key for internal usage, as desired. e.g.
2164 instances may wish to prepend the repo name, introduce path
2165 instances may wish to prepend the repo name, introduce path
2165 components for filesystem or URL addressing, etc. Behavior is up to
2166 components for filesystem or URL addressing, etc. Behavior is up to
2166 the cache.
2167 the cache.
2167
2168
2168 Returns a bool indicating if the request is cacheable by this
2169 Returns a bool indicating if the request is cacheable by this
2169 instance.
2170 instance.
2170 """
2171 """
2171
2172
2172 def lookup(self):
2173 def lookup(self):
2173 """Attempt to resolve an entry in the cache.
2174 """Attempt to resolve an entry in the cache.
2174
2175
2175 The instance is instructed to look for the cache key that it was
2176 The instance is instructed to look for the cache key that it was
2176 informed about via the call to ``setcachekey()``.
2177 informed about via the call to ``setcachekey()``.
2177
2178
2178 If there's no cache hit or the cacher doesn't wish to use the cached
2179 If there's no cache hit or the cacher doesn't wish to use the cached
2179 entry, ``None`` should be returned.
2180 entry, ``None`` should be returned.
2180
2181
2181 Else, a dict defining the cached result should be returned. The
2182 Else, a dict defining the cached result should be returned. The
2182 dict may have the following keys:
2183 dict may have the following keys:
2183
2184
2184 objs
2185 objs
2185 An iterable of objects that should be sent to the client. That
2186 An iterable of objects that should be sent to the client. That
2186 iterable of objects is expected to be what the command function
2187 iterable of objects is expected to be what the command function
2187 would return if invoked or an equivalent representation thereof.
2188 would return if invoked or an equivalent representation thereof.
2188 """
2189 """
2189
2190
2190 def onobject(self, obj):
2191 def onobject(self, obj):
2191 """Called when a new object is emitted from the command function.
2192 """Called when a new object is emitted from the command function.
2192
2193
2193 Receives as its argument the object that was emitted from the
2194 Receives as its argument the object that was emitted from the
2194 command function.
2195 command function.
2195
2196
2196 This method returns an iterator of objects to forward to the output
2197 This method returns an iterator of objects to forward to the output
2197 layer. The easiest implementation is a generator that just
2198 layer. The easiest implementation is a generator that just
2198 ``yield obj``.
2199 ``yield obj``.
2199 """
2200 """
2200
2201
2201 def onfinished(self):
2202 def onfinished(self):
2202 """Called after all objects have been emitted from the command function.
2203 """Called after all objects have been emitted from the command function.
2203
2204
2204 Implementations should return an iterator of objects to forward to
2205 Implementations should return an iterator of objects to forward to
2205 the output layer.
2206 the output layer.
2206
2207
2207 This method can be a generator.
2208 This method can be a generator.
2208 """
2209 """
General Comments 0
You need to be logged in to leave comments. Login now