2019-04-13 20:17:01 +00:00
|
|
|
"""Validate dependencies."""
|
|
|
|
import pathlib
|
|
|
|
import re
|
|
|
|
from typing import Set, Dict
|
|
|
|
|
|
|
|
from .model import Integration
|
|
|
|
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def grep_dir(path: pathlib.Path, glob_pattern: str, search_pattern: str) -> Set[str]:
|
2019-04-13 20:17:01 +00:00
|
|
|
"""Recursively go through a dir and it's children and find the regex."""
|
|
|
|
pattern = re.compile(search_pattern)
|
|
|
|
found = set()
|
|
|
|
|
|
|
|
for fil in path.glob(glob_pattern):
|
|
|
|
if not fil.is_file():
|
|
|
|
continue
|
|
|
|
|
|
|
|
for match in pattern.finditer(fil.read_text()):
|
|
|
|
found.add(match.groups()[0])
|
|
|
|
|
|
|
|
return found
|
|
|
|
|
|
|
|
|
|
|
|
ALLOWED_USED_COMPONENTS = {
|
2019-04-16 21:11:58 +00:00
|
|
|
# This component will always be set up
|
2019-07-31 19:25:30 +00:00
|
|
|
"persistent_notification",
|
2019-04-16 21:11:58 +00:00
|
|
|
# These allow to register things without being set up
|
2019-07-31 19:25:30 +00:00
|
|
|
"conversation",
|
|
|
|
"frontend",
|
|
|
|
"hassio",
|
|
|
|
"system_health",
|
|
|
|
"websocket_api",
|
2019-04-13 20:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def validate_dependencies(integration: Integration):
|
|
|
|
"""Validate all dependencies."""
|
|
|
|
# Find usage of hass.components
|
2019-07-31 19:25:30 +00:00
|
|
|
referenced = grep_dir(integration.path, "**/*.py", r"hass\.components\.(\w+)")
|
2019-04-13 20:17:01 +00:00
|
|
|
referenced -= ALLOWED_USED_COMPONENTS
|
2019-07-31 19:25:30 +00:00
|
|
|
referenced -= set(integration.manifest["dependencies"])
|
|
|
|
referenced -= set(integration.manifest.get("after_dependencies", []))
|
2019-04-13 20:17:01 +00:00
|
|
|
|
|
|
|
if referenced:
|
|
|
|
for domain in sorted(referenced):
|
2019-07-31 19:25:30 +00:00
|
|
|
print(
|
|
|
|
"Warning: {} references integration {} but it's not a "
|
|
|
|
"dependency".format(integration.domain, domain)
|
|
|
|
)
|
2019-04-13 20:17:01 +00:00
|
|
|
# Not enforced yet.
|
|
|
|
# integration.add_error(
|
|
|
|
# 'dependencies',
|
|
|
|
# "Using component {} but it's not a dependency".format(domain)
|
|
|
|
# )
|
|
|
|
|
|
|
|
|
|
|
|
def validate(integrations: Dict[str, Integration], config):
|
|
|
|
"""Handle dependencies for integrations."""
|
|
|
|
# check for non-existing dependencies
|
|
|
|
for integration in integrations.values():
|
|
|
|
if not integration.manifest:
|
|
|
|
continue
|
|
|
|
|
|
|
|
validate_dependencies(integration)
|
|
|
|
|
|
|
|
# check that all referenced dependencies exist
|
2019-07-31 19:25:30 +00:00
|
|
|
for dep in integration.manifest["dependencies"]:
|
2019-04-13 20:17:01 +00:00
|
|
|
if dep not in integrations:
|
|
|
|
integration.add_error(
|
2019-07-31 19:25:30 +00:00
|
|
|
"dependencies", "Dependency {} does not exist".format(dep)
|
2019-04-13 20:17:01 +00:00
|
|
|
)
|