mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
Reraise in strict through the IDF flow, funnel the remaining degrade paths, exempt nobuild
This commit is contained in:
@@ -334,6 +334,7 @@ def prepare_pch() -> None:
|
||||
"Could not read %s; compiling without the pch: %s", sdkconfig_path, err
|
||||
)
|
||||
pch.discard_pch(CORE.relative_build_path("build"))
|
||||
pch.pch_degraded(f"sdkconfig unreadable: {err}")
|
||||
return
|
||||
pch.prepare_pch(
|
||||
CORE.relative_build_path("build"),
|
||||
|
||||
@@ -407,6 +407,7 @@ def prepare_pch(
|
||||
-result.returncode,
|
||||
)
|
||||
discard_pch(build_dir)
|
||||
pch_degraded(f"compile killed by signal {-result.returncode}")
|
||||
return
|
||||
if result.returncode != 0:
|
||||
error = result.stderr.strip() or f"exit code {result.returncode}"
|
||||
|
||||
@@ -539,6 +539,10 @@ def run_compile(config, verbose: bool) -> int:
|
||||
# Discard so a stale .gch can never be consumed
|
||||
with suppress(OSError):
|
||||
discard_pch()
|
||||
from esphome.build_helpers.pch import pch_strict
|
||||
|
||||
if pch_strict():
|
||||
raise
|
||||
_LOGGER.warning(
|
||||
"Precompiled header setup failed; compiling without it", exc_info=True
|
||||
)
|
||||
|
||||
@@ -160,9 +160,10 @@ def _read_stamp(path: Path) -> str:
|
||||
|
||||
def _setup_pch() -> bool | None:
|
||||
if projenv is None:
|
||||
# Expected under -t nobuild; anything else must leave a trail
|
||||
# Expected under -t nobuild (nothing compiles), so not a degrade
|
||||
# even in strict mode; anything else still leaves a trail
|
||||
print(f"ESPHome: projenv unavailable ({_projenv_error}); skipping pch")
|
||||
return
|
||||
return True
|
||||
# Project root: SCons compiles run here, so the relative -include
|
||||
# resolves; an absolute path would break cross-device ccache sharing.
|
||||
proj_dir = Path(env.subst("$PROJECT_DIR")) # noqa: F821
|
||||
|
||||
@@ -669,6 +669,29 @@ def test_get_core_framework_version_from_core_data():
|
||||
assert toolchain._get_core_framework_version() == "5.5.4"
|
||||
|
||||
|
||||
def test_run_compile_strict_reraises_pch_failure(
|
||||
setup_core: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""ESPHOME_PCH_STRICT must reach through the real compile flow."""
|
||||
from esphome.core import EsphomeError
|
||||
|
||||
monkeypatch.setenv("ESPHOME_PCH_ENABLE", "1")
|
||||
monkeypatch.setenv("ESPHOME_PCH_STRICT", "1")
|
||||
_setup_build(setup_core)
|
||||
|
||||
with (
|
||||
patch.object(toolchain, "need_reconfigure", return_value=False),
|
||||
patch.object(toolchain, "run_idf_py", return_value=0),
|
||||
patch.object(toolchain, "print_summary"),
|
||||
patch(
|
||||
"esphome.build_gen.espidf.prepare_pch",
|
||||
side_effect=EsphomeError("ESPHOME_PCH_STRICT: no usable compile command"),
|
||||
),
|
||||
pytest.raises(EsphomeError, match="no usable compile command"),
|
||||
):
|
||||
toolchain.run_compile({CONF_ESPHOME: {}}, verbose=False)
|
||||
|
||||
|
||||
def test_run_compile_invokes_prepare_pch_and_survives_failure(
|
||||
setup_core: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
|
||||
@@ -462,10 +462,34 @@ def test_pch_script_unreadable_local_header_skips_pch(
|
||||
|
||||
def test_pch_script_strict_raises_when_pch_not_used(tmp_path: Path) -> None:
|
||||
"""ESPHOME_PCH_STRICT fails the build instead of degrading."""
|
||||
with pytest.raises(Exception, match="ESPHOME_PCH_STRICT|boom"):
|
||||
with pytest.raises(RuntimeError, match="ESPHOME_PCH_STRICT"):
|
||||
_run_script(tmp_path, fail=True, env_vars={"ESPHOME_PCH_STRICT": "1"})
|
||||
|
||||
|
||||
def test_pch_script_strict_reraises_internal_errors(tmp_path: Path) -> None:
|
||||
"""The catch-all must not swallow programming errors in strict mode."""
|
||||
with pytest.raises(TypeError):
|
||||
_run_script(tmp_path, env_vars={"ESPHOME_PCH_STRICT": "1"}, platform_cls=None)
|
||||
|
||||
|
||||
def test_pch_script_strict_allows_nobuild_skip(tmp_path: Path) -> None:
|
||||
"""-t nobuild compiles nothing; the skip is expected even in strict."""
|
||||
proj = tmp_path / "dev"
|
||||
(proj / "src").mkdir(parents=True)
|
||||
|
||||
def strict_import(*names: str) -> None:
|
||||
if "projenv" in names:
|
||||
raise RuntimeError("Import of non-existent variable 'projenv'")
|
||||
|
||||
env = _FakeSConsEnv(proj, proj / "src", "g++", ["-DX=1"])
|
||||
with patch.dict(os.environ, {"ESPHOME_PCH_STRICT": "1"}, clear=True):
|
||||
exec( # noqa: S102
|
||||
compile(_SCRIPT.read_text(), "pch.py", "exec"),
|
||||
{"Import": strict_import, "env": env},
|
||||
)
|
||||
assert not (proj / "esphome_pch.h").exists()
|
||||
|
||||
|
||||
def test_pch_script_strict_passes_on_success(tmp_path: Path) -> None:
|
||||
scons_env = _run_script(tmp_path, env_vars={"ESPHOME_PCH_STRICT": "1"})
|
||||
assert scons_env.prepended
|
||||
|
||||
Reference in New Issue
Block a user