Skip to content

Commit

Permalink
Remove share (#2382)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludeeus authored Dec 26, 2021
1 parent 1e36ca1 commit 74e3de9
Show file tree
Hide file tree
Showing 26 changed files with 234 additions and 184 deletions.
3 changes: 3 additions & 0 deletions custom_components/hacs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from homeassistant.loader import async_get_integration
import voluptuous as vol

from custom_components.hacs.validate.manager import ValidationManager

from .base import HacsBase
from .const import DOMAIN, PLATFORMS, STARTUP
from .enums import ConfigurationType, HacsDisabledReason, HacsStage, LovelaceMode
Expand Down Expand Up @@ -82,6 +84,7 @@ async def async_initialize_integration(
hacs.system.running = True
hacs.session = async_create_clientsession(hass)
hacs.tasks = HacsTaskManager(hacs=hacs, hass=hass)
hacs.validation = ValidationManager(hacs=hacs, hass=hass)

hacs.core.lovelace_mode = LovelaceMode.YAML
try:
Expand Down
2 changes: 2 additions & 0 deletions custom_components/hacs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from .repositories.base import HacsRepository
from .tasks.manager import HacsTaskManager
from .utils.data import HacsData
from .validate.manager import ValidationManager


@dataclass
Expand Down Expand Up @@ -332,6 +333,7 @@ class HacsBase:
status = HacsStatus()
system = HacsSystem()
tasks: HacsTaskManager | None = None
validation: ValidationManager | None = None
version: str | None = None

@property
Expand Down
3 changes: 1 addition & 2 deletions custom_components/hacs/repositories/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
version_left_higher_then_right,
version_to_download,
)
from ..validate import async_run_repository_checks

if TYPE_CHECKING:
from ..base import HacsBase
Expand Down Expand Up @@ -706,7 +705,7 @@ async def async_registration(self, ref=None) -> None:

async def async_post_registration(self):
"""Run post registration steps."""
await async_run_repository_checks(self.hacs, self)
await self.hacs.validation.async_run_repository_checks(self)

async def async_pre_install(self) -> None:
"""Run pre install steps."""
Expand Down
6 changes: 0 additions & 6 deletions custom_components/hacs/share.py

This file was deleted.

2 changes: 0 additions & 2 deletions custom_components/hacs/tasks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
class HacsTask(LogMixin):
"""Hacs task base."""

hass: HomeAssistant

events: list[str] | None = None
schedule: timedelta | None = None
stages: list[HacsStage] | None = None
Expand Down
59 changes: 1 addition & 58 deletions custom_components/hacs/validate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,58 +1 @@
from __future__ import annotations

import asyncio
import glob
import importlib
from os.path import dirname, join, sep
from typing import TYPE_CHECKING

from homeassistant.core import HomeAssistant

from ..share import SHARE

if TYPE_CHECKING:
from ..base import HacsBase
from ..repositories.base import HacsRepository


def _initialize_rules():
rules = glob.glob(join(dirname(__file__), "**/*.py"))
for rule in rules:
rule = rule.replace(sep, "/")
rule = rule.split("custom_components/hacs")[-1]
rule = f"custom_components/hacs{rule}".replace("/", ".")[:-3]
importlib.import_module(rule)


async def async_initialize_rules(hass: HomeAssistant) -> None:
await hass.async_add_executor_job(_initialize_rules)


async def async_run_repository_checks(hacs: HacsBase, repository: HacsRepository):
if not SHARE["rules"]:
await async_initialize_rules(hacs.hass)
if not hacs.system.running:
return
checks = []
for check in SHARE["rules"].get("common", []):
checks.append(check(repository))
for check in SHARE["rules"].get(repository.data.category, []):
checks.append(check(repository))

await asyncio.gather(
*[
check._async_run_check()
for check in checks or []
if hacs.system.action or not check.action_only
]
)

total = len([x for x in checks if hacs.system.action or not x.action_only])
failed = len([x for x in checks if x.failed])

if failed != 0:
repository.logger.error("%s %s/%s checks failed", repository, failed, total)
if hacs.system.action:
exit(1)
else:
repository.logger.debug("%s All (%s) checks passed", repository, total)
"""Initialize validation."""
59 changes: 33 additions & 26 deletions custom_components/hacs/validate/base.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,58 @@
"""Base class for validation."""
from __future__ import annotations

from time import monotonic
from typing import TYPE_CHECKING

from ..share import SHARE
from ..exceptions import HacsException

if TYPE_CHECKING:
from ..repositories.base import HacsRepository


class ValidationException(Exception):
pass
class ValidationException(HacsException):
"""Raise when there is a validation issue."""


class ValidationBase:
action_only = False
"""Base class for validation."""

action_only: bool = False
category: str = "common"

def __init__(self, repository: HacsRepository) -> None:
self.hacs = repository.hacs
self.repository = repository
self.failed = False
self.logger = repository.logger

def __init_subclass__(cls, category="common", **kwargs) -> None:
"""Initialize a subclass, register if possible."""
super().__init_subclass__(**kwargs)
if SHARE["rules"].get(category) is None:
SHARE["rules"][category] = []
if cls not in SHARE["rules"][category]:
SHARE["rules"][category].append(cls)

async def _async_run_check(self):
"""DO NOT OVERRIDE THIS IN SUBCLASSES!"""
if self.hacs.system.action:
self.logger.info(f"Running check '{self.__class__.__name__}'")

@property
def slug(self) -> str:
"""Return the check slug."""
return self.__class__.__module__.rsplit(".", maxsplit=1)[-1]

async def execute_validation(self, *_, **__) -> None:
"""Execute the task defined in subclass."""
self.hacs.log.debug("Validation<%s> Starting validation", self.slug)

start_time = monotonic()
self.failed = False

try:
await self.hacs.hass.async_add_executor_job(self.check)
await self.async_check()
if task := getattr(self, "validate", None):
await self.hacs.hass.async_add_executor_job(task)
elif task := getattr(self, "async_validate", None):
await task() # pylint: disable=not-callable
except ValidationException as exception:
self.failed = True
self.logger.error(exception)
self.hacs.log.error("Validation<%s> failed: %s", self.slug, exception)

def check(self):
pass

async def async_check(self):
pass
else:
self.hacs.log.debug(
"Validation<%s> took %.3f seconds to complete", self.slug, monotonic() - start_time
)


class ActionValidationBase(ValidationBase):
"""Base class for action validation."""

action_only = True
Empty file.
8 changes: 0 additions & 8 deletions custom_components/hacs/validate/common/hacs_manifest.py

This file was deleted.

This file was deleted.

7 changes: 0 additions & 7 deletions custom_components/hacs/validate/common/repository_topics.py

This file was deleted.

16 changes: 16 additions & 0 deletions custom_components/hacs/validate/hacs_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations

from ..enums import RepositoryFile
from ..repositories.base import HacsRepository
from .base import ActionValidationBase, ValidationException


async def async_setup_validator(repository: HacsRepository) -> Validator:
"""Set up this validator."""
return Validator(repository=repository)


class Validator(ActionValidationBase):
def validate(self):
if RepositoryFile.HACS_JSON not in [x.filename for x in self.repository.tree]:
raise ValidationException(f"The repository has no '{RepositoryFile.HACS_JSON}' file")
Empty file.

This file was deleted.

20 changes: 20 additions & 0 deletions custom_components/hacs/validate/integration_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from __future__ import annotations

from ..enums import RepositoryFile
from ..repositories.base import HacsRepository
from .base import ActionValidationBase, ValidationException


async def async_setup_validator(repository: HacsRepository) -> Validator:
"""Set up this validator."""
return Validator(repository=repository)


class Validator(ActionValidationBase):
category = "integration"

def validate(self):
if RepositoryFile.MAINIFEST_JSON not in [x.filename for x in self.repository.tree]:
raise ValidationException(
f"The repository has no '{RepositoryFile.MAINIFEST_JSON}' file"
)
77 changes: 77 additions & 0 deletions custom_components/hacs/validate/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Hacs validation manager."""
from __future__ import annotations

import asyncio
from importlib import import_module
from pathlib import Path
from typing import TYPE_CHECKING

from homeassistant.core import HomeAssistant

from custom_components.hacs.repositories.base import HacsRepository

from .base import ValidationBase

if TYPE_CHECKING:
from ..base import HacsBase


class ValidationManager:
"""Hacs validation manager."""

def __init__(self, hacs: HacsBase, hass: HomeAssistant) -> None:
"""Initialize the setup manager class."""
self.hacs = hacs
self.hass = hass
self._validatiors: dict[str, ValidationBase] = {}

@property
def validatiors(self) -> dict[str, ValidationBase]:
"""Return all list of all tasks."""
return list(self._validatiors.values())

async def async_load(self, repository: HacsRepository) -> None:
"""Load all tasks."""
self._validatiors = {}
validator_files = Path(__file__).parent
validator_modules = (
module.stem
for module in validator_files.glob("*.py")
if module.name not in ("base.py", "__init__.py", "manager.py")
)

async def _load_module(module: str):
task_module = import_module(f"{__package__}.{module}")
if task := await task_module.async_setup_validator(repository=repository):
self._validatiors[task.slug] = task

await asyncio.gather(*[_load_module(task) for task in validator_modules])
self.hacs.log.info("Loaded %s validators", len(self.validatiors))

async def async_run_repository_checks(self, repository: HacsRepository) -> None:
"""Run all validators for a repository."""
if not self.hacs.system.running:
return

await self.async_load(repository)

await asyncio.gather(
*[
validator.execute_validation()
for validator in self.validatiors or []
if (self.hacs.system.action or not validator.action_only)
and (
validator.category == "common" or validator.category == repository.data.category
)
]
)

total = len([x for x in self.validatiors if self.hacs.system.action or not x.action_only])
failed = len([x for x in self.validatiors if x.failed])

if failed != 0:
repository.logger.error("%s %s/%s checks failed", repository, failed, total)
if self.hacs.system.action:
exit(1)
else:
repository.logger.debug("%s All (%s) checks passed", repository, total)
15 changes: 15 additions & 0 deletions custom_components/hacs/validate/repository_description.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import annotations

from ..repositories.base import HacsRepository
from .base import ActionValidationBase, ValidationException


async def async_setup_validator(repository: HacsRepository) -> Validator:
"""Set up this validator."""
return Validator(repository=repository)


class Validator(ActionValidationBase):
def validate(self):
if not self.repository.data.description:
raise ValidationException("The repository has no description")
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
from ..base import ActionValidationBase, ValidationException
from __future__ import annotations

from ..repositories.base import HacsRepository
from .base import ActionValidationBase, ValidationException

class RepositoryInformationFile(ActionValidationBase):
async def async_check(self):

async def async_setup_validator(repository: HacsRepository) -> Validator:
"""Set up this validator."""
return Validator(repository=repository)


class Validator(ActionValidationBase):
async def async_validate(self):
filenames = [x.filename.lower() for x in self.repository.tree]
if self.repository.data.render_readme and "readme" in filenames:
pass
Expand Down
Loading

0 comments on commit 74e3de9

Please sign in to comment.