mirror of
https://github.com/esphome/esphome.git
synced 2026-08-23 06:36:23 +00:00
Merge branch 'esp8266-native-framework-installer' into esp8266-native-library-backend
# Conflicts: # tests/unit_tests/test_platformio_library.py
This commit is contained in:
@@ -73,15 +73,16 @@ def print_summary(size_json: Path, partitions_csv: Path | None) -> None:
|
||||
"""Print PlatformIO-shaped RAM and Flash one-liners.
|
||||
|
||||
Failures are non-fatal: the build has already succeeded, we just couldn't
|
||||
summarize. Logs the cause at debug level.
|
||||
summarize. Logs the cause at warning level, so a missing RAM/Flash line
|
||||
(which CI's memory-impact extraction greps for) is diagnosable.
|
||||
"""
|
||||
if not size_json.is_file():
|
||||
_LOGGER.debug("Skipping size summary: %s not found", size_json)
|
||||
_LOGGER.warning("Skipping size summary: %s not found", size_json)
|
||||
return
|
||||
try:
|
||||
data = json.loads(size_json.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
_LOGGER.debug("Skipping size summary: %s", e)
|
||||
_LOGGER.warning("Skipping size summary: %s", e)
|
||||
return
|
||||
|
||||
memory_types = data.get("memory_types", {})
|
||||
@@ -90,6 +91,8 @@ def print_summary(size_json: Path, partitions_csv: Path | None) -> None:
|
||||
ram_total = ram_region.get("size")
|
||||
if ram_total and ram_used is not None:
|
||||
print_size_line("RAM", ram_used, ram_total)
|
||||
else:
|
||||
_LOGGER.warning("Skipping RAM summary: no DRAM/DIRAM region in %s", size_json)
|
||||
|
||||
image_size = data.get("image_size")
|
||||
if image_size is None or partitions_csv is None:
|
||||
@@ -97,6 +100,6 @@ def print_summary(size_json: Path, partitions_csv: Path | None) -> None:
|
||||
try:
|
||||
app_size = _find_app_partition_size(partitions_csv)
|
||||
except ValueError as e:
|
||||
_LOGGER.debug("Skipping Flash summary: %s", e)
|
||||
_LOGGER.warning("Skipping Flash summary: %s", e)
|
||||
return
|
||||
print_size_line("Flash", image_size, app_size)
|
||||
|
||||
@@ -173,9 +173,9 @@ def run_extra_script(
|
||||
process CWD so relative-path lookups (``join``, ``realpath``,
|
||||
``open``) resolve against the library tree.
|
||||
|
||||
On any exception inside the script we log at debug level and return
|
||||
an empty result — extra-scripts are best-effort, and an unsupported
|
||||
script shouldn't block the build.
|
||||
On any exception inside the script we warn and return whatever the
|
||||
script captured before failing — extra-scripts are best-effort, and an
|
||||
unsupported script shouldn't block the build.
|
||||
"""
|
||||
env = _FakeSConsEnv(
|
||||
board_mcu=board_mcu,
|
||||
@@ -196,8 +196,15 @@ def run_extra_script(
|
||||
},
|
||||
)
|
||||
except Exception as e: # noqa: BLE001 # pylint: disable=broad-exception-caught
|
||||
_LOGGER.warning("PIO extra-script %s raised %s; skipping", script_path, e)
|
||||
return ExtraScriptResult()
|
||||
# Keep what the script captured before failing: dropping flags it
|
||||
# already appended would fail later at link time, far from the cause
|
||||
_LOGGER.warning(
|
||||
"PIO extra-script %s (in %s) raised %s; keeping the partial capture",
|
||||
script_path,
|
||||
library_dir.name,
|
||||
e,
|
||||
)
|
||||
return env.result
|
||||
finally:
|
||||
os.chdir(old_cwd)
|
||||
return env.result
|
||||
|
||||
@@ -564,7 +564,9 @@ def split_flag_entry(entry: str, owner: str) -> list[str]:
|
||||
"""``shlex.split`` with a clean error naming the offending flags entry."""
|
||||
try:
|
||||
return shlex.split(entry)
|
||||
except ValueError as err:
|
||||
except (ValueError, AttributeError, TypeError) as err:
|
||||
# AttributeError/TypeError: a dict or number from a third-party
|
||||
# manifest; name the entry instead of an opaque shlex traceback
|
||||
raise EsphomeError(f"Malformed build flag {entry!r} in {owner}: {err}") from err
|
||||
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ def test_apply_extra_script_swallows_script_errors(tmp_path, caplog) -> None:
|
||||
c.data = {"build": {"extraScript": "extra.py"}}
|
||||
apply_extra_script(c, board_mcu=lambda: "esp8266", pio_platform="espressif8266")
|
||||
assert "flags" not in c.data["build"]
|
||||
assert "skipping" in caplog.text
|
||||
assert "keeping the partial capture" in caplog.text
|
||||
|
||||
|
||||
def test_apply_extra_script_pio_platform(tmp_path) -> None:
|
||||
@@ -250,3 +250,16 @@ def test_apply_extra_script_missing_script_logged(tmp_path, caplog) -> None:
|
||||
c.data = {"build": {"extraScript": "nope.py"}}
|
||||
apply_extra_script(c, board_mcu=lambda: "esp8266", pio_platform="espressif8266")
|
||||
assert "not found" in caplog.text
|
||||
|
||||
|
||||
def test_run_extra_script_keeps_partial_capture(tmp_path, caplog) -> None:
|
||||
"""Flags appended before a script fails are kept, not dropped."""
|
||||
from esphome.platformio.extra_script import run_extra_script
|
||||
|
||||
script = tmp_path / "extra.py"
|
||||
script.write_text("env.Append(LIBS=['algobsec'])\nraise RuntimeError('boom')\n")
|
||||
result = run_extra_script(
|
||||
script, library_dir=tmp_path, board_mcu="esp32", pio_platform="espressif32"
|
||||
)
|
||||
assert result.libs == ["algobsec"]
|
||||
assert "keeping the partial capture" in caplog.text
|
||||
|
||||
@@ -564,3 +564,16 @@ def test_lex_build_flags_dangling_flag_does_not_cross_entries(
|
||||
|
||||
assert lex_build_flags(["-Wall -I", "-DFOO=1"], "lib x") == ["-Wall", "-DFOO=1"]
|
||||
assert "Ignoring trailing '-I'" in caplog.text
|
||||
|
||||
|
||||
def test_split_flag_entry_non_string_is_clean( # type: ignore[no-untyped-def]
|
||||
) -> None:
|
||||
"""A dict or number from a third-party manifest fails naming the entry,
|
||||
not with an opaque shlex traceback."""
|
||||
from esphome.core import EsphomeError
|
||||
from esphome.platformio.library import split_flag_entry
|
||||
|
||||
with pytest.raises(EsphomeError, match="Malformed build flag"):
|
||||
split_flag_entry({"esp32": ["-DX"]}, "lib x")
|
||||
with pytest.raises(EsphomeError, match="Malformed build flag 5"):
|
||||
split_flag_entry(5, "lib x")
|
||||
|
||||
@@ -149,3 +149,32 @@ def test_print_summary_flash_line(
|
||||
out = capsys.readouterr().out
|
||||
assert "RAM: [===== ] 50.0% (used 100 bytes from 200 bytes)" in out
|
||||
assert "Flash: [ ] 0.0% (used 500 bytes from 1048576 bytes)" in out
|
||||
|
||||
|
||||
def test_print_summary_missing_ram_region_warns(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""A missing RAM line is diagnosable, not a silently absent CI metric."""
|
||||
size_json = _write_size_json(tmp_path, {"memory_types": {}, "image_size": 100})
|
||||
print_summary(size_json, partitions_csv=None)
|
||||
assert "Skipping RAM summary" in caplog.text
|
||||
|
||||
|
||||
def test_print_summary_bad_partitions_warns(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""An unparseable partition table skips the Flash line with a warning."""
|
||||
size_json = _write_size_json(tmp_path, _esp32_size_data())
|
||||
partitions = tmp_path / "partitions.csv"
|
||||
partitions.write_text("not,a,valid,partition,table\n")
|
||||
print_summary(size_json, partitions_csv=partitions)
|
||||
assert "Skipping Flash summary" in caplog.text
|
||||
|
||||
|
||||
def test_print_summary_corrupt_json_warns(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
size_json = tmp_path / "size.json"
|
||||
size_json.write_text("{not json")
|
||||
print_summary(size_json, partitions_csv=None)
|
||||
assert "Skipping size summary" in caplog.text
|
||||
|
||||
Reference in New Issue
Block a user