feat: adding overrides

This commit is contained in:
Henry Schreiner
2021-10-16 21:34:02 -04:00
parent f511961b40
commit cd07697fe5
13 changed files with 405 additions and 89 deletions
+70 -12
View File
@@ -1,9 +1,10 @@
import copy
import os
import sys
import traceback
from configparser import ConfigParser
from pathlib import Path
from typing import Any, Dict, List, Mapping, Optional, Set, Tuple, Union
from typing import Any, Dict, List, Mapping, Optional, Set, Tuple, TypeVar, Union
import tomli
from packaging.specifiers import SpecifierSet
@@ -58,6 +59,9 @@ def _dig_first(*pairs: Tuple[Mapping[str, Setting], str], ignore_empty: bool = F
raise KeyError(key)
T = TypeVar("T", bound="ConfigOptions")
class ConfigOptions:
"""
Gets options from the environment, config or defaults, optionally scoped
@@ -117,12 +121,27 @@ class ConfigOptions:
self.config_options = config_options
self.config_platform_options = config_platform_options
self.overrides: Dict[str, Dict[str, Any]] = {}
self.current_override: str = "*"
overrides = self.config_options.get("overrides")
if overrides is not None:
if not isinstance(overrides, list):
raise ConfigOptionError('"tool.cibuildwheel.overrides" must be a list')
for override in overrides:
selector = override.pop("select")
if isinstance(selector, list):
selector = " ".join(selector)
if selector in {"", "*"}:
raise ConfigOptionError("select all must not be used in an override")
self.overrides[selector.strip()] = override
def _is_valid_global_option(self, name: str) -> bool:
"""
Returns True if an option with this name is allowed in the
[tool.cibuildwheel] section of a config file.
"""
allowed_option_names = self.default_options.keys() | PLATFORMS
allowed_option_names = self.default_options.keys() | PLATFORMS | {"overrides"}
return name in allowed_option_names
@@ -151,6 +170,14 @@ class ConfigOptions:
return global_options, platform_options
def override(self: T, selector: str) -> T:
"""
Start an override scope.
"""
other = copy.copy(self)
other.current_override = selector
return other
def __call__(
self,
name: str,
@@ -179,9 +206,11 @@ class ConfigOptions:
# get the option from the environment, then the config file, then finally the default.
# platform-specific options are preferred, if they're allowed.
empty: Dict[str, Any] = {}
result = _dig_first(
(os.environ if env_plat else {}, plat_envvar), # type: ignore[arg-type]
(os.environ, envvar),
(self.overrides.get(self.current_override, empty), name),
(self.config_platform_options, name),
(self.config_options, name),
(self.default_platform_options, name),
@@ -210,7 +239,7 @@ def compute_options(
config_file: Optional[str],
args_archs: Optional[str],
prerelease_pythons: bool,
) -> BuildOptions:
) -> Tuple[BuildOptions, Dict[str, BuildOptions]]:
"""
Compute the options from the environment and configuration file.
"""
@@ -263,11 +292,25 @@ def compute_options(
)
test_selector = TestSelector(skip_config=test_skip)
return _compute_single_options(
return _compute_all_options(
options, args_archs, build_selector, test_selector, platform, package_dir, output_dir
)
def _get_pinned_docker_images() -> Mapping[str, Mapping[str, str]]:
"""
This looks like a dict of dicts, e.g.
{ 'x86_64': {'manylinux1': '...', 'manylinux2010': '...', 'manylinux2014': '...'},
'i686': {'manylinux1': '...', 'manylinux2010': '...', 'manylinux2014': '...'},
'pypy_x86_64': {'manylinux2010': '...' }
... }
"""
pinned_docker_images_file = resources_dir / "pinned_docker_images.cfg"
all_pinned_docker_images = ConfigParser()
all_pinned_docker_images.read(pinned_docker_images_file)
return all_pinned_docker_images
def _compute_single_options(
options: ConfigOptions,
args_archs: Optional[str],
@@ -337,14 +380,7 @@ def _compute_single_options(
manylinux_images: Dict[str, str] = {}
musllinux_images: Dict[str, str] = {}
if platform == "linux":
pinned_docker_images_file = resources_dir / "pinned_docker_images.cfg"
all_pinned_docker_images = ConfigParser()
all_pinned_docker_images.read(pinned_docker_images_file)
# all_pinned_docker_images looks like a dict of dicts, e.g.
# { 'x86_64': {'manylinux1': '...', 'manylinux2010': '...', 'manylinux2014': '...'},
# 'i686': {'manylinux1': '...', 'manylinux2010': '...', 'manylinux2014': '...'},
# 'pypy_x86_64': {'manylinux2010': '...' }
# ... }
all_pinned_docker_images = _get_pinned_docker_images()
for build_platform in MANYLINUX_ARCHS:
pinned_images = all_pinned_docker_images[build_platform]
@@ -359,6 +395,7 @@ def _compute_single_options(
else:
image = config_value
assert image is not None
manylinux_images[build_platform] = image
for build_platform in MUSLLINUX_ARCHS:
@@ -397,6 +434,27 @@ def _compute_single_options(
)
def _compute_all_options(
options: ConfigOptions,
args_archs: Optional[str],
build_selector: BuildSelector,
test_selector: TestSelector,
platform: PlatformName,
package_dir: Path,
output_dir: Path,
) -> Tuple[BuildOptions, Dict[str, BuildOptions]]:
args = (args_archs, build_selector, test_selector, platform, package_dir, output_dir)
general_build_options = _compute_single_options(options, *args)
selectors = options.overrides.keys()
build_options_by_selector = {
s: _compute_single_options(options.override(s), *args) for s in selectors
}
return general_build_options, build_options_by_selector
def deprecated_selectors(name: str, selector: str, *, error: bool = False) -> None:
if "p2" in selector or "p35" in selector:
msg = f"cibuildwheel 2.x no longer supports Python < 3.6. Please use the 1.x series or update {name}"