Mercurial > public > mercurial-scm > hg
diff mercurial/upgrade_utils/auto_upgrade.py @ 49192:2ab79873786e
auto-upgrade: introduce a way to auto-upgrade to/from share-safe
This is the first "automatic-upgrade" capability. In the following commits,
similar features are coming for other "fast to upgrade" formats.
This is different from the `safe-mismatch.source-not-safe` and
`safe-mismatch.source-safe` configuration that deal with mismatch between a
share and its share-source. Here we are dealing with mismatch between a
repository configuration and its actual format.
We will need further work for cases were the repository cannot be locked. A
basic protection is in place to avoid a infinite loop for now, but it will get
proper attention in a later changeset.
Differential Revision: https://phab.mercurial-scm.org/D12611
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Tue, 05 Apr 2022 05:19:47 +0200 |
parents | |
children | e4b31016e194 |
line wrap: on
line diff
--- /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