Exemplo n.º 1
0
async def async_setup_frontend():
    """Configure the HACS frontend elements."""
    hacs = get_hacs()
    hacs.log.info("Setup task %s", HacsSetupTask.FRONTEND)
    hass = hacs.hass

    # Register themes
    hass.http.register_static_path(f"{URL_BASE}/themes",
                                   hass.config.path("themes"))

    # Register frontend
    if hacs.configuration.frontend_repo_url:
        getLogger().warning(
            "Frontend development mode enabled. Do not run in production.")
        hass.http.register_view(HacsFrontendDev())
    else:
        #
        hass.http.register_static_path(f"{URL_BASE}/frontend",
                                       locate_dir(),
                                       cache_headers=False)

    # Custom iconset
    hass.http.register_static_path(f"{URL_BASE}/iconset.js",
                                   str(hacs.integration_dir / "iconset.js"))
    if "frontend_extra_module_url" not in hass.data:
        hass.data["frontend_extra_module_url"] = set()
    hass.data["frontend_extra_module_url"].add("/hacsfiles/iconset.js")

    # Register www/community for all other files
    hass.http.register_static_path(URL_BASE,
                                   hass.config.path("www/community"),
                                   cache_headers=False)

    hacs.frontend.version_running = FE_VERSION
    hacs.frontend.version_expected = await hass.async_add_executor_job(
        get_frontend_version)

    # Add to sidepanel
    if "hacs" not in hass.data.get("frontend_panels", {}):
        hass.components.frontend.async_register_built_in_panel(
            component_name="custom",
            sidebar_title=hacs.configuration.sidepanel_title,
            sidebar_icon=hacs.configuration.sidepanel_icon,
            frontend_url_path="hacs",
            config={
                "_panel_custom": {
                    "name": "hacs-frontend",
                    "embed_iframe": True,
                    "trust_external": False,
                    "js_url": "/hacsfiles/frontend/entrypoint.js",
                }
            },
            require_admin=True,
        )
Exemplo n.º 2
0
async def async_download_file(url):
    """Download files, and return the content."""
    hacs = get_hacs()
    logger = getLogger("async_download_file")
    if url is None:
        return

    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
Exemplo n.º 3
0
async def async_serve_category_file(requested_file):
    hacs = get_hacs()
    logger = getLogger("web.category")
    try:
        if requested_file.startswith("themes/"):
            servefile = f"{hacs.system.config_path}/{requested_file}"
        else:
            servefile = f"{hacs.system.config_path}/www/community/{requested_file}"

        # Serve .gz if it exist
        if await async_path_exsist(f"{servefile}.gz"):
            servefile += ".gz"

        if await async_path_exsist(servefile):
            logger.debug(f"Serving {requested_file} from {servefile}")
            response = web.FileResponse(servefile)
            response.headers["Cache-Control"] = "no-store, max-age=0"
            response.headers["Pragma"] = "no-store"
            return response
        else:
            logger.error(
                f"Tried to serve up '{servefile}' but it does not exist")

    except (Exception, BaseException) as error:
        logger.debug(
            f"there was an issue trying to serve {requested_file} - {error}")

    return web.Response(status=404)
Exemplo n.º 4
0
async def hacs_settings(hass, connection, msg):
    """Handle get media player cover command."""
    hacs = get_hacs()
    logger = getLogger("api.settings")

    action = msg["action"]
    logger.debug(f"WS action '{action}'")

    if action == "set_fe_grid":
        hacs.configuration.frontend_mode = "Grid"

    elif action == "onboarding_done":
        hacs.configuration.onboarding_done = True

    elif action == "set_fe_table":
        hacs.configuration.frontend_mode = "Table"

    elif action == "set_fe_compact_true":
        hacs.configuration.frontend_compact = False

    elif action == "set_fe_compact_false":
        hacs.configuration.frontend_compact = True

    elif action == "clear_new":
        for repo in hacs.repositories:
            if repo.data.new and repo.data.category in msg.get("categories", []):
                logger.debug(f"Clearing new flag from '{repo.data.full_name}'")
                repo.data.new = False
    else:
        logger.error(f"WS action '{action}' is not valid")
    hass.bus.async_fire("hacs/config", {})
    await hacs.data.async_write()
    connection.send_message(websocket_api.result_message(msg["id"], {}))
Exemplo n.º 5
0
 def __init__(self, repository):
     """Initialize."""
     self.repository = repository
     self.logger = getLogger("backup")
     self.backup_path = (tempfile.gettempdir() +
                         "/hacs_persistent_netdaemon/" +
                         repository.data.name)
Exemplo n.º 6
0
 def __init__(self, full_name):
     """Initialize."""
     super().__init__()
     self.data.full_name = full_name
     self.data.category = "appdaemon"
     self.content.path.local = self.localpath
     self.content.path.remote = "apps"
     self.logger = getLogger(f"repository.{self.data.category}.{full_name}")
Exemplo n.º 7
0
 def print(self):
     """Print the current configuration to the log."""
     logger = getLogger("configuration")
     config = self.to_json()
     for key in config:
         if key in ["config", "config_entry", "options", "token"]:
             continue
         logger.debug(f"{key}: {config[key]}")
Exemplo n.º 8
0
 def __init__(self, full_name):
     """Initialize."""
     super().__init__()
     self.data.full_name = full_name
     self.data.category = "python_script"
     self.content.path.remote = "python_scripts"
     self.content.path.local = self.localpath
     self.content.single = True
     self.logger = getLogger(f"repository.{self.data.category}.{full_name}")
Exemplo n.º 9
0
 def __init__(self, full_name):
     """Initialize."""
     super().__init__()
     self.data.full_name = full_name
     self.data.file_name = None
     self.data.category = "plugin"
     self.information.javascript_type = None
     self.content.path.local = self.localpath
     self.logger = getLogger(f"repository.{self.data.category}.{full_name}")
Exemplo n.º 10
0
 def __init__(self, full_name):
     """Initialize."""
     super().__init__()
     self.data.full_name = full_name
     self.data.full_name_lower = full_name.lower()
     self.data.category = "integration"
     self.content.path.remote = "custom_components"
     self.content.path.local = self.localpath
     self.logger = getLogger(f"repository.{self.data.category}.{full_name}")
def _clear_storage():
    """Clear old files from storage."""
    hacs = get_hacs()
    logger = getLogger("startup.clear_storage")
    storagefiles = ["hacs"]
    for s_f in storagefiles:
        path = f"{hacs.system.config_path}/.storage/{s_f}"
        if os.path.isfile(path):
            logger.info(f"Cleaning up old storage file {path}")
            os.remove(path)
Exemplo n.º 12
0
 def __init__(self, full_name):
     """Initialize."""
     super().__init__()
     self.data.full_name = full_name
     self.data.full_name_lower = full_name.lower()
     self.data.category = "theme"
     self.content.path.remote = "themes"
     self.content.path.local = self.localpath
     self.content.single = False
     self.logger = getLogger(f"repository.{self.data.category}.{full_name}")
Exemplo n.º 13
0
async def remaining(github):
    """Helper to calculate the remaining calls to github."""
    logger = getLogger("custom_components.hacs.remaining_github_calls")
    try:
        ratelimits = await github.get_rate_limit()
    except (BaseException, Exception) as exception:  # pylint: disable=broad-except
        logger.error(exception)
        return None
    if ratelimits.get("remaining") is not None:
        return int(ratelimits["remaining"])
    return 0
Exemplo n.º 14
0
class MockRepo(RepositoryMethodInstall, RepositoryMethodPreInstall,
               RepositoryMethodPostInstall):
    logger = getLogger()
    content = MockContent()
    validate = Validate()
    can_install = False
    data = RepositoryData()
    tree = []
    hacs = get_hacs()

    async def update_repository(self):
        pass
Exemplo n.º 15
0
async def get_file_response(requested_file):
    """Get file."""
    logger = getLogger("web")

    if requested_file in IGNORE:
        logger.debug(f"Ignoring request for {requested_file}")
        return web.Response(status=200)

    if requested_file.startswith("frontend-"):
        return await async_serve_frontend()

    elif requested_file == "iconset.js":
        return serve_iconset()

    return await async_serve_category_file(requested_file)
Exemplo n.º 16
0
def dummy_repository_base(repository=None):
    if repository is None:
        repository = HacsRepository()
    repository.hacs.hass = HomeAssistant()
    repository.hacs.hass.data = {"custom_components": []}
    repository.hacs.system.config_path = tempfile.gettempdir()
    repository.logger = getLogger("test.test")
    repository.data.full_name = "test/test"
    repository.data.domain = "test"
    repository.data.last_version = "3"
    repository.data.selected_tag = "3"
    repository.ref = version_to_install(repository)
    repository.integration_manifest = {"config_flow": False, "domain": "test"}
    repository.data.published_tags = ["1", "2", "3"]
    repository.data.update_data(repository_data)
    return repository
Exemplo n.º 17
0
async def async_save_file(location, content):
    """Save files."""
    logger = getLogger("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, BaseException) as error:  # pylint: disable=broad-except
        msg = f"Could not write data to {location} - {error}"
        logger.error(msg)
        return False

    return os.path.exists(location)
Exemplo n.º 18
0
 def __init__(self):
     """Set up HacsRepository."""
     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.force_branch = False
     self.integration_manifest = {}
     self.repository_manifest = HacsManifest.from_dict({})
     self.validate = Validate()
     self.releases = RepositoryReleases()
     self.versions = RepositoryVersions()
     self.pending_restart = False
     self.tree = []
     self.treefiles = []
     self.ref = None
     self.logger = getLogger()
async def async_get_list_from_default(default: str) -> List:
    """Get repositories from default list."""
    hacs = get_hacs()
    repositories = []
    logger = getLogger("async_get_list_from_default")

    try:
        repo = await get_repository(
            hacs.session,
            hacs.configuration.token,
            "hacs/default",
        )
        content = await repo.get_contents(default, repo.default_branch)
        repositories = json.loads(content.content)

    except (AIOGitHubAPIException, HacsException) as exception:
        logger.error(exception)

    except (Exception, BaseException) as exception:
        logger.error(exception)

    logger.debug(f"Got {len(repositories)} elements for {default}")

    return repositories
Exemplo n.º 20
0
# pylint: disable=missing-docstring,invalid-name
import asyncio
from aiogithubapi import AIOGitHubAPIException

from custom_components.hacs.helpers.classes.exceptions import HacsException
from custom_components.hacs.helpers.functions.logger import getLogger
from custom_components.hacs.helpers.functions.register_repository import (
    register_repository, )

max_concurrent_tasks = asyncio.Semaphore(15)
sleeper = 5

logger = getLogger("factory")


class HacsTaskFactory:
    def __init__(self):
        self.tasks = []
        self.running = False

    async def safe_common_update(self, repository):
        async with max_concurrent_tasks:
            try:
                await repository.common_update()
            except (AIOGitHubAPIException, HacsException) as exception:
                logger.error("%s - %s", repository.data.full_name, exception)

            # Due to GitHub ratelimits we need to sleep a bit
            await asyncio.sleep(sleeper)

    async def safe_update(self, repository):
Exemplo n.º 21
0
class Hacs(HacsHelpers):
    """The base class of HACS, nested throughout the project."""

    token = f"{str(uuid.uuid4())}-{str(uuid.uuid4())}"
    action = False
    hacsweb = f"/hacsweb/{token}"
    hacsapi = f"/hacsapi/{token}"
    repositories = []
    frontend = HacsFrontend()
    repo = None
    data_repo = None
    data = None
    configuration = None
    logger = getLogger()
    github = None
    hass = None
    version = None
    session = None
    factory = get_factory()
    queue = get_queue()
    system = System()
    recuring_tasks = []

    common = HacsCommon()

    def get_by_id(self, repository_id):
        """Get repository by ID."""
        try:
            for repository in self.repositories:
                if str(repository.data.id) == str(repository_id):
                    return repository
        except (Exception, BaseException):  # pylint: disable=broad-except
            pass
        return None

    def get_by_name(self, repository_full_name):
        """Get repository by full_name."""
        try:
            repository_full_name_lower = repository_full_name.lower()
            for repository in self.repositories:
                if repository.data.full_name_lower == repository_full_name_lower:
                    return repository
        except (Exception, BaseException):  # pylint: disable=broad-except
            pass
        return None

    def is_known(self, repository_id):
        """Return a bool if the repository is known."""
        return str(repository_id) in [
            str(x.data.id) for x in self.repositories
        ]

    @property
    def sorted_by_name(self):
        """Return a sorted(by name) list of repository objects."""
        return sorted(self.repositories, key=lambda x: x.display_name)

    @property
    def sorted_by_repository_name(self):
        """Return a sorted(by repository_name) list of repository objects."""
        return sorted(self.repositories, key=lambda x: x.data.full_name)

    async def register_repository(self, full_name, category, check=True):
        """Register a repository."""
        await register_repository(full_name, category, check=True)

    async def startup_tasks(self):
        """Tasks that are started after startup."""
        self.system.status.background_task = True
        await async_setup_extra_stores()
        self.hass.bus.async_fire("hacs/status", {})

        await self.handle_critical_repositories_startup()
        await self.handle_critical_repositories()
        await self.async_load_default_repositories()
        await self.clear_out_removed_repositories()

        self.recuring_tasks.append(
            self.hass.helpers.event.async_track_time_interval(
                self.recurring_tasks_installed, timedelta(minutes=30)))
        self.recuring_tasks.append(
            self.hass.helpers.event.async_track_time_interval(
                self.recurring_tasks_all, timedelta(minutes=800)))
        self.recuring_tasks.append(
            self.hass.helpers.event.async_track_time_interval(
                self.prosess_queue, timedelta(minutes=10)))

        self.hass.bus.async_fire("hacs/reload", {"force": True})
        await self.recurring_tasks_installed()

        await self.prosess_queue()

        self.system.status.startup = False
        self.system.status.background_task = False
        self.hass.bus.async_fire("hacs/status", {})
        await self.data.async_write()

    async def handle_critical_repositories_startup(self):
        """Handled critical repositories during startup."""
        alert = False
        critical = await async_load_from_store(self.hass, "critical")
        if not critical:
            return
        for repo in critical:
            if not repo["acknowledged"]:
                alert = True
        if alert:
            self.logger.critical("URGENT!: Check the HACS panel!")
            self.hass.components.persistent_notification.create(
                title="URGENT!", message="**Check the HACS panel!**")

    async def handle_critical_repositories(self):
        """Handled critical repositories during runtime."""
        # Get critical repositories
        critical_queue = QueueManager()
        instored = []
        critical = []
        was_installed = False

        try:
            critical = await self.data_repo.get_contents("critical")
            critical = json.loads(critical.content)
        except AIOGitHubAPIException:
            pass

        if not critical:
            self.logger.debug("No critical repositories")
            return

        stored_critical = await async_load_from_store(self.hass, "critical")

        for stored in stored_critical or []:
            instored.append(stored["repository"])

        stored_critical = []

        for repository in critical:
            removed_repo = get_removed(repository["repository"])
            removed_repo.removal_type = "critical"
            repo = self.get_by_name(repository["repository"])

            stored = {
                "repository": repository["repository"],
                "reason": repository["reason"],
                "link": repository["link"],
                "acknowledged": True,
            }
            if repository["repository"] not in instored:
                if repo is not None and repo.installed:
                    self.logger.critical(
                        f"Removing repository {repository['repository']}, it is marked as critical"
                    )
                    was_installed = True
                    stored["acknowledged"] = False
                    # Remove from HACS
                    critical_queue.add(repository.uninstall())
                    repo.remove()

            stored_critical.append(stored)
            removed_repo.update_data(stored)

        # Uninstall
        await critical_queue.execute()

        # Save to FS
        await async_save_to_store(self.hass, "critical", stored_critical)

        # Restart HASS
        if was_installed:
            self.logger.critical("Resarting Home Assistant")
            self.hass.async_create_task(self.hass.async_stop(100))

    async def prosess_queue(self, _notarealarg=None):
        """Recurring tasks for installed repositories."""
        if not self.queue.has_pending_tasks:
            self.logger.debug("Nothing in the queue")
            return
        if self.queue.running:
            self.logger.debug("Queue is already running")
            return

        can_update = await get_fetch_updates_for(self.github)
        if can_update == 0:
            self.logger.info(
                "HACS is ratelimited, repository updates will resume later.")
        else:
            self.system.status.background_task = True
            self.hass.bus.async_fire("hacs/status", {})
            await self.queue.execute(can_update)
            self.system.status.background_task = False
            self.hass.bus.async_fire("hacs/status", {})

    async def recurring_tasks_installed(self, _notarealarg=None):
        """Recurring tasks for installed repositories."""
        self.logger.debug(
            "Starting recurring background task for installed repositories")
        self.system.status.background_task = True
        self.hass.bus.async_fire("hacs/status", {})

        for repository in self.repositories:
            if (repository.data.installed
                    and repository.data.category in self.common.categories):
                self.queue.add(self.factory.safe_update(repository))

        await self.handle_critical_repositories()
        self.system.status.background_task = False
        self.hass.bus.async_fire("hacs/status", {})
        await self.data.async_write()
        self.logger.debug(
            "Recurring background task for installed repositories done")

    async def recurring_tasks_all(self, _notarealarg=None):
        """Recurring tasks for all repositories."""
        self.logger.debug(
            "Starting recurring background task for all repositories")
        await async_setup_extra_stores()
        self.system.status.background_task = True
        self.hass.bus.async_fire("hacs/status", {})

        for repository in self.repositories:
            if repository.data.category in self.common.categories:
                self.queue.add(self.factory.safe_common_update(repository))

        await self.async_load_default_repositories()
        await self.clear_out_removed_repositories()
        self.system.status.background_task = False
        await self.data.async_write()
        self.hass.bus.async_fire("hacs/status", {})
        self.hass.bus.async_fire("hacs/repository", {"action": "reload"})
        self.logger.debug(
            "Recurring background task for all repositories done")

    async def clear_out_removed_repositories(self):
        """Clear out blaclisted repositories."""
        need_to_save = False
        for removed in list_removed_repositories():
            repository = self.get_by_name(removed.repository)
            if repository is not None:
                if repository.data.installed and removed.removal_type != "critical":
                    self.logger.warning(
                        f"You have {repository.data.full_name} installed with HACS "
                        +
                        "this repository has been removed, please consider removing it. "
                        + f"Removal reason ({removed.removal_type})")
                else:
                    need_to_save = True
                    repository.remove()

        if need_to_save:
            await self.data.async_write()

    async def async_load_default_repositories(self):
        """Load known repositories."""
        self.logger.info("Loading known repositories")

        for item in await async_get_list_from_default("removed"):
            removed = get_removed(item["repository"])
            removed.reason = item.get("reason")
            removed.link = item.get("link")
            removed.removal_type = item.get("removal_type")

        for category in self.common.categories or []:
            self.queue.add(self.async_get_category_repositories(category))

        await self.queue.execute()

    async def async_get_category_repositories(self, category):
        repositories = await async_get_list_from_default(category)
        for repo in repositories:
            if is_removed(repo):
                continue
            repository = self.get_by_name(repo)
            if repository is not None:
                if str(repository.data.id) not in self.common.default:
                    self.common.default.append(str(repository.data.id))
                else:
                    continue
                continue
            self.queue.add(self.factory.safe_register(repo, category))
Exemplo n.º 22
0
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")
CHANGED_FILES = os.getenv("CHANGED_FILES", "")

REPOSITORY = os.getenv("REPOSITORY", os.getenv("INPUT_REPOSITORY"))
CATEGORY = os.getenv("CATEGORY", os.getenv("INPUT_CATEGORY", ""))

CATEGORIES = [
    "appdaemon",
    "integration",
    "netdaemon",
    "plugin",
    "python_script",
    "theme",
]

logger = getLogger("action")


def error(error: str):
    logger.error(error)
    exit()


def get_event_data():
    if GITHUB_EVENT_PATH is None:
        return {}
    with open(GITHUB_EVENT_PATH) as ev:
        return json.loads(ev.read())


def chose_repository(category):
Exemplo n.º 23
0
 def __init__(self):
     """Initialize."""
     self.logger = getLogger("data")
     self.hacs = get_hacs()
     self.queue = QueueManager()
     self.content = {}
Exemplo n.º 24
0
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")
CHANGED_FILES = os.getenv("CHANGED_FILES", "")

REPOSITORY = os.getenv("REPOSITORY", os.getenv("INPUT_REPOSITORY"))
CATEGORY = os.getenv("CATEGORY", os.getenv("INPUT_CATEGORY", ""))

CATEGORIES = [
    "appdaemon",
    "integration",
    "netdaemon",
    "plugin",
    "python_script",
    "theme",
]

logger = getLogger()


def error(error: str):
    logger.error(error)
    exit(1)


def get_event_data():
    if GITHUB_EVENT_PATH is None or not os.path.exists(GITHUB_EVENT_PATH):
        return {}
    with open(GITHUB_EVENT_PATH) as ev:
        return json.loads(ev.read())


def chose_repository(category):
Exemplo n.º 25
0
from aiohttp import web

from custom_components.hacs.helpers.functions.logger import getLogger
from custom_components.hacs.helpers.functions.path_exsist import async_path_exsist
from custom_components.hacs.share import get_hacs

_LOGGER = getLogger()


async def async_serve_category_file(request, requested_file):
    hacs = get_hacs()
    try:
        if requested_file.startswith("themes/"):
            servefile = f"{hacs.core.config_path}/{requested_file}"
        else:
            servefile = f"{hacs.core.config_path}/www/community/{requested_file}"

        if await async_path_exsist(servefile):
            _LOGGER.debug("Serving %s from %s", requested_file, servefile)
            response = web.FileResponse(servefile)
            if requested_file.startswith("themes/"):
                response.headers["Cache-Control"] = "public, max-age=2678400"
            else:
                response.headers["Cache-Control"] = "no-store, max-age=0"
                response.headers["Pragma"] = "no-store"
            return response
        else:
            _LOGGER.error(
                "%s tried to request '%s' but the file does not exist",
                request.remote,
                servefile,
Exemplo n.º 26
0
async def hacs_repository(hass, connection, msg):
    """Handle get media player cover command."""
    hacs = get_hacs()
    logger = getLogger()
    data = {}
    repository = None

    repo_id = msg.get("repository")
    action = msg.get("action")
    if repo_id is None or action is None:
        return

    try:
        repository = hacs.get_by_id(repo_id)
        logger.debug(f"Running {action} for {repository.data.full_name}")

        if action == "update":
            await repository.update_repository(True)
            repository.status.updated_info = True

        elif action == "install":
            repository.data.new = False
            was_installed = repository.data.installed
            await repository.async_install()
            if not was_installed:
                hass.bus.async_fire("hacs/reload", {"force": True})

        elif action == "not_new":
            repository.data.new = False

        elif action == "uninstall":
            repository.data.new = False
            await repository.update_repository(True)
            await repository.uninstall()

        elif action == "hide":
            repository.data.hide = True

        elif action == "unhide":
            repository.data.hide = False

        elif action == "show_beta":
            repository.data.show_beta = True
            await repository.update_repository()

        elif action == "hide_beta":
            repository.data.show_beta = False
            await repository.update_repository()

        elif action == "toggle_beta":
            repository.data.show_beta = not repository.data.show_beta
            await repository.update_repository()

        elif action == "delete":
            repository.data.show_beta = False
            repository.remove()

        elif action == "release_notes":
            data = [
                {
                    "name": x.attributes["name"],
                    "body": x.attributes["body"],
                    "tag": x.attributes["tag_name"],
                }
                for x in repository.releases.objects
            ]

        elif action == "set_version":
            if msg["version"] == repository.data.default_branch:
                repository.data.selected_tag = None
            else:
                repository.data.selected_tag = msg["version"]
            await repository.update_repository()

            hass.bus.async_fire("hacs/reload", {"force": True})

        else:
            logger.error(f"WS action '{action}' is not valid")

        await hacs.data.async_write()
        message = None
    except AIOGitHubAPIException as exception:
        message = exception
    except AttributeError as exception:
        message = f"Could not use repository with ID {repo_id} ({exception})"
    except (Exception, BaseException) as exception:  # pylint: disable=broad-except
        message = exception

    if message is not None:
        logger.error(message)
        hass.bus.async_fire("hacs/error", {"message": str(message)})

    if repository:
        repository.state = None
        connection.send_message(websocket_api.result_message(msg["id"], data))
Exemplo n.º 27
0
 def __init__(self, local_path, backup_path=BACKUP_PATH):
     """initialize."""
     self.logger = getLogger("backup")
     self.local_path = local_path
     self.backup_path = backup_path
     self.backup_path_full = f"{self.backup_path}{self.local_path.split('/')[-1]}"
Exemplo n.º 28
0
def test_logger():
    os.environ["GITHUB_ACTION"] = "value"
    getLogger()
    del os.environ["GITHUB_ACTION"]
Exemplo n.º 29
0
async def hacs_repository_data(hass, connection, msg):
    """Handle get media player cover command."""
    hacs = get_hacs()
    logger = getLogger("api.repository_data")
    repo_id = msg.get("repository")
    action = msg.get("action")
    data = msg.get("data")

    if repo_id is None:
        return

    if action == "add":
        if "github." in repo_id:
            repo_id = repo_id.split("github.com/")[1]

        if repo_id in hacs.common.skip:
            hacs.common.skip.remove(repo_id)

        if not hacs.get_by_name(repo_id):
            try:
                registration = await register_repository(repo_id, data.lower())
                if registration is not None:
                    raise HacsException(registration)
            except (
                    Exception,
                    BaseException,
            ) as exception:  # pylint: disable=broad-except
                hass.bus.async_fire(
                    "hacs/error",
                    {
                        "action": "add_repository",
                        "exception": str(sys.exc_info()[0].__name__),
                        "message": str(exception),
                    },
                )
        else:
            hass.bus.async_fire(
                "hacs/error",
                {
                    "action": "add_repository",
                    "message": f"Repository '{repo_id}' exists in the store.",
                },
            )

        repository = hacs.get_by_name(repo_id)
    else:
        repository = hacs.get_by_id(repo_id)

    if repository is None:
        hass.bus.async_fire("hacs/repository", {})
        return

    logger.debug(f"Running {action} for {repository.data.full_name}")
    try:
        if action == "set_state":
            repository.state = data

        elif action == "set_version":
            repository.data.selected_tag = data
            await repository.update_repository()

            repository.state = None

        elif action == "install":
            was_installed = repository.data.installed
            repository.data.selected_tag = data
            await repository.update_repository()
            await repository.async_install()
            repository.state = None
            if not was_installed:
                hass.bus.async_fire("hacs/reload", {"force": True})

        elif action == "add":
            repository.state = None

        else:
            repository.state = None
            logger.error(f"WS action '{action}' is not valid")

        message = None
    except AIOGitHubAPIException as exception:
        message = exception
    except AttributeError as exception:
        message = f"Could not use repository with ID {repo_id} ({exception})"
    except (Exception, BaseException) as exception:  # pylint: disable=broad-except
        message = exception

    if message is not None:
        logger.error(message)
        hass.bus.async_fire("hacs/error", {"message": str(message)})

    await hacs.data.async_write()
    connection.send_message(websocket_api.result_message(msg["id"], {}))
Exemplo n.º 30
0
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client

from custom_components.hacs.const import DOMAIN
from custom_components.hacs.helpers.functions.configuration_schema import (
    hacs_base_config_schema,
    hacs_config_option_schema,
)
from custom_components.hacs.helpers.functions.information import get_repository

# pylint: disable=dangerous-default-value
from custom_components.hacs.helpers.functions.logger import getLogger
from custom_components.hacs.share import get_hacs

_LOGGER = getLogger(__name__)


class HacsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
    """Config flow for HACS."""

    VERSION = 1
    CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL

    def __init__(self):
        """Initialize."""
        self._errors = {}

    async def async_step_user(self, user_input={}):
        """Handle a flow initialized by the user."""
        self._errors = {}