summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBernát Gábor <gaborjbernat@gmail.com>2022-12-07 16:21:41 -0800
committerGitHub <noreply@github.com>2022-12-07 16:21:41 -0800
commit2476e95b3f50b0f584ac17bc25eaaa77fb876671 (patch)
tree4e25587d335aae344d95fc90a13dc15b5e1767f7 /src
parent6305d9aa33d8b1e43d7c0aceaecf89233d0d17ee (diff)
downloadtox-git-2476e95b3f50b0f584ac17bc25eaaa77fb876671.tar.gz
Create session views of the build wheel/sdist into temp_dir (#2614)
Resolves https://github.com/tox-dev/tox/issues/2612
Diffstat (limited to 'src')
-rw-r--r--src/tox/config/sets.py4
-rw-r--r--src/tox/tox_env/python/virtual_env/package/pyproject.py21
-rw-r--r--src/tox/tox_env/python/virtual_env/package/util.py2
-rw-r--r--src/tox/util/file_view.py37
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