##// END OF EJS Templates
upgrade: move the revlog selection code lower down the chain...
marmoute -
r49273:6e045497 default
parent child Browse files
Show More
@@ -1,356 +1,361 b''
1 1 # upgrade.py - functions for in place upgrade of Mercurial repository
2 2 #
3 3 # Copyright (c) 2016-present, Gregory Szorc
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from . import (
12 12 error,
13 13 hg,
14 14 localrepo,
15 15 lock as lockmod,
16 16 pycompat,
17 17 requirements as requirementsmod,
18 18 scmutil,
19 19 )
20 20
21 21 from .upgrade_utils import (
22 22 actions as upgrade_actions,
23 23 engine as upgrade_engine,
24 24 )
25 25
26 26 from .utils import (
27 27 stringutil,
28 28 )
29 29
30 30 allformatvariant = upgrade_actions.allformatvariant
31 31
32 32
33 33 def upgraderepo(
34 34 ui,
35 35 repo,
36 36 run=False,
37 37 optimize=None,
38 38 backup=True,
39 39 manifest=None,
40 40 changelog=None,
41 41 filelogs=None,
42 42 ):
43 43 """Upgrade a repository in place."""
44 44 if optimize is None:
45 45 optimize = {}
46 46 repo = repo.unfiltered()
47 47
48 revlogs = set(upgrade_engine.UPGRADE_ALL_REVLOGS)
49 48 specentries = (
50 49 (upgrade_engine.UPGRADE_CHANGELOG, changelog),
51 50 (upgrade_engine.UPGRADE_MANIFEST, manifest),
52 51 (upgrade_engine.UPGRADE_FILELOGS, filelogs),
53 52 )
54 specified = [(y, x) for (y, x) in specentries if x is not None]
55 if specified:
56 # we have some limitation on revlogs to be recloned
57 if any(x for y, x in specified):
58 revlogs = set()
59 for upgrade, enabled in specified:
60 if enabled:
61 revlogs.add(upgrade)
62 else:
63 # none are enabled
64 for upgrade, __ in specified:
65 revlogs.discard(upgrade)
66 53
67 54 # Ensure the repository can be upgraded.
68 55 upgrade_actions.check_source_requirements(repo)
69 56
70 57 default_options = localrepo.defaultcreateopts(repo.ui)
71 58 newreqs = localrepo.newreporequirements(repo.ui, default_options)
72 59 newreqs.update(upgrade_actions.preservedrequirements(repo))
73 60
74 61 upgrade_actions.check_requirements_changes(repo, newreqs)
75 62
76 63 # Find and validate all improvements that can be made.
77 64 alloptimizations = upgrade_actions.findoptimizations(repo)
78 65
79 66 # Apply and Validate arguments.
80 67 optimizations = []
81 68 for o in alloptimizations:
82 69 if o.name in optimize:
83 70 optimizations.append(o)
84 71 optimize.discard(o.name)
85 72
86 73 if optimize: # anything left is unknown
87 74 raise error.Abort(
88 75 _(b'unknown optimization action requested: %s')
89 76 % b', '.join(sorted(optimize)),
90 77 hint=_(b'run without arguments to see valid optimizations'),
91 78 )
92 79
93 80 format_upgrades = upgrade_actions.find_format_upgrades(repo)
94 81 up_actions = upgrade_actions.determine_upgrade_actions(
95 82 repo, format_upgrades, optimizations, repo.requirements, newreqs
96 83 )
97 84 removed_actions = upgrade_actions.find_format_downgrades(repo)
98 85
99 86 removedreqs = repo.requirements - newreqs
100 87 addedreqs = newreqs - repo.requirements
101 88
89 # check if we need to touch revlog and if so, which ones
90
91 revlogs = set(upgrade_engine.UPGRADE_ALL_REVLOGS)
92 specified = [(y, x) for (y, x) in specentries if x is not None]
93 if specified:
94 # we have some limitation on revlogs to be recloned
95 if any(x for y, x in specified):
96 revlogs = set()
97 for upgrade, enabled in specified:
98 if enabled:
99 revlogs.add(upgrade)
100 else:
101 # none are enabled
102 for upgrade, __ in specified:
103 revlogs.discard(upgrade)
104
105 # check the consistency of the revlog selection with the planned action
106
102 107 if revlogs != upgrade_engine.UPGRADE_ALL_REVLOGS:
103 108 incompatible = upgrade_actions.RECLONES_REQUIREMENTS & (
104 109 removedreqs | addedreqs
105 110 )
106 111 if incompatible:
107 112 msg = _(
108 113 b'ignoring revlogs selection flags, format requirements '
109 114 b'change: %s\n'
110 115 )
111 116 ui.warn(msg % b', '.join(sorted(incompatible)))
112 117 revlogs = upgrade_engine.UPGRADE_ALL_REVLOGS
113 118
114 119 upgrade_op = upgrade_actions.UpgradeOperation(
115 120 ui,
116 121 newreqs,
117 122 repo.requirements,
118 123 up_actions,
119 124 removed_actions,
120 125 revlogs,
121 126 backup,
122 127 )
123 128
124 129 if not run:
125 130 fromconfig = []
126 131 onlydefault = []
127 132
128 133 for d in format_upgrades:
129 134 if d.fromconfig(repo):
130 135 fromconfig.append(d)
131 136 elif d.default:
132 137 onlydefault.append(d)
133 138
134 139 if fromconfig or onlydefault:
135 140
136 141 if fromconfig:
137 142 ui.status(
138 143 _(
139 144 b'repository lacks features recommended by '
140 145 b'current config options:\n\n'
141 146 )
142 147 )
143 148 for i in fromconfig:
144 149 ui.status(b'%s\n %s\n\n' % (i.name, i.description))
145 150
146 151 if onlydefault:
147 152 ui.status(
148 153 _(
149 154 b'repository lacks features used by the default '
150 155 b'config options:\n\n'
151 156 )
152 157 )
153 158 for i in onlydefault:
154 159 ui.status(b'%s\n %s\n\n' % (i.name, i.description))
155 160
156 161 ui.status(b'\n')
157 162 else:
158 163 ui.status(_(b'(no format upgrades found in existing repository)\n'))
159 164
160 165 ui.status(
161 166 _(
162 167 b'performing an upgrade with "--run" will make the following '
163 168 b'changes:\n\n'
164 169 )
165 170 )
166 171
167 172 upgrade_op.print_requirements()
168 173 upgrade_op.print_optimisations()
169 174 upgrade_op.print_upgrade_actions()
170 175 upgrade_op.print_affected_revlogs()
171 176
172 177 if upgrade_op.unused_optimizations:
173 178 ui.status(
174 179 _(
175 180 b'additional optimizations are available by specifying '
176 181 b'"--optimize <name>":\n\n'
177 182 )
178 183 )
179 184 upgrade_op.print_unused_optimizations()
180 185 return
181 186
182 187 if not (upgrade_op.upgrade_actions or upgrade_op.removed_actions):
183 188 ui.status(_(b'nothing to do\n'))
184 189 return
185 190 # Else we're in the run=true case.
186 191 ui.write(_(b'upgrade will perform the following actions:\n\n'))
187 192 upgrade_op.print_requirements()
188 193 upgrade_op.print_optimisations()
189 194 upgrade_op.print_upgrade_actions()
190 195 upgrade_op.print_affected_revlogs()
191 196
192 197 ui.status(_(b'beginning upgrade...\n'))
193 198 with repo.wlock(), repo.lock():
194 199 ui.status(_(b'repository locked and read-only\n'))
195 200 # Our strategy for upgrading the repository is to create a new,
196 201 # temporary repository, write data to it, then do a swap of the
197 202 # data. There are less heavyweight ways to do this, but it is easier
198 203 # to create a new repo object than to instantiate all the components
199 204 # (like the store) separately.
200 205 tmppath = pycompat.mkdtemp(prefix=b'upgrade.', dir=repo.path)
201 206 backuppath = None
202 207 try:
203 208 ui.status(
204 209 _(
205 210 b'creating temporary repository to stage upgraded '
206 211 b'data: %s\n'
207 212 )
208 213 % tmppath
209 214 )
210 215
211 216 # clone ui without using ui.copy because repo.ui is protected
212 217 repoui = repo.ui.__class__(repo.ui)
213 218 dstrepo = hg.repository(repoui, path=tmppath, create=True)
214 219
215 220 with dstrepo.wlock(), dstrepo.lock():
216 221 backuppath = upgrade_engine.upgrade(
217 222 ui, repo, dstrepo, upgrade_op
218 223 )
219 224
220 225 finally:
221 226 ui.status(_(b'removing temporary repository %s\n') % tmppath)
222 227 repo.vfs.rmtree(tmppath, forcibly=True)
223 228
224 229 if backuppath and not ui.quiet:
225 230 ui.warn(
226 231 _(b'copy of old repository backed up at %s\n') % backuppath
227 232 )
228 233 ui.warn(
229 234 _(
230 235 b'the old repository will not be deleted; remove '
231 236 b'it to free up disk space once the upgraded '
232 237 b'repository is verified\n'
233 238 )
234 239 )
235 240
236 241 upgrade_op.print_post_op_messages()
237 242
238 243
239 244 def upgrade_share_to_safe(
240 245 ui,
241 246 hgvfs,
242 247 storevfs,
243 248 current_requirements,
244 249 mismatch_config,
245 250 mismatch_warn,
246 251 ):
247 252 """Upgrades a share to use share-safe mechanism"""
248 253 wlock = None
249 254 store_requirements = localrepo._readrequires(storevfs, False)
250 255 original_crequirements = current_requirements.copy()
251 256 # after upgrade, store requires will be shared, so lets find
252 257 # the requirements which are not present in store and
253 258 # write them to share's .hg/requires
254 259 diffrequires = current_requirements - store_requirements
255 260 # add share-safe requirement as it will mark the share as share-safe
256 261 diffrequires.add(requirementsmod.SHARESAFE_REQUIREMENT)
257 262 current_requirements.add(requirementsmod.SHARESAFE_REQUIREMENT)
258 263 # in `allow` case, we don't try to upgrade, we just respect the source
259 264 # state, update requirements and continue
260 265 if mismatch_config == b'allow':
261 266 return
262 267 try:
263 268 wlock = lockmod.trylock(ui, hgvfs, b'wlock', 0, 0)
264 269 # some process might change the requirement in between, re-read
265 270 # and update current_requirements
266 271 locked_requirements = localrepo._readrequires(hgvfs, True)
267 272 if locked_requirements != original_crequirements:
268 273 removed = current_requirements - locked_requirements
269 274 # update current_requirements in place because it's passed
270 275 # as reference
271 276 current_requirements -= removed
272 277 current_requirements |= locked_requirements
273 278 diffrequires = current_requirements - store_requirements
274 279 # add share-safe requirement as it will mark the share as share-safe
275 280 diffrequires.add(requirementsmod.SHARESAFE_REQUIREMENT)
276 281 current_requirements.add(requirementsmod.SHARESAFE_REQUIREMENT)
277 282 scmutil.writerequires(hgvfs, diffrequires)
278 283 ui.warn(_(b'repository upgraded to use share-safe mode\n'))
279 284 except error.LockError as e:
280 285 hint = _(
281 286 "see `hg help config.format.use-share-safe` for more information"
282 287 )
283 288 if mismatch_config == b'upgrade-abort':
284 289 raise error.Abort(
285 290 _(b'failed to upgrade share, got error: %s')
286 291 % stringutil.forcebytestr(e.strerror),
287 292 hint=hint,
288 293 )
289 294 elif mismatch_warn:
290 295 ui.warn(
291 296 _(b'failed to upgrade share, got error: %s\n')
292 297 % stringutil.forcebytestr(e.strerror),
293 298 hint=hint,
294 299 )
295 300 finally:
296 301 if wlock:
297 302 wlock.release()
298 303
299 304
300 305 def downgrade_share_to_non_safe(
301 306 ui,
302 307 hgvfs,
303 308 sharedvfs,
304 309 current_requirements,
305 310 mismatch_config,
306 311 mismatch_warn,
307 312 ):
308 313 """Downgrades a share which use share-safe to not use it"""
309 314 wlock = None
310 315 source_requirements = localrepo._readrequires(sharedvfs, True)
311 316 original_crequirements = current_requirements.copy()
312 317 # we cannot be 100% sure on which requirements were present in store when
313 318 # the source supported share-safe. However, we do know that working
314 319 # directory requirements were not there. Hence we remove them
315 320 source_requirements -= requirementsmod.WORKING_DIR_REQUIREMENTS
316 321 current_requirements |= source_requirements
317 322 current_requirements.remove(requirementsmod.SHARESAFE_REQUIREMENT)
318 323 if mismatch_config == b'allow':
319 324 return
320 325
321 326 try:
322 327 wlock = lockmod.trylock(ui, hgvfs, b'wlock', 0, 0)
323 328 # some process might change the requirement in between, re-read
324 329 # and update current_requirements
325 330 locked_requirements = localrepo._readrequires(hgvfs, True)
326 331 if locked_requirements != original_crequirements:
327 332 removed = current_requirements - locked_requirements
328 333 # update current_requirements in place because it's passed
329 334 # as reference
330 335 current_requirements -= removed
331 336 current_requirements |= locked_requirements
332 337 current_requirements |= source_requirements
333 338 current_requirements -= set(requirementsmod.SHARESAFE_REQUIREMENT)
334 339 scmutil.writerequires(hgvfs, current_requirements)
335 340 ui.warn(_(b'repository downgraded to not use share-safe mode\n'))
336 341 except error.LockError as e:
337 342 hint = _(
338 343 "see `hg help config.format.use-share-safe` for more information"
339 344 )
340 345 # If upgrade-abort is set, abort when upgrade fails, else let the
341 346 # process continue as `upgrade-allow` is set
342 347 if mismatch_config == b'downgrade-abort':
343 348 raise error.Abort(
344 349 _(b'failed to downgrade share, got error: %s')
345 350 % stringutil.forcebytestr(e.strerror),
346 351 hint=hint,
347 352 )
348 353 elif mismatch_warn:
349 354 ui.warn(
350 355 _(b'failed to downgrade share, got error: %s\n')
351 356 % stringutil.forcebytestr(e.strerror),
352 357 hint=hint,
353 358 )
354 359 finally:
355 360 if wlock:
356 361 wlock.release()
General Comments 0
You need to be logged in to leave comments. Login now