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')):