Skip to content

Commit 9ee7f40

Browse files
committed
Resolve symlinks in locker.lock path to real physical paths
Fixes #5849
1 parent 3f54fdc commit 9ee7f40

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

src/poetry/packages/locker.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,8 @@ def _dump_package(self, package: Package) -> dict[str, Any]:
603603
# The lock file should only store paths relative to the root project
604604
url = Path(
605605
os.path.relpath(
606-
Path(url).as_posix(), self._lock.path.parent.as_posix()
606+
Path(url).resolve().as_posix(),
607+
Path(self._lock.path.parent).resolve().as_posix(),
607608
)
608609
).as_posix()
609610

tests/packages/test_locker.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
import logging
5+
import os
56
import tempfile
67
import uuid
78

@@ -753,3 +754,77 @@ def test_content_hash_with_legacy_is_compatible(
753754
content_hash = locker._get_content_hash()
754755

755756
assert (content_hash == old_content_hash) or fresh
757+
758+
759+
def test_lock_file_resolves_file_url_symlinks(root: ProjectPackage):
760+
"""
761+
Create directories and file structure as follows:
762+
763+
d1/
764+
d1/testsymlink -> d1/d2/d3
765+
d1/d2/d3/lock_file
766+
d1/d4/source_file
767+
768+
Using the testsymlink as the Locker.lock file path should correctly resolve to
769+
the real physical path of the source_file when calculating the relative path
770+
from the lock_file, i.e. "../../d4/source_file" instead of the unresolved path
771+
from the symlink itself which would have been "../d4/source_file"
772+
773+
See https://github.com/python-poetry/poetry/issues/5849
774+
"""
775+
with tempfile.TemporaryDirectory() as d1:
776+
symlink_path = Path(d1).joinpath("testsymlink")
777+
with tempfile.TemporaryDirectory(dir=d1) as d2, tempfile.TemporaryDirectory(
778+
dir=d1
779+
) as d4, tempfile.TemporaryDirectory(dir=d2) as d3, tempfile.NamedTemporaryFile(
780+
dir=d4
781+
) as source_file, tempfile.NamedTemporaryFile(
782+
dir=d3
783+
) as lock_file:
784+
lock_file.close()
785+
os.symlink(Path(d3), symlink_path)
786+
locker = Locker(str(symlink_path) + os.sep + Path(lock_file.name).name, {})
787+
788+
package_local = Package(
789+
"local-package",
790+
"1.2.3",
791+
source_type="file",
792+
source_url=source_file.name,
793+
source_reference="develop",
794+
source_resolved_reference="123456",
795+
)
796+
packages = [
797+
package_local,
798+
]
799+
800+
locker.set_lock_data(root, packages)
801+
802+
with locker.lock.open(encoding="utf-8") as f:
803+
content = f.read()
804+
805+
expected = f"""\
806+
[[package]]
807+
name = "local-package"
808+
version = "1.2.3"
809+
description = ""
810+
category = "main"
811+
optional = false
812+
python-versions = "*"
813+
814+
[package.source]
815+
type = "file"
816+
url = "{Path(os.path.relpath(Path(source_file.name).resolve().as_posix(),
817+
Path(Path(lock_file.name).parent).resolve().as_posix())).as_posix()}"
818+
reference = "develop"
819+
resolved_reference = "123456"
820+
821+
[metadata]
822+
lock-version = "1.1"
823+
python-versions = "*"
824+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
825+
826+
[metadata.files]
827+
local-package = []
828+
"""
829+
830+
assert content == expected

0 commit comments

Comments
 (0)