diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tox/config/sets.py | 4 | ||||
-rw-r--r-- | src/tox/tox_env/python/virtual_env/package/pyproject.py | 21 | ||||
-rw-r--r-- | src/tox/tox_env/python/virtual_env/package/util.py | 2 | ||||
-rw-r--r-- | src/tox/util/file_view.py | 37 |
4 files changed, 58 insertions, 6 deletions
diff --git a/src/tox/config/sets.py b/src/tox/config/sets.py index c87701f8..0315369a 100644 --- a/src/tox/config/sets.py +++ b/src/tox/config/sets.py @@ -199,8 +199,8 @@ class CoreConfigSet(ConfigSet): self.add_config( keys=["temp_dir"], of_type=Path, - default=lambda conf, _: cast(Path, self["tox_root"]) / ".tmp", # noqa: U100, U101 - desc="temporary directory cleaned at start", + default=lambda conf, _: cast(Path, self["work_dir"]) / ".tmp", # noqa: U100, U101 + desc="a folder for temporary files (is not cleaned at start)", ) def _on_duplicate_conf(self, key: str, definition: ConfigDefinition[V]) -> None: # noqa: U100 diff --git a/src/tox/tox_env/python/virtual_env/package/pyproject.py b/src/tox/tox_env/python/virtual_env/package/pyproject.py index b9255c1c..de3a81c5 100644 --- a/src/tox/tox_env/python/virtual_env/package/pyproject.py +++ b/src/tox/tox_env/python/virtual_env/package/pyproject.py @@ -30,6 +30,7 @@ from tox.tox_env.python.package import ( ) from tox.tox_env.register import ToxEnvRegister from tox.tox_env.runner import RunToxEnv +from tox.util.file_view import create_session_view from ..api import VirtualEnv from .util import dependencies_with_extras @@ -99,6 +100,7 @@ class Pep517VirtualEnvPackager(PythonPackageToxEnv, VirtualEnv): self._package_name: str | None = None self._pkg_lock = RLock() # can build only one package at a time self.root = self.conf["package_root"] + self._package_paths: set[Path] = set() @staticmethod def id() -> str: @@ -164,6 +166,10 @@ class Pep517VirtualEnvPackager(PythonPackageToxEnv, VirtualEnv): pass finally: executor.close() + for path in self._package_paths: + if path.exists(): + logging.debug("delete package %s", path) + path.unlink() super()._teardown() def perform_packaging(self, for_env: EnvConfigSet) -> list[Package]: @@ -189,7 +195,10 @@ class Pep517VirtualEnvPackager(PythonPackageToxEnv, VirtualEnv): elif of_type == "sdist": self.setup() with self._pkg_lock: - package = SdistPackage(self._frontend.build_sdist(sdist_directory=self.pkg_dir).sdist, deps) + sdist = self._frontend.build_sdist(sdist_directory=self.pkg_dir).sdist + sdist = create_session_view(sdist, self._package_temp_path) + self._package_paths.add(sdist) + package = SdistPackage(sdist, deps) elif of_type in {"wheel", "editable"}: w_env = self._wheel_build_envs.get(for_env["wheel_build_env"]) if w_env is not None and w_env is not self: @@ -199,16 +208,22 @@ class Pep517VirtualEnvPackager(PythonPackageToxEnv, VirtualEnv): self.setup() method = "build_editable" if of_type == "editable" else "build_wheel" with self._pkg_lock: - path = getattr(self._frontend, method)( + wheel = getattr(self._frontend, method)( wheel_directory=self.pkg_dir, metadata_directory=self.meta_folder, config_settings=self._wheel_config_settings, ).wheel - package = (EditablePackage if of_type == "editable" else WheelPackage)(path, deps) + wheel = create_session_view(wheel, self._package_temp_path) + self._package_paths.add(wheel) + package = (EditablePackage if of_type == "editable" else WheelPackage)(wheel, deps) else: # pragma: no cover # for when we introduce new packaging types and don't implement raise TypeError(f"cannot handle package type {of_type}") # pragma: no cover return [package] + @property + def _package_temp_path(self) -> Path: + return cast(Path, self.core["temp_dir"]) / "package" + def _load_deps(self, for_env: EnvConfigSet) -> list[Requirement]: # first check if this is statically available via PEP-621 deps = self._load_deps_from_static(for_env) diff --git a/src/tox/tox_env/python/virtual_env/package/util.py b/src/tox/tox_env/python/virtual_env/package/util.py index 9936c7f2..5139e7ba 100644 --- a/src/tox/tox_env/python/virtual_env/package/util.py +++ b/src/tox/tox_env/python/virtual_env/package/util.py @@ -2,7 +2,7 @@ from __future__ import annotations from copy import deepcopy -from packaging.markers import Variable +from packaging.markers import Variable # type: ignore[attr-defined] from packaging.requirements import Requirement diff --git a/src/tox/util/file_view.py b/src/tox/util/file_view.py new file mode 100644 index 00000000..488d9aa8 --- /dev/null +++ b/src/tox/util/file_view.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import logging +import os +import shutil +from itertools import chain +from os.path import commonpath +from pathlib import Path + + +def create_session_view(package: Path, temp_path: Path) -> Path: + """Allows using the file after you no longer holding a lock to it by moving it into a temp folder""" + # we'll number the active instances, and use the max value as session folder for a new build + # note we cannot change package names as PEP-491 (wheel binary format) + # is strict about file name structure + + temp_path.mkdir(parents=True, exist_ok=True) + exists = [i.name for i in temp_path.iterdir()] + file_id = max(chain((0,), (int(i) for i in exists if str(i).isnumeric()))) + session_dir = temp_path / str(file_id + 1) + session_dir.mkdir() + session_package = session_dir / package.name + + links = False # if we can do hard links do that, otherwise just copy + if hasattr(os, "link"): + try: + os.link(package, session_package) + links = True + except (OSError, NotImplementedError): + pass + if not links: + shutil.copyfile(package, session_package) + operation = "links" if links else "copied" + common = commonpath((session_package, package)) + rel_session, rel_package = session_package.relative_to(common), package.relative_to(common) + logging.debug("package %s %s to %s (%s)", rel_session, operation, rel_package, common) + return session_package |