コード例 #1
0
def test_check_package_global():
    """Test for an installed package."""
    first_package = list(pkg_resources.working_set)[0]
    installed_package = first_package.project_name
    installed_version = first_package.version

    assert package.is_installed(installed_package)
    assert package.is_installed(f"{installed_package}=={installed_version}")
    assert package.is_installed(f"{installed_package}>={installed_version}")
    assert package.is_installed(f"{installed_package}<={installed_version}")
    assert not package.is_installed(f"{installed_package}<{installed_version}")
コード例 #2
0
def test_check_package_previous_failed_install():
    """Test for when a previously install package failed and left cruft behind."""
    first_package = list(pkg_resources.working_set)[0]
    installed_package = first_package.project_name
    installed_version = first_package.version

    with patch(
            "homeassistant.util.package.pkg_resources.get_distribution",
            side_effect=pkg_resources.ExtractionError,
    ), patch("homeassistant.util.package.version", return_value=None):
        assert not package.is_installed(installed_package)
        assert not package.is_installed(
            f"{installed_package}=={installed_version}")
コード例 #3
0
def install_requirements(integration: Integration, requirements: Set[str]) -> bool:
    """Install integration requirements.

    Return True if successful.
    """
    global PIPDEPTREE_CACHE

    ensure_cache()

    for req in requirements:
        match = PIP_REGEX.search(req)

        if not match:
            integration.add_error(
                "requirements",
                f"Failed to parse requirement {req} before installation",
            )
            continue

        install_args = match.group(1)
        requirement_arg = match.group(2)

        is_installed = False

        normalized = normalize_package_name(requirement_arg)

        if normalized and "==" in requirement_arg:
            ver = requirement_arg.split("==")[-1]
            item = PIPDEPTREE_CACHE.get(normalized)
            is_installed = item and item["installed_version"] == ver

        if not is_installed:
            try:
                is_installed = pkg_util.is_installed(req)
            except ValueError:
                is_installed = False

        if is_installed:
            continue

        args = [sys.executable, "-m", "pip", "install", "--quiet"]
        if install_args:
            args.append(install_args)
        args.append(requirement_arg)
        try:
            result = subprocess.run(args, check=True, capture_output=True, text=True)
        except subprocess.SubprocessError:
            integration.add_error(
                "requirements",
                f"Requirement {req} failed to install",
            )
        else:
            # Clear the pipdeptree cache if something got installed
            if "Successfully installed" in result.stdout:
                PIPDEPTREE_CACHE = None

    if integration.errors:
        return False

    return True
コード例 #4
0
async def async_process_requirements(hass: HomeAssistant, name: str,
                                     requirements: list[str]) -> None:
    """Install the requirements for a component or platform.

    This method is a coroutine. It will raise RequirementsNotFound
    if an requirement can't be satisfied.
    """
    pip_lock = hass.data.get(DATA_PIP_LOCK)
    if pip_lock is None:
        pip_lock = hass.data[DATA_PIP_LOCK] = asyncio.Lock()

    kwargs = pip_kwargs(hass.config.config_dir)

    async with pip_lock:
        for req in requirements:
            if pkg_util.is_installed(req):
                continue

            def _install(req: str, kwargs: dict[str, Any]) -> bool:
                """Install requirement."""
                return pkg_util.install_package(req, **kwargs)

            ret = await hass.async_add_executor_job(_install, req, kwargs)

            if not ret:
                raise RequirementsNotFound(name, [req])
コード例 #5
0
async def async_process_requirements(hass: HomeAssistant, name: str,
                                     requirements: List[str]) -> bool:
    """Install the requirements for a component or platform.

    This method is a coroutine.
    """
    pip_lock = hass.data.get(DATA_PIP_LOCK)
    if pip_lock is None:
        pip_lock = hass.data[DATA_PIP_LOCK] = asyncio.Lock()

    kwargs = pip_kwargs(hass.config.config_dir)

    async with pip_lock:
        for req in requirements:
            if pkg_util.is_installed(req):
                continue

            ret = await hass.async_add_executor_job(_install, hass, req,
                                                    kwargs)

            if not ret:
                _LOGGER.error(
                    "Not initializing %s because could not install "
                    "requirement %s",
                    name,
                    req,
                )
                return False

    return True
コード例 #6
0
async def _async_process_requirements(
    hass: HomeAssistant,
    name: str,
    req: str,
    install_failure_history: set[str],
    kwargs: Any,
) -> None:
    """Install a requirement and save failures."""
    if req in install_failure_history:
        _LOGGER.info(
            "Multiple attempts to install %s failed, install will be retried after next configuration check or restart",
            req,
        )
        raise RequirementsNotFound(name, [req])

    if pkg_util.is_installed(req):
        return

    def _install(req: str, kwargs: dict[str, Any]) -> bool:
        """Install requirement."""
        return pkg_util.install_package(req, **kwargs)

    for _ in range(MAX_INSTALL_FAILURES):
        if await hass.async_add_executor_job(_install, req, kwargs):
            return

    install_failure_history.add(req)
    raise RequirementsNotFound(name, [req])
コード例 #7
0
def test_get_distribution_falls_back_to_version():
    """Test for get_distribution failing and fallback to version."""
    first_package = list(pkg_resources.working_set)[0]
    installed_package = first_package.project_name
    installed_version = first_package.version

    with patch(
            "homeassistant.util.package.pkg_resources.get_distribution",
            side_effect=pkg_resources.ExtractionError,
    ):
        assert package.is_installed(installed_package)
        assert package.is_installed(
            f"{installed_package}=={installed_version}")
        assert package.is_installed(
            f"{installed_package}>={installed_version}")
        assert package.is_installed(
            f"{installed_package}<={installed_version}")
        assert not package.is_installed(
            f"{installed_package}<{installed_version}")
コード例 #8
0
def run(args: List) -> int:
    """Run a script."""
    scripts = []
    path = os.path.dirname(__file__)
    for fil in os.listdir(path):
        if fil == "__pycache__":
            continue

        if os.path.isdir(os.path.join(path, fil)):
            scripts.append(fil)
        elif fil != "__init__.py" and fil.endswith(".py"):
            scripts.append(fil[:-3])

    if not args:
        print("Please specify a script to run.")
        print("Available scripts:", ", ".join(scripts))
        return 1

    if args[0] not in scripts:
        print("Invalid script specified.")
        print("Available scripts:", ", ".join(scripts))
        return 1

    script = importlib.import_module(f"homeassistant.scripts.{args[0]}")

    config_dir = extract_config_dir()

    loop = asyncio.get_event_loop()

    if not is_virtual_env():
        loop.run_until_complete(async_mount_local_lib_path(config_dir))

    _pip_kwargs = pip_kwargs(config_dir)

    logging.basicConfig(stream=sys.stdout, level=logging.INFO)

    for req in getattr(script, "REQUIREMENTS", []):
        if is_installed(req):
            continue

        if not install_package(req, **_pip_kwargs):
            print("Aborting script, could not install dependency", req)
            return 1

    asyncio.set_event_loop_policy(runner.HassEventLoopPolicy(False))

    return script.run(args[1:])  # type: ignore
コード例 #9
0
def run(args: List) -> int:
    """Run a script."""
    scripts = []
    path = os.path.dirname(__file__)
    for fil in os.listdir(path):
        if fil == '__pycache__':
            continue
        elif os.path.isdir(os.path.join(path, fil)):
            scripts.append(fil)
        elif fil != '__init__.py' and fil.endswith('.py'):
            scripts.append(fil[:-3])

    if not args:
        print('Please specify a script to run.')
        print('Available scripts:', ', '.join(scripts))
        return 1

    if args[0] not in scripts:
        print('Invalid script specified.')
        print('Available scripts:', ', '.join(scripts))
        return 1

    script = importlib.import_module('homeassistant.scripts.' + args[0])

    config_dir = extract_config_dir()

    loop = asyncio.get_event_loop()

    if not is_virtual_env():
        loop.run_until_complete(async_mount_local_lib_path(config_dir))

    _pip_kwargs = pip_kwargs(config_dir)

    logging.basicConfig(stream=sys.stdout, level=logging.INFO)

    for req in getattr(script, 'REQUIREMENTS', []):
        if is_installed(req):
            continue

        if not install_package(req, **_pip_kwargs):
            print('Aborting script, could not install dependency', req)
            return 1

    return script.run(args[1:])  # type: ignore
コード例 #10
0
def install_requirements(integration: Integration,
                         requirements: Set[str]) -> bool:
    """Install integration requirements.

    Return True if successful.
    """
    for req in requirements:
        try:
            is_installed = pkg_util.is_installed(req)
        except ValueError:
            is_installed = False

        if is_installed:
            continue

        match = PIP_REGEX.search(req)

        if not match:
            integration.add_error(
                "requirements",
                f"Failed to parse requirement {req} before installation",
            )
            continue

        install_args = match.group(1)
        requirement_arg = match.group(2)

        args = [sys.executable, "-m", "pip", "install", "--quiet"]
        if install_args:
            args.append(install_args)
        args.append(requirement_arg)
        try:
            subprocess.run(args, check=True)
        except subprocess.SubprocessError:
            integration.add_error(
                "requirements",
                f"Requirement {req} failed to install",
            )

    if integration.errors:
        return False

    return True
コード例 #11
0
def test_check_package_zip():
    """Test for an installed zip package."""
    assert not package.is_installed(TEST_ZIP_REQ)
コード例 #12
0
def test_check_package_version_does_not_match():
    """Test for version mismatch."""
    installed_package = list(pkg_resources.working_set)[0].project_name
    assert not package.is_installed(f"{installed_package}==999.999.999")
    assert not package.is_installed(f"{installed_package}>=999.999.999")
コード例 #13
0
def test_check_package_global():
    """Test for an installed package."""
    installed_package = list(pkg_resources.working_set)[0].project_name
    assert package.is_installed(installed_package)
コード例 #14
0
 async def post(self, request):
     hass = request.app["hass"]
     fileExplorer = hass.data[DOMAIN]
     res = await request.json()
     _type = res.get('type', '')
     _url = res.get('url', '')
     _path = hass.config.path('./' + res.get('path', ''))
     try:
         if _type == 'get':
             # 获取目录和文件
             data = fileExplorer.getDirectory(_path)
             return self.json(data)
         elif _type == 'get-content':
             # 获取文件内容
             data = fileExplorer.getContent(_path)
             return self.json({'code': 0, 'data': data})
         elif _type == 'get-cloud-list':
             # 获取七牛云备份列表
             return self.json({'code': 0, 'data': []})
         elif _type == 'delete':
             # 删除文件
             fileExplorer.delete(_path)
             return self.json({'code': 0, 'msg': '删除成功'})
         elif _type == 'delete-qiniu':
             # 删除备份文件
             return self.json({'code': 0, 'msg': '删除成功'})
         elif _type == 'new-file':
             # 新建文件
             data = res.get('data', '')
             fileExplorer.setContent(_path, data)
             return self.json({'code': 0, 'msg': '保存成功'})
         elif _type == 'new-dir':
             # 新建文件夹
             fileExplorer.mkdir(_path)
             return self.json({'code': 0, 'msg': '新建成功'})
         elif _type == 'upload-file':
             # 上传文件
             return self.json({'code': 0, 'msg': '上传文件成功'})
         elif _type == 'upload-dir':
             # 上传文件夹
             return self.json({'code': 0, 'msg': '上传文件夹成功'})
         elif _type == 'download-url':
             # 下载网络文件到文件夹
             print(_url)
             down_res = None
             # 下载文件流
             async with aiohttp.request('GET', _url) as r:
                 down_res = await r.read()
             # 保存文件
             with open(_path + '/' + os.path.basename(_url), "wb") as code:
                 code.write(down_res)
             return self.json({'code': 0, 'msg': '下载成功'})
         elif _type == 'download-tmpfile':
             # 下载临时文件
             print(_url)
             down_res = None
             async with aiohttp.request('GET', _url) as r:
                 down_res = await r.read()
             # 获取临时文件目录
             _path = tempfile.gettempdir()
             backup_path = _path + '/ha_file_explorer_backup.zip'
             with open(backup_path, "wb") as code:
                 code.write(down_res)
             # 解压文件
             fileExplorer.unzip(backup_path,
                                _path + '/ha_file_explorer_backup')
             # 删除下截的备份文件
             fileExplorer.delete(backup_path)
             # 返回文件夹里的数据
             return self.json({
                 'code':
                 0,
                 'data':
                 fileExplorer.getAllFile(_path +
                                         '/ha_file_explorer_backup'),
                 'msg':
                 '下载成功'
             })
         elif _type == 'rename':
             rename_path = hass.config.path(f"./{res['rename_path']}")
             os.rename(_path, rename_path)
             return self.json({'code': 0, 'msg': '重命名成功'})
         ## ====================== 七牛云 ==========================
         elif _type == 'qn-list':
             if fileExplorer.q is None:
                 return self.json({'code': 1, 'msg': '请配置七牛云相关密钥信息'})
             try:
                 res = await fileExplorer.q.get_list(None)
                 # print('测试一下:', res)
                 return self.json({'code': 0, 'msg': '获取备份列表', 'data': res})
             except Exception as e:
                 print(e)
                 return self.json({
                     'code': 1,
                     'msg': '备份列表获取异常,请检查是否正确配置七牛云密钥'
                 })
         elif _type == 'qn-upload':
             if fileExplorer.q is None:
                 return self.json({'code': 1, 'msg': '请配置七牛云相关密钥信息'})
             if 'path' in res:
                 zf = fileExplorer.zipdir(res['path'])
             elif 'list' in res:
                 # 压缩多个文件
                 zf = fileExplorer.zip(res['list'])
             try:
                 await fileExplorer.q.upload(zf)
                 # 上传成功,删除文件
                 fileExplorer.delete(zf)
                 return self.json({'code': 0, 'msg': '上传成功'})
             except Exception as ex:
                 print(ex)
                 return self.json({
                     'code': 1,
                     'msg': '上传错误,一般是七牛云不能创建配置文件的权限问题'
                 })
         elif _type == 'qn-delete':
             if fileExplorer.q is None:
                 return self.json({'code': 1, 'msg': '请配置七牛云相关密钥信息'})
             await fileExplorer.q.delete(res.get('key'))
             return self.json({'code': 0, 'msg': '删除成功'})
         ## ====================== 移动文件 ==========================
         elif _type == 'move-file':
             # 移动文件
             return self.json({'code': 0, 'msg': '移动文件成功'})
         elif _type == 'move-tmpfile':
             # 还原数据
             fileExplorer.move(res['list'])
             await fileExplorer.notify("还原成功")
             return self.json({'code': 0, 'msg': '还原成功'})
         elif _type == 'install-package':
             # 安装依赖包
             package_name = _url
             if package.is_installed(package_name) == False:
                 package.install_package(package_name)
                 return self.json({'code': 0, 'msg': '正在更新依赖包'})
             return self.json({'code': 0, 'msg': '已经安装成功啦'})
         elif _type == 'update-package':
             # 更新系统依赖包
             data = pip_install(_url)
             return self.json({'code': 0, 'data': data, 'msg': '更新依赖包完成'})
         elif _type == 'update':
             # 拉取组件
             _domain = res['domain']
             _path = hass.config.path("custom_components").replace(
                 '\\', '/')
             # https://github.com.cnpmjs.org/shaonianzhentan/$DOMAIN
             with open(_path + '/' + DOMAIN + '/update.sh',
                       'r',
                       encoding='utf-8') as f:
                 arr = _url.split('/')
                 content = f.read().replace('$PATH', _path).replace(
                     '$DOMAIN',
                     _domain).replace('$URL',
                                      _url).replace('$PROJECT',
                                                    arr[len(arr) - 1])
             # 获取临时文件目录
             tmp_path = tempfile.gettempdir()
             _sh = tmp_path + '/' + _domain + '.sh'
             with open(_sh, 'w', encoding='utf-8') as f:
                 f.write(content)
             # 如果是windows则直接运行
             _cmd = 'bash ' + _sh
             if os.name == 'nt':
                 _cmd = _sh
             subprocess.Popen(_cmd, shell=True)
             return self.json({'code': 0, 'msg': '正在异步拉取代码,请自行查看是否成功'})
     except Exception as ex:
         print(ex)
         return self.json({'code': 1, 'msg': f'出现异常:{ex}'})
     return self.json(res)