mirror of
https://github.com/esphome/esphome.git
synced 2026-08-24 07:06:20 +00:00
Merge branch 'esp8266-native-build-infra' into esp8266-native-framework-installer
This commit is contained in:
@@ -777,6 +777,7 @@ def _prefetch_idf_tool_archives(
|
||||
# The installer downloads anything missing itself; never let the
|
||||
# prefetch become a new way for the install to fail.
|
||||
_LOGGER.warning("ESP-IDF tool prefetch failed: %s", e)
|
||||
_LOGGER.debug("Prefetch failure detail", exc_info=True)
|
||||
|
||||
|
||||
def _check_esphome_idf_framework_install(
|
||||
|
||||
@@ -114,10 +114,19 @@ class _FakeSConsEnv:
|
||||
self.result = ExtraScriptResult()
|
||||
self._warned_methods: set[str] = set()
|
||||
self._warned_keys: set[str] = set()
|
||||
self._warned_gets: set[str] = set()
|
||||
|
||||
# ----- SCons env API the common scripts use -----
|
||||
|
||||
def get(self, key: str, default: str | None = None) -> str | None:
|
||||
if key not in self._vars and key not in self._warned_gets:
|
||||
# A script branching on an unmodelled var silently takes the
|
||||
# default branch; make that diagnosable from a normal build log
|
||||
self._warned_gets.add(key)
|
||||
_LOGGER.warning(
|
||||
"PIO extra-script env.get(%r) is not modelled; returning the default",
|
||||
key,
|
||||
)
|
||||
return self._vars.get(key, default)
|
||||
|
||||
def __getitem__(self, key: str) -> str:
|
||||
@@ -140,6 +149,12 @@ class _FakeSConsEnv:
|
||||
bucket = getattr(self.result, key.lower())
|
||||
bucket.extend(items)
|
||||
|
||||
# Same keys, same flattened capture; ordering/dedup don't matter since
|
||||
# the consumer re-orders anyway
|
||||
Prepend = Append
|
||||
AppendUnique = Append
|
||||
PrependUnique = Append
|
||||
|
||||
# ----- Everything else is a no-op so unsupported scripts don't crash -----
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
@@ -267,7 +282,7 @@ def captured_as_build_flags(
|
||||
flags.extend(
|
||||
f"-L{shlex.quote(_anchored(path))}" for path in _strs(result.libpath, "LIBPATH")
|
||||
)
|
||||
flags.extend(f"-l{lib}" for lib in _strs(result.libs, "LIBS"))
|
||||
flags.extend(f"-l{shlex.quote(lib)}" for lib in _strs(result.libs, "LIBS"))
|
||||
for define in result.cppdefines:
|
||||
# SCons also accepts dict/list CPPDEFINES; formatting those blind
|
||||
# would hand the compiler garbage like -D{'FOO': '1'}
|
||||
@@ -277,6 +292,8 @@ def captured_as_build_flags(
|
||||
flags.append(f"-D{define}")
|
||||
else:
|
||||
_LOGGER.warning("Ignoring unsupported CPPDEFINES entry %r", define)
|
||||
flags.extend(_strs(result.linkflags, "LINKFLAGS"))
|
||||
flags.extend(_strs(result.cppflags, "CPPFLAGS"))
|
||||
# Each captured entry is one argv token in SCons; quote so the
|
||||
# lex_build_flags round-trip cannot split a spaced value into two
|
||||
flags.extend(shlex.quote(f) for f in _strs(result.linkflags, "LINKFLAGS"))
|
||||
flags.extend(shlex.quote(f) for f in _strs(result.cppflags, "CPPFLAGS"))
|
||||
return flags
|
||||
|
||||
@@ -925,6 +925,12 @@ def _content_lengths(urls: list[str]) -> list[int | None]:
|
||||
"""Content-Length per URL via HEAD requests; None when unknown."""
|
||||
import requests
|
||||
|
||||
from esphome.happy_eyeballs import ensure_happy_eyeballs
|
||||
|
||||
# Same convention as every other network call: without it a broken-IPv6
|
||||
# network burns the full timeout per HEAD before falling back
|
||||
ensure_happy_eyeballs()
|
||||
|
||||
def head(url: str) -> int | None:
|
||||
try:
|
||||
resp = requests.head(url, timeout=10, allow_redirects=True)
|
||||
|
||||
@@ -432,6 +432,41 @@ def test_run_extra_script_bad_encoding_is_best_effort(tmp_path, caplog) -> None:
|
||||
assert "is not UTF-8" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method", ("Prepend", "AppendUnique", "PrependUnique"))
|
||||
def test_append_variants_capture_like_append(method: str) -> None:
|
||||
"""Prepend/AppendUnique/PrependUnique write the captured keys too."""
|
||||
env = _FakeSConsEnv(
|
||||
board_mcu="esp8266", pio_env="esphome_esp8266", pio_platform="espressif8266"
|
||||
)
|
||||
getattr(env, method)(LIBS=["algobsec"], LIBPATH=["lib"])
|
||||
assert env.result.libs == ["algobsec"]
|
||||
assert env.result.libpath == ["lib"]
|
||||
|
||||
|
||||
def test_env_get_unknown_key_warns_once(caplog) -> None:
|
||||
"""A script branching on an unmodelled env var is diagnosable."""
|
||||
env = _FakeSConsEnv(
|
||||
board_mcu="esp8266", pio_env="esphome_esp8266", pio_platform="espressif8266"
|
||||
)
|
||||
assert env.get("BOARD") is None
|
||||
assert env.get("BOARD", "d1") == "d1"
|
||||
assert env.get("BOARD_MCU") == "esp8266"
|
||||
assert caplog.text.count("env.get('BOARD') is not modelled") == 1
|
||||
assert "BOARD_MCU" not in caplog.text
|
||||
|
||||
|
||||
def test_spaced_linkflag_survives_relexing(tmp_path) -> None:
|
||||
"""A captured argv token with a space stays one token after lexing."""
|
||||
result = ExtraScriptResult(
|
||||
linkflags=["-Wl,-T my linker.ld"], cppflags=["-include my hdr.h"]
|
||||
)
|
||||
flags = captured_as_build_flags(result, library_dir=tmp_path)
|
||||
assert lex_build_flags(flags, "test") == [
|
||||
"-Wl,-T my linker.ld",
|
||||
"-include my hdr.h",
|
||||
]
|
||||
|
||||
|
||||
def test_uncaptured_append_key_warns_once(caplog) -> None:
|
||||
"""A loop of Appends to the same uncaptured key warns once."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user