homeassistant/custom_components/hacs/handler/download.py

91 lines
2.6 KiB
Python
Raw Normal View History

"""Download."""
import os
import gzip
import shutil
import aiofiles
import async_timeout
from integrationhelper import Logger
import backoff
from ..hacsbase.exceptions import HacsException
from custom_components.hacs.globals import get_hacs
@backoff.on_exception(backoff.expo, Exception, max_tries=5)
async def async_download_file(url):
"""
Download files, and return the content.
"""
hacs = get_hacs()
logger = Logger("hacs.download.downloader")
if url is None:
return
# There is a bug somewhere... TODO: Find that bug....
if "tags/" in url:
url = url.replace("tags/", "")
logger.debug(f"Downloading {url}")
result = None
with async_timeout.timeout(60, loop=hacs.hass.loop):
request = await hacs.session.get(url)
# Make sure that we got a valid result
if request.status == 200:
result = await request.read()
else:
raise HacsException(
"Got status code {} when trying to download {}".format(
request.status, url
)
)
return result
async def async_save_file(location, content):
"""Save files."""
logger = Logger("hacs.download.save")
logger.debug(f"Saving {location}")
mode = "w"
encoding = "utf-8"
errors = "ignore"
if not isinstance(content, str):
mode = "wb"
encoding = None
errors = None
try:
async with aiofiles.open(
location, mode=mode, encoding=encoding, errors=errors
) as outfile:
await outfile.write(content)
outfile.close()
# Create gz for .js files
if os.path.isfile(location):
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)
# Remove with 2.0
if "themes" in location and location.endswith(".yaml"):
filename = location.split("/")[-1]
base = location.split("/themes/")[0]
combined = f"{base}/themes/{filename}"
if os.path.exists(combined):
logger.info(f"Removing old theme file {combined}")
os.remove(combined)
except Exception as error: # pylint: disable=broad-except
msg = "Could not write data to {} - {}".format(location, error)
logger.error(msg)
return False
return os.path.exists(location)