From 74363e6ec2d366594eab77cbb1deda0fd1cf64ac Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 3 Apr 2014 23:31:45 -0700 Subject: [PATCH] Print message when installing repositories. --- pre_commit/languages/all.py | 5 ++++- pre_commit/languages/node.py | 20 ++++++++------------ pre_commit/languages/python.py | 11 ++++------- pre_commit/languages/ruby.py | 10 +++++----- pre_commit/languages/script.py | 4 +++- pre_commit/languages/system.py | 4 +++- pre_commit/repository.py | 18 ++++++++++++++++-- tests/languages/all_test.py | 1 + tests/repository_test.py | 34 ++++++++++++++++++++++++++++++++++ 9 files changed, 78 insertions(+), 29 deletions(-) diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index 541b4dca..2a4ae1da 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -5,7 +5,10 @@ from pre_commit.languages import ruby from pre_commit.languages import script from pre_commit.languages import system -# A language implements the following two functions in its module: +# A language implements the following constant and two functions in its module: +# +# # Use None for no environment +# ENVIRONMENT_DIR = 'foo_env' # # def install_environment(repo_cmd_runner): # """Installs a repository in the given repository. Note that the current diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index d6dfad50..fb07a8b0 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -6,7 +6,7 @@ from pre_commit.prefixed_command_runner import CalledProcessError from pre_commit.util import clean_path_on_failure -NODE_ENV = 'node_env' +ENVIRONMENT_DIR = 'node_env' class NodeEnv(python.PythonEnv): @@ -15,7 +15,7 @@ class NodeEnv(python.PythonEnv): base = super(NodeEnv, self).env_prefix return ' '.join([ base, - '. {{prefix}}{0}/bin/activate &&'.format(NODE_ENV)] + '. {{prefix}}{0}/bin/activate &&'.format(ENVIRONMENT_DIR)] ) @@ -27,30 +27,26 @@ def in_env(repo_cmd_runner): def install_environment(repo_cmd_runner): assert repo_cmd_runner.exists('package.json') - # Return immediately if we already have a virtualenv - if repo_cmd_runner.exists(NODE_ENV): - return - - with clean_path_on_failure(repo_cmd_runner.path(python.PY_ENV)): + with clean_path_on_failure(repo_cmd_runner.path(python.ENVIRONMENT_DIR)): repo_cmd_runner.run( - ['virtualenv', '{{prefix}}{0}'.format(python.PY_ENV)], + ['virtualenv', '{{prefix}}{0}'.format(python.ENVIRONMENT_DIR)], ) with python.in_env(repo_cmd_runner) as python_env: python_env.run('pip install nodeenv') - with clean_path_on_failure(repo_cmd_runner.path(NODE_ENV)): + with clean_path_on_failure(repo_cmd_runner.path(ENVIRONMENT_DIR)): # Try and use the system level node executable first try: python_env.run( - 'nodeenv -n system {{prefix}}{0}'.format(NODE_ENV), + 'nodeenv -n system {{prefix}}{0}'.format(ENVIRONMENT_DIR), ) except CalledProcessError: # TODO: log failure here # cleanup - # TODO: local.path(NODE_ENV).delete() + # TODO: local.path(ENVIRONMENT_DIR).delete() python_env.run( - 'nodeenv --jobs 4 {{prefix}}{0}'.format(NODE_ENV), + 'nodeenv --jobs 4 {{prefix}}{0}'.format(ENVIRONMENT_DIR), ) with in_env(repo_cmd_runner) as node_env: diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 23cf9f1a..db233b51 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -5,13 +5,13 @@ from pre_commit.languages import helpers from pre_commit.util import clean_path_on_failure -PY_ENV = 'py_env' +ENVIRONMENT_DIR = 'py_env' class PythonEnv(helpers.Environment): @property def env_prefix(self): - return '. {{prefix}}{0}/bin/activate &&'.format(PY_ENV) + return '. {{prefix}}{0}/bin/activate &&'.format(ENVIRONMENT_DIR) @contextlib.contextmanager @@ -21,13 +21,10 @@ def in_env(repo_cmd_runner): def install_environment(repo_cmd_runner): assert repo_cmd_runner.exists('setup.py') - # Return immediately if we already have a virtualenv - if repo_cmd_runner.exists(PY_ENV): - return # Install a virtualenv - with clean_path_on_failure(repo_cmd_runner.path(PY_ENV)): - repo_cmd_runner.run(['virtualenv', '{{prefix}}{0}'.format(PY_ENV)]) + with clean_path_on_failure(repo_cmd_runner.path(ENVIRONMENT_DIR)): + repo_cmd_runner.run(['virtualenv', '{{prefix}}{0}'.format(ENVIRONMENT_DIR)]) with in_env(repo_cmd_runner) as env: env.run('cd {prefix} && pip install .') diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index bf058f97..6448bf58 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -5,13 +5,13 @@ from pre_commit.languages import helpers from pre_commit.util import clean_path_on_failure -RVM_ENV = 'rvm_env' +ENVIRONMENT_DIR = 'rvm_env' class RubyEnv(helpers.Environment): @property def env_prefix(self): - return '. {{prefix}}{0}/bin/activate &&'.format(RVM_ENV) + return '. {{prefix}}{0}/bin/activate &&'.format(ENVIRONMENT_DIR) @contextlib.contextmanager @@ -21,11 +21,11 @@ def in_env(repo_cmd_runner): def install_environment(repo_cmd_runner): # Return immediately if we already have a virtualenv - if repo_cmd_runner.exists(RVM_ENV): + if repo_cmd_runner.exists(ENVIRONMENT_DIR): return - with clean_path_on_failure(repo_cmd_runner.path(RVM_ENV)): - repo_cmd_runner.run(['__rvm-env.sh', '{{prefix}}{0}'.format(RVM_ENV)]) + with clean_path_on_failure(repo_cmd_runner.path(ENVIRONMENT_DIR)): + repo_cmd_runner.run(['__rvm-env.sh', '{{prefix}}{0}'.format(ENVIRONMENT_DIR)]) with in_env(repo_cmd_runner) as env: env.run('cd {prefix} && bundle install') diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index e622a7c8..626e81c9 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -1,7 +1,9 @@ +ENVIRONMENT_DIR = None + + def install_environment(repo_cmd_runner): """Installation for script type is a noop.""" - pass def run_hook(repo_cmd_runner, hook, file_args): diff --git a/pre_commit/languages/system.py b/pre_commit/languages/system.py index 39dcf89c..c3848f2b 100644 --- a/pre_commit/languages/system.py +++ b/pre_commit/languages/system.py @@ -1,7 +1,9 @@ +ENVIRONMENT_DIR = None + + def install_environment(repo_cmd_runner): """Installation for system type is a noop.""" - pass def run_hook(repo_cmd_runner, hook, file_args): diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 80308674..46764957 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -1,4 +1,6 @@ +from __future__ import print_function + import contextlib from plumbum import local @@ -63,6 +65,10 @@ class Repository(object): # Project already exists, no reason to re-create it return + # Checking out environment for the first time + print('Installing environment for {0}.'.format(self.repo_url)) + print('Once installed this environment will be reused.') + print('This may take a few minutes...') with clean_path_on_failure(unicode(local.path(self.sha))): local['git']['clone', '--no-checkout', self.repo_url, self.sha]() with self.in_checkout(): @@ -73,6 +79,7 @@ class Repository(object): return self.install(cmd_runner) + self.__installed = True def install(self, cmd_runner): """Install the hook repository. @@ -82,8 +89,15 @@ class Repository(object): """ self.require_created() repo_cmd_runner = self.get_cmd_runner(cmd_runner) - for language in self.languages: - languages[language].install_environment(repo_cmd_runner) + for language_name in self.languages: + language = languages[language_name] + if ( + language.ENVIRONMENT_DIR is None or + repo_cmd_runner.exists(language.ENVIRONMENT_DIR) + ): + # The language is already installed + continue + language.install_environment(repo_cmd_runner) @contextlib.contextmanager def in_checkout(self): diff --git a/tests/languages/all_test.py b/tests/languages/all_test.py index b4bdaf25..91e252a8 100644 --- a/tests/languages/all_test.py +++ b/tests/languages/all_test.py @@ -9,3 +9,4 @@ from pre_commit.languages.all import languages def test_all_languages_support_interface(language): assert hasattr(languages[language], 'install_environment') assert hasattr(languages[language], 'run_hook') + assert hasattr(languages[language], 'ENVIRONMENT_DIR') diff --git a/tests/repository_test.py b/tests/repository_test.py index 2276b224..925dbbdd 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1,3 +1,5 @@ +import __builtin__ +import mock import os import pytest @@ -130,3 +132,35 @@ def test_sha(mock_repo_config): def test_languages(config_for_python_hooks_repo): repo = Repository(config_for_python_hooks_repo) assert repo.languages == set(['python']) + + +@pytest.yield_fixture +def print_mock(): + with mock.patch.object(__builtin__, 'print', autospec=True) as print_mock: + yield print_mock + + +def test_prints_while_creating(config_for_python_hooks_repo, print_mock): + repo = Repository(config_for_python_hooks_repo) + repo.require_created() + print_mock.assert_called_with('This may take a few minutes...') + print_mock.reset_mock() + # Reinstall with same repo should not trigger another install + repo.require_created() + assert print_mock.call_count == 0 + # Reinstall on another run should not trigger another install + repo = Repository(config_for_python_hooks_repo) + repo.require_created() + assert print_mock.call_count == 0 + + +def test_reinstall(config_for_python_hooks_repo): + repo = Repository(config_for_python_hooks_repo) + repo.require_installed(PrefixedCommandRunner(C.HOOKS_WORKSPACE)) + # Reinstall with same repo should not trigger another install + # TODO: how to assert this? + repo.require_installed(PrefixedCommandRunner(C.HOOKS_WORKSPACE)) + # Reinstall on another run should not trigger another install + # TODO: how to assert this? + repo = Repository(config_for_python_hooks_repo) + repo.require_installed(PrefixedCommandRunner(C.HOOKS_WORKSPACE))