forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add services.yaml validator (home-assistant#23205)
* Add services.yaml validator * Fix path
- Loading branch information
Showing
9 changed files
with
172 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,15 @@ | ||
system_log: | ||
clear: | ||
description: Clear all log entries. | ||
write: | ||
description: Write log entry. | ||
fields: | ||
message: | ||
description: Message to log. [Required] | ||
example: Something went wrong | ||
level: | ||
description: "Log level: debug, info, warning, error, critical. Defaults to 'error'." | ||
example: debug | ||
logger: | ||
description: Logger name under which to log the message. Defaults to 'system_log.external'. | ||
example: mycomponent.myplatform | ||
clear: | ||
description: Clear all log entries. | ||
|
||
write: | ||
description: Write log entry. | ||
fields: | ||
message: | ||
description: Message to log. [Required] | ||
example: Something went wrong | ||
level: | ||
description: "Log level: debug, info, warning, error, critical. Defaults to 'error'." | ||
example: debug | ||
logger: | ||
description: Logger name under which to log the message. Defaults to 'system_log.external'. | ||
example: mycomponent.myplatform |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
"""Validate dependencies.""" | ||
import pathlib | ||
from typing import Dict | ||
|
||
import re | ||
import voluptuous as vol | ||
from voluptuous.humanize import humanize_error | ||
|
||
from homeassistant.exceptions import HomeAssistantError | ||
from homeassistant.helpers import config_validation as cv | ||
from homeassistant.util.yaml import load_yaml | ||
|
||
from .model import Integration | ||
|
||
|
||
def exists(value): | ||
"""Check if value exists.""" | ||
if value is None: | ||
raise vol.Invalid("Value cannot be None") | ||
return value | ||
|
||
|
||
FIELD_SCHEMA = vol.Schema({ | ||
vol.Required('description'): str, | ||
vol.Optional('example'): exists, | ||
vol.Optional('default'): exists, | ||
vol.Optional('values'): exists, | ||
vol.Optional('required'): bool, | ||
}) | ||
|
||
SERVICE_SCHEMA = vol.Schema({ | ||
vol.Required('description'): str, | ||
vol.Optional('fields'): vol.Schema({ | ||
str: FIELD_SCHEMA | ||
}) | ||
}) | ||
|
||
SERVICES_SCHEMA = vol.Schema({ | ||
cv.slug: SERVICE_SCHEMA | ||
}) | ||
|
||
|
||
def grep_dir(path: pathlib.Path, glob_pattern: str, search_pattern: str) \ | ||
-> bool: | ||
"""Recursively go through a dir and it's children and find the regex.""" | ||
pattern = re.compile(search_pattern) | ||
|
||
for fil in path.glob(glob_pattern): | ||
if not fil.is_file(): | ||
continue | ||
|
||
if pattern.search(fil.read_text()): | ||
return True | ||
|
||
return False | ||
|
||
|
||
def validate_services(integration: Integration): | ||
"""Validate services.""" | ||
# Find if integration uses services | ||
has_services = grep_dir(integration.path, "**/*.py", | ||
r"hass\.(services|async_register)") | ||
|
||
if not has_services: | ||
return | ||
|
||
try: | ||
data = load_yaml(str(integration.path / 'services.yaml')) | ||
except FileNotFoundError: | ||
print( | ||
"Warning: {} registeres services but has no services.yaml".format( | ||
integration.domain)) | ||
# integration.add_error( | ||
# 'services', 'Registers services but has no services.yaml') | ||
return | ||
except HomeAssistantError: | ||
integration.add_error( | ||
'services', 'Registers services but unable to load services.yaml') | ||
return | ||
|
||
try: | ||
SERVICES_SCHEMA(data) | ||
except vol.Invalid as err: | ||
integration.add_error( | ||
'services', | ||
"Invalid services.yaml: {}".format(humanize_error(data, err))) | ||
|
||
|
||
def validate(integrations: Dict[str, Integration], config): | ||
"""Handle dependencies for integrations.""" | ||
# check services.yaml is cool | ||
for integration in integrations.values(): | ||
if not integration.manifest: | ||
continue | ||
|
||
validate_services(integration) | ||
|
||
# check that all referenced dependencies exist | ||
for dep in integration.manifest['dependencies']: | ||
if dep not in integrations: | ||
integration.add_error( | ||
'dependencies', | ||
"Dependency {} does not exist" | ||
) |