mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
Merge branch 'esp8266-native-library-backend' into esp8266-native-build-spec
This commit is contained in:
@@ -71,13 +71,22 @@ class ArduinoLibrary:
|
||||
link_flags: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
def _library_info(name: str, read_path: Path, data: dict) -> ArduinoLibrary:
|
||||
"""Resolve one library's sources, include dirs, and flags (PIO semantics)."""
|
||||
def _manifest_build(name: str, data: object) -> dict:
|
||||
"""The manifest's ``build`` section, validated by name.
|
||||
|
||||
A bare json.load imposes no shape; a malformed manifest must name the
|
||||
library instead of an AttributeError deep in a traceback (and must do so
|
||||
before apply_extra_script dereferences the same section).
|
||||
"""
|
||||
build = data.get("build", {}) if isinstance(data, dict) else None
|
||||
if not isinstance(build, dict):
|
||||
# A bare json.load imposes no shape; name the library instead of an
|
||||
# AttributeError deep in a traceback
|
||||
raise EsphomeError(f"Library {name} has a malformed manifest")
|
||||
return build
|
||||
|
||||
|
||||
def _library_info(name: str, read_path: Path, data: dict) -> ArduinoLibrary:
|
||||
"""Resolve one library's sources, include dirs, and flags (PIO semantics)."""
|
||||
build = _manifest_build(name, data)
|
||||
|
||||
# PIO's source-dir resolution: manifest srcDir, else src/Src, else the root
|
||||
if "srcDir" in build:
|
||||
@@ -326,6 +335,7 @@ def resolve_libraries(
|
||||
bundled.append(_bundled_library(framework_path, name))
|
||||
|
||||
def _emit(component: ConvertedLibrary) -> None:
|
||||
_manifest_build(component.get_require_name(), component.data)
|
||||
apply_extra_script(
|
||||
component, board_mcu=lambda: board_mcu, pio_platform=pio_platform
|
||||
)
|
||||
@@ -344,6 +354,10 @@ def resolve_libraries(
|
||||
framework="arduino",
|
||||
emit=_emit,
|
||||
cache_key=cache_key,
|
||||
# The graph walk must not resolve a bundled name from the
|
||||
# registry ({"Wire": "*"} in a manifest); the bundled copy
|
||||
# is added by _add_bundled_dependencies after emit
|
||||
provides=lambda name: (framework_path / "libraries" / name).is_dir(),
|
||||
),
|
||||
)
|
||||
if len(resolved) < len(external):
|
||||
|
||||
@@ -300,6 +300,11 @@ class LibraryBackend:
|
||||
framework: str
|
||||
emit: Callable[["ConvertedLibrary"], None]
|
||||
cache_key: str
|
||||
# When set, an owner-less manifest dependency this returns True for is
|
||||
# skipped by the graph walk: the backend provides it outside the
|
||||
# registry (e.g. a library bundled with the Arduino core), mirroring
|
||||
# PlatformIO's process_dependencies preference for bundled builders.
|
||||
provides: Callable[[str], bool] | None = None
|
||||
|
||||
|
||||
def ensure_list[T](obj: T | list[T]) -> list[T]:
|
||||
@@ -973,6 +978,15 @@ def convert_libraries(
|
||||
if is_lib_ignored(dep_name, lib_ignore):
|
||||
_LOGGER.debug("Skip ignored dependency %s", dep_name)
|
||||
continue
|
||||
if (
|
||||
backend.provides is not None
|
||||
and not dependency.get("owner")
|
||||
and backend.provides(dep_name)
|
||||
):
|
||||
# The backend adds it from its own tree; resolving it here
|
||||
# would fetch a same-named registry package instead
|
||||
_LOGGER.debug("Skip backend-provided dependency %s", dep_name)
|
||||
continue
|
||||
# The version field may actually be a URL (git/archive dependency).
|
||||
dep_version = dependency["version"]
|
||||
dep_url = _url_or_none(dep_version)
|
||||
|
||||
@@ -757,3 +757,59 @@ def test_bundled_library_non_dict_manifest_skips_probes_and_raises(
|
||||
(wire / "library.json").write_text('["not", "a", "manifest"]')
|
||||
with pytest.raises(EsphomeError, match="Library Wire has a malformed manifest"):
|
||||
component._bundled_library(framework, "Wire")
|
||||
|
||||
|
||||
def test_dict_shorthand_dependency_skips_registry_through_real_converter(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""{"Wire": "*"} in a real manifest must never reach the registry: the
|
||||
graph walk skips backend-provided names and the bundled copy is added
|
||||
after emit (no converter mock; a registry touch fails the test)."""
|
||||
import esphome.platformio.library as pio_library
|
||||
|
||||
framework = _make_framework(tmp_path)
|
||||
local_lib = tmp_path / "locallib"
|
||||
(local_lib / "src").mkdir(parents=True)
|
||||
(local_lib / "src" / "local.cpp").write_text("")
|
||||
(local_lib / "library.json").write_text(
|
||||
'{"name": "LocalLib", "version": "1.0.0", "dependencies": {"Wire": "*"}}'
|
||||
)
|
||||
_add_library(f"file://{local_lib}", None)
|
||||
# The real converter writes its component cache under the config dir
|
||||
CORE.config_path = tmp_path / "test.yaml"
|
||||
CORE.config_path.write_text("")
|
||||
with patch.object(
|
||||
pio_library,
|
||||
"_resolve_registry_version",
|
||||
side_effect=AssertionError("registry touched"),
|
||||
):
|
||||
libs = component.resolve_libraries(
|
||||
framework,
|
||||
pio_platform="espressif8266",
|
||||
board_mcu="esp8266",
|
||||
cache_key="arduino8266",
|
||||
)
|
||||
names = [lib.name for lib in libs]
|
||||
assert "Wire" in names
|
||||
assert any("locallib" in n.lower() for n in names)
|
||||
|
||||
|
||||
def test_emit_validates_manifest_before_extra_script(tmp_path: Path) -> None:
|
||||
"""A malformed build section fails by name before apply_extra_script
|
||||
dereferences it."""
|
||||
framework = _make_framework(tmp_path)
|
||||
_add_library("ESP32Async/ESPAsyncWebServer", "3.9.6")
|
||||
lib_dir = tmp_path / "converted" / "webserver"
|
||||
(lib_dir / "src").mkdir(parents=True)
|
||||
converted = _converted("esp32async__ESPAsyncWebServer", lib_dir, {"build": "src"})
|
||||
with (
|
||||
_emitting_converter(converted) as mock_extra,
|
||||
pytest.raises(EsphomeError, match="has a malformed manifest"),
|
||||
):
|
||||
component.resolve_libraries(
|
||||
framework,
|
||||
pio_platform="espressif8266",
|
||||
board_mcu="esp8266",
|
||||
cache_key="arduino8266",
|
||||
)
|
||||
mock_extra.assert_not_called()
|
||||
|
||||
Reference in New Issue
Block a user