##// END OF EJS Templates
formatting: blacken the codebase...
formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971

File last commit:

r43346:2372284d default
r43346:2372284d default
Show More
upgrade.py
1333 lines | 40.9 KiB | text/x-python | PythonLexer
Pierre-Yves David
upgrade: update the header comment
r31894 # upgrade.py - functions for in place upgrade of Mercurial repository
Pierre-Yves David
upgrade: extract code in its own module...
r31864 #
Pierre-Yves David
upgrade: update the copyright statement
r31895 # Copyright (c) 2016-present, Gregory Szorc
Pierre-Yves David
upgrade: extract code in its own module...
r31864 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import stat
from .i18n import _
from . import (
changelog,
error,
Boris Feld
upgrade: use actual filelog to convert filelog...
r35345 filelog,
Boris Feld
upgrade: more standard creation of the temporary repository...
r35344 hg,
Pierre-Yves David
upgrade: import 'localrepo' globally...
r31893 localrepo,
Pierre-Yves David
upgrade: extract code in its own module...
r31864 manifest,
Yuya Nishihara
py3: wrap tempfile.mkdtemp() to use bytes path...
r38183 pycompat,
Pierre-Yves David
upgrade: extract code in its own module...
r31864 revlog,
scmutil,
util,
vfs as vfsmod,
)
Augie Fackler
formatting: blacken the codebase...
r43346 from .utils import compression
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306
upgrade: make sure we reclone all revlogs when updating to some format...
r43100 # list of requirements that request a clone of all revlog if added/removed
RECLONES_REQUIREMENTS = {
'generaldelta',
localrepo.SPARSEREVLOG_REQUIREMENT,
}
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the 'requiredsourcerequirements' function...
r31865 def requiredsourcerequirements(repo):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Obtain requirements required to be present to upgrade a repo.
An upgrade will not be allowed if the repository doesn't have the
requirements returned by this function.
"""
Martin von Zweigbergk
cleanup: use set literals...
r32291 return {
Pierre-Yves David
upgrade: extract code in its own module...
r31864 # Introduced in Mercurial 0.9.2.
'revlogv1',
# Introduced in Mercurial 0.9.2.
'store',
Martin von Zweigbergk
cleanup: use set literals...
r32291 }
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the 'blocksourcerequirements' function...
r31866 def blocksourcerequirements(repo):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Obtain requirements that will prevent an upgrade from occurring.
An upgrade cannot be performed if the source repository contains a
requirements in the returned set.
"""
Martin von Zweigbergk
cleanup: use set literals...
r32291 return {
Pierre-Yves David
upgrade: extract code in its own module...
r31864 # The upgrade code does not yet support these experimental features.
# This is an artificial limitation.
'treemanifest',
# This was a precursor to generaldelta and was never enabled by default.
# It should (hopefully) not exist in the wild.
'parentdelta',
# Upgrade should operate on the actual store, not the shared link.
'shared',
Martin von Zweigbergk
cleanup: use set literals...
r32291 }
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the 'supportremovedrequirements' function...
r31867 def supportremovedrequirements(repo):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Obtain requirements that can be removed during an upgrade.
If an upgrade were to create a repository that dropped a requirement,
the dropped requirement must appear in the returned set for the upgrade
to be allowed.
"""
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306 supported = {
Paul Morelle
upgrade: enable adding or removing sparse-revlog requirement
r38742 localrepo.SPARSEREVLOG_REQUIREMENT,
}
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306 for name in compression.compengines:
engine = compression.compengines[name]
if engine.available() and engine.revlogheader():
supported.add(b'exp-compression-%s' % name)
if engine.name() == 'zstd':
supported.add(b'revlog-compression-zstd')
return supported
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the 'supporteddestrequirements' function...
r31870 def supporteddestrequirements(repo):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Obtain requirements that upgrade supports in the destination.
If the result of the upgrade would create requirements not in this set,
the upgrade is disallowed.
Extensions should monkeypatch this to add their custom requirements.
"""
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306 supported = {
Pierre-Yves David
upgrade: extract code in its own module...
r31864 'dotencode',
'fncache',
'generaldelta',
'revlogv1',
'store',
Paul Morelle
upgrade: enable adding or removing sparse-revlog requirement
r38742 localrepo.SPARSEREVLOG_REQUIREMENT,
Martin von Zweigbergk
cleanup: use set literals...
r32291 }
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306 for name in compression.compengines:
engine = compression.compengines[name]
if engine.available() and engine.revlogheader():
supported.add(b'exp-compression-%s' % name)
if engine.name() == 'zstd':
supported.add(b'revlog-compression-zstd')
return supported
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the 'allowednewrequirements' function...
r31869 def allowednewrequirements(repo):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Obtain requirements that can be added to a repository during upgrade.
This is used to disallow proposed requirements from being added when
they weren't present before.
We use a list of allowed requirement additions instead of a list of known
bad additions because the whitelist approach is safer and will prevent
future, unknown requirements from accidentally being added.
"""
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306 supported = {
Pierre-Yves David
upgrade: extract code in its own module...
r31864 'dotencode',
'fncache',
'generaldelta',
Paul Morelle
upgrade: enable adding or removing sparse-revlog requirement
r38742 localrepo.SPARSEREVLOG_REQUIREMENT,
Martin von Zweigbergk
cleanup: use set literals...
r32291 }
upgrade: support upgrade to/from zstd storage (issue6088)...
r42306 for name in compression.compengines:
engine = compression.compengines[name]
if engine.available() and engine.revlogheader():
supported.add(b'exp-compression-%s' % name)
if engine.name() == 'zstd':
supported.add(b'revlog-compression-zstd')
return supported
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
upgraderepo: allow extension to register preserved requirements...
r35303 def preservedrequirements(repo):
return set()
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: extract code in its own module...
r31864 deficiency = 'deficiency'
optimisation = 'optimization'
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the 'improvement' class...
r31868 class improvement(object):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Represents an improvement that can be made as part of an upgrade.
The following attributes are defined on each instance:
name
Machine-readable string uniquely identifying this improvement. It
will be mapped to an action later in the upgrade process.
type
Either ``deficiency`` or ``optimisation``. A deficiency is an obvious
problem. An optimization is an action (sometimes optional) that
can be taken to further improve the state of the repository.
description
Message intended for humans explaining the improvement in more detail,
including the implications of it. For ``deficiency`` types, should be
worded in the present tense. For ``optimisation`` types, should be
worded in the future tense.
upgrademessage
Message intended for humans explaining what an upgrade addressing this
issue will do. Should be worded in the future tense.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030 def __init__(self, name, type, description, upgrademessage):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 self.name = name
self.type = type
self.description = description
self.upgrademessage = upgrademessage
Pierre-Yves David
upgrade: implement equality for 'improvement' object...
r31902 def __eq__(self, other):
if not isinstance(other, improvement):
# This is what python tell use to do
return NotImplemented
return self.name == other.name
Pierre-Yves David
upgrade: implement '__ne__' on 'improvement' class...
r32028 def __ne__(self, other):
Benjamin Peterson
upgrade: correct implementation of improvement.__ne__...
r41033 return not (self == other)
Pierre-Yves David
upgrade: implement '__ne__' on 'improvement' class...
r32028
Pierre-Yves David
upgrade: implement '__hash__' on 'improvement' class...
r32029 def __hash__(self):
return hash(self.name)
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 allformatvariant = []
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 def registerformatvariant(cls):
allformatvariant.append(cls)
return cls
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030 class formatvariant(improvement):
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 """an improvement subclass dedicated to repository format"""
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 type = deficiency
### The following attributes should be defined for each class:
# machine-readable string uniquely identifying this improvement. it will be
# mapped to an action later in the upgrade process.
name = None
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 # message intended for humans explaining the improvement in more detail,
# including the implications of it ``deficiency`` types, should be worded
# in the present tense.
description = None
# message intended for humans explaining what an upgrade addressing this
# issue will do. should be worded in the future tense.
upgrademessage = None
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 # value of current Mercurial default for new repository
default = None
def __init__(self):
raise NotImplementedError()
@staticmethod
def fromrepo(repo):
"""current value of the variant in the repository"""
raise NotImplementedError()
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 @staticmethod
def fromconfig(repo):
"""current value of the variant in the configuration"""
raise NotImplementedError()
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 class requirementformatvariant(formatvariant):
"""formatvariant based on a 'requirement' name.
Many format variant are controlled by a 'requirement'. We define a small
subclass to factor the code.
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030 """
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 # the requirement that control this format variant
_requirement = None
@staticmethod
Gregory Szorc
localrepo: pass ui to newreporequirements() (API)...
r39583 def _newreporequirements(ui):
Gregory Szorc
localrepo: define storage backend in creation options (API)...
r40032 return localrepo.newreporequirements(
Augie Fackler
formatting: blacken the codebase...
r43346 ui, localrepo.defaultcreateopts(ui)
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
@classmethod
def fromrepo(cls, repo):
assert cls._requirement is not None
return cls._requirement in repo.requirements
@classmethod
def fromconfig(cls, repo):
assert cls._requirement is not None
Gregory Szorc
localrepo: pass ui to newreporequirements() (API)...
r39583 return cls._requirement in cls._newreporequirements(repo.ui)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 @registerformatvariant
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 class fncache(requirementformatvariant):
name = 'fncache'
_requirement = 'fncache'
default = True
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'long and reserved filenames may not work correctly; '
'repository performance is sub-optimal'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Augie Fackler
formatting: blacken the codebase...
r43346 upgrademessage = _(
'repository will be more resilient to storing '
'certain paths and performance of certain '
'operations should be improved'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 @registerformatvariant
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 class dotencode(requirementformatvariant):
name = 'dotencode'
_requirement = 'dotencode'
default = True
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'storage of filenames beginning with a period or '
'space may not work correctly'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Augie Fackler
formatting: blacken the codebase...
r43346 upgrademessage = _(
'repository will be better able to store files '
'beginning with a space or period'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 @registerformatvariant
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 class generaldelta(requirementformatvariant):
name = 'generaldelta'
_requirement = 'generaldelta'
default = True
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'deltas within internal storage are unable to '
'choose optimal revisions; repository is larger and '
'slower than it could be; interaction with other '
'repositories may require extra network and CPU '
'resources, making "hg push" and "hg pull" slower'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Augie Fackler
formatting: blacken the codebase...
r43346 upgrademessage = _(
'repository storage will be able to create '
'optimal deltas; new repository data will be '
'smaller and read times should decrease; '
'interacting with other repositories using this '
'storage model should require less network and '
'CPU resources, making "hg push" and "hg pull" '
'faster'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 @registerformatvariant
Paul Morelle
upgrade: add information about sparse-revlog...
r38741 class sparserevlog(requirementformatvariant):
name = 'sparserevlog'
_requirement = localrepo.SPARSEREVLOG_REQUIREMENT
Boris Feld
sparse-revlog: enabled by default...
r40954 default = True
Paul Morelle
upgrade: add information about sparse-revlog...
r38741
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'in order to limit disk reading and memory usage on older '
'version, the span of a delta chain from its root to its '
'end is limited, whatever the relevant data in this span. '
'This can severly limit Mercurial ability to build good '
'chain of delta resulting is much more storage space being '
'taken and limit reusability of on disk delta during '
'exchange.'
)
Paul Morelle
upgrade: add information about sparse-revlog...
r38741
Augie Fackler
formatting: blacken the codebase...
r43346 upgrademessage = _(
'Revlog supports delta chain with more unused data '
'between payload. These gaps will be skipped at read '
'time. This allows for better delta chains, making a '
'better compression and faster exchange with server.'
)
Paul Morelle
upgrade: add information about sparse-revlog...
r38741
@registerformatvariant
upgrade: detect the side-data format variants...
r43299 class sidedata(requirementformatvariant):
name = 'sidedata'
_requirement = localrepo.SIDEDATA_REQUIREMENT
default = False
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'Allows storage of extra data alongside a revision, '
'unlocking various caching options.'
)
upgrade: detect the side-data format variants...
r43299
upgrademessage = _('Allows storage of extra data alongside a revision.')
Augie Fackler
formatting: blacken the codebase...
r43346
upgrade: detect the side-data format variants...
r43299 @registerformatvariant
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 class removecldeltachain(formatvariant):
Boris Feld
upgrade: rename 'removecldeltachain' to 'plain-cl-delta'...
r35336 name = 'plain-cl-delta'
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
default = True
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'changelog storage is using deltas instead of '
'raw entries; changelog reading and any '
'operation relying on changelog data are slower '
'than they could be'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
Augie Fackler
formatting: blacken the codebase...
r43346 upgrademessage = _(
'changelog storage will be reformated to '
'store raw entries; changelog reading will be '
'faster; changelog size may be reduced'
)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031
@staticmethod
def fromrepo(repo):
# Mercurial 4.0 changed changelogs to not use delta chains. Search for
# changelogs with deltas.
cl = repo.changelog
chainbase = cl.chainbase
return all(rev == chainbase(rev) for rev in cl)
@staticmethod
def fromconfig(repo):
return True
Pierre-Yves David
upgrade: introduce a 'formatvariant' class...
r32030
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
upgrade: register compression as a format variants...
r35341 @registerformatvariant
class compressionengine(formatvariant):
name = 'compression'
default = 'zlib'
Augie Fackler
formatting: blacken the codebase...
r43346 description = _(
'Compresion algorithm used to compress data. '
'Some engine are faster than other'
)
Boris Feld
upgrade: register compression as a format variants...
r35341
Augie Fackler
formatting: blacken the codebase...
r43346 upgrademessage = _(
'revlog content will be recompressed with the new ' 'algorithm.'
)
Boris Feld
upgrade: register compression as a format variants...
r35341
@classmethod
def fromrepo(cls, repo):
compression: introduce an official `zstd-revlog` requirement...
r42305 # we allow multiple compression engine requirement to co-exist because
# strickly speaking, revlog seems to support mixed compression style.
#
# The compression used for new entries will be "the last one"
compression = 'zlib'
Boris Feld
upgrade: register compression as a format variants...
r35341 for req in repo.requirements:
compression: introduce an official `zstd-revlog` requirement...
r42305 prefix = req.startswith
if prefix('revlog-compression-') or prefix('exp-compression-'):
compression = req.split('-', 2)[2]
return compression
Boris Feld
upgrade: register compression as a format variants...
r35341
@classmethod
def fromconfig(cls, repo):
compression: introduce an official `format.revlog-compression` option...
r42213 return repo.ui.config('format', 'revlog-compression')
Boris Feld
upgrade: register compression as a format variants...
r35341
Augie Fackler
formatting: blacken the codebase...
r43346
compression: display compression level in debugformat...
r42212 @registerformatvariant
class compressionlevel(formatvariant):
name = 'compression-level'
default = 'default'
description = _('compression level')
upgrademessage = _('revlog content will be recompressed')
@classmethod
def fromrepo(cls, repo):
comp = compressionengine.fromrepo(repo)
level = None
if comp == 'zlib':
level = repo.ui.configint('storage', 'revlog.zlib.level')
elif comp == 'zstd':
level = repo.ui.configint('storage', 'revlog.zstd.level')
if level is None:
return 'default'
return bytes(level)
@classmethod
def fromconfig(cls, repo):
comp = compressionengine.fromconfig(repo)
level = None
if comp == 'zlib':
level = repo.ui.configint('storage', 'revlog.zlib.level')
elif comp == 'zstd':
level = repo.ui.configint('storage', 'revlog.zstd.level')
if level is None:
return 'default'
return bytes(level)
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: split finding deficiencies from finding optimisations...
r31896 def finddeficiencies(repo):
"""returns a list of deficiencies that the repo suffer from"""
deficiencies = []
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# We could detect lack of revlogv1 and store here, but they were added
# in 0.9.2 and we don't support upgrading repos without these
# requirements, so let's not bother.
Pierre-Yves David
upgrade: register all format variants in a list...
r32032 for fv in allformatvariant:
if not fv.fromrepo(repo):
deficiencies.append(fv)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: split finding deficiencies from finding optimisations...
r31896 return deficiencies
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
upgrade: add '-' in optimization name...
r41120 # search without '-' to support older form on newer client.
#
# We don't enforce backward compatibility for debug command so this
# might eventually be dropped. However, having to use two different
# forms in script when comparing result is anoying enough to add
# backward compatibility for a while.
legacy_opts_map = {
'redeltaparent': 're-delta-parent',
'redeltamultibase': 're-delta-multibase',
'redeltaall': 're-delta-all',
'redeltafulladd': 're-delta-fulladd',
}
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: split finding deficiencies from finding optimisations...
r31896 def findoptimizations(repo):
"""Determine optimisation that could be used during upgrade"""
Pierre-Yves David
upgrade: extract code in its own module...
r31864 # These are unconditionally added. There is logic later that figures out
# which ones to apply.
Pierre-Yves David
upgrade: split finding deficiencies from finding optimisations...
r31896 optimizations = []
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 optimizations.append(
improvement(
name='re-delta-parent',
type=optimisation,
description=_(
'deltas within internal storage will be recalculated to '
'choose an optimal base revision where this was not '
'already done; the size of the repository may shrink and '
'various operations may become faster; the first time '
'this optimization is performed could slow down upgrade '
'execution considerably; subsequent invocations should '
'not run noticeably slower'
),
upgrademessage=_(
'deltas within internal storage will choose a new '
'base revision if needed'
),
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 optimizations.append(
improvement(
name='re-delta-multibase',
type=optimisation,
description=_(
'deltas within internal storage will be recalculated '
'against multiple base revision and the smallest '
'difference will be used; the size of the repository may '
'shrink significantly when there are many merges; this '
'optimization will slow down execution in proportion to '
'the number of merges in the repository and the amount '
'of files in the repository; this slow down should not '
'be significant unless there are tens of thousands of '
'files and thousands of merges'
),
upgrademessage=_(
'deltas within internal storage will choose an '
'optimal delta by computing deltas against multiple '
'parents; may slow down execution time '
'significantly'
),
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 optimizations.append(
improvement(
name='re-delta-all',
type=optimisation,
description=_(
'deltas within internal storage will always be '
'recalculated without reusing prior deltas; this will '
'likely make execution run several times slower; this '
'optimization is typically not needed'
),
upgrademessage=_(
'deltas within internal storage will be fully '
'recomputed; this will likely drastically slow down '
'execution time'
),
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 optimizations.append(
improvement(
name='re-delta-fulladd',
type=optimisation,
description=_(
'every revision will be re-added as if it was new '
'content. It will go through the full storage '
'mechanism giving extensions a chance to process it '
'(eg. lfs). This is similar to "re-delta-all" but even '
'slower since more logic is involved.'
),
upgrademessage=_(
'each revision will be added as new content to the '
'internal storage; this will likely drastically slow '
'down execution time, but some extensions might need '
'it'
),
)
)
Boris Feld
upgrade: add a 'redeltafullall' mode...
r35346
Pierre-Yves David
upgrade: split finding deficiencies from finding optimisations...
r31896 return optimizations
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: simplify 'determineactions'...
r31900 def determineactions(repo, deficiencies, sourcereqs, destreqs):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Determine upgrade actions that will be performed.
Pierre-Yves David
upgrade: split finding deficiencies from finding optimisations...
r31896 Given a list of improvements as returned by ``finddeficiencies`` and
``findoptimizations``, determine the list of upgrade actions that
will be performed.
Pierre-Yves David
upgrade: extract code in its own module...
r31864
The role of this function is to filter improvements if needed, apply
recommended optimizations from the improvements list that make sense,
etc.
Returns a list of action names.
"""
newactions = []
Pierre-Yves David
upgrade: drop the prefix to the 'supporteddestrequirements' function...
r31870 knownreqs = supporteddestrequirements(repo)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: simplify 'determineactions'...
r31900 for d in deficiencies:
name = d.name
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# If the action is a requirement that doesn't show up in the
# destination requirements, prune the action.
if name in knownreqs and name not in destreqs:
continue
Pierre-Yves David
upgrade: use 'improvement' object for action too...
r31903 newactions.append(d)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# FUTURE consider adding some optimizations here for certain transitions.
# e.g. adding generaldelta could schedule parent redeltas.
return newactions
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: extract code in its own module...
r31864 def _revlogfrompath(repo, path):
"""Obtain a revlog from a repo path.
An instance of the appropriate class is returned.
"""
if path == '00changelog.i':
return changelog.changelog(repo.svfs)
elif path.endswith('00manifest.i'):
Augie Fackler
formatting: blacken the codebase...
r43346 mandir = path[: -len('00manifest.i')]
Gregory Szorc
manifest: rename dir argument and attribute to tree...
r39279 return manifest.manifestrevlog(repo.svfs, tree=mandir)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 else:
Augie Fackler
formatting: blacken the codebase...
r43346 # reverse of "/".join(("data", path + ".i"))
Boris Feld
upgrade: use actual filelog to convert filelog...
r35345 return filelog.filelog(repo.svfs, path[5:-2])
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346
upgrade: introduce a _copyrevlog method...
r42918 def _copyrevlog(tr, destrepo, oldrl, unencodedname):
"""copy all relevant files for `oldrl` into `destrepo` store
Files are copied "as is" without any transformation. The copy is performed
without extra checks. Callers are responsible for making sure the copied
content is compatible with format of the destination repository.
"""
oldrl = getattr(oldrl, '_revlog', oldrl)
newrl = _revlogfrompath(destrepo, unencodedname)
newrl = getattr(newrl, '_revlog', newrl)
oldvfs = oldrl.opener
newvfs = newrl.opener
oldindex = oldvfs.join(oldrl.indexfile)
newindex = newvfs.join(newrl.indexfile)
olddata = oldvfs.join(oldrl.datafile)
newdata = newvfs.join(newrl.datafile)
upgrade: create the correct destination directory for copies revlogs...
r43269 with newvfs(newrl.indexfile, 'w'):
Augie Fackler
formatting: blacken the codebase...
r43346 pass # create all the directories
upgrade: introduce a _copyrevlog method...
r42918
util.copyfile(oldindex, newindex)
upgrade: also register copied `.d` files to fncache...
r43272 copydata = oldrl.opener.exists(oldrl.datafile)
if copydata:
upgrade: introduce a _copyrevlog method...
r42918 util.copyfile(olddata, newdata)
Augie Fackler
formatting: blacken the codebase...
r43346 if not (
unencodedname.endswith('00changelog.i')
or unencodedname.endswith('00manifest.i')
):
upgrade: introduce a _copyrevlog method...
r42918 destrepo.svfs.fncache.add(unencodedname)
upgrade: also register copied `.d` files to fncache...
r43272 if copydata:
destrepo.svfs.fncache.add(unencodedname[:-2] + '.d')
upgrade: introduce a _copyrevlog method...
r42918
Augie Fackler
formatting: blacken the codebase...
r43346
upgrade: introduce the internal code for revlog cloning selection...
r42921 UPGRADE_CHANGELOG = object()
UPGRADE_MANIFEST = object()
UPGRADE_FILELOG = object()
Augie Fackler
formatting: blacken the codebase...
r43346 UPGRADE_ALL_REVLOGS = frozenset(
[UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOG]
)
upgrade: introduce the internal code for revlog cloning selection...
r42921
def matchrevlog(revlogfilter, entry):
"""check is a revlog is selected for cloning
The store entry is checked against the passed filter"""
if entry.endswith('00changelog.i'):
return UPGRADE_CHANGELOG in revlogfilter
elif entry.endswith('00manifest.i'):
return UPGRADE_MANIFEST in revlogfilter
return UPGRADE_FILELOG in revlogfilter
Augie Fackler
formatting: blacken the codebase...
r43346
def _clonerevlogs(
ui,
srcrepo,
dstrepo,
tr,
deltareuse,
forcedeltabothparents,
revlogs=UPGRADE_ALL_REVLOGS,
):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Copy revlogs between 2 repos."""
revcount = 0
srcsize = 0
srcrawsize = 0
dstsize = 0
fcount = 0
frevcount = 0
fsrcsize = 0
frawsize = 0
fdstsize = 0
mcount = 0
mrevcount = 0
msrcsize = 0
mrawsize = 0
mdstsize = 0
crevcount = 0
csrcsize = 0
crawsize = 0
cdstsize = 0
upgrade: walk the source store file only once...
r42916 alldatafiles = list(srcrepo.store.walk())
Pierre-Yves David
upgrade: extract code in its own module...
r31864 # Perform a pass to collect metadata. This validates we can open all
# source files and allows a unified progress bar to be displayed.
upgrade: walk the source store file only once...
r42916 for unencoded, encoded, size in alldatafiles:
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if unencoded.endswith('.d'):
continue
rl = _revlogfrompath(srcrepo, unencoded)
Augie Fackler
formatting: blacken the codebase...
r43346 info = rl.storageinfo(
exclusivefiles=True,
revisionscount=True,
trackedsize=True,
storedsize=True,
)
Gregory Szorc
upgrade: report size of backing files, not internal storage size...
r39893
Gregory Szorc
upgrade: use storageinfo() for obtaining storage metadata...
r39906 revcount += info['revisionscount'] or 0
datasize = info['storedsize'] or 0
rawsize = info['trackedsize'] or 0
Pierre-Yves David
upgrade: extract code in its own module...
r31864
srcsize += datasize
srcrawsize += rawsize
# This is for the separate progress bars.
if isinstance(rl, changelog.changelog):
crevcount += len(rl)
csrcsize += datasize
crawsize += rawsize
elif isinstance(rl, manifest.manifestrevlog):
mcount += 1
mrevcount += len(rl)
msrcsize += datasize
mrawsize += rawsize
Gregory Szorc
upgrade: sniff for filelog type...
r37462 elif isinstance(rl, filelog.filelog):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 fcount += 1
frevcount += len(rl)
fsrcsize += datasize
frawsize += rawsize
Gregory Szorc
upgrade: sniff for filelog type...
r37462 else:
error.ProgrammingError('unknown revlog type')
Pierre-Yves David
upgrade: extract code in its own module...
r31864
if not revcount:
return
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'migrating %d total revisions (%d in filelogs, %d in manifests, '
'%d in changelog)\n'
)
% (revcount, frevcount, mrevcount, crevcount)
)
ui.write(
_('migrating %s in store; %s tracked data\n')
% ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# Used to keep track of progress.
Martin von Zweigbergk
upgrade: use progress helper...
r38418 progress = None
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: extract code in its own module...
r31864 def oncopiedrevision(rl, rev, node):
Martin von Zweigbergk
upgrade: use progress helper...
r38418 progress.increment()
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# Do the actual copying.
# FUTURE this operation can be farmed off to worker processes.
seen = set()
upgrade: walk the source store file only once...
r42916 for unencoded, encoded, size in alldatafiles:
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if unencoded.endswith('.d'):
continue
oldrl = _revlogfrompath(srcrepo, unencoded)
if isinstance(oldrl, changelog.changelog) and 'c' not in seen:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'finished migrating %d manifest revisions across %d '
'manifests; change in size: %s\n'
)
% (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'migrating changelog containing %d revisions '
'(%s in store; %s tracked data)\n'
)
% (
crevcount,
util.bytecount(csrcsize),
util.bytecount(crawsize),
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 seen.add('c')
Augie Fackler
formatting: blacken the codebase...
r43346 progress = srcrepo.ui.makeprogress(
_('changelog revisions'), total=crevcount
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 elif isinstance(oldrl, manifest.manifestrevlog) and 'm' not in seen:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'finished migrating %d filelog revisions across %d '
'filelogs; change in size: %s\n'
)
% (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'migrating %d manifests containing %d revisions '
'(%s in store; %s tracked data)\n'
)
% (
mcount,
mrevcount,
util.bytecount(msrcsize),
util.bytecount(mrawsize),
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 seen.add('m')
Martin von Zweigbergk
upgrade: close progress after each revlog...
r38417 if progress:
Martin von Zweigbergk
upgrade: use progress helper...
r38418 progress.complete()
Augie Fackler
formatting: blacken the codebase...
r43346 progress = srcrepo.ui.makeprogress(
_('manifest revisions'), total=mrevcount
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 elif 'f' not in seen:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'migrating %d filelogs containing %d revisions '
'(%s in store; %s tracked data)\n'
)
% (
fcount,
frevcount,
util.bytecount(fsrcsize),
util.bytecount(frawsize),
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 seen.add('f')
Martin von Zweigbergk
upgrade: close progress after each revlog...
r38417 if progress:
Martin von Zweigbergk
upgrade: use progress helper...
r38418 progress.complete()
Augie Fackler
formatting: blacken the codebase...
r43346 progress = srcrepo.ui.makeprogress(
_('file revisions'), total=frevcount
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
upgrade: introduce the internal code for revlog cloning selection...
r42921 if matchrevlog(revlogs, unencoded):
Augie Fackler
formatting: blacken the codebase...
r43346 ui.note(
_('cloning %d revisions from %s\n') % (len(oldrl), unencoded)
)
upgrade: introduce the internal code for revlog cloning selection...
r42921 newrl = _revlogfrompath(dstrepo, unencoded)
Augie Fackler
formatting: blacken the codebase...
r43346 oldrl.clone(
tr,
newrl,
addrevisioncb=oncopiedrevision,
deltareuse=deltareuse,
forcedeltabothparents=forcedeltabothparents,
)
upgrade: introduce the internal code for revlog cloning selection...
r42921 else:
msg = _('blindly copying %s containing %i revisions\n')
ui.note(msg % (unencoded, len(oldrl)))
_copyrevlog(tr, dstrepo, oldrl, unencoded)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
upgrade: introduce the internal code for revlog cloning selection...
r42921 newrl = _revlogfrompath(dstrepo, unencoded)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Gregory Szorc
upgrade: use storageinfo() for obtaining storage metadata...
r39906 info = newrl.storageinfo(storedsize=True)
datasize = info['storedsize'] or 0
Pierre-Yves David
upgrade: extract code in its own module...
r31864
dstsize += datasize
if isinstance(newrl, changelog.changelog):
cdstsize += datasize
elif isinstance(newrl, manifest.manifestrevlog):
mdstsize += datasize
else:
fdstsize += datasize
Martin von Zweigbergk
upgrade: use progress helper...
r38418 progress.complete()
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_('finished migrating %d changelog revisions; change in size: ' '%s\n')
% (crevcount, util.bytecount(cdstsize - csrcsize))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'finished migrating %d total revisions; total change in store '
'size: %s\n'
)
% (revcount, util.bytecount(dstsize - srcsize))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: drop the prefix to the '_filterstorefile' function...
r31873 def _filterstorefile(srcrepo, dstrepo, requirements, path, mode, st):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Determine whether to copy a store file during upgrade.
This function is called when migrating store files from ``srcrepo`` to
``dstrepo`` as part of upgrading a repository.
Args:
srcrepo: repo we are copying from
dstrepo: repo we are copying to
requirements: set of requirements for ``dstrepo``
path: store file being examined
mode: the ``ST_MODE`` file type of ``path``
st: ``stat`` data structure for ``path``
Function should return ``True`` if the file is to be copied.
"""
# Skip revlogs.
if path.endswith(('.i', '.d')):
return False
# Skip transaction related files.
if path.startswith('undo'):
return False
# Only copy regular files.
if mode != stat.S_IFREG:
return False
# Skip other skipped files.
if path in ('lock', 'fncache'):
return False
return True
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
upgrade: drop the prefix to the '_finishdatamigration' function...
r31874 def _finishdatamigration(ui, srcrepo, dstrepo, requirements):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Hook point for extensions to perform additional actions during upgrade.
This function is called after revlogs and store files have been copied but
before the new store is swapped into the original location.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
def _upgraderepo(
ui, srcrepo, dstrepo, requirements, actions, revlogs=UPGRADE_ALL_REVLOGS
):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Do the low-level work of upgrading a repository.
The upgrade is effectively performed as a copy between a source
repository and a temporary destination repository.
The source repository is unmodified for as long as possible so the
upgrade can abort at any time without causing loss of service for
readers and without corrupting the source repository.
"""
assert srcrepo.currentwlock()
assert dstrepo.currentwlock()
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'(it is safe to interrupt this process any time before '
'data migration completes)\n'
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Boris Feld
upgrade: add '-' in optimization name...
r41120 if 're-delta-all' in actions:
Pierre-Yves David
upgrade: extract code in its own module...
r31864 deltareuse = revlog.revlog.DELTAREUSENEVER
Boris Feld
upgrade: add '-' in optimization name...
r41120 elif 're-delta-parent' in actions:
Pierre-Yves David
upgrade: extract code in its own module...
r31864 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
Boris Feld
upgrade: add '-' in optimization name...
r41120 elif 're-delta-multibase' in actions:
Pierre-Yves David
upgrade: extract code in its own module...
r31864 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
Boris Feld
upgrade: add '-' in optimization name...
r41120 elif 're-delta-fulladd' in actions:
Boris Feld
upgrade: add a 'redeltafullall' mode...
r35346 deltareuse = revlog.revlog.DELTAREUSEFULLADD
Pierre-Yves David
upgrade: extract code in its own module...
r31864 else:
deltareuse = revlog.revlog.DELTAREUSEALWAYS
with dstrepo.transaction('upgrade') as tr:
Augie Fackler
formatting: blacken the codebase...
r43346 _clonerevlogs(
ui,
srcrepo,
dstrepo,
tr,
deltareuse,
're-delta-multibase' in actions,
revlogs=revlogs,
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# Now copy other files in the store directory.
Yuya Nishihara
merge with stable
r31875 # The sorted() makes execution deterministic.
for p, kind, st in sorted(srcrepo.store.vfs.readdir('', stat=True)):
Augie Fackler
formatting: blacken the codebase...
r43346 if not _filterstorefile(srcrepo, dstrepo, requirements, p, kind, st):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 continue
srcrepo.ui.write(_('copying %s\n') % p)
Yuya Nishihara
merge with stable
r31875 src = srcrepo.store.rawvfs.join(p)
dst = dstrepo.store.rawvfs.join(p)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 util.copyfile(src, dst, copystat=True)
Pierre-Yves David
upgrade: drop the prefix to the '_finishdatamigration' function...
r31874 _finishdatamigration(ui, srcrepo, dstrepo, requirements)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
ui.write(_('data fully migrated to temporary repository\n'))
Yuya Nishihara
py3: wrap tempfile.mkdtemp() to use bytes path...
r38183 backuppath = pycompat.mkdtemp(prefix='upgradebackup.', dir=srcrepo.path)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 backupvfs = vfsmod.vfs(backuppath)
# Make a backup of requires file first, as it is the first to be modified.
util.copyfile(srcrepo.vfs.join('requires'), backupvfs.join('requires'))
# We install an arbitrary requirement that clients must not support
# as a mechanism to lock out new clients during the data swap. This is
# better than allowing a client to continue while the repository is in
# an inconsistent state.
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'marking source repository as being upgraded; clients will be '
'unable to read from repository\n'
)
)
scmutil.writerequires(
srcrepo.vfs, srcrepo.requirements | {'upgradeinprogress'}
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
ui.write(_('starting in-place swap of repository data\n'))
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(_('replaced files will be backed up at %s\n') % backuppath)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# Now swap in the new store directory. Doing it as a rename should make
# the operation nearly instantaneous and atomic (at least in well-behaved
# environments).
ui.write(_('replacing store...\n'))
tstart = util.timer()
util.rename(srcrepo.spath, backupvfs.join('store'))
util.rename(dstrepo.spath, srcrepo.spath)
elapsed = util.timer() - tstart
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'store replacement complete; repository was inconsistent for '
'%0.1fs\n'
)
% elapsed
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# We first write the requirements file. Any new requirements will lock
# out legacy clients.
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'finalizing requirements file and making repository readable '
'again\n'
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 scmutil.writerequires(srcrepo.vfs, requirements)
# The lock file from the old store won't be removed because nothing has a
# reference to its new location. So clean it up manually. Alternatively, we
# could update srcrepo.svfs and other variables to point to the new
# location. This is simpler.
backupvfs.unlink('store/lock')
return backuppath
Augie Fackler
formatting: blacken the codebase...
r43346
def upgraderepo(
ui,
repo,
run=False,
optimize=None,
backup=True,
manifest=None,
changelog=None,
):
Pierre-Yves David
upgrade: extract code in its own module...
r31864 """Upgrade a repository in place."""
Boris Feld
upgrade: add '-' in optimization name...
r41120 if optimize is None:
optimize = []
optimize = set(legacy_opts_map.get(o, o) for o in optimize)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 repo = repo.unfiltered()
upgrade: add an argument to control manifest upgrade...
r43098 revlogs = set(UPGRADE_ALL_REVLOGS)
upgrade: add an argument to control changelog upgrade...
r43099 specentries = (('c', changelog), ('m', manifest))
upgrade: add an argument to control manifest upgrade...
r43098 specified = [(y, x) for (y, x) in specentries if x is not None]
if specified:
# we have some limitation on revlogs to be recloned
if any(x for y, x in specified):
revlogs = set()
for r, enabled in specified:
if enabled:
upgrade: add an argument to control changelog upgrade...
r43099 if r == 'c':
revlogs.add(UPGRADE_CHANGELOG)
elif r == 'm':
upgrade: add an argument to control manifest upgrade...
r43098 revlogs.add(UPGRADE_MANIFEST)
else:
# none are enabled
for r, __ in specified:
upgrade: add an argument to control changelog upgrade...
r43099 if r == 'c':
revlogs.discard(UPGRADE_CHANGELOG)
elif r == 'm':
upgrade: add an argument to control manifest upgrade...
r43098 revlogs.discard(UPGRADE_MANIFEST)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 # Ensure the repository can be upgraded.
Pierre-Yves David
upgrade: drop the prefix to the 'requiredsourcerequirements' function...
r31865 missingreqs = requiredsourcerequirements(repo) - repo.requirements
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if missingreqs:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_('cannot upgrade repository; requirement ' 'missing: %s')
% _(', ').join(sorted(missingreqs))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: drop the prefix to the 'blocksourcerequirements' function...
r31866 blockedreqs = blocksourcerequirements(repo) & repo.requirements
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if blockedreqs:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
'cannot upgrade repository; unsupported source '
'requirement: %s'
)
% _(', ').join(sorted(blockedreqs))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# FUTURE there is potentially a need to control the wanted requirements via
# command arguments or via an extension hook point.
Gregory Szorc
localrepo: define storage backend in creation options (API)...
r40032 newreqs = localrepo.newreporequirements(
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui, localrepo.defaultcreateopts(repo.ui)
)
Boris Feld
upgraderepo: allow extension to register preserved requirements...
r35303 newreqs.update(preservedrequirements(repo))
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 noremovereqs = (
repo.requirements - newreqs - supportremovedrequirements(repo)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if noremovereqs:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_('cannot upgrade repository; requirement would be ' 'removed: %s')
% _(', ').join(sorted(noremovereqs))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 noaddreqs = newreqs - repo.requirements - allowednewrequirements(repo)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if noaddreqs:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
'cannot upgrade repository; do not support adding '
'requirement: %s'
)
% _(', ').join(sorted(noaddreqs))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: drop the prefix to the 'supporteddestrequirements' function...
r31870 unsupportedreqs = newreqs - supporteddestrequirements(repo)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if unsupportedreqs:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
'cannot upgrade repository; do not support '
'destination requirement: %s'
)
% _(', ').join(sorted(unsupportedreqs))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
# Find and validate all improvements that can be made.
Pierre-Yves David
upgrade: filter optimizations outside of 'determineactions'...
r31899 alloptimizations = findoptimizations(repo)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: filter optimizations outside of 'determineactions'...
r31899 # Apply and Validate arguments.
optimizations = []
for o in alloptimizations:
if o.name in optimize:
optimizations.append(o)
optimize.discard(o.name)
Augie Fackler
formatting: blacken the codebase...
r43346 if optimize: # anything left is unknown
raise error.Abort(
_('unknown optimization action requested: %s')
% ', '.join(sorted(optimize)),
hint=_('run without arguments to see valid ' 'optimizations'),
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: simplify optimisations validation...
r31897 deficiencies = finddeficiencies(repo)
Pierre-Yves David
upgrade: filter optimizations outside of 'determineactions'...
r31899 actions = determineactions(repo, deficiencies, repo.requirements, newreqs)
Augie Fackler
formatting: blacken the codebase...
r43346 actions.extend(
o
for o in sorted(optimizations)
# determineactions could have added optimisation
if o not in actions
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
upgrade: make sure we reclone all revlogs when updating to some format...
r43100 removedreqs = repo.requirements - newreqs
addedreqs = newreqs - repo.requirements
if revlogs != UPGRADE_ALL_REVLOGS:
incompatible = RECLONES_REQUIREMENTS & (removedreqs | addedreqs)
if incompatible:
Augie Fackler
formatting: blacken the codebase...
r43346 msg = _(
'ignoring revlogs selection flags, format requirements '
'change: %s\n'
)
upgrade: make sure we reclone all revlogs when updating to some format...
r43100 ui.warn(msg % ', '.join(sorted(incompatible)))
revlogs = UPGRADE_ALL_REVLOGS
Pierre-Yves David
upgrade: extract code in its own module...
r31864 def printrequirements():
ui.write(_('requirements\n'))
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(' preserved: %s\n')
% _(', ').join(sorted(newreqs & repo.requirements))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
if repo.requirements - newreqs:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(' removed: %s\n')
% _(', ').join(sorted(repo.requirements - newreqs))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
if newreqs - repo.requirements:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(' added: %s\n')
% _(', ').join(sorted(newreqs - repo.requirements))
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
ui.write('\n')
def printupgradeactions():
Pierre-Yves David
upgrade: use 'improvement' object for action too...
r31903 for a in actions:
ui.write('%s\n %s\n\n' % (a.name, a.upgrademessage))
Pierre-Yves David
upgrade: extract code in its own module...
r31864
if not run:
fromconfig = []
Pierre-Yves David
upgrade: simplify the "origin" dispatch in dry run...
r31904 onlydefault = []
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: simplify some of the initial dispatch for dry run...
r31901 for d in deficiencies:
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 if d.fromconfig(repo):
Pierre-Yves David
upgrade: simplify some of the initial dispatch for dry run...
r31901 fromconfig.append(d)
Pierre-Yves David
upgrade: move descriptions and selection logic in individual classes...
r32031 elif d.default:
Pierre-Yves David
upgrade: simplify the "origin" dispatch in dry run...
r31904 onlydefault.append(d)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Pierre-Yves David
upgrade: simplify the "origin" dispatch in dry run...
r31904 if fromconfig or onlydefault:
Pierre-Yves David
upgrade: extract code in its own module...
r31864
if fromconfig:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'repository lacks features recommended by '
'current config options:\n\n'
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 for i in fromconfig:
ui.write('%s\n %s\n\n' % (i.name, i.description))
if onlydefault:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'repository lacks features used by the default '
'config options:\n\n'
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 for i in onlydefault:
ui.write('%s\n %s\n\n' % (i.name, i.description))
ui.write('\n')
else:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_('(no feature deficiencies found in existing ' 'repository)\n')
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'performing an upgrade with "--run" will make the following '
'changes:\n\n'
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
printrequirements()
printupgradeactions()
Pierre-Yves David
upgrade: use 'improvement' object for action too...
r31903 unusedoptimize = [i for i in alloptimizations if i not in actions]
Pierre-Yves David
upgrade: extract code in its own module...
r31864 if unusedoptimize:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'additional optimizations are available by specifying '
'"--optimize <name>":\n\n'
)
)
Pierre-Yves David
upgrade: extract code in its own module...
r31864 for i in unusedoptimize:
ui.write(_('%s\n %s\n\n') % (i.name, i.description))
return
# Else we're in the run=true case.
ui.write(_('upgrade will perform the following actions:\n\n'))
printrequirements()
printupgradeactions()
Pierre-Yves David
upgrade: use 'improvement' object for action too...
r31903 upgradeactions = [a.name for a in actions]
Pierre-Yves David
upgrade: extract code in its own module...
r31864 ui.write(_('beginning upgrade...\n'))
Jun Wu
codemod: simplify nested withs...
r33438 with repo.wlock(), repo.lock():
ui.write(_('repository locked and read-only\n'))
# Our strategy for upgrading the repository is to create a new,
# temporary repository, write data to it, then do a swap of the
# data. There are less heavyweight ways to do this, but it is easier
# to create a new repo object than to instantiate all the components
# (like the store) separately.
Yuya Nishihara
py3: wrap tempfile.mkdtemp() to use bytes path...
r38183 tmppath = pycompat.mkdtemp(prefix='upgrade.', dir=repo.path)
Jun Wu
codemod: simplify nested withs...
r33438 backuppath = None
try:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
_(
'creating temporary repository to stage migrated '
'data: %s\n'
)
% tmppath
)
Boris Feld
upgrade: use the repository 'ui' as the base for the new repository...
r35343
Yuya Nishihara
upgrade: simplify workaround for repo.ui.copy()...
r35380 # clone ui without using ui.copy because repo.ui is protected
repoui = repo.ui.__class__(repo.ui)
dstrepo = hg.repository(repoui, path=tmppath, create=True)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Jun Wu
codemod: simplify nested withs...
r33438 with dstrepo.wlock(), dstrepo.lock():
Augie Fackler
formatting: blacken the codebase...
r43346 backuppath = _upgraderepo(
ui, repo, dstrepo, newreqs, upgradeactions, revlogs=revlogs
)
Boris Feld
debugupgraderepo: add a --no-backup mode...
r41121 if not (backup or backuppath is None):
ui.write(_('removing old repository content%s\n') % backuppath)
repo.vfs.rmtree(backuppath, forcibly=True)
backuppath = None
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Jun Wu
codemod: simplify nested withs...
r33438 finally:
ui.write(_('removing temporary repository %s\n') % tmppath)
repo.vfs.rmtree(tmppath, forcibly=True)
Pierre-Yves David
upgrade: extract code in its own module...
r31864
Jun Wu
codemod: simplify nested withs...
r33438 if backuppath:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_('copy of old repository backed up at %s\n') % backuppath
)
ui.warn(
_(
'the old repository will not be deleted; remove '
'it to free up disk space once the upgraded '
'repository is verified\n'
)
)