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