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
+129 -2
View File
@@ -1,4 +1,5 @@
import contextlib
import dataclasses
import fnmatch
import itertools
import os
@@ -9,10 +10,23 @@ import sys
import textwrap
import time
import urllib.request
from collections import defaultdict
from enum import Enum
from pathlib import Path
from time import sleep
from typing import Dict, Iterator, List, NamedTuple, Optional, Set
from typing import (
Counter,
Dict,
Iterable,
Iterator,
List,
Mapping,
NamedTuple,
Optional,
Set,
Tuple,
TypeVar,
)
import bracex
import certifi
@@ -22,7 +36,7 @@ from packaging.version import Version
from .architecture import Architecture
from .environment import ParsedEnvironment
from .typing import Literal, PathOrStr, PlatformName
from .typing import Literal, PathOrStr, PlatformName, Protocol
resources_dir = Path(__file__).parent / "resources"
@@ -250,6 +264,119 @@ class BuildOptions(NamedTuple):
return "\n".join(res)
class SimpleConfig(Protocol):
@property
def identifier(self) -> str:
...
SC = TypeVar("SC", bound=SimpleConfig)
T = TypeVar("T", bound="AllBuildOptions")
@dataclasses.dataclass
class AllBuildOptions:
general_build_options: BuildOptions
build_options_by_selector: Dict[str, BuildOptions]
identifiers: List[str]
def __getitem__(self, identifier: str) -> BuildOptions:
for sel in self.build_options_by_selector:
bs = BuildSelector(build_config=sel, skip_config="")
if bs(identifier):
return self.build_options_by_selector[sel]
return self.general_build_options
def values(self) -> Iterable[BuildOptions]:
return itertools.chain(
[self.general_build_options], self.build_options_by_selector.values()
)
# These values are not overridable in some cases
@property
def package_dir(self) -> Path:
return self.general_build_options.package_dir
@property
def build_selector(self) -> BuildSelector:
return self.general_build_options.build_selector
@property
def output_dir(self) -> Path:
return self.general_build_options.output_dir
@property
def architectures(self) -> Set[Architecture]:
return self.general_build_options.architectures
@property
def environment(self) -> ParsedEnvironment:
return self.general_build_options.environment
@property
def before_all(self) -> str:
return self.general_build_options.before_all
def produce_image_batches(
self,
configurations: List[SC],
platform_tag: str,
platform_arch: str,
) -> Iterator[Tuple[List[SC], str]]:
docker_images: Mapping[str, List[SC]] = defaultdict(list)
for config in configurations:
build_options = self[config.identifier]
images = (
build_options.manylinux_images
if platform_tag.startswith("manylinux")
else build_options.musllinux_images
)
assert images is not None
docker_images[images[platform_arch]].append(config)
for image, configs in docker_images.items():
# TODO: check for colisions for identifiers in configs
# Some settings (before-all) are not overridable in the same image
yield configs, image
def check_build_selectors(self) -> None:
hits = Counter[str]()
for sel in self.build_options_by_selector:
bs = BuildSelector(build_config=sel, skip_config="")
hits += Counter(i for i in self.identifiers if bs(i))
non_unique_identifers = {idnt for idnt, count in hits.items() if count > 1}
if non_unique_identifers:
msg = "cibuildwheel: error, the windows/macOS selectors must match uniquely"
print(msg, file=sys.stderr)
for sel in self.build_options_by_selector:
bs = BuildSelector(build_config=sel, skip_config="")
for i in non_unique_identifers:
if bs(i):
print(f" {sel}: {i} (nonunique match)")
sys.exit(1)
def __str__(self) -> str:
results = []
for option in sorted(self.general_build_options._asdict().keys()):
variations = {
key: value._asdict()[option]
for key, value in self.build_options_by_selector.items()
}
variations["*"] = self.general_build_options._asdict()[option]
if len({repr(v) for v in variations.values()}) == 1:
results.append(f"{option}: {variations['*']!r}")
else:
results.append(f"{option}:")
for key, value in sorted(variations.items()):
results.append(f" {key}: {value!r}")
return "\n".join(results)
class NonPlatformWheelError(Exception):
def __init__(self) -> None:
message = textwrap.dedent(