Support Hass.io wheels / docker env (#24175)
* Support Hass.io wheels / docker env * address comments * fix lintpull/24185/head
parent
6aeccf0330
commit
d9852bc75d
|
@ -47,6 +47,9 @@ def pip_kwargs(config_dir: Optional[str]) -> Dict[str, Any]:
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'constraints': os.path.join(os.path.dirname(__file__), CONSTRAINT_FILE)
|
'constraints': os.path.join(os.path.dirname(__file__), CONSTRAINT_FILE)
|
||||||
}
|
}
|
||||||
if not (config_dir is None or pkg_util.is_virtual_env()):
|
if 'WHEELS_LINKS' in os.environ:
|
||||||
|
kwargs['find_links'] = os.environ['WHEELS_LINKS']
|
||||||
|
if not (config_dir is None or pkg_util.is_virtual_env()) and \
|
||||||
|
not pkg_util.is_docker_env():
|
||||||
kwargs['target'] = os.path.join(config_dir, 'deps')
|
kwargs['target'] = os.path.join(config_dir, 'deps')
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
|
@ -6,6 +6,7 @@ from subprocess import PIPE, Popen
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from importlib_metadata import version, PackageNotFoundError
|
from importlib_metadata import version, PackageNotFoundError
|
||||||
|
@ -21,6 +22,11 @@ def is_virtual_env() -> bool:
|
||||||
hasattr(sys, 'real_prefix'))
|
hasattr(sys, 'real_prefix'))
|
||||||
|
|
||||||
|
|
||||||
|
def is_docker_env() -> bool:
|
||||||
|
"""Return True if we run in a docker env."""
|
||||||
|
return Path("/.dockerenv").exists()
|
||||||
|
|
||||||
|
|
||||||
def is_installed(package: str) -> bool:
|
def is_installed(package: str) -> bool:
|
||||||
"""Check if a package is installed and will be loaded when we import it.
|
"""Check if a package is installed and will be loaded when we import it.
|
||||||
|
|
||||||
|
@ -42,7 +48,8 @@ def is_installed(package: str) -> bool:
|
||||||
|
|
||||||
def install_package(package: str, upgrade: bool = True,
|
def install_package(package: str, upgrade: bool = True,
|
||||||
target: Optional[str] = None,
|
target: Optional[str] = None,
|
||||||
constraints: Optional[str] = None) -> bool:
|
constraints: Optional[str] = None,
|
||||||
|
find_links: Optional[str] = None) -> bool:
|
||||||
"""Install a package on PyPi. Accepts pip compatible package strings.
|
"""Install a package on PyPi. Accepts pip compatible package strings.
|
||||||
|
|
||||||
Return boolean if install successful.
|
Return boolean if install successful.
|
||||||
|
@ -55,6 +62,8 @@ def install_package(package: str, upgrade: bool = True,
|
||||||
args.append('--upgrade')
|
args.append('--upgrade')
|
||||||
if constraints is not None:
|
if constraints is not None:
|
||||||
args += ['--constraint', constraints]
|
args += ['--constraint', constraints]
|
||||||
|
if find_links is not None:
|
||||||
|
args += ['--find-links', find_links]
|
||||||
if target:
|
if target:
|
||||||
assert not is_virtual_env()
|
assert not is_virtual_env()
|
||||||
# This only works if not running in venv
|
# This only works if not running in venv
|
||||||
|
|
|
@ -27,9 +27,10 @@ class TestRequirements:
|
||||||
|
|
||||||
@patch('os.path.dirname')
|
@patch('os.path.dirname')
|
||||||
@patch('homeassistant.util.package.is_virtual_env', return_value=True)
|
@patch('homeassistant.util.package.is_virtual_env', return_value=True)
|
||||||
|
@patch('homeassistant.util.package.is_docker_env', return_value=False)
|
||||||
@patch('homeassistant.util.package.install_package', return_value=True)
|
@patch('homeassistant.util.package.install_package', return_value=True)
|
||||||
def test_requirement_installed_in_venv(
|
def test_requirement_installed_in_venv(
|
||||||
self, mock_install, mock_venv, mock_dirname):
|
self, mock_install, mock_venv, mock_denv, mock_dirname):
|
||||||
"""Test requirement installed in virtual environment."""
|
"""Test requirement installed in virtual environment."""
|
||||||
mock_venv.return_value = True
|
mock_venv.return_value = True
|
||||||
mock_dirname.return_value = 'ha_package_path'
|
mock_dirname.return_value = 'ha_package_path'
|
||||||
|
@ -45,9 +46,10 @@ class TestRequirements:
|
||||||
|
|
||||||
@patch('os.path.dirname')
|
@patch('os.path.dirname')
|
||||||
@patch('homeassistant.util.package.is_virtual_env', return_value=False)
|
@patch('homeassistant.util.package.is_virtual_env', return_value=False)
|
||||||
|
@patch('homeassistant.util.package.is_docker_env', return_value=False)
|
||||||
@patch('homeassistant.util.package.install_package', return_value=True)
|
@patch('homeassistant.util.package.install_package', return_value=True)
|
||||||
def test_requirement_installed_in_deps(
|
def test_requirement_installed_in_deps(
|
||||||
self, mock_install, mock_venv, mock_dirname):
|
self, mock_install, mock_venv, mock_denv, mock_dirname):
|
||||||
"""Test requirement installed in deps directory."""
|
"""Test requirement installed in deps directory."""
|
||||||
mock_dirname.return_value = 'ha_package_path'
|
mock_dirname.return_value = 'ha_package_path'
|
||||||
self.hass.config.skip_pip = False
|
self.hass.config.skip_pip = False
|
||||||
|
@ -77,3 +79,60 @@ async def test_install_existing_package(hass):
|
||||||
hass, 'test_component', ['hello==1.0.0'])
|
hass, 'test_component', ['hello==1.0.0'])
|
||||||
|
|
||||||
assert len(mock_inst.mock_calls) == 0
|
assert len(mock_inst.mock_calls) == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_install_with_wheels_index(hass):
|
||||||
|
"""Test an install attempt with wheels index URL."""
|
||||||
|
hass.config.skip_pip = False
|
||||||
|
mock_integration(
|
||||||
|
hass, MockModule('comp', requirements=['hello==1.0.0']))
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
'homeassistant.util.package.is_installed', return_value=False
|
||||||
|
), \
|
||||||
|
patch(
|
||||||
|
'homeassistant.util.package.is_docker_env', return_value=True
|
||||||
|
), \
|
||||||
|
patch(
|
||||||
|
'homeassistant.util.package.install_package'
|
||||||
|
) as mock_inst, \
|
||||||
|
patch.dict(
|
||||||
|
os.environ, {'WHEELS_LINKS': "https://wheels.hass.io/test"}
|
||||||
|
), \
|
||||||
|
patch(
|
||||||
|
'os.path.dirname'
|
||||||
|
) as mock_dir:
|
||||||
|
mock_dir.return_value = 'ha_package_path'
|
||||||
|
assert await setup.async_setup_component(hass, 'comp', {})
|
||||||
|
assert 'comp' in hass.config.components
|
||||||
|
print(mock_inst.call_args)
|
||||||
|
assert mock_inst.call_args == call(
|
||||||
|
'hello==1.0.0', find_links="https://wheels.hass.io/test",
|
||||||
|
constraints=os.path.join('ha_package_path', CONSTRAINT_FILE))
|
||||||
|
|
||||||
|
|
||||||
|
async def test_install_on_docker(hass):
|
||||||
|
"""Test an install attempt on an docker system env."""
|
||||||
|
hass.config.skip_pip = False
|
||||||
|
mock_integration(
|
||||||
|
hass, MockModule('comp', requirements=['hello==1.0.0']))
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
'homeassistant.util.package.is_installed', return_value=False
|
||||||
|
), \
|
||||||
|
patch(
|
||||||
|
'homeassistant.util.package.is_docker_env', return_value=True
|
||||||
|
), \
|
||||||
|
patch(
|
||||||
|
'homeassistant.util.package.install_package'
|
||||||
|
) as mock_inst, \
|
||||||
|
patch(
|
||||||
|
'os.path.dirname'
|
||||||
|
) as mock_dir:
|
||||||
|
mock_dir.return_value = 'ha_package_path'
|
||||||
|
assert await setup.async_setup_component(hass, 'comp', {})
|
||||||
|
assert 'comp' in hass.config.components
|
||||||
|
print(mock_inst.call_args)
|
||||||
|
assert mock_inst.call_args == call(
|
||||||
|
'hello==1.0.0',
|
||||||
|
constraints=os.path.join('ha_package_path', CONSTRAINT_FILE))
|
||||||
|
|
|
@ -167,6 +167,23 @@ def test_install_constraint(mock_sys, mock_popen, mock_env_copy, mock_venv):
|
||||||
assert mock_popen.return_value.communicate.call_count == 1
|
assert mock_popen.return_value.communicate.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_find_links(mock_sys, mock_popen, mock_env_copy, mock_venv):
|
||||||
|
"""Test install with find-links on not installed package."""
|
||||||
|
env = mock_env_copy()
|
||||||
|
link = 'https://wheels-repository'
|
||||||
|
assert package.install_package(
|
||||||
|
TEST_NEW_REQ, False, find_links=link)
|
||||||
|
assert mock_popen.call_count == 1
|
||||||
|
assert (
|
||||||
|
mock_popen.call_args ==
|
||||||
|
call([
|
||||||
|
mock_sys.executable, '-m', 'pip', 'install', '--quiet',
|
||||||
|
TEST_NEW_REQ, '--find-links', link
|
||||||
|
], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
|
||||||
|
)
|
||||||
|
assert mock_popen.return_value.communicate.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_async_get_user_site(mock_env_copy):
|
def test_async_get_user_site(mock_env_copy):
|
||||||
"""Test async get user site directory."""
|
"""Test async get user site directory."""
|
||||||
|
|
Loading…
Reference in New Issue