From df90dcc6cb71a9a5c8c20fe587a2f096f38e5d3f Mon Sep 17 00:00:00 2001 From: root Date: Thu, 13 Apr 2023 05:55:06 -0700 Subject: [PATCH] Update HACS --- custom_components/hacs/base.py | 45 ++++++++++--------- custom_components/hacs/enums.py | 1 + custom_components/hacs/frontend.py | 29 +++--------- custom_components/hacs/manifest.json | 2 +- .../hacs/repositories/__init__.py | 2 + custom_components/hacs/repositories/base.py | 10 ++++- custom_components/hacs/translations/en.json | 4 +- custom_components/hacs/utils/data.py | 12 ++--- custom_components/hacs/utils/path.py | 1 + 9 files changed, 49 insertions(+), 57 deletions(-) diff --git a/custom_components/hacs/base.py b/custom_components/hacs/base.py index 5a97c55..f11bc03 100644 --- a/custom_components/hacs/base.py +++ b/custom_components/hacs/base.py @@ -160,9 +160,9 @@ class HacsCommon: categories: set[str] = field(default_factory=set) renamed_repositories: dict[str, str] = field(default_factory=dict) - archived_repositories: list[str] = field(default_factory=list) - ignored_repositories: list[str] = field(default_factory=list) - skip: list[str] = field(default_factory=list) + archived_repositories: set[str] = field(default_factory=set) + ignored_repositories: set[str] = field(default_factory=set) + skip: set[str] = field(default_factory=set) @dataclass @@ -197,20 +197,20 @@ class HacsRepositories: """HACS Repositories.""" _default_repositories: set[str] = field(default_factory=set) - _repositories: list[HacsRepository] = field(default_factory=list) + _repositories: set[HacsRepository] = field(default_factory=set) _repositories_by_full_name: dict[str, HacsRepository] = field(default_factory=dict) _repositories_by_id: dict[str, HacsRepository] = field(default_factory=dict) - _removed_repositories: list[RemovedRepository] = field(default_factory=list) + _removed_repositories_by_full_name: dict[str, RemovedRepository] = field(default_factory=dict) @property def list_all(self) -> list[HacsRepository]: """Return a list of repositories.""" - return self._repositories + return list(self._repositories) @property def list_removed(self) -> list[RemovedRepository]: """Return a list of removed repositories.""" - return self._removed_repositories + return list(self._removed_repositories_by_full_name.values()) @property def list_downloaded(self) -> list[HacsRepository]: @@ -235,7 +235,7 @@ class HacsRepositories: repository = registered_repo if repository not in self._repositories: - self._repositories.append(repository) + self._repositories.add(repository) self._repositories_by_id[repo_id] = repository self._repositories_by_full_name[repository.data.full_name_lower] = repository @@ -333,22 +333,15 @@ class HacsRepositories: def is_removed(self, repository_full_name: str) -> bool: """Check if a repository is removed.""" - return repository_full_name in ( - repository.repository for repository in self._removed_repositories - ) + return repository_full_name in self._removed_repositories_by_full_name def removed_repository(self, repository_full_name: str) -> RemovedRepository: """Get repository by full name.""" - if self.is_removed(repository_full_name): - if removed := [ - repository - for repository in self._removed_repositories - if repository.repository == repository_full_name - ]: - return removed[0] + if removed := self._removed_repositories_by_full_name.get(repository_full_name): + return removed removed = RemovedRepository(repository=repository_full_name) - self._removed_repositories.append(removed) + self._removed_repositories_by_full_name[repository_full_name] = removed return removed @@ -553,7 +546,12 @@ class HacsBase: raise AddonRepositoryException() if category not in RERPOSITORY_CLASSES: - raise HacsException(f"{category} is not a valid repository category.") + self.log.warning( + "%s is not a valid repository category, %s will not be registered.", + category, + repository_full_name, + ) + return if (renamed := self.common.renamed_repositories.get(repository_full_name)) is not None: repository_full_name = renamed @@ -563,7 +561,7 @@ class HacsBase: try: await repository.async_registration(ref) if repository.validate.errors: - self.common.skip.append(repository.data.full_name) + self.common.skip.add(repository.data.full_name) if not self.status.startup: self.log.error("Validation for %s failed.", repository_full_name) if self.system.action: @@ -582,7 +580,7 @@ class HacsBase: ) return except AIOGitHubAPIException as exception: - self.common.skip.append(repository.data.full_name) + self.common.skip.add(repository.data.full_name) raise HacsException( f"Validation for {repository_full_name} failed with {exception}." ) from exception @@ -765,6 +763,9 @@ class HacsBase: for category in (HacsCategory.INTEGRATION, HacsCategory.PLUGIN): self.enable_hacs_category(HacsCategory(category)) + if self.configuration.experimental and self.core.ha_version >= "2023.4.0b0": + self.enable_hacs_category(HacsCategory.TEMPLATE) + if HacsCategory.PYTHON_SCRIPT in self.hass.config.components: self.enable_hacs_category(HacsCategory.PYTHON_SCRIPT) diff --git a/custom_components/hacs/enums.py b/custom_components/hacs/enums.py index bbe2482..1454422 100644 --- a/custom_components/hacs/enums.py +++ b/custom_components/hacs/enums.py @@ -31,6 +31,7 @@ class HacsCategory(StrEnum): PLUGIN = "plugin" # Kept for legacy purposes NETDAEMON = "netdaemon" PYTHON_SCRIPT = "python_script" + TEMPLATE = "template" THEME = "theme" REMOVED = "removed" diff --git a/custom_components/hacs/frontend.py b/custom_components/hacs/frontend.py index 4adb32b..c49c35f 100644 --- a/custom_components/hacs/frontend.py +++ b/custom_components/hacs/frontend.py @@ -1,10 +1,9 @@ """"Starting setup task: Frontend".""" from __future__ import annotations +import os from typing import TYPE_CHECKING -from aiohttp import web -from homeassistant.components.http import HomeAssistantView from homeassistant.core import HomeAssistant, callback from .const import DOMAIN, URL_BASE @@ -26,11 +25,13 @@ def async_register_frontend(hass: HomeAssistant, hacs: HacsBase) -> None: hacs.async_setup_frontend_endpoint_themes() # Register frontend - if hacs.configuration.frontend_repo_url: + if hacs.configuration.dev and (frontend_path := os.getenv("HACS_FRONTEND_DIR")): hacs.log.warning( " Frontend development mode enabled. Do not run in production!" ) - hass.http.register_view(HacsFrontendDev()) + hass.http.register_static_path( + f"{URL_BASE}/frontend", f"{frontend_path}/hacs_frontend", cache_headers=False + ) elif hacs.configuration.experimental: hacs.log.info(" Using experimental frontend") hass.http.register_static_path( @@ -72,23 +73,3 @@ def async_register_frontend(hass: HomeAssistant, hacs: HacsBase) -> None: # Setup plugin endpoint if needed hacs.async_setup_frontend_endpoint_plugin() - - -class HacsFrontendDev(HomeAssistantView): - """Dev View Class for HACS.""" - - requires_auth = False - name = "hacs_files:frontend" - url = r"/hacsfiles/frontend/{requested_file:.+}" - - async def get(self, request, requested_file): # pylint: disable=unused-argument - """Handle HACS Web requests.""" - hacs: HacsBase = request.app["hass"].data.get(DOMAIN) - requested = requested_file.split("/")[-1] - request = await hacs.session.get(f"{hacs.configuration.frontend_repo_url}/{requested}") - if request.status == 200: - result = await request.read() - response = web.Response(body=result) - response.headers["Content-Type"] = "application/javascript" - - return response diff --git a/custom_components/hacs/manifest.json b/custom_components/hacs/manifest.json index fb8a0af..a1395f8 100644 --- a/custom_components/hacs/manifest.json +++ b/custom_components/hacs/manifest.json @@ -19,5 +19,5 @@ "requirements": [ "aiogithubapi>=22.10.1" ], - "version": "1.31.0" + "version": "1.32.1" } \ No newline at end of file diff --git a/custom_components/hacs/repositories/__init__.py b/custom_components/hacs/repositories/__init__.py index e5478ae..fcd8f1f 100644 --- a/custom_components/hacs/repositories/__init__.py +++ b/custom_components/hacs/repositories/__init__.py @@ -8,6 +8,7 @@ from .integration import HacsIntegrationRepository from .netdaemon import HacsNetdaemonRepository from .plugin import HacsPluginRepository from .python_script import HacsPythonScriptRepository +from .template import HacsTemplateRepository from .theme import HacsThemeRepository RERPOSITORY_CLASSES: dict[HacsCategory, HacsRepository] = { @@ -17,4 +18,5 @@ RERPOSITORY_CLASSES: dict[HacsCategory, HacsRepository] = { HacsCategory.APPDAEMON: HacsAppdaemonRepository, HacsCategory.NETDAEMON: HacsNetdaemonRepository, HacsCategory.PLUGIN: HacsPluginRepository, + HacsCategory.TEMPLATE: HacsTemplateRepository, } diff --git a/custom_components/hacs/repositories/base.py b/custom_components/hacs/repositories/base.py index c35ce69..320583a 100644 --- a/custom_components/hacs/repositories/base.py +++ b/custom_components/hacs/repositories/base.py @@ -91,6 +91,8 @@ TOPIC_FILTER = ( "sensor", "smart-home", "smarthome", + "template", + "templates", "theme", "themes", ) @@ -772,6 +774,8 @@ class HacsRepository: await self.hacs.hass.services.async_call("frontend", "reload_themes", {}) except BaseException: # lgtm [py/catch-base-exception] pylint: disable=broad-except pass + elif self.data.category == "template": + await self.hacs.hass.services.async_call("homeassistant", "reload_custom_templates", {}) await async_remove_store(self.hacs.hass, f"hacs/{self.data.id}.hacs") @@ -796,6 +800,8 @@ class HacsRepository: try: if self.data.category == "python_script": local_path = f"{self.content.path.local}/{self.data.name}.py" + elif self.data.category == "template": + local_path = f"{self.content.path.local}/{self.data.file_name}" elif self.data.category == "theme": path = ( f"{self.hacs.core.config_path}/" @@ -823,7 +829,7 @@ class HacsRepository: return False self.logger.debug("%s Removing %s", self.string, local_path) - if self.data.category in ["python_script"]: + if self.data.category in ["python_script", "template"]: os.remove(local_path) else: shutil.rmtree(local_path) @@ -1093,7 +1099,7 @@ class HacsRepository: if self.data.archived and not ignore_issues: self.validate.errors.append("Repository is archived.") if self.data.full_name not in self.hacs.common.archived_repositories: - self.hacs.common.archived_repositories.append(self.data.full_name) + self.hacs.common.archived_repositories.add(self.data.full_name) raise HacsRepositoryArchivedException(f"{self} Repository is archived.") # Make sure the repository is not in the blacklist. diff --git a/custom_components/hacs/translations/en.json b/custom_components/hacs/translations/en.json index e0451b2..8da487a 100644 --- a/custom_components/hacs/translations/en.json +++ b/custom_components/hacs/translations/en.json @@ -68,7 +68,7 @@ }, "removed": { "title": "Repository removed from HACS", - "description": "{name} has been removed from HACS for {reason} visit the [HACS Panel](/hacs/repository/{repositry_id}) to remove it." + "description": "Because {reason}, '{name}' has been removed from HACS. Please visit the [HACS Panel](/hacs/repository/{repositry_id}) to remove it." } } -} \ No newline at end of file +} diff --git a/custom_components/hacs/utils/data.py b/custom_components/hacs/utils/data.py index 76616dc..b128a3f 100644 --- a/custom_components/hacs/utils/data.py +++ b/custom_components/hacs/utils/data.py @@ -207,8 +207,8 @@ class HacsData: self.logger.info(" Restore started") # Hacs - self.hacs.common.archived_repositories = [] - self.hacs.common.ignored_repositories = [] + self.hacs.common.archived_repositories = set() + self.hacs.common.ignored_repositories = set() self.hacs.common.renamed_repositories = {} # Clear out doubble renamed values @@ -219,14 +219,14 @@ class HacsData: self.hacs.common.renamed_repositories[entry] = value # Clear out doubble archived values - for entry in hacs.get("archived_repositories", []): + for entry in hacs.get("archived_repositories", set()): if entry not in self.hacs.common.archived_repositories: - self.hacs.common.archived_repositories.append(entry) + self.hacs.common.archived_repositories.add(entry) # Clear out doubble ignored values - for entry in hacs.get("ignored_repositories", []): + for entry in hacs.get("ignored_repositories", set()): if entry not in self.hacs.common.ignored_repositories: - self.hacs.common.ignored_repositories.append(entry) + self.hacs.common.ignored_repositories.add(entry) try: await self.register_unknown_repositories(repositories) diff --git a/custom_components/hacs/utils/path.py b/custom_components/hacs/utils/path.py index e7e878a..493b9e6 100644 --- a/custom_components/hacs/utils/path.py +++ b/custom_components/hacs/utils/path.py @@ -17,4 +17,5 @@ def is_safe(hacs: HacsBase, path: str | Path) -> bool: Path(f"{hacs.core.config_path}/{hacs.configuration.python_script_path}").as_posix(), Path(f"{hacs.core.config_path}/{hacs.configuration.theme_path}").as_posix(), Path(f"{hacs.core.config_path}/custom_components/").as_posix(), + Path(f"{hacs.core.config_path}/custom_templates/").as_posix(), )