mercurial/upgrade_utils/auto_upgrade.py
changeset 49192 2ab79873786e
child 49194 e4b31016e194
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/upgrade_utils/auto_upgrade.py	Tue Apr 05 05:19:47 2022 +0200
@@ -0,0 +1,107 @@
+# upgrade.py - functions for automatic upgrade of Mercurial repository
+#
+# Copyright (c) 2022-present, Pierre-Yves David
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+from ..i18n import _
+
+from .. import (
+    error,
+    requirements as requirementsmod,
+    scmutil,
+)
+
+
+def get_share_safe_action(repo):
+    """return an automatic-upgrade action for `share-safe` if applicable
+
+    If no action is needed, return None, otherwise return a callback to upgrade
+    or downgrade the repository according the configuration and repository
+    format.
+    """
+    ui = repo.ui
+    requirements = repo.requirements
+    auto_upgrade_share_source = ui.configbool(
+        b'format',
+        b'use-share-safe.automatic-upgrade-of-mismatching-repositories',
+    )
+
+    action = None
+
+    if (
+        auto_upgrade_share_source
+        and requirementsmod.SHARED_REQUIREMENT not in requirements
+    ):
+        sf_config = ui.configbool(b'format', b'use-share-safe')
+        sf_local = requirementsmod.SHARESAFE_REQUIREMENT in requirements
+        if sf_config and not sf_local:
+            msg = _(
+                b"automatically upgrading repository to the `share-safe`"
+                b" feature\n"
+            )
+            hint = b"(see `hg help config.format.use-share-safe` for details)\n"
+
+            def action():
+                if not ui.quiet:
+                    ui.write_err(msg)
+                    ui.write_err(hint)
+                requirements.add(requirementsmod.SHARESAFE_REQUIREMENT)
+                scmutil.writereporequirements(repo, requirements)
+
+        elif sf_local and not sf_config:
+            msg = _(
+                b"automatically downgrading repository from the `share-safe`"
+                b" feature\n"
+            )
+            hint = b"(see `hg help config.format.use-share-safe` for details)\n"
+
+            def action():
+                if not ui.quiet:
+                    ui.write_err(msg)
+                    ui.write_err(hint)
+                requirements.discard(requirementsmod.SHARESAFE_REQUIREMENT)
+                scmutil.writereporequirements(repo, requirements)
+
+    return action
+
+
+AUTO_UPGRADE_ACTIONS = [
+    get_share_safe_action,
+]
+
+
+def may_auto_upgrade(repo, maker_func):
+    """potentially perform auto-upgrade and return the final repository to use
+
+    Auto-upgrade are "quick" repository upgrade that might automatically be run
+    by "any" repository access. See `hg help config.format` for automatic
+    upgrade documentation.
+
+    note: each relevant upgrades are done one after the other for simplicity.
+    This avoid having repository is partially inconsistent state while
+    upgrading.
+
+    repo: the current repository instance
+    maker_func: a factory function that can recreate a repository after an upgrade
+    """
+    clear = False
+
+    loop = 0
+
+    while not clear:
+        loop += 1
+        if loop > 100:
+            # XXX basic protection against infinite loop, make it better.
+            raise error.ProgrammingError("Too many auto upgrade loops")
+        clear = True
+        for get_action in AUTO_UPGRADE_ACTIONS:
+            action = get_action(repo)
+            if action is not None:
+                clear = False
+                with repo.wlock(wait=False), repo.lock(wait=False):
+                    action = get_action(repo)
+                    if action is not None:
+                        action()
+                    repo = maker_func()
+    return repo