Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions custom_components/hacs/repositories/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ async def _async_post_install(self) -> None:
"repository_id": self.data.id,
},
)
self.hacs.data.async_schedule_write()
self.logger.info("%s Post installation steps completed", self.string)

async def async_install_repository(self, *, version: str | None = None, **_) -> None:
Expand Down
96 changes: 60 additions & 36 deletions custom_components/hacs/utils/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
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
from .store import async_delay_save_to_store, async_load_from_store, async_save_to_store

DELAYED_WRITE_DELAY = 30

EXPORTED_BASE_DATA = (
("new", False),
Expand Down Expand Up @@ -62,7 +64,7 @@ def __init__(self, hacs: HacsBase):
"""Initialize."""
self.logger = LOGGER
self.hacs = hacs
self.content = {}
self.content: dict = {}

async def async_force_write(self, _=None):
"""Force write."""
Expand All @@ -75,45 +77,69 @@ async def async_write(self, force: bool = False) -> None:

self.logger.debug("<HacsData async_write> Saving data")

# Hacs
await async_save_to_store(self.hacs.hass, "hacs", self._build_hacs_data())
await async_save_to_store(
self.hacs.hass, "data", self._build_experimental_data()
)
await async_save_to_store(
self.hacs.hass, "repositories", self._build_repositories_data()
)
for event in (HacsDispatchEvent.REPOSITORY, HacsDispatchEvent.CONFIG):
self.hacs.async_dispatch(event, {})

@callback
def async_schedule_write(self) -> None:
"""Schedule a debounced write of all HACS stores."""
if self.hacs.system.disabled:
return

self.logger.debug("<HacsData async_schedule_write> Scheduling delayed save")

async_delay_save_to_store(
self.hacs.hass, "hacs", self._build_hacs_data, DELAYED_WRITE_DELAY
)
async_delay_save_to_store(
self.hacs.hass, "data", self._build_experimental_data, DELAYED_WRITE_DELAY
)
async_delay_save_to_store(
self.hacs.hass,
"hacs",
{
"archived_repositories": self.hacs.common.archived_repositories,
"renamed_repositories": self.hacs.common.renamed_repositories,
"ignored_repositories": self.hacs.common.ignored_repositories,
},
"repositories",
self._build_repositories_data,
DELAYED_WRITE_DELAY,
)
Comment thread
ludeeus marked this conversation as resolved.
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
"""Store the main repos file and each repo that is out of date."""
# Repositories
self.content = {}
@callback
def _build_hacs_data(self) -> dict:
return {
"archived_repositories": self.hacs.common.archived_repositories,
"renamed_repositories": self.hacs.common.renamed_repositories,
"ignored_repositories": self.hacs.common.ignored_repositories,
}

@callback
def _build_repositories_data(self) -> dict:
content: dict[str, dict] = {}
for repository in self.hacs.repositories.list_all:
if repository.data.category in self.hacs.common.categories:
self.async_store_repository_data(repository)
content[str(repository.data.id)] = self._repository_export(repository)
return content

await async_save_to_store(self.hacs.hass, "repositories", self.content)
for event in (HacsDispatchEvent.REPOSITORY, HacsDispatchEvent.CONFIG):
self.hacs.async_dispatch(event, {})

async def _async_store_experimental_content_and_repos(self, _=None):
"""Store the main repos file and each repo that is out of date."""
# Repositories
self.content = {}
@callback
def _build_experimental_data(self) -> dict:
content: dict[str, list] = {}
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})
content.setdefault(repository.data.category, []).append(
{
"id": str(repository.data.id),
**self._experimental_repository_export(repository),
}
)
return {"repositories": content}

@callback
def async_store_repository_data(self, repository: HacsRepository) -> dict:
"""Store the repository data."""
data = {"repository_manifest": repository.repository_manifest.manifest}
def _repository_export(self, repository: HacsRepository) -> dict:
data: dict[str, Any] = {"repository_manifest": repository.repository_manifest.manifest}

for key, default in (
EXPORTED_DOWNLOADED_REPOSITORY_DATA
Expand All @@ -128,13 +154,11 @@ def async_store_repository_data(self, repository: HacsRepository) -> dict:
if repository.data.last_fetched:
data["last_fetched"] = repository.data.last_fetched.timestamp()

self.content[str(repository.data.id)] = data
return 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, [])
def _experimental_repository_export(self, repository: HacsRepository) -> dict:
data: dict[str, Any] = {}

if repository.data.installed:
data["repository_manifest"] = repository.repository_manifest.manifest
Expand All @@ -151,7 +175,7 @@ def async_store_experimental_repository_data(self, repository: HacsRepository) -
if (value := getattr(repository.data, key, default)) != default:
data[key] = value

self.content[repository.data.category].append({"id": str(repository.data.id), **data})
return data

async def restore(self):
"""Restore saved data."""
Expand Down
15 changes: 15 additions & 0 deletions custom_components/hacs/utils/store.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
"""Storage handers."""

from collections.abc import Callable
from typing import Any

from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.json import JSONEncoder
from homeassistant.helpers.storage import Store
from homeassistant.util import json as json_util
Expand Down Expand Up @@ -72,6 +76,17 @@ async def async_save_to_store(hass, key, data):
)


@callback
def async_delay_save_to_store(
hass: HomeAssistant,
key: str,
data_func: Callable[[], Any],
delay: float,
) -> None:
"""Schedule a debounced save to the store."""
get_store_for_key(hass, key).async_delay_save(data_func, delay)
Comment thread
ludeeus marked this conversation as resolved.


async def async_remove_store(hass, key):
"""Remove a store element that should no longer be used."""
if "/" not in key:
Expand Down
Loading