From 89c9b3a7dc4d7b5f75196a402ef4a6066d029284 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Fri, 31 May 2024 02:18:24 +0200 Subject: [PATCH] Prevent copying tmp dir to itself in build backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, setting `TMPDIR="$(pwd)/smth-inside"` would cause the in-tree PEP 517 build backend to go into infinite recursion, attempting to copy the project directory into a nested folder. Specifically, this is happening in the Fedora land because macros used in RPM packaging (`pyproject-rpm-macros`) are setting it up like this. Additionally, this is only happening with `pip wheel` and doesn't affect `pyproject-build`, because the latter pre-copies the project directory by itself early, and changes current working directory to it while the former does not. This patch addresses the issue by excluding the temporary directory from traversal when copying the directory tree within the build backend. Co-Authored-By: Miro HronĨok --- packaging/pep517_backend/_backend.py | 37 ++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/packaging/pep517_backend/_backend.py b/packaging/pep517_backend/_backend.py index c8e6fc93a..32ad45be0 100644 --- a/packaging/pep517_backend/_backend.py +++ b/packaging/pep517_backend/_backend.py @@ -7,6 +7,7 @@ import os import typing as t # noqa: WPS111 from contextlib import contextmanager, suppress +from functools import partial from pathlib import Path from shutil import copytree from sys import version_info as _python_version_tuple @@ -192,12 +193,44 @@ def _get_sanitized_long_description(self): # noqa: WPS430 _DistutilsDistributionMetadata.get_long_description = orig_func +def _exclude_dir_path( + excluded_dir_path: Path, + visited_directory: str, + _visited_dir_contents: list[str], +) -> list[str]: + """Prevent recursive directory traversal.""" + # This stops the temporary directory from being copied + # into self recursively forever. + # Ref: https://github.com/aio-libs/yarl/issues/992 + visited_directory_subdirs_to_ignore = [ + subdir + for subdir in _visited_dir_contents + if excluded_dir_path == Path(visited_directory) / subdir + ] + if visited_directory_subdirs_to_ignore: + print( + f'Preventing `{excluded_dir_path !s}` from being ' + 'copied into itself recursively...', + file=_standard_error_stream, + ) + return visited_directory_subdirs_to_ignore + + @contextmanager def _in_temporary_directory(src_dir: Path) -> t.Iterator[None]: with TemporaryDirectory(prefix='.tmp-ansible-pylibssh-pep517-') as tmp_dir: + tmp_dir_path = Path(tmp_dir) + root_tmp_dir_path = tmp_dir_path.parent + _exclude_tmpdir_parent = partial(_exclude_dir_path, root_tmp_dir_path) + with chdir_cm(tmp_dir): - tmp_src_dir = Path(tmp_dir) / 'src' - copytree(src_dir, tmp_src_dir, symlinks=True) + tmp_src_dir = tmp_dir_path / 'src' + copytree( + src_dir, + tmp_src_dir, + ignore=_exclude_tmpdir_parent, + symlinks=True, + ) os.chdir(tmp_src_dir) yield