Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
19 changes: 19 additions & 0 deletions cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ def main_inner(global_options: GlobalOptions) -> None:
help="Print the build identifiers matched by the current invocation and exit.",
)

parser.add_argument(
"--clean-cache",
action="store_true",
help="Clear the cibuildwheel cache and exit.",
)

parser.add_argument(
"--allow-empty",
action="store_true",
Expand All @@ -197,6 +203,19 @@ def main_inner(global_options: GlobalOptions) -> None:

global_options.print_traceback_on_error = args.debug_traceback

if args.clean_cache:
if CIBW_CACHE_PATH.exists():
print(f"Clearing cache directory: {CIBW_CACHE_PATH}")
try:
shutil.rmtree(CIBW_CACHE_PATH)
print("Cache cleared successfully.")
except OSError as e:
print(f"Error clearing cache: {e}", file=sys.stderr)
sys.exit(1)
else:
print(f"Cache directory does not exist: {CIBW_CACHE_PATH}")
sys.exit(0)

args.package_dir = args.package_dir.resolve()

# This are always relative to the base directory, even in SDist builds
Expand Down
2 changes: 2 additions & 0 deletions cibuildwheel/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class CommandLineArguments:
allow_empty: bool
debug_traceback: bool
enable: list[str]
clean_cache: bool

@classmethod
def defaults(cls) -> Self:
Expand All @@ -77,6 +78,7 @@ def defaults(cls) -> Self:
print_build_identifiers=False,
debug_traceback=False,
enable=[],
clean_cache=False,
)


Expand Down
68 changes: 68 additions & 0 deletions unit_test/main_tests/main_options_test.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import errno
import shutil
import sys
import tomllib
from fnmatch import fnmatch
from pathlib import Path

import pytest

import cibuildwheel.__main__ as main_module
from cibuildwheel.__main__ import main
from cibuildwheel.environment import ParsedEnvironment
from cibuildwheel.frontend import _split_config_settings
Expand Down Expand Up @@ -421,6 +424,71 @@ def test_debug_traceback(monkeypatch, method, capfd):
assert "Traceback (most recent call last)" in err


def test_clean_cache_when_cache_exists(tmp_path, monkeypatch, capfd):
monkeypatch.undo()
fake_cache_dir = (tmp_path / "cibw_cache").resolve()
monkeypatch.setattr(main_module, "CIBW_CACHE_PATH", fake_cache_dir)

fake_cache_dir.mkdir(parents=True, exist_ok=True)
assert fake_cache_dir.exists()

dummy_file = fake_cache_dir / "dummy.txt"
dummy_file.write_text("hello")

monkeypatch.setattr(sys, "argv", ["cibuildwheel", "--clean-cache"])

with pytest.raises(SystemExit) as e:
main()

assert e.value.code == 0

out, err = capfd.readouterr()
assert f"Clearing cache directory: {fake_cache_dir}" in out
assert "Cache cleared successfully." in out
assert not fake_cache_dir.exists()


def test_clean_cache_when_cache_does_not_exist(tmp_path, monkeypatch, capfd):
monkeypatch.undo()
fake_cache_dir = (tmp_path / "nonexistent_cache").resolve()
monkeypatch.setattr(main_module, "CIBW_CACHE_PATH", fake_cache_dir)

monkeypatch.setattr(sys, "argv", ["cibuildwheel", "--clean-cache"])

with pytest.raises(SystemExit) as e:
main()

assert e.value.code == 0

out, err = capfd.readouterr()
assert f"Cache directory does not exist: {fake_cache_dir}" in out


def test_clean_cache_with_error(tmp_path, monkeypatch, capfd):
monkeypatch.undo()
fake_cache_dir = (tmp_path / "cibw_cache").resolve()
monkeypatch.setattr(main_module, "CIBW_CACHE_PATH", fake_cache_dir)

fake_cache_dir.mkdir(parents=True, exist_ok=True)
assert fake_cache_dir.exists()

monkeypatch.setattr(sys, "argv", ["cibuildwheel", "--clean-cache"])

def fake_rmtree(path): # noqa: ARG001
raise OSError(errno.EACCES, "Permission denied")

monkeypatch.setattr(shutil, "rmtree", fake_rmtree)

with pytest.raises(SystemExit) as e:
main()

assert e.value.code == 1

out, err = capfd.readouterr()
assert f"Clearing cache directory: {fake_cache_dir}" in out
assert "Error clearing cache:" in err


@pytest.mark.parametrize("method", ["unset", "command_line", "env_var"])
def test_enable(method, intercepted_build_args, monkeypatch):
monkeypatch.delenv("CIBW_ENABLE", raising=False)
Expand Down