From aa63eb9734cd0104771ef224762654e8a2df794a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 22 Aug 2026 21:18:48 -0500 Subject: [PATCH] Move the resolve-for-me ccache sentinel to its one consumer --- esphome/arduino8266/toolchain.py | 16 ++++++++++++---- tests/unit_tests/test_arduino8266_toolchain.py | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/esphome/arduino8266/toolchain.py b/esphome/arduino8266/toolchain.py index f671a68ba7..8d9292e501 100644 --- a/esphome/arduino8266/toolchain.py +++ b/esphome/arduino8266/toolchain.py @@ -6,8 +6,10 @@ import json import logging from pathlib import Path import subprocess +from typing import Any from esphome.arduino8266 import framework +from esphome.build_helpers.ccache import resolve_ccache_path from esphome.const import ( CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, @@ -78,7 +80,7 @@ def run_compile(config: ConfigType, verbose: bool) -> int: paths = framework.check_and_install(CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]) # Resolved once per build: the resolution probes PATH and spawns the # runnability check, and three consumers need the same answer - ccache = framework.ccache_path() + ccache = resolve_ccache_path() ninja_changed = build_gen.write_project(paths, ccache) build_dir = get_build_dir() @@ -262,7 +264,11 @@ def _print_size_summary(build_dir: Path, paths: framework.InstalledPaths) -> Non print_size_line("Flash", flash, app_size) -def get_idedata(ccache: str | None = framework.CCACHE_UNRESOLVED) -> dict | None: +# Sentinel: "resolve for me"; None is a real value meaning disabled. +_CCACHE_UNRESOLVED: Any = object() + + +def get_idedata(ccache: str | None = _CCACHE_UNRESOLVED) -> dict | None: """Derive idedata from the build's compile_commands.json. Same contract as ``espidf.toolchain.get_idedata``: the fields IDE @@ -270,8 +276,10 @@ def get_idedata(ccache: str | None = framework.CCACHE_UNRESOLVED) -> dict | None """ from esphome.build_helpers.idedata import load_or_build_idedata - if ccache is framework.CCACHE_UNRESOLVED: - ccache = framework.ccache_path() + if ccache is _CCACHE_UNRESOLVED: + # Deliberately uncached: env/PATH can change between builds in a + # long-lived host process + ccache = resolve_ccache_path() return load_or_build_idedata( get_build_dir() / "compile_commands.json", get_elf_path(), diff --git a/tests/unit_tests/test_arduino8266_toolchain.py b/tests/unit_tests/test_arduino8266_toolchain.py index ec760887ae..a949dccc4b 100644 --- a/tests/unit_tests/test_arduino8266_toolchain.py +++ b/tests/unit_tests/test_arduino8266_toolchain.py @@ -357,7 +357,7 @@ def test_get_idedata_delegates(tmp_path: Path) -> None: "esphome.build_helpers.idedata.load_or_build_idedata", return_value={"cc_path": "x"}, ) as mock_load, - patch.object(framework, "ccache_path", return_value=Path("/cc/ccache")), + patch.object(toolchain, "resolve_ccache_path", return_value="/cc/ccache"), ): assert toolchain.get_idedata() == {"cc_path": "x"} compile_commands, elf, cache = mock_load.call_args[0] @@ -373,7 +373,7 @@ def test_get_idedata_no_ccache(tmp_path: Path) -> None: patch( "esphome.build_helpers.idedata.load_or_build_idedata", return_value={} ) as mock_load, - patch.object(framework, "ccache_path", return_value=None), + patch.object(toolchain, "resolve_ccache_path", return_value=None), ): toolchain.get_idedata() assert mock_load.call_args.kwargs["launcher"] is None @@ -513,7 +513,7 @@ def test_get_idedata_accepts_preresolved_ccache() -> None: "esphome.build_helpers.idedata.load_or_build_idedata", return_value={"ok": True}, ) as mock_build, - patch.object(framework, "ccache_path") as mock_resolve, + patch.object(toolchain, "resolve_ccache_path") as mock_resolve, ): assert toolchain.get_idedata("/usr/bin/ccache") == {"ok": True} mock_resolve.assert_not_called()