diff --git a/esphome/build_gen/arduino8266.py b/esphome/build_gen/arduino8266.py index 496ec1167e..50b506ef82 100644 --- a/esphome/build_gen/arduino8266.py +++ b/esphome/build_gen/arduino8266.py @@ -21,6 +21,7 @@ import logging import os from pathlib import Path import re +import shlex import subprocess import sys from typing import TYPE_CHECKING, NamedTuple @@ -722,7 +723,9 @@ def generate_ld_scripts( # and the surgery fingerprint (a build_surgery edit invalidates old # build dirs) stamp_content = ( - " ".join(cmd) + # shlex.join: a spaced path stays one quoted element, so two + # different cmd lists can never collide to the same stamp string + shlex.join(cmd) + f" testing={CORE.testing_mode}" + f" header={_stat_sig(header)}" + f" gcc={_stat_sig(gcc)}" diff --git a/tests/unit_tests/build_gen/test_arduino8266.py b/tests/unit_tests/build_gen/test_arduino8266.py index 6528f79226..cd9ffcd3ce 100644 --- a/tests/unit_tests/build_gen/test_arduino8266.py +++ b/tests/unit_tests/build_gen/test_arduino8266.py @@ -64,30 +64,32 @@ def _shq(tok: str) -> str: return f'"{tok}"' if os.name == "nt" else f"'{tok}'" -def _resolve(*flags: str): +def _resolve(*flags: str) -> arduino8266._BuildConfig: """Set the build flags and resolve the knob config in one step.""" _set_flags(*flags) return _resolve_current() -def _defines(): +def _defines() -> dict[str, str]: """The -D map for the current build flags.""" return _flag_defines(set(), arduino8266._lexed_build_flags()) -def _resolve_current(): +def _resolve_current() -> arduino8266._BuildConfig: """Resolve whatever flags are already set (must not clear them).""" return _resolve_build_config(_defines()) -def _split_flags(): +def _split_flags() -> tuple[list[str], list[str], list[Path], list[str]]: """Classify the current build flags the way write_project does.""" return arduino8266._project_flags( arduino8266._unflag_tokens(), arduino8266._lexed_build_flags() ) -def _ok_result(stdout=None, stderr=""): +def _ok_result( + stdout: str | bytes | None = None, stderr: str | bytes = "" +) -> MagicMock: """A successful preprocessor spawn (defaults to the common ld output). Streams are bytes, as the un-decoded subprocess.run delivers them.