Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check hacs.json before downloading #3350

Merged
merged 1 commit into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 10 additions & 62 deletions custom_components/hacs/repositories/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,56 +560,23 @@ async def common_update(self, ignore_issues=False, force=False, skip_releases=Fa

async def download_zip_files(self, validate: Validate) -> None:
"""Download ZIP archive from repository release."""
contents: list[DownloadableContent] = []
target_ref = self.ref.split("/")[1]

if self.repository_manifest.zip_release:
contents.append(
try:
await self.async_download_zip_file(
DownloadableContent(
name=self.repository_manifest.filename,
url=asset_download(
repository=self.data.full_name,
version=target_ref,
version=self.ref,
filenme=self.repository_manifest.filename,
),
)
),
validate,
)
else:
for release in self.releases.objects:
self.logger.debug(
"%s ref: %s --- tag: %s", self.string, target_ref, release.tag_name
)
if release.tag_name == target_ref and release.assets:
contents = [
DownloadableContent(
name=asset.name,
url=asset.browser_download_url,
)
for asset in release.assets
]
break

if len(contents) == 0:
validate.errors.append(f"No assets found for release '{self.ref}'")
return

download_queue = QueueManager(hass=self.hacs.hass)
try:
for content in contents:
if (
self.repository_manifest.zip_release
and content["name"] != self.repository_manifest.filename
):
continue
download_queue.add(self.async_download_zip_file(content, validate))

if download_queue.pending_tasks == 0:
validate.errors.append("Nothing to download")
return

await download_queue.execute()
except BaseException: # lgtm [py/catch-base-exception] pylint: disable=broad-except
validate.errors.append("Download was not completed")
validate.errors.append(
f"Download of {self.repository_manifest.filename} was not completed"
)

async def async_download_zip_file(
self,
Expand All @@ -621,7 +588,7 @@ async def async_download_zip_file(
filecontent = await self.hacs.async_download_file(content["url"])

if filecontent is None:
validate.errors.append(f"[{content['name']}] was not downloaded")
validate.errors.append(f"Failed to download {content['url']}")
return

temp_dir = await self.hacs.hass.async_add_executor_job(tempfile.mkdtemp)
Expand Down Expand Up @@ -706,7 +673,6 @@ async def download_repository_zip(self):
raise HacsException(f"[{self}] Failed to download zipball")

temp_dir = await self.hacs.hass.async_add_executor_job(tempfile.mkdtemp)
tmp_extract = f"{temp_dir}/extracted"
temp_file = f"{temp_dir}/{self.repository_manifest.filename}"
result = await self.hacs.async_save_file(temp_file, filecontent)
if not result:
Expand All @@ -723,24 +689,6 @@ async def download_repository_zip(self):
path.filename = filename.replace(self.content.path.remote, "")
extractable.append(path)

if filename == "hacs.json":
path.filename = "hacs.json"
zip_file.extract(path, tmp_extract)
with open(f"{tmp_extract}/hacs.json", encoding="utf-8") as hacsfile:
hacs_manifest = json_loads(hacsfile.read())
if (
hacs_version := hacs_manifest.get("hacs")
) and hacs_version > self.hacs.version:
raise HacsException(
f"This repository requires HACS version {hacs_manifest['hacs']}, you have {self.hacs.version}"
)
if (
homeassistant_version := hacs_manifest["homeassistant"]
) and homeassistant_version > self.hacs.core.ha_version:
raise HacsException(
f"This repository requires Home Assistant version {hacs_manifest['homeassistant']}, you have {self.hacs.core.ha_version}"
)

if len(extractable) == 0:
raise HacsException("No content to extract")
zip_file.extractall(self.content.path.local, extractable)
Expand Down Expand Up @@ -1019,7 +967,7 @@ async def async_install_repository(self, *, version: str | None = None, **_) ->
{"repository": self.data.full_name, "progress": 50},
)

if self.repository_manifest.zip_release and version_to_install != self.data.default_branch:
if self.repository_manifest.zip_release and self.repository_manifest.filename:
await self.download_zip_files(self.validate)
else:
await self.download_content(version_to_install)
Expand Down
29 changes: 23 additions & 6 deletions custom_components/hacs/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .entity import HacsRepositoryEntity
from .enums import HacsCategory, HacsDispatchEvent
from .exceptions import HacsException
from .repositories.base import HacsManifest


async def async_setup_entry(hass, _config_entry, async_add_devices):
Expand Down Expand Up @@ -70,25 +71,41 @@ def entity_picture(self) -> str | None:

return f"https://brands.home-assistant.io/_/{self.repository.data.domain}/icon.png"

def _ensure_capabilities(self, version: str | None, **kwargs: Any) -> None:
async def _ensure_capabilities(self, version: str | None, **kwargs: Any) -> None:
"""Ensure that the entity has capabilities."""
target_manifest: HacsManifest | None = None
if version is None:
if not self.repository.can_download:
raise HomeAssistantError(
f"This {self.repository.data.category.value} is not available for download."
)
return

if version == self.repository.data.last_version:
target_manifest = self.repository.repository_manifest
else:
target_manifest = await self.repository.get_hacs_json(version=version)

if target_manifest is None:
raise HomeAssistantError(
f"The version {version} for this {self.repository.data.category.value} can not be used with HACS."
)

self.repository.logger.warning("target_manifest: %s", target_manifest.to_dict())

if (
self.repository.display_version_or_commit != "version"
or self.repository.repository_manifest.hide_default_branch
target_manifest.homeassistant is not None
and self.hacs.core.ha_version < target_manifest.homeassistant
):
raise HomeAssistantError(
f"This {self.repository.data.category.value} does not support version selection."
f"This version requires Home Assistant {target_manifest.homeassistant} or newer."
)
if target_manifest.hacs is not None and self.hacs.core.ha_version < target_manifest.hacs:
raise HomeAssistantError(f"This version requires HACS {target_manifest.hacs} or newer.")

async def async_install(self, version: str | None, backup: bool, **kwargs: Any) -> None:
"""Install an update."""
self._ensure_capabilities(version)
await self._ensure_capabilities(version)
self.repository.logger.info("Starting update, %s", version)
if self.repository.display_version_or_commit == "version":
self._update_in_progress(progress=10)
Expand All @@ -104,7 +121,7 @@ async def async_install(self, version: str | None, backup: bool, **kwargs: Any)
await self.repository.async_install(version=version)
except HacsException as exception:
raise HomeAssistantError(
f"{exception} for {version}" if version else exception
f"Downloading {self.repository.data.full_name} with version {version or self.repository.data.last_version or self.repository.data.last_commit} failed with ({exception})"
) from exception
finally:
self._update_in_progress(progress=False)
Expand Down