mirror of
https://github.com/hacs/integration.git
synced 2025-08-16 17:12:38 +00:00
Formating
This commit is contained in:
@ -49,7 +49,7 @@ DOMAIN = "{}".format(NAME_SHORT.lower())
|
||||
# TODO: Remove this when minimum HA version is > 0.93
|
||||
REQUIREMENTS = ["aiofiles"]
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs")
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{DOMAIN: vol.Schema({vol.Required("token"): cv.string})}, extra=vol.ALLOW_EXTRA
|
||||
@ -65,7 +65,7 @@ async def async_setup(hass, config): # pylint: disable=unused-argument
|
||||
# Configure HACS
|
||||
await configure_hacs(hass, github_token, config_dir)
|
||||
|
||||
# Check if custom_updater exists
|
||||
# Check if custom_updater exists
|
||||
for location in CUSTOM_UPDATER_LOCATIONS:
|
||||
if os.path.exists(location.format(config_dir)):
|
||||
msg = CUSTOM_UPDATER_WARNING.format(location.format(config_dir))
|
||||
@ -73,12 +73,14 @@ async def async_setup(hass, config): # pylint: disable=unused-argument
|
||||
return False
|
||||
|
||||
# Check if HA is the required version.
|
||||
if parse_version(HAVERSION) < parse_version('0.92.0'):
|
||||
if parse_version(HAVERSION) < parse_version("0.92.0"):
|
||||
_LOGGER.critical("You need HA version 92 or newer to use this integration.")
|
||||
return False
|
||||
|
||||
# Add sensor
|
||||
hass.async_create_task(discovery.async_load_platform(hass, "sensor", DOMAIN, {}, config[DOMAIN]))
|
||||
hass.async_create_task(
|
||||
discovery.async_load_platform(hass, "sensor", DOMAIN, {}, config[DOMAIN])
|
||||
)
|
||||
|
||||
# Setup startup tasks
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, hacs().startup_tasks())
|
||||
@ -95,7 +97,7 @@ async def async_setup(hass, config): # pylint: disable=unused-argument
|
||||
|
||||
# Add to sidepanel
|
||||
# TODO: Remove this check when minimum HA version is > 0.94
|
||||
if parse_version(HAVERSION) < parse_version('0.93.9'):
|
||||
if parse_version(HAVERSION) < parse_version("0.93.9"):
|
||||
await hass.components.frontend.async_register_built_in_panel(
|
||||
"iframe",
|
||||
IFRAME["title"],
|
||||
@ -127,7 +129,9 @@ async def configure_hacs(hass, github_token, hass_config_dir):
|
||||
hacs.migration = HacsMigration()
|
||||
hacs.storage = HacsStorage()
|
||||
|
||||
hacs.aiogithub = AIOGitHub(github_token, hass.loop, async_create_clientsession(hass))
|
||||
hacs.aiogithub = AIOGitHub(
|
||||
github_token, hass.loop, async_create_clientsession(hass)
|
||||
)
|
||||
|
||||
hacs.hass = hass
|
||||
hacs.config_dir = hass_config_dir
|
||||
|
@ -9,12 +9,13 @@ from aiohttp import ClientError
|
||||
|
||||
import backoff
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.aiogithub')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.aiogithub")
|
||||
|
||||
|
||||
class AIOGitHubException(BaseException):
|
||||
"""Raise this when something is off."""
|
||||
|
||||
|
||||
class AIOGitHub(object):
|
||||
"""Base Github API implementation."""
|
||||
|
||||
@ -70,7 +71,9 @@ class AIOGitHub(object):
|
||||
repositories = []
|
||||
|
||||
for repository in response:
|
||||
repositories.append(AIOGithubRepository(repository, self.token, self.loop, self.session))
|
||||
repositories.append(
|
||||
AIOGithubRepository(repository, self.token, self.loop, self.session)
|
||||
)
|
||||
|
||||
return repositories
|
||||
|
||||
@ -103,7 +106,6 @@ class AIOGithubRepository(AIOGitHub):
|
||||
self.attributes = attributes
|
||||
self._last_commit = None
|
||||
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.attributes.get("id")
|
||||
@ -165,7 +167,9 @@ class AIOGithubRepository(AIOGitHub):
|
||||
@backoff.on_exception(backoff.expo, ClientError, max_tries=3)
|
||||
async def get_releases(self, latest=False):
|
||||
"""Retrun a list of repository release objects."""
|
||||
endpoint = "/repos/" + self.full_name + "/releases/" + "latest" if latest else ""
|
||||
endpoint = (
|
||||
"/repos/" + self.full_name + "/releases/" + "latest" if latest else ""
|
||||
)
|
||||
url = self.baseapi + endpoint
|
||||
|
||||
async with async_timeout.timeout(20, loop=self.loop):
|
||||
@ -198,7 +202,8 @@ class AIOGithubRepository(AIOGitHub):
|
||||
if response.get("message"):
|
||||
raise AIOGitHubException("No commits")
|
||||
|
||||
self._last_commit = response['sha'][0:7]
|
||||
self._last_commit = response["sha"][0:7]
|
||||
|
||||
|
||||
class AIOGithubRepositoryContent(AIOGitHub):
|
||||
"""Repository Conetent Github API implementation."""
|
||||
@ -225,15 +230,20 @@ class AIOGithubRepositoryContent(AIOGitHub):
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
return base64.b64decode(bytearray(self.attributes.get("content"), "utf-8")).decode()
|
||||
return base64.b64decode(
|
||||
bytearray(self.attributes.get("content"), "utf-8")
|
||||
).decode()
|
||||
|
||||
@property
|
||||
def download_url(self):
|
||||
return self.attributes.get("download_url") or self.attributes.get("browser_download_url")
|
||||
return self.attributes.get("download_url") or self.attributes.get(
|
||||
"browser_download_url"
|
||||
)
|
||||
|
||||
|
||||
class AIOGithubRepositoryRelease(AIOGitHub):
|
||||
"""Repository Release Github API implementation."""
|
||||
|
||||
def __init__(self, attributes):
|
||||
"""Initialize."""
|
||||
self.attributes = attributes
|
||||
@ -248,7 +258,9 @@ class AIOGithubRepositoryRelease(AIOGitHub):
|
||||
|
||||
@property
|
||||
def published_at(self):
|
||||
return datetime.strptime(self.attributes.get("published_at"), "%Y-%m-%dT%H:%M:%SZ")
|
||||
return datetime.strptime(
|
||||
self.attributes.get("published_at"), "%Y-%m-%dT%H:%M:%SZ"
|
||||
)
|
||||
|
||||
@property
|
||||
def draft(self):
|
||||
|
@ -73,9 +73,7 @@ ERROR = [
|
||||
################################
|
||||
|
||||
DEFAULT_REPOSITORIES = {
|
||||
"integration": [
|
||||
"StyraHem/ShellyForHASS"
|
||||
],
|
||||
"integration": ["StyraHem/ShellyForHASS"],
|
||||
"plugin": [
|
||||
"maykar/compact-custom-header",
|
||||
"maykar/lovelace-swipe-navigation",
|
||||
@ -87,5 +85,5 @@ DEFAULT_REPOSITORIES = {
|
||||
"finity69x2/fan-control-entity-row",
|
||||
"thomasloven/lovelace-card-mod",
|
||||
"thomasloven/lovelace-markdown-mod",
|
||||
]
|
||||
],
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
"""Custom Exceptions."""
|
||||
|
||||
|
||||
class HacsBaseException(Exception):
|
||||
"""Super basic."""
|
||||
|
||||
|
||||
class HacsUserScrewupException(HacsBaseException):
|
||||
"""Raise this when the user does something they should not do."""
|
||||
|
||||
@ -14,6 +16,7 @@ class HacsNotSoBasicException(HacsBaseException):
|
||||
class HacsDataFileMissing(HacsBaseException):
|
||||
"""Raise this storage datafile is missing."""
|
||||
|
||||
|
||||
class HacsDataNotExpected(HacsBaseException):
|
||||
"""Raise this when data returned from storage is not ok."""
|
||||
|
||||
@ -21,17 +24,22 @@ class HacsDataNotExpected(HacsBaseException):
|
||||
class HacsRepositoryInfo(HacsBaseException):
|
||||
"""Raise this when repository info is missing/wrong."""
|
||||
|
||||
|
||||
class HacsRequirement(HacsBaseException):
|
||||
"""Raise this when repository is missing a requirement."""
|
||||
|
||||
|
||||
class HacsMissingManifest(HacsBaseException):
|
||||
"""Raise this when manifest is missing."""
|
||||
|
||||
def __init__(self, message="The manifest file is missing in the repository."):
|
||||
super().__init__(message)
|
||||
self.message = message
|
||||
|
||||
|
||||
class HacsBlacklistException(HacsBaseException):
|
||||
"""Raise this when the repository is currently in the blacklist."""
|
||||
|
||||
def __init__(self, message="The repository is currently in the blacklist."):
|
||||
super().__init__(message)
|
||||
self.message = message
|
||||
|
@ -4,7 +4,7 @@ import logging
|
||||
from aiohttp import web
|
||||
from ...blueprints import HacsViewBase
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
|
||||
class HacsAPIView(HacsViewBase):
|
||||
@ -16,7 +16,9 @@ class HacsAPIView(HacsViewBase):
|
||||
"""Initilize."""
|
||||
self.url = self.url_path["api"] + r"/{element}/{action}"
|
||||
|
||||
async def get(self, request, element, action=None): # pylint: disable=unused-argument
|
||||
async def get(
|
||||
self, request, element, action=None
|
||||
): # pylint: disable=unused-argument
|
||||
"""Serve HacsAPIView."""
|
||||
_LOGGER.debug("GET API call for %s with %s", element, action)
|
||||
|
||||
@ -26,43 +28,47 @@ class HacsAPIView(HacsViewBase):
|
||||
await repository.install()
|
||||
await self.storage.set()
|
||||
if action == "172733314":
|
||||
raise web.HTTPFound(self.url_path['settings'])
|
||||
raise web.HTTPFound("{}/{}".format(self.url_path['repository'], repository.repository_id))
|
||||
raise web.HTTPFound(self.url_path["settings"])
|
||||
raise web.HTTPFound(
|
||||
"{}/{}".format(self.url_path["repository"], repository.repository_id)
|
||||
)
|
||||
|
||||
# Update a repository
|
||||
elif element == "repository_update_repository":
|
||||
repository = self.repositories[action]
|
||||
await repository.update()
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound("{}/{}".format(self.url_path['repository'], repository.repository_id))
|
||||
raise web.HTTPFound(
|
||||
"{}/{}".format(self.url_path["repository"], repository.repository_id)
|
||||
)
|
||||
|
||||
# Update a repository
|
||||
elif element == "repository_update_settings":
|
||||
repository = self.repositories[action]
|
||||
await repository.update()
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound(self.url_path['settings'])
|
||||
raise web.HTTPFound(self.url_path["settings"])
|
||||
|
||||
# Uninstall a element from the repository view
|
||||
elif element == "repository_uninstall":
|
||||
repository = self.repositories[action]
|
||||
await repository.uninstall()
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound(self.url_path['store'])
|
||||
raise web.HTTPFound(self.url_path["store"])
|
||||
|
||||
# Remove a custom repository from the settings view
|
||||
elif element == "repository_remove":
|
||||
repository = self.repositories[action]
|
||||
await repository.remove()
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound(self.url_path['settings'])
|
||||
raise web.HTTPFound(self.url_path["settings"])
|
||||
|
||||
# Hide a repository.
|
||||
elif element == "repository_hide":
|
||||
repository = self.repositories[action]
|
||||
repository.hide = True
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound(self.url_path['store'])
|
||||
raise web.HTTPFound(self.url_path["store"])
|
||||
|
||||
# Unhide a repository.
|
||||
elif element == "repository_unhide":
|
||||
@ -70,21 +76,17 @@ class HacsAPIView(HacsViewBase):
|
||||
repository.hide = False
|
||||
await repository.update()
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound(self.url_path['settings'])
|
||||
raise web.HTTPFound(self.url_path["settings"])
|
||||
|
||||
# Remove a custom repository from the settings view
|
||||
elif element == "repositories_reload":
|
||||
self.hass.async_create_task(self.update_repositories("Run it!"))
|
||||
raise web.HTTPFound(self.url_path['settings'])
|
||||
raise web.HTTPFound(self.url_path["settings"])
|
||||
|
||||
# Show content of hacs
|
||||
elif element == "hacs" and action == "inspect":
|
||||
jsons = {}
|
||||
skip = [
|
||||
"content_objects",
|
||||
"last_release_object",
|
||||
"repository",
|
||||
]
|
||||
skip = ["content_objects", "last_release_object", "repository"]
|
||||
for repository in self.repositories:
|
||||
repository = self.repositories[repository]
|
||||
jsons[repository.repository_id] = {}
|
||||
@ -97,13 +99,16 @@ class HacsAPIView(HacsViewBase):
|
||||
|
||||
elif element == "log" and action == "get":
|
||||
from ...handler.log import get_log_file_content
|
||||
|
||||
content = self.base_content
|
||||
content += await get_log_file_content(self.config_dir)
|
||||
return web.Response(body=content, content_type="text/html", charset="utf-8")
|
||||
|
||||
raise web.HTTPFound(self.url_path['error'])
|
||||
raise web.HTTPFound(self.url_path["error"])
|
||||
|
||||
async def post(self, request, element, action=None): # pylint: disable=unused-argument
|
||||
async def post(
|
||||
self, request, element, action=None
|
||||
): # pylint: disable=unused-argument
|
||||
"""Prosess POST API actions."""
|
||||
_LOGGER.debug("GET POST call for %s with %s", element, action)
|
||||
|
||||
@ -111,16 +116,20 @@ class HacsAPIView(HacsViewBase):
|
||||
|
||||
if element == "repository_register":
|
||||
repository_name = postdata["custom_url"]
|
||||
if 'repository_type' in postdata:
|
||||
if "repository_type" in postdata:
|
||||
repository_type = postdata["repository_type"]
|
||||
_LOGGER.debug("GET POST call for %s with %s", repository_name, repository_type)
|
||||
_LOGGER.debug(
|
||||
"GET POST call for %s with %s", repository_name, repository_type
|
||||
)
|
||||
|
||||
# Stip first part if it's an URL.
|
||||
if "https://github" in repository_name:
|
||||
repository_name = repository_name.split("https://github.com/")[-1]
|
||||
|
||||
if "https://www.github" in repository_name:
|
||||
repository_name = repository_name.split("https://www.github.com/")[-1]
|
||||
repository_name = repository_name.split("https://www.github.com/")[
|
||||
-1
|
||||
]
|
||||
|
||||
# Strip whitespace
|
||||
repository_name = repository_name.split()[0]
|
||||
@ -129,11 +138,21 @@ class HacsAPIView(HacsViewBase):
|
||||
if repository_name != "":
|
||||
if repository_name in self.blacklist:
|
||||
self.blacklist.remove(repository_name)
|
||||
repository, result = await self.register_new_repository(repository_type, repository_name)
|
||||
repository, result = await self.register_new_repository(
|
||||
repository_type, repository_name
|
||||
)
|
||||
if result:
|
||||
await self.storage.set()
|
||||
raise web.HTTPFound("{}/{}".format(self.url_path['repository'], repository.repository_id))
|
||||
raise web.HTTPFound(
|
||||
"{}/{}".format(
|
||||
self.url_path["repository"], repository.repository_id
|
||||
)
|
||||
)
|
||||
|
||||
message = "Could not add {} at this time, check the log for more details.".format(repository_name)
|
||||
message = "Could not add {} at this time, check the log for more details.".format(
|
||||
repository_name
|
||||
)
|
||||
|
||||
raise web.HTTPFound("{}?message={}".format(self.url_path['settings'], message))
|
||||
raise web.HTTPFound(
|
||||
"{}?message={}".format(self.url_path["settings"], message)
|
||||
)
|
||||
|
@ -10,7 +10,8 @@ from aiohttp import web
|
||||
from ...blueprints import HacsViewBase
|
||||
from ...const import ERROR, ISSUE_URL
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs..frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs..frontend")
|
||||
|
||||
|
||||
class HacsErrorView(HacsViewBase):
|
||||
"""Serve error."""
|
||||
@ -30,31 +31,34 @@ class HacsErrorView(HacsViewBase):
|
||||
stack_trace = list()
|
||||
|
||||
for trace in trace_back:
|
||||
stack_trace.append("File : {} , Line : {}, Func.Name : {}, Message : {}", format(
|
||||
trace[0], trace[1], trace[2], trace[3]
|
||||
))
|
||||
stack_trace.append(
|
||||
"File : {} , Line : {}, Func.Name : {}, Message : {}",
|
||||
format(trace[0], trace[1], trace[2], trace[3]),
|
||||
)
|
||||
|
||||
# HARD styling
|
||||
stacks = ""
|
||||
for stack in stack_trace:
|
||||
stacks += stack
|
||||
stacks = stacks.replace("File :", "</br>---------------------------------------------------------------</br><b>File :</b>")
|
||||
stacks = stacks.replace(
|
||||
"File :",
|
||||
"</br>---------------------------------------------------------------</br><b>File :</b>",
|
||||
)
|
||||
stacks = stacks.replace(", Line :", "</br><b>Line :</b>")
|
||||
stacks = stacks.replace(", Func.Name :", "</br><b>Func.Name :</b>")
|
||||
stacks = stacks.replace(", Message :", "</br><b>Message :</b>")[86:-1]
|
||||
|
||||
|
||||
|
||||
if ex_type is not None:
|
||||
codeblock = """
|
||||
<p><b>Exception type:</b> {}</p>
|
||||
<p><b>Exception message:</b> {}</p>
|
||||
<code class="codeblock errorview"">{}</code>
|
||||
""".format(ex_type.__name__, ex_value, stacks)
|
||||
""".format(
|
||||
ex_type.__name__, ex_value, stacks
|
||||
)
|
||||
else:
|
||||
codeblock = ""
|
||||
|
||||
|
||||
# Generate content
|
||||
content = self.base_content
|
||||
content += """
|
||||
@ -74,7 +78,9 @@ class HacsErrorView(HacsViewBase):
|
||||
<div class='center-align' style='margin-top: 100px'>
|
||||
<img src='https://i.pinimg.com/originals/ec/85/67/ec856744fac64a5a9e407733f190da5a.png'>
|
||||
</div>
|
||||
""".format(random.choice(ERROR), codeblock, ISSUE_URL, self.url_path["api"])
|
||||
""".format(
|
||||
random.choice(ERROR), codeblock, ISSUE_URL, self.url_path["api"]
|
||||
)
|
||||
|
||||
except Exception as exception:
|
||||
message = "GREAT!, even the error page is broken... ({})".format(exception)
|
||||
|
@ -5,7 +5,7 @@ from aiohttp import web
|
||||
from ...blueprints import HacsViewBase
|
||||
from ...const import NO_ELEMENTS
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
|
||||
class HacsOverviewView(HacsViewBase):
|
||||
@ -32,14 +32,22 @@ class HacsOverviewView(HacsViewBase):
|
||||
else:
|
||||
for repository in self.repositories_list_name:
|
||||
|
||||
if not repository.track or repository.hide or not repository.installed:
|
||||
if (
|
||||
not repository.track
|
||||
or repository.hide
|
||||
or not repository.installed
|
||||
):
|
||||
continue
|
||||
|
||||
if repository.pending_restart:
|
||||
card_icon = "<i class='fas fa-cube card-status pending-restart'></i>"
|
||||
card_icon = (
|
||||
"<i class='fas fa-cube card-status pending-restart'></i>"
|
||||
)
|
||||
|
||||
elif repository.pending_update:
|
||||
card_icon = "<i class='fas fa-cube card-status pending-update'></i>"
|
||||
card_icon = (
|
||||
"<i class='fas fa-cube card-status pending-update'></i>"
|
||||
)
|
||||
|
||||
elif repository.installed:
|
||||
card_icon = "<i class='fas fa-cube card-status installed'></i>"
|
||||
@ -58,7 +66,15 @@ class HacsOverviewView(HacsViewBase):
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
""".format(self.url_path["repository"], repository.repository_id, repository.topics, repository.authors, card_icon, repository.name, repository.description)
|
||||
""".format(
|
||||
self.url_path["repository"],
|
||||
repository.repository_id,
|
||||
repository.topics,
|
||||
repository.authors,
|
||||
card_icon,
|
||||
repository.name,
|
||||
repository.description,
|
||||
)
|
||||
|
||||
if repository.repository_type == "integration":
|
||||
integrations.append(card)
|
||||
@ -95,4 +111,4 @@ class HacsOverviewView(HacsViewBase):
|
||||
_LOGGER.error(exception)
|
||||
raise web.HTTPFound(self.url_path["error"])
|
||||
|
||||
return web.Response(body=content, content_type="text/html", charset="utf-8")
|
||||
return web.Response(body=content, content_type="text/html", charset="utf-8")
|
||||
|
@ -6,7 +6,7 @@ from aiohttp import web
|
||||
from aiohttp.web_exceptions import HTTPNotFound
|
||||
from ...blueprints import HacsViewBase
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
|
||||
class HacsPluginView(HacsViewBase):
|
||||
@ -25,8 +25,8 @@ class HacsPluginView(HacsViewBase):
|
||||
file = "{}/www/community/{}".format(self.config_dir, requested_file)
|
||||
|
||||
# Serve .gz if it exist
|
||||
if os.path.exists(file + '.gz'):
|
||||
file += '.gz'
|
||||
if os.path.exists(file + ".gz"):
|
||||
file += ".gz"
|
||||
|
||||
response = None
|
||||
if os.path.exists(file):
|
||||
@ -38,7 +38,9 @@ class HacsPluginView(HacsViewBase):
|
||||
raise HTTPNotFound()
|
||||
|
||||
except Exception as error: # pylint: disable=broad-except
|
||||
_LOGGER.debug("there was an issue trying to serve %s - %s", requested_file, error)
|
||||
_LOGGER.debug(
|
||||
"there was an issue trying to serve %s - %s", requested_file, error
|
||||
)
|
||||
raise HTTPNotFound()
|
||||
|
||||
return response
|
||||
|
@ -4,7 +4,7 @@ import logging
|
||||
from aiohttp import web
|
||||
from ...blueprints import HacsViewBase
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
LOVELACE_EXAMLE_URL = """
|
||||
<pre id="LovelaceExample" class="yaml">
|
||||
@ -23,6 +23,7 @@ LOVELACE_EXAMLE_URL_TYPE = """
|
||||
</pre>
|
||||
"""
|
||||
|
||||
|
||||
class HacsRepositoryView(HacsViewBase):
|
||||
"""Serve HacsRepositoryView."""
|
||||
|
||||
@ -53,11 +54,12 @@ class HacsRepositoryView(HacsViewBase):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
""".format(message)
|
||||
""".format(
|
||||
message
|
||||
)
|
||||
else:
|
||||
custom_message = ""
|
||||
|
||||
|
||||
if repository.pending_restart:
|
||||
pending_restart = """
|
||||
<div class='container''>
|
||||
@ -79,20 +81,14 @@ class HacsRepositoryView(HacsViewBase):
|
||||
|
||||
if repository.additional_info:
|
||||
if repository.info is None:
|
||||
info = "</br>" + await self.aiogithub.render_markdown(repository.additional_info)
|
||||
info = info.replace("<h3>", "<h6>").replace(
|
||||
"</h3>", "</h6>"
|
||||
)
|
||||
info = info.replace("<h2>", "<h5>").replace(
|
||||
"</h2>", "</h5>"
|
||||
)
|
||||
info = info.replace("<h1>", "<h4>").replace(
|
||||
"</h1>", "</h4>"
|
||||
info = "</br>" + await self.aiogithub.render_markdown(
|
||||
repository.additional_info
|
||||
)
|
||||
info = info.replace("<h3>", "<h6>").replace("</h3>", "</h6>")
|
||||
info = info.replace("<h2>", "<h5>").replace("</h2>", "</h5>")
|
||||
info = info.replace("<h1>", "<h4>").replace("</h1>", "</h4>")
|
||||
info = info.replace("<code>", "<code class='codeinfo'>")
|
||||
info = info.replace(
|
||||
"<table>", "<table class='white-text'>"
|
||||
)
|
||||
info = info.replace("<table>", "<table class='white-text'>")
|
||||
info = info.replace(
|
||||
'<a href="http', '<a target="_blank" href="http'
|
||||
)
|
||||
@ -104,13 +100,14 @@ class HacsRepositoryView(HacsViewBase):
|
||||
else:
|
||||
info = ""
|
||||
|
||||
|
||||
if repository.authors:
|
||||
authors = "<p>Author(s): "
|
||||
for author in repository.authors:
|
||||
if "@" in author:
|
||||
author = author.split("@")[-1]
|
||||
authors += "<a href='https://github.com/{author}' target='_blank' style='color: var(--primary-color) !important; margin: 2'> @{author}</a>".format(author=author)
|
||||
authors += "<a href='https://github.com/{author}' target='_blank' style='color: var(--primary-color) !important; margin: 2'> @{author}</a>".format(
|
||||
author=author
|
||||
)
|
||||
authors += "</p>"
|
||||
else:
|
||||
authors = ""
|
||||
@ -126,13 +123,21 @@ class HacsRepositoryView(HacsViewBase):
|
||||
To learn more about how to configure this,
|
||||
click the "REPOSITORY" link below to get to the repository for this integration.
|
||||
</i>
|
||||
""".format(repository.local_path)
|
||||
""".format(
|
||||
repository.local_path
|
||||
)
|
||||
else:
|
||||
if repository.javascript_type is None:
|
||||
llnote = LOVELACE_EXAMLE_URL.format(repository.name, repository.name.replace("lovelace-", ""))
|
||||
llnote = LOVELACE_EXAMLE_URL.format(
|
||||
repository.name, repository.name.replace("lovelace-", "")
|
||||
)
|
||||
jsnote = MISSING_JS_TYPE
|
||||
else:
|
||||
llnote = LOVELACE_EXAMLE_URL_TYPE.format(repository.name, repository.name.replace("lovelace-", ""), repository.javascript_type)
|
||||
llnote = LOVELACE_EXAMLE_URL_TYPE.format(
|
||||
repository.name,
|
||||
repository.name.replace("lovelace-", ""),
|
||||
repository.javascript_type,
|
||||
)
|
||||
jsnote = ""
|
||||
note = """
|
||||
</br><i>
|
||||
@ -150,7 +155,9 @@ class HacsRepositoryView(HacsViewBase):
|
||||
To learn more about how to configure this,
|
||||
click the "REPOSITORY" link below button to get to the repository for this plugin.
|
||||
</i>
|
||||
""".format(repository.local_path, llnote, jsnote)
|
||||
""".format(
|
||||
repository.local_path, llnote, jsnote
|
||||
)
|
||||
|
||||
if not repository.installed:
|
||||
main_action = "INSTALL"
|
||||
@ -167,7 +174,9 @@ class HacsRepositoryView(HacsViewBase):
|
||||
name = repository.name.split("lovelace-")[-1]
|
||||
else:
|
||||
name = repository.name
|
||||
open_plugin = "<a href='/community_plugin/{}/{}.js' target='_blank' style='color: var(--primary-color) !important'>OPEN PLUGIN</a>".format(repository.name, name)
|
||||
open_plugin = "<a href='/community_plugin/{}/{}.js' target='_blank' style='color: var(--primary-color) !important'>OPEN PLUGIN</a>".format(
|
||||
repository.name, name
|
||||
)
|
||||
else:
|
||||
open_plugin = ""
|
||||
|
||||
@ -178,37 +187,52 @@ class HacsRepositoryView(HacsViewBase):
|
||||
if repository.hide:
|
||||
hide_option = """
|
||||
<li><a class="dropdown-list-item" href="{}/repository_unhide/{}" onclick="ShowProgressBar()">Unhide</a></li>
|
||||
""".format(self.url_path["api"], repository.repository_id)
|
||||
""".format(
|
||||
self.url_path["api"], repository.repository_id
|
||||
)
|
||||
else:
|
||||
hide_option = """
|
||||
<li><a class="dropdown-list-item" href="{}/repository_hide/{}" onclick="ShowProgressBar()">Hide</a></li>
|
||||
""".format(self.url_path["api"], repository.repository_id)
|
||||
|
||||
""".format(
|
||||
self.url_path["api"], repository.repository_id
|
||||
)
|
||||
|
||||
content = self.base_content
|
||||
|
||||
if repository.version_installed is not None:
|
||||
inst_ver = "<p><b>Installed version:</b> {}</p>".format(repository.version_installed)
|
||||
inst_ver = "<p><b>Installed version:</b> {}</p>".format(
|
||||
repository.version_installed
|
||||
)
|
||||
else:
|
||||
if repository.installed_commit is not None:
|
||||
inst_ver = "<p><b>Installed commit:</b> {}</p>".format(repository.installed_commit)
|
||||
inst_ver = "<p><b>Installed commit:</b> {}</p>".format(
|
||||
repository.installed_commit
|
||||
)
|
||||
else:
|
||||
inst_ver = ""
|
||||
|
||||
if repository.last_release_tag is not None:
|
||||
last_ver = "<p><b>Available version:</b> {}</p>".format(repository.last_release_tag)
|
||||
last_ver = "<p><b>Available version:</b> {}</p>".format(
|
||||
repository.last_release_tag
|
||||
)
|
||||
else:
|
||||
last_ver = "<p><b>Available commit:</b> {}</p>".format(repository.last_commit)
|
||||
last_ver = "<p><b>Available commit:</b> {}</p>".format(
|
||||
repository.last_commit
|
||||
)
|
||||
|
||||
last_up = ""
|
||||
|
||||
if repository.pending_update and repository.version_installed is not None:
|
||||
changelog = "<a href='https://github.com/{}/releases' target='_blank' style='color: var(--primary-color) !important'>CHANGELOG</a>".format(repository.repository_name)
|
||||
changelog = "<a href='https://github.com/{}/releases' target='_blank' style='color: var(--primary-color) !important'>CHANGELOG</a>".format(
|
||||
repository.repository_name
|
||||
)
|
||||
else:
|
||||
changelog = ""
|
||||
|
||||
if repository.installed:
|
||||
uninstall = "<a href='{}/repository_uninstall/{}' style='float: right; color: var(--google-red-500) !important; font-weight: bold;' onclick='ShowProgressBar()'>UNINSTALL</a>".format(self.url_path['api'], repository.repository_id)
|
||||
uninstall = "<a href='{}/repository_uninstall/{}' style='float: right; color: var(--google-red-500) !important; font-weight: bold;' onclick='ShowProgressBar()'>UNINSTALL</a>".format(
|
||||
self.url_path["api"], repository.repository_id
|
||||
)
|
||||
else:
|
||||
uninstall = ""
|
||||
|
||||
@ -258,9 +282,30 @@ class HacsRepositoryView(HacsViewBase):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
""".format(custom_message, pending_restart, repository.name, self.url_path["api"], repository.repository_id, hide_option, repository.repository_name,
|
||||
repository.name, repository.description, inst_ver, last_ver, last_up, info, authors, note, self.url_path["api"],
|
||||
repository.repository_id, main_action, changelog, repository.repository_name, open_plugin, uninstall)
|
||||
""".format(
|
||||
custom_message,
|
||||
pending_restart,
|
||||
repository.name,
|
||||
self.url_path["api"],
|
||||
repository.repository_id,
|
||||
hide_option,
|
||||
repository.repository_name,
|
||||
repository.name,
|
||||
repository.description,
|
||||
inst_ver,
|
||||
last_ver,
|
||||
last_up,
|
||||
info,
|
||||
authors,
|
||||
note,
|
||||
self.url_path["api"],
|
||||
repository.repository_id,
|
||||
main_action,
|
||||
changelog,
|
||||
repository.repository_name,
|
||||
open_plugin,
|
||||
uninstall,
|
||||
)
|
||||
|
||||
except Exception as exception:
|
||||
_LOGGER.error(exception)
|
||||
|
@ -7,7 +7,7 @@ from homeassistant.const import __version__ as HAVERSION
|
||||
from ...blueprints import HacsViewBase
|
||||
from ...const import ISSUE_URL, NAME_LONG
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
|
||||
class HacsSettingsView(HacsViewBase):
|
||||
@ -74,7 +74,12 @@ class HacsSettingsView(HacsViewBase):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
""".format(hacs.version_installed, hacs.last_release_tag, self.url_path["api"], hacs.last_release_tag)
|
||||
""".format(
|
||||
hacs.version_installed,
|
||||
hacs.last_release_tag,
|
||||
self.url_path["api"],
|
||||
hacs.last_release_tag,
|
||||
)
|
||||
else:
|
||||
hacs_update = ""
|
||||
|
||||
@ -93,11 +98,12 @@ class HacsSettingsView(HacsViewBase):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
""".format(message)
|
||||
""".format(
|
||||
message
|
||||
)
|
||||
else:
|
||||
custom_message = ""
|
||||
|
||||
|
||||
# Repos:
|
||||
for repository in self.repositories_list_repo:
|
||||
if repository.hide and repository.repository_id != "172733314":
|
||||
@ -107,7 +113,12 @@ class HacsSettingsView(HacsViewBase):
|
||||
<i title="Unhide" class="fas fa-plus-circle" style="padding-right: 8px"></i></a>
|
||||
{}
|
||||
<span class="repository-list-badge">{}</span>
|
||||
""".format(self.url_path["api"], repository.repository_id, repository.repository_name, repository.repository_type)
|
||||
""".format(
|
||||
self.url_path["api"],
|
||||
repository.repository_id,
|
||||
repository.repository_name,
|
||||
repository.repository_type,
|
||||
)
|
||||
line += "</div></li>"
|
||||
hidden.append(line)
|
||||
|
||||
@ -117,22 +128,30 @@ class HacsSettingsView(HacsViewBase):
|
||||
line = '<li class="collection-item hacscolor hacslist"><div>'
|
||||
line += """
|
||||
<a href="{}/{}"><span class="repository-list-badge">{}</span> {}</a>
|
||||
""".format(self.url_path["repository"], repository.repository_id, repository.repository_type, repository.repository_name)
|
||||
""".format(
|
||||
self.url_path["repository"],
|
||||
repository.repository_id,
|
||||
repository.repository_type,
|
||||
repository.repository_name,
|
||||
)
|
||||
|
||||
if repository.installed:
|
||||
remove = """
|
||||
<i title="Remove is not possible when {} is installed." class="secondary-content fas fa-trash-alt disabledaction"></i>
|
||||
""".format(repository.repository_type)
|
||||
""".format(
|
||||
repository.repository_type
|
||||
)
|
||||
else:
|
||||
remove = """
|
||||
<a href={}/repository_remove/{} onclick="ShowProgressBar()" class="secondary-content" style="color: var(--primary-color)">
|
||||
<i title="Remove." class="fas fa-trash-alt"></i>
|
||||
</a>
|
||||
""".format(self.url_path["api"], repository.repository_id)
|
||||
""".format(
|
||||
self.url_path["api"], repository.repository_id
|
||||
)
|
||||
line += remove
|
||||
line += "</div></li>"
|
||||
|
||||
|
||||
repository_lines.append(line)
|
||||
|
||||
# Generate content to display
|
||||
@ -143,7 +162,9 @@ class HacsSettingsView(HacsViewBase):
|
||||
{}
|
||||
{}
|
||||
</div>
|
||||
""".format(hacs_restart, hacs_update, custom_message)
|
||||
""".format(
|
||||
hacs_restart, hacs_update, custom_message
|
||||
)
|
||||
|
||||
# HACS card
|
||||
content += """
|
||||
@ -155,7 +176,12 @@ class HacsSettingsView(HacsViewBase):
|
||||
<b>Home Assistant version:</b> {}</br>
|
||||
</div>
|
||||
</div>
|
||||
""".format(NAME_LONG, hacs.version_installed, " <b>(RESTART PENDING!)</b>" if hacs.pending_restart else "", HAVERSION)
|
||||
""".format(
|
||||
NAME_LONG,
|
||||
hacs.version_installed,
|
||||
" <b>(RESTART PENDING!)</b>" if hacs.pending_restart else "",
|
||||
HAVERSION,
|
||||
)
|
||||
|
||||
# The buttons, must have buttons
|
||||
content += """
|
||||
@ -173,7 +199,9 @@ class HacsSettingsView(HacsViewBase):
|
||||
OPEN LOG
|
||||
</a>
|
||||
</div>
|
||||
""".format(self.url_path["api"], ISSUE_URL, self.url_path["api"])
|
||||
""".format(
|
||||
self.url_path["api"], ISSUE_URL, self.url_path["api"]
|
||||
)
|
||||
|
||||
## Integration URL's
|
||||
content += """
|
||||
@ -205,7 +233,9 @@ class HacsSettingsView(HacsViewBase):
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
""".format(self.url_path["api"])
|
||||
""".format(
|
||||
self.url_path["api"]
|
||||
)
|
||||
|
||||
## Hidden repositories
|
||||
if hidden:
|
||||
|
@ -6,7 +6,7 @@ from aiohttp import web
|
||||
from aiohttp.web import HTTPNotFound
|
||||
from ...blueprints import HacsViewBase
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
|
||||
class HacsStaticView(HacsViewBase):
|
||||
@ -21,10 +21,11 @@ class HacsStaticView(HacsViewBase):
|
||||
async def get(self, request, requested_file): # pylint: disable=unused-argument
|
||||
"""Serve static files."""
|
||||
servefile = "{}/custom_components/hacs/frontend/elements/{}".format(
|
||||
self.config_dir, requested_file)
|
||||
self.config_dir, requested_file
|
||||
)
|
||||
|
||||
if os.path.exists(servefile + '.gz'):
|
||||
return web.FileResponse(servefile + '.gz')
|
||||
if os.path.exists(servefile + ".gz"):
|
||||
return web.FileResponse(servefile + ".gz")
|
||||
else:
|
||||
if os.path.exists(servefile):
|
||||
return web.FileResponse(servefile)
|
||||
|
@ -4,7 +4,7 @@ import logging
|
||||
from aiohttp import web
|
||||
from ...blueprints import HacsViewBase
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.frontend')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.frontend")
|
||||
|
||||
|
||||
class HacsStoreView(HacsViewBase):
|
||||
@ -41,10 +41,14 @@ class HacsStoreView(HacsViewBase):
|
||||
continue
|
||||
|
||||
if repository.pending_restart:
|
||||
card_icon = "<i class='fas fa-cube card-status pending-restart'></i>"
|
||||
card_icon = (
|
||||
"<i class='fas fa-cube card-status pending-restart'></i>"
|
||||
)
|
||||
|
||||
elif repository.pending_update:
|
||||
card_icon = "<i class='fas fa-cube card-status pending-update'></i>"
|
||||
card_icon = (
|
||||
"<i class='fas fa-cube card-status pending-update'></i>"
|
||||
)
|
||||
|
||||
elif repository.installed:
|
||||
card_icon = "<i class='fas fa-cube card-status installed'></i>"
|
||||
@ -63,7 +67,15 @@ class HacsStoreView(HacsViewBase):
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
""".format(self.url_path["repository"], repository.repository_id, repository.topics, repository.authors, card_icon, repository.name, repository.description)
|
||||
""".format(
|
||||
self.url_path["repository"],
|
||||
repository.repository_id,
|
||||
repository.topics,
|
||||
repository.authors,
|
||||
card_icon,
|
||||
repository.name,
|
||||
repository.description,
|
||||
)
|
||||
|
||||
if repository.repository_type == "integration":
|
||||
integrations.append(card)
|
||||
|
@ -8,11 +8,12 @@ from homeassistant.helpers.event import async_track_time_interval
|
||||
from .aiogithub import AIOGitHubException
|
||||
from .const import DEFAULT_REPOSITORIES
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.hacs')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.hacs")
|
||||
|
||||
|
||||
class HacsBase:
|
||||
"""The base class of HACS, nested thoughout the project."""
|
||||
|
||||
const = None
|
||||
migration = None
|
||||
storage = None
|
||||
@ -26,12 +27,23 @@ class HacsBase:
|
||||
repositories = {}
|
||||
|
||||
url_path = {}
|
||||
for endpoint in ["api", "error", "overview", "static", "store", "settings", "repository"]:
|
||||
url_path[endpoint] = "/community_{}-{}".format(str(uuid.uuid4()), str(uuid.uuid4()))
|
||||
for endpoint in [
|
||||
"api",
|
||||
"error",
|
||||
"overview",
|
||||
"static",
|
||||
"store",
|
||||
"settings",
|
||||
"repository",
|
||||
]:
|
||||
url_path[endpoint] = "/community_{}-{}".format(
|
||||
str(uuid.uuid4()), str(uuid.uuid4())
|
||||
)
|
||||
|
||||
async def startup_tasks(self):
|
||||
"""Run startup_tasks."""
|
||||
from .hacsrepositoryintegration import HacsRepositoryIntegration
|
||||
|
||||
self.data["task_running"] = True
|
||||
|
||||
_LOGGER.info("Runing startup tasks.")
|
||||
@ -40,10 +52,14 @@ class HacsBase:
|
||||
self.data["hacs"]["endpoints"] = self.url_path
|
||||
|
||||
# For installed repositories only.
|
||||
async_track_time_interval(self.hass, self.recuring_tasks_installed, timedelta(minutes=30))
|
||||
async_track_time_interval(
|
||||
self.hass, self.recuring_tasks_installed, timedelta(minutes=30)
|
||||
)
|
||||
|
||||
# For the rest.
|
||||
async_track_time_interval(self.hass, self.update_repositories, timedelta(minutes=500))
|
||||
async_track_time_interval(
|
||||
self.hass, self.update_repositories, timedelta(minutes=500)
|
||||
)
|
||||
|
||||
# Check for updates to HACS.
|
||||
repository = await self.aiogithub.get_repo("custom-components/hacs")
|
||||
@ -109,12 +125,17 @@ class HacsBase:
|
||||
for repository in self.repositories:
|
||||
try:
|
||||
repository = self.repositories[repository]
|
||||
if not repository.track or repository.repository_name in self.blacklist:
|
||||
if (
|
||||
not repository.track
|
||||
or repository.repository_name in self.blacklist
|
||||
):
|
||||
continue
|
||||
if repository.hide and repository.repository_id != "172733314":
|
||||
continue
|
||||
if now is not None:
|
||||
_LOGGER.info("Running update for %s", repository.repository_name)
|
||||
_LOGGER.info(
|
||||
"Running update for %s", repository.repository_name
|
||||
)
|
||||
await repository.update()
|
||||
except AIOGitHubException as exception:
|
||||
_LOGGER.error("%s - %s", repository.repository_name, exception)
|
||||
@ -135,18 +156,22 @@ class HacsBase:
|
||||
await repository.update()
|
||||
else:
|
||||
try:
|
||||
await self.register_new_repository(repository_type, repository.full_name, repository)
|
||||
await self.register_new_repository(
|
||||
repository_type, repository.full_name, repository
|
||||
)
|
||||
except AIOGitHubException as exception:
|
||||
_LOGGER.error("%s - %s", repository.full_name, exception)
|
||||
await self.storage.set()
|
||||
self.data["task_running"] = False
|
||||
await self.storage.set()
|
||||
|
||||
async def get_repositories(self):
|
||||
"""Get defined repositories."""
|
||||
repositories = {}
|
||||
|
||||
# Get org repositories
|
||||
repositories["integration"] = await self.aiogithub.get_org_repos("custom-components")
|
||||
repositories["integration"] = await self.aiogithub.get_org_repos(
|
||||
"custom-components"
|
||||
)
|
||||
repositories["plugin"] = await self.aiogithub.get_org_repos("custom-cards")
|
||||
|
||||
# Additional repositories (Not implemented)
|
||||
@ -157,7 +182,9 @@ class HacsBase:
|
||||
|
||||
return repositories["integration"], repositories["plugin"]
|
||||
|
||||
async def recuring_tasks_installed(self, notarealarg): # pylint: disable=unused-argument
|
||||
async def recuring_tasks_installed(
|
||||
self, notarealarg
|
||||
): # pylint: disable=unused-argument
|
||||
"""Recuring tasks for installed repositories."""
|
||||
self.data["task_running"] = True
|
||||
_LOGGER.info("Running scheduled update of installed repositories")
|
||||
|
@ -5,7 +5,7 @@ from shutil import copy2
|
||||
from .hacsbase import HacsBase
|
||||
from .const import STORAGE_VERSION
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.migration')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.migration")
|
||||
|
||||
|
||||
class HacsMigration(HacsBase):
|
||||
@ -51,7 +51,9 @@ class HacsMigration(HacsBase):
|
||||
if repodata.get("isinstalled"):
|
||||
# Register new repository
|
||||
_LOGGER.info("Migrating %s", repodata["repo"])
|
||||
repository, setup_result = await self.register_new_repository(repodata["element_type"], repodata["repo"])
|
||||
repository, setup_result = await self.register_new_repository(
|
||||
repodata["element_type"], repodata["repo"]
|
||||
)
|
||||
|
||||
repository.version_installed = repodata["installed_version"]
|
||||
repository.installed = True
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""Blueprint for HacsRepositoryBase."""
|
||||
# pylint: disable=too-many-instance-attributes,invalid-name,broad-except,wildcard-import
|
||||
# pylint: disable=too-many-instance-attributes,invalid-name,broad-except,wildcard-import,no-member
|
||||
from asyncio import sleep
|
||||
from datetime import datetime
|
||||
import logging
|
||||
@ -9,11 +9,16 @@ import shutil
|
||||
|
||||
from .aiogithub import AIOGitHubException
|
||||
from .hacsbase import HacsBase
|
||||
from .exceptions import HacsRepositoryInfo, HacsUserScrewupException, HacsBaseException, HacsBlacklistException
|
||||
from .exceptions import (
|
||||
HacsRepositoryInfo,
|
||||
HacsUserScrewupException,
|
||||
HacsBaseException,
|
||||
HacsBlacklistException,
|
||||
)
|
||||
from .handler.download import async_download_file, async_save_file
|
||||
from .const import DEFAULT_REPOSITORIES, VERSION
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.repository')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.repository")
|
||||
|
||||
|
||||
class HacsRepositoryBase(HacsBase):
|
||||
@ -70,10 +75,12 @@ class HacsRepositoryBase(HacsBase):
|
||||
"""Return local path."""
|
||||
local_path = None
|
||||
if self.repository_type == "integration":
|
||||
if self.domain is None: # pylint: disable=no-member
|
||||
if self.domain is None:
|
||||
local_path = None
|
||||
else:
|
||||
local_path = "{}/custom_components/{}".format(self.config_dir, self.domain) # pylint: disable=no-member
|
||||
local_path = "{}/custom_components/{}".format(
|
||||
self.config_dir, self.domain
|
||||
)
|
||||
|
||||
elif self.repository_type == "plugin":
|
||||
local_path = "{}/www/community/{}".format(self.config_dir, self.name)
|
||||
@ -87,7 +94,9 @@ class HacsRepositoryBase(HacsBase):
|
||||
@property
|
||||
def description(self):
|
||||
"""Description."""
|
||||
return "" if self.repository.description is None else self.repository.description
|
||||
return (
|
||||
"" if self.repository.description is None else self.repository.description
|
||||
)
|
||||
|
||||
@property
|
||||
def ref(self):
|
||||
@ -156,35 +165,53 @@ class HacsRepositoryBase(HacsBase):
|
||||
except AIOGitHubException:
|
||||
pass
|
||||
|
||||
async def download_repository_directory_content(self, repository_directory_path, local_directory, ref):
|
||||
async def download_repository_directory_content(
|
||||
self, repository_directory_path, local_directory, ref
|
||||
):
|
||||
"""Download the content of a directory."""
|
||||
try:
|
||||
# Get content
|
||||
if self.content_path == "release":
|
||||
contents = self.content_objects
|
||||
else:
|
||||
contents = await self.repository.get_contents(repository_directory_path, ref)
|
||||
contents = await self.repository.get_contents(
|
||||
repository_directory_path, ref
|
||||
)
|
||||
|
||||
for content_object in contents:
|
||||
if content_object.type == "dir":
|
||||
await self.download_repository_directory_content(content_object.path, local_directory, ref)
|
||||
await self.download_repository_directory_content(
|
||||
content_object.path, local_directory, ref
|
||||
)
|
||||
continue
|
||||
if self.repository_type == "plugin" and not content_object.name.endswith(".js"):
|
||||
if (
|
||||
self.repository_type == "plugin"
|
||||
and not content_object.name.endswith(".js")
|
||||
):
|
||||
# For plugins we currently only need .js files
|
||||
continue
|
||||
|
||||
_LOGGER.debug("Downloading %s", content_object.name)
|
||||
|
||||
filecontent = await async_download_file(self.hass, content_object.download_url)
|
||||
filecontent = await async_download_file(
|
||||
self.hass, content_object.download_url
|
||||
)
|
||||
|
||||
if filecontent is None:
|
||||
_LOGGER.debug("There was an error downloading the file %s", content_object.name)
|
||||
_LOGGER.debug(
|
||||
"There was an error downloading the file %s",
|
||||
content_object.name,
|
||||
)
|
||||
continue
|
||||
|
||||
# Save the content of the file.
|
||||
if self.repository_name == "custom-components/hacs":
|
||||
local_directory = "{}/{}".format(self.config_dir, content_object.path)
|
||||
local_directory = local_directory.split("/{}".format(content_object.name))[0]
|
||||
local_directory = "{}/{}".format(
|
||||
self.config_dir, content_object.path
|
||||
)
|
||||
local_directory = local_directory.split(
|
||||
"/{}".format(content_object.name)
|
||||
)[0]
|
||||
_LOGGER.debug(content_object.path)
|
||||
_LOGGER.debug(local_directory)
|
||||
|
||||
@ -200,7 +227,7 @@ class HacsRepositoryBase(HacsBase):
|
||||
async def install(self):
|
||||
"""Run install tasks."""
|
||||
start_time = datetime.now()
|
||||
_LOGGER.info('(%s) - Starting installation', self.repository_name)
|
||||
_LOGGER.info("(%s) - Starting installation", self.repository_name)
|
||||
try:
|
||||
# Run update
|
||||
await self.update() # pylint: disable=no-member
|
||||
@ -209,7 +236,9 @@ class HacsRepositoryBase(HacsBase):
|
||||
await self.check_local_directory()
|
||||
|
||||
# Download files
|
||||
await self.download_repository_directory_content(self.content_path, self.local_path, self.ref)
|
||||
await self.download_repository_directory_content(
|
||||
self.content_path, self.local_path, self.ref
|
||||
)
|
||||
|
||||
except HacsBaseException as exception:
|
||||
_LOGGER.debug("(%s) - %s", self.repository_name, exception)
|
||||
@ -221,8 +250,11 @@ class HacsRepositoryBase(HacsBase):
|
||||
self.installed_commit = self.last_commit
|
||||
if self.repository_type == "integration":
|
||||
self.pending_restart = True
|
||||
_LOGGER.info('(%s) - installation completed in %s seconds', self.repository_name, (datetime.now() - start_time).seconds)
|
||||
|
||||
_LOGGER.info(
|
||||
"(%s) - installation completed in %s seconds",
|
||||
self.repository_name,
|
||||
(datetime.now() - start_time).seconds,
|
||||
)
|
||||
|
||||
async def remove(self):
|
||||
"""Run remove tasks."""
|
||||
@ -260,21 +292,33 @@ class HacsRepositoryBase(HacsBase):
|
||||
pathlib.Path(local_path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
except Exception as exception:
|
||||
_LOGGER.debug("(%s) - Creating directory %s failed with %s", self.repository_name, local_path, exception)
|
||||
_LOGGER.debug(
|
||||
"(%s) - Creating directory %s failed with %s",
|
||||
self.repository_name,
|
||||
local_path,
|
||||
exception,
|
||||
)
|
||||
return
|
||||
|
||||
async def remove_local_directory(self):
|
||||
"""Check the local directory."""
|
||||
try:
|
||||
if os.path.exists(self.local_path):
|
||||
_LOGGER.debug("(%s) - Removing %s", self.repository_name, self.local_path)
|
||||
_LOGGER.debug(
|
||||
"(%s) - Removing %s", self.repository_name, self.local_path
|
||||
)
|
||||
shutil.rmtree(self.local_path)
|
||||
|
||||
while os.path.exists(self.local_path):
|
||||
await sleep(1)
|
||||
|
||||
except Exception as exception:
|
||||
_LOGGER.debug("(%s) - Removing directory %s failed with %s", self.repository_name, self.local_path, exception)
|
||||
_LOGGER.debug(
|
||||
"(%s) - Removing directory %s failed with %s",
|
||||
self.repository_name,
|
||||
self.local_path,
|
||||
exception,
|
||||
)
|
||||
return
|
||||
|
||||
async def set_additional_info(self):
|
||||
@ -293,12 +337,10 @@ class HacsRepositoryBase(HacsBase):
|
||||
# We kinda expect this one to fail
|
||||
self.additional_info = ""
|
||||
|
||||
|
||||
async def set_repository(self):
|
||||
"""Set the AIOGitHub repository object."""
|
||||
self.repository = await self.aiogithub.get_repo(self.repository_name)
|
||||
|
||||
|
||||
async def set_repository_releases(self):
|
||||
"""Set attributes for releases."""
|
||||
if self.repository is None:
|
||||
@ -313,19 +355,19 @@ class HacsRepositoryBase(HacsBase):
|
||||
self.last_release_object = temp
|
||||
self.last_release_tag = temp.tag_name
|
||||
|
||||
|
||||
|
||||
async def validate_repository_name(self):
|
||||
"""Validate the given repository_name."""
|
||||
if "/" not in self.repository_name:
|
||||
raise HacsUserScrewupException(
|
||||
"GitHub repository name "
|
||||
"'{}' is not the correct format".format(self.repository_name))
|
||||
"'{}' is not the correct format".format(self.repository_name)
|
||||
)
|
||||
|
||||
elif len(self.repository_name.split('/')) > 2:
|
||||
elif len(self.repository_name.split("/")) > 2:
|
||||
raise HacsUserScrewupException(
|
||||
"GitHub repository name "
|
||||
"'{}' is not the correct format".format(self.repository_name))
|
||||
"'{}' is not the correct format".format(self.repository_name)
|
||||
)
|
||||
|
||||
async def return_last_update(self):
|
||||
"""Return a last update string."""
|
||||
|
@ -6,7 +6,7 @@ from .aiogithub import AIOGitHubException
|
||||
from .blueprints import HacsRepositoryBase
|
||||
from .exceptions import HacsRequirement
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.repository')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.repository")
|
||||
|
||||
|
||||
class HacsRepositoryPlugin(HacsRepositoryBase):
|
||||
@ -60,7 +60,6 @@ class HacsRepositoryPlugin(HacsRepositoryBase):
|
||||
pass
|
||||
await self.set_repository_content()
|
||||
|
||||
|
||||
async def set_repository_content(self):
|
||||
"""Set repository content attributes."""
|
||||
if self.content_path is None or self.content_path == "":
|
||||
|
@ -6,7 +6,7 @@ import json
|
||||
from .blueprints import HacsRepositoryBase
|
||||
from .exceptions import HacsRequirement
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.repository')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.repository")
|
||||
|
||||
|
||||
class HacsRepositoryIntegration(HacsRepositoryBase):
|
||||
@ -43,7 +43,8 @@ class HacsRepositoryIntegration(HacsRepositoryBase):
|
||||
self.content_path = first[0].path
|
||||
|
||||
self.content_objects = await self.repository.get_contents(
|
||||
self.content_path, self.ref)
|
||||
self.content_path, self.ref
|
||||
)
|
||||
|
||||
if not isinstance(self.content_objects, list):
|
||||
raise HacsRequirement("Repository structure does not meet the requirements")
|
||||
|
@ -8,7 +8,7 @@ from .hacsbase import HacsBase
|
||||
from .exceptions import HacsNotSoBasicException, HacsRequirement
|
||||
from .const import STORENAME, GENERIC_ERROR, STORAGE_VERSION
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.storage')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.storage")
|
||||
|
||||
|
||||
class HacsStorage(HacsBase):
|
||||
@ -16,16 +16,16 @@ class HacsStorage(HacsBase):
|
||||
|
||||
async def get(self):
|
||||
"""Read HACS data to storage."""
|
||||
from .blueprints import (
|
||||
HacsRepositoryIntegration,
|
||||
HacsRepositoryPlugin,)
|
||||
from .blueprints import HacsRepositoryIntegration, HacsRepositoryPlugin
|
||||
|
||||
datastore = "{}/.storage/{}".format(self.config_dir, STORENAME)
|
||||
_LOGGER.debug("Reading from datastore %s.", datastore)
|
||||
|
||||
self.data["task_running"] = True
|
||||
try:
|
||||
async with aiofiles.open(
|
||||
datastore, mode='r', encoding="utf-8", errors="ignore") as datafile:
|
||||
datastore, mode="r", encoding="utf-8", errors="ignore"
|
||||
) as datafile:
|
||||
store_data = await datafile.read()
|
||||
store_data = json.loads(store_data)
|
||||
datafile.close()
|
||||
@ -45,7 +45,9 @@ class HacsStorage(HacsBase):
|
||||
repository = store_data["repositories"][repository]
|
||||
if not repository.get("custom"):
|
||||
continue
|
||||
repository, status = await self.register_new_repository(repository["repository_type"], repository["repository_name"])
|
||||
repository, status = await self.register_new_repository(
|
||||
repository["repository_type"], repository["repository_name"]
|
||||
)
|
||||
if status:
|
||||
await self.restore(store_data, repository)
|
||||
|
||||
@ -65,9 +67,13 @@ class HacsStorage(HacsBase):
|
||||
else:
|
||||
_LOGGER.info("Loading %s", repository.full_name)
|
||||
if repository_type == "integration":
|
||||
repository = HacsRepositoryIntegration(repository.full_name, repository)
|
||||
repository = HacsRepositoryIntegration(
|
||||
repository.full_name, repository
|
||||
)
|
||||
elif repository_type == "plugin":
|
||||
repository = HacsRepositoryPlugin(repository.full_name, repository)
|
||||
repository = HacsRepositoryPlugin(
|
||||
repository.full_name, repository
|
||||
)
|
||||
else:
|
||||
raise HacsNotSoBasicException(GENERIC_ERROR)
|
||||
|
||||
@ -76,7 +82,9 @@ class HacsStorage(HacsBase):
|
||||
await repository.setup_repository()
|
||||
except (HacsRequirement, AIOGitHubException) as exception:
|
||||
if not self.data["task_running"]:
|
||||
_LOGGER.error("%s - %s", repository.repository_name, exception)
|
||||
_LOGGER.error(
|
||||
"%s - %s", repository.repository_name, exception
|
||||
)
|
||||
self.blacklist.append(repository.repository_name)
|
||||
continue
|
||||
|
||||
@ -90,7 +98,6 @@ class HacsStorage(HacsBase):
|
||||
self.data["task_running"] = False
|
||||
return store_data
|
||||
|
||||
|
||||
async def set(self):
|
||||
"""Write HACS data to storage."""
|
||||
if self.data["task_running"]:
|
||||
@ -123,7 +130,8 @@ class HacsStorage(HacsBase):
|
||||
|
||||
try:
|
||||
async with aiofiles.open(
|
||||
datastore, mode='w', encoding="utf-8", errors="ignore") as outfile:
|
||||
datastore, mode="w", encoding="utf-8", errors="ignore"
|
||||
) as outfile:
|
||||
await outfile.write(json.dumps(data, indent=4))
|
||||
outfile.close()
|
||||
|
||||
|
@ -5,6 +5,7 @@ from .hacsbase import HacsBase
|
||||
|
||||
class HacsViewBase(HomeAssistantView, HacsBase):
|
||||
"""Base View Class for HACS."""
|
||||
|
||||
requires_auth = False
|
||||
|
||||
@property
|
||||
@ -18,7 +19,9 @@ class HacsViewBase(HomeAssistantView, HacsBase):
|
||||
{}
|
||||
<div id="main" class="hacs-content">
|
||||
{}
|
||||
""".format(self.imports, self.header, self.progress_bar)
|
||||
""".format(
|
||||
self.imports, self.header, self.progress_bar
|
||||
)
|
||||
|
||||
@property
|
||||
def imports(self):
|
||||
@ -29,7 +32,9 @@ class HacsViewBase(HomeAssistantView, HacsBase):
|
||||
<script src="{static}/materialize.min.js.gz"></script>
|
||||
<link rel="stylesheet" href="{static}/hacs.css">
|
||||
<script src="{static}/hacs.js"></script>
|
||||
""".format(static=self.url_path["static"])
|
||||
""".format(
|
||||
static=self.url_path["static"]
|
||||
)
|
||||
|
||||
@property
|
||||
def header(self):
|
||||
@ -46,7 +51,9 @@ class HacsViewBase(HomeAssistantView, HacsBase):
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
""".format(self.url_path["overview"], self.url_path["store"], self.url_path["settings"])
|
||||
""".format(
|
||||
self.url_path["overview"], self.url_path["store"], self.url_path["settings"]
|
||||
)
|
||||
|
||||
@property
|
||||
def progress_bar(self):
|
||||
@ -61,7 +68,9 @@ class HacsViewBase(HomeAssistantView, HacsBase):
|
||||
<div class="progress hacs-bar-background" id="progressbar" style="display: {}">
|
||||
<div class="indeterminate hacs-bar"></div>
|
||||
</div>
|
||||
""".format(display, display)
|
||||
""".format(
|
||||
display, display
|
||||
)
|
||||
|
||||
@property
|
||||
def footer(self):
|
||||
|
@ -10,7 +10,7 @@ import backoff
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from ..exceptions import HacsNotSoBasicException
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.download')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.download")
|
||||
|
||||
|
||||
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
||||
@ -39,7 +39,11 @@ async def async_download_file(hass, url):
|
||||
else:
|
||||
result = await request.text()
|
||||
else:
|
||||
raise HacsNotSoBasicException("Got status code {} when trying to download {}".format(request.status, url))
|
||||
raise HacsNotSoBasicException(
|
||||
"Got status code {} when trying to download {}".format(
|
||||
request.status, url
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@ -48,23 +52,25 @@ async def async_save_file(location, content):
|
||||
"""Save files."""
|
||||
if "-bundle" in location:
|
||||
location = location.replace("-bundle", "")
|
||||
if "lovelace-" in location.split('/')[-1]:
|
||||
search = location.split('/')[-1]
|
||||
if "lovelace-" in location.split("/")[-1]:
|
||||
search = location.split("/")[-1]
|
||||
replace = search.replace("lovelace-", "")
|
||||
location = location.replace(search, replace)
|
||||
|
||||
_LOGGER.debug("Saving %s", location)
|
||||
mode = 'w'
|
||||
mode = "w"
|
||||
encoding = "utf-8"
|
||||
errors="ignore"
|
||||
errors = "ignore"
|
||||
|
||||
if not isinstance(content, str):
|
||||
mode = 'wb'
|
||||
mode = "wb"
|
||||
encoding = None
|
||||
errors = None
|
||||
|
||||
try:
|
||||
async with aiofiles.open(location, mode=mode, encoding=encoding, errors=errors) as outfile:
|
||||
async with aiofiles.open(
|
||||
location, mode=mode, encoding=encoding, errors=errors
|
||||
) as outfile:
|
||||
await outfile.write(content)
|
||||
outfile.close()
|
||||
|
||||
@ -73,7 +79,7 @@ async def async_save_file(location, content):
|
||||
_LOGGER.debug(msg)
|
||||
|
||||
# Create gz for .js files
|
||||
if location.endswith('.js') or location.endswith('.css'):
|
||||
with open(location, 'rb') as f_in:
|
||||
with gzip.open(location + '.gz', 'wb') as f_out:
|
||||
if location.endswith(".js") or location.endswith(".css"):
|
||||
with open(location, "rb") as f_in:
|
||||
with gzip.open(location + ".gz", "wb") as f_out:
|
||||
shutil.copyfileobj(f_in, f_out)
|
||||
|
@ -5,7 +5,7 @@ import aiofiles
|
||||
|
||||
from ..const import STARTUP
|
||||
|
||||
_LOGGER = logging.getLogger('custom_components.hacs.log')
|
||||
_LOGGER = logging.getLogger("custom_components.hacs.log")
|
||||
|
||||
|
||||
async def get_log_file_content(config_dir):
|
||||
@ -16,7 +16,8 @@ async def get_log_file_content(config_dir):
|
||||
|
||||
try:
|
||||
async with aiofiles.open(
|
||||
log_file, mode='r', encoding="utf-8", errors="ignore") as localfile:
|
||||
log_file, mode="r", encoding="utf-8", errors="ignore"
|
||||
) as localfile:
|
||||
logfile = await localfile.readlines()
|
||||
localfile.close()
|
||||
for line in logfile:
|
||||
@ -27,7 +28,9 @@ async def get_log_file_content(config_dir):
|
||||
line = line.replace(" WARNING ", "")
|
||||
line = line.replace(" ERROR ", "")
|
||||
line = line.replace(" CRITICAL ", "")
|
||||
interesting += "<pre style='margin: 0; white-space: pre-wrap'>{}</pre>".format(line)
|
||||
interesting += "<pre style='margin: 0; white-space: pre-wrap'>{}</pre>".format(
|
||||
line
|
||||
)
|
||||
except Exception as exception:
|
||||
_LOGGER.error(exception)
|
||||
return interesting
|
||||
|
@ -4,7 +4,8 @@ from . import hacs
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None): # pylint: disable=unused-argument
|
||||
hass, config, async_add_entities, discovery_info=None
|
||||
): # pylint: disable=unused-argument
|
||||
"""Setup sensor platform."""
|
||||
async_add_entities([HACSSensor()])
|
||||
|
||||
|
Reference in New Issue
Block a user