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

View file

@ -1,6 +1,7 @@
import logging import logging
import multiprocessing import multiprocessing
import os import os
from pathlib import Path
import re import re
from esphome import automation from esphome import automation
@ -35,7 +36,6 @@ from esphome.const import (
CONF_VERSION, CONF_VERSION,
KEY_CORE, KEY_CORE,
PLATFORM_ESP8266, PLATFORM_ESP8266,
TARGET_PLATFORMS,
__version__ as ESPHOME_VERSION, __version__ as ESPHOME_VERSION,
) )
from esphome.core import CORE, coroutine_with_priority 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 # Compat options, these were moved to target-platform specific sections
# but we'll keep these around for a long time because every config would # but we'll keep these around for a long time because every config would
# be impacted # 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_BOARD): cv.string_strict,
cv.Optional(CONF_ESP8266_RESTORE_FROM_FLASH): cv.valid, cv.Optional(CONF_ESP8266_RESTORE_FROM_FLASH): cv.valid,
cv.Optional(CONF_BOARD_FLASH_MODE): 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): with cv.prepend_path(CONF_ESPHOME):
conf = PRELOAD_CONFIG_SCHEMA(config[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]) CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH])
has_oldstyle = CONF_PLATFORM in conf 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 = [ oldstyle_opts = [
CONF_ESP8266_RESTORE_FROM_FLASH, CONF_ESP8266_RESTORE_FROM_FLASH,
CONF_BOARD_FLASH_MODE, CONF_BOARD_FLASH_MODE,
@ -214,7 +250,7 @@ def preload_core_config(config, result):
if not has_oldstyle and not newstyle_found: if not has_oldstyle and not newstyle_found:
raise cv.Invalid( raise cv.Invalid(
"Platform missing. You must include one of the available platform keys: " "Platform missing. You must include one of the available platform keys: "
+ ", ".join(TARGET_PLATFORMS), + ", ".join(_supported_target_platforms()),
[CONF_ESPHOME], [CONF_ESPHOME],
) )
if has_oldstyle and newstyle_found: if has_oldstyle and newstyle_found:
@ -238,6 +274,11 @@ def preload_core_config(config, result):
if has_oldstyle: if has_oldstyle:
plat = conf.pop(CONF_PLATFORM) 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 = {} plat_conf = {}
if CONF_ESP8266_RESTORE_FROM_FLASH in conf: if CONF_ESP8266_RESTORE_FROM_FLASH in conf:
plat_conf["restore_from_flash"] = conf.pop(CONF_ESP8266_RESTORE_FROM_FLASH) 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 # Insert generated target platform config to main config
config[plat] = plat_conf config[plat] = plat_conf
config[CONF_ESPHOME] = conf config[CONF_ESPHOME] = conf
return newstyle_found[0] if newstyle_found else plat
def include_file(path, basename): def include_file(path, basename):

View file

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