Merge branch 'esp8266-native-shared-helpers' into esp8266-native-build-surgery

This commit is contained in:
J. Nick Koston
2026-08-24 12:20:18 -05:00
3 changed files with 38 additions and 33 deletions
+1 -1
View File
@@ -791,7 +791,7 @@ def _prefetch_idf_tool_archives(
# failure_reason: a message-less exception must not log blank
_LOGGER.warning("Could not prefetch %s: %s", name, failure_reason(e))
_LOGGER.debug("Prefetch failure detail", exc_info=e)
if failures and len(failures) == len(entries):
if len(failures) == len(entries):
# A systematic fault, not one flaky mirror: the resume
# workaround (#17703) is off for this whole install
_LOGGER.error(
+15 -15
View File
@@ -776,16 +776,14 @@ def run_batch_downloads(
try:
fetch(checked)
except (_BatchDownloadCancelled, Exception) as err: # noqa: BLE001 # pylint: disable=broad-exception-caught
# A cancelled job reports like a failure: an abandoned download
# must never read as completed if a caller sees the list after
# Ctrl-C
failure = (name, err)
else:
return None
# A bar-frame write failure must not displace the download error
with suppress(Exception):
tracker(0)
return failure
# The cancelled arm exists for the tracker rollback below; the
# batch re-raises the interrupt, so the list is never returned
# after Ctrl-C. A bar-frame write failure must not displace the
# download error.
with suppress(Exception):
tracker(0)
return (name, err)
return None
ex = ThreadPoolExecutor(max_workers=max_workers)
try:
@@ -1316,11 +1314,13 @@ def download_from_mirrors(
)
# Tick with the bytes already on disk so a combined bar holds
# steady during the backoff instead of rewinding to zero
if f is not None:
done = f.tell()
else:
part = _part_path(path_target)
done = part.stat().st_size if part.is_file() else 0
done = 0
if progress is not None:
if f is not None:
done = f.tell()
else:
part = _part_path(path_target)
done = part.stat().st_size if part.is_file() else 0
_cancellable_sleep(delay, progress, done)
# 4. Report every attempted URL if all mirrors failed. failures spans
+22 -17
View File
@@ -446,6 +446,27 @@ def split_list_by_condition(
return matched, non_matched
def _valid_manifest_shape(data: Any) -> bool:
"""Whether the manifest has the dict shapes every backend dereferences.
A bare json.load imposes no shape; validating once here means a
malformed third-party manifest fails by library name instead of a raw
TypeError/AttributeError in a backend.
"""
if not isinstance(data, dict):
return False
build = data.get("build", {})
esphome_data = data.get(ESPHOME_DATA_KEY, {})
return (
isinstance(build, dict)
and isinstance(esphome_data, dict)
and isinstance(esphome_data.get(ESPHOME_DATA_LINK_FLAGS_KEY, []), list)
and isinstance(build.get("srcDir", ""), str)
and isinstance(build.get("includeDir", ""), str)
and isinstance(build.get("srcFilter", ""), (str, list))
)
def check_library_data(data: dict, platform: str | None, framework: str):
"""
Check whether a library manifest is compatible with the target toolchain.
@@ -1132,23 +1153,7 @@ def convert_libraries(
f"library.properties in {source_dir}"
)
# A bare json.load imposes no shape; every backend dereferences
# these fields, so validate once here and name the library
malformed = not isinstance(component.data, dict)
if not malformed:
build = component.data.get("build", {})
esphome_data = component.data.get(ESPHOME_DATA_KEY, {})
malformed = (
not isinstance(build, dict)
or not isinstance(esphome_data, dict)
or not isinstance(
esphome_data.get(ESPHOME_DATA_LINK_FLAGS_KEY, []), list
)
or not isinstance(build.get("srcDir", ""), str)
or not isinstance(build.get("includeDir", ""), str)
or not isinstance(build.get("srcFilter", ""), (str, list))
)
if malformed:
if not _valid_manifest_shape(component.data):
# Fail fast only for a library the user asked for; a defect
# in an unrequested corner of the graph must not block the
# build