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