diff --git a/HISTORY.rst b/HISTORY.rst index 4f1cc2d3..9b6c8e0b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -21,8 +21,9 @@ test-driven methodologies, and modern toolchains for unrivaled success. ~~~~~~~~~~~~~~~~~~~ * Broadened version support for the ``pyelftools`` dependency, enabling compatibility with lower versions and facilitating integration with a wider range of third-party tools (`issue #4834 `_) -* Resolved an issue related to the relative package path in the `pio pkg publish `__ command * Addressed an issue where passing a relative path (``--project-dir``) to the `pio project init `__ command resulted in an error (`issue #4847 `_) +* Resolved an issue related to the relative package path in the `pio pkg publish `__ command +* Resolved an issue where the |LDF| selected an incorrect library version (`issue #4860 `_) 6.1.13 (2024-01-12) ~~~~~~~~~~~~~~~~~~~ diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index aa18cd1a..b6ba8d84 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -309,10 +309,10 @@ class LibBuilderBase: if not self.dependencies or self._deps_are_processed: return self._deps_are_processed = True - for item in self.dependencies: + for dependency in self.dependencies: found = False for lb in self.env.GetLibBuilders(): - if item["name"] != lb.name: + if not lb.is_dependency_compatible(dependency): continue found = True if lb not in self.depbuilders: @@ -322,9 +322,20 @@ class LibBuilderBase: if not found and self.verbose: sys.stderr.write( "Warning: Ignored `%s` dependency for `%s` " - "library\n" % (item["name"], self.name) + "library\n" % (dependency["name"], self.name) ) + def is_dependency_compatible(self, dependency): + pkg = PackageItem(self.path) + qualifiers = {"name": self.name, "version": self.version} + if pkg.metadata: + qualifiers = {"name": pkg.metadata.name, "version": pkg.metadata.version} + if pkg.metadata.spec and pkg.metadata.spec.owner: + qualifiers["owner"] = pkg.metadata.spec.owner + return PackageCompatibility.from_dependency(dependency).is_compatible( + PackageCompatibility(**qualifiers) + ) + def get_search_files(self): return [ os.path.join(self.src_dir, item) diff --git a/platformio/package/manager/_install.py b/platformio/package/manager/_install.py index 125766d3..12c116d1 100644 --- a/platformio/package/manager/_install.py +++ b/platformio/package/manager/_install.py @@ -99,7 +99,11 @@ class PackageManagerInstallMixin: pkg = self.install_from_registry( spec, search_qualifiers=( - compatibility.to_search_qualifiers() if compatibility else None + compatibility.to_search_qualifiers( + ["platforms", "frameworks", "authors"] + ) + if compatibility + else None ), ) diff --git a/platformio/package/meta.py b/platformio/package/meta.py index b9e3750d..7597148e 100644 --- a/platformio/package/meta.py +++ b/platformio/package/meta.py @@ -65,7 +65,14 @@ class PackageType: class PackageCompatibility: - KNOWN_QUALIFIERS = ("platforms", "frameworks", "authors") + KNOWN_QUALIFIERS = ( + "owner", + "name", + "version", + "platforms", + "frameworks", + "authors", + ) @classmethod def from_dependency(cls, dependency): @@ -89,19 +96,45 @@ class PackageCompatibility: def __repr__(self): return "PackageCompatibility <%s>" % self.qualifiers - def to_search_qualifiers(self): - return self.qualifiers + def to_search_qualifiers(self, fields=None): + result = {} + for name, value in self.qualifiers.items(): + if not fields or name in fields: + result[name] = value + return result def is_compatible(self, other): assert isinstance(other, PackageCompatibility) - for key, value in self.qualifiers.items(): + for key, current_value in self.qualifiers.items(): other_value = other.qualifiers.get(key) - if not value or not other_value: + if not current_value or not other_value: continue - if not items_in_list(value, other_value): + if any(isinstance(v, list) for v in (current_value, other_value)): + if not items_in_list(current_value, other_value): + return False + continue + if key == "version": + if not self._compare_versions(current_value, other_value): + return False + continue + if current_value != other_value: return False return True + def _compare_versions(self, current, other): + if current == other: + return True + try: + version = ( + other + if isinstance(other, semantic_version.Version) + else cast_version_to_semver(other) + ) + return version in semantic_version.SimpleSpec(current) + except ValueError: + pass + return False + class PackageOutdatedResult: UPDATE_INCREMENT_MAJOR = "major"