Make the testing-mode require explicit, reject a missing declared srcDir, and validate installs before marking success

This commit is contained in:
J. Nick Koston
2026-08-20 08:08:29 -05:00
parent 0defff2c81
commit 4eeceded0d
7 changed files with 63 additions and 17 deletions
+6 -4
View File
@@ -17,7 +17,7 @@ from dataclasses import dataclass, field
import logging
from pathlib import Path
from esphome.core import CORE, Library
from esphome.core import CORE, EsphomeError, Library
from esphome.espidf.extra_script import apply_extra_script
from esphome.platformio.library import (
DEFAULT_BUILD_INCLUDE_DIR,
@@ -68,9 +68,11 @@ def _library_info(name: str, read_path: Path, data: dict) -> ArduinoLibrary:
(d for d in ("src", "Src") if (read_path / d).is_dir()), "."
)
if "srcDir" in build and not (read_path / src_dir).is_dir():
# A silently empty source set would surface as link errors instead
_LOGGER.warning(
"Library %s declares srcDir %s which does not exist", name, src_dir
# Unlike the default probes, an explicitly declared srcDir that does
# not resolve is unambiguously a manifest/tree error; a silently
# empty source set would surface as link errors far from the cause
raise EsphomeError(
f"Library {name} declares srcDir {src_dir} which does not exist"
)
src_filter = ensure_list(build.get("srcFilter", DEFAULT_BUILD_SRC_FILTER))
+12
View File
@@ -17,6 +17,7 @@ toolchain has always used, so the bits are identical); the
from __future__ import annotations
from collections.abc import Collection
import functools
import logging
import os
@@ -178,6 +179,7 @@ def _install_package(
version: str,
dest: Path,
mirrors: list[str],
expect: Collection[str] = (),
) -> None:
"""Download, verify, and extract one package if not already installed.
@@ -207,6 +209,14 @@ def _install_package(
download_with_resume(url, archive, sha256=sha256, size=size)
_LOGGER.info("Extracting %s ...", name)
archive_extract_all(archive, dest, progress_header="Extracting")
# Validate the layout before recording success, so an unexpected package
# is never cached as a working install.
for rel in expect:
if not (dest / rel).is_dir():
raise EsphomeError(
f"{name} {version} extracted without the expected {rel} "
"directory; run 'esphome clean-all' and retry"
)
marker.touch()
archive.unlink(missing_ok=True)
@@ -245,6 +255,7 @@ def check_and_install(framework_version: cv.Version) -> dict[str, Path]:
package_version,
framework_path,
ESPHOME_ARDUINO8266_FRAMEWORK_MIRRORS,
expect=("cores/esp8266", "tools/sdk"),
)
toolchain_path = get_toolchain_path()
_install_package(
@@ -252,6 +263,7 @@ def check_and_install(framework_version: cv.Version) -> dict[str, Path]:
TOOLCHAIN_VERSION,
toolchain_path,
ESPHOME_ARDUINO8266_TOOLCHAIN_MIRRORS,
expect=("bin",),
)
return {
"framework_path": framework_path,
+2 -1
View File
@@ -481,7 +481,8 @@ def write_project(paths: dict[str, Path]) -> bool:
for required in include_dirs:
if not required.is_dir():
raise EsphomeError(
f"Arduino toolchain install is incomplete: missing {required}"
f"Arduino toolchain install is incomplete: missing {required}; "
"run 'esphome clean-all' and retry"
)
for lib in libraries:
include_dirs += lib.include_dirs
+1 -1
View File
@@ -60,7 +60,7 @@ def _patch_segment_size(content: str, segment_name: str, new_size: str) -> str:
return re.sub(pattern, rf"\g<1>{new_size}", content)
def apply_testing_memory_patches(content: str, require: Collection[str] = ()) -> str:
def apply_testing_memory_patches(content: str, require: Collection[str]) -> str:
"""Enlarge IRAM/DRAM/flash segments so grouped CI test builds can link.
``require`` names the segments this file must define; a silently