mirror of
https://github.com/CCOSTAN/Home-AssistantConfig.git
synced 2025-09-14 23:55:18 +00:00
Updated HACS and also fixed Garadget #727
This commit is contained in:
20
config/custom_components/hacs/repositories/__init__.py
Executable file → Normal file
20
config/custom_components/hacs/repositories/__init__.py
Executable file → Normal file
@@ -1,6 +1,16 @@
|
||||
"""Initialize repositories."""
|
||||
from .theme import HacsTheme
|
||||
from .integration import HacsIntegration
|
||||
from .python_script import HacsPythonScript
|
||||
from .appdaemon import HacsAppdaemon
|
||||
from .plugin import HacsPlugin
|
||||
from custom_components.hacs.repositories.theme import HacsTheme
|
||||
from custom_components.hacs.repositories.integration import HacsIntegration
|
||||
from custom_components.hacs.repositories.python_script import HacsPythonScript
|
||||
from custom_components.hacs.repositories.appdaemon import HacsAppdaemon
|
||||
from custom_components.hacs.repositories.netdaemon import HacsNetdaemon
|
||||
from custom_components.hacs.repositories.plugin import HacsPlugin
|
||||
|
||||
RERPOSITORY_CLASSES = {
|
||||
"theme": HacsTheme,
|
||||
"integration": HacsIntegration,
|
||||
"python_script": HacsPythonScript,
|
||||
"appdaemon": HacsAppdaemon,
|
||||
"netdaemon": HacsNetdaemon,
|
||||
"plugin": HacsPlugin,
|
||||
}
|
||||
|
30
config/custom_components/hacs/repositories/appdaemon.py
Executable file → Normal file
30
config/custom_components/hacs/repositories/appdaemon.py
Executable file → Normal file
@@ -1,27 +1,27 @@
|
||||
"""Class for appdaemon apps in HACS."""
|
||||
from aiogithubapi import AIOGitHubException
|
||||
from .repository import HacsRepository, register_repository_class
|
||||
from integrationhelper import Logger
|
||||
|
||||
from .repository import HacsRepository
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
|
||||
|
||||
@register_repository_class
|
||||
class HacsAppdaemon(HacsRepository):
|
||||
"""Appdaemon apps in HACS."""
|
||||
|
||||
category = "appdaemon"
|
||||
|
||||
def __init__(self, full_name):
|
||||
"""Initialize."""
|
||||
super().__init__()
|
||||
self.information.full_name = full_name
|
||||
self.information.category = self.category
|
||||
self.data.full_name = full_name
|
||||
self.data.category = "appdaemon"
|
||||
self.content.path.local = self.localpath
|
||||
self.content.path.remote = "apps"
|
||||
self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}")
|
||||
|
||||
@property
|
||||
def localpath(self):
|
||||
"""Return localpath."""
|
||||
return f"{self.system.config_path}/appdaemon/apps/{self.information.name}"
|
||||
return f"{self.hacs.system.config_path}/appdaemon/apps/{self.data.name}"
|
||||
|
||||
async def validate_repository(self):
|
||||
"""Validate."""
|
||||
@@ -39,19 +39,14 @@ class HacsAppdaemon(HacsRepository):
|
||||
self.validate.errors.append("Repostitory structure not compliant")
|
||||
|
||||
self.content.path.remote = addir[0].path
|
||||
self.information.name = addir[0].name
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
# Handle potential errors
|
||||
if self.validate.errors:
|
||||
for error in self.validate.errors:
|
||||
if not self.system.status.startup:
|
||||
if not self.hacs.system.status.startup:
|
||||
self.logger.error(error)
|
||||
return self.validate.success
|
||||
|
||||
@@ -68,13 +63,13 @@ class HacsAppdaemon(HacsRepository):
|
||||
|
||||
async def update_repository(self):
|
||||
"""Update."""
|
||||
if self.github.ratelimits.remaining == 0:
|
||||
if self.hacs.github.ratelimits.remaining == 0:
|
||||
return
|
||||
await self.common_update()
|
||||
|
||||
# Get appdaemon objects.
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
if self.content.path.remote == "apps":
|
||||
@@ -82,14 +77,9 @@ class HacsAppdaemon(HacsRepository):
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
self.content.path.remote = addir[0].path
|
||||
self.information.name = addir[0].name
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
# Set local path
|
||||
self.content.path.local = self.localpath
|
||||
|
134
config/custom_components/hacs/repositories/integration.py
Executable file → Normal file
134
config/custom_components/hacs/repositories/integration.py
Executable file → Normal file
@@ -1,80 +1,56 @@
|
||||
"""Class for integrations in HACS."""
|
||||
import json
|
||||
from aiogithubapi import AIOGitHubException
|
||||
from integrationhelper import Logger
|
||||
|
||||
from homeassistant.loader import async_get_custom_components
|
||||
from .repository import HacsRepository, register_repository_class
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
|
||||
from custom_components.hacs.hacsbase.exceptions import HacsException
|
||||
from custom_components.hacs.helpers.filters import get_first_directory_in_directory
|
||||
from custom_components.hacs.helpers.information import get_integration_manifest
|
||||
from custom_components.hacs.repositories.repository import HacsRepository
|
||||
|
||||
|
||||
@register_repository_class
|
||||
class HacsIntegration(HacsRepository):
|
||||
"""Integrations in HACS."""
|
||||
|
||||
category = "integration"
|
||||
|
||||
def __init__(self, full_name):
|
||||
"""Initialize."""
|
||||
super().__init__()
|
||||
self.information.full_name = full_name
|
||||
self.information.category = self.category
|
||||
self.domain = None
|
||||
self.data.full_name = full_name
|
||||
self.data.category = "integration"
|
||||
self.content.path.remote = "custom_components"
|
||||
self.content.path.local = self.localpath
|
||||
self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}")
|
||||
|
||||
@property
|
||||
def localpath(self):
|
||||
"""Return localpath."""
|
||||
return f"{self.system.config_path}/custom_components/{self.domain}"
|
||||
return f"{self.hacs.system.config_path}/custom_components/{self.data.domain}"
|
||||
|
||||
async def validate_repository(self):
|
||||
"""Validate."""
|
||||
await self.common_validate()
|
||||
|
||||
# Attach repository
|
||||
if self.repository_object is None:
|
||||
self.repository_object = await self.github.get_repo(
|
||||
self.information.full_name
|
||||
)
|
||||
|
||||
# Custom step 1: Validate content.
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
if self.content.path.remote == "custom_components":
|
||||
try:
|
||||
ccdir = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
except AIOGitHubException:
|
||||
name = get_first_directory_in_directory(self.tree, "custom_components")
|
||||
if name is None:
|
||||
raise HacsException(
|
||||
f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant"
|
||||
)
|
||||
self.content.path.remote = f"custom_components/{name}"
|
||||
|
||||
for item in ccdir or []:
|
||||
if item.type == "dir":
|
||||
self.content.path.remote = item.path
|
||||
break
|
||||
|
||||
if self.repository_manifest.zip_release:
|
||||
self.content.objects = self.releases.last_release_object.assets
|
||||
|
||||
else:
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects or []:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
if not await self.get_manifest():
|
||||
self.validate.errors.append("Missing manifest file.")
|
||||
try:
|
||||
await get_integration_manifest(self)
|
||||
except HacsException as exception:
|
||||
self.logger.error(exception)
|
||||
|
||||
# Handle potential errors
|
||||
if self.validate.errors:
|
||||
for error in self.validate.errors:
|
||||
if not self.system.status.startup:
|
||||
if not self.hacs.system.status.startup:
|
||||
self.logger.error(error)
|
||||
return self.validate.success
|
||||
|
||||
@@ -86,46 +62,26 @@ class HacsIntegration(HacsRepository):
|
||||
# Run common registration steps.
|
||||
await self.common_registration()
|
||||
|
||||
# Get the content of the manifest file.
|
||||
await self.get_manifest()
|
||||
|
||||
# Set local path
|
||||
self.content.path.local = self.localpath
|
||||
|
||||
async def update_repository(self):
|
||||
"""Update."""
|
||||
if self.github.ratelimits.remaining == 0:
|
||||
if self.hacs.github.ratelimits.remaining == 0:
|
||||
return
|
||||
await self.common_update()
|
||||
|
||||
# Get integration objects.
|
||||
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
if self.content.path.remote == "custom_components":
|
||||
ccdir = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
if not isinstance(ccdir, list):
|
||||
self.validate.errors.append("Repostitory structure not compliant")
|
||||
|
||||
self.content.path.remote = ccdir[0].path
|
||||
name = get_first_directory_in_directory(self.tree, "custom_components")
|
||||
self.content.path.remote = f"custom_components/{name}"
|
||||
|
||||
try:
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
except AIOGitHubException:
|
||||
return
|
||||
|
||||
self.content.files = []
|
||||
if isinstance(self.content.objects, list):
|
||||
for filename in self.content.objects or []:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
await self.get_manifest()
|
||||
await get_integration_manifest(self)
|
||||
except HacsException as exception:
|
||||
self.logger.error(exception)
|
||||
|
||||
# Set local path
|
||||
self.content.path.local = self.localpath
|
||||
@@ -133,33 +89,5 @@ class HacsIntegration(HacsRepository):
|
||||
async def reload_custom_components(self):
|
||||
"""Reload custom_components (and config flows)in HA."""
|
||||
self.logger.info("Reloading custom_component cache")
|
||||
del self.hass.data["custom_components"]
|
||||
await async_get_custom_components(self.hass)
|
||||
|
||||
async def get_manifest(self):
|
||||
"""Get info from the manifest file."""
|
||||
manifest_path = f"{self.content.path.remote}/manifest.json"
|
||||
try:
|
||||
manifest = await self.repository_object.get_contents(
|
||||
manifest_path, self.ref
|
||||
)
|
||||
manifest = json.loads(manifest.content)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return False
|
||||
|
||||
if manifest:
|
||||
try:
|
||||
self.manifest = manifest
|
||||
self.information.authors = manifest["codeowners"]
|
||||
self.domain = manifest["domain"]
|
||||
self.information.name = manifest["name"]
|
||||
self.information.homeassistant_version = manifest.get("homeassistant")
|
||||
|
||||
# Set local path
|
||||
self.content.path.local = self.localpath
|
||||
return True
|
||||
except KeyError as exception:
|
||||
raise HacsException(
|
||||
f"Missing expected key {exception} in 'manifest.json'"
|
||||
)
|
||||
return False
|
||||
del self.hacs.hass.data["custom_components"]
|
||||
await async_get_custom_components(self.hacs.hass)
|
||||
|
0
config/custom_components/hacs/repositories/manifest.py
Executable file → Normal file
0
config/custom_components/hacs/repositories/manifest.py
Executable file → Normal file
90
config/custom_components/hacs/repositories/netdaemon.py
Normal file
90
config/custom_components/hacs/repositories/netdaemon.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""Class for netdaemon apps in HACS."""
|
||||
from integrationhelper import Logger
|
||||
|
||||
from .repository import HacsRepository
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
|
||||
from custom_components.hacs.helpers.filters import get_first_directory_in_directory
|
||||
|
||||
|
||||
class HacsNetdaemon(HacsRepository):
|
||||
"""Netdaemon apps in HACS."""
|
||||
|
||||
def __init__(self, full_name):
|
||||
"""Initialize."""
|
||||
super().__init__()
|
||||
self.data.full_name = full_name
|
||||
self.data.category = "netdaemon"
|
||||
self.content.path.local = self.localpath
|
||||
self.content.path.remote = "apps"
|
||||
self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}")
|
||||
|
||||
@property
|
||||
def localpath(self):
|
||||
"""Return localpath."""
|
||||
return f"{self.hacs.system.config_path}/netdaemon/apps/{self.data.name}"
|
||||
|
||||
async def validate_repository(self):
|
||||
"""Validate."""
|
||||
await self.common_validate()
|
||||
|
||||
# Custom step 1: Validate content.
|
||||
if self.repository_manifest:
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
if self.content.path.remote == "apps":
|
||||
self.data.domain = get_first_directory_in_directory(
|
||||
self.tree, self.content.path.remote
|
||||
)
|
||||
self.content.path.remote = f"apps/{self.data.name}"
|
||||
|
||||
compliant = False
|
||||
for treefile in self.treefiles:
|
||||
if treefile.startswith(f"{self.content.path.remote}") and treefile.endswith(
|
||||
".cs"
|
||||
):
|
||||
compliant = True
|
||||
break
|
||||
if not compliant:
|
||||
raise HacsException(
|
||||
f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant"
|
||||
)
|
||||
|
||||
# Handle potential errors
|
||||
if self.validate.errors:
|
||||
for error in self.validate.errors:
|
||||
if not self.hacs.system.status.startup:
|
||||
self.logger.error(error)
|
||||
return self.validate.success
|
||||
|
||||
async def registration(self):
|
||||
"""Registration."""
|
||||
if not await self.validate_repository():
|
||||
return False
|
||||
|
||||
# Run common registration steps.
|
||||
await self.common_registration()
|
||||
|
||||
# Set local path
|
||||
self.content.path.local = self.localpath
|
||||
|
||||
async def update_repository(self):
|
||||
"""Update."""
|
||||
if self.hacs.github.ratelimits.remaining == 0:
|
||||
return
|
||||
await self.common_update()
|
||||
|
||||
# Get appdaemon objects.
|
||||
if self.repository_manifest:
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
if self.content.path.remote == "apps":
|
||||
self.data.domain = get_first_directory_in_directory(
|
||||
self.tree, self.content.path.remote
|
||||
)
|
||||
self.content.path.remote = f"apps/{self.data.name}"
|
||||
|
||||
# Set local path
|
||||
self.content.path.local = self.localpath
|
95
config/custom_components/hacs/repositories/plugin.py
Executable file → Normal file
95
config/custom_components/hacs/repositories/plugin.py
Executable file → Normal file
@@ -1,26 +1,27 @@
|
||||
"""Class for plugins in HACS."""
|
||||
import json
|
||||
from aiogithubapi import AIOGitHubException
|
||||
from .repository import HacsRepository, register_repository_class
|
||||
from integrationhelper import Logger
|
||||
|
||||
from .repository import HacsRepository
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
|
||||
from custom_components.hacs.helpers.information import find_file_name
|
||||
|
||||
|
||||
@register_repository_class
|
||||
class HacsPlugin(HacsRepository):
|
||||
"""Plugins in HACS."""
|
||||
|
||||
category = "plugin"
|
||||
|
||||
def __init__(self, full_name):
|
||||
"""Initialize."""
|
||||
super().__init__()
|
||||
self.information.full_name = full_name
|
||||
self.information.category = self.category
|
||||
self.information.file_name = None
|
||||
self.data.full_name = full_name
|
||||
self.data.file_name = None
|
||||
self.data.category = "plugin"
|
||||
self.information.javascript_type = None
|
||||
self.content.path.local = (
|
||||
f"{self.system.config_path}/www/community/{full_name.split('/')[-1]}"
|
||||
f"{self.hacs.system.config_path}/www/community/{full_name.split('/')[-1]}"
|
||||
)
|
||||
self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}")
|
||||
|
||||
async def validate_repository(self):
|
||||
"""Validate."""
|
||||
@@ -28,7 +29,7 @@ class HacsPlugin(HacsRepository):
|
||||
await self.common_validate()
|
||||
|
||||
# Custom step 1: Validate content.
|
||||
await self.get_plugin_location()
|
||||
find_file_name(self)
|
||||
|
||||
if self.content.path.remote is None:
|
||||
raise HacsException(
|
||||
@@ -38,14 +39,10 @@ class HacsPlugin(HacsRepository):
|
||||
if self.content.path.remote == "release":
|
||||
self.content.single = True
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
# Handle potential errors
|
||||
if self.validate.errors:
|
||||
for error in self.validate.errors:
|
||||
if not self.system.status.startup:
|
||||
if not self.hacs.system.status.startup:
|
||||
self.logger.error(error)
|
||||
return self.validate.success
|
||||
|
||||
@@ -59,13 +56,13 @@ class HacsPlugin(HacsRepository):
|
||||
|
||||
async def update_repository(self):
|
||||
"""Update."""
|
||||
if self.github.ratelimits.remaining == 0:
|
||||
if self.hacs.github.ratelimits.remaining == 0:
|
||||
return
|
||||
# Run common update steps.
|
||||
await self.common_update()
|
||||
|
||||
# Get plugin objects.
|
||||
await self.get_plugin_location()
|
||||
find_file_name(self)
|
||||
|
||||
# Get JS type
|
||||
await self.parse_readme_for_jstype()
|
||||
@@ -76,68 +73,6 @@ class HacsPlugin(HacsRepository):
|
||||
if self.content.path.remote == "release":
|
||||
self.content.single = True
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
async def get_plugin_location(self):
|
||||
"""Get plugin location."""
|
||||
if self.content.path.remote is not None:
|
||||
return
|
||||
|
||||
possible_locations = ["dist", "release", ""]
|
||||
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
possible_locations = [""]
|
||||
|
||||
for location in possible_locations:
|
||||
if self.content.path.remote is not None:
|
||||
continue
|
||||
try:
|
||||
objects = []
|
||||
files = []
|
||||
if location != "release":
|
||||
try:
|
||||
objects = await self.repository_object.get_contents(
|
||||
location, self.ref
|
||||
)
|
||||
except AIOGitHubException:
|
||||
continue
|
||||
else:
|
||||
await self.get_releases()
|
||||
if self.releases.releases:
|
||||
if self.releases.last_release_object.assets is not None:
|
||||
objects = self.releases.last_release_object.assets
|
||||
|
||||
for item in objects:
|
||||
if item.name.endswith(".js"):
|
||||
files.append(item.name)
|
||||
|
||||
# Handler for plug requirement 3
|
||||
valid_filenames = [
|
||||
f"{self.information.name.replace('lovelace-', '')}.js",
|
||||
f"{self.information.name}.js",
|
||||
f"{self.information.name}.umd.js",
|
||||
f"{self.information.name}-bundle.js",
|
||||
]
|
||||
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.filename:
|
||||
valid_filenames.append(self.repository_manifest.filename)
|
||||
|
||||
for name in valid_filenames:
|
||||
if name in files:
|
||||
# YES! We got it!
|
||||
self.information.file_name = name
|
||||
self.content.path.remote = location
|
||||
self.content.objects = objects
|
||||
self.content.files = files
|
||||
break
|
||||
|
||||
except SystemError:
|
||||
pass
|
||||
|
||||
async def get_package_content(self):
|
||||
"""Get package content."""
|
||||
try:
|
||||
@@ -145,7 +80,7 @@ class HacsPlugin(HacsRepository):
|
||||
package = json.loads(package.content)
|
||||
|
||||
if package:
|
||||
self.information.authors = package["author"]
|
||||
self.data.authors = package["author"]
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
|
||||
|
72
config/custom_components/hacs/repositories/python_script.py
Executable file → Normal file
72
config/custom_components/hacs/repositories/python_script.py
Executable file → Normal file
@@ -1,10 +1,11 @@
|
||||
"""Class for python_scripts in HACS."""
|
||||
from aiogithubapi import AIOGitHubException
|
||||
from .repository import HacsRepository, register_repository_class
|
||||
from integrationhelper import Logger
|
||||
|
||||
from .repository import HacsRepository
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
from ..helpers.information import find_file_name
|
||||
|
||||
|
||||
@register_repository_class
|
||||
class HacsPythonScript(HacsRepository):
|
||||
"""python_scripts in HACS."""
|
||||
|
||||
@@ -13,11 +14,12 @@ class HacsPythonScript(HacsRepository):
|
||||
def __init__(self, full_name):
|
||||
"""Initialize."""
|
||||
super().__init__()
|
||||
self.information.full_name = full_name
|
||||
self.information.category = self.category
|
||||
self.data.full_name = full_name
|
||||
self.data.category = "python_script"
|
||||
self.content.path.remote = "python_scripts"
|
||||
self.content.path.local = f"{self.system.config_path}/python_scripts"
|
||||
self.content.path.local = f"{self.hacs.system.config_path}/python_scripts"
|
||||
self.content.single = True
|
||||
self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}")
|
||||
|
||||
async def validate_repository(self):
|
||||
"""Validate."""
|
||||
@@ -25,26 +27,25 @@ class HacsPythonScript(HacsRepository):
|
||||
await self.common_validate()
|
||||
|
||||
# Custom step 1: Validate content.
|
||||
try:
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
except AIOGitHubException:
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
compliant = False
|
||||
for treefile in self.treefiles:
|
||||
if treefile.startswith(f"{self.content.path.remote}") and treefile.endswith(
|
||||
".py"
|
||||
):
|
||||
compliant = True
|
||||
break
|
||||
if not compliant:
|
||||
raise HacsException(
|
||||
f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant"
|
||||
)
|
||||
|
||||
if not isinstance(self.content.objects, list):
|
||||
self.validate.errors.append("Repostitory structure not compliant")
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
|
||||
# Handle potential errors
|
||||
if self.validate.errors:
|
||||
for error in self.validate.errors:
|
||||
if not self.system.status.startup:
|
||||
if not self.hacs.system.status.startup:
|
||||
self.logger.error(error)
|
||||
return self.validate.success
|
||||
|
||||
@@ -57,31 +58,30 @@ class HacsPythonScript(HacsRepository):
|
||||
await self.common_registration()
|
||||
|
||||
# Set name
|
||||
self.information.name = self.content.objects[0].name.replace(".py", "")
|
||||
find_file_name(self)
|
||||
|
||||
async def update_repository(self): # lgtm[py/similar-function]
|
||||
"""Update."""
|
||||
if self.github.ratelimits.remaining == 0:
|
||||
if self.hacs.github.ratelimits.remaining == 0:
|
||||
return
|
||||
# Run common update steps.
|
||||
await self.common_update()
|
||||
|
||||
# Get python_script objects.
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
compliant = False
|
||||
for treefile in self.treefiles:
|
||||
if treefile.startswith(f"{self.content.path.remote}") and treefile.endswith(
|
||||
".py"
|
||||
):
|
||||
compliant = True
|
||||
break
|
||||
if not compliant:
|
||||
raise HacsException(
|
||||
f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant"
|
||||
)
|
||||
|
||||
# Update name
|
||||
self.information.name = self.content.objects[0].name.replace(".py", "")
|
||||
|
||||
self.content.files = []
|
||||
for filename in self.content.objects:
|
||||
self.content.files.append(filename.name)
|
||||
find_file_name(self)
|
||||
|
17
config/custom_components/hacs/repositories/removed.py
Normal file
17
config/custom_components/hacs/repositories/removed.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Object for removed repositories."""
|
||||
import attr
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class RemovedRepository:
|
||||
repository: str = None
|
||||
reason: str = None
|
||||
link: str = None
|
||||
removal_type: str = None # archived, not_compliant, critical, dev, broken
|
||||
acknowledged: bool = False
|
||||
|
||||
def update_data(self, data: dict):
|
||||
"""Update data of the repository."""
|
||||
for key in data:
|
||||
if key in self.__dict__:
|
||||
setattr(self, key, data[key])
|
307
config/custom_components/hacs/repositories/repository.py
Executable file → Normal file
307
config/custom_components/hacs/repositories/repository.py
Executable file → Normal file
@@ -1,29 +1,27 @@
|
||||
"""Repository."""
|
||||
# pylint: disable=broad-except, bad-continuation, no-member
|
||||
import pathlib
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import zipfile
|
||||
from integrationhelper import Validate, Logger
|
||||
from integrationhelper import Validate
|
||||
from aiogithubapi import AIOGitHubException
|
||||
from .manifest import HacsManifest
|
||||
from ..helpers.misc import get_repository_name
|
||||
from ..hacsbase import Hacs
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
from ..hacsbase.backup import Backup
|
||||
from ..handler.download import async_download_file, async_save_file
|
||||
from ..helpers.misc import version_left_higher_then_right
|
||||
from ..helpers.install import install_repository, version_to_install
|
||||
|
||||
|
||||
RERPOSITORY_CLASSES = {}
|
||||
|
||||
|
||||
def register_repository_class(cls):
|
||||
"""Register class."""
|
||||
RERPOSITORY_CLASSES[cls.category] = cls
|
||||
return cls
|
||||
from custom_components.hacs.globals import get_hacs
|
||||
from custom_components.hacs.helpers.information import (
|
||||
get_info_md_content,
|
||||
get_repository,
|
||||
)
|
||||
from custom_components.hacs.helpers.validate_repository import (
|
||||
common_validate,
|
||||
common_update_data,
|
||||
)
|
||||
from custom_components.hacs.repositories.repositorydata import RepositoryData
|
||||
|
||||
|
||||
class RepositoryVersions:
|
||||
@@ -79,6 +77,7 @@ class RepositoryReleases:
|
||||
published_tags = []
|
||||
objects = []
|
||||
releases = False
|
||||
downloads = None
|
||||
|
||||
|
||||
class RepositoryPath:
|
||||
@@ -97,26 +96,25 @@ class RepositoryContent:
|
||||
single = False
|
||||
|
||||
|
||||
class HacsRepository(Hacs):
|
||||
class HacsRepository:
|
||||
"""HacsRepository."""
|
||||
|
||||
def __init__(self):
|
||||
"""Set up HacsRepository."""
|
||||
|
||||
self.data = {}
|
||||
self.hacs = get_hacs()
|
||||
self.data = RepositoryData()
|
||||
self.content = RepositoryContent()
|
||||
self.content.path = RepositoryPath()
|
||||
self.information = RepositoryInformation()
|
||||
self.repository_object = None
|
||||
self.status = RepositoryStatus()
|
||||
self.state = None
|
||||
self.manifest = {}
|
||||
self.integration_manifest = {}
|
||||
self.repository_manifest = HacsManifest.from_dict({})
|
||||
self.validate = Validate()
|
||||
self.releases = RepositoryReleases()
|
||||
self.versions = RepositoryVersions()
|
||||
self.pending_restart = False
|
||||
self.logger = None
|
||||
self.tree = []
|
||||
self.treefiles = []
|
||||
self.ref = None
|
||||
@@ -126,7 +124,7 @@ class HacsRepository(Hacs):
|
||||
"""Return pending upgrade."""
|
||||
if self.status.installed:
|
||||
if self.status.selected_tag is not None:
|
||||
if self.status.selected_tag == self.information.default_branch:
|
||||
if self.status.selected_tag == self.data.default_branch:
|
||||
if self.versions.installed_commit != self.versions.available_commit:
|
||||
return True
|
||||
return False
|
||||
@@ -137,23 +135,20 @@ class HacsRepository(Hacs):
|
||||
@property
|
||||
def config_flow(self):
|
||||
"""Return bool if integration has config_flow."""
|
||||
if self.manifest:
|
||||
if self.information.full_name == "hacs/integration":
|
||||
if self.integration_manifest:
|
||||
if self.data.full_name == "hacs/integration":
|
||||
return False
|
||||
return self.manifest.get("config_flow", False)
|
||||
return self.integration_manifest.get("config_flow", False)
|
||||
return False
|
||||
|
||||
@property
|
||||
def custom(self):
|
||||
"""Return flag if the repository is custom."""
|
||||
if self.information.full_name.split("/")[0] in [
|
||||
"custom-components",
|
||||
"custom-cards",
|
||||
]:
|
||||
if self.data.full_name.split("/")[0] in ["custom-components", "custom-cards"]:
|
||||
return False
|
||||
if self.information.full_name in self.common.default:
|
||||
if self.data.full_name.lower() in [x.lower() for x in self.hacs.common.default]:
|
||||
return False
|
||||
if self.information.full_name == "hacs/integration":
|
||||
if self.data.full_name == "hacs/integration":
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -164,24 +159,21 @@ class HacsRepository(Hacs):
|
||||
if self.information.homeassistant_version is not None:
|
||||
target = self.information.homeassistant_version
|
||||
if self.repository_manifest is not None:
|
||||
if self.repository_manifest.homeassistant is not None:
|
||||
target = self.repository_manifest.homeassistant
|
||||
if self.data.homeassistant is not None:
|
||||
target = self.data.homeassistant
|
||||
|
||||
if target is not None:
|
||||
if self.releases.releases:
|
||||
if not version_left_higher_then_right(self.system.ha_version, target):
|
||||
if not version_left_higher_then_right(
|
||||
self.hacs.system.ha_version, target
|
||||
):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
"""Return display name."""
|
||||
return get_repository_name(
|
||||
self.repository_manifest,
|
||||
self.information.name,
|
||||
self.information.category,
|
||||
self.manifest,
|
||||
)
|
||||
return get_repository_name(self)
|
||||
|
||||
@property
|
||||
def display_status(self):
|
||||
@@ -257,127 +249,41 @@ class HacsRepository(Hacs):
|
||||
|
||||
async def common_validate(self):
|
||||
"""Common validation steps of the repository."""
|
||||
# Attach helpers
|
||||
self.validate.errors = []
|
||||
self.logger = Logger(
|
||||
f"hacs.repository.{self.information.category}.{self.information.full_name}"
|
||||
)
|
||||
if self.ref is None:
|
||||
self.ref = version_to_install(self)
|
||||
|
||||
# Step 1: Make sure the repository exist.
|
||||
self.logger.debug("Checking repository.")
|
||||
try:
|
||||
self.repository_object = await self.github.get_repo(
|
||||
self.information.full_name
|
||||
)
|
||||
self.data = self.repository_object.attributes
|
||||
except Exception as exception: # Gotta Catch 'Em All
|
||||
if not self.system.status.startup:
|
||||
self.logger.error(exception)
|
||||
self.validate.errors.append("Repository does not exist.")
|
||||
return
|
||||
|
||||
if not self.tree:
|
||||
self.tree = await self.repository_object.get_tree(self.ref)
|
||||
self.treefiles = []
|
||||
for treefile in self.tree:
|
||||
self.treefiles.append(treefile.full_path)
|
||||
|
||||
# Step 2: Make sure the repository is not archived.
|
||||
if self.repository_object.archived:
|
||||
self.validate.errors.append("Repository is archived.")
|
||||
return
|
||||
|
||||
# Step 3: Make sure the repository is not in the blacklist.
|
||||
if self.information.full_name in self.common.blacklist:
|
||||
self.validate.errors.append("Repository is in the blacklist.")
|
||||
return
|
||||
|
||||
# Step 4: default branch
|
||||
self.information.default_branch = self.repository_object.default_branch
|
||||
|
||||
# Step 5: Get releases.
|
||||
await self.get_releases()
|
||||
|
||||
# Step 6: Get the content of hacs.json
|
||||
await self.get_repository_manifest_content()
|
||||
|
||||
# Set repository name
|
||||
self.information.name = self.information.full_name.split("/")[1]
|
||||
await common_validate(self)
|
||||
|
||||
async def common_registration(self):
|
||||
"""Common registration steps of the repository."""
|
||||
# Attach logger
|
||||
if self.logger is None:
|
||||
self.logger = Logger(
|
||||
f"hacs.repository.{self.information.category}.{self.information.full_name}"
|
||||
)
|
||||
|
||||
# Attach repository
|
||||
if self.repository_object is None:
|
||||
self.repository_object = await self.github.get_repo(
|
||||
self.information.full_name
|
||||
self.repository_object = await get_repository(
|
||||
self.hacs.session, self.hacs.configuration.token, self.data.full_name
|
||||
)
|
||||
self.data.update_data(self.repository_object.attributes)
|
||||
|
||||
# Set id
|
||||
self.information.uid = str(self.repository_object.id)
|
||||
self.information.uid = str(self.data.id)
|
||||
|
||||
# Set topics
|
||||
self.information.topics = self.repository_object.topics
|
||||
self.data.topics = self.data.topics
|
||||
|
||||
# Set stargazers_count
|
||||
self.information.stars = self.repository_object.attributes.get(
|
||||
"stargazers_count", 0
|
||||
)
|
||||
self.data.stargazers_count = self.data.stargazers_count
|
||||
|
||||
# Set description
|
||||
if self.repository_object.description:
|
||||
self.information.description = self.repository_object.description
|
||||
self.data.description = self.data.description
|
||||
|
||||
async def common_update(self):
|
||||
"""Common information update steps of the repository."""
|
||||
# Attach logger
|
||||
if self.logger is None:
|
||||
self.logger = Logger(
|
||||
f"hacs.repository.{self.information.category}.{self.information.full_name}"
|
||||
)
|
||||
|
||||
self.logger.debug("Getting repository information")
|
||||
|
||||
# Set ref
|
||||
if self.ref is None:
|
||||
self.ref = version_to_install(self)
|
||||
|
||||
# Attach repository
|
||||
self.repository_object = await self.github.get_repo(self.information.full_name)
|
||||
|
||||
# Update tree
|
||||
self.tree = await self.repository_object.get_tree(self.ref)
|
||||
self.treefiles = []
|
||||
for treefile in self.tree:
|
||||
self.treefiles.append(treefile.full_path)
|
||||
|
||||
# Update description
|
||||
if self.repository_object.description:
|
||||
self.information.description = self.repository_object.description
|
||||
|
||||
# Set stargazers_count
|
||||
self.information.stars = self.repository_object.attributes.get(
|
||||
"stargazers_count", 0
|
||||
)
|
||||
|
||||
# Update default branch
|
||||
self.information.default_branch = self.repository_object.default_branch
|
||||
await common_update_data(self)
|
||||
|
||||
# Update last updaeted
|
||||
self.information.last_updated = self.repository_object.attributes.get(
|
||||
"pushed_at", 0
|
||||
)
|
||||
|
||||
# Update topics
|
||||
self.information.topics = self.repository_object.topics
|
||||
|
||||
# Update last available commit
|
||||
await self.repository_object.set_last_commit()
|
||||
self.versions.available_commit = self.repository_object.last_commit
|
||||
@@ -386,10 +292,7 @@ class HacsRepository(Hacs):
|
||||
await self.get_repository_manifest_content()
|
||||
|
||||
# Update "info.md"
|
||||
await self.get_info_md_content()
|
||||
|
||||
# Update releases
|
||||
await self.get_releases()
|
||||
self.information.additional_info = await get_info_md_content(self)
|
||||
|
||||
async def install(self):
|
||||
"""Common installation steps of the repository."""
|
||||
@@ -409,18 +312,17 @@ class HacsRepository(Hacs):
|
||||
return validate
|
||||
|
||||
for content in contents or []:
|
||||
filecontent = await async_download_file(self.hass, content.download_url)
|
||||
filecontent = await async_download_file(content.download_url)
|
||||
|
||||
if filecontent is None:
|
||||
validate.errors.append(f"[{content.name}] was not downloaded.")
|
||||
continue
|
||||
|
||||
result = await async_save_file(
|
||||
f"{tempfile.gettempdir()}/{self.repository_manifest.filename}",
|
||||
filecontent,
|
||||
f"{tempfile.gettempdir()}/{self.data.filename}", filecontent
|
||||
)
|
||||
with zipfile.ZipFile(
|
||||
f"{tempfile.gettempdir()}/{self.repository_manifest.filename}", "r"
|
||||
f"{tempfile.gettempdir()}/{self.data.filename}", "r"
|
||||
) as zip_file:
|
||||
zip_file.extractall(self.content.path.local)
|
||||
|
||||
@@ -437,11 +339,13 @@ class HacsRepository(Hacs):
|
||||
"""Download the content of a directory."""
|
||||
from custom_components.hacs.helpers.download import download_content
|
||||
|
||||
validate = await download_content(self, validate, local_directory)
|
||||
validate = await download_content(self)
|
||||
return validate
|
||||
|
||||
async def get_repository_manifest_content(self):
|
||||
"""Get the content of the hacs.json file."""
|
||||
if not "hacs.json" in [x.filename for x in self.tree]:
|
||||
return
|
||||
if self.ref is None:
|
||||
self.ref = version_to_install(self)
|
||||
try:
|
||||
@@ -449,125 +353,44 @@ class HacsRepository(Hacs):
|
||||
self.repository_manifest = HacsManifest.from_dict(
|
||||
json.loads(manifest.content)
|
||||
)
|
||||
self.data.update_data(json.loads(manifest.content))
|
||||
except (AIOGitHubException, Exception): # Gotta Catch 'Em All
|
||||
pass
|
||||
|
||||
async def get_info_md_content(self):
|
||||
"""Get the content of info.md"""
|
||||
from ..handler.template import render_template
|
||||
|
||||
if self.ref is None:
|
||||
self.ref = version_to_install(self)
|
||||
|
||||
info = None
|
||||
info_files = ["info", "info.md"]
|
||||
|
||||
if self.repository_manifest is not None:
|
||||
if self.repository_manifest.render_readme:
|
||||
info_files = ["readme", "readme.md"]
|
||||
try:
|
||||
root = await self.repository_object.get_contents("", self.ref)
|
||||
for file in root:
|
||||
if file.name.lower() in info_files:
|
||||
|
||||
info = await self.repository_object.get_contents(
|
||||
file.name, self.ref
|
||||
)
|
||||
break
|
||||
if info is None:
|
||||
self.information.additional_info = ""
|
||||
else:
|
||||
info = info.content.replace("<svg", "<disabled").replace(
|
||||
"</svg", "</disabled"
|
||||
)
|
||||
|
||||
self.information.additional_info = render_template(info, self)
|
||||
|
||||
except (AIOGitHubException, Exception):
|
||||
self.information.additional_info = ""
|
||||
|
||||
async def get_releases(self):
|
||||
"""Get repository releases."""
|
||||
if self.status.show_beta:
|
||||
self.releases.objects = await self.repository_object.get_releases(
|
||||
prerelease=True, returnlimit=self.configuration.release_limit
|
||||
)
|
||||
else:
|
||||
self.releases.objects = await self.repository_object.get_releases(
|
||||
prerelease=False, returnlimit=self.configuration.release_limit
|
||||
)
|
||||
|
||||
if not self.releases.objects:
|
||||
return
|
||||
|
||||
self.releases.releases = True
|
||||
|
||||
self.releases.published_tags = []
|
||||
|
||||
for release in self.releases.objects:
|
||||
self.releases.published_tags.append(release.tag_name)
|
||||
|
||||
self.releases.last_release_object = self.releases.objects[0]
|
||||
if self.status.selected_tag is not None:
|
||||
if self.status.selected_tag != self.information.default_branch:
|
||||
for release in self.releases.objects:
|
||||
if release.tag_name == self.status.selected_tag:
|
||||
self.releases.last_release_object = release
|
||||
break
|
||||
if self.releases.last_release_object.assets:
|
||||
self.releases.last_release_object_downloads = self.releases.last_release_object.assets[
|
||||
0
|
||||
].attributes.get(
|
||||
"download_count"
|
||||
)
|
||||
self.versions.available = self.releases.objects[0].tag_name
|
||||
|
||||
def remove(self):
|
||||
"""Run remove tasks."""
|
||||
# Attach logger
|
||||
if self.logger is None:
|
||||
self.logger = Logger(
|
||||
f"hacs.repository.{self.information.category}.{self.information.full_name}"
|
||||
)
|
||||
self.logger.info("Starting removal")
|
||||
|
||||
if self.information.uid in self.common.installed:
|
||||
self.common.installed.remove(self.information.uid)
|
||||
for repository in self.repositories:
|
||||
if self.information.uid in self.hacs.common.installed:
|
||||
self.hacs.common.installed.remove(self.information.uid)
|
||||
for repository in self.hacs.repositories:
|
||||
if repository.information.uid == self.information.uid:
|
||||
self.repositories.remove(repository)
|
||||
self.hacs.repositories.remove(repository)
|
||||
|
||||
async def uninstall(self):
|
||||
"""Run uninstall tasks."""
|
||||
# Attach logger
|
||||
if self.logger is None:
|
||||
self.logger = Logger(
|
||||
f"hacs.repository.{self.information.category}.{self.information.full_name}"
|
||||
)
|
||||
self.logger.info("Uninstalling")
|
||||
await self.remove_local_directory()
|
||||
self.status.installed = False
|
||||
if self.information.category == "integration":
|
||||
if self.data.category == "integration":
|
||||
if self.config_flow:
|
||||
await self.reload_custom_components()
|
||||
else:
|
||||
self.pending_restart = True
|
||||
elif self.information.category == "theme":
|
||||
elif self.data.category == "theme":
|
||||
try:
|
||||
await self.hass.services.async_call("frontend", "reload_themes", {})
|
||||
await self.hacs.hass.services.async_call(
|
||||
"frontend", "reload_themes", {}
|
||||
)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
if self.information.full_name in self.common.installed:
|
||||
self.common.installed.remove(self.information.full_name)
|
||||
if self.data.full_name in self.hacs.common.installed:
|
||||
self.hacs.common.installed.remove(self.data.full_name)
|
||||
self.versions.installed = None
|
||||
self.versions.installed_commit = None
|
||||
self.hass.bus.async_fire(
|
||||
self.hacs.hass.bus.async_fire(
|
||||
"hacs/repository",
|
||||
{
|
||||
"id": 1337,
|
||||
"action": "uninstall",
|
||||
"repository": self.information.full_name,
|
||||
},
|
||||
{"id": 1337, "action": "uninstall", "repository": self.data.full_name},
|
||||
)
|
||||
|
||||
async def remove_local_directory(self):
|
||||
@@ -576,13 +399,11 @@ class HacsRepository(Hacs):
|
||||
from asyncio import sleep
|
||||
|
||||
try:
|
||||
if self.information.category == "python_script":
|
||||
local_path = "{}/{}.py".format(
|
||||
self.content.path.local, self.information.name
|
||||
)
|
||||
elif self.information.category == "theme":
|
||||
if self.data.category == "python_script":
|
||||
local_path = "{}/{}.py".format(self.content.path.local, self.data.name)
|
||||
elif self.data.category == "theme":
|
||||
local_path = "{}/{}.yaml".format(
|
||||
self.content.path.local, self.information.name
|
||||
self.content.path.local, self.data.name
|
||||
)
|
||||
else:
|
||||
local_path = self.content.path.local
|
||||
@@ -590,7 +411,7 @@ class HacsRepository(Hacs):
|
||||
if os.path.exists(local_path):
|
||||
self.logger.debug(f"Removing {local_path}")
|
||||
|
||||
if self.information.category in ["python_script", "theme"]:
|
||||
if self.data.category in ["python_script", "theme"]:
|
||||
os.remove(local_path)
|
||||
else:
|
||||
shutil.rmtree(local_path)
|
||||
|
82
config/custom_components/hacs/repositories/repositorydata.py
Normal file
82
config/custom_components/hacs/repositories/repositorydata.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Repository data."""
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
import attr
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class RepositoryData:
|
||||
"""RepositoryData class."""
|
||||
|
||||
id: int = 0
|
||||
full_name: str = ""
|
||||
pushed_at: str = ""
|
||||
category: str = ""
|
||||
archived: bool = False
|
||||
description: str = ""
|
||||
manifest_name: str = None
|
||||
topics: List[str] = []
|
||||
fork: bool = False
|
||||
domain: str = ""
|
||||
default_branch: str = None
|
||||
stargazers_count: int = 0
|
||||
last_commit: str = ""
|
||||
file_name: str = ""
|
||||
content_in_root: bool = False
|
||||
zip_release: bool = False
|
||||
filename: str = ""
|
||||
render_readme: bool = False
|
||||
hide_default_branch: bool = False
|
||||
domains: List[str] = []
|
||||
country: List[str] = []
|
||||
authors: List[str] = []
|
||||
homeassistant: str = None # Minimum Home Assistant version
|
||||
hacs: str = None # Minimum HACS version
|
||||
persistent_directory: str = None
|
||||
iot_class: str = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name."""
|
||||
if self.category in ["integration", "netdaemon"]:
|
||||
return self.domain
|
||||
return self.full_name.split("/")[-1]
|
||||
|
||||
def to_json(self):
|
||||
"""Export to json."""
|
||||
return self.__dict__
|
||||
|
||||
@staticmethod
|
||||
def create_from_dict(source: dict):
|
||||
"""Set attributes from dicts."""
|
||||
data = RepositoryData()
|
||||
for key in source:
|
||||
if key in data.__dict__:
|
||||
if key == "pushed_at":
|
||||
setattr(
|
||||
data, key, datetime.strptime(source[key], "%Y-%m-%dT%H:%M:%SZ")
|
||||
)
|
||||
elif key == "county":
|
||||
if isinstance(source[key], str):
|
||||
setattr(data, key, [source[key]])
|
||||
else:
|
||||
setattr(data, key, source[key])
|
||||
else:
|
||||
setattr(data, key, source[key])
|
||||
return data
|
||||
|
||||
def update_data(self, data: dict):
|
||||
"""Update data of the repository."""
|
||||
for key in data:
|
||||
if key in self.__dict__:
|
||||
if key == "pushed_at":
|
||||
setattr(
|
||||
self, key, datetime.strptime(data[key], "%Y-%m-%dT%H:%M:%SZ")
|
||||
)
|
||||
elif key == "county":
|
||||
if isinstance(data[key], str):
|
||||
setattr(self, key, [data[key]])
|
||||
else:
|
||||
setattr(self, key, data[key])
|
||||
else:
|
||||
setattr(self, key, data[key])
|
72
config/custom_components/hacs/repositories/theme.py
Executable file → Normal file
72
config/custom_components/hacs/repositories/theme.py
Executable file → Normal file
@@ -1,23 +1,22 @@
|
||||
"""Class for themes in HACS."""
|
||||
from .repository import HacsRepository, register_repository_class
|
||||
from integrationhelper import Logger
|
||||
from .repository import HacsRepository
|
||||
from ..hacsbase.exceptions import HacsException
|
||||
from ..helpers.filters import filter_content_return_one_of_type, find_first_of_filetype
|
||||
from ..helpers.information import find_file_name
|
||||
|
||||
|
||||
@register_repository_class
|
||||
class HacsTheme(HacsRepository):
|
||||
"""Themes in HACS."""
|
||||
|
||||
category = "theme"
|
||||
|
||||
def __init__(self, full_name):
|
||||
"""Initialize."""
|
||||
super().__init__()
|
||||
self.information.full_name = full_name
|
||||
self.information.category = self.category
|
||||
self.data.full_name = full_name
|
||||
self.data.category = "theme"
|
||||
self.content.path.remote = "themes"
|
||||
self.content.path.local = f"{self.system.config_path}/themes"
|
||||
self.content.path.local = f"{self.hacs.system.config_path}/themes/"
|
||||
self.content.single = False
|
||||
self.logger = Logger(f"hacs.repository.{self.data.category}.{full_name}")
|
||||
|
||||
async def validate_repository(self):
|
||||
"""Validate."""
|
||||
@@ -27,7 +26,6 @@ class HacsTheme(HacsRepository):
|
||||
# Custom step 1: Validate content.
|
||||
compliant = False
|
||||
for treefile in self.treefiles:
|
||||
self.logger.debug(treefile)
|
||||
if treefile.startswith("themes/") and treefile.endswith(".yaml"):
|
||||
compliant = True
|
||||
break
|
||||
@@ -36,25 +34,13 @@ class HacsTheme(HacsRepository):
|
||||
f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant"
|
||||
)
|
||||
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
|
||||
if not isinstance(self.content.objects, list):
|
||||
self.validate.errors.append("Repostitory structure not compliant")
|
||||
|
||||
self.content.files = filter_content_return_one_of_type(
|
||||
self.treefiles, "themes", "yaml"
|
||||
)
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
# Handle potential errors
|
||||
if self.validate.errors:
|
||||
for error in self.validate.errors:
|
||||
if not self.system.status.startup:
|
||||
if not self.hacs.system.status.startup:
|
||||
self.logger.error(error)
|
||||
return self.validate.success
|
||||
|
||||
@@ -67,44 +53,20 @@ class HacsTheme(HacsRepository):
|
||||
await self.common_registration()
|
||||
|
||||
# Set name
|
||||
if self.repository_manifest.filename is not None:
|
||||
self.information.file_name = self.repository_manifest.filename
|
||||
else:
|
||||
self.information.file_name = find_first_of_filetype(
|
||||
self.content.files, "yaml"
|
||||
).split("/")[-1]
|
||||
self.information.name = self.information.file_name.replace(".yaml", "")
|
||||
self.content.path.local = (
|
||||
f"{self.system.config_path}/themes/{self.information.name}"
|
||||
)
|
||||
find_file_name(self)
|
||||
self.content.path.local = f"{self.hacs.system.config_path}/themes/{self.data.file_name.replace('.yaml', '')}"
|
||||
|
||||
async def update_repository(self): # lgtm[py/similar-function]
|
||||
"""Update."""
|
||||
if self.github.ratelimits.remaining == 0:
|
||||
if self.hacs.github.ratelimits.remaining == 0:
|
||||
return
|
||||
# Run common update steps.
|
||||
await self.common_update()
|
||||
|
||||
# Get theme objects.
|
||||
if self.repository_manifest:
|
||||
if self.repository_manifest.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
self.content.objects = await self.repository_object.get_contents(
|
||||
self.content.path.remote, self.ref
|
||||
)
|
||||
|
||||
self.content.files = filter_content_return_one_of_type(
|
||||
self.treefiles, "themes", "yaml"
|
||||
)
|
||||
if self.data.content_in_root:
|
||||
self.content.path.remote = ""
|
||||
|
||||
# Update name
|
||||
if self.repository_manifest.filename is not None:
|
||||
self.information.file_name = self.repository_manifest.filename
|
||||
else:
|
||||
self.information.file_name = find_first_of_filetype(
|
||||
self.content.files, "yaml"
|
||||
).split("/")[-1]
|
||||
self.information.name = self.information.file_name.replace(".yaml", "")
|
||||
self.content.path.local = (
|
||||
f"{self.system.config_path}/themes/{self.information.name}"
|
||||
)
|
||||
find_file_name(self)
|
||||
self.content.path.local = f"{self.hacs.system.config_path}/themes/{self.data.file_name.replace('.yaml', '')}"
|
||||
|
Reference in New Issue
Block a user