mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Check circular dependencies (#88778)
This commit is contained in:
parent
bea81d3f63
commit
9be3f86a4c
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"domain": "hassio",
|
"domain": "hassio",
|
||||||
"name": "Home Assistant Supervisor",
|
"name": "Home Assistant Supervisor",
|
||||||
"after_dependencies": ["panel_custom"],
|
|
||||||
"codeowners": ["@home-assistant/supervisor"],
|
"codeowners": ["@home-assistant/supervisor"],
|
||||||
"dependencies": ["http"],
|
"dependencies": ["http"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/hassio",
|
"documentation": "https://www.home-assistant.io/integrations/hassio",
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
{
|
{
|
||||||
"domain": "zha",
|
"domain": "zha",
|
||||||
"name": "Zigbee Home Automation",
|
"name": "Zigbee Home Automation",
|
||||||
"after_dependencies": [
|
"after_dependencies": ["onboarding", "usb"],
|
||||||
"onboarding",
|
|
||||||
"usb",
|
|
||||||
"zeroconf",
|
|
||||||
"homeassistant_yellow"
|
|
||||||
],
|
|
||||||
"codeowners": ["@dmulcahey", "@adminiuga", "@puddly"],
|
"codeowners": ["@dmulcahey", "@adminiuga", "@puddly"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["file_upload"],
|
"dependencies": ["file_upload"],
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
from collections import deque
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
@ -118,6 +119,7 @@ ALLOWED_USED_COMPONENTS = {
|
|||||||
"input_text",
|
"input_text",
|
||||||
"media_source",
|
"media_source",
|
||||||
"onboarding",
|
"onboarding",
|
||||||
|
"panel_custom",
|
||||||
"persistent_notification",
|
"persistent_notification",
|
||||||
"person",
|
"person",
|
||||||
"script",
|
"script",
|
||||||
@ -138,22 +140,19 @@ IGNORE_VIOLATIONS = {
|
|||||||
# Has same requirement, gets defaults.
|
# Has same requirement, gets defaults.
|
||||||
("sql", "recorder"),
|
("sql", "recorder"),
|
||||||
# Sharing a base class
|
# Sharing a base class
|
||||||
("openalpr_cloud", "openalpr_local"),
|
|
||||||
("lutron_caseta", "lutron"),
|
("lutron_caseta", "lutron"),
|
||||||
("ffmpeg_noise", "ffmpeg_motion"),
|
("ffmpeg_noise", "ffmpeg_motion"),
|
||||||
# Demo
|
# Demo
|
||||||
("demo", "manual"),
|
("demo", "manual"),
|
||||||
("demo", "openalpr_local"),
|
|
||||||
# This would be a circular dep
|
# This would be a circular dep
|
||||||
("http", "network"),
|
("http", "network"),
|
||||||
# This would be a circular dep
|
# This would be a circular dep
|
||||||
("zha", "homeassistant_hardware"),
|
("zha", "homeassistant_hardware"),
|
||||||
|
("zha", "homeassistant_yellow"),
|
||||||
# This should become a helper method that integrations can submit data to
|
# This should become a helper method that integrations can submit data to
|
||||||
("websocket_api", "lovelace"),
|
("websocket_api", "lovelace"),
|
||||||
("websocket_api", "shopping_list"),
|
("websocket_api", "shopping_list"),
|
||||||
"logbook",
|
"logbook",
|
||||||
# Migration wizard from zwave to zwave_js.
|
|
||||||
"zwave_js",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -231,6 +230,7 @@ def find_non_referenced_integrations(
|
|||||||
def validate_dependencies(
|
def validate_dependencies(
|
||||||
integrations: dict[str, Integration],
|
integrations: dict[str, Integration],
|
||||||
integration: Integration,
|
integration: Integration,
|
||||||
|
check_dependencies: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Validate all dependencies."""
|
"""Validate all dependencies."""
|
||||||
# Some integrations are allowed to have violations.
|
# Some integrations are allowed to have violations.
|
||||||
@ -252,12 +252,60 @@ def validate_dependencies(
|
|||||||
"or 'after_dependencies'",
|
"or 'after_dependencies'",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if check_dependencies:
|
||||||
|
_check_circular_deps(
|
||||||
|
integrations, integration.domain, integration, set(), deque()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_circular_deps(
|
||||||
|
integrations: dict[str, Integration],
|
||||||
|
start_domain: str,
|
||||||
|
integration: Integration,
|
||||||
|
checked: set[str],
|
||||||
|
checking: deque[str],
|
||||||
|
) -> None:
|
||||||
|
"""Check for circular dependencies pointing at starting_domain."""
|
||||||
|
if integration.domain in checked or integration.domain in checking:
|
||||||
|
return
|
||||||
|
|
||||||
|
checking.append(integration.domain)
|
||||||
|
for domain in integration.manifest.get("dependencies", []):
|
||||||
|
if domain == start_domain:
|
||||||
|
integrations[start_domain].add_error(
|
||||||
|
"dependencies",
|
||||||
|
f"Found a circular dependency with {integration.domain} ({', '.join(checking)})",
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
_check_circular_deps(
|
||||||
|
integrations, start_domain, integrations[domain], checked, checking
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for domain in integration.manifest.get("after_dependencies", []):
|
||||||
|
if domain == start_domain:
|
||||||
|
integrations[start_domain].add_error(
|
||||||
|
"dependencies",
|
||||||
|
f"Found a circular dependency with after dependencies of {integration.domain} ({', '.join(checking)})",
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
_check_circular_deps(
|
||||||
|
integrations, start_domain, integrations[domain], checked, checking
|
||||||
|
)
|
||||||
|
checked.add(integration.domain)
|
||||||
|
checking.remove(integration.domain)
|
||||||
|
|
||||||
|
|
||||||
def validate(integrations: dict[str, Integration], config: Config) -> None:
|
def validate(integrations: dict[str, Integration], config: Config) -> None:
|
||||||
"""Handle dependencies for integrations."""
|
"""Handle dependencies for integrations."""
|
||||||
# check for non-existing dependencies
|
# check for non-existing dependencies
|
||||||
for integration in integrations.values():
|
for integration in integrations.values():
|
||||||
validate_dependencies(integrations, integration)
|
validate_dependencies(
|
||||||
|
integrations,
|
||||||
|
integration,
|
||||||
|
check_dependencies=not config.specific_integrations,
|
||||||
|
)
|
||||||
|
|
||||||
if config.specific_integrations:
|
if config.specific_integrations:
|
||||||
continue
|
continue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user