D4568: localrepo: read requirements file in makelocalrepository()

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Thu Sep 13 16:30:56 UTC 2018


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

REVISION SUMMARY
  Previously, scmutil.readrequires() loaded the requirements file
  and validated its content against what was supported.
  
  Requirements translate to repository features and are critical to
  our plans to dynamically create local repository types. So, we must
  load them in makelocalrepository() before a repository instance is
  constructed.
  
  This commit moves the reading of the .hg/requires file to
  makelocalrepository(). Because scmutil.readrequires() was performing
  I/O and validation, we inlined the validation into
  localrepository.__init__ and removed scmutil.readrequires().
  
  I plan to remove scmutil.readrequires() in a future commit (we can't
  do it now because statichttprepo uses it).

REPOSITORY
  rHG Mercurial

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

AFFECTED FILES
  mercurial/localrepo.py

CHANGE DETAILS

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -408,6 +408,18 @@
 
         raise error.RepoError(_(b'repository %s not found') % path)
 
+    # .hg/requires file contains a newline-delimited list of
+    # features/capabilities the opener (us) must have in order to use
+    # the repository. This file was introduced in Mercurial 0.9.2,
+    # which means very old repositories may not have one. We assume
+    # a missing file translates to no requirements.
+    try:
+        requirements = set(hgvfs.read(b'requires').splitlines())
+    except IOError as e:
+        if e.errno != errno.ENOENT:
+            raise
+        requirements = set()
+
     # The .hg/hgrc file may load extensions or contain config options
     # that influence repository construction. Attempt to load it and
     # process any new extensions that it may have pulled in.
@@ -424,6 +436,7 @@
         origroot=path,
         wdirvfs=wdirvfs,
         hgvfs=hgvfs,
+        requirements=requirements,
         intents=intents)
 
 @interfaceutil.implementer(repository.completelocalrepository)
@@ -476,7 +489,8 @@
         'bisect.state',
     }
 
-    def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, intents=None):
+    def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements,
+                 intents=None):
         """Create a new local repository instance.
 
         Most callers should use ``hg.repository()``, ``localrepo.instance()``,
@@ -500,6 +514,9 @@
         hgvfs
            ``vfs.vfs`` rooted at .hg/
 
+        requirements
+           ``set`` of bytestrings representing repository opening requirements.
+
         intents
            ``set`` of system strings indicating what this repo will be used
            for.
@@ -545,12 +562,23 @@
             if engine.revlogheader():
                 self.supported.add('exp-compression-%s' % name)
 
-        try:
-            self.requirements = scmutil.readrequires(self.vfs, self.supported)
-        except IOError as inst:
-            if inst.errno != errno.ENOENT:
-                raise
-            self.requirements = set()
+        # Validate that all seen repository requirements are supported.
+        missingrequirements = []
+        for r in requirements:
+            if r not in self.supported:
+                if not r or not r[0:1].isalnum():
+                    raise error.RequirementError(
+                        _(".hg/requires file is corrupt"))
+                missingrequirements.append(r)
+        missingrequirements.sort()
+        if missingrequirements:
+            raise error.RequirementError(
+                _("repository requires features unknown to this Mercurial: %s")
+                % " ".join(missingrequirements),
+                hint=_("see https://mercurial-scm.org/wiki/MissingRequirement"
+                       " for more information"))
+
+        self.requirements = requirements
 
         cachepath = self.vfs.join('cache')
         self.sharedpath = self.path



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


More information about the Mercurial-devel mailing list