mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 12:35:25 +00:00
[core] Clean build when the toolchain changes (#16744)
This commit is contained in:
committed by
Jesse Hills
parent
a4d247fa0a
commit
571a12ffe5
@@ -90,10 +90,12 @@ def storage_should_clean(old: StorageJSON | None, new: StorageJSON) -> bool:
|
||||
"""Return True when the build tree must be wiped before reuse.
|
||||
|
||||
Predicate is True when *old* is missing (first build),
|
||||
``src_version`` differs, ``build_path`` differs, or a previously
|
||||
loaded integration was removed in *new*. Adding integrations or
|
||||
changing unrelated fields (friendly name, esphome version, etc.)
|
||||
does not trigger a clean.
|
||||
``src_version`` differs, ``build_path`` differs, the build
|
||||
``toolchain`` differs (e.g. switching between the PlatformIO and
|
||||
native ESP-IDF toolchains, which produce incompatible build trees),
|
||||
or a previously loaded integration was removed in *new*. Adding
|
||||
integrations or changing unrelated fields (friendly name, esphome
|
||||
version, etc.) does not trigger a clean.
|
||||
|
||||
Used by esphome-device-builder (esphome/device-builder) to gate
|
||||
its remote-build artifact materialiser so a local → remote → local
|
||||
@@ -109,6 +111,8 @@ def storage_should_clean(old: StorageJSON | None, new: StorageJSON) -> bool:
|
||||
return True
|
||||
if old.build_path != new.build_path:
|
||||
return True
|
||||
if old.toolchain != new.toolchain:
|
||||
return True
|
||||
# Check if any components have been removed
|
||||
return bool(old.loaded_integrations - new.loaded_integrations)
|
||||
|
||||
@@ -505,6 +509,10 @@ def clean_build(clear_pio_cache: bool = True):
|
||||
if dependencies_lock.is_file():
|
||||
_LOGGER.info("Deleting %s", dependencies_lock)
|
||||
dependencies_lock.unlink()
|
||||
idedata_cache = CORE.relative_internal_path("idedata", f"{CORE.name}.json")
|
||||
if idedata_cache.is_file():
|
||||
_LOGGER.info("Deleting %s", idedata_cache)
|
||||
idedata_cache.unlink()
|
||||
# Native ESP-IDF toolchain artifacts: the IDF CMake/ninja build dir
|
||||
# and the Component Manager's fetched managed components live under
|
||||
# the project's build path, not under .pioenvs / .piolibdeps.
|
||||
|
||||
@@ -75,6 +75,7 @@ def create_storage() -> Callable[..., StorageJSON]:
|
||||
no_mdns=kwargs.get("no_mdns", False),
|
||||
framework=kwargs.get("framework", "arduino"),
|
||||
core_platform=kwargs.get("core_platform", "esp32"),
|
||||
toolchain=kwargs.get("toolchain", "platformio"),
|
||||
)
|
||||
|
||||
return _create
|
||||
@@ -106,6 +107,20 @@ def test_storage_should_clean_when_build_path_changes(
|
||||
assert storage_should_clean(old, new) is True
|
||||
|
||||
|
||||
def test_storage_should_clean_when_toolchain_changes(
|
||||
create_storage: Callable[..., StorageJSON],
|
||||
) -> None:
|
||||
"""Test that clean is triggered when the build toolchain changes.
|
||||
|
||||
Switching between the PlatformIO and native ESP-IDF toolchains produces
|
||||
incompatible build trees (and toolchain-specific idedata), so the build
|
||||
must be wiped.
|
||||
"""
|
||||
old = create_storage(loaded_integrations=["api", "wifi"], toolchain="platformio")
|
||||
new = create_storage(loaded_integrations=["api", "wifi"], toolchain="esp-idf")
|
||||
assert storage_should_clean(old, new) is True
|
||||
|
||||
|
||||
def test_storage_should_clean_when_component_removed(
|
||||
create_storage: Callable[..., StorageJSON],
|
||||
) -> None:
|
||||
@@ -443,6 +458,11 @@ def test_clean_build(
|
||||
dependencies_lock = tmp_path / "dependencies.lock"
|
||||
dependencies_lock.write_text("lock file")
|
||||
|
||||
# idedata cache lives under the data dir, not the build path.
|
||||
idedata_cache = tmp_path / "idedata" / "test.json"
|
||||
idedata_cache.parent.mkdir()
|
||||
idedata_cache.write_text("{}")
|
||||
|
||||
# Native ESP-IDF toolchain artifacts.
|
||||
idf_build_dir = tmp_path / "build"
|
||||
idf_build_dir.mkdir()
|
||||
@@ -463,11 +483,14 @@ def test_clean_build(
|
||||
mock_core.relative_pioenvs_path.return_value = pioenvs_dir
|
||||
mock_core.relative_piolibdeps_path.return_value = piolibdeps_dir
|
||||
mock_core.relative_build_path.side_effect = lambda name: tmp_path / name
|
||||
mock_core.name = "test"
|
||||
mock_core.relative_internal_path.side_effect = tmp_path.joinpath
|
||||
|
||||
# Verify all exist before
|
||||
assert pioenvs_dir.exists()
|
||||
assert piolibdeps_dir.exists()
|
||||
assert dependencies_lock.exists()
|
||||
assert idedata_cache.exists()
|
||||
assert idf_build_dir.exists()
|
||||
assert managed_components_dir.exists()
|
||||
assert platformio_cache_dir.exists()
|
||||
@@ -492,6 +515,7 @@ def test_clean_build(
|
||||
assert not pioenvs_dir.exists()
|
||||
assert not piolibdeps_dir.exists()
|
||||
assert not dependencies_lock.exists()
|
||||
assert not idedata_cache.exists()
|
||||
assert not idf_build_dir.exists()
|
||||
assert not managed_components_dir.exists()
|
||||
assert not platformio_cache_dir.exists()
|
||||
@@ -501,6 +525,7 @@ def test_clean_build(
|
||||
assert ".pioenvs" in caplog.text
|
||||
assert ".piolibdeps" in caplog.text
|
||||
assert "dependencies.lock" in caplog.text
|
||||
assert str(idedata_cache) in caplog.text
|
||||
assert str(idf_build_dir) in caplog.text
|
||||
assert str(managed_components_dir) in caplog.text
|
||||
assert "PlatformIO cache" in caplog.text
|
||||
|
||||
Reference in New Issue
Block a user