Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

respect metadata_directory #487

Merged
merged 3 commits into from Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 6 additions & 15 deletions src/poetry/core/masonry/api.py
Expand Up @@ -39,20 +39,8 @@ def prepare_metadata_for_build_wheel(
) -> str:
poetry = Factory().create_poetry(Path(".").resolve(), with_groups=False)
builder = WheelBuilder(poetry)

dist_info = Path(metadata_directory, builder.dist_info)
dist_info.mkdir(parents=True, exist_ok=True)

if "scripts" in poetry.local_config or "plugins" in poetry.local_config:
with (dist_info / "entry_points.txt").open("w", encoding="utf-8") as f:
builder._write_entry_points(f)

with (dist_info / "WHEEL").open("w", encoding="utf-8") as f:
builder._write_wheel_file(f)

with (dist_info / "METADATA").open("w", encoding="utf-8") as f:
builder._write_metadata_file(f)

metadata_path = Path(metadata_directory)
dist_info = builder.prepare_metadata(metadata_path)
return dist_info.name


Expand All @@ -63,8 +51,11 @@ def build_wheel(
) -> str:
"""Builds a wheel, places it in wheel_directory"""
poetry = Factory().create_poetry(Path(".").resolve(), with_groups=False)
metadata_path = None if metadata_directory is None else Path(metadata_directory)

return WheelBuilder.make_in(poetry, Path(wheel_directory))
return WheelBuilder.make_in(
poetry, Path(wheel_directory), metadata_directory=metadata_path
)


def build_sdist(
Expand Down
80 changes: 55 additions & 25 deletions src/poetry/core/masonry/builders/wheel.py
Expand Up @@ -27,6 +27,7 @@
from poetry.core.masonry.utils.helpers import distribution_name
from poetry.core.masonry.utils.helpers import normalize_file_permissions
from poetry.core.masonry.utils.package_include import PackageInclude
from poetry.core.utils.helpers import temporary_directory


if TYPE_CHECKING:
Expand All @@ -53,6 +54,7 @@ def __init__(
original: Path | None = None,
executable: Path | None = None,
editable: bool = False,
metadata_directory: Path | None = None,
) -> None:
super().__init__(poetry, executable=executable)

Expand All @@ -61,6 +63,7 @@ def __init__(
if original:
self._original_path = original.parent
self._editable = editable
self._metadata_directory = metadata_directory

@classmethod
def make_in(
Expand All @@ -70,12 +73,14 @@ def make_in(
original: Path | None = None,
executable: Path | None = None,
editable: bool = False,
metadata_directory: Path | None = None,
) -> str:
wb = WheelBuilder(
poetry,
original=original,
executable=executable,
editable=editable,
metadata_directory=metadata_directory,
)
wb.build(target_dir=directory)

Expand Down Expand Up @@ -105,19 +110,25 @@ def build(
with os.fdopen(fd, "w+b") as fd_file, zipfile.ZipFile(
fd_file, mode="w", compression=zipfile.ZIP_DEFLATED
) as zip_file:
if not self._editable:
if not self._poetry.package.build_should_generate_setup():
self._build(zip_file)
self._copy_module(zip_file)
else:
self._copy_module(zip_file)
self._build(zip_file)
else:
if self._editable:
self._build(zip_file)
self._add_pth(zip_file)
elif self._poetry.package.build_should_generate_setup():
self._copy_module(zip_file)
self._build(zip_file)
else:
self._build(zip_file)
self._copy_module(zip_file)

self._copy_file_scripts(zip_file)
self._write_metadata(zip_file)

if self._metadata_directory is None:
with temporary_directory() as temp_dir:
metadata_directory = self.prepare_metadata(Path(temp_dir))
self._copy_dist_info(zip_file, metadata_directory)
else:
self._copy_dist_info(zip_file, self._metadata_directory)

self._write_record(zip_file)

wheel_path = target_dir / self.wheel_filename
Expand Down Expand Up @@ -225,33 +236,42 @@ def _copy_module(self, wheel: zipfile.ZipFile) -> None:
for file in sorted(to_add, key=lambda x: x.path):
self._add_file(wheel, file.path, file.relative_to_source_root())

def _write_metadata(self, wheel: zipfile.ZipFile) -> None:
def prepare_metadata(self, metadata_directory: Path) -> Path:
dist_info = metadata_directory / self.dist_info
dist_info.mkdir(parents=True, exist_ok=True)

if (
"scripts" in self._poetry.local_config
or "plugins" in self._poetry.local_config
):
with self._write_to_zip(wheel, self.dist_info + "/entry_points.txt") as f:
with (dist_info / "entry_points.txt").open(
"w", encoding="utf-8", newline="\n"
) as f:
self._write_entry_points(f)

license_files_to_add = []
with (dist_info / "WHEEL").open("w", encoding="utf-8", newline="\n") as f:
self._write_wheel_file(f)

with (dist_info / "METADATA").open("w", encoding="utf-8", newline="\n") as f:
self._write_metadata_file(f)

license_files = set()
for base in ("COPYING", "LICENSE"):
license_files_to_add.append(self._path / base)
license_files_to_add.extend(self._path.glob(base + ".*"))
license_files.add(self._path / base)
license_files.update(self._path.glob(base + ".*"))

license_files_to_add.extend(self._path.joinpath("LICENSES").glob("**/*"))
license_files.update(self._path.joinpath("LICENSES").glob("**/*"))

for path in set(license_files_to_add):
if path.is_file():
relative_path = f"{self.dist_info}/{path.relative_to(self._path)}"
self._add_file(wheel, path, relative_path)
else:
logger.debug(f"Skipping: {path.as_posix()}")
for license_file in license_files:
if not license_file.is_file():
logger.debug(f"Skipping: {license_file.as_posix()}")
continue

with self._write_to_zip(wheel, self.dist_info + "/WHEEL") as f:
self._write_wheel_file(f)
dest = dist_info / license_file.relative_to(self._path)
os.makedirs(dest.parent, exist_ok=True)
shutil.copy(license_file, dest)

with self._write_to_zip(wheel, self.dist_info + "/METADATA") as f:
self._write_metadata_file(f)
return dist_info

def _write_record(self, wheel: zipfile.ZipFile) -> None:
# Write a record of the files in the wheel
Expand All @@ -272,6 +292,16 @@ def _write_record(self, wheel: zipfile.ZipFile) -> None:

f.write(record.getvalue())

def _copy_dist_info(self, wheel: zipfile.ZipFile, source: Path) -> None:
dist_info = Path(self.dist_info)
for file in source.glob("**/*"):
if not file.is_file():
continue

rel_path = file.relative_to(source)
target = dist_info / rel_path
self._add_file(wheel, file, target)

@property
def dist_info(self) -> str:
return self.dist_info_name(self._package.name, self._meta.version)
Expand Down
9 changes: 6 additions & 3 deletions tests/masonry/builders/test_wheel.py
Expand Up @@ -180,17 +180,20 @@ def test_dist_info_file_permissions() -> None:

with zipfile.ZipFile(str(whl)) as z:
assert (
z.getinfo("my_package-1.2.3.dist-info/WHEEL").external_attr == 0o644 << 16
z.getinfo("my_package-1.2.3.dist-info/WHEEL").external_attr & 0x1FF0000
== 0o644 << 16
)
assert (
z.getinfo("my_package-1.2.3.dist-info/METADATA").external_attr
z.getinfo("my_package-1.2.3.dist-info/METADATA").external_attr & 0x1FF0000
== 0o644 << 16
)
assert (
z.getinfo("my_package-1.2.3.dist-info/RECORD").external_attr == 0o644 << 16
z.getinfo("my_package-1.2.3.dist-info/RECORD").external_attr & 0x1FF0000
== 0o644 << 16
)
assert (
z.getinfo("my_package-1.2.3.dist-info/entry_points.txt").external_attr
& 0x1FF0000
== 0o644 << 16
)

Expand Down
19 changes: 19 additions & 0 deletions tests/masonry/test_api.py
Expand Up @@ -235,3 +235,22 @@ def test_build_editable_wheel() -> None:

assert "my_package.pth" in namelist
assert pkg_dir.as_posix() == z.read("my_package.pth").decode().strip()


def test_build_wheel_with_metadata_directory() -> None:
with temporary_directory() as metadata_tmp_dir, cwd(
os.path.join(fixtures, "complete")
):
metadata_directory = api.prepare_metadata_for_build_wheel(metadata_tmp_dir)

with temporary_directory() as wheel_tmp_dir:
dist_info_path = Path(metadata_tmp_dir) / metadata_directory
filename = api.build_wheel(
wheel_tmp_dir, metadata_directory=str(dist_info_path)
)
validate_wheel_contents(
name="my_package",
version="1.2.3",
path=str(os.path.join(wheel_tmp_dir, filename)),
files=["entry_points.txt"],
)