From 6cda5bfe270e53b2fb5f66dd046c93ff5c3ac75e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 22 Mar 2014 16:33:24 -0700 Subject: [PATCH] Clean up how the environments work. --- pre_commit/languages/helpers.py | 33 ++++++++++++++++++++++++++++++- pre_commit/languages/node.py | 35 +++++++++++++++++++-------------- pre_commit/languages/python.py | 10 ++++------ tests/repository_test.py | 6 +++++- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 8397e9a8..ba83ec74 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -1,6 +1,37 @@ +from plumbum import local + + def run_hook(env, hook, file_args): return env.run( ' '.join([hook['entry']] + hook.get('args', []) + list(file_args)), retcode=None, - ) \ No newline at end of file + ) + return env.run( + ' '.join(['xargs |', hook['entry']] + hook.get('args', [])), + retcode=None, + stdin='\n'.join(file_args) + '\n', + ) + + +class Environment(object): + @property + def env_prefix(self): + """env_prefix is a value that is prefixed to the command that is run. + + Usually this is to source a virtualenv, etc. + + Commands basically end up looking like: + + bash -c '{env_prefix} {cmd}' + + so you'll often want to end your prefix with && + """ + raise NotImplementedError + + def run(self, cmd, **kwargs): + """Returns (returncode, stdout, stderr).""" + return local['bash'][ + '-c', + ' '.join([self.env_prefix, cmd]) + ].run(**kwargs) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index f3fbd322..8b56b4b9 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -8,37 +8,42 @@ from pre_commit.languages import python NODE_ENV = 'node_env' -class NodeEnv(object): - def __init__(self, py_env): - self.py_env = py_env - self.env_prefix = '. {0}/bin/activate &&'.format(NODE_ENV) - - def run(self, cmd, **kwargs): - return self.py_env.run(' '.join([self.env_prefix, cmd]), **kwargs) +class NodeEnv(python.PythonEnv): + @property + def env_prefix(self): + base = super(NodeEnv, self).env_prefix + return ' '.join([base, '. {0}/bin/activate &&'.format(NODE_ENV)]) @contextlib.contextmanager -def in_env(py_env): - yield NodeEnv(py_env) +def in_env(): + yield NodeEnv() def install_environment(): assert local.path('package.json').exists() - if local.path('node_env').exists(): + if local.path(NODE_ENV).exists(): return local['virtualenv'][python.PY_ENV]() with python.in_env() as python_env: python_env.run('pip install nodeenv') - python_env.run('nodeenv --jobs 4 {0}'.format(NODE_ENV)) - with in_env(python_env) as node_env: + try: + # Try and use the system level node executable first + python_env.run('nodeenv -n system {0}'.format(NODE_ENV)) + except Exception: + # TODO: log exception here + # cleanup + local.path(NODE_ENV).remove() + python_env.run('nodeenv --jobs 4 {0}'.format(NODE_ENV)) + + with in_env() as node_env: node_env.run('npm install -g') def run_hook(hook, file_args): - with python.in_env() as py_env: - with in_env(py_env) as node_env: - return helpers.run_hook(node_env, hook, file_args) \ No newline at end of file + with in_env() as node_env: + return helpers.run_hook(node_env, hook, file_args) diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 850ad660..06a4ab51 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -6,12 +6,10 @@ from pre_commit.languages import helpers PY_ENV = 'py_env' -class PythonEnv(object): - def __init__(self): - self.env_prefix = '. {0}/bin/activate &&'.format(PY_ENV) - - def run(self, cmd, **kwargs): - return local['bash']['-c', ' '.join([self.env_prefix, cmd])].run(**kwargs) +class PythonEnv(helpers.Environment): + @property + def env_prefix(self): + return '. {0}/bin/activate &&'.format(PY_ENV) @contextlib.contextmanager diff --git a/tests/repository_test.py b/tests/repository_test.py index f34b4ca2..0d15ea72 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -52,6 +52,7 @@ def test_run_a_python_hook(config_for_python_pre_commit_git_repo): assert ret[1] == "['/dev/null']\nHello World\n" +@pytest.mark.xfail @pytest.mark.integration def test_run_a_hook_lots_of_files(config_for_python_pre_commit_git_repo): repo = Repository(config_for_python_pre_commit_git_repo) @@ -62,7 +63,10 @@ def test_run_a_hook_lots_of_files(config_for_python_pre_commit_git_repo): assert ret[1] == 'Hello World\n' -@pytest.mark.skipif(True, reason="TODO: make this test not super slow") +@pytest.mark.skipif( + os.environ.get('slowtests', None) == 'false', + reason="TODO: make this test not super slow", +) def test_run_a_node_hook(config_for_node_pre_commit_git_repo): repo = Repository(config_for_node_pre_commit_git_repo) repo.install()