is target platform

This commit is contained in:
Tomasz Duda 2024-10-28 19:29:10 +01:00
parent e7c7516c53
commit c3ea6630d3
3 changed files with 59 additions and 14 deletions

View file

@ -21,7 +21,6 @@ from esphome.const import (
CONF_PACKAGES,
CONF_PLATFORM,
CONF_SUBSTITUTIONS,
TARGET_PLATFORMS,
)
from esphome.core import CORE, DocumentRange, EsphomeError
import esphome.core.config as core_config
@ -832,7 +831,7 @@ def validate_config(
result[CONF_ESPHOME] = config[CONF_ESPHOME]
result.add_output_path([CONF_ESPHOME], CONF_ESPHOME)
try:
core_config.preload_core_config(config, result)
target_platform = core_config.preload_core_config(config, result)
except vol.Invalid as err:
result.add_error(err)
return result
@ -840,9 +839,9 @@ def validate_config(
result.remove_output_path([CONF_ESPHOME], CONF_ESPHOME)
# First run platform validation steps
for key in TARGET_PLATFORMS:
if key in config:
result.add_validation_step(LoadValidationStep(key, config[key]))
result.add_validation_step(
LoadValidationStep(target_platform, config[target_platform])
)
result.run_validation_steps()
if result.errors:

View file

@ -1,6 +1,7 @@
import logging
import multiprocessing
import os
from pathlib import Path
import re
from esphome import automation
@ -35,7 +36,6 @@ from esphome.const import (
CONF_VERSION,
KEY_CORE,
PLATFORM_ESP8266,
TARGET_PLATFORMS,
__version__ as ESPHOME_VERSION,
)
from esphome.core import CORE, coroutine_with_priority
@ -179,7 +179,7 @@ PRELOAD_CONFIG_SCHEMA = cv.Schema(
# Compat options, these were moved to target-platform specific sections
# but we'll keep these around for a long time because every config would
# be impacted
cv.Optional(CONF_PLATFORM): cv.one_of(*TARGET_PLATFORMS, lower=True),
cv.Optional(CONF_PLATFORM): cv.string,
cv.Optional(CONF_BOARD): cv.string_strict,
cv.Optional(CONF_ESP8266_RESTORE_FROM_FLASH): cv.valid,
cv.Optional(CONF_BOARD_FLASH_MODE): cv.valid,
@ -189,7 +189,38 @@ PRELOAD_CONFIG_SCHEMA = cv.Schema(
)
def preload_core_config(config, result):
def _is_target_platform(name):
try:
from esphome.loader import get_component
# we cannot load some components without platform
component = get_component(name, True)
if component.is_target_platform:
return True
except KeyError:
pass
return False
def _supported_target_platforms():
target_platforms = []
# The root directory of the repo
root = Path(__file__).parent.parent
components_dir = root / "components"
for path in components_dir.iterdir():
if not path.is_dir():
continue
if not (path / "__init__.py").is_file():
continue
name = path.name
if _is_target_platform(name):
target_platforms += [name]
return target_platforms
def preload_core_config(config, result) -> str:
with cv.prepend_path(CONF_ESPHOME):
conf = PRELOAD_CONFIG_SCHEMA(config[CONF_ESPHOME])
@ -203,7 +234,12 @@ def preload_core_config(config, result):
CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH])
has_oldstyle = CONF_PLATFORM in conf
newstyle_found = [key for key in TARGET_PLATFORMS if key in config]
newstyle_found = []
for domain, _ in config.items():
if _is_target_platform(domain):
newstyle_found += [domain]
oldstyle_opts = [
CONF_ESP8266_RESTORE_FROM_FLASH,
CONF_BOARD_FLASH_MODE,
@ -214,7 +250,7 @@ def preload_core_config(config, result):
if not has_oldstyle and not newstyle_found:
raise cv.Invalid(
"Platform missing. You must include one of the available platform keys: "
+ ", ".join(TARGET_PLATFORMS),
+ ", ".join(_supported_target_platforms()),
[CONF_ESPHOME],
)
if has_oldstyle and newstyle_found:
@ -238,6 +274,11 @@ def preload_core_config(config, result):
if has_oldstyle:
plat = conf.pop(CONF_PLATFORM)
if not _is_target_platform(plat):
raise cv.Invalid(
"Platform missing. You must include one of the available platform keys: "
+ ", ".join(_supported_target_platforms())
)
plat_conf = {}
if CONF_ESP8266_RESTORE_FROM_FLASH in conf:
plat_conf["restore_from_flash"] = conf.pop(CONF_ESP8266_RESTORE_FROM_FLASH)
@ -259,6 +300,7 @@ def preload_core_config(config, result):
# Insert generated target platform config to main config
config[plat] = plat_conf
config[CONF_ESPHOME] = conf
return newstyle_found[0] if newstyle_found else plat
def include_file(path, basename):

View file

@ -173,13 +173,15 @@ def install_custom_components_meta_finder():
install_meta_finder(custom_components_dir)
def _lookup_module(domain):
def _lookup_module(domain, exception):
if domain in _COMPONENT_CACHE:
return _COMPONENT_CACHE[domain]
try:
module = importlib.import_module(f"esphome.components.{domain}")
except ImportError as e:
if exception:
raise
if "No module named" in str(e):
_LOGGER.info(
"Unable to import component %s: %s", domain, str(e), exc_info=False
@ -188,6 +190,8 @@ def _lookup_module(domain):
_LOGGER.error("Unable to import component %s:", domain, exc_info=True)
return None
except Exception: # pylint: disable=broad-except
if exception:
raise
_LOGGER.error("Unable to load component %s:", domain, exc_info=True)
return None
@ -196,14 +200,14 @@ def _lookup_module(domain):
return manif
def get_component(domain):
def get_component(domain, exception=False):
assert "." not in domain
return _lookup_module(domain)
return _lookup_module(domain, exception)
def get_platform(domain, platform):
full = f"{platform}.{domain}"
return _lookup_module(full)
return _lookup_module(full, False)
_COMPONENT_CACHE = {}