mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 19:44:08 +00:00
Harden the shared toolchain check and pin every platform family's rejection
This commit is contained in:
@@ -314,8 +314,8 @@ BASE_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
BASE_SCHEMA.add_extra(_detect_variant)
|
||||
BASE_SCHEMA.add_extra(_update_core_data)
|
||||
BASE_SCHEMA.add_extra(cv.require_platformio_toolchain("LibreTiny"))
|
||||
BASE_SCHEMA.add_extra(_update_core_data)
|
||||
|
||||
|
||||
def _configure_lwip(config: dict) -> None:
|
||||
|
||||
@@ -107,6 +107,9 @@ from esphome.util import parse_esphome_version # noqa: F401
|
||||
from esphome.voluptuous_schema import _Schema
|
||||
from esphome.yaml_util import SensitiveStr, make_data_base
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from esphome.types import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@@ -2533,17 +2536,21 @@ def platformio_version_constraint(value):
|
||||
return constraints
|
||||
|
||||
|
||||
def check_supported_toolchain(platform_name: str, supported: tuple) -> None:
|
||||
def check_supported_toolchain(
|
||||
platform_name: str, supported: tuple[Toolchain, ...]
|
||||
) -> None:
|
||||
"""Raise when the resolved ``CORE.toolchain`` is not in ``supported``.
|
||||
|
||||
One message shape for every platform, so a ``--toolchain`` a platform
|
||||
cannot serve always fails by name instead of silently building with a
|
||||
different backend.
|
||||
"""
|
||||
if CORE.toolchain not in supported:
|
||||
toolchain = CORE.toolchain
|
||||
if toolchain is None or toolchain not in supported:
|
||||
names = ", ".join(f"'{tc.value}'" for tc in supported)
|
||||
raise Invalid(
|
||||
f"Unsupported toolchain '{CORE.toolchain.value}' for "
|
||||
f"Unsupported toolchain "
|
||||
f"'{toolchain.value if toolchain else 'unresolved'}' for "
|
||||
f"{platform_name}. Supported: {names}."
|
||||
)
|
||||
|
||||
@@ -2555,7 +2562,7 @@ def require_platformio_toolchain(platform_name: str):
|
||||
``--toolchain`` they cannot serve would silently build with PlatformIO.
|
||||
"""
|
||||
|
||||
def validator(config):
|
||||
def validator(config: ConfigType) -> ConfigType:
|
||||
if CORE.toolchain is None:
|
||||
CORE.toolchain = Toolchain.PLATFORMIO
|
||||
check_supported_toolchain(platform_name, (Toolchain.PLATFORMIO,))
|
||||
|
||||
@@ -984,6 +984,12 @@ class EsphomeCore:
|
||||
|
||||
@property
|
||||
def using_toolchain_arduino(self):
|
||||
"""The native (PlatformIO-free) ESP8266 Arduino build backend.
|
||||
|
||||
Unlike ``using_arduino`` (the target *framework*, true for any
|
||||
platform compiling Arduino code), this is a build *toolchain*
|
||||
choice, like its ``using_toolchain_*`` siblings.
|
||||
"""
|
||||
return self.toolchain == Toolchain.ARDUINO
|
||||
|
||||
@property
|
||||
@@ -1099,6 +1105,8 @@ class EsphomeCore:
|
||||
return build_flag
|
||||
|
||||
def add_build_unflag(self, build_unflag: str) -> None:
|
||||
# No warning for using_toolchain_arduino: the native ESP8266 build
|
||||
# honors build_unflags (token-level, matching PlatformIO).
|
||||
if self.using_toolchain_esp_idf:
|
||||
# The native ESP-IDF build generator does not consume build_unflags
|
||||
_LOGGER.warning(
|
||||
|
||||
@@ -576,14 +576,15 @@ async def _add_platformio_options(pio_options: dict[str, str | list[str]]) -> No
|
||||
for flag in vals:
|
||||
cg.add_build_flag(flag)
|
||||
elif key == "lib_deps":
|
||||
# Routed through the regular library mechanism so the libraries
|
||||
# are converted to IDF components like any other PIO library
|
||||
# Routed through the regular library mechanism so the
|
||||
# libraries reach the native backend's converter (IDF
|
||||
# components, or the ESP8266 native library resolution)
|
||||
for lib in vals:
|
||||
_add_library_str(lib)
|
||||
elif key == "lib_ignore":
|
||||
# Read by the PIO-library-to-IDF-component conversion
|
||||
# (generate_idf_components); filters both top-level libraries
|
||||
# and dependencies discovered during conversion
|
||||
# Read by the shared library conversion (lib_ignore_set in
|
||||
# platformio/library.py) on both native backends; filters
|
||||
# top-level libraries and discovered dependencies
|
||||
cg.add_platformio_option(key, vals)
|
||||
elif key != "upload_speed":
|
||||
# upload_speed needs no handling: it is read from the raw
|
||||
|
||||
@@ -3181,3 +3181,28 @@ def test_require_platformio_toolchain() -> None:
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
with pytest.raises(Invalid, match="Unsupported toolchain 'arduino' for RP2"):
|
||||
validator(config)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("platform", "minimal_config"),
|
||||
[
|
||||
("host", {}),
|
||||
("rp2", {"board": "rpipicow"}),
|
||||
("bk72xx", {"board": "generic-bk7231n-qfn32-tuya"}),
|
||||
],
|
||||
)
|
||||
def test_every_platformio_only_platform_rejects_arduino_toolchain(
|
||||
platform: str, minimal_config: dict
|
||||
) -> None:
|
||||
"""The invariant every native-toolchain gate relies on: a platform that
|
||||
cannot serve a CLI toolchain rejects it at validation (esp32, esp8266,
|
||||
and nrf52 pin this in their own suites)."""
|
||||
import importlib
|
||||
|
||||
from esphome.const import Toolchain
|
||||
from esphome.core import CORE
|
||||
|
||||
module = importlib.import_module(f"esphome.components.{platform}")
|
||||
CORE.toolchain = Toolchain.ARDUINO
|
||||
with pytest.raises(Invalid, match="Unsupported toolchain 'arduino'"):
|
||||
module.CONFIG_SCHEMA(dict(minimal_config))
|
||||
|
||||
Reference in New Issue
Block a user