284 lines
9.0 KiB
Python
284 lines
9.0 KiB
Python
"""Update platform for Supervisor."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import Any
|
|
|
|
from aiohasupervisor import SupervisorError
|
|
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
|
|
|
|
from homeassistant.components.update import (
|
|
UpdateEntity,
|
|
UpdateEntityDescription,
|
|
UpdateEntityFeature,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import ATTR_ICON, ATTR_NAME
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from .const import (
|
|
ADDONS_COORDINATOR,
|
|
ATTR_AUTO_UPDATE,
|
|
ATTR_VERSION,
|
|
ATTR_VERSION_LATEST,
|
|
DATA_KEY_ADDONS,
|
|
DATA_KEY_CORE,
|
|
DATA_KEY_OS,
|
|
DATA_KEY_SUPERVISOR,
|
|
)
|
|
from .entity import (
|
|
HassioAddonEntity,
|
|
HassioCoreEntity,
|
|
HassioOSEntity,
|
|
HassioSupervisorEntity,
|
|
)
|
|
from .update_helper import update_addon, update_core, update_os
|
|
|
|
ENTITY_DESCRIPTION = UpdateEntityDescription(
|
|
translation_key="update",
|
|
key=ATTR_VERSION_LATEST,
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up Supervisor update based on a config entry."""
|
|
coordinator = hass.data[ADDONS_COORDINATOR]
|
|
|
|
entities = [
|
|
SupervisorSupervisorUpdateEntity(
|
|
coordinator=coordinator,
|
|
entity_description=ENTITY_DESCRIPTION,
|
|
),
|
|
SupervisorCoreUpdateEntity(
|
|
coordinator=coordinator,
|
|
entity_description=ENTITY_DESCRIPTION,
|
|
),
|
|
]
|
|
|
|
entities.extend(
|
|
SupervisorAddonUpdateEntity(
|
|
addon=addon,
|
|
coordinator=coordinator,
|
|
entity_description=ENTITY_DESCRIPTION,
|
|
)
|
|
for addon in coordinator.data[DATA_KEY_ADDONS].values()
|
|
)
|
|
|
|
if coordinator.is_hass_os:
|
|
entities.append(
|
|
SupervisorOSUpdateEntity(
|
|
coordinator=coordinator,
|
|
entity_description=ENTITY_DESCRIPTION,
|
|
)
|
|
)
|
|
|
|
async_add_entities(entities)
|
|
|
|
|
|
class SupervisorAddonUpdateEntity(HassioAddonEntity, UpdateEntity):
|
|
"""Update entity to handle updates for the Supervisor add-ons."""
|
|
|
|
_attr_supported_features = (
|
|
UpdateEntityFeature.INSTALL
|
|
| UpdateEntityFeature.BACKUP
|
|
| UpdateEntityFeature.RELEASE_NOTES
|
|
)
|
|
|
|
@property
|
|
def _addon_data(self) -> dict:
|
|
"""Return the add-on data."""
|
|
return self.coordinator.data[DATA_KEY_ADDONS][self._addon_slug]
|
|
|
|
@property
|
|
def auto_update(self) -> bool:
|
|
"""Return true if auto-update is enabled for the add-on."""
|
|
return self._addon_data[ATTR_AUTO_UPDATE]
|
|
|
|
@property
|
|
def title(self) -> str | None:
|
|
"""Return the title of the update."""
|
|
return self._addon_data[ATTR_NAME]
|
|
|
|
@property
|
|
def latest_version(self) -> str | None:
|
|
"""Latest version available for install."""
|
|
return self._addon_data[ATTR_VERSION_LATEST]
|
|
|
|
@property
|
|
def installed_version(self) -> str | None:
|
|
"""Version installed and in use."""
|
|
return self._addon_data[ATTR_VERSION]
|
|
|
|
@property
|
|
def entity_picture(self) -> str | None:
|
|
"""Return the icon of the add-on if any."""
|
|
if not self.available:
|
|
return None
|
|
if self._addon_data[ATTR_ICON]:
|
|
return f"/api/hassio/addons/{self._addon_slug}/icon"
|
|
return None
|
|
|
|
async def async_release_notes(self) -> str | None:
|
|
"""Return the release notes for the update."""
|
|
if (
|
|
changelog := await self.coordinator.get_changelog(self._addon_slug)
|
|
) is None:
|
|
return None
|
|
|
|
if self.latest_version is None or self.installed_version is None:
|
|
return changelog
|
|
|
|
regex_pattern = re.compile(
|
|
rf"^#* {re.escape(self.latest_version)}\n(?:^(?!#* {re.escape(self.installed_version)}).*\n)*",
|
|
re.MULTILINE,
|
|
)
|
|
match = regex_pattern.search(changelog)
|
|
return match.group(0) if match else changelog
|
|
|
|
async def async_install(
|
|
self,
|
|
version: str | None = None,
|
|
backup: bool = False,
|
|
**kwargs: Any,
|
|
) -> None:
|
|
"""Install an update."""
|
|
await update_addon(
|
|
self.hass, self._addon_slug, backup, self.title, self.installed_version
|
|
)
|
|
await self.coordinator.async_refresh()
|
|
|
|
|
|
class SupervisorOSUpdateEntity(HassioOSEntity, UpdateEntity):
|
|
"""Update entity to handle updates for the Home Assistant Operating System."""
|
|
|
|
_attr_supported_features = (
|
|
UpdateEntityFeature.INSTALL
|
|
| UpdateEntityFeature.SPECIFIC_VERSION
|
|
| UpdateEntityFeature.BACKUP
|
|
)
|
|
_attr_title = "Home Assistant Operating System"
|
|
|
|
@property
|
|
def latest_version(self) -> str:
|
|
"""Return the latest version."""
|
|
return self.coordinator.data[DATA_KEY_OS][ATTR_VERSION_LATEST]
|
|
|
|
@property
|
|
def installed_version(self) -> str:
|
|
"""Return the installed version."""
|
|
return self.coordinator.data[DATA_KEY_OS][ATTR_VERSION]
|
|
|
|
@property
|
|
def entity_picture(self) -> str | None:
|
|
"""Return the icon of the entity."""
|
|
return "https://brands.home-assistant.io/homeassistant/icon.png"
|
|
|
|
@property
|
|
def release_url(self) -> str | None:
|
|
"""URL to the full release notes of the latest version available."""
|
|
version = AwesomeVersion(self.latest_version)
|
|
if version.dev or version.strategy == AwesomeVersionStrategy.UNKNOWN:
|
|
return "https://github.com/home-assistant/operating-system/commits/dev"
|
|
return (
|
|
f"https://github.com/home-assistant/operating-system/releases/tag/{version}"
|
|
)
|
|
|
|
async def async_install(
|
|
self, version: str | None, backup: bool, **kwargs: Any
|
|
) -> None:
|
|
"""Install an update."""
|
|
await update_os(self.hass, version, backup)
|
|
|
|
|
|
class SupervisorSupervisorUpdateEntity(HassioSupervisorEntity, UpdateEntity):
|
|
"""Update entity to handle updates for the Home Assistant Supervisor."""
|
|
|
|
_attr_supported_features = UpdateEntityFeature.INSTALL
|
|
_attr_title = "Home Assistant Supervisor"
|
|
|
|
@property
|
|
def latest_version(self) -> str:
|
|
"""Return the latest version."""
|
|
return self.coordinator.data[DATA_KEY_SUPERVISOR][ATTR_VERSION_LATEST]
|
|
|
|
@property
|
|
def installed_version(self) -> str:
|
|
"""Return the installed version."""
|
|
return self.coordinator.data[DATA_KEY_SUPERVISOR][ATTR_VERSION]
|
|
|
|
@property
|
|
def auto_update(self) -> bool:
|
|
"""Return true if auto-update is enabled for supervisor."""
|
|
return self.coordinator.data[DATA_KEY_SUPERVISOR][ATTR_AUTO_UPDATE]
|
|
|
|
@property
|
|
def release_url(self) -> str | None:
|
|
"""URL to the full release notes of the latest version available."""
|
|
version = AwesomeVersion(self.latest_version)
|
|
if version.dev or version.strategy == AwesomeVersionStrategy.UNKNOWN:
|
|
return "https://github.com/home-assistant/supervisor/commits/main"
|
|
return f"https://github.com/home-assistant/supervisor/releases/tag/{version}"
|
|
|
|
@property
|
|
def entity_picture(self) -> str | None:
|
|
"""Return the icon of the entity."""
|
|
return "https://brands.home-assistant.io/hassio/icon.png"
|
|
|
|
async def async_install(
|
|
self, version: str | None, backup: bool, **kwargs: Any
|
|
) -> None:
|
|
"""Install an update."""
|
|
try:
|
|
await self.coordinator.supervisor_client.supervisor.update()
|
|
except SupervisorError as err:
|
|
raise HomeAssistantError(
|
|
f"Error updating Home Assistant Supervisor: {err}"
|
|
) from err
|
|
|
|
|
|
class SupervisorCoreUpdateEntity(HassioCoreEntity, UpdateEntity):
|
|
"""Update entity to handle updates for Home Assistant Core."""
|
|
|
|
_attr_supported_features = (
|
|
UpdateEntityFeature.INSTALL
|
|
| UpdateEntityFeature.SPECIFIC_VERSION
|
|
| UpdateEntityFeature.BACKUP
|
|
)
|
|
_attr_title = "Home Assistant Core"
|
|
|
|
@property
|
|
def latest_version(self) -> str:
|
|
"""Return the latest version."""
|
|
return self.coordinator.data[DATA_KEY_CORE][ATTR_VERSION_LATEST]
|
|
|
|
@property
|
|
def installed_version(self) -> str:
|
|
"""Return the installed version."""
|
|
return self.coordinator.data[DATA_KEY_CORE][ATTR_VERSION]
|
|
|
|
@property
|
|
def entity_picture(self) -> str | None:
|
|
"""Return the icon of the entity."""
|
|
return "https://brands.home-assistant.io/homeassistant/icon.png"
|
|
|
|
@property
|
|
def release_url(self) -> str | None:
|
|
"""URL to the full release notes of the latest version available."""
|
|
version = AwesomeVersion(self.latest_version)
|
|
if version.dev:
|
|
return "https://github.com/home-assistant/core/commits/dev"
|
|
return f"https://{'rc' if version.beta else 'www'}.home-assistant.io/latest-release-notes/"
|
|
|
|
async def async_install(
|
|
self, version: str | None, backup: bool, **kwargs: Any
|
|
) -> None:
|
|
"""Install an update."""
|
|
await update_core(self.hass, version, backup)
|