theme.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. """Class for themes in HACS."""
  2. from __future__ import annotations
  3. from typing import TYPE_CHECKING
  4. from ..enums import HacsCategory, HacsDispatchEvent
  5. from ..exceptions import HacsException
  6. from ..utils.decorator import concurrent
  7. from .base import HacsRepository
  8. if TYPE_CHECKING:
  9. from ..base import HacsBase
  10. class HacsThemeRepository(HacsRepository):
  11. """Themes in HACS."""
  12. def __init__(self, hacs: HacsBase, full_name: str):
  13. """Initialize."""
  14. super().__init__(hacs=hacs)
  15. self.data.full_name = full_name
  16. self.data.full_name_lower = full_name.lower()
  17. self.data.category = HacsCategory.THEME
  18. self.content.path.remote = "themes"
  19. self.content.path.local = self.localpath
  20. self.content.single = False
  21. @property
  22. def localpath(self):
  23. """Return localpath."""
  24. return f"{self.hacs.core.config_path}/themes/{self.data.file_name.replace('.yaml', '')}"
  25. async def async_post_installation(self):
  26. """Run post installation steps."""
  27. try:
  28. await self.hacs.hass.services.async_call("frontend", "reload_themes", {})
  29. except BaseException: # lgtm [py/catch-base-exception] pylint: disable=broad-except
  30. pass
  31. async def validate_repository(self):
  32. """Validate."""
  33. # Run common validation steps.
  34. await self.common_validate()
  35. # Custom step 1: Validate content.
  36. compliant = False
  37. for treefile in self.treefiles:
  38. if treefile.startswith("themes/") and treefile.endswith(".yaml"):
  39. compliant = True
  40. break
  41. if not compliant:
  42. raise HacsException(
  43. f"{self.string} Repository structure for {self.ref.replace('tags/','')} is not compliant"
  44. )
  45. if self.repository_manifest.content_in_root:
  46. self.content.path.remote = ""
  47. # Handle potential errors
  48. if self.validate.errors:
  49. for error in self.validate.errors:
  50. if not self.hacs.status.startup:
  51. self.logger.error("%s %s", self.string, error)
  52. return self.validate.success
  53. async def async_post_registration(self):
  54. """Registration."""
  55. # Set name
  56. self.update_filenames()
  57. self.content.path.local = self.localpath
  58. if self.hacs.system.action:
  59. await self.hacs.validation.async_run_repository_checks(self)
  60. @concurrent(concurrenttasks=10, backoff_time=5)
  61. async def update_repository(self, ignore_issues=False, force=False):
  62. """Update."""
  63. if not await self.common_update(ignore_issues, force) and not force:
  64. return
  65. # Get theme objects.
  66. if self.repository_manifest.content_in_root:
  67. self.content.path.remote = ""
  68. # Update name
  69. self.update_filenames()
  70. self.content.path.local = self.localpath
  71. # Signal entities to refresh
  72. if self.data.installed:
  73. self.hacs.async_dispatch(
  74. HacsDispatchEvent.REPOSITORY,
  75. {
  76. "id": 1337,
  77. "action": "update",
  78. "repository": self.data.full_name,
  79. "repository_id": self.data.id,
  80. },
  81. )
  82. def update_filenames(self) -> None:
  83. """Get the filename to target."""
  84. for treefile in self.tree:
  85. if treefile.full_path.startswith(
  86. self.content.path.remote
  87. ) and treefile.full_path.endswith(".yaml"):
  88. self.data.file_name = treefile.filename