2024-03-26 08:24:58 +01:00
|
|
|
from __future__ import annotations
|
2024-07-29 04:07:44 +02:00
|
|
|
|
|
|
|
from io import StringIO
|
2019-04-22 21:56:30 +02:00
|
|
|
import json
|
2019-05-11 11:41:09 +02:00
|
|
|
import os
|
2024-03-26 08:24:58 +01:00
|
|
|
from typing import Any
|
2019-04-22 21:56:30 +02:00
|
|
|
|
2024-07-29 04:07:44 +02:00
|
|
|
from esphome.config import Config, _format_vol_invalid, validate_config
|
2019-12-07 18:28:55 +01:00
|
|
|
import esphome.config_validation as cv
|
2024-07-29 04:07:44 +02:00
|
|
|
from esphome.core import CORE, DocumentRange
|
|
|
|
from esphome.yaml_util import parse_yaml
|
2019-04-22 21:56:30 +02:00
|
|
|
|
|
|
|
|
2024-03-26 08:24:58 +01:00
|
|
|
def _get_invalid_range(res: Config, invalid: cv.Invalid) -> DocumentRange | None:
|
2022-09-20 07:23:55 +02:00
|
|
|
return res.get_deepest_document_range_for_path(
|
|
|
|
invalid.path, invalid.error_message == "extra keys not allowed"
|
|
|
|
)
|
2019-04-22 21:56:30 +02:00
|
|
|
|
|
|
|
|
2024-03-26 08:24:58 +01:00
|
|
|
def _dump_range(range: DocumentRange | None) -> dict | None:
|
2019-04-22 21:56:30 +02:00
|
|
|
if range is None:
|
|
|
|
return None
|
|
|
|
return {
|
2021-03-07 20:03:16 +01:00
|
|
|
"document": range.start_mark.document,
|
|
|
|
"start_line": range.start_mark.line,
|
|
|
|
"start_col": range.start_mark.column,
|
|
|
|
"end_line": range.end_mark.line,
|
|
|
|
"end_col": range.end_mark.column,
|
2019-04-22 21:56:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-07 18:28:55 +01:00
|
|
|
class VSCodeResult:
|
2019-04-22 21:56:30 +02:00
|
|
|
def __init__(self):
|
|
|
|
self.yaml_errors = []
|
|
|
|
self.validation_errors = []
|
|
|
|
|
|
|
|
def dump(self):
|
2021-03-07 20:03:16 +01:00
|
|
|
return json.dumps(
|
|
|
|
{
|
|
|
|
"type": "result",
|
|
|
|
"yaml_errors": self.yaml_errors,
|
|
|
|
"validation_errors": self.validation_errors,
|
|
|
|
}
|
|
|
|
)
|
2019-04-22 21:56:30 +02:00
|
|
|
|
|
|
|
def add_yaml_error(self, message):
|
2021-03-07 20:03:16 +01:00
|
|
|
self.yaml_errors.append(
|
|
|
|
{
|
|
|
|
"message": message,
|
|
|
|
}
|
|
|
|
)
|
2019-04-22 21:56:30 +02:00
|
|
|
|
|
|
|
def add_validation_error(self, range_, message):
|
2021-03-07 20:03:16 +01:00
|
|
|
self.validation_errors.append(
|
|
|
|
{
|
|
|
|
"range": _dump_range(range_),
|
|
|
|
"message": message,
|
|
|
|
}
|
|
|
|
)
|
2019-04-22 21:56:30 +02:00
|
|
|
|
|
|
|
|
2024-03-26 08:24:58 +01:00
|
|
|
def _read_file_content_from_json_on_stdin() -> str:
|
|
|
|
"""Read the content of a json encoded file from stdin."""
|
|
|
|
data = json.loads(input())
|
|
|
|
assert data["type"] == "file_response"
|
|
|
|
return data["content"]
|
|
|
|
|
|
|
|
|
|
|
|
def _print_file_read_event(path: str) -> None:
|
|
|
|
"""Print a file read event."""
|
|
|
|
print(
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"type": "read_file",
|
|
|
|
"path": path,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2019-05-11 11:41:09 +02:00
|
|
|
def read_config(args):
|
2019-04-22 21:56:30 +02:00
|
|
|
while True:
|
|
|
|
CORE.reset()
|
2019-12-07 18:28:55 +01:00
|
|
|
data = json.loads(input())
|
2021-03-07 20:03:16 +01:00
|
|
|
assert data["type"] == "validate"
|
2019-04-22 21:56:30 +02:00
|
|
|
CORE.vscode = True
|
2019-05-11 11:41:09 +02:00
|
|
|
CORE.ace = args.ace
|
2021-03-07 20:03:16 +01:00
|
|
|
f = data["file"]
|
2019-05-11 11:41:09 +02:00
|
|
|
if CORE.ace:
|
2021-08-11 07:21:57 +02:00
|
|
|
CORE.config_path = os.path.join(args.configuration, f)
|
2019-05-11 11:41:09 +02:00
|
|
|
else:
|
2021-03-07 20:03:16 +01:00
|
|
|
CORE.config_path = data["file"]
|
2024-03-26 08:24:58 +01:00
|
|
|
|
|
|
|
file_name = CORE.config_path
|
|
|
|
_print_file_read_event(file_name)
|
|
|
|
raw_yaml = _read_file_content_from_json_on_stdin()
|
|
|
|
command_line_substitutions: dict[str, Any] = (
|
|
|
|
dict(args.substitution) if args.substitution else {}
|
|
|
|
)
|
2019-04-22 21:56:30 +02:00
|
|
|
vs = VSCodeResult()
|
|
|
|
try:
|
2024-03-26 08:24:58 +01:00
|
|
|
config = parse_yaml(file_name, StringIO(raw_yaml))
|
|
|
|
res = validate_config(config, command_line_substitutions)
|
2019-04-22 21:56:30 +02:00
|
|
|
except Exception as err: # pylint: disable=broad-except
|
2019-12-07 18:28:55 +01:00
|
|
|
vs.add_yaml_error(str(err))
|
2019-04-22 21:56:30 +02:00
|
|
|
else:
|
|
|
|
for err in res.errors:
|
2019-05-11 11:41:09 +02:00
|
|
|
try:
|
|
|
|
range_ = _get_invalid_range(res, err)
|
|
|
|
vs.add_validation_error(range_, _format_vol_invalid(err, res))
|
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
continue
|
2019-04-22 21:56:30 +02:00
|
|
|
print(vs.dump())
|