[PATCH 1 of 5 requirements-tidy] localrepo: add requirements helper functions

Gregory Szorc gregory.szorc at gmail.com
Thu Oct 1 19:29:55 UTC 2015


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1443725945 25200
#      Thu Oct 01 11:59:05 2015 -0700
# Node ID a6ba4ec0ac210f86459ae7da0a8843d6132a0d12
# Parent  97dc6ab42aad232c73180dee648685c26662230b
localrepo: add requirements helper functions

Currently, various consumers of requirements call "private" functions on
localrepository to update the requirements set. This breaks an API
contract. Furthermore, consumers are inconsistent in their handling of
requirements updating, forgetting to call _applyopenerreqs().

This patch adds new APIs for updating a repository's requirements.

Yes, it adds 3 functions to localrepository. However, subsequent work
will offset this. Also, given the importance of requirements, I think
having an appropriate API point for performing requirements
manipulation is warranted.

This work started because I was moving streaming clone code out of
localrepo.py so it could be better integrated into bundle2 and it was
performing low-level requirements manipulation that I didn't think was
appropriate for a caller outside of localrepo.py.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -339,8 +339,58 @@ class localrepository(object):
             capsblob = bundle2.encodecaps(bundle2.getrepocaps(self))
             caps.add('bundle2=' + urllib.quote(capsblob))
         return caps
 
+    def _replacerequirements(self, requirements, frominit=False):
+        """Replace the requirements for this repository.
+
+        Requirements are strings that define:
+
+        1) features required to open the repository
+        2) what capabilities the repository is using [that may impact reading
+           from it]
+
+        Requirements are used to ensure a Mercurial client is able to properly
+        interface with a repository. They prevent a client from attempting to
+        read from a repository that is stored in a potentially incompatible
+        format. They also prevent new clients from writing data to repositories
+        in a manner that isn't compatible with older clients.
+
+        This function should only be called internally or at repository
+        creation time. Extension code should almost certainly use
+        ``addrequirement()`` instead.
+        """
+        assert isinstance(requirements, set)
+        if requirements == self.requirements:
+            return
+        self.requirements = requirements
+        self._applyopenerreqs()
+        if not frominit:
+            self._writerequirements()
+
+    def addrequirement(self, requirement):
+        """Add a new requirement to the repository.
+
+        This is the preferred mechanism for extensions and most code
+        to update a repository's requirements.
+        """
+        if requirement in self.requirements:
+            return
+        self._replacerequirements(self.requirements | set([requirement]))
+
+    def removerequirement(self, requirement):
+        """Remove a requirement from a repository.
+
+        This is the preferred mechanism for extensions and most code to remove
+        a requirement from a repository.
+
+        Removing requirements is rare and has implications for compatibility
+        with other clients. Use with caution!
+        """
+        if requirement not in self.requirements:
+            return
+        self._replacerequirements(self.requirements - set([requirement]))
+
     def _applyopenerreqs(self):
         self.svfs.options = dict((r, 1) for r in self.requirements
                                            if r in self.openerreqs)
         # experimental config: format.chunkcachesize


More information about the Mercurial-devel mailing list