mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission
This commit is contained in:
@@ -300,7 +300,9 @@ def resolve_libraries(
|
||||
"with add_library() if needed",
|
||||
component.name,
|
||||
)
|
||||
for dep in normalize_dependencies(component.data.get("dependencies")):
|
||||
for dep in normalize_dependencies(
|
||||
component.data.get("dependencies"), component.name
|
||||
):
|
||||
name = dep.get("name")
|
||||
if (
|
||||
not name
|
||||
|
||||
@@ -628,13 +628,15 @@ def join_flag_args(tokens: Iterable[str], owner: str) -> list[str]:
|
||||
return out
|
||||
|
||||
|
||||
def normalize_dependencies(dependencies: Any, owner: str = "manifest") -> list[dict]:
|
||||
def normalize_dependencies(
|
||||
dependencies: Any, manifest_name: str = "manifest"
|
||||
) -> list[dict]:
|
||||
"""Normalize a library manifest's ``dependencies`` to a list of dicts.
|
||||
|
||||
PIO's library.json accepts the list-of-dicts form, the shorthand dict
|
||||
form (``{"owner/Name": "version_spec"}``), bare name strings inside the
|
||||
list, and a plain (possibly comma-separated) string; normalize them all
|
||||
so callers see a uniform list. ``owner`` names the manifest in the
|
||||
so callers see a uniform list. ``manifest_name`` names the manifest in the
|
||||
warning for entries that cannot be normalized.
|
||||
"""
|
||||
if not dependencies:
|
||||
@@ -668,7 +670,9 @@ def normalize_dependencies(dependencies: Any, owner: str = "manifest") -> list[d
|
||||
normalized.append({"name": entry})
|
||||
else:
|
||||
_LOGGER.warning(
|
||||
"Ignoring unrecognized dependency entry %r of %s", entry, owner
|
||||
"Ignoring unrecognized dependency entry %r of %s",
|
||||
entry,
|
||||
manifest_name,
|
||||
)
|
||||
return normalized
|
||||
|
||||
@@ -987,18 +991,41 @@ def convert_libraries(
|
||||
component.data.get("dependencies"), component.name
|
||||
):
|
||||
if "name" not in dependency or "version" not in dependency:
|
||||
# Version-less deps cannot resolve from the registry; the
|
||||
# arduino backend picks bundled ones up after emit
|
||||
_LOGGER.debug(
|
||||
"Skip version-less dependency %r of %s",
|
||||
dependency.get("name"),
|
||||
component.name,
|
||||
)
|
||||
if backend.provides is None:
|
||||
# No backend tree can supply it and the registry cannot
|
||||
# resolve it: a real drop, not a routine skip
|
||||
_LOGGER.warning(
|
||||
"Dependency %r of %s has no version to resolve; skipping",
|
||||
dependency.get("name"),
|
||||
component.name,
|
||||
)
|
||||
else:
|
||||
# The backend (e.g. the arduino bundled tree) picks
|
||||
# these up after emit
|
||||
_LOGGER.debug(
|
||||
"Skip version-less dependency %r of %s",
|
||||
dependency.get("name"),
|
||||
component.name,
|
||||
)
|
||||
continue
|
||||
try:
|
||||
check_library_data(dependency, backend.platform, backend.framework)
|
||||
except InvalidLibrary as e:
|
||||
_LOGGER.debug("Skip dependency %s: %s", dependency.get("name"), str(e))
|
||||
if isinstance(e, IncompatiblePlatform):
|
||||
# Routine cross-platform skip
|
||||
_LOGGER.debug(
|
||||
"Skip dependency %s: %s", dependency.get("name"), str(e)
|
||||
)
|
||||
else:
|
||||
# Any other cause is a dropped dependency and must be
|
||||
# visible (unreachable from check_library_data today,
|
||||
# which raises only for the platform filter)
|
||||
_LOGGER.warning(
|
||||
"Skipping dependency %s of %s: %s",
|
||||
dependency.get("name"),
|
||||
component.name,
|
||||
e,
|
||||
)
|
||||
continue
|
||||
dep_name = _owner_pkgname_to_name(
|
||||
dependency.get("owner"), dependency.get("name")
|
||||
|
||||
@@ -760,7 +760,7 @@ def test_bundled_library_non_dict_manifest_skips_probes_and_raises(
|
||||
|
||||
|
||||
def test_dict_shorthand_dependency_skips_registry_through_real_converter(
|
||||
tmp_path: Path,
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""{"Wire": "*"} in a real manifest must never reach the registry: the
|
||||
graph walk skips backend-provided names and the bundled copy is added
|
||||
@@ -777,9 +777,9 @@ def test_dict_shorthand_dependency_skips_registry_through_real_converter(
|
||||
# as_uri() forms a valid file:// URL on every platform (file:///C:/...
|
||||
# on Windows; a bare f-string would embed backslashes)
|
||||
_add_library(local_lib.as_uri(), None)
|
||||
# The real converter writes its component cache under the config dir
|
||||
CORE.config_path = tmp_path / "test.yaml"
|
||||
CORE.config_path.write_text("")
|
||||
# Pin the component cache to tmp_path (data_dir honors an ambient
|
||||
# ESPHOME_DATA_DIR otherwise)
|
||||
monkeypatch.setenv("ESPHOME_DATA_DIR", str(tmp_path / ".esphome"))
|
||||
with patch.object(
|
||||
pio_library,
|
||||
"_resolve_registry_version",
|
||||
@@ -891,7 +891,9 @@ def test_bundled_dependency_string_list_form(
|
||||
|
||||
|
||||
def test_pinned_bundled_dependency_substitution_warns(
|
||||
tmp_path: Path, caplog: pytest.LogCaptureFixture
|
||||
tmp_path: Path,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""A non-* version pin on a backend-provided dependency is discarded
|
||||
for the bundled copy; the substitution must be visible."""
|
||||
|
||||
@@ -607,3 +607,41 @@ def test_normalize_dependencies_forms(caplog) -> None:
|
||||
{"name": "SPI"},
|
||||
]
|
||||
assert normalize_dependencies("Wire") == [{"name": "Wire"}]
|
||||
|
||||
|
||||
def test_versionless_dependency_without_provider_warns(
|
||||
tmp_path, monkeypatch, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""When no backend tree can supply a version-less dependency, the drop
|
||||
is a warning, not a debug line."""
|
||||
_patch_download_with_manifests(
|
||||
monkeypatch,
|
||||
tmp_path,
|
||||
{"esphome/A": {"name": "A", "dependencies": [{"name": "Hash"}]}},
|
||||
)
|
||||
convert_libraries([Library("esphome/A", None, None)], _backend())
|
||||
assert "'Hash' of esphome/A has no version to resolve" in caplog.text
|
||||
|
||||
|
||||
def test_walk_warns_for_nonplatform_invalid_library(
|
||||
tmp_path, monkeypatch, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""A dependency dropped for any cause other than the routine platform
|
||||
filter is visible in every backend."""
|
||||
_patch_download_with_manifests(
|
||||
monkeypatch,
|
||||
tmp_path,
|
||||
{"esphome/A": {"name": "A", "dependencies": [{"name": "B", "version": "1.0"}]}},
|
||||
)
|
||||
calls = {"n": 0}
|
||||
real = lib.check_library_data
|
||||
|
||||
def flaky(data, platform, framework):
|
||||
calls["n"] += 1
|
||||
if calls["n"] > 1:
|
||||
raise InvalidLibrary("manifest is corrupt")
|
||||
return real(data, platform, framework)
|
||||
|
||||
monkeypatch.setattr(lib, "check_library_data", flaky)
|
||||
convert_libraries([Library("esphome/A", None, None)], _backend())
|
||||
assert "Skipping dependency B of esphome/A: manifest is corrupt" in caplog.text
|
||||
|
||||
Reference in New Issue
Block a user