Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 39850:d89d5bc06eaa
localrepo: define "features" on repository instances (API)
There are a handful of attributes/methods on repository instances that
describe the behavior of the repository. Furthermore, there is
an unbound set of repository descriptors that we may wish to expose.
For example, an extension may wish to add a descriptor and have
monkeypatched functions look for the presence of an attribute before
taking actions.
This commit introduces a "features" mechanism to allow repositories
to self-advertise an arbitrary set of strings that describe repository
behavior or capabilities.
We implement basic support for advertising a few features to give an
idea of what I want to use this for.
Differential Revision: https://phab.mercurial-scm.org/D4709
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 19 Sep 2018 14:36:57 -0700 |
parents | d3d4b4b5f725 |
children | 2c2fadbc9851 |
comparison
equal
deleted
inserted
replaced
39849:d3d4b4b5f725 | 39850:d89d5bc06eaa |
---|---|
476 # that shared store since it has an unknown-to-us requirement. | 476 # that shared store since it has an unknown-to-us requirement. |
477 | 477 |
478 # At this point, we know we should be capable of opening the repository. | 478 # At this point, we know we should be capable of opening the repository. |
479 # Now get on with doing that. | 479 # Now get on with doing that. |
480 | 480 |
481 features = set() | |
482 | |
481 # The "store" part of the repository holds versioned data. How it is | 483 # The "store" part of the repository holds versioned data. How it is |
482 # accessed is determined by various requirements. The ``shared`` or | 484 # accessed is determined by various requirements. The ``shared`` or |
483 # ``relshared`` requirements indicate the store lives in the path contained | 485 # ``relshared`` requirements indicate the store lives in the path contained |
484 # in the ``.hg/sharedpath`` file. This is an absolute path for | 486 # in the ``.hg/sharedpath`` file. This is an absolute path for |
485 # ``shared`` and relative to ``.hg/`` for ``relshared``. | 487 # ``shared`` and relative to ``.hg/`` for ``relshared``. |
492 | 494 |
493 if not sharedvfs.exists(): | 495 if not sharedvfs.exists(): |
494 raise error.RepoError(_(b'.hg/sharedpath points to nonexistent ' | 496 raise error.RepoError(_(b'.hg/sharedpath points to nonexistent ' |
495 b'directory %s') % sharedvfs.base) | 497 b'directory %s') % sharedvfs.base) |
496 | 498 |
499 features.add(repository.REPO_FEATURE_SHARED_STORAGE) | |
500 | |
497 storebasepath = sharedvfs.base | 501 storebasepath = sharedvfs.base |
498 cachepath = sharedvfs.join(b'cache') | 502 cachepath = sharedvfs.join(b'cache') |
499 else: | 503 else: |
500 storebasepath = hgvfs.base | 504 storebasepath = hgvfs.base |
501 cachepath = hgvfs.join(b'cache') | 505 cachepath = hgvfs.join(b'cache') |
506 store = makestore(requirements, storebasepath, | 510 store = makestore(requirements, storebasepath, |
507 lambda base: vfsmod.vfs(base, cacheaudited=True)) | 511 lambda base: vfsmod.vfs(base, cacheaudited=True)) |
508 hgvfs.createmode = store.createmode | 512 hgvfs.createmode = store.createmode |
509 | 513 |
510 storevfs = store.vfs | 514 storevfs = store.vfs |
511 storevfs.options = resolvestorevfsoptions(ui, requirements) | 515 storevfs.options = resolvestorevfsoptions(ui, requirements, features) |
512 | 516 |
513 # The cache vfs is used to manage cache files. | 517 # The cache vfs is used to manage cache files. |
514 cachevfs = vfsmod.vfs(cachepath, cacheaudited=True) | 518 cachevfs = vfsmod.vfs(cachepath, cacheaudited=True) |
515 cachevfs.createmode = store.createmode | 519 cachevfs.createmode = store.createmode |
516 | 520 |
526 # We pass all potentially useful state to give extensions tons of | 530 # We pass all potentially useful state to give extensions tons of |
527 # flexibility. | 531 # flexibility. |
528 typ = fn(ui=ui, | 532 typ = fn(ui=ui, |
529 intents=intents, | 533 intents=intents, |
530 requirements=requirements, | 534 requirements=requirements, |
535 features=features, | |
531 wdirvfs=wdirvfs, | 536 wdirvfs=wdirvfs, |
532 hgvfs=hgvfs, | 537 hgvfs=hgvfs, |
533 store=store, | 538 store=store, |
534 storevfs=storevfs, | 539 storevfs=storevfs, |
535 storeoptions=storevfs.options, | 540 storeoptions=storevfs.options, |
562 requirements=requirements, | 567 requirements=requirements, |
563 supportedrequirements=supportedrequirements, | 568 supportedrequirements=supportedrequirements, |
564 sharedpath=storebasepath, | 569 sharedpath=storebasepath, |
565 store=store, | 570 store=store, |
566 cachevfs=cachevfs, | 571 cachevfs=cachevfs, |
572 features=features, | |
567 intents=intents) | 573 intents=intents) |
568 | 574 |
569 def gathersupportedrequirements(ui): | 575 def gathersupportedrequirements(ui): |
570 """Determine the complete set of recognized requirements.""" | 576 """Determine the complete set of recognized requirements.""" |
571 # Start with all requirements supported by this file. | 577 # Start with all requirements supported by this file. |
641 | 647 |
642 return storemod.encodedstore(path, vfstype) | 648 return storemod.encodedstore(path, vfstype) |
643 | 649 |
644 return storemod.basicstore(path, vfstype) | 650 return storemod.basicstore(path, vfstype) |
645 | 651 |
646 def resolvestorevfsoptions(ui, requirements): | 652 def resolvestorevfsoptions(ui, requirements, features): |
647 """Resolve the options to pass to the store vfs opener. | 653 """Resolve the options to pass to the store vfs opener. |
648 | 654 |
649 The returned dict is used to influence behavior of the storage layer. | 655 The returned dict is used to influence behavior of the storage layer. |
650 """ | 656 """ |
651 options = {} | 657 options = {} |
662 # requirement, we have to assume the repo is using revlog version 0. | 668 # requirement, we have to assume the repo is using revlog version 0. |
663 # This revlog format is super old and we don't bother trying to parse | 669 # This revlog format is super old and we don't bother trying to parse |
664 # opener options for it because those options wouldn't do anything | 670 # opener options for it because those options wouldn't do anything |
665 # meaningful on such old repos. | 671 # meaningful on such old repos. |
666 if b'revlogv1' in requirements or REVLOGV2_REQUIREMENT in requirements: | 672 if b'revlogv1' in requirements or REVLOGV2_REQUIREMENT in requirements: |
667 options.update(resolverevlogstorevfsoptions(ui, requirements)) | 673 options.update(resolverevlogstorevfsoptions(ui, requirements, features)) |
668 | 674 |
669 return options | 675 return options |
670 | 676 |
671 def resolverevlogstorevfsoptions(ui, requirements): | 677 def resolverevlogstorevfsoptions(ui, requirements, features): |
672 """Resolve opener options specific to revlogs.""" | 678 """Resolve opener options specific to revlogs.""" |
673 | 679 |
674 options = {} | 680 options = {} |
675 | 681 |
676 if b'revlogv1' in requirements: | 682 if b'revlogv1' in requirements: |
754 if path[0] == b'/': | 760 if path[0] == b'/': |
755 path = path[1:] | 761 path = path[1:] |
756 | 762 |
757 return filelog.narrowfilelog(self.svfs, path, self.narrowmatch()) | 763 return filelog.narrowfilelog(self.svfs, path, self.narrowmatch()) |
758 | 764 |
759 def makefilestorage(requirements, **kwargs): | 765 def makefilestorage(requirements, features, **kwargs): |
760 """Produce a type conforming to ``ilocalrepositoryfilestorage``.""" | 766 """Produce a type conforming to ``ilocalrepositoryfilestorage``.""" |
767 features.add(repository.REPO_FEATURE_REVLOG_FILE_STORAGE) | |
768 | |
761 if repository.NARROW_REQUIREMENT in requirements: | 769 if repository.NARROW_REQUIREMENT in requirements: |
762 return revlognarrowfilestorage | 770 return revlognarrowfilestorage |
763 else: | 771 else: |
764 return revlogfilestorage | 772 return revlogfilestorage |
765 | 773 |
829 'bisect.state', | 837 'bisect.state', |
830 } | 838 } |
831 | 839 |
832 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements, | 840 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements, |
833 supportedrequirements, sharedpath, store, cachevfs, | 841 supportedrequirements, sharedpath, store, cachevfs, |
834 intents=None): | 842 features, intents=None): |
835 """Create a new local repository instance. | 843 """Create a new local repository instance. |
836 | 844 |
837 Most callers should use ``hg.repository()``, ``localrepo.instance()``, | 845 Most callers should use ``hg.repository()``, ``localrepo.instance()``, |
838 or ``localrepo.makelocalrepository()`` for obtaining a new repository | 846 or ``localrepo.makelocalrepository()`` for obtaining a new repository |
839 object. | 847 object. |
870 ``store.basicstore`` (or derived) instance providing access to | 878 ``store.basicstore`` (or derived) instance providing access to |
871 versioned storage. | 879 versioned storage. |
872 | 880 |
873 cachevfs | 881 cachevfs |
874 ``vfs.vfs`` used for cache files. | 882 ``vfs.vfs`` used for cache files. |
883 | |
884 features | |
885 ``set`` of bytestrings defining features/capabilities of this | |
886 instance. | |
875 | 887 |
876 intents | 888 intents |
877 ``set`` of system strings indicating what this repo will be used | 889 ``set`` of system strings indicating what this repo will be used |
878 for. | 890 for. |
879 """ | 891 """ |
889 self.requirements = requirements | 901 self.requirements = requirements |
890 self.supported = supportedrequirements | 902 self.supported = supportedrequirements |
891 self.sharedpath = sharedpath | 903 self.sharedpath = sharedpath |
892 self.store = store | 904 self.store = store |
893 self.cachevfs = cachevfs | 905 self.cachevfs = cachevfs |
906 self.features = features | |
894 | 907 |
895 self.filtername = None | 908 self.filtername = None |
896 | 909 |
897 if (self.ui.configbool('devel', 'all-warnings') or | 910 if (self.ui.configbool('devel', 'all-warnings') or |
898 self.ui.configbool('devel', 'check-locks')): | 911 self.ui.configbool('devel', 'check-locks')): |