Skip to content

Commit

Permalink
Prevent copying tmp dir to itself in build backend
Browse files Browse the repository at this point in the history
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 <miro@hroncok.cz>
  • Loading branch information
webknjaz and hroncok committed May 31, 2024
1 parent ba0797c commit 89c9b3a
Showing 1 changed file with 35 additions and 2 deletions.
37 changes: 35 additions & 2 deletions packaging/pep517_backend/_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 89c9b3a

Please sign in to comment.