Commit cd72aed8 by Sébastien Eustace Committed by Arun Babu Neelicattu

Add lock versioning support

parent f117a955
...@@ -54,7 +54,11 @@ class ApplicationConfig(BaseApplicationConfig): ...@@ -54,7 +54,11 @@ class ApplicationConfig(BaseApplicationConfig):
io = event.io io = event.io
loggers = ["poetry.packages.package", "poetry.utils.password_manager"] loggers = [
"poetry.packages.locker",
"poetry.packages.package",
"poetry.utils.password_manager",
]
loggers += command.loggers loggers += command.loggers
...@@ -65,7 +69,6 @@ class ApplicationConfig(BaseApplicationConfig): ...@@ -65,7 +69,6 @@ class ApplicationConfig(BaseApplicationConfig):
logger = logging.getLogger(logger) logger = logging.getLogger(logger)
logger.handlers = [handler] logger.handlers = [handler]
logger.propagate = False
level = logging.WARNING level = logging.WARNING
if io.is_debug(): if io.is_debug():
......
import json import json
import logging
import re import re
from hashlib import sha256 from hashlib import sha256
...@@ -13,13 +14,20 @@ from tomlkit.exceptions import TOMLKitError ...@@ -13,13 +14,20 @@ from tomlkit.exceptions import TOMLKitError
import poetry.packages import poetry.packages
import poetry.repositories import poetry.repositories
from poetry.semver import parse_constraint
from poetry.semver.version import Version
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
from poetry.version.markers import parse_marker from poetry.version.markers import parse_marker
logger = logging.getLogger(__name__)
class Locker(object): class Locker(object):
_VERSION = "1.0"
_relevant_keys = ["dependencies", "dev-dependencies", "source", "extras"] _relevant_keys = ["dependencies", "dev-dependencies", "source", "extras"]
def __init__(self, lock, local_config): # type: (Path, dict) -> None def __init__(self, lock, local_config): # type: (Path, dict) -> None
...@@ -180,6 +188,7 @@ class Locker(object): ...@@ -180,6 +188,7 @@ class Locker(object):
} }
lock["metadata"] = { lock["metadata"] = {
"lock-version": self._VERSION,
"python-versions": root.python_versions, "python-versions": root.python_versions,
"content-hash": self._content_hash, "content-hash": self._content_hash,
"files": files, "files": files,
...@@ -222,10 +231,31 @@ class Locker(object): ...@@ -222,10 +231,31 @@ class Locker(object):
raise RuntimeError("No lockfile found. Unable to read locked packages") raise RuntimeError("No lockfile found. Unable to read locked packages")
try: try:
return self._lock.read() lock_data = self._lock.read()
except TOMLKitError as e: except TOMLKitError as e:
raise RuntimeError("Unable to read the lock file ({}).".format(e)) raise RuntimeError("Unable to read the lock file ({}).".format(e))
lock_version = Version.parse(lock_data["metadata"].get("lock-version", "1.0"))
current_version = Version.parse(self._VERSION)
accepted_versions = parse_constraint(
"^{}".format(Version(current_version.major, current_version.minor))
)
lock_version_allowed = accepted_versions.allows(lock_version)
if lock_version_allowed and current_version < lock_version:
logger.warning(
"The lock file might not be compatible with the current version of Poetry.\n"
"Upgrade Poetry to ensure the lock file is read properly or, alternatively, "
"regenerate the lock file with the `poetry lock` command."
)
elif not lock_version_allowed:
raise RuntimeError(
"The lock file is not compatible with the current version of Poetry.\n"
"Upgrade Poetry to be able to read the lock file or, alternatively, "
"regenerate the lock file with the `poetry lock` command."
)
return lock_data
def _lock_packages( def _lock_packages(
self, packages self, packages
): # type: (List['poetry.packages.Package']) -> list ): # type: (List['poetry.packages.Package']) -> list
......
...@@ -38,6 +38,7 @@ foo = ["C"] ...@@ -38,6 +38,7 @@ foo = ["C"]
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -35,6 +35,7 @@ foo = ["D"] ...@@ -35,6 +35,7 @@ foo = ["D"]
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -24,6 +24,7 @@ python-versions = "*" ...@@ -24,6 +24,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -2,6 +2,7 @@ package = [] ...@@ -2,6 +2,7 @@ package = []
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
...@@ -8,6 +8,7 @@ python-versions = "*" ...@@ -8,6 +8,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -8,6 +8,7 @@ python-versions = "*" ...@@ -8,6 +8,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -40,6 +40,7 @@ python-versions = "*" ...@@ -40,6 +40,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -19,6 +19,7 @@ A = "^1.0" ...@@ -19,6 +19,7 @@ A = "^1.0"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -22,6 +22,7 @@ python = ">=3.6,<4.0" ...@@ -22,6 +22,7 @@ python = ">=3.6,<4.0"
[metadata] [metadata]
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -30,6 +30,7 @@ python-versions = "*" ...@@ -30,6 +30,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -16,6 +16,7 @@ python-versions = "*" ...@@ -16,6 +16,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -96,6 +96,7 @@ url = "project_with_transitive_file_dependencies" ...@@ -96,6 +96,7 @@ url = "project_with_transitive_file_dependencies"
[metadata] [metadata]
content-hash = "123456789" content-hash = "123456789"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
......
...@@ -29,6 +29,7 @@ url = "tests/fixtures/project_with_extras" ...@@ -29,6 +29,7 @@ url = "tests/fixtures/project_with_extras"
[metadata] [metadata]
content-hash = "123456789" content-hash = "123456789"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
......
...@@ -34,6 +34,7 @@ python-versions = "*" ...@@ -34,6 +34,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -31,6 +31,7 @@ python-versions = "*" ...@@ -31,6 +31,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -56,6 +56,7 @@ python-versions = "*" ...@@ -56,6 +56,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -60,6 +60,7 @@ url = "project_with_transitive_file_dependencies" ...@@ -60,6 +60,7 @@ url = "project_with_transitive_file_dependencies"
[metadata] [metadata]
content-hash = "123456789" content-hash = "123456789"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
......
...@@ -28,6 +28,7 @@ python-versions = "*" ...@@ -28,6 +28,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -49,6 +49,7 @@ python-versions = "*" ...@@ -49,6 +49,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -32,6 +32,7 @@ foo = ["A"] ...@@ -32,6 +32,7 @@ foo = ["A"]
[metadata] [metadata]
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -41,6 +41,7 @@ foo = ["A"] ...@@ -41,6 +41,7 @@ foo = ["A"]
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -16,6 +16,7 @@ python-versions = "*" ...@@ -16,6 +16,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -84,6 +84,7 @@ python-versions = "*" ...@@ -84,6 +84,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -24,6 +24,7 @@ python-versions = "~2.7 || ^3.3" ...@@ -24,6 +24,7 @@ python-versions = "~2.7 || ^3.3"
[metadata] [metadata]
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -38,6 +38,7 @@ python-versions = "*" ...@@ -38,6 +38,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -28,6 +28,7 @@ python-versions = "*" ...@@ -28,6 +28,7 @@ python-versions = "*"
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
...@@ -13,6 +13,7 @@ url = "tests/fixtures/wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.wh ...@@ -13,6 +13,7 @@ url = "tests/fixtures/wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.wh
[metadata] [metadata]
python-versions = "*" python-versions = "*"
lock-version = "1.0"
content-hash = "123456789" content-hash = "123456789"
[metadata.files] [metadata.files]
......
import logging
import tempfile import tempfile
import pytest import pytest
...@@ -56,6 +57,7 @@ version = "1.2" ...@@ -56,6 +57,7 @@ version = "1.2"
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
...@@ -93,6 +95,7 @@ redis = ["redis (>=2.10.5)"] ...@@ -93,6 +95,7 @@ redis = ["redis (>=2.10.5)"]
[metadata] [metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77" content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "1.0"
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
[metadata.files] [metadata.files]
...@@ -132,6 +135,7 @@ version = "1.0.0" ...@@ -132,6 +135,7 @@ version = "1.0.0"
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
...@@ -171,6 +175,7 @@ foo = ["B (>=1.0.0)"] ...@@ -171,6 +175,7 @@ foo = ["B (>=1.0.0)"]
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
...@@ -200,6 +205,7 @@ foo = ["bar"] ...@@ -200,6 +205,7 @@ foo = ["bar"]
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
...@@ -239,6 +245,7 @@ url = "https://foo.bar" ...@@ -239,6 +245,7 @@ url = "https://foo.bar"
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.0"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
...@@ -246,3 +253,52 @@ A = [] ...@@ -246,3 +253,52 @@ A = []
""" """
assert expected == content assert expected == content
def test_locker_should_emit_warnings_if_lock_version_is_newer_but_allowed(
locker, caplog
):
content = """\
[metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "1.1"
python-versions = "~2.7 || ^3.4"
[metadata.files]
"""
caplog.set_level(logging.WARNING, logger="poetry.packages.locker")
locker.lock.write(tomlkit.parse(content))
_ = locker.lock_data
assert 1 == len(caplog.records)
record = caplog.records[0]
assert "WARNING" == record.levelname
expected = """\
The lock file might not be compatible with the current version of Poetry.
Upgrade Poetry to ensure the lock file is read properly or, alternatively, \
regenerate the lock file with the `poetry lock` command.\
"""
assert expected == record.message
def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed(
locker, caplog
):
content = """\
[metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "2.0"
python-versions = "~2.7 || ^3.4"
[metadata.files]
"""
caplog.set_level(logging.WARNING, logger="poetry.packages.locker")
locker.lock.write(tomlkit.parse(content))
with pytest.raises(RuntimeError, match="^The lock file is not compatible"):
_ = locker.lock_data
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment