Skip to content
Closed
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
25 changes: 4 additions & 21 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,47 +71,30 @@ runs:
shutil.rmtree(venv_path)
builder = EnvBuilder()
builder.create(venv_path)
exposed_binaries = {"cibuildwheel"}
if "uv" in EXTRAS:
exposed_binaries.add("uv")
clean_bin_path = builder.bin_path.parent / f"{builder.bin_path.name}.clean"
clean_bin_path.mkdir()
for path in list(builder.bin_path.iterdir()):
if path.stem in exposed_binaries:
try:
os.symlink(path, clean_bin_path / path.name)
except OSError:
import shutil

shutil.copy2(path, clean_bin_path / path.name)
full_path = f"{clean_bin_path}{os.pathsep}{os.environ['PATH']}"
cibw_path = [path for path in builder.bin_path.glob("cibuildwheel*") if path.stem == "cibuildwheel"][0]
with open(os.environ["GITHUB_OUTPUT"], "at") as f:
f.write(f"updated-path={full_path}\n")
f.write(f"cibw-path={cibw_path}\n")
print("::endgroup::")
EOF
shell: bash

# Redirecting stderr to stdout to fix interleaving issue in Actions.
- run: >
cibuildwheel
"${{ steps.cibw.outputs.cibw-path }}"
"${{ inputs.package-dir }}"
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
2>&1
env:
PATH: "${{ steps.cibw.outputs.updated-path }}"
shell: bash
if: runner.os != 'Windows'

# Windows needs powershell to interact nicely with Meson
- run: >
cibuildwheel
& "${{ steps.cibw.outputs.cibw-path }}"
"${{ inputs.package-dir }}"
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
env:
PATH: "${{ steps.cibw.outputs.updated-path }}"
shell: pwsh
if: runner.os == 'Windows'
14 changes: 3 additions & 11 deletions cibuildwheel/platforms/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from ..util.helpers import prepare_command
from ..util.packaging import find_compatible_wheel
from ..util.python_build_standalone import create_python_build_standalone_environment
from ..venv import constraint_flags, find_uv, virtualenv
from ..venv import constraint_flags, virtualenv

ANDROID_TRIPLET = {
"arm64_v8a": "aarch64-linux-android",
Expand Down Expand Up @@ -191,11 +191,7 @@ def setup_env(
log.step("Setting up build environment...")
build_frontend = build_options.build_frontend.name
use_uv = build_frontend == "build[uv]"
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
raise AssertionError(msg)
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
pip = ["pip"] if not use_uv else ["uv", "pip"]

# Create virtual environment
python_exe = create_python_build_standalone_environment(
Expand Down Expand Up @@ -609,11 +605,7 @@ def test_wheel(state: BuildState, wheel: Path, *, build_frontend: str) -> None:

log.step("Testing wheel...")
use_uv = build_frontend == "build[uv]"
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
raise AssertionError(msg)
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
pip = ["pip"] if not use_uv else ["uv", "pip"]

native_arch = arch_synonym(platform.machine(), platforms.native_platform(), "android")
if state.config.arch != native_arch:
Expand Down
14 changes: 4 additions & 10 deletions cibuildwheel/platforms/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv
from ..venv import constraint_flags, virtualenv


@functools.cache
Expand Down Expand Up @@ -217,7 +217,6 @@ def setup_python(
environment: ParsedEnvironment,
build_frontend: BuildFrontendName,
) -> tuple[Path, dict[str, str]]:
uv_path = find_uv()
use_uv = build_frontend == "build[uv]"

tmp.mkdir()
Expand Down Expand Up @@ -370,14 +369,13 @@ def setup_python(
env=env,
)
case "build[uv]":
assert uv_path is not None
call(
uv_path,
"uv",
"pip",
"install",
"--upgrade",
"delocate",
"build[virtualenv, uv]",
"build",
*constraint_flags(dependency_constraint),
env=env,
)
Expand Down Expand Up @@ -414,11 +412,7 @@ def build(options: Options, tmp_path: Path) -> None:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend
use_uv = build_frontend.name == "build[uv]"
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
raise AssertionError(msg)
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
pip = ["pip"] if not use_uv else ["uv", "pip"]
log.build_start(config.identifier)

identifier_tmp_dir = tmp_path / config.identifier
Expand Down
8 changes: 3 additions & 5 deletions cibuildwheel/platforms/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv
from ..venv import constraint_flags, virtualenv


def get_nuget_args(
Expand Down Expand Up @@ -272,7 +272,6 @@ def setup_python(
build_frontend = "build"

use_uv = build_frontend == "build[uv]"
uv_path = find_uv()

log.step("Setting up build environment...")
venv_path = tmp / "venv"
Expand Down Expand Up @@ -323,13 +322,12 @@ def setup_python(
env=env,
)
case "build[uv]":
assert uv_path is not None
call(
uv_path,
"uv",
"pip",
"install",
"--upgrade",
"build[virtualenv]",
"build",
*constraint_flags(dependency_constraint),
env=env,
)
Expand Down
36 changes: 33 additions & 3 deletions cibuildwheel/venv.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import atexit
import contextlib
import functools
import os
import shutil
import sys
import tempfile
import tomllib
from collections.abc import Sequence
from pathlib import Path
Expand Down Expand Up @@ -107,8 +109,15 @@ def virtualenv(

assert python.exists()

paths = [str(venv_path), str(venv_path / "Scripts")] if _IS_WIN else [str(venv_path / "bin")]

if use_uv:
call("uv", "venv", venv_path, "--python", python)
uv_path = find_uv()
if uv_path is None:
msg = "Could not find 'uv' executable."
raise FileNotFoundError(msg)
call(uv_path, "venv", venv_path, "--python", python)
paths.insert(0, str(uv_path.parent.resolve(strict=True)))
else:
virtualenv_app, virtualenv_version = _ensure_virtualenv(version)
if pip_version is None:
Expand Down Expand Up @@ -137,7 +146,7 @@ def virtualenv(
python,
venv_path,
)
paths = [str(venv_path), str(venv_path / "Scripts")] if _IS_WIN else [str(venv_path / "bin")]

venv_env = os.environ.copy() if env is None else env.copy()
venv_env["PATH"] = os.pathsep.join([*paths, venv_env["PATH"]])
venv_env["VIRTUAL_ENV"] = str(venv_path)
Expand All @@ -156,7 +165,7 @@ def virtualenv(
return venv_env


def find_uv() -> Path | None:
def _find_uv() -> Path | None:
# Prefer uv in our environment
with contextlib.suppress(ImportError, FileNotFoundError):
from uv import find_uv_bin # noqa: PLC0415
Expand All @@ -165,3 +174,24 @@ def find_uv() -> Path | None:

uv_on_path = shutil.which("uv")
return Path(uv_on_path) if uv_on_path else None


@functools.cache
def find_uv() -> Path | None:
uv_path = _find_uv()
if uv_path is None:
return None

# we create a symlink or copy in a folder we can expose in PATH
# in order to never install build's `uv` extra
_tmp_uv_dir = Path(tempfile.mkdtemp(suffix="-uv"))
atexit.register(shutil.rmtree, _tmp_uv_dir, ignore_errors=True)
uv_dest = _tmp_uv_dir / uv_path.name
try:
uv_dest.symlink_to(uv_path)
except OSError:
if not _IS_WIN:
raise
shutil.copy(uv_path, uv_dest)

return uv_dest
Loading