mirror of
https://github.com/esphome/esphome.git
synced 2025-10-12 23:03:46 +01:00
handle merging comp with compont_dir
This commit is contained in:
@@ -67,6 +67,7 @@ ISOLATED_COMPONENTS = {
|
|||||||
"esp32_camera": "Leaks config into other components",
|
"esp32_camera": "Leaks config into other components",
|
||||||
"esp32_camera_web_server": "Leaks config into other components",
|
"esp32_camera_web_server": "Leaks config into other components",
|
||||||
"esphome": "Defines devices/areas in esphome: section that are referenced in other sections - breaks when merged",
|
"esphome": "Defines devices/areas in esphome: section that are referenced in other sections - breaks when merged",
|
||||||
|
"lvgl": "Defines multiple SDL displays on host platform that conflict when merged with other display configs",
|
||||||
"matrix_keypad": "Needs isolation due to keypad",
|
"matrix_keypad": "Needs isolation due to keypad",
|
||||||
"mcp4725": "no YAML config to specify i2c bus id",
|
"mcp4725": "no YAML config to specify i2c bus id",
|
||||||
"mcp47a1": "no YAML config to specify i2c bus id",
|
"mcp47a1": "no YAML config to specify i2c bus id",
|
||||||
@@ -317,9 +318,8 @@ def analyze_all_components(
|
|||||||
if platform_buses:
|
if platform_buses:
|
||||||
components[component_name] = platform_buses
|
components[component_name] = platform_buses
|
||||||
|
|
||||||
# Check if component uses local file references
|
# Note: Components using $component_dir are now groupable because the merge
|
||||||
if uses_local_file_references(component_dir):
|
# script rewrites these to absolute paths with component-specific substitutions
|
||||||
non_groupable.add(component_name)
|
|
||||||
|
|
||||||
# Check if component is a base bus component
|
# Check if component is a base bus component
|
||||||
# These are platform implementations and must be tested separately
|
# These are platform implementations and must be tested separately
|
||||||
@@ -444,8 +444,7 @@ def main() -> None:
|
|||||||
)
|
)
|
||||||
if platform_buses:
|
if platform_buses:
|
||||||
components[comp] = platform_buses
|
components[comp] = platform_buses
|
||||||
if uses_local_file_references(comp_dir):
|
# Note: Components using $component_dir are now groupable
|
||||||
non_groupable.add(comp)
|
|
||||||
if comp in BASE_BUS_COMPONENTS:
|
if comp in BASE_BUS_COMPONENTS:
|
||||||
non_groupable.add(comp)
|
non_groupable.add(comp)
|
||||||
if has_extend_remove:
|
if has_extend_remove:
|
||||||
|
@@ -102,9 +102,11 @@ def prefix_substitutions_in_dict(
|
|||||||
sub_name = match.group(1)
|
sub_name = match.group(1)
|
||||||
if sub_name in exclude:
|
if sub_name in exclude:
|
||||||
return match.group(0)
|
return match.group(0)
|
||||||
|
# Always use braced format in output for consistency
|
||||||
return f"${{{prefix}_{sub_name}}}"
|
return f"${{{prefix}_{sub_name}}}"
|
||||||
|
|
||||||
return re.sub(r"\$\{(\w+)\}", replace_match, text)
|
# Match both ${substitution} and $substitution formats
|
||||||
|
return re.sub(r"\$\{?(\w+)\}?", replace_match, text)
|
||||||
|
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
result = {}
|
result = {}
|
||||||
@@ -207,9 +209,9 @@ def merge_component_configs(
|
|||||||
f"All components must use the same common bus configs to be merged."
|
f"All components must use the same common bus configs to be merged."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove packages from component data (we'll add them back once)
|
# Handle $component_dir by replacing with absolute path
|
||||||
if "packages" in comp_data:
|
# This allows components that use local file references to be grouped
|
||||||
del comp_data["packages"]
|
comp_abs_dir = str(comp_dir.absolute())
|
||||||
|
|
||||||
# Prefix substitutions in component data
|
# Prefix substitutions in component data
|
||||||
if "substitutions" in comp_data and comp_data["substitutions"] is not None:
|
if "substitutions" in comp_data and comp_data["substitutions"] is not None:
|
||||||
@@ -218,23 +220,46 @@ def merge_component_configs(
|
|||||||
prefixed_subs[f"{comp_name}_{sub_name}"] = sub_value
|
prefixed_subs[f"{comp_name}_{sub_name}"] = sub_value
|
||||||
comp_data["substitutions"] = prefixed_subs
|
comp_data["substitutions"] = prefixed_subs
|
||||||
|
|
||||||
# Prefix substitution references throughout the config
|
# Add component_dir substitution with absolute path for this component
|
||||||
|
if "substitutions" not in comp_data or comp_data["substitutions"] is None:
|
||||||
|
comp_data["substitutions"] = {}
|
||||||
|
comp_data["substitutions"][f"{comp_name}_component_dir"] = comp_abs_dir
|
||||||
|
|
||||||
|
# Prefix substitution references throughout the config (including in packages)
|
||||||
comp_data = prefix_substitutions_in_dict(comp_data, comp_name)
|
comp_data = prefix_substitutions_in_dict(comp_data, comp_name)
|
||||||
|
|
||||||
|
# Now handle packages: remove common bus packages, expand component-specific ones
|
||||||
|
if "packages" in comp_data:
|
||||||
|
common_bus_packages = get_common_bus_packages()
|
||||||
|
for pkg_name, pkg_value in list(comp_data["packages"].items()):
|
||||||
|
if pkg_name not in common_bus_packages and isinstance(pkg_value, dict):
|
||||||
|
# Component-specific package - expand its content into top level
|
||||||
|
# Merge package content using ESPHome's merge_config
|
||||||
|
comp_data = merge_config(comp_data, pkg_value)
|
||||||
|
# Remove all packages (common will be re-added at the end)
|
||||||
|
del comp_data["packages"]
|
||||||
|
|
||||||
# Use ESPHome's merge_config to merge this component into the result
|
# Use ESPHome's merge_config to merge this component into the result
|
||||||
# merge_config handles list merging with ID-based deduplication automatically
|
# merge_config handles list merging with ID-based deduplication automatically
|
||||||
merged_config_data = merge_config(merged_config_data, comp_data)
|
merged_config_data = merge_config(merged_config_data, comp_data)
|
||||||
|
|
||||||
# Add packages back (only once, since they're identical)
|
# Add packages back (only once, since they're identical)
|
||||||
if all_packages and "packages" in list(
|
# IMPORTANT: Only re-add common bus packages (spi, i2c, uart, etc.)
|
||||||
load_yaml_file(tests_dir / component_names[0] / f"test.{platform}.yaml")
|
# Do NOT re-add component-specific packages as they contain unprefixed $component_dir refs
|
||||||
):
|
if all_packages:
|
||||||
# Re-read first component to get original packages with !include
|
|
||||||
first_comp_data = load_yaml_file(
|
first_comp_data = load_yaml_file(
|
||||||
tests_dir / component_names[0] / f"test.{platform}.yaml"
|
tests_dir / component_names[0] / f"test.{platform}.yaml"
|
||||||
)
|
)
|
||||||
if "packages" in first_comp_data:
|
if "packages" in first_comp_data:
|
||||||
merged_config_data["packages"] = first_comp_data["packages"]
|
# Filter to only include common bus packages
|
||||||
|
common_bus_packages = get_common_bus_packages()
|
||||||
|
filtered_packages = {
|
||||||
|
name: value
|
||||||
|
for name, value in first_comp_data["packages"].items()
|
||||||
|
if name in common_bus_packages
|
||||||
|
}
|
||||||
|
if filtered_packages:
|
||||||
|
merged_config_data["packages"] = filtered_packages
|
||||||
|
|
||||||
# Deduplicate items with same ID (keeps first occurrence)
|
# Deduplicate items with same ID (keeps first occurrence)
|
||||||
merged_config_data = deduplicate_by_id(merged_config_data)
|
merged_config_data = deduplicate_by_id(merged_config_data)
|
||||||
|
Reference in New Issue
Block a user