Skip to content

Commit

Permalink
locker: lock transitive marker and groups for each package
Browse files Browse the repository at this point in the history
  • Loading branch information
radoering committed Apr 20, 2024
1 parent 2ad0d93 commit 4339150
Show file tree
Hide file tree
Showing 42 changed files with 1,098 additions and 221 deletions.
35 changes: 20 additions & 15 deletions src/poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@

from cleo.io.io import IO
from packaging.utils import NormalizedName
from poetry.core.packages.package import Package
from poetry.core.packages.path_dependency import PathDependency
from poetry.core.packages.project_package import ProjectPackage

from poetry.config.config import Config
from poetry.installation.operations.operation import Operation
from poetry.packages import Locker
from poetry.puzzle.solver import SolverPackageInfo
from poetry.utils.env import Env


Expand Down Expand Up @@ -198,12 +200,9 @@ def _do_refresh(self) -> int:
with solver.provider.use_source_root(
source_root=self._env.path.joinpath("src")
):
ops = solver.solve(use_latest=use_latest).calculate_operations()
solved_packages = solver.solve(use_latest=use_latest).get_solved_packages()

lockfile_repo = LockfileRepository()
self._populate_lockfile_repo(lockfile_repo, ops)

self._write_lock_file(lockfile_repo, force=True)
self._write_lock_file(solved_packages, force=True)

return 0

Expand Down Expand Up @@ -238,7 +237,14 @@ def _do_install(self) -> int:
with solver.provider.use_source_root(
source_root=self._env.path.joinpath("src")
):
ops = solver.solve(use_latest=self._whitelist).calculate_operations()
solution = solver.solve(use_latest=self._whitelist)
solved_packages = solution.get_solved_packages()
ops = solution.calculate_operations()

if not self.executor.enabled:
# If we are only in lock mode, no need to go any further
self._write_lock_file(solved_packages)
return 0
else:
self._io.write_line("<info>Installing dependencies from lock file</>")

Expand Down Expand Up @@ -266,11 +272,6 @@ def _do_install(self) -> int:
lockfile_repo = LockfileRepository()
uninstalls = self._populate_lockfile_repo(lockfile_repo, ops)

if not self.executor.enabled:
# If we are only in lock mode, no need to go any further
self._write_lock_file(lockfile_repo)
return 0

if self._groups is not None:
root = self._package.with_dependency_groups(list(self._groups), only=True)
else:
Expand Down Expand Up @@ -311,7 +312,7 @@ def _do_install(self) -> int:

transaction = Transaction(
locked_repository.packages,
[(package, 0) for package in lockfile_repo.packages],
lockfile_repo.packages,
installed_packages=self._installed_repository.packages,
root_package=root,
)
Expand Down Expand Up @@ -341,13 +342,17 @@ def _do_install(self) -> int:

if status == 0 and self._update:
# Only write lock file when installation is success
self._write_lock_file(lockfile_repo)
self._write_lock_file(solved_packages)

return status

def _write_lock_file(self, repo: LockfileRepository, force: bool = False) -> None:
def _write_lock_file(
self,
packages: dict[Package, SolverPackageInfo],
force: bool = False,
) -> None:
if not self.is_dry_run() and (force or self._update):
updated_lock = self._locker.set_lock_data(self._package, repo.packages)
updated_lock = self._locker.set_lock_data(self._package, packages)

if updated_lock:
self._io.write_line("")
Expand Down
31 changes: 24 additions & 7 deletions src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from poetry.core.packages.vcs_dependency import VCSDependency
from tomlkit.toml_document import TOMLDocument

from poetry.puzzle.solver import SolverPackageInfo
from poetry.repositories.lockfile_repository import LockfileRepository

logger = logging.getLogger(__name__)
Expand All @@ -50,7 +51,7 @@


class Locker:
_VERSION = "2.0"
_VERSION = "2.1"
_READ_VERSION_RANGE = ">=1,<3"

_legacy_keys: ClassVar[list[str]] = [
Expand Down Expand Up @@ -248,7 +249,9 @@ def locked_repository(self) -> LockfileRepository:

return repository

def set_lock_data(self, root: Package, packages: list[Package]) -> bool:
def set_lock_data(
self, root: Package, packages: dict[Package, SolverPackageInfo]
) -> bool:
"""Store lock data and eventually persist to the lock file"""
lock = self._compute_lock_data(root, packages)

Expand All @@ -259,7 +262,7 @@ def set_lock_data(self, root: Package, packages: list[Package]) -> bool:
return False

def _compute_lock_data(
self, root: Package, packages: list[Package]
self, root: Package, packages: dict[Package, SolverPackageInfo]
) -> TOMLDocument:
package_specs = self._lock_packages(packages)
# Retrieving hashes
Expand Down Expand Up @@ -368,7 +371,9 @@ def _get_lock_data(self) -> dict[str, Any]:

return lock_data

def _lock_packages(self, packages: list[Package]) -> list[dict[str, Any]]:
def _lock_packages(
self, packages: dict[Package, SolverPackageInfo]
) -> list[dict[str, Any]]:
locked = []

for package in sorted(
Expand All @@ -383,13 +388,15 @@ def _lock_packages(self, packages: list[Package]) -> list[dict[str, Any]]:
x.source_resolved_reference or "",
),
):
spec = self._dump_package(package)
spec = self._dump_package(package, packages[package])

locked.append(spec)

return locked

def _dump_package(self, package: Package) -> dict[str, Any]:
def _dump_package(
self, package: Package, solver_info: SolverPackageInfo
) -> dict[str, Any]:
dependencies: dict[str, list[Any]] = {}
for dependency in sorted(
package.requires,
Expand Down Expand Up @@ -459,8 +466,18 @@ def _dump_package(self, package: Package) -> dict[str, Any]:
"description": package.description or "",
"optional": package.optional,
"python-versions": package.python_versions,
"files": sorted(package.files, key=lambda x: x["file"]),
"groups": sorted(solver_info.groups, key=lambda x: (x != "main", x)),
}
if solver_info.transitive_marker:
if len(markers := set(solver_info.transitive_marker.values())) == 1:
if not (marker := next(iter(markers))).is_any():
data["marker"] = str(marker)
else:
data["marker"] = inline_table()
for k, v in solver_info.transitive_marker.items():
if not v.is_any():
data["marker"][k] = str(v)
data["files"] = sorted(package.files, key=lambda x: x["file"])

if dependencies:
data["dependencies"] = table()
Expand Down
1 change: 1 addition & 0 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ def complete_package(
package = dependency_package.package
dependency = dependency_package.dependency
new_dependency = package.without_features().to_dependency()
new_dependency.marker = AnyMarker()

# When adding dependency foo[extra] -> foo, preserve foo's source, if it's
# specified. This prevents us from trying to get foo from PyPI
Expand Down
Loading

0 comments on commit 4339150

Please sign in to comment.