Example #1
0
async def get_info_md_content(repository):
    """Get the content of info.md"""
    filename = info_file(repository)
    if not filename:
        return ""
    try:
        info = await repository.repository_object.get_contents(
            filename, repository.ref)
        if info is None:
            return ""
        info = info.content.replace("<svg", "<disabled").replace(
            "</svg", "</disabled")
        return render_template(info, repository)
    except (AIOGitHubAPIException, Exception):  # pylint: disable=broad-except
        if repository.hacs.system.action:
            raise HacsException("::error:: No info file found")
    return ""
    async def update_repository(self, ignore_issues=False):
        """Update."""
        await self.common_update(ignore_issues)

        # Get python_script objects.
        if self.data.content_in_root:
            self.content.path.remote = ""

        compliant = False
        for treefile in self.treefiles:
            if treefile.startswith(f"{self.content.path.remote}"
                                   ) and treefile.endswith(".py"):
                compliant = True
                break
        if not compliant:
            raise HacsException(
                f"Repository structure for {self.ref.replace('tags/','')} is not compliant"
            )

        # Update name
        find_file_name(self)
Example #3
0
    async def common_registration(self):
        """Common registration steps of the repository."""
        # Attach repository
        if self.repository_object is None:
            self.repository_object = await get_repository(
                self.hacs.session, self.hacs.configuration.token, self.data.full_name
            )
            self.data.update_data(self.repository_object.attributes)

        # Set topics
        self.data.topics = self.data.topics

        # Set stargazers_count
        self.data.stargazers_count = self.data.stargazers_count

        # Set description
        self.data.description = self.data.description

        if self.hacs.action:
            if self.data.description is None or len(self.data.description) == 0:
                raise HacsException("::error:: Missing repository description")
    async def validate_repository(self):
        """Validate."""
        # Run common validation steps.
        await self.common_validate()

        # Custom step 1: Validate content.
        find_file_name(self)

        if self.content.path.remote is None:
            raise HacsException(
                f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant"
            )

        if self.content.path.remote == "release":
            self.content.single = True

        # Handle potential errors
        if self.validate.errors:
            for error in self.validate.errors:
                if not self.hacs.system.status.startup:
                    self.logger.error(error)
        return self.validate.success
Example #5
0
async def async_install_repository(repository):
    """Common installation steps of the repository."""
    hacs = get_hacs()
    persistent_directory = None
    await repository.update_repository()
    if repository.content.path.local is None:
        raise HacsException("repository.content.path.local is None")
    repository.validate.errors = []

    if not repository.can_install:
        raise HacsException(
            "The version of Home Assistant is not compatible with this version"
        )

    version = version_to_install(repository)
    if version == repository.data.default_branch:
        repository.ref = version
    else:
        repository.ref = f"tags/{version}"

    if repository.data.installed and repository.data.category == "netdaemon":
        persistent_directory = await hacs.hass.async_add_executor_job(
            BackupNetDaemon, repository)
        await hacs.hass.async_add_executor_job(persistent_directory.create)

    elif repository.data.persistent_directory:
        if os.path.exists(
                f"{repository.content.path.local}/{repository.data.persistent_directory}"
        ):
            persistent_directory = Backup(
                f"{repository.content.path.local}/{repository.data.persistent_directory}",
                tempfile.gettempdir() + "/hacs_persistent_directory/",
            )
            await hacs.hass.async_add_executor_job(persistent_directory.create)

    if repository.data.installed and not repository.content.single:
        backup = Backup(repository.content.path.local)
        await hacs.hass.async_add_executor_job(backup.create)

    if repository.data.zip_release and version != repository.data.default_branch:
        await repository.download_zip_files(repository)
    else:
        await download_content(repository)

    if repository.validate.errors:
        for error in repository.validate.errors:
            repository.logger.error(error)
        if repository.data.installed and not repository.content.single:
            await hacs.hass.async_add_executor_job(backup.restore)

    if repository.data.installed and not repository.content.single:
        await hacs.hass.async_add_executor_job(backup.cleanup)

    if persistent_directory is not None:
        await hacs.hass.async_add_executor_job(persistent_directory.restore)
        await hacs.hass.async_add_executor_job(persistent_directory.cleanup)

    if repository.validate.success:
        if repository.data.full_name not in repository.hacs.common.installed:
            if repository.data.full_name == "hacs/integration":
                repository.hacs.common.installed.append(
                    repository.data.full_name)
        repository.data.installed = True
        repository.data.installed_commit = repository.data.last_commit

        if version == repository.data.default_branch:
            repository.data.installed_version = None
        else:
            repository.data.installed_version = version
Example #6
0
async def common_update_data(repository, ignore_issues=False):
    """Common update data."""
    hacs = get_hacs()
    releases = []
    try:
        repository_object = await get_repository(hacs.session,
                                                 hacs.configuration.token,
                                                 repository.data.full_name)
        repository.repository_object = repository_object
        repository.data.update_data(repository_object.attributes)
    except (AIOGitHubAPIException, HacsException) as exception:
        if not hacs.status.startup:
            repository.logger.error("%s %s", repository, exception)
        if not ignore_issues:
            repository.validate.errors.append("Repository does not exist.")
            raise HacsException(exception) from None

    # Make sure the repository is not archived.
    if repository.data.archived and not ignore_issues:
        repository.validate.errors.append("Repository is archived.")
        raise HacsRepositoryArchivedException("Repository is archived.")

    # Make sure the repository is not in the blacklist.
    if is_removed(repository.data.full_name) and not ignore_issues:
        repository.validate.errors.append("Repository is in the blacklist.")
        raise HacsException("Repository is in the blacklist.")

    # Get releases.
    try:
        releases = await get_releases(
            repository.repository_object,
            repository.data.show_beta,
            hacs.configuration.release_limit,
        )
        if releases:
            repository.data.releases = True
            repository.releases.objects = [x for x in releases if not x.draft]
            repository.data.published_tags = [
                x.tag_name for x in repository.releases.objects
            ]
            repository.data.last_version = next(
                iter(repository.data.published_tags))

    except (AIOGitHubAPIException, HacsException):
        repository.data.releases = False

    if not repository.force_branch:
        repository.ref = version_to_install(repository)
    if repository.data.releases:
        for release in repository.releases.objects or []:
            if release.tag_name == repository.ref:
                assets = release.assets
                if assets:
                    downloads = next(
                        iter(assets)).attributes.get("download_count")
                    repository.data.downloads = downloads

    repository.logger.debug("%s Running checks against %s", repository,
                            repository.ref.replace("tags/", ""))

    try:
        repository.tree = await get_tree(repository.repository_object,
                                         repository.ref)
        if not repository.tree:
            raise HacsException("No files in tree")
        repository.treefiles = []
        for treefile in repository.tree:
            repository.treefiles.append(treefile.full_path)
    except (AIOGitHubAPIException, HacsException) as exception:
        if not hacs.status.startup:
            repository.logger.error("%s %s", repository, exception)
        if not ignore_issues:
            raise HacsException(exception) from None
Example #7
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"], {}))