Add toolchain validator factories and a native-toolchain predicate

This commit is contained in:
J. Nick Koston
2026-08-20 15:44:23 -05:00
parent 9d9953ea47
commit 6ad3e0d8ad
6 changed files with 54 additions and 34 deletions
+5 -14
View File
@@ -1071,20 +1071,11 @@ def _check_esp_idf_versions(config: ConfigType) -> ConfigType:
return config
def _validate_toolchain(value) -> Toolchain:
return Toolchain(
cv.one_of(Toolchain.PLATFORMIO, Toolchain.ESP_IDF, lower=True)(value)
)
def _resolve_toolchain(value: ConfigType) -> ConfigType:
# Resolve toolchain: CLI (already on CORE.toolchain) > YAML > default.
# Runs before _detect_variant so downstream validators can rely on
# CORE.toolchain instead of re-resolving it from the config dict.
if CORE.toolchain is None:
CORE.toolchain = value.get(CONF_TOOLCHAIN, Toolchain.ESP_IDF)
cv.check_supported_toolchain("ESP32", (Toolchain.PLATFORMIO, Toolchain.ESP_IDF))
return value
_TOOLCHAINS = (Toolchain.PLATFORMIO, Toolchain.ESP_IDF)
_validate_toolchain = cv.toolchain_enum(_TOOLCHAINS)
# Runs before _detect_variant so downstream validators can rely on
# CORE.toolchain instead of re-resolving it from the config dict.
_resolve_toolchain = cv.resolve_toolchain("ESP32", _TOOLCHAINS, Toolchain.ESP_IDF)
def _check_versions(config: ConfigType) -> ConfigType:
+3 -9
View File
@@ -125,11 +125,8 @@ def set_core_data(config: ConfigType) -> ConfigType:
return config
def _resolve_toolchain(config: ConfigType) -> ConfigType:
if CORE.toolchain is None:
CORE.toolchain = config.get(CONF_TOOLCHAIN, Toolchain.SDK_NRF)
cv.check_supported_toolchain("nRF52", (Toolchain.PLATFORMIO, Toolchain.SDK_NRF))
return config
_TOOLCHAINS = (Toolchain.PLATFORMIO, Toolchain.SDK_NRF)
_resolve_toolchain = cv.resolve_toolchain("nRF52", _TOOLCHAINS, Toolchain.SDK_NRF)
def set_framework(config: ConfigType) -> ConfigType:
@@ -171,10 +168,7 @@ BOOTLOADERS = [
]
def _validate_toolchain(value) -> Toolchain:
return Toolchain(
cv.one_of(Toolchain.PLATFORMIO, Toolchain.SDK_NRF, lower=True)(value)
)
_validate_toolchain = cv.toolchain_enum(_TOOLCHAINS)
def _detect_bootloader(config: ConfigType) -> ConfigType:
+32 -8
View File
@@ -53,6 +53,7 @@ from esphome.const import (
CONF_SETUP_PRIORITY,
CONF_STATE_TOPIC,
CONF_SUBSCRIBE_QOS,
CONF_TOOLCHAIN,
CONF_TOPIC,
CONF_TYPE,
CONF_TYPE_ID,
@@ -2555,20 +2556,43 @@ def check_supported_toolchain(
)
def toolchain_enum(supported: tuple[Toolchain, ...]):
"""Schema validator for a platform's ``toolchain`` config key."""
def validator(value) -> Toolchain:
return Toolchain(one_of(*supported, lower=True)(value))
return validator
def resolve_toolchain(
platform_name: str, supported: tuple[Toolchain, ...], default: Toolchain
):
"""Resolve ``CORE.toolchain`` (CLI > YAML > default) and reject one the
platform cannot serve.
Add to the platform's validation chain before anything that reads
``CORE.toolchain``.
"""
def validator(config: ConfigType) -> ConfigType:
if CORE.toolchain is None:
CORE.toolchain = config.get(CONF_TOOLCHAIN, default)
check_supported_toolchain(platform_name, supported)
return config
return validator
def require_platformio_toolchain(platform_name: str):
"""Reject a CLI-selected toolchain other than PlatformIO.
For platforms with only the PlatformIO backend; without this a
``--toolchain`` they cannot serve would silently build with PlatformIO.
"""
def validator(config: ConfigType) -> ConfigType:
if CORE.toolchain is None:
CORE.toolchain = Toolchain.PLATFORMIO
check_supported_toolchain(platform_name, (Toolchain.PLATFORMIO,))
return config
return validator
return resolve_toolchain(
platform_name, (Toolchain.PLATFORMIO,), Toolchain.PLATFORMIO
)
def require_framework_version(
+6
View File
@@ -25,6 +25,12 @@ class Toolchain(StrEnum):
ARDUINO = "arduino"
# Toolchains that drive their build natively and never read platformio.ini.
# SDK_NRF is absent on purpose: the zephyr backend keeps consuming
# platformio_options.
NATIVE_TOOLCHAINS = frozenset({Toolchain.ESP_IDF, Toolchain.ARDUINO})
class Platform(StrEnum):
"""Platform identifiers for ESPHome."""
+7
View File
@@ -21,6 +21,7 @@ from esphome.const import (
KEY_CORE,
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
NATIVE_TOOLCHAINS,
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
@@ -992,6 +993,12 @@ class EsphomeCore:
"""
return self.toolchain == Toolchain.ARDUINO
@property
def using_native_toolchain(self):
"""Whether the selected toolchain builds natively, without reading
``platformio.ini`` (see ``NATIVE_TOOLCHAINS`` in ``esphome.const``)."""
return self.toolchain in NATIVE_TOOLCHAINS
@property
def using_zephyr(self):
return self.target_framework == "zephyr"
+1 -3
View File
@@ -557,9 +557,7 @@ def _add_library_str(lib: str) -> None:
@coroutine_with_priority(CoroPriority.FINAL)
async def _add_platformio_options(pio_options: dict[str, str | list[str]]) -> None:
# Every platform's toolchain validation rejects values it cannot serve,
# so using_toolchain_arduino by itself implies the native ESP8266 build.
if CORE.using_toolchain_esp_idf or CORE.using_toolchain_arduino:
if CORE.using_native_toolchain:
# The native builds don't read platformio.ini; honor the options
# with a native equivalent and warn about the rest, which would
# otherwise be silently ignored.