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