Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend

This commit is contained in:
J. Nick Koston
2026-08-25 13:34:51 -05:00
4 changed files with 57 additions and 21 deletions
+16 -7
View File
@@ -1209,14 +1209,23 @@ def _ccache_env() -> dict[str, str]:
# export the canonical off spelling instead
return {"IDF_CCACHE_ENABLE": "0"}
if idf_knob is True:
# Forced on ignores the runnability verdict, but a missing or
# unusable binary is worth saying out loud: idf.py silently
# compiles without ccache in that case
# Forced on ignores the runnability verdict, but the outcome is
# worth saying out loud. Only the truly-missing case means idf.py
# compiles without ccache; a present-but-rejected binary (probe
# failure or shared opt-out) is still used, since idf.py does its
# own PATH lookup.
if resolve_ccache_path() is None:
_LOGGER.warning(
"IDF_CCACHE_ENABLE=1 but no usable ccache binary was "
"found; idf.py will compile without ccache"
)
if shutil.which("ccache") is None:
_LOGGER.warning(
"IDF_CCACHE_ENABLE=1 but no ccache binary is on PATH; "
"idf.py will compile without ccache"
)
else:
_LOGGER.warning(
"IDF_CCACHE_ENABLE=1 forces ccache on even though it "
"was rejected here (probe failure or "
"ESPHOME_CCACHE_ENABLE=0); idf.py will use it anyway"
)
elif resolve_ccache_path() is None:
# ESP-IDF silently skips ccache without the binary; export the
# canonical off spelling so an unparsable inherited value (or a
+11 -12
View File
@@ -218,18 +218,17 @@ def prefetch_packages(
def _fetch(entry: _PendingArchive, tracker: Callable[[int], None]) -> None:
entry.dest.parent.mkdir(parents=True, exist_ok=True)
with FileLock(f"{entry.dest}.lock", fallback_to_soft=False):
if (entry.dest / ".esphome_extracted").is_file():
# A concurrent build installed (and deleted the archive of)
# this package while we waited; re-downloading would orphan
# a fresh copy in downloads_dir
return
download_with_resume(
entry.url,
downloads_dir / f"{entry.name}-{entry.version}",
sha256=entry.sha256,
size=entry.size,
progress=tracker,
)
# Marker re-check: a concurrent build may have installed (and
# deleted the archive of) this package while we waited;
# re-downloading would orphan a fresh copy in downloads_dir
if not (entry.dest / ".esphome_extracted").is_file():
download_with_resume(
entry.url,
downloads_dir / f"{entry.name}-{entry.version}",
sha256=entry.sha256,
size=entry.size,
progress=tracker,
)
failures = run_batch_downloads(
"Downloading packages",
+20 -1
View File
@@ -1613,7 +1613,26 @@ def test_ccache_env_opt_in_without_binary(
assert env["IDF_CCACHE_ENABLE"] == "1"
assert env["CCACHE_DIR"] == str(tmp_path / "tools" / "ccache")
assert env["CCACHE_DEPEND"] == "1"
assert "no usable ccache binary" in caplog.text
assert "no ccache binary is on PATH" in caplog.text
def test_ccache_env_opt_in_with_rejected_binary(
tmp_path: Path, caplog: pytest.LogCaptureFixture
) -> None:
# Forced on with a present-but-rejected binary: idf.py does its own
# PATH lookup and uses it anyway; the warning must say so, not claim
# the build runs without ccache.
p1, p2, p3 = _ccache_patches(tmp_path, None, tmp_path / "build")
with (
patch.dict("os.environ", {"IDF_CCACHE_ENABLE": "1"}, clear=True),
patch("esphome.espidf.framework.shutil.which", return_value="/usr/bin/ccache"),
p1,
p2,
p3,
):
env = _ccache_env()
assert env["IDF_CCACHE_ENABLE"] == "1"
assert "idf.py will use it anyway" in caplog.text
def test_ccache_env_honors_shared_esphome_opt_out(tmp_path: Path) -> None:
+10 -1
View File
@@ -539,8 +539,17 @@ def test_prefetch_packages_skips_freshly_installed_dest(tmp_path: Path) -> None:
already installed; re-downloading would orphan an archive copy."""
dest = tmp_path / "a"
dest.mkdir()
(dest / ".esphome_extracted").touch()
from contextlib import contextmanager
@contextmanager
def marker_appears_under_lock(path, **kwargs):
# Simulates the concurrent build finishing while we waited
(dest / ".esphome_extracted").touch()
yield
with (
patch("filelock.FileLock", side_effect=marker_appears_under_lock),
patch.object(registry, "download_with_resume") as mock_download,
patch.object(
registry, "registry_download", side_effect=_resolve_for({"a": 10})