Skip to content

Commit

Permalink
Resolve symlinks in locker.lock path to real physical paths (#5850)
Browse files Browse the repository at this point in the history
Fixes #5849
  • Loading branch information
spoorn authored Aug 3, 2022
1 parent 83e6c31 commit 62701fe
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,8 @@ def _dump_package(self, package: Package) -> dict[str, Any]:
# The lock file should only store paths relative to the root project
url = Path(
os.path.relpath(
Path(url).as_posix(), self._lock.path.parent.as_posix()
Path(url).resolve().as_posix(),
Path(self._lock.path.parent).resolve().as_posix(),
)
).as_posix()

Expand Down
90 changes: 90 additions & 0 deletions tests/packages/test_locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import json
import logging
import os
import sys
import tempfile
import uuid

Expand Down Expand Up @@ -753,3 +755,91 @@ def test_content_hash_with_legacy_is_compatible(
content_hash = locker._get_content_hash()

assert (content_hash == old_content_hash) or fresh


def test_lock_file_resolves_file_url_symlinks(root: ProjectPackage):
"""
Create directories and file structure as follows:
d1/
d1/testsymlink -> d1/d2/d3
d1/d2/d3/lock_file
d1/d4/source_file
Using the testsymlink as the Locker.lock file path should correctly resolve to
the real physical path of the source_file when calculating the relative path
from the lock_file, i.e. "../../d4/source_file" instead of the unresolved path
from the symlink itself which would have been "../d4/source_file"
See https://github.com/python-poetry/poetry/issues/5849
"""
with tempfile.TemporaryDirectory() as d1:
symlink_path = Path(d1).joinpath("testsymlink")
with tempfile.TemporaryDirectory(dir=d1) as d2, tempfile.TemporaryDirectory(
dir=d1
) as d4, tempfile.TemporaryDirectory(dir=d2) as d3, tempfile.NamedTemporaryFile(
dir=d4
) as source_file, tempfile.NamedTemporaryFile(
dir=d3
) as lock_file:
lock_file.close()
try:
os.symlink(Path(d3), symlink_path)
except OSError:
if sys.platform == "win32":
# os.symlink requires either administrative privileges or developer
# mode on Win10, throwing an OSError if neither is active.
# Test is not possible in that case.
return
raise
locker = Locker(str(symlink_path) + os.sep + Path(lock_file.name).name, {})

package_local = Package(
"local-package",
"1.2.3",
source_type="file",
source_url=source_file.name,
source_reference="develop",
source_resolved_reference="123456",
)
packages = [
package_local,
]

locker.set_lock_data(root, packages)

with locker.lock.open(encoding="utf-8") as f:
content = f.read()

expected = f"""\
[[package]]
name = "local-package"
version = "1.2.3"
description = ""
category = "main"
optional = false
python-versions = "*"
[package.source]
type = "file"
url = "{
Path(
os.path.relpath(
Path(source_file.name).resolve().as_posix(),
Path(Path(lock_file.name).parent).resolve().as_posix(),
)
).as_posix()
}"
reference = "develop"
resolved_reference = "123456"
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
local-package = []
"""

assert content == expected

0 comments on commit 62701fe

Please sign in to comment.