Skip to content
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: 18 additions & 0 deletions cibuildwheel/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,21 @@ def __init__(self) -> None:
)
super().__init__(message)
self.return_code = 8


class RepairStepProducedMultipleWheelsError(FatalError):
def __init__(self, wheels: list[str]) -> None:
message = textwrap.dedent(
f"""
Build failed because the repair step completed successfully but
produced multiple wheels: {wheels}

Your `repair-wheel-command` is expected to place one repaired
wheel in the {{dest_dir}} directory. See the documentation for
example configurations:

https://cibuildwheel.pypa.io/en/stable/options/#repair-wheel-command
"""
)
super().__init__(message)
self.return_code = 8
34 changes: 14 additions & 20 deletions cibuildwheel/platforms/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def build_in_container(
print(
f"\nFound previously built wheel {compatible_wheel.name}, that's compatible with {config.identifier}. Skipping build step..."
)
repaired_wheels = [compatible_wheel]
repaired_wheel = compatible_wheel
else:
if build_options.before_build:
log.step("Running before_build...")
Expand Down Expand Up @@ -325,14 +325,16 @@ def build_in_container(
else:
container.call(["mv", built_wheel, repaired_wheel_dir])

repaired_wheels = container.glob(repaired_wheel_dir, "*.whl")
match container.glob(repaired_wheel_dir, "*.whl"):
case []:
raise errors.RepairStepProducedNoWheelError()
case [repaired_wheel]:
pass
case too_many:
raise errors.RepairStepProducedMultipleWheelsError([p.name for p in too_many])

if not repaired_wheels:
raise errors.RepairStepProducedNoWheelError()

for repaired_wheel in repaired_wheels:
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)

if build_options.test_command and build_options.test_selector(config.identifier):
log.step("Testing wheel...")
Expand Down Expand Up @@ -374,14 +376,8 @@ def build_in_container(
container.call(["sh", "-c", before_test_prepared], env=virtualenv_env)

# Install the wheel we just built
# Note: If auditwheel produced two wheels, it's because the earlier produced wheel
# conforms to multiple manylinux standards. These multiple versions of the wheel are
# functionally the same, differing only in name, wheel metadata, and possibly include
# different external shared libraries. so it doesn't matter which one we run the tests on.
# Let's just pick the first one.
wheel_to_test = repaired_wheels[0]
container.call(
[*pip, "install", str(wheel_to_test) + build_options.test_extras],
[*pip, "install", str(repaired_wheel) + build_options.test_extras],
env=virtualenv_env,
)

Expand All @@ -394,7 +390,7 @@ def build_in_container(
build_options.test_command,
project=container_project_path,
package=container_package_dir,
wheel=wheel_to_test,
wheel=repaired_wheel,
)

test_cwd = testing_temp_dir / "test_cwd"
Expand All @@ -420,10 +416,8 @@ def build_in_container(
# move repaired wheels to output
if compatible_wheel is None:
container.call(["mkdir", "-p", container_output_dir])
container.call(["mv", *repaired_wheels, container_output_dir])
built_wheels.extend(
container_output_dir / repaired_wheel.name for repaired_wheel in repaired_wheels
)
container.call(["mv", repaired_wheel, container_output_dir])
built_wheels.append(container_output_dir / repaired_wheel.name)

log.build_end()

Expand Down