Skip to content

Commit

Permalink
[1.2] feat: forward compatibility for lock file format 2.0 (#6608)
Browse files Browse the repository at this point in the history
Backport the ability to read 2.0 lockfiles per #6393
  • Loading branch information
dimbleby authored Sep 24, 2022
1 parent 2f71a53 commit 790e156
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 4 deletions.
24 changes: 21 additions & 3 deletions src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ def locked_repository(self) -> Repository:
if source_type in ["directory", "file"]:
url = self._lock.path.parent.joinpath(url).resolve().as_posix()

name = info["name"]
package = Package(
info["name"],
name,
info["version"],
info["version"],
source_type=source_type,
Expand All @@ -123,8 +124,19 @@ def locked_repository(self) -> Repository:
package.category = info.get("category", "main")
package.optional = info["optional"]
metadata = cast("dict[str, Any]", lock_data["metadata"])
name = info["name"]
if "hashes" in metadata:

# Storing of package files and hashes has been through a few generations in
# the lockfile, we can read them all:
#
# - latest and preferred is that this is read per package, from
# package.files
# - oldest is that hashes were stored in metadata.hashes without filenames
# - in between those two, hashes were stored alongside filenames in
# metadata.files
package_files = info.get("files")
if package_files is not None:
package.files = package_files
elif "hashes" in metadata:
# Old lock so we create dummy files from the hashes
hashes = cast("dict[str, Any]", metadata["hashes"])
package.files = [{"name": h, "hash": h} for h in hashes[name]]
Expand Down Expand Up @@ -288,6 +300,12 @@ def _get_lock_data(self) -> TOMLDocument:

metadata = cast("Table", lock_data["metadata"])
lock_version = Version.parse(metadata.get("lock-version", "1.0"))

# As a special case: the ability to read a 2.0 lockfile was backported and is
# fully supported.
if lock_version == Version.parse("2.0"):
return lock_data

current_version = Version.parse(self._VERSION)
# We expect the locker to be able to read lock files
# from the same semantic versioning range
Expand Down
40 changes: 39 additions & 1 deletion tests/packages/test_locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,14 +700,52 @@ def test_locker_should_emit_warnings_if_lock_version_is_newer_but_allowed(
assert record.message == expected


def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed(
def test_locker_can_read_2_0_lockfile_because_backported(
locker: Locker, caplog: LogCaptureFixture
):
content = """\
[[package]]
name = "demo"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"
develop = false
files = [
{file = "demo-1.0-cp39-win_amd64.whl", hash = "sha256"},
{file = "demo-1.0.tar.gz", hash = "sha256"},
{file = "demo-1.0-py3-none-any.whl", hash = "sha256"},
]
[metadata]
lock-version = "2.0"
python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
"""
caplog.set_level(logging.WARNING, logger="poetry.packages.locker")

locker.lock.write(tomlkit.parse(content))

repository = locker.locked_repository()
packages = repository.packages
assert len(packages) == 1
package = packages[0]
assert package.files == [
{"file": "demo-1.0-cp39-win_amd64.whl", "hash": "sha256"},
{"file": "demo-1.0.tar.gz", "hash": "sha256"},
{"file": "demo-1.0-py3-none-any.whl", "hash": "sha256"},
]


def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed(
locker: Locker, caplog: LogCaptureFixture
):
content = """\
[metadata]
lock-version = "2.1"
python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
[metadata.files]
"""
Expand Down

0 comments on commit 790e156

Please sign in to comment.