Improve error messages when Spack finds a too new DB / lockfile (#37614)
This PR ensures that we'll get a comprehensible error message whenever an old version of Spack tries to use a DB or a lockfile that is "too new". * Fix error message when using a too new DB * Add a unit-test to ensure we have a comprehensible error message
This commit is contained in:
parent
644a10ee35
commit
ebfc706c8c
@ -798,9 +798,8 @@ def check(cond, msg):
|
|||||||
|
|
||||||
# TODO: better version checking semantics.
|
# TODO: better version checking semantics.
|
||||||
version = vn.Version(db["version"])
|
version = vn.Version(db["version"])
|
||||||
spec_reader = reader(version)
|
|
||||||
if version > _db_version:
|
if version > _db_version:
|
||||||
raise InvalidDatabaseVersionError(_db_version, version)
|
raise InvalidDatabaseVersionError(self, _db_version, version)
|
||||||
elif version < _db_version:
|
elif version < _db_version:
|
||||||
if not any(old == version and new == _db_version for old, new in _skip_reindex):
|
if not any(old == version and new == _db_version for old, new in _skip_reindex):
|
||||||
tty.warn(
|
tty.warn(
|
||||||
@ -814,6 +813,8 @@ def check(cond, msg):
|
|||||||
for k, v in self._data.items()
|
for k, v in self._data.items()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
spec_reader = reader(version)
|
||||||
|
|
||||||
def invalid_record(hash_key, error):
|
def invalid_record(hash_key, error):
|
||||||
return CorruptDatabaseError(
|
return CorruptDatabaseError(
|
||||||
f"Invalid record in Spack database: hash: {hash_key}, cause: "
|
f"Invalid record in Spack database: hash: {hash_key}, cause: "
|
||||||
@ -1642,7 +1643,7 @@ class CorruptDatabaseError(SpackError):
|
|||||||
|
|
||||||
|
|
||||||
class NonConcreteSpecAddError(SpackError):
|
class NonConcreteSpecAddError(SpackError):
|
||||||
"""Raised when attemptint to add non-concrete spec to DB."""
|
"""Raised when attempting to add non-concrete spec to DB."""
|
||||||
|
|
||||||
|
|
||||||
class MissingDependenciesError(SpackError):
|
class MissingDependenciesError(SpackError):
|
||||||
@ -1650,8 +1651,11 @@ class MissingDependenciesError(SpackError):
|
|||||||
|
|
||||||
|
|
||||||
class InvalidDatabaseVersionError(SpackError):
|
class InvalidDatabaseVersionError(SpackError):
|
||||||
def __init__(self, expected, found):
|
"""Exception raised when the database metadata is newer than current Spack."""
|
||||||
super(InvalidDatabaseVersionError, self).__init__(
|
|
||||||
"Expected database version %s but found version %s." % (expected, found),
|
def __init__(self, database, expected, found):
|
||||||
"`spack reindex` may fix this, or you may need a newer " "Spack version.",
|
msg = (
|
||||||
|
f"you need a newer Spack version to read the database in '{database.root}'. "
|
||||||
|
f"The expected database version is '{expected}', but '{found}' was found."
|
||||||
)
|
)
|
||||||
|
super(InvalidDatabaseVersionError, self).__init__(msg)
|
||||||
|
@ -2127,10 +2127,12 @@ def _read_lockfile_dict(self, d):
|
|||||||
reader = READER_CLS[current_lockfile_format]
|
reader = READER_CLS[current_lockfile_format]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
msg = (
|
msg = (
|
||||||
f"Spack {spack.__version__} cannot read environment lockfiles using the "
|
f"Spack {spack.__version__} cannot read the lockfile '{self.lock_path}', using "
|
||||||
f"v{current_lockfile_format} format"
|
f"the v{current_lockfile_format} format."
|
||||||
)
|
)
|
||||||
raise RuntimeError(msg)
|
if lockfile_format_version < current_lockfile_format:
|
||||||
|
msg += " You need to use a newer Spack version."
|
||||||
|
raise SpackEnvironmentError(msg)
|
||||||
|
|
||||||
# First pass: Put each spec in the map ignoring dependencies
|
# First pass: Put each spec in the map ignoring dependencies
|
||||||
for lockfile_key, node_dict in json_specs_by_hash.items():
|
for lockfile_key, node_dict in json_specs_by_hash.items():
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.store
|
import spack.store
|
||||||
|
import spack.version as vn
|
||||||
from spack.schema.database_index import schema
|
from spack.schema.database_index import schema
|
||||||
from spack.util.executable import Executable
|
from spack.util.executable import Executable
|
||||||
|
|
||||||
@ -1051,3 +1052,16 @@ def test_query_installed_when_package_unknown(database, tmpdir):
|
|||||||
assert not s.installed_upstream
|
assert not s.installed_upstream
|
||||||
with pytest.raises(spack.repo.UnknownNamespaceError):
|
with pytest.raises(spack.repo.UnknownNamespaceError):
|
||||||
s.package
|
s.package
|
||||||
|
|
||||||
|
|
||||||
|
def test_error_message_when_using_too_new_db(database, monkeypatch):
|
||||||
|
"""Sometimes the database format needs to be bumped. When that happens, we have forward
|
||||||
|
incompatibilities that need to be reported in a clear way to the user, in case we moved
|
||||||
|
back to an older version of Spack. This test ensures that the error message for a too
|
||||||
|
new database version stays comprehensible across refactoring of the database code.
|
||||||
|
"""
|
||||||
|
monkeypatch.setattr(spack.database, "_db_version", vn.Version("0"))
|
||||||
|
with pytest.raises(
|
||||||
|
spack.database.InvalidDatabaseVersionError, match="you need a newer Spack version"
|
||||||
|
):
|
||||||
|
spack.database.Database(database.root)._read()
|
||||||
|
@ -474,3 +474,29 @@ def test_initialize_from_random_file_as_manifest(tmp_path, filename):
|
|||||||
assert not os.path.exists(env_dir / ev.lockfile_name)
|
assert not os.path.exists(env_dir / ev.lockfile_name)
|
||||||
assert os.path.exists(env_dir / ev.manifest_name)
|
assert os.path.exists(env_dir / ev.manifest_name)
|
||||||
assert filecmp.cmp(env_dir / ev.manifest_name, init_file, shallow=False)
|
assert filecmp.cmp(env_dir / ev.manifest_name, init_file, shallow=False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_error_message_when_using_too_new_lockfile(tmp_path):
|
||||||
|
"""Sometimes the lockfile format needs to be bumped. When that happens, we have forward
|
||||||
|
incompatibilities that need to be reported in a clear way to the user, in case we moved
|
||||||
|
back to an older version of Spack. This test ensures that the error message for a too
|
||||||
|
new lockfile version stays comprehensible across refactoring of the environment code.
|
||||||
|
"""
|
||||||
|
init_file = tmp_path / ev.lockfile_name
|
||||||
|
env_dir = tmp_path / "env_dir"
|
||||||
|
init_file.write_text(
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"file-type": "spack-lockfile",
|
||||||
|
"lockfile-version": 100,
|
||||||
|
"specfile-version": 3
|
||||||
|
},
|
||||||
|
"roots": [],
|
||||||
|
"concrete_specs": {}
|
||||||
|
}\n
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
ev.initialize_environment_dir(env_dir, init_file)
|
||||||
|
with pytest.raises(ev.SpackEnvironmentError, match="You need to use a newer Spack version."):
|
||||||
|
ev.Environment(env_dir)
|
||||||
|
Loading…
Reference in New Issue
Block a user