Bump HACS to 1.30.1
This commit is contained in:
@@ -1,38 +1,45 @@
|
||||
"""Data handler for HACS."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.util import json as json_util
|
||||
|
||||
from ..base import HacsBase
|
||||
from ..enums import HacsDisabledReason, HacsDispatchEvent, HacsGitHubRepo
|
||||
from ..const import HACS_REPOSITORY_ID
|
||||
from ..enums import HacsDisabledReason, HacsDispatchEvent
|
||||
from ..repositories.base import TOPIC_FILTER, HacsManifest, HacsRepository
|
||||
from .logger import LOGGER
|
||||
from .path import is_safe
|
||||
from .store import async_load_from_store, async_save_to_store
|
||||
|
||||
DEFAULT_BASE_REPOSITORY_DATA = (
|
||||
EXPORTED_BASE_DATA = (
|
||||
("new", False),
|
||||
("full_name", ""),
|
||||
)
|
||||
|
||||
EXPORTED_REPOSITORY_DATA = EXPORTED_BASE_DATA + (
|
||||
("authors", []),
|
||||
("category", ""),
|
||||
("description", ""),
|
||||
("domain", None),
|
||||
("downloads", 0),
|
||||
("etag_repository", None),
|
||||
("full_name", ""),
|
||||
("last_updated", 0),
|
||||
("hide", False),
|
||||
("last_updated", 0),
|
||||
("new", False),
|
||||
("stargazers_count", 0),
|
||||
("topics", []),
|
||||
)
|
||||
|
||||
DEFAULT_EXTENDED_REPOSITORY_DATA = (
|
||||
EXPORTED_DOWNLOADED_REPOSITORY_DATA = EXPORTED_REPOSITORY_DATA + (
|
||||
("archived", False),
|
||||
("config_flow", False),
|
||||
("default_branch", None),
|
||||
("description", ""),
|
||||
("first_install", False),
|
||||
("installed_commit", None),
|
||||
("installed", False),
|
||||
@@ -41,12 +48,9 @@ DEFAULT_EXTENDED_REPOSITORY_DATA = (
|
||||
("manifest_name", None),
|
||||
("open_issues", 0),
|
||||
("published_tags", []),
|
||||
("pushed_at", ""),
|
||||
("releases", False),
|
||||
("selected_tag", None),
|
||||
("show_beta", False),
|
||||
("stargazers_count", 0),
|
||||
("topics", []),
|
||||
)
|
||||
|
||||
|
||||
@@ -80,6 +84,8 @@ class HacsData:
|
||||
"ignored_repositories": self.hacs.common.ignored_repositories,
|
||||
},
|
||||
)
|
||||
if self.hacs.configuration.experimental:
|
||||
await self._async_store_experimental_content_and_repos()
|
||||
await self._async_store_content_and_repos()
|
||||
|
||||
async def _async_store_content_and_repos(self, _=None): # bb: ignore
|
||||
@@ -94,40 +100,94 @@ class HacsData:
|
||||
for event in (HacsDispatchEvent.REPOSITORY, HacsDispatchEvent.CONFIG):
|
||||
self.hacs.async_dispatch(event, {})
|
||||
|
||||
async def _async_store_experimental_content_and_repos(self, _=None): # bb: ignore
|
||||
"""Store the main repos file and each repo that is out of date."""
|
||||
# Repositories
|
||||
self.content = {}
|
||||
for repository in self.hacs.repositories.list_all:
|
||||
if repository.data.category in self.hacs.common.categories:
|
||||
self.async_store_experimental_repository_data(repository)
|
||||
|
||||
await async_save_to_store(self.hacs.hass, "data", {"repositories": self.content})
|
||||
|
||||
@callback
|
||||
def async_store_repository_data(self, repository: HacsRepository) -> dict:
|
||||
"""Store the repository data."""
|
||||
data = {"repository_manifest": repository.repository_manifest.manifest}
|
||||
|
||||
for key, default_value in DEFAULT_BASE_REPOSITORY_DATA:
|
||||
if (value := repository.data.__getattribute__(key)) != default_value:
|
||||
for key, default in (
|
||||
EXPORTED_DOWNLOADED_REPOSITORY_DATA
|
||||
if repository.data.installed
|
||||
else EXPORTED_REPOSITORY_DATA
|
||||
):
|
||||
if (value := getattr(repository.data, key, default)) != default:
|
||||
data[key] = value
|
||||
|
||||
if repository.data.installed:
|
||||
for key, default_value in DEFAULT_EXTENDED_REPOSITORY_DATA:
|
||||
if (value := repository.data.__getattribute__(key)) != default_value:
|
||||
data[key] = value
|
||||
if repository.data.installed_version:
|
||||
data["version_installed"] = repository.data.installed_version
|
||||
|
||||
if repository.data.last_fetched:
|
||||
data["last_fetched"] = repository.data.last_fetched.timestamp()
|
||||
|
||||
self.content[str(repository.data.id)] = data
|
||||
|
||||
@callback
|
||||
def async_store_experimental_repository_data(self, repository: HacsRepository) -> None:
|
||||
"""Store the experimental repository data for non downloaded repositories."""
|
||||
data = {}
|
||||
self.content.setdefault(repository.data.category, [])
|
||||
|
||||
if repository.data.installed:
|
||||
data["repository_manifest"] = repository.repository_manifest.manifest
|
||||
for key, default in EXPORTED_DOWNLOADED_REPOSITORY_DATA:
|
||||
if (value := getattr(repository.data, key, default)) != default:
|
||||
data[key] = value
|
||||
|
||||
if repository.data.installed_version:
|
||||
data["version_installed"] = repository.data.installed_version
|
||||
if repository.data.last_fetched:
|
||||
data["last_fetched"] = repository.data.last_fetched.timestamp()
|
||||
else:
|
||||
for key, default in EXPORTED_BASE_DATA:
|
||||
if (value := getattr(repository.data, key, default)) != default:
|
||||
data[key] = value
|
||||
|
||||
self.content[repository.data.category].append({"id": str(repository.data.id), **data})
|
||||
|
||||
async def restore(self):
|
||||
"""Restore saved data."""
|
||||
self.hacs.status.new = False
|
||||
repositories = {}
|
||||
hacs = {}
|
||||
|
||||
try:
|
||||
hacs = await async_load_from_store(self.hacs.hass, "hacs") or {}
|
||||
except HomeAssistantError:
|
||||
hacs = {}
|
||||
pass
|
||||
|
||||
try:
|
||||
repositories = await async_load_from_store(self.hacs.hass, "repositories") or {}
|
||||
data = (
|
||||
await async_load_from_store(
|
||||
self.hacs.hass,
|
||||
"data" if self.hacs.configuration.experimental else "repositories",
|
||||
)
|
||||
or {}
|
||||
)
|
||||
if data and self.hacs.configuration.experimental:
|
||||
for category, entries in data.get("repositories", {}).items():
|
||||
for repository in entries:
|
||||
repositories[repository["id"]] = {"category": category, **repository}
|
||||
else:
|
||||
repositories = (
|
||||
data or await async_load_from_store(self.hacs.hass, "repositories") or {}
|
||||
)
|
||||
except HomeAssistantError as exception:
|
||||
self.hacs.log.error(
|
||||
"Could not read %s, restore the file from a backup - %s",
|
||||
self.hacs.hass.config.path(".storage/hacs.repositories"),
|
||||
self.hacs.hass.config.path(
|
||||
".storage/hacs.data"
|
||||
if self.hacs.configuration.experimental
|
||||
else ".storage/hacs.repositories"
|
||||
),
|
||||
exception,
|
||||
)
|
||||
self.hacs.disable_hacs(HacsDisabledReason.RESTORE)
|
||||
@@ -136,6 +196,8 @@ class HacsData:
|
||||
if not hacs and not repositories:
|
||||
# Assume new install
|
||||
self.hacs.status.new = True
|
||||
if self.hacs.configuration.experimental:
|
||||
return True
|
||||
self.logger.info("<HacsData restore> Loading base repository information")
|
||||
repositories = await self.hacs.hass.async_add_executor_job(
|
||||
json_util.load_json,
|
||||
@@ -186,28 +248,34 @@ class HacsData:
|
||||
return False
|
||||
return True
|
||||
|
||||
async def register_unknown_repositories(self, repositories):
|
||||
async def register_unknown_repositories(self, repositories, category: str | None = None):
|
||||
"""Registry any unknown repositories."""
|
||||
register_tasks = [
|
||||
self.hacs.async_register_repository(
|
||||
repository_full_name=repo_data["full_name"],
|
||||
category=repo_data["category"],
|
||||
category=repo_data.get("category", category),
|
||||
check=False,
|
||||
repository_id=entry,
|
||||
)
|
||||
for entry, repo_data in repositories.items()
|
||||
if entry != "0" and not self.hacs.repositories.is_registered(repository_id=entry)
|
||||
if entry != "0"
|
||||
and not self.hacs.repositories.is_registered(repository_id=entry)
|
||||
and repo_data.get("category", category) is not None
|
||||
]
|
||||
if register_tasks:
|
||||
await asyncio.gather(*register_tasks)
|
||||
|
||||
@callback
|
||||
def async_restore_repository(self, entry, repository_data):
|
||||
def async_restore_repository(self, entry: str, repository_data: dict[str, Any]):
|
||||
"""Restore repository."""
|
||||
full_name = repository_data["full_name"]
|
||||
if not (repository := self.hacs.repositories.get_by_full_name(full_name)):
|
||||
self.logger.error("<HacsData restore> Did not find %s (%s)", full_name, entry)
|
||||
repository: HacsRepository | None = None
|
||||
if full_name := repository_data.get("full_name"):
|
||||
repository = self.hacs.repositories.get_by_full_name(full_name)
|
||||
if not repository:
|
||||
repository = self.hacs.repositories.get_by_id(entry)
|
||||
if not repository:
|
||||
return
|
||||
|
||||
# Restore repository attributes
|
||||
self.hacs.repositories.set_repository_id(repository, entry)
|
||||
repository.data.authors = repository_data.get("authors", [])
|
||||
@@ -238,7 +306,7 @@ class HacsData:
|
||||
repository.data.last_fetched = datetime.fromtimestamp(last_fetched)
|
||||
|
||||
repository.repository_manifest = HacsManifest.from_dict(
|
||||
repository_data.get("repository_manifest", {})
|
||||
repository_data.get("manifest") or repository_data.get("repository_manifest") or {}
|
||||
)
|
||||
|
||||
if repository.localpath is not None and is_safe(self.hacs, repository.localpath):
|
||||
@@ -248,6 +316,6 @@ class HacsData:
|
||||
if repository.data.installed:
|
||||
repository.data.first_install = False
|
||||
|
||||
if full_name == HacsGitHubRepo.INTEGRATION:
|
||||
if entry == HACS_REPOSITORY_ID:
|
||||
repository.data.installed_version = self.hacs.version
|
||||
repository.data.installed = True
|
||||
|
||||
Reference in New Issue
Block a user