D4709: localrepo: define "features" on repository instances (API)

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Mon Sep 24 16:13:16 UTC 2018


indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  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.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D4709

AFFECTED FILES
  mercurial/bundle2.py
  mercurial/localrepo.py
  mercurial/repository.py
  mercurial/streamclone.py

CHANGE DETAILS

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()
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/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/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')



To: indygreg, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list