Пример #1
0
def installation_complete(repository):
    """Action to run when the installation is complete."""
    hacs = get_hacs()
    hacs.hass.bus.async_fire(
        "hacs/repository",
        {"id": 1337, "action": "install", "repository": repository.data.full_name},
    )
Пример #2
0
async def async_setup(hass, config):
    """Set up this integration using yaml."""
    hacs = get_hacs()
    if DOMAIN not in config:
        return True
    if hacs.configuration and hacs.configuration.config_type == "flow":
        return True

    configuration = config[DOMAIN]

    if configuration.get(FRONTEND_REPO) and configuration.get(
            FRONTEND_REPO_URL):
        hacs.logger.critical(
            "Could not setup HACS, set only one of ('frontend_repo', 'frontend_repo_url)"
        )

        return False

    hass.data[DOMAIN] = config
    hacs.hass = hass
    hacs.session = async_create_clientsession(hass)
    hacs.configuration = Configuration.from_dict(configuration)
    hacs.configuration.config = config
    hacs.configuration.config_type = "yaml"
    await startup_wrapper_for_yaml()
    return True
Пример #3
0
async def load_hacs_repository():
    """Load HACS repositroy."""
    hacs = get_hacs()
    from .const import VERSION
    from aiogithubapi import (
        AIOGitHubAuthentication,
        AIOGitHubException,
        AIOGitHubRatelimit,
    )

    try:
        repository = hacs.get_by_name("hacs/integration")
        if repository is None:
            await register_repository("hacs/integration", "integration")
            repository = hacs.get_by_name("hacs/integration")
        if repository is None:
            raise AIOGitHubException("Unknown error")
        repository.status.installed = True
        repository.versions.installed = VERSION
        repository.status.new = False
        hacs.repo = repository.repository_object
        hacs.data_repo = await get_repository(hacs.session,
                                              hacs.configuration.token,
                                              "hacs/default")
    except (
            AIOGitHubException,
            AIOGitHubRatelimit,
            AIOGitHubAuthentication,
    ) as exception:
        hacs.logger.critical(f"[{exception}] - Could not load HACS!")
        return False
    return True
Пример #4
0
def test_check_constrains(tmpdir):
    hacs = get_hacs()
    hacs.system.ha_version = HAVERSION
    hacs.system.config_path = tmpdir.dirname

    assert not check_constrains()

    translations_dir = f"{hacs.system.config_path}/custom_components/hacs/translations"
    os.makedirs(translations_dir, exist_ok=True)

    custom_updater_dir = f"{hacs.system.config_path}/custom_components/custom_updater"
    os.makedirs(custom_updater_dir, exist_ok=True)
    with open(f"{custom_updater_dir}/__init__.py", "w") as cufile:
        cufile.write("")

    assert not check_constrains()
    temp_cleanup(tmpdir)

    translations_dir = f"{hacs.system.config_path}/custom_components/hacs/translations"
    os.makedirs(translations_dir, exist_ok=True)

    hacs.system.ha_version = "0.97.0"
    assert not check_constrains()

    hacs.system.ha_version = HAVERSION

    translations_dir = f"{hacs.system.config_path}/custom_components/hacs/translations"
    os.makedirs(translations_dir, exist_ok=True)

    assert constrain_version()
    assert check_constrains()
    assert constrain_translations()

    temp_cleanup(tmpdir)
Пример #5
0
async def setup_frontend():
    """Configure the HACS frontend elements."""
    from .http import HacsFrontend
    from .ws_api_handlers import setup_ws_api

    hacs = get_hacs()

    hacs.hass.http.register_view(HacsFrontend())
    hacs.frontend.version_running = FE_VERSION

    # Add to sidepanel
    custom_panel_config = {
        "name": "hacs-frontend",
        "embed_iframe": False,
        "trust_external": False,
        "js_url": f"/hacsfiles/frontend-{hacs.frontend.version_running}.js",
    }

    config = {}
    config["_panel_custom"] = custom_panel_config

    hacs.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=config,
        require_admin=True,
    )

    if "frontend_extra_module_url" not in hacs.hass.data:
        hacs.hass.data["frontend_extra_module_url"] = set()
    hacs.hass.data["frontend_extra_module_url"].add("/hacsfiles/iconset.js")

    await setup_ws_api(hacs.hass)
Пример #6
0
async def async_setup_entry(hass, config_entry):
    """Set up this integration using UI."""
    hacs = get_hacs()
    conf = hass.data.get(DOMAIN)
    if conf is not None:
        return False
    if config_entry.source == config_entries.SOURCE_IMPORT:
        hass.async_create_task(hass.config_entries.async_remove(config_entry.entry_id))
        return False
    hacs.hass = hass
    hacs.session = async_create_clientsession(hass)
    hacs.configuration = Configuration.from_dict(
        config_entry.data, config_entry.options
    )
    hacs.configuration.config_type = "flow"
    hacs.configuration.config_entry = config_entry
    config_entry.add_update_listener(reload_hacs)
    try:
        startup_result = await hacs_startup()
    except AIOGitHubAPIException:
        startup_result = False
    if not startup_result:
        hacs.system.disabled = True
        raise ConfigEntryNotReady
    hacs.system.disabled = False
    return startup_result
Пример #7
0
async def test_common_base_exception_does_not_exsist(aresponses, event_loop):
    aresponses.add(
        "api.github.com",
        "/rate_limit",
        "get",
        aresponses.Response(headers=response_rate_limit_header_with_limit,
                            status=500),
    )
    aresponses.add(
        "api.github.com",
        "/repos/test/test",
        "get",
        aresponses.Response(
            body=json.dumps({"message": "X"}),
            headers=response_rate_limit_header_with_limit,
            status=500,
        ),
    )

    async with aiohttp.ClientSession(loop=event_loop) as session:
        hacs = get_hacs()
        hacs.session = session
        hacs.configuration = Configuration()
        hacs.configuration.token = TOKEN
        hacs.system.status.startup = False
        repository = dummy_repository_base()
        with pytest.raises(HacsException):
            await common_validate(repository)
Пример #8
0
async def test_common_blacklist(aresponses, event_loop):
    aresponses.add(
        "api.github.com",
        "/rate_limit",
        "get",
        aresponses.Response(body=b"{}",
                            headers=response_rate_limit_header,
                            status=200),
    )
    aresponses.add(
        "api.github.com",
        "/repos/test/test",
        "get",
        aresponses.Response(body=json.dumps(repository_data),
                            headers=response_rate_limit_header),
    )
    async with aiohttp.ClientSession(loop=event_loop) as session:
        hacs = get_hacs()
        hacs.session = session
        hacs.configuration = Configuration()
        hacs.configuration.token = TOKEN
        hacs.common.blacklist.append("test/test")
        repository = dummy_repository_base()
        with pytest.raises(HacsException):
            await common_validate(repository)
        hacs.common.blacklist = []
Пример #9
0
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
Пример #10
0
async def test_download_content(aresponses, tmp_path, event_loop):
    aresponses.add(
        "raw.githubusercontent.com",
        "/test/test/master/test/path/file.file",
        "get",
        aresponses.Response(body="test", headers=response_rate_limit_header),
    )

    repository = dummy_repository_base()
    repository.content.path.remote = ""
    repository.content.path.local = tmp_path
    repository.tree = [
        AIOGitHubAPIRepositoryTreeContent(
            {
                "path": "test/path/file.file",
                "type": "blob"
            }, "test/test", "master")
    ]
    async with aiohttp.ClientSession(loop=event_loop) as session:
        hacs = get_hacs()
        hacs.hass.loop = event_loop
        hacs.session = session
        await download_content(repository)
        assert os.path.exists(
            f"{repository.content.path.local}/test/path/file.file")
Пример #11
0
async def load_hacs_repository():
    """Load HACS repositroy."""
    hacs = get_hacs()

    try:
        repository = hacs.get_by_name("hacs/integration")
        if repository is None:
            await register_repository("hacs/integration", "integration")
            repository = hacs.get_by_name("hacs/integration")
        if repository is None:
            raise HacsException("Unknown error")
        repository.data.installed = True
        repository.data.installed_version = VERSION
        repository.data.new = False
        hacs.repo = repository.repository_object
        hacs.data_repo = await get_repository(hacs.session,
                                              hacs.configuration.token,
                                              "hacs/default")
    except HacsException as exception:
        if "403" in f"{exception}":
            hacs.logger.critical(
                "GitHub API is ratelimited, or the token is wrong.")
        else:
            hacs.logger.critical(f"[{exception}] - Could not load HACS!")
        return False
    return True
Пример #12
0
def constrain_translations():
    """Check if traslations exist."""
    hacs = get_hacs()
    if not os.path.exists(
            f"{hacs.system.config_path}/custom_components/hacs/.translations"):
        hacs.logger.critical("You are missing the translations directory.")
        return False
    return True
Пример #13
0
def read_hacs_manifest():
    """Reads the HACS manifest file and returns the contents."""
    hacs = get_hacs()
    content = {}
    with open(f"{hacs.system.config_path}/custom_components/hacs/manifest.json"
              ) as manifest:
        content = json.loads(manifest.read())
    return content
Пример #14
0
def clear_storage():
    """Clear old files from storage."""
    hacs = get_hacs()
    storagefiles = ["hacs"]
    for s_f in storagefiles:
        path = f"{hacs.system.config_path}/.storage/{s_f}"
        if os.path.isfile(path):
            os.remove(path)
Пример #15
0
def test_clear_storage(tmpdir):
    hacs = get_hacs()
    hacs.system.config_path = tmpdir.dirname
    os.makedirs(f"{hacs.system.config_path}/.storage")
    with open(f"{hacs.system.config_path}/.storage/hacs", "w") as h_f:
        h_f.write("")
    clear_storage()
    os.makedirs(f"{hacs.system.config_path}/.storage/hacs")
    clear_storage()
Пример #16
0
async def test_common_base_exception_tree_issues(aresponses, event_loop):
    aresponses.add(
        "api.github.com",
        "/rate_limit",
        "get",
        aresponses.Response(body=b"{}",
                            headers=response_rate_limit_header,
                            status=200),
    )
    aresponses.add(
        "api.github.com",
        "/repos/test/test",
        "get",
        aresponses.Response(body=json.dumps(repository_data),
                            headers=response_rate_limit_header),
    )
    aresponses.add(
        "api.github.com",
        "/rate_limit",
        "get",
        aresponses.Response(body=b"{}",
                            headers=response_rate_limit_header,
                            status=200),
    )
    aresponses.add(
        "api.github.com",
        "/repos/test/test/releases",
        "get",
        aresponses.Response(body=json.dumps(release_data),
                            headers=response_rate_limit_header),
    )
    aresponses.add(
        "api.github.com",
        "/rate_limit",
        "get",
        aresponses.Response(body=b"{}",
                            headers=response_rate_limit_header,
                            status=200),
    )
    aresponses.add(
        "api.github.com",
        "/repos/test/test/git/trees/3",
        "get",
        aresponses.Response(body=json.dumps({"message": "X"}),
                            headers=response_rate_limit_header),
    )

    async with aiohttp.ClientSession(loop=event_loop) as session:
        hacs = get_hacs()
        hacs.session = session
        hacs.configuration = Configuration()
        hacs.configuration.token = TOKEN
        repository = dummy_repository_base()
        hacs.common.blacklist = []
        hacs.system.status.startup = False
        with pytest.raises(HacsException):
            await common_validate(repository)
Пример #17
0
def clear_storage():
    """Clear old files from storage."""
    hacs = get_hacs()
    storagefiles = ["hacs"]
    for s_f in storagefiles:
        path = f"{hacs.system.config_path}/.storage/{s_f}"
        if os.path.isfile(path):
            hacs.logger.info(f"Cleaning up old storage file {path}")
            os.remove(path)
Пример #18
0
def setup_extra_stores():
    """Set up extra stores in HACS if enabled in Home Assistant."""
    hacs = get_hacs()
    if "python_script" in hacs.hass.config.components:
        hacs.common.categories.append("python_script")

    if hacs.hass.services.services.get("frontend",
                                       {}).get("reload_themes") is not None:
        hacs.common.categories.append("theme")
Пример #19
0
def constrain_version():
    """Check if the version is valid."""
    hacs = get_hacs()
    if not version_left_higher_then_right(hacs.system.ha_version, MINIMUM_HA_VERSION):
        hacs.logger.critical(
            f"You need HA version {MINIMUM_HA_VERSION} or newer to use this integration."
        )
        return False
    return True
Пример #20
0
    async def get(self, request, requested_file):  # pylint: disable=unused-argument
        """DEPRECATED."""
        hacs = get_hacs()
        if hacs.system.ha_version.split(".")[1] >= "107":
            logger = Logger("hacs.deprecated")
            logger.warning(
                "The '/community_plugin/*' is deprecated and will be removed in an upcoming version of HACS, it has been replaced by '/hacsfiles/*', if you use the UI to manage your lovelace configuration, you can update this by going to the settings tab in HACS, if you use YAML to manage your lovelace configuration, you manually need to replace the URL in your resources."
            )

        return await get_file_response(requested_file)
Пример #21
0
def constrain_custom_updater():
    """Check if custom_updater exist."""
    hacs = get_hacs()
    for location in CUSTOM_UPDATER_LOCATIONS:
        if os.path.exists(location.format(hacs.system.config_path)):
            msg = CUSTOM_UPDATER_WARNING.format(
                location.format(hacs.system.config_path))
            hacs.logger.critical(msg)
            return False
    return True
Пример #22
0
async def validate_repository(repository, category, ref=None):
    """Validate."""
    async with aiohttp.ClientSession() as session:
        hacs = get_hacs()
        hacs.session = session
        hacs.configuration = Configuration()
        hacs.configuration.token = TOKEN
        hacs.github = AIOGitHub(hacs.configuration.token, hacs.session)
        await register_repository(repository, category, ref=ref)
        print("All good!")
Пример #23
0
async def test_download_content_integration(aresponses, tmp_path, event_loop):
    aresponses.add(
        "raw.githubusercontent.com",
        aresponses.ANY,
        "get",
        aresponses.Response(body="", headers=response_rate_limit_header),
    )
    aresponses.add(
        "raw.githubusercontent.com",
        aresponses.ANY,
        "get",
        aresponses.Response(body="", headers=response_rate_limit_header),
    )
    aresponses.add(
        "raw.githubusercontent.com",
        aresponses.ANY,
        "get",
        aresponses.Response(body="", headers=response_rate_limit_header),
    )
    aresponses.add(
        "raw.githubusercontent.com",
        aresponses.ANY,
        "get",
        aresponses.Response(body="", headers=response_rate_limit_header),
    )
    hacs = get_hacs()
    hacs.system.config_path = tmp_path
    repository = dummy_repository_integration()
    repository.domain = "test"
    repository.content.path.local = repository.localpath
    repository.content.path.remote = "custom_components/test"
    integration_files = [
        "__init__.py",
        "sensor.py",
        ".translations/en.json",
        "manifest.json",
    ]
    for integration_file in integration_files:
        repository.tree.append(
            AIOGithubTreeContent(
                {
                    "path": f"custom_components/test/{integration_file}",
                    "type": "blob"
                },
                "test/test",
                "master",
            ))

    async with aiohttp.ClientSession(loop=event_loop) as session:
        hacs.hass.loop = event_loop
        hacs.session = session
        await download_content(repository)
        for path in repository.tree:
            assert os.path.exists(
                f"{hacs.system.config_path}/{path.full_path}")
Пример #24
0
async def get_file_response(requested_file):
    """Get file."""
    hacs = get_hacs()

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

    if requested_file.startswith("frontend-"):
        if hacs.configuration.debug:
            servefile = await hacs.hass.async_add_executor_job(locate_debug_gz)
            hacs.logger.debug("Serving DEBUG frontend")
        elif hacs.configuration.frontend_repo:
            hacs.logger.debug("Serving DEVELOPMENT frontend")
            servefile = f"{hacs.configuration.frontend_repo}/hacs_frontend/main.js"
        else:
            servefile = await hacs.hass.async_add_executor_job(locate_gz)

        if os.path.exists(servefile):
            if hacs.configuration.frontend_repo:
                response = web.FileResponse(servefile)
                response.headers["Cache-Control"] = "no-store, max-age=0"
                response.headers["Pragma"] = "no-store"
                return response
            return web.FileResponse(servefile)
    elif requested_file == "iconset.js":
        return web.FileResponse(
            f"{hacs.system.config_path}/custom_components/hacs/iconset.js")

    try:
        if requested_file.startswith("themes"):
            file = f"{hacs.system.config_path}/{requested_file}"
        else:
            file = f"{hacs.system.config_path}/www/community/{requested_file}"

        # Serve .gz if it exist
        if os.path.exists(file + ".gz"):
            file += ".gz"

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

    except Exception as error:  # pylint: disable=broad-except
        hacs.logger.debug("there was an issue trying to serve {} - {}".format(
            requested_file, error))

    return web.Response(status=404)
Пример #25
0
def test_translations(tmpdir):
    hacs = get_hacs()
    hacs.system.config_path = tmpdir.dirname

    assert not constrain_translations()

    translations_dir = f"{hacs.system.config_path}/custom_components/hacs/translations"
    os.makedirs(translations_dir, exist_ok=True)
    assert constrain_translations()

    temp_cleanup(tmpdir)
Пример #26
0
async def hacs_repositories(hass, connection, msg):
    """Handle get media player cover command."""
    hacs = get_hacs()
    repositories = hacs.repositories
    content = []
    for repo in repositories:
        if repo.data.category in hacs.common.categories:
            data = {
                "additional_info": repo.information.additional_info,
                "authors": repo.data.authors,
                "available_version": repo.display_available_version,
                "beta": repo.data.show_beta,
                "can_install": repo.can_install,
                "category": repo.data.category,
                "country": repo.data.country,
                "config_flow": repo.data.config_flow,
                "custom": repo.custom,
                "default_branch": repo.data.default_branch,
                "description": repo.data.description,
                "domain": repo.data.domain,
                "downloads": repo.data.downloads,
                "file_name": repo.data.file_name,
                "first_install": repo.status.first_install,
                "full_name": repo.data.full_name,
                "hide": repo.data.hide,
                "hide_default_branch": repo.data.hide_default_branch,
                "homeassistant": repo.data.homeassistant,
                "id": repo.data.id,
                "info": repo.information.info,
                "installed_version": repo.display_installed_version,
                "installed": repo.data.installed,
                "issues": repo.data.open_issues,
                "javascript_type": repo.information.javascript_type,
                "last_updated": repo.data.last_updated,
                "local_path": repo.content.path.local,
                "main_action": repo.main_action,
                "name": repo.display_name,
                "new": repo.data.new,
                "pending_upgrade": repo.pending_upgrade,
                "releases": repo.data.published_tags,
                "selected_tag": repo.data.selected_tag,
                "stars": repo.data.stargazers_count,
                "state": repo.state,
                "status_description": repo.display_status_description,
                "status": repo.display_status,
                "topics": repo.data.topics,
                "updated_info": repo.status.updated_info,
                "version_or_commit": repo.display_version_or_commit,
            }

            content.append(data)

    connection.send_message(websocket_api.result_message(msg["id"], content))
Пример #27
0
async def hacs_settings(hass, connection, msg):
    """Handle get media player cover command."""
    hacs = get_hacs()
    action = msg["action"]
    hacs.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 == "reload_data":
        hacs.system.status.reloading_data = True
        hass.bus.async_fire("hacs/status", {})
        await hacs.recuring_tasks_all()
        hacs.system.status.reloading_data = False
        hass.bus.async_fire("hacs/status", {})

    elif action == "upgrade_all":
        hacs.system.status.upgrading_all = True
        hacs.system.status.background_task = True
        hass.bus.async_fire("hacs/status", {})
        for repository in hacs.repositories:
            if repository.pending_upgrade:
                repository.status.selected_tag = None
                await repository.install()
        hacs.system.status.upgrading_all = False
        hacs.system.status.background_task = False
        hass.bus.async_fire("hacs/status", {})
        hass.bus.async_fire("hacs/repository", {})

    elif action == "clear_new":
        for repo in hacs.repositories:
            if msg.get("category") == repo.information.category:
                if repo.status.new:
                    hacs.logger.debug(
                        f"Clearing new flag from '{repo.information.full_name}'"
                    )
                    repo.status.new = False
    else:
        hacs.logger.error(f"WS action '{action}' is not valid")
    hass.bus.async_fire("hacs/config", {})
    await hacs.data.async_write()
Пример #28
0
    async def async_step_user(self, user_input=None):
        """Handle a flow initialized by the user."""
        hacs = get_hacs()
        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)

        if hacs.configuration.config_type == "yaml":
            schema = {vol.Optional("not_in_use", default=""): str}
        else:
            schema = hacs_config_option_schema(self.config_entry.options)

        return self.async_show_form(step_id="user", data_schema=vol.Schema(schema))
Пример #29
0
async def hacs_status(hass, connection, msg):
    """Handle get media player cover command."""
    hacs = get_hacs()
    content = {
        "startup": hacs.system.status.startup,
        "background_task": hacs.system.status.background_task,
        "lovelace_mode": hacs.system.lovelace_mode,
        "reloading_data": hacs.system.status.reloading_data,
        "upgrading_all": hacs.system.status.upgrading_all,
        "disabled": hacs.system.disabled,
    }
    connection.send_message(websocket_api.result_message(msg["id"], content))
Пример #30
0
async def validate_repository(repository, category, ref=None):
    """Validate."""
    async with aiohttp.ClientSession() as session:
        hacs = get_hacs()
        hacs.session = session
        hacs.configuration = Configuration()
        hacs.configuration.token = TOKEN
        hacs.github = GitHub(hacs.configuration.token, hacs.session)
        try:
            await register_repository(repository, category, ref=ref, action=True)
        except HacsException as exception:
            exit(exception)
        print("All good!")