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