|
1 # upgrade.py - functions for automatic upgrade of Mercurial repository |
|
2 # |
|
3 # Copyright (c) 2022-present, Pierre-Yves David |
|
4 # |
|
5 # This software may be used and distributed according to the terms of the |
|
6 # GNU General Public License version 2 or any later version. |
|
7 from ..i18n import _ |
|
8 |
|
9 from .. import ( |
|
10 error, |
|
11 requirements as requirementsmod, |
|
12 scmutil, |
|
13 ) |
|
14 |
|
15 |
|
16 def get_share_safe_action(repo): |
|
17 """return an automatic-upgrade action for `share-safe` if applicable |
|
18 |
|
19 If no action is needed, return None, otherwise return a callback to upgrade |
|
20 or downgrade the repository according the configuration and repository |
|
21 format. |
|
22 """ |
|
23 ui = repo.ui |
|
24 requirements = repo.requirements |
|
25 auto_upgrade_share_source = ui.configbool( |
|
26 b'format', |
|
27 b'use-share-safe.automatic-upgrade-of-mismatching-repositories', |
|
28 ) |
|
29 |
|
30 action = None |
|
31 |
|
32 if ( |
|
33 auto_upgrade_share_source |
|
34 and requirementsmod.SHARED_REQUIREMENT not in requirements |
|
35 ): |
|
36 sf_config = ui.configbool(b'format', b'use-share-safe') |
|
37 sf_local = requirementsmod.SHARESAFE_REQUIREMENT in requirements |
|
38 if sf_config and not sf_local: |
|
39 msg = _( |
|
40 b"automatically upgrading repository to the `share-safe`" |
|
41 b" feature\n" |
|
42 ) |
|
43 hint = b"(see `hg help config.format.use-share-safe` for details)\n" |
|
44 |
|
45 def action(): |
|
46 if not ui.quiet: |
|
47 ui.write_err(msg) |
|
48 ui.write_err(hint) |
|
49 requirements.add(requirementsmod.SHARESAFE_REQUIREMENT) |
|
50 scmutil.writereporequirements(repo, requirements) |
|
51 |
|
52 elif sf_local and not sf_config: |
|
53 msg = _( |
|
54 b"automatically downgrading repository from the `share-safe`" |
|
55 b" feature\n" |
|
56 ) |
|
57 hint = b"(see `hg help config.format.use-share-safe` for details)\n" |
|
58 |
|
59 def action(): |
|
60 if not ui.quiet: |
|
61 ui.write_err(msg) |
|
62 ui.write_err(hint) |
|
63 requirements.discard(requirementsmod.SHARESAFE_REQUIREMENT) |
|
64 scmutil.writereporequirements(repo, requirements) |
|
65 |
|
66 return action |
|
67 |
|
68 |
|
69 AUTO_UPGRADE_ACTIONS = [ |
|
70 get_share_safe_action, |
|
71 ] |
|
72 |
|
73 |
|
74 def may_auto_upgrade(repo, maker_func): |
|
75 """potentially perform auto-upgrade and return the final repository to use |
|
76 |
|
77 Auto-upgrade are "quick" repository upgrade that might automatically be run |
|
78 by "any" repository access. See `hg help config.format` for automatic |
|
79 upgrade documentation. |
|
80 |
|
81 note: each relevant upgrades are done one after the other for simplicity. |
|
82 This avoid having repository is partially inconsistent state while |
|
83 upgrading. |
|
84 |
|
85 repo: the current repository instance |
|
86 maker_func: a factory function that can recreate a repository after an upgrade |
|
87 """ |
|
88 clear = False |
|
89 |
|
90 loop = 0 |
|
91 |
|
92 while not clear: |
|
93 loop += 1 |
|
94 if loop > 100: |
|
95 # XXX basic protection against infinite loop, make it better. |
|
96 raise error.ProgrammingError("Too many auto upgrade loops") |
|
97 clear = True |
|
98 for get_action in AUTO_UPGRADE_ACTIONS: |
|
99 action = get_action(repo) |
|
100 if action is not None: |
|
101 clear = False |
|
102 with repo.wlock(wait=False), repo.lock(wait=False): |
|
103 action = get_action(repo) |
|
104 if action is not None: |
|
105 action() |
|
106 repo = maker_func() |
|
107 return repo |