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

Make sure all wheel have same min requirements #386

Merged
merged 4 commits into from
Jun 16, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion builder/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
)
from builder.upload import run_upload
from builder.utils import check_url
from builder.wheel import copy_wheels_from_cache, run_auditwheel
from builder.wheel import (
copy_wheels_from_cache,
run_auditwheel,
fix_wheels_unmatch_requirements,
)


@click.command("builder")
Expand Down Expand Up @@ -174,6 +178,18 @@ def builder(

run_auditwheel(wheels_dir)

# Check if all wheels are on our min requirements
if package_wrong := fix_wheels_unmatch_requirements(wheels_dir):
for package, version in package_wrong.items():
build_wheels_package(
f"{package}=={str(version)}",
wheels_index,
wheels_dir,
package,
timeout,
)
run_auditwheel(wheels_dir)

if skip_binary != ":none:":
# Some wheels that already exist should not be overwritten in case we replace with
# a wheel that came from pypi rather than a wheel built from source with extra flags.
Expand Down
33 changes: 30 additions & 3 deletions builder/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
import re
import shutil
from tempfile import TemporaryDirectory
from typing import Dict, Final

from awesomeversion import AwesomeVersion

from .utils import run_command, build_arch, build_abi, alpine_version


_RE_LINUX_PLATFORM = re.compile(r"-linux_\w+\.whl$")
_RE_MUSLLINUX_PLATFORM = re.compile(
_RE_PACKAGE_FULL: Final = re.compile(
r"^(?P<namever>(?P<name>.+?)-(?P<ver>.+?))(-(?P<build>\d[^-]*))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?)\.whl$"
)
_RE_LINUX_PLATFORM: Final = re.compile(r"-linux_\w+\.whl$")
_RE_MUSLLINUX_PLATFORM: Final = re.compile(
r"-musllinux_(?P<major>\d)_(?P<minor>\d)_(?P<arch>\w+)\.whl$"
)

Expand All @@ -26,7 +32,7 @@

def check_abi_platform(abi: str, platform: str) -> bool:
"""Return True if abi and platform work."""
arch = build_arch()
arch = _ARCH_PLAT[build_arch()]
sys_abi = build_abi()
sys_platform = _ALPINE_PLATFORM[alpine_version()]

Expand All @@ -45,6 +51,27 @@ def check_abi_platform(abi: str, platform: str) -> bool:
return True


def fix_wheels_unmatch_requirements(wheels_folder: Path) -> Dict[str, AwesomeVersion]:
"""Check Wheels against our min requirements."""
result = {}
for wheel_file in wheels_folder.glob("*.whl"):
package = _RE_PACKAGE_FULL.fullmatch(wheel_file.name)
if not package:
raise RuntimeError(f"Error on parse wheel {wheel_file.name}")

if check_abi_platform(package["abi"], package["plat"]):
continue

print(
f"Found wheel {wheel_file.name} that not match our min requirements",
flush=True,
)
result[package["name"]] = AwesomeVersion(package["ver"])
wheel_file.unlink()

return result


def copy_wheels_from_cache(cache_folder: Path, wheels_folder: Path) -> None:
"""Preserve wheels from cache on timeout error."""
for wheel_file in cache_folder.glob("**/*.whl"):
Expand Down
1 change: 1 addition & 0 deletions requirements_wheels_test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
requests==2.28.0
cchardet==2.1.7
Brotli==1.0.9
14 changes: 10 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Common test functions."""
from pathlib import Path
from unittest.mock import patch

import pytest
Expand All @@ -9,11 +10,11 @@
# versions to exercise different corner cases.
TEST_INDEX_FILES = [
"aiohttp-3.6.0-cp310-cp310-musllinux_1_2_i686.whl",
"aiohttp-3.6.1-cp310-cp310-musllinux_1_2_amd64.whl",
"aiohttp-3.7.3-cp310-cp310-musllinux_1_2_amd64.whl",
"aiohttp-3.7.4-cp310-cp310-musllinux_1_2_amd64.whl",
"aiohttp-3.6.1-cp310-cp310-musllinux_1_2_x86_64.whl",
"aiohttp-3.7.3-cp310-cp310-musllinux_1_2_x86_64.whl",
"aiohttp-3.7.4-cp310-cp310-musllinux_1_2_x86_64.whl",
"google_cloud_pubsub-2.1.0-py2.py3-none-any.whl",
"grpcio-1.31.0-cp310-cp310-musllinux_1_2_amd64.whl",
"grpcio-1.31.0-cp310-cp310-musllinux_1_2_x86_64.whl",
"aioconsole-0.4.1-py3-none-any.whl",
"aioconsole-0.4.2-py3-none-any.whl",
]
Expand Down Expand Up @@ -58,3 +59,8 @@ def sys_alpine():
"builder.wheel.alpine_version", return_value=("3", "16")
):
yield


@pytest.fixture
def tmppath(tmpdir):
return Path(tmpdir)
17 changes: 5 additions & 12 deletions tests/test_infra.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""Tests for infra module."""
from pathlib import Path

import pytest

from builder import infra


Expand Down Expand Up @@ -146,21 +144,16 @@ def test_check_available_binary_for_missing_constraint() -> None:
)


@pytest.fixture
def tmppath(tmpdir):
return Path(tmpdir)


def test_remove_local_wheel(tmppath: Path) -> None:
"""Test removing an existing wheel."""
package_index = infra.extract_packages_from_index("https://example.com")

p = tmppath / "google_cloud_pubsub-2.9.0-py2.py3-none-any.whl"
p.touch()
p = tmppath / "grpcio-1.31.0-cp310-cp310-musllinux_1_2_amd64.whl"
p = tmppath / "grpcio-1.31.0-cp310-cp310-musllinux_1_2_x86_64.whl"
p.touch()
assert {p.name for p in tmppath.glob("*.whl")} == {
"grpcio-1.31.0-cp310-cp310-musllinux_1_2_amd64.whl",
"grpcio-1.31.0-cp310-cp310-musllinux_1_2_x86_64.whl",
"google_cloud_pubsub-2.9.0-py2.py3-none-any.whl",
}

Expand All @@ -186,10 +179,10 @@ def test_remove_local_wheel_preserves_newer(tmppath: Path) -> None:

p = tmppath / "google_cloud_pubsub-2.9.0-py2.py3-none-any.whl"
p.touch()
p = tmppath / "grpcio-1.43.0-cp310-cp310-musllinux_1_2_amd64.whl"
p = tmppath / "grpcio-1.43.0-cp310-cp310-musllinux_1_2_x86_64.whl"
p.touch()
assert {p.name for p in tmppath.glob("*.whl")} == {
"grpcio-1.43.0-cp310-cp310-musllinux_1_2_amd64.whl",
"grpcio-1.43.0-cp310-cp310-musllinux_1_2_x86_64.whl",
"google_cloud_pubsub-2.9.0-py2.py3-none-any.whl",
}

Expand All @@ -205,6 +198,6 @@ def test_remove_local_wheel_preserves_newer(tmppath: Path) -> None:

# grpc is removed
assert {p.name for p in tmppath.glob("*.whl")} == {
"grpcio-1.43.0-cp310-cp310-musllinux_1_2_amd64.whl",
"grpcio-1.43.0-cp310-cp310-musllinux_1_2_x86_64.whl",
"google_cloud_pubsub-2.9.0-py2.py3-none-any.whl",
}
28 changes: 25 additions & 3 deletions tests/test_wheel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Tests for pip module."""
from pathlib import Path

import pytest

from builder import wheel
Expand Down Expand Up @@ -60,7 +62,7 @@ def test_linux_regex_wrong(test):
@pytest.mark.parametrize(
"abi,platform",
[
("cp310", "musllinux_1_2_amd64"),
("cp310", "musllinux_1_2_x86_64"),
("none", "any"),
],
)
Expand All @@ -72,11 +74,31 @@ def test_working_abi_platform(abi, platform):
@pytest.mark.parametrize(
"abi,platform",
[
("cp311", "musllinux_1_2_amd64"),
("cp311", "musllinux_1_2_x86_64"),
("cp310", "musllinux_1_2_i686"),
("cp310", "musllinux_1_1_amd64"),
("cp310", "musllinux_1_1_x86_64"),
],
)
def test_not_working_abi_platform(abi, platform):
"""Test not working abi/platform variations."""
assert not wheel.check_abi_platform(abi, platform)


def test_fix_wheel_unmatch(tmppath: Path) -> None:
"""Test removing an existing wheel that are not match requirements."""

p = tmppath / "google_cloud_pubsub-2.9.0-py2.py3-none-any.whl"
p.touch()
p = tmppath / "grpcio-1.31.0-cp310-cp310-musllinux_1_1_x86_64.whl"
p.touch()
assert {p.name for p in tmppath.glob("*.whl")} == {
"grpcio-1.31.0-cp310-cp310-musllinux_1_1_x86_64.whl",
"google_cloud_pubsub-2.9.0-py2.py3-none-any.whl",
}

assert wheel.fix_wheels_unmatch_requirements(tmppath) == {"grpcio": "1.31.0"}

# grpc is removed
assert {p.name for p in tmppath.glob("*.whl")} == {
"google_cloud_pubsub-2.9.0-py2.py3-none-any.whl",
}