Create progress file for pip installs (#24297)

* Create progress file for pip installs

* fix dedlock

* unflacky test

* Address comments

* Lint

* Types
This commit is contained in:
Pascal Vizeli 2019-06-04 20:04:20 +02:00 committed by Paulus Schoutsen
parent d7c8adc085
commit bf52aa8ccc
2 changed files with 37 additions and 5 deletions

View file

@ -1,6 +1,6 @@
"""Module to handle installing requirements.""" """Module to handle installing requirements."""
import asyncio import asyncio
from functools import partial from pathlib import Path
import logging import logging
import os import os
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
@ -11,6 +11,7 @@ from homeassistant.core import HomeAssistant
DATA_PIP_LOCK = 'pip_lock' DATA_PIP_LOCK = 'pip_lock'
DATA_PKG_CACHE = 'pkg_cache' DATA_PKG_CACHE = 'pkg_cache'
CONSTRAINT_FILE = 'package_constraints.txt' CONSTRAINT_FILE = 'package_constraints.txt'
PROGRESS_FILE = '.pip_progress'
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -24,15 +25,16 @@ async def async_process_requirements(hass: HomeAssistant, name: str,
if pip_lock is None: if pip_lock is None:
pip_lock = hass.data[DATA_PIP_LOCK] = asyncio.Lock() pip_lock = hass.data[DATA_PIP_LOCK] = asyncio.Lock()
pip_install = partial(pkg_util.install_package, kwargs = pip_kwargs(hass.config.config_dir)
**pip_kwargs(hass.config.config_dir))
async with pip_lock: async with pip_lock:
for req in requirements: for req in requirements:
if pkg_util.is_installed(req): if pkg_util.is_installed(req):
continue continue
ret = await hass.async_add_executor_job(pip_install, req) ret = await hass.async_add_executor_job(
_install, hass, req, kwargs
)
if not ret: if not ret:
_LOGGER.error("Not initializing %s because could not install " _LOGGER.error("Not initializing %s because could not install "
@ -42,6 +44,16 @@ async def async_process_requirements(hass: HomeAssistant, name: str,
return True return True
def _install(hass: HomeAssistant, req: str, kwargs: Dict) -> bool:
"""Install requirement."""
progress_path = Path(hass.config.path(PROGRESS_FILE))
progress_path.touch()
try:
return pkg_util.install_package(req, **kwargs)
finally:
progress_path.unlink()
def pip_kwargs(config_dir: Optional[str]) -> Dict[str, Any]: def pip_kwargs(config_dir: Optional[str]) -> Dict[str, Any]:
"""Return keyword arguments for PIP install.""" """Return keyword arguments for PIP install."""
is_docker = pkg_util.is_docker_env() is_docker = pkg_util.is_docker_env()

View file

@ -1,10 +1,11 @@
"""Test requirements module.""" """Test requirements module."""
import os import os
from pathlib import Path
from unittest.mock import patch, call from unittest.mock import patch, call
from homeassistant import setup from homeassistant import setup
from homeassistant.requirements import ( from homeassistant.requirements import (
CONSTRAINT_FILE, async_process_requirements) CONSTRAINT_FILE, async_process_requirements, PROGRESS_FILE, _install)
from tests.common import ( from tests.common import (
get_test_home_assistant, MockModule, mock_coro, mock_integration) get_test_home_assistant, MockModule, mock_coro, mock_integration)
@ -143,3 +144,22 @@ async def test_install_on_docker(hass):
constraints=os.path.join('ha_package_path', CONSTRAINT_FILE), constraints=os.path.join('ha_package_path', CONSTRAINT_FILE),
no_cache_dir=True, no_cache_dir=True,
) )
async def test_progress_lock(hass):
"""Test an install attempt on an existing package."""
progress_path = Path(hass.config.path(PROGRESS_FILE))
kwargs = {'hello': 'world'}
def assert_env(req, **passed_kwargs):
"""Assert the env."""
assert progress_path.exists()
assert req == 'hello'
assert passed_kwargs == kwargs
return True
with patch('homeassistant.util.package.install_package',
side_effect=assert_env):
_install(hass, 'hello', kwargs)
assert not progress_path.exists()