mirror of
https://github.com/esphome/esphome.git
synced 2026-10-06 02:51:29 +00:00
[core] Save the validated config cache on the first upload or logs run (#18367)
This commit is contained in:
+48
-8
@@ -71,8 +71,11 @@ def archive_storage_path() -> Path:
|
||||
|
||||
|
||||
def _to_path_if_not_none(value: str | None) -> Path | None:
|
||||
"""Convert a string to Path if it's not None."""
|
||||
return Path(value) if value is not None else None
|
||||
"""Convert a string to Path; None and the legacy "None" both map to None.
|
||||
|
||||
Sidecars written before as_dict skipped unset paths hold str(None).
|
||||
"""
|
||||
return Path(value) if value is not None and value != "None" else None
|
||||
|
||||
|
||||
def _parse_framework_version(framework_version: str) -> Version:
|
||||
@@ -170,8 +173,10 @@ class StorageJSON:
|
||||
"address": self.address,
|
||||
"web_port": self.web_port,
|
||||
"esp_platform": self.target_platform,
|
||||
"build_path": str(self.build_path),
|
||||
"firmware_bin_path": str(self.firmware_bin_path),
|
||||
"build_path": str(self.build_path) if self.build_path else None,
|
||||
"firmware_bin_path": (
|
||||
str(self.firmware_bin_path) if self.firmware_bin_path else None
|
||||
),
|
||||
"loaded_integrations": sorted(self.loaded_integrations),
|
||||
"loaded_platforms": sorted(self.loaded_platforms),
|
||||
"no_mdns": self.no_mdns,
|
||||
@@ -189,7 +194,18 @@ class StorageJSON:
|
||||
write_file_if_changed(path, self.to_json())
|
||||
|
||||
@staticmethod
|
||||
def from_esphome_core(esph: CoreType, old: StorageJSON | None) -> StorageJSON:
|
||||
def from_esphome_core(
|
||||
esph: CoreType, old: StorageJSON | None, *, claim_build: bool = True
|
||||
) -> StorageJSON:
|
||||
"""Build a sidecar from post-validation CORE state.
|
||||
|
||||
claim_build=False (the upload/logs fallback, which runs no build)
|
||||
carries the build-artifact fields (esphome_version,
|
||||
firmware_bin_path) from *old* instead of asserting this run built
|
||||
firmware. Validation-derived fields (platform, framework_version,
|
||||
toolchain, build_path) always stamp; storage_should_clean compares
|
||||
them against the next compile.
|
||||
"""
|
||||
hardware = esph.target_platform.upper()
|
||||
framework_version: str | None = None
|
||||
if esph.is_esp32:
|
||||
@@ -204,13 +220,21 @@ class StorageJSON:
|
||||
name=esph.name,
|
||||
friendly_name=esph.friendly_name,
|
||||
comment=esph.comment,
|
||||
esphome_version=const.__version__,
|
||||
esphome_version=(
|
||||
const.__version__
|
||||
if claim_build
|
||||
else (old.esphome_version if old else None)
|
||||
),
|
||||
src_version=1,
|
||||
address=esph.address,
|
||||
web_port=esph.web_port,
|
||||
target_platform=hardware,
|
||||
build_path=esph.build_path,
|
||||
firmware_bin_path=esph.firmware_bin,
|
||||
firmware_bin_path=(
|
||||
esph.firmware_bin
|
||||
if claim_build
|
||||
else (old.firmware_bin_path if old else None)
|
||||
),
|
||||
loaded_integrations=esph.loaded_integrations,
|
||||
loaded_platforms=esph.loaded_platforms,
|
||||
no_mdns=(
|
||||
@@ -302,11 +326,27 @@ class StorageJSON:
|
||||
except Exception: # noqa: BLE001 # pylint: disable=broad-except
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def load_strict(path: Path) -> StorageJSON | None:
|
||||
"""Like load, but None only means missing; an unreadable file raises."""
|
||||
if not path.is_file():
|
||||
return None
|
||||
return StorageJSON._load_impl(path)
|
||||
|
||||
def can_apply_to_core(self) -> bool:
|
||||
"""True when the sidecar carries everything apply_to_core hands CORE.
|
||||
|
||||
Wizard-written sidecars leave build_path unset (older wizards also
|
||||
the platform fields) and can't drive upload/logs.
|
||||
"""
|
||||
return bool((self.core_platform or self.target_platform) and self.build_path)
|
||||
|
||||
def apply_to_core(self) -> None:
|
||||
"""Populate CORE with the metadata upload/logs read.
|
||||
|
||||
Inverse of :meth:`from_esphome_core`. Keep paired -- a new
|
||||
attribute upload/logs needs has to be captured there too.
|
||||
attribute upload/logs needs has to be captured there too and
|
||||
reflected in :meth:`can_apply_to_core`.
|
||||
Validator-only fields (loaded_integrations/platforms,
|
||||
friendly_name) are skipped; the fast path doesn't run
|
||||
validation and CORE.__init__ defaults them.
|
||||
|
||||
Reference in New Issue
Block a user