Esempio n. 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},
    )
Esempio n. 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
Esempio n. 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
Esempio n. 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)
Esempio n. 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)
Esempio n. 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
Esempio n. 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)
Esempio n. 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 = []
Esempio n. 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
Esempio n. 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")
Esempio n. 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
Esempio n. 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
Esempio n. 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
Esempio n. 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)
Esempio n. 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()
Esempio n. 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)
Esempio n. 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)
Esempio n. 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")
Esempio n. 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
Esempio n. 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)
Esempio n. 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
Esempio n. 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!")
Esempio n. 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}")
Esempio n. 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)
Esempio n. 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)
Esempio n. 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))
Esempio n. 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()
Esempio n. 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))
Esempio n. 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))
Esempio n. 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!")