mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-17 08:14:42 +04:00
Merge pull request #565 from pre-commit/healthcheck
Recover from invalid python virtualenvs
This commit is contained in:
commit
2e23ad43fc
15 changed files with 76 additions and 6 deletions
|
|
@ -21,6 +21,9 @@ from pre_commit.languages import system
|
||||||
# return 'default' if there is no better option.
|
# return 'default' if there is no better option.
|
||||||
# """
|
# """
|
||||||
#
|
#
|
||||||
|
# def healthy(repo_cmd_runner, language_version):
|
||||||
|
# """Return whether or not the environment is considered functional."""
|
||||||
|
#
|
||||||
# def install_environment(repo_cmd_runner, version, additional_dependencies):
|
# def install_environment(repo_cmd_runner, version, additional_dependencies):
|
||||||
# """Installs a repository in the given repository. Note that the current
|
# """Installs a repository in the given repository. Note that the current
|
||||||
# working directory will already be inside the repository.
|
# working directory will already be inside the repository.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from pre_commit.xargs import xargs
|
||||||
ENVIRONMENT_DIR = 'docker'
|
ENVIRONMENT_DIR = 'docker'
|
||||||
PRE_COMMIT_LABEL = 'PRE_COMMIT'
|
PRE_COMMIT_LABEL = 'PRE_COMMIT'
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def md5(s): # pragma: windows no cover
|
def md5(s): # pragma: windows no cover
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from pre_commit.xargs import xargs
|
||||||
|
|
||||||
ENVIRONMENT_DIR = 'golangenv'
|
ENVIRONMENT_DIR = 'golangenv'
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def get_env_patch(venv):
|
def get_env_patch(venv):
|
||||||
|
|
|
||||||
|
|
@ -37,3 +37,7 @@ def assert_no_additional_deps(lang, additional_deps):
|
||||||
|
|
||||||
def basic_get_default_version():
|
def basic_get_default_version():
|
||||||
return 'default'
|
return 'default'
|
||||||
|
|
||||||
|
|
||||||
|
def basic_healthy(repo_cmd_runner, language_version):
|
||||||
|
return True
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ from pre_commit.xargs import xargs
|
||||||
|
|
||||||
ENVIRONMENT_DIR = 'node_env'
|
ENVIRONMENT_DIR = 'node_env'
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def get_env_patch(venv): # pragma: windows no cover
|
def get_env_patch(venv): # pragma: windows no cover
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from pre_commit.xargs import xargs
|
||||||
ENVIRONMENT_DIR = None
|
ENVIRONMENT_DIR = None
|
||||||
GREP = 'ggrep' if sys.platform == 'darwin' else 'grep'
|
GREP = 'ggrep' if sys.platform == 'darwin' else 'grep'
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def install_environment(repo_cmd_runner, version, additional_dependencies):
|
def install_environment(repo_cmd_runner, version, additional_dependencies):
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ from pre_commit.envcontext import Var
|
||||||
from pre_commit.languages import helpers
|
from pre_commit.languages import helpers
|
||||||
from pre_commit.parse_shebang import find_executable
|
from pre_commit.parse_shebang import find_executable
|
||||||
from pre_commit.util import clean_path_on_failure
|
from pre_commit.util import clean_path_on_failure
|
||||||
|
from pre_commit.util import cmd_output
|
||||||
from pre_commit.xargs import xargs
|
from pre_commit.xargs import xargs
|
||||||
|
|
||||||
|
|
||||||
ENVIRONMENT_DIR = 'py_env'
|
ENVIRONMENT_DIR = 'py_env'
|
||||||
get_default_version = helpers.basic_get_default_version
|
|
||||||
|
|
||||||
|
|
||||||
def bin_dir(venv):
|
def bin_dir(venv):
|
||||||
|
|
@ -83,6 +83,14 @@ def get_default_version():
|
||||||
return get_default_version()
|
return get_default_version()
|
||||||
|
|
||||||
|
|
||||||
|
def healthy(repo_cmd_runner, language_version):
|
||||||
|
with in_env(repo_cmd_runner, language_version):
|
||||||
|
retcode, _, _ = cmd_output(
|
||||||
|
'python', '-c', 'import datetime, io, os, weakref', retcode=None,
|
||||||
|
)
|
||||||
|
return retcode == 0
|
||||||
|
|
||||||
|
|
||||||
def norm_version(version):
|
def norm_version(version):
|
||||||
if os.name == 'nt': # pragma: no cover (windows)
|
if os.name == 'nt': # pragma: no cover (windows)
|
||||||
# Try looking up by name
|
# Try looking up by name
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from pre_commit.xargs import xargs
|
||||||
|
|
||||||
ENVIRONMENT_DIR = 'rbenv'
|
ENVIRONMENT_DIR = 'rbenv'
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def get_env_patch(venv, language_version): # pragma: windows no cover
|
def get_env_patch(venv, language_version): # pragma: windows no cover
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from pre_commit.xargs import xargs
|
||||||
|
|
||||||
ENVIRONMENT_DIR = None
|
ENVIRONMENT_DIR = None
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def install_environment(repo_cmd_runner, version, additional_dependencies):
|
def install_environment(repo_cmd_runner, version, additional_dependencies):
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ from pre_commit.xargs import xargs
|
||||||
|
|
||||||
ENVIRONMENT_DIR = 'swift_env'
|
ENVIRONMENT_DIR = 'swift_env'
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
BUILD_DIR = '.build'
|
BUILD_DIR = '.build'
|
||||||
BUILD_CONFIG = 'release'
|
BUILD_CONFIG = 'release'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from pre_commit.xargs import xargs
|
||||||
|
|
||||||
ENVIRONMENT_DIR = None
|
ENVIRONMENT_DIR = None
|
||||||
get_default_version = helpers.basic_get_default_version
|
get_default_version = helpers.basic_get_default_version
|
||||||
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
def install_environment(repo_cmd_runner, version, additional_dependencies):
|
def install_environment(repo_cmd_runner, version, additional_dependencies):
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ def _state_filename(cmd_runner, venv):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _read_installed_state(cmd_runner, venv):
|
def _read_state(cmd_runner, venv):
|
||||||
filename = _state_filename(cmd_runner, venv)
|
filename = _state_filename(cmd_runner, venv)
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
return None
|
return None
|
||||||
|
|
@ -44,7 +44,7 @@ def _read_installed_state(cmd_runner, venv):
|
||||||
return json.loads(io.open(filename).read())
|
return json.loads(io.open(filename).read())
|
||||||
|
|
||||||
|
|
||||||
def _write_installed_state(cmd_runner, venv, state):
|
def _write_state(cmd_runner, venv, state):
|
||||||
state_filename = _state_filename(cmd_runner, venv)
|
state_filename = _state_filename(cmd_runner, venv)
|
||||||
staging = state_filename + 'staging'
|
staging = state_filename + 'staging'
|
||||||
with io.open(staging, 'w') as state_file:
|
with io.open(staging, 'w') as state_file:
|
||||||
|
|
@ -57,8 +57,10 @@ def _installed(cmd_runner, language_name, language_version, additional_deps):
|
||||||
language = languages[language_name]
|
language = languages[language_name]
|
||||||
venv = environment_dir(language.ENVIRONMENT_DIR, language_version)
|
venv = environment_dir(language.ENVIRONMENT_DIR, language_version)
|
||||||
return (
|
return (
|
||||||
venv is None or
|
venv is None or (
|
||||||
_read_installed_state(cmd_runner, venv) == _state(additional_deps)
|
_read_state(cmd_runner, venv) == _state(additional_deps) and
|
||||||
|
language.healthy(cmd_runner, language_version)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -89,7 +91,7 @@ def _install_all(venvs, repo_url):
|
||||||
language.install_environment(cmd_runner, version, deps)
|
language.install_environment(cmd_runner, version, deps)
|
||||||
# Write our state to indicate we're installed
|
# Write our state to indicate we're installed
|
||||||
state = _state(deps)
|
state = _state(deps)
|
||||||
_write_installed_state(cmd_runner, venv, state)
|
_write_state(cmd_runner, venv, state)
|
||||||
|
|
||||||
|
|
||||||
def _validate_minimum_version(hook):
|
def _validate_minimum_version(hook):
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,13 @@ def test_get_default_version_argspec(language):
|
||||||
)
|
)
|
||||||
argspec = inspect.getargspec(languages[language].get_default_version)
|
argspec = inspect.getargspec(languages[language].get_default_version)
|
||||||
assert argspec == expected_argspec
|
assert argspec == expected_argspec
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('language', all_languages)
|
||||||
|
def test_healthy_argspec(language):
|
||||||
|
expected_argspec = inspect.ArgSpec(
|
||||||
|
args=['repo_cmd_runner', 'language_version'],
|
||||||
|
varargs=None, keywords=None, defaults=None,
|
||||||
|
)
|
||||||
|
argspec = inspect.getargspec(languages[language].healthy)
|
||||||
|
assert argspec == expected_argspec
|
||||||
|
|
|
||||||
12
tests/languages/helpers_test.py
Normal file
12
tests/languages/helpers_test.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from pre_commit.languages import helpers
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic_get_default_version():
|
||||||
|
assert helpers.basic_get_default_version() == 'default'
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic_healthy():
|
||||||
|
assert helpers.basic_healthy(None, None) is True
|
||||||
|
|
@ -600,6 +600,29 @@ def test_control_c_control_c_on_install(tempdir_factory, store):
|
||||||
assert retv == 0
|
assert retv == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalidated_virtualenv(tempdir_factory, store):
|
||||||
|
# A cached virtualenv may become invalidated if the system python upgrades
|
||||||
|
# This should not cause every hook in that virtualenv to fail.
|
||||||
|
path = make_repo(tempdir_factory, 'python_hooks_repo')
|
||||||
|
config = make_config_from_repo(path)
|
||||||
|
repo = Repository.create(config, store)
|
||||||
|
|
||||||
|
# Simulate breaking of the virtualenv
|
||||||
|
repo.require_installed()
|
||||||
|
version = python.get_default_version()
|
||||||
|
libdir = repo._cmd_runner.path('py_env-{}'.format(version), 'lib', version)
|
||||||
|
paths = [
|
||||||
|
os.path.join(libdir, p) for p in ('site.py', 'site.pyc', '__pycache__')
|
||||||
|
]
|
||||||
|
cmd_output('rm', '-rf', *paths)
|
||||||
|
|
||||||
|
# pre-commit should rebuild the virtualenv and it should be runnable
|
||||||
|
repo = Repository.create(config, store)
|
||||||
|
hook = repo.hooks[0][1]
|
||||||
|
retv, stdout, stderr = repo.run_hook(hook, [])
|
||||||
|
assert retv == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration
|
@pytest.mark.integration
|
||||||
def test_really_long_file_paths(tempdir_factory, store):
|
def test_really_long_file_paths(tempdir_factory, store):
|
||||||
base_path = tempdir_factory.get()
|
base_path = tempdir_factory.get()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue