diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index df98e1b150..743e6938d7 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -408,19 +408,28 @@ class Define: class Library: - def __init__(self, name, version): + def __init__(self, name, version, repository=None): self.name = name self.version = version + self.repository = repository + + def __str__(self): + return self.as_lib_dep @property def as_lib_dep(self): + if self.repository is not None: + if self.name is not None: + return f"{self.name}={self.repository}" + return self.repository + if self.version is None: return self.name return f"{self.name}@{self.version}" @property def as_tuple(self): - return self.name, self.version + return self.name, self.version, self.repository def __hash__(self): return hash(self.as_tuple) @@ -632,10 +641,24 @@ class EsphomeCore: "Library {} must be instance of Library, not {}" "".format(library, type(library)) ) - _LOGGER.debug("Adding library: %s", library) for other in self.libraries[:]: if other.name != library.name: continue + if other.repository is not None: + if library.repository is None or other.repository == library.repository: + # Other is using a/the same repository, takes precendence + break + raise ValueError( + "Adding named Library with repository failed! Libraries {} and {} " + "requested with conflicting repositories!" + "".format(library, other) + ) + + if library.repository is not None: + # This is more specific since its using a repository + self.libraries.remove(other) + continue + if library.version is None: # Other requirement is more specific break @@ -652,6 +675,7 @@ class EsphomeCore: "".format(library, other) ) else: + _LOGGER.debug("Adding library: %s", library) self.libraries.append(library) return library diff --git a/esphome/core/config.py b/esphome/core/config.py index 9475225f4d..eb748d89ac 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -332,6 +332,14 @@ async def to_code(config): if "@" in lib: name, vers = lib.split("@", 1) cg.add_library(name, vers) + elif "://" in lib: + # Repository... + if "=" in lib: + name, repo = lib.split("=", 1) + cg.add_library(name, None, repo) + else: + cg.add_library(None, None, lib) + else: cg.add_library(lib, None) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 802e9a9d38..eda378e5eb 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -543,13 +543,13 @@ def add_global(expression: Union[SafeExpType, Statement]): CORE.add_global(expression) -def add_library(name: str, version: Optional[str]): +def add_library(name: str, version: Optional[str], repository: Optional[str] = None): """Add a library to the codegen library storage. :param name: The name of the library (for example 'AsyncTCP') :param version: The version of the library, may be None. """ - CORE.add_library(Library(name, version)) + CORE.add_library(Library(name, version, repository)) def add_build_flag(build_flag: str): diff --git a/tests/unit_tests/test_core.py b/tests/unit_tests/test_core.py index 4e60880033..9e4ad3d79d 100644 --- a/tests/unit_tests/test_core.py +++ b/tests/unit_tests/test_core.py @@ -444,16 +444,24 @@ class TestDefine: class TestLibrary: @pytest.mark.parametrize( - "name, value, prop, expected", + "name, version, repository, prop, expected", ( - ("mylib", None, "as_lib_dep", "mylib"), - ("mylib", None, "as_tuple", ("mylib", None)), - ("mylib", "1.2.3", "as_lib_dep", "mylib@1.2.3"), - ("mylib", "1.2.3", "as_tuple", ("mylib", "1.2.3")), + ("mylib", None, None, "as_lib_dep", "mylib"), + ("mylib", None, None, "as_tuple", ("mylib", None, None)), + ("mylib", "1.2.3", None, "as_lib_dep", "mylib@1.2.3"), + ("mylib", "1.2.3", None, "as_tuple", ("mylib", "1.2.3", None)), + ("mylib", None, "file:///test", "as_lib_dep", "mylib=file:///test"), + ( + "mylib", + None, + "file:///test", + "as_tuple", + ("mylib", None, "file:///test"), + ), ), ) - def test_properties(self, name, value, prop, expected): - target = core.Library(name, value) + def test_properties(self, name, version, repository, prop, expected): + target = core.Library(name, version, repository) actual = getattr(target, prop) @@ -465,6 +473,7 @@ class TestLibrary: ("__eq__", core.Library(name="libfoo", version="1.2.3"), True), ("__eq__", core.Library(name="libfoo", version="1.2.4"), False), ("__eq__", core.Library(name="libbar", version="1.2.3"), False), + ("__eq__", core.Library(name="libbar", version=None, repository="file:///test"), False), ("__eq__", 1000, NotImplemented), ("__eq__", "1000", NotImplemented), ("__eq__", True, NotImplemented),