diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -1798,7 +1798,7 @@ "non-empty and does not use tree manifests")) op.repo.requirements.add('treemanifest') op.repo.svfs.options = localrepo.resolvestorevfsoptions( - op.repo.ui, op.repo.requirements) + op.repo.ui, op.repo.requirements, op.repo.features) op.repo._writerequirements() extrakwargs = {} targetphase = inpart.params.get('targetphase') diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -478,6 +478,8 @@ # At this point, we know we should be capable of opening the repository. # Now get on with doing that. + features = set() + # The "store" part of the repository holds versioned data. How it is # accessed is determined by various requirements. The ``shared`` or # ``relshared`` requirements indicate the store lives in the path contained @@ -494,6 +496,8 @@ raise error.RepoError(_(b'.hg/sharedpath points to nonexistent ' b'directory %s') % sharedvfs.base) + features.add(repository.REPO_FEATURE_SHARED_STORAGE) + storebasepath = sharedvfs.base cachepath = sharedvfs.join(b'cache') else: @@ -508,7 +512,7 @@ hgvfs.createmode = store.createmode storevfs = store.vfs - storevfs.options = resolvestorevfsoptions(ui, requirements) + storevfs.options = resolvestorevfsoptions(ui, requirements, features) # The cache vfs is used to manage cache files. cachevfs = vfsmod.vfs(cachepath, cacheaudited=True) @@ -528,6 +532,7 @@ typ = fn(ui=ui, intents=intents, requirements=requirements, + features=features, wdirvfs=wdirvfs, hgvfs=hgvfs, store=store, @@ -564,6 +569,7 @@ sharedpath=storebasepath, store=store, cachevfs=cachevfs, + features=features, intents=intents) def gathersupportedrequirements(ui): @@ -643,7 +649,7 @@ return storemod.basicstore(path, vfstype) -def resolvestorevfsoptions(ui, requirements): +def resolvestorevfsoptions(ui, requirements, features): """Resolve the options to pass to the store vfs opener. The returned dict is used to influence behavior of the storage layer. @@ -664,11 +670,11 @@ # opener options for it because those options wouldn't do anything # meaningful on such old repos. if b'revlogv1' in requirements or REVLOGV2_REQUIREMENT in requirements: - options.update(resolverevlogstorevfsoptions(ui, requirements)) + options.update(resolverevlogstorevfsoptions(ui, requirements, features)) return options -def resolverevlogstorevfsoptions(ui, requirements): +def resolverevlogstorevfsoptions(ui, requirements, features): """Resolve opener options specific to revlogs.""" options = {} @@ -756,8 +762,10 @@ return filelog.narrowfilelog(self.svfs, path, self.narrowmatch()) -def makefilestorage(requirements, **kwargs): +def makefilestorage(requirements, features, **kwargs): """Produce a type conforming to ``ilocalrepositoryfilestorage``.""" + features.add(repository.REPO_FEATURE_REVLOG_FILE_STORAGE) + if repository.NARROW_REQUIREMENT in requirements: return revlognarrowfilestorage else: @@ -831,7 +839,7 @@ def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements, supportedrequirements, sharedpath, store, cachevfs, - intents=None): + features, intents=None): """Create a new local repository instance. Most callers should use ``hg.repository()``, ``localrepo.instance()``, @@ -873,6 +881,10 @@ cachevfs ``vfs.vfs`` used for cache files. + features + ``set`` of bytestrings defining features/capabilities of this + instance. + intents ``set`` of system strings indicating what this repo will be used for. @@ -891,6 +903,7 @@ self.sharedpath = sharedpath self.store = store self.cachevfs = cachevfs + self.features = features self.filtername = None diff --git a/mercurial/repository.py b/mercurial/repository.py --- a/mercurial/repository.py +++ b/mercurial/repository.py @@ -19,6 +19,13 @@ # we should move this to just "narrow" or similar. NARROW_REQUIREMENT = 'narrowhg-experimental' +# Local repository feature string. + +# Revlogs are being used for file storage. +REPO_FEATURE_REVLOG_FILE_STORAGE = b'revlogfilestorage' +# The storage part of the repository is shared from an external source. +REPO_FEATURE_SHARED_STORAGE = b'sharedstore' + class ipeerconnection(interfaceutil.Interface): """Represents a "connection" to a repository. @@ -1275,6 +1282,24 @@ requirements = interfaceutil.Attribute( """Set of requirements this repo uses.""") + features = interfaceutil.Attribute( + """Set of "features" this repository supports. + + A "feature" is a loosely-defined term. It can refer to a feature + in the classical sense or can describe an implementation detail + of the repository. For example, a ``readonly`` feature may denote + the repository as read-only. Or a ``revlogfilestore`` feature may + denote that the repository is using revlogs for file storage. + + The intent of features is to provide a machine-queryable mechanism + for repo consumers to test for various repository characteristics. + + Features are similar to ``requirements``. The main difference is that + requirements are stored on-disk and represent requirements to open the + repository. Features are more run-time capabilities of the repository + and more granular capabilities (which may be derived from requirements). + """) + filtername = interfaceutil.Attribute( """Name of the repoview that is active on this repo.""") diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py --- a/mercurial/streamclone.py +++ b/mercurial/streamclone.py @@ -168,7 +168,7 @@ repo.requirements = requirements | ( repo.requirements - repo.supportedformats) repo.svfs.options = localrepo.resolvestorevfsoptions( - repo.ui, repo.requirements) + repo.ui, repo.requirements, repo.features) repo._writerequirements() if rbranchmap: @@ -643,5 +643,5 @@ repo.requirements = set(requirements) | ( repo.requirements - repo.supportedformats) repo.svfs.options = localrepo.resolvestorevfsoptions( - repo.ui, repo.requirements) + repo.ui, repo.requirements, repo.features) repo._writerequirements()