mirror of
https://github.com/esphome/esphome.git
synced 2026-08-30 01:26:43 +00:00
[esp32] Skip full rebuild on sdkconfig change with the esp-idf toolchain (#18876)
This commit is contained in:
@@ -3249,7 +3249,13 @@ def _write_sdkconfig():
|
||||
if write_file_if_changed(internal_path, contents):
|
||||
# internal changed, update real one
|
||||
write_file_if_changed(sdk_path, contents)
|
||||
clean_build(clear_pio_cache=False)
|
||||
if not CORE.using_toolchain_esp_idf:
|
||||
# PIO's dependency tracking under-declares sdkconfig inputs
|
||||
# (ldgen, linker scripts); without a clean the image can be
|
||||
# unbootable (esphome#15336). The esp-idf toolchain tracks
|
||||
# sdkconfig via IDF's cmake and has_outdated_files(), so a
|
||||
# reconfigure suffices there; everything else fails safe.
|
||||
clean_build(clear_pio_cache=False)
|
||||
|
||||
|
||||
def _write_idf_component_yml():
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
"""Tests for the esp32 sdkconfig write and its toolchain-gated clean."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import time
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.esp32 import _write_sdkconfig
|
||||
from esphome.components.esp32.const import KEY_SDKCONFIG_OPTIONS
|
||||
from esphome.const import KEY_CORE, KEY_ESP32, KEY_FRAMEWORK_VERSION, Toolchain
|
||||
from esphome.core import CORE
|
||||
from esphome.espidf.toolchain import has_outdated_files
|
||||
|
||||
|
||||
def _setup_core(tmp_path: Path, toolchain: Toolchain | None) -> None:
|
||||
CORE.config_path = tmp_path / "test.yaml"
|
||||
CORE.build_path = tmp_path
|
||||
CORE.toolchain = toolchain
|
||||
CORE.data[KEY_ESP32] = {KEY_SDKCONFIG_OPTIONS: {"CONFIG_X": "y"}}
|
||||
CORE.data[KEY_CORE] = {KEY_FRAMEWORK_VERSION: "5.5.5"}
|
||||
|
||||
|
||||
def _seed_configured_build(tmp_path: Path) -> None:
|
||||
"""A settled native build: configure outputs predate what comes next."""
|
||||
build = tmp_path / "build"
|
||||
(build / "config").mkdir(parents=True)
|
||||
(build / "config" / "sdkconfig.h").write_text("")
|
||||
(build / "CMakeCache.txt").write_text("")
|
||||
(build / "build.ninja").write_text("")
|
||||
# Explicitly older than what the test writes next: has_outdated_files()
|
||||
# compares st_mtime with a strict >, so same-tick writes would pass
|
||||
past = time.time() - 60
|
||||
for f in build.rglob("*"):
|
||||
os.utime(f, (past, past))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("toolchain", "clean_expected"),
|
||||
[(Toolchain.ESP_IDF, False), (Toolchain.PLATFORMIO, True), (None, True)],
|
||||
)
|
||||
def test_write_sdkconfig_cleans_only_on_platformio(
|
||||
tmp_path: Path, toolchain: Toolchain | None, clean_expected: bool
|
||||
) -> None:
|
||||
"""A changed sdkconfig forces a full clean only under PlatformIO; the
|
||||
esp-idf toolchain reconfigures via has_outdated_files() instead; an
|
||||
unresolved toolchain fails safe onto the clean."""
|
||||
_setup_core(tmp_path, toolchain)
|
||||
_seed_configured_build(tmp_path)
|
||||
with (
|
||||
patch.object(CORE, "name", "test"),
|
||||
patch("esphome.components.esp32.clean_build") as clean,
|
||||
):
|
||||
_write_sdkconfig()
|
||||
assert "CONFIG_X" in CORE.relative_build_path("sdkconfig.test").read_text()
|
||||
assert clean.called is clean_expected
|
||||
if clean_expected:
|
||||
clean.assert_called_once_with(clear_pio_cache=False)
|
||||
# The change must still trigger a reconfigure: the internal
|
||||
# sdkconfig snapshot is now newer than build/CMakeCache.txt
|
||||
assert has_outdated_files() is True
|
||||
clean.reset_mock()
|
||||
# A settled configure restamps the cache; an unchanged rewrite
|
||||
# must then neither clean nor mark the build stale
|
||||
future = time.time() + 60
|
||||
os.utime(CORE.relative_build_path("build/CMakeCache.txt"), (future, future))
|
||||
_write_sdkconfig()
|
||||
clean.assert_not_called()
|
||||
assert has_outdated_files() is False
|
||||
Reference in New Issue
Block a user