diff --git a/custom_components/hacs/__init__.py b/custom_components/hacs/__init__.py index db07e044b95..33c40d3325a 100644 --- a/custom_components/hacs/__init__.py +++ b/custom_components/hacs/__init__.py @@ -8,17 +8,24 @@ from typing import TYPE_CHECKING, Any -from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from aiogithubapi import AIOGitHubAPIException, GitHub, GitHubAPI +from aiogithubapi.const import ACCEPT_HEADERS +from awesomeversion import AwesomeVersion +from homeassistant.components.lovelace.system_health import system_health_info +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, __version__ as HAVERSION +from homeassistant.core import CoreState, HomeAssistant +from homeassistant.helpers.aiohttp_client import async_create_clientsession +from homeassistant.helpers.event import async_call_later +from homeassistant.loader import async_get_integration import voluptuous as vol -from .const import DOMAIN, PLATFORMS -from .enums import HacsDisabledReason +from .const import DOMAIN, PLATFORMS, STARTUP +from .enums import ConfigurationType, HacsDisabledReason, HacsStage, LovelaceMode +from .hacsbase.data import HacsData from .helpers.functions.configuration_schema import hacs_config_combined -from .operational.setup import ( - async_setup as hacs_yaml_setup, - async_setup_entry as hacs_ui_setup, -) +from .share import get_hacs +from .tasks.manager import HacsTaskManager if TYPE_CHECKING: from .base import HacsBase @@ -26,17 +33,138 @@ CONFIG_SCHEMA = vol.Schema({DOMAIN: hacs_config_combined()}, extra=vol.ALLOW_EXTRA) +async def async_initialize_integration( + hass: HomeAssistant, + *, + config_entry: ConfigEntry | None = None, + config: dict[str, Any] | None = None, +) -> bool: + """Initialize the integration""" + hass.data[DOMAIN] = hacs = get_hacs() + hacs.enable_hacs() + + if config is not None: + if DOMAIN not in config: + return True + if hacs.configuration.config_type == ConfigurationType.CONFIG_ENTRY: + return True + hacs.configuration.update_from_dict( + { + "config_type": ConfigurationType.YAML, + **config[DOMAIN], + "config": config[DOMAIN], + } + ) + + if config_entry is not None: + if config_entry.source == SOURCE_IMPORT: + hass.async_create_task(hass.config_entries.async_remove(config_entry.entry_id)) + return False + + hacs.configuration.update_from_dict( + { + "config_entry": config_entry, + "config_type": ConfigurationType.CONFIG_ENTRY, + **config_entry.data, + **config_entry.options, + } + ) + + integration = await async_get_integration(hass, DOMAIN) + + await hacs.async_set_stage(None) + + hacs.log.info(STARTUP.format(version=integration.version)) + + hacs.integration = integration + hacs.version = integration.version + hacs.hass = hass + hacs.data = HacsData() + hacs.system.running = True + hacs.session = async_create_clientsession(hass) + hacs.tasks = HacsTaskManager(hacs=hacs, hass=hass) + + hacs.core.lovelace_mode = LovelaceMode.YAML + try: + lovelace_info = await system_health_info(hacs.hass) + hacs.core.lovelace_mode = LovelaceMode(lovelace_info.get("mode", "yaml")) + except Exception: # pylint: disable=broad-except + # If this happens, the users YAML is not valid, we assume YAML mode + pass + hacs.log.debug(f"Configuration type: {hacs.configuration.config_type}") + hacs.core.config_path = hacs.hass.config.path() + + if hacs.core.ha_version is None: + hacs.core.ha_version = AwesomeVersion(HAVERSION) + + await hacs.tasks.async_load() + + # Setup session for API clients + session = async_create_clientsession(hacs.hass) + + ## Legacy GitHub client + hacs.github = GitHub( + hacs.configuration.token, + session, + headers={ + "User-Agent": f"HACS/{hacs.version}", + "Accept": ACCEPT_HEADERS["preview"], + }, + ) + + ## New GitHub client + hacs.githubapi = GitHubAPI( + token=hacs.configuration.token, + session=session, + **{"client_name": f"HACS/{hacs.version}"}, + ) + + async def async_startup(): + """HACS startup tasks.""" + hacs.enable_hacs() + + await hacs.async_set_stage(HacsStage.SETUP) + if hacs.system.disabled: + return False + + # Setup startup tasks + if hacs.hass.state == CoreState.running: + async_call_later(hacs.hass, 5, hacs.startup_tasks) + else: + hacs.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, hacs.startup_tasks) + + await hacs.async_set_stage(HacsStage.WAITING) + hacs.log.info("Setup complete, waiting for Home Assistant before startup tasks starts") + + return not hacs.system.disabled + + async def async_try_startup(_=None): + """Startup wrapper for yaml config.""" + try: + startup_result = await async_startup() + except AIOGitHubAPIException: + startup_result = False + if not startup_result: + hacs.log.info("Could not setup HACS, trying again in 15 min") + async_call_later(hass, 900, async_try_startup) + return + hacs.enable_hacs() + + await async_try_startup() + + # Mischief managed! + return True + + async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool: """Set up this integration using yaml.""" - - return await hacs_yaml_setup(hass, config) + return await async_initialize_integration(hass=hass, config=config) async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: """Set up this integration using UI.""" config_entry.add_update_listener(async_reload_entry) - - return await hacs_ui_setup(hass, config_entry) + return await async_initialize_integration(hass=hass, config_entry=config_entry) async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: diff --git a/custom_components/hacs/operational/setup.py b/custom_components/hacs/operational/setup.py deleted file mode 100644 index 36055bfbb22..00000000000 --- a/custom_components/hacs/operational/setup.py +++ /dev/null @@ -1,169 +0,0 @@ -"""Setup HACS.""" -from aiogithubapi import AIOGitHubAPIException, GitHub, GitHubAPI -from aiogithubapi.const import ACCEPT_HEADERS -from awesomeversion import AwesomeVersion -from homeassistant.components.lovelace.system_health import system_health_info -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry -from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, __version__ as HAVERSION -from homeassistant.core import CoreState, HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.helpers.aiohttp_client import async_create_clientsession -from homeassistant.helpers.event import async_call_later -from homeassistant.loader import async_get_integration - -from custom_components.hacs.const import DOMAIN, STARTUP -from custom_components.hacs.enums import ConfigurationType, HacsStage, LovelaceMode -from custom_components.hacs.hacsbase.data import HacsData -from custom_components.hacs.share import get_hacs -from custom_components.hacs.tasks.manager import HacsTaskManager - - -async def _async_common_setup(hass: HomeAssistant): - """Common setup stages.""" - integration = await async_get_integration(hass, DOMAIN) - - hacs = get_hacs() - - hacs.enable_hacs() - await hacs.async_set_stage(None) - - hacs.log.info(STARTUP.format(version=integration.version)) - - hacs.integration = integration - hacs.version = integration.version - hacs.hass = hass - hacs.data = HacsData() - hacs.system.running = True - hacs.session = async_create_clientsession(hass) - hacs.tasks = HacsTaskManager(hacs=hacs, hass=hass) - - hacs.core.lovelace_mode = LovelaceMode.YAML - try: - lovelace_info = await system_health_info(hacs.hass) - hacs.core.lovelace_mode = LovelaceMode(lovelace_info.get("mode", "yaml")) - except Exception: # pylint: disable=broad-except - # If this happens, the users YAML is not valid, we assume YAML mode - pass - hacs.log.debug(f"Configuration type: {hacs.configuration.config_type}") - hacs.core.config_path = hacs.hass.config.path() - - if hacs.core.ha_version is None: - hacs.core.ha_version = AwesomeVersion(HAVERSION) - - await hacs.tasks.async_load() - - # Setup session for API clients - session = async_create_clientsession(hacs.hass) - - ## Legacy GitHub client - hacs.github = GitHub( - hacs.configuration.token, - session, - headers={ - "User-Agent": f"HACS/{hacs.version}", - "Accept": ACCEPT_HEADERS["preview"], - }, - ) - - ## New GitHub client - hacs.githubapi = GitHubAPI( - token=hacs.configuration.token, - session=session, - **{"client_name": f"HACS/{hacs.version}"}, - ) - - hass.data[DOMAIN] = hacs - - -async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: - """Set up this integration using UI.""" - hacs = get_hacs() - - if config_entry.source == SOURCE_IMPORT: - hass.async_create_task(hass.config_entries.async_remove(config_entry.entry_id)) - return False - if hass.data.get(DOMAIN) is not None: - return False - - hacs.configuration.update_from_dict( - { - "config_entry": config_entry, - "config_type": ConfigurationType.CONFIG_ENTRY, - **config_entry.data, - **config_entry.options, - } - ) - - await _async_common_setup(hass) - return await async_startup_wrapper_for_config_entry() - - -async def async_setup(hass, config): - """Set up this integration using yaml.""" - hacs = get_hacs() - if DOMAIN not in config: - return True - if hacs.configuration.config_type == ConfigurationType.CONFIG_ENTRY: - return True - - hacs.configuration.update_from_dict( - { - "config_type": ConfigurationType.YAML, - **config[DOMAIN], - "config": config[DOMAIN], - } - ) - - await _async_common_setup(hass) - await async_startup_wrapper_for_yaml() - return True - - -async def async_startup_wrapper_for_config_entry(): - """Startup wrapper for ui config.""" - hacs = get_hacs() - - try: - startup_result = await async_hacs_startup() - except AIOGitHubAPIException: - startup_result = False - if not startup_result: - raise ConfigEntryNotReady(hacs.system.disabled_reason) - hacs.enable_hacs() - return startup_result - - -async def async_startup_wrapper_for_yaml(_=None): - """Startup wrapper for yaml config.""" - hacs = get_hacs() - try: - startup_result = await async_hacs_startup() - except AIOGitHubAPIException: - startup_result = False - if not startup_result: - hacs.log.info("Could not setup HACS, trying again in 15 min") - async_call_later(hacs.hass, 900, async_startup_wrapper_for_yaml) - return - hacs.enable_hacs() - - -async def async_hacs_startup(): - """HACS startup tasks.""" - hacs = get_hacs() - hacs.enable_hacs() - - await hacs.async_set_stage(HacsStage.SETUP) - if hacs.system.disabled: - return False - - # Setup startup tasks - if hacs.hass.state == CoreState.running: - async_call_later(hacs.hass, 5, hacs.startup_tasks) - else: - hacs.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, hacs.startup_tasks) - - # Mischief managed! - await hacs.async_set_stage(HacsStage.WAITING) - hacs.log.info("Setup complete, waiting for Home Assistant before startup tasks starts") - - return not hacs.system.disabled diff --git a/tests/conftest.py b/tests/conftest.py index e8476eaecef..9b0b41a941f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,8 +4,8 @@ import logging from pathlib import Path from unittest.mock import AsyncMock -from awesomeversion import AwesomeVersion +from awesomeversion import AwesomeVersion from homeassistant.const import __version__ as HAVERSION from homeassistant.exceptions import ServiceNotFound from homeassistant.helpers.aiohttp_client import async_create_clientsession diff --git a/tests/repositories/helpers/test_properties.py b/tests/repositories/helpers/test_properties.py index 194942443c0..364592aa09d 100644 --- a/tests/repositories/helpers/test_properties.py +++ b/tests/repositories/helpers/test_properties.py @@ -1,6 +1,7 @@ """HACS Repository Helper properties.""" # pylint: disable=missing-docstring from awesomeversion import AwesomeVersion + from custom_components.hacs.helpers.classes.repository import HacsRepository diff --git a/tests/repositories/test_can_install.py b/tests/repositories/test_can_install.py index a7884f7e82d..4d64d598ec9 100644 --- a/tests/repositories/test_can_install.py +++ b/tests/repositories/test_can_install.py @@ -1,6 +1,7 @@ """Configuration Test Suite: can install.""" # pylint: disable=missing-docstring from awesomeversion import AwesomeVersion + from custom_components.hacs.helpers.classes.repository import HacsRepository diff --git a/tests/repositories/test_core.py b/tests/repositories/test_core.py index 531f709358e..8bf77531acd 100644 --- a/tests/repositories/test_core.py +++ b/tests/repositories/test_core.py @@ -1,6 +1,7 @@ """Configuration Test Suite: Core repository.""" # pylint: disable=missing-docstring from awesomeversion import AwesomeVersion + from custom_components.hacs.helpers.classes.repository import HacsRepository diff --git a/tests/tasks/test_check_constrains.py b/tests/tasks/test_check_constrains.py index 834f9b4de89..876bc06f0af 100644 --- a/tests/tasks/test_check_constrains.py +++ b/tests/tasks/test_check_constrains.py @@ -1,7 +1,7 @@ # pylint: disable=missing-function-docstring,missing-module-docstring, protected-access from unittest.mock import patch -from awesomeversion.awesomeversion import AwesomeVersion +from awesomeversion.awesomeversion import AwesomeVersion import pytest from custom_components.hacs.base import HacsBase