Reject malformed build.flags by name and pin the idedata cache-hit path

This commit is contained in:
J. Nick Koston
2026-08-20 15:59:03 -05:00
parent 7a3f700206
commit 12c1b15578
2 changed files with 26 additions and 4 deletions
+12 -4
View File
@@ -35,7 +35,7 @@ import os
from pathlib import Path
from typing import TYPE_CHECKING
from esphome.platformio.library import ensure_list
from esphome.core import EsphomeError
if TYPE_CHECKING:
from esphome.platformio.library import ConvertedLibrary
@@ -89,9 +89,17 @@ def apply_extra_script(
extra_flags = captured_as_build_flags(result, library_dir=source_path)
if not extra_flags:
return
flags = ensure_list(component.data.setdefault("build", {}).setdefault("flags", []))
flags.extend(extra_flags)
component.data["build"]["flags"] = flags
flags = component.data.setdefault("build", {}).setdefault("flags", [])
if isinstance(flags, str):
flags = [flags]
elif not isinstance(flags, list):
# A null/dict value coerced through a list wrapper would inject a
# non-string into the compiler command line; fail naming the library
raise EsphomeError(
f"Library {component.name} has a malformed build.flags "
f"({type(flags).__name__}); expected a string or list"
)
component.data["build"]["flags"] = [*flags, *extra_flags]
# Keys we know how to translate back into ESPHome's build-flag pipeline.
@@ -451,3 +451,17 @@ def test_load_or_build_idedata_never_caches_bad_compiler(tmp_path: Path) -> None
)
assert data["cxx_path"] == "/usr/bin/python3"
assert not cache.exists()
def test_load_or_build_idedata_cache_hit_skips_rebuild(tmp_path: Path) -> None:
"""A valid cache newer than the compile DB is served without re-parsing."""
compile_commands = _write_compile_commands(tmp_path)
cache = tmp_path / "c.json"
cache.write_text(json.dumps({"cc_path": "/tools/gcc", "cached": True}))
os.utime(cache, (compile_commands.stat().st_mtime + 5,) * 2)
with patch.object(idedata, "idedata_from_build") as mock_build:
data = idedata.load_or_build_idedata(
compile_commands, tmp_path / "f.elf", cache
)
mock_build.assert_not_called()
assert data["cached"] is True