mirror of
https://github.com/esphome/esphome.git
synced 2026-09-19 02:58:38 +00:00
[external_files] Skip remote freshness checks during esphome logs
Avoid per-file HTTP HEAD requests during config validation when running esphome logs against a previously-cached project. The skip_external_update flag was already plumbed for git operations, but external_files.download_content ignored it. Thread it through CORE so audio_file, micro_wake_word, speaker/media_player, image, font, and bme68x_bsec2 reuse cached files without per-URL network round-trips when the file already exists locally.
This commit is contained in:
@@ -997,6 +997,8 @@ def validate_config(
|
||||
) -> Config:
|
||||
result = Config()
|
||||
|
||||
CORE.skip_external_update = skip_external_update
|
||||
|
||||
loader.clear_component_meta_finders()
|
||||
loader.install_custom_components_meta_finder()
|
||||
|
||||
|
||||
@@ -615,6 +615,9 @@ class EsphomeCore:
|
||||
self.address_cache: AddressCache | None = None
|
||||
# Cached config hash (computed lazily)
|
||||
self._config_hash: int | None = None
|
||||
# When True, skip network freshness checks for cached external files
|
||||
# (e.g. for `esphome logs`, where remote downloads aren't needed)
|
||||
self.skip_external_update: bool = False
|
||||
|
||||
def reset(self):
|
||||
from esphome.pins import PIN_SCHEMA_REGISTRY
|
||||
@@ -644,6 +647,7 @@ class EsphomeCore:
|
||||
self.current_component = None
|
||||
self.address_cache = None
|
||||
self._config_hash = None
|
||||
self.skip_external_update = False
|
||||
PIN_SCHEMA_REGISTRY.reset()
|
||||
|
||||
@contextmanager
|
||||
|
||||
@@ -82,6 +82,9 @@ def compute_local_file_dir(domain: str) -> Path:
|
||||
|
||||
|
||||
def download_content(url: str, path: Path, timeout=NETWORK_TIMEOUT) -> bytes:
|
||||
if CORE.skip_external_update and path.exists():
|
||||
_LOGGER.debug("Skipping update for %s (refresh disabled)", url)
|
||||
return path.read_bytes()
|
||||
if not has_remote_file_changed(url, path):
|
||||
_LOGGER.debug("Remote file has not changed %s", url)
|
||||
return path.read_bytes()
|
||||
|
||||
@@ -236,3 +236,51 @@ def test_download_content_with_network_error_no_cache_fails(
|
||||
|
||||
with pytest.raises(Invalid, match="Could not download from.*Network error"):
|
||||
external_files.download_content(url, test_file)
|
||||
|
||||
|
||||
@patch("esphome.external_files.requests.get")
|
||||
@patch("esphome.external_files.has_remote_file_changed")
|
||||
def test_download_content_skip_external_update_uses_cache(
|
||||
mock_has_changed: MagicMock, mock_get: MagicMock, setup_core: Path
|
||||
) -> None:
|
||||
"""Test download_content skips network checks when CORE.skip_external_update is set."""
|
||||
test_file = setup_core / "cached.txt"
|
||||
cached_content = b"cached content"
|
||||
test_file.write_bytes(cached_content)
|
||||
|
||||
CORE.skip_external_update = True
|
||||
try:
|
||||
url = "https://example.com/file.txt"
|
||||
result = external_files.download_content(url, test_file)
|
||||
finally:
|
||||
CORE.skip_external_update = False
|
||||
|
||||
assert result == cached_content
|
||||
mock_has_changed.assert_not_called()
|
||||
mock_get.assert_not_called()
|
||||
|
||||
|
||||
@patch("esphome.external_files.requests.get")
|
||||
@patch("esphome.external_files.has_remote_file_changed")
|
||||
def test_download_content_skip_external_update_downloads_when_missing(
|
||||
mock_has_changed: MagicMock, mock_get: MagicMock, setup_core: Path
|
||||
) -> None:
|
||||
"""Test download_content still downloads when file is missing, even with skip_external_update."""
|
||||
test_file = setup_core / "missing.txt"
|
||||
new_content = b"fresh content"
|
||||
|
||||
mock_has_changed.return_value = True
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = new_content
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
CORE.skip_external_update = True
|
||||
try:
|
||||
url = "https://example.com/file.txt"
|
||||
result = external_files.download_content(url, test_file)
|
||||
finally:
|
||||
CORE.skip_external_update = False
|
||||
|
||||
assert result == new_content
|
||||
assert test_file.read_bytes() == new_content
|
||||
|
||||
Reference in New Issue
Block a user