diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index b2973270..fa213150 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -5,7 +5,6 @@ import sys from aspy.yaml import ordered_dump from aspy.yaml import ordered_load -from plumbum import local import pre_commit.constants as C from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA @@ -13,6 +12,8 @@ from pre_commit.clientlib.validate_config import load_config from pre_commit.jsonschema_extensions import remove_defaults from pre_commit.ordereddict import OrderedDict from pre_commit.repository import Repository +from pre_commit.util import cwd +from pre_commit.util import cmd_output class RepositoryCannotBeUpdatedError(RuntimeError): @@ -29,9 +30,9 @@ def _update_repository(repo_config, runner): """ repo = Repository.create(repo_config, runner.store) - with local.cwd(repo.repo_path_getter.repo_path): - local['git']('fetch') - head_sha = local['git']('rev-parse', 'origin/master').strip() + with cwd(repo.repo_path_getter.repo_path): + cmd_output('git', 'fetch') + head_sha = cmd_output('git', 'rev-parse', 'origin/master')[1].strip() # Don't bother trying to update if our sha is the same if head_sha == repo_config['sha']: diff --git a/pre_commit/git.py b/pre_commit/git.py index 4d03c26a..a2b26527 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -5,9 +5,9 @@ import logging import os import os.path import re -from plumbum import local from pre_commit.errors import FatalError +from pre_commit.util import cmd_output from pre_commit.util import memoize_by_cwd @@ -54,21 +54,21 @@ def get_conflicted_files(): # This will get the rest of the changes made after the merge. # If they resolved the merge conflict by choosing a mesh of both sides # this will also include the conflicted files - tree_hash = local['git']('write-tree').strip() - merge_diff_filenames = local['git']( - 'diff', '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--name-only', - ).splitlines() + tree_hash = cmd_output('git', 'write-tree')[1].strip() + merge_diff_filenames = cmd_output( + 'git', 'diff', '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--name-only', + )[1].splitlines() return set(merge_conflict_filenames) | set(merge_diff_filenames) @memoize_by_cwd def get_staged_files(): - return local['git']('diff', '--staged', '--name-only').splitlines() + return cmd_output('git', 'diff', '--staged', '--name-only')[1].splitlines() @memoize_by_cwd def get_all_files(): - return local['git']('ls-files').splitlines() + return cmd_output('git', 'ls-files')[1].splitlines() def get_files_matching(all_file_list_strategy): diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index f23f1d12..94e0f574 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -4,7 +4,7 @@ import contextlib import io from pre_commit.languages import helpers -from pre_commit.prefixed_command_runner import CalledProcessError +from pre_commit.util import CalledProcessError from pre_commit.util import clean_path_on_failure from pre_commit.util import resource_filename from pre_commit.util import tarfile_open diff --git a/pre_commit/make_archives.py b/pre_commit/make_archives.py index a13e66b4..0c447a7e 100644 --- a/pre_commit/make_archives.py +++ b/pre_commit/make_archives.py @@ -4,8 +4,9 @@ from __future__ import unicode_literals import os.path import shutil -from plumbum import local +from pre_commit.util import cmd_output +from pre_commit.util import cwd from pre_commit.util import tarfile_open from pre_commit.util import tmpdir @@ -42,9 +43,9 @@ def make_archive(name, repo, ref, destdir): output_path = os.path.join(destdir, name + '.tar.gz') with tmpdir() as tempdir: # Clone the repository to the temporary directory - local['git']('clone', repo, tempdir) - with local.cwd(tempdir): - local['git']('checkout', ref) + cmd_output('git', 'clone', repo, tempdir) + with cwd(tempdir): + cmd_output('git', 'checkout', ref) # We don't want the '.git' directory # It adds a bunch of size to the archive and we don't use it at diff --git a/pre_commit/prefixed_command_runner.py b/pre_commit/prefixed_command_runner.py index eacf6308..720bb103 100644 --- a/pre_commit/prefixed_command_runner.py +++ b/pre_commit/prefixed_command_runner.py @@ -4,29 +4,7 @@ import os import os.path import subprocess - -class CalledProcessError(RuntimeError): - def __init__(self, returncode, cmd, expected_returncode, output=None): - super(CalledProcessError, self).__init__( - returncode, cmd, expected_returncode, output, - ) - self.returncode = returncode - self.cmd = cmd - self.expected_returncode = expected_returncode - self.output = output - - def __str__(self): - return ( - 'Command: {0!r}\n' - 'Return code: {1}\n' - 'Expected return code: {2}\n' - 'Output: {3!r}\n'.format( - self.cmd, - self.returncode, - self.expected_returncode, - self.output, - ) - ) +from pre_commit.util import cmd_output def _replace_cmd(cmd, **kwargs): @@ -57,32 +35,10 @@ class PrefixedCommandRunner(object): if not os.path.exists(self.prefix_dir): self.__makedirs(self.prefix_dir) - def run(self, cmd, retcode=0, stdin=None, encoding='UTF-8', **kwargs): - popen_kwargs = { - 'stdin': subprocess.PIPE, - 'stdout': subprocess.PIPE, - 'stderr': subprocess.PIPE, - } - if stdin is not None: - stdin = stdin.encode('UTF-8') - - popen_kwargs.update(kwargs) + def run(self, cmd, **kwargs): self._create_path_if_not_exists() replaced_cmd = _replace_cmd(cmd, prefix=self.prefix_dir) - proc = self.__popen(replaced_cmd, **popen_kwargs) - stdout, stderr = proc.communicate(stdin) - if encoding is not None: - stdout = stdout.decode(encoding) - if encoding is not None: - stderr = stderr.decode(encoding) - returncode = proc.returncode - - if retcode is not None and retcode != returncode: - raise CalledProcessError( - returncode, replaced_cmd, retcode, output=(stdout, stderr), - ) - - return proc.returncode, stdout, stderr + return cmd_output(*replaced_cmd, __popen=self.__popen, **kwargs) def path(self, *parts): path = os.path.join(self.prefix_dir, *parts) diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index ff6f1eb7..9ede8032 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -5,7 +5,7 @@ import io import logging import time -from pre_commit.prefixed_command_runner import CalledProcessError +from pre_commit.util import CalledProcessError logger = logging.getLogger('pre_commit') diff --git a/pre_commit/store.py b/pre_commit/store.py index 38c02385..c42048db 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -6,10 +6,11 @@ import os import os.path import tempfile from cached_property import cached_property -from plumbum import local from pre_commit.prefixed_command_runner import PrefixedCommandRunner from pre_commit.util import clean_path_on_failure +from pre_commit.util import cmd_output +from pre_commit.util import cwd from pre_commit.util import hex_md5 @@ -85,9 +86,9 @@ class Store(object): dir = tempfile.mkdtemp(prefix='repo', dir=self.directory) with clean_path_on_failure(dir): - local['git']('clone', '--no-checkout', url, dir) - with local.cwd(dir): - local['git']('checkout', sha) + cmd_output('git', 'clone', '--no-checkout', url, dir) + with cwd(dir): + cmd_output('git', 'checkout', sha) # Make a symlink from sha->repo os.symlink(dir, sha_path) diff --git a/pre_commit/util.py b/pre_commit/util.py index eef67375..9488b96a 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -7,10 +7,21 @@ import os import os.path import pkg_resources import shutil +import subprocess import tarfile import tempfile +@contextlib.contextmanager +def cwd(path): + original_cwd = os.getcwd() + os.chdir(path) + try: + yield + finally: + os.chdir(original_cwd) + + def memoize_by_cwd(func): """Memoize a function call based on os.getcwd().""" @functools.wraps(func) @@ -83,3 +94,59 @@ def resource_filename(filename): 'pre_commit', os.path.join('resources', filename), ) + + +class CalledProcessError(RuntimeError): + def __init__(self, returncode, cmd, expected_returncode, output=None): + super(CalledProcessError, self).__init__( + returncode, cmd, expected_returncode, output, + ) + self.returncode = returncode + self.cmd = cmd + self.expected_returncode = expected_returncode + self.output = output + + def __str__(self): + return ( + 'Command: {0!r}\n' + 'Return code: {1}\n' + 'Expected return code: {2}\n' + 'Output: {3!r}\n'.format( + self.cmd, + self.returncode, + self.expected_returncode, + self.output, + ) + ) + + +def cmd_output(*cmd, **kwargs): + retcode = kwargs.pop('retcode', 0) + stdin = kwargs.pop('stdin', None) + encoding = kwargs.pop('encoding', 'UTF-8') + __popen = kwargs.pop('__popen', subprocess.Popen) + + popen_kwargs = { + 'stdin': subprocess.PIPE, + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + } + + if stdin is not None: + stdin = stdin.encode('UTF-8') + + popen_kwargs.update(kwargs) + proc = __popen(cmd, **popen_kwargs) + stdout, stderr = proc.communicate(stdin) + if encoding is not None and stdout is not None: + stdout = stdout.decode(encoding) + if encoding is not None and stderr is not None: + stderr = stderr.decode(encoding) + returncode = proc.returncode + + if retcode is not None and retcode != returncode: + raise CalledProcessError( + returncode, cmd, retcode, output=(stdout, stderr), + ) + + return proc.returncode, stdout, stderr diff --git a/setup.py b/setup.py index bce8bbe3..5e8ffe0e 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,6 @@ setup( 'jsonschema', 'nodeenv>=0.11.1', 'ordereddict', - 'plumbum', 'pyyaml', 'simplejson', 'virtualenv', diff --git a/testing/fixtures.py b/testing/fixtures.py index fd6b5401..c42f92dc 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals import io import os.path from aspy.yaml import ordered_dump -from plumbum import local import pre_commit.constants as C from pre_commit.clientlib.validate_manifest import load_manifest @@ -12,27 +11,26 @@ from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA from pre_commit.clientlib.validate_config import validate_config_extra from pre_commit.jsonschema_extensions import apply_defaults from pre_commit.ordereddict import OrderedDict +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.util import copy_tree_to_path from testing.util import get_head_sha from testing.util import get_resource_path -git = local['git'] - - def git_dir(tmpdir_factory): path = tmpdir_factory.get() - with local.cwd(path): - git('init') + with cwd(path): + cmd_output('git', 'init') return path def make_repo(tmpdir_factory, repo_source): path = git_dir(tmpdir_factory) copy_tree_to_path(get_resource_path(repo_source), path) - with local.cwd(path): - git('add', '.') - git('commit', '-m', 'Add hooks') + with cwd(path): + cmd_output('git', 'add', '.') + cmd_output('git', 'commit', '-m', 'Add hooks') return path @@ -66,7 +64,7 @@ def make_consuming_repo(tmpdir_factory, repo_source): config = make_config_from_repo(path) git_path = git_dir(tmpdir_factory) write_config(git_path, config) - with local.cwd(git_path): - git('add', C.CONFIG_FILE) - git('commit', '-m', 'Add hooks config') + with cwd(git_path): + cmd_output('git', 'add', C.CONFIG_FILE) + cmd_output('git', 'commit', '-m', 'Add hooks config') return git_path diff --git a/testing/util.py b/testing/util.py index be61169c..e83d5cb1 100644 --- a/testing/util.py +++ b/testing/util.py @@ -5,7 +5,9 @@ import os import os.path import pytest import shutil -from plumbum import local + +from pre_commit.util import cmd_output +from pre_commit.util import cwd TESTING_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -34,8 +36,8 @@ def copy_tree_to_path(src_dir, dest_dir): def get_head_sha(dir): - with local.cwd(dir): - return local['git']('rev-parse', 'HEAD').strip() + with cwd(dir): + return cmd_output('git', 'rev-parse', 'HEAD')[1].strip() def is_valid_according_to_schema(obj, schema): diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index b011ac28..d8c564f5 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals import pytest import shutil -from plumbum import local import pre_commit.constants as C from pre_commit.commands.autoupdate import _update_repository @@ -10,6 +9,8 @@ from pre_commit.commands.autoupdate import autoupdate from pre_commit.commands.autoupdate import RepositoryCannotBeUpdatedError from pre_commit.ordereddict import OrderedDict from pre_commit.runner import Runner +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.auto_namedtuple import auto_namedtuple from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo @@ -52,8 +53,8 @@ def out_of_date_repo(tmpdir_factory): original_sha = get_head_sha(path) # Make a commit - with local.cwd(path): - local['git']['commit', '--allow-empty', '-m', 'foo']() + with cwd(path): + cmd_output('git', 'commit', '--allow-empty', '-m', 'foo') head_sha = get_head_sha(path) yield auto_namedtuple( @@ -95,13 +96,13 @@ def hook_disappearing_repo(tmpdir_factory): path = make_repo(tmpdir_factory, 'python_hooks_repo') original_sha = get_head_sha(path) - with local.cwd(path): + with cwd(path): shutil.copy( get_resource_path('manifest_without_foo.yaml'), C.MANIFEST_FILE, ) - local['git']('add', '.') - local['git']('commit', '-m', 'Remove foo') + cmd_output('git', 'add', '.') + cmd_output('git', 'commit', '-m', 'Remove foo') yield auto_namedtuple(path=path, original_sha=original_sha) diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 68ee29de..3de7ffce 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -9,7 +9,6 @@ import re import subprocess import stat import sys -from plumbum import local from pre_commit.commands.install_uninstall import IDENTIFYING_HASH from pre_commit.commands.install_uninstall import PREVIOUS_IDENTIFYING_HASHES @@ -19,6 +18,8 @@ from pre_commit.commands.install_uninstall import is_previous_pre_commit from pre_commit.commands.install_uninstall import make_executable from pre_commit.commands.install_uninstall import uninstall from pre_commit.runner import Runner +from pre_commit.util import cmd_output +from pre_commit.util import cwd from pre_commit.util import resource_filename from testing.fixtures import git_dir from testing.fixtures import make_consuming_repo @@ -86,13 +87,13 @@ def _get_commit_output( home=None, env_base=os.environ, ): - local['touch'](touch_file) - local['git']('add', touch_file) + cmd_output('touch', touch_file) + cmd_output('git', 'add', touch_file) # Don't want to write to home directory home = home or tmpdir_factory.get() env = dict(env_base, **{'PRE_COMMIT_HOME': home}) - return local['git'].run( - ['commit', '-m', 'Commit!', '--allow-empty'], + return cmd_output( + 'git', 'commit', '-m', 'Commit!', '--allow-empty', # git commit puts pre-commit to stderr stderr=subprocess.STDOUT, env=env, @@ -123,7 +124,7 @@ NORMAL_PRE_COMMIT_RUN = re.compile( def test_install_pre_commit_and_run(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): assert install(Runner(path)) == 0 ret, output = _get_commit_output(tmpdir_factory) @@ -133,7 +134,7 @@ def test_install_pre_commit_and_run(tmpdir_factory): def test_install_idempotent(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): assert install(Runner(path)) == 0 assert install(Runner(path)) == 0 @@ -144,13 +145,13 @@ def test_install_idempotent(tmpdir_factory): def test_environment_not_sourced(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): # Patch the executable to simulate rming virtualenv with mock.patch.object(sys, 'executable', '/bin/false'): assert install(Runner(path)) == 0 - ret, stdout, stderr = local['git'].run( - ['commit', '--allow-empty', '-m', 'foo'], + ret, stdout, stderr = cmd_output( + 'git', 'commit', '--allow-empty', '-m', 'foo', env={'HOME': os.environ['HOME']}, retcode=None, ) @@ -177,7 +178,7 @@ FAILING_PRE_COMMIT_RUN = re.compile( def test_failing_hooks_returns_nonzero(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'failing_hook_repo') - with local.cwd(path): + with cwd(path): assert install(Runner(path)) == 0 ret, output = _get_commit_output(tmpdir_factory) @@ -195,7 +196,7 @@ EXISTING_COMMIT_RUN = re.compile( def test_install_existing_hooks_no_overwrite(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): runner = Runner(path) # Write out an "old" hook @@ -220,7 +221,7 @@ def test_install_existing_hooks_no_overwrite(tmpdir_factory): def test_install_existing_hook_no_overwrite_idempotent(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): runner = Runner(path) # Write out an "old" hook @@ -250,7 +251,7 @@ FAIL_OLD_HOOK = re.compile( def test_failing_existing_hook_returns_1(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): runner = Runner(path) # Write out a failing "old" hook @@ -268,7 +269,7 @@ def test_failing_existing_hook_returns_1(tmpdir_factory): def test_install_overwrite_no_existing_hooks(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): assert install(Runner(path), overwrite=True) == 0 ret, output = _get_commit_output(tmpdir_factory) @@ -278,7 +279,7 @@ def test_install_overwrite_no_existing_hooks(tmpdir_factory): def test_install_overwrite(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): runner = Runner(path) # Write out the "old" hook @@ -295,7 +296,7 @@ def test_install_overwrite(tmpdir_factory): def test_uninstall_restores_legacy_hooks(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): runner = Runner(path) # Write out an "old" hook @@ -315,7 +316,7 @@ def test_uninstall_restores_legacy_hooks(tmpdir_factory): def test_replace_old_commit_script(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): runner = Runner(path) # Install a script that looks like our old script @@ -340,7 +341,7 @@ def test_replace_old_commit_script(tmpdir_factory): def test_uninstall_doesnt_remove_not_our_hooks(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): runner = Runner(path) with io.open(runner.pre_commit_path, 'w') as pre_commit_file: pre_commit_file.write('#!/usr/bin/env bash\necho 1\n') @@ -364,7 +365,7 @@ def test_installs_hooks_with_hooks_True( mock_out_store_directory, ): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): install(Runner(path), hooks=True) ret, output = _get_commit_output( tmpdir_factory, home=mock_out_store_directory, @@ -376,7 +377,7 @@ def test_installs_hooks_with_hooks_True( def test_installed_from_venv(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): + with cwd(path): install(Runner(path)) # No environment so pre-commit is not on the path when running! # Should still pick up the python from when we installed diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 3a83a60c..26b27010 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -7,13 +7,14 @@ import os import os.path import pytest import subprocess -from plumbum import local from pre_commit.commands.install_uninstall import install from pre_commit.commands.run import _get_skips from pre_commit.commands.run import _has_unmerged_paths from pre_commit.commands.run import run from pre_commit.runner import Runner +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.auto_namedtuple import auto_namedtuple from testing.fixtures import make_consuming_repo @@ -21,20 +22,20 @@ from testing.fixtures import make_consuming_repo @pytest.yield_fixture def repo_with_passing_hook(tmpdir_factory): git_path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(git_path): + with cwd(git_path): yield git_path @pytest.yield_fixture def repo_with_failing_hook(tmpdir_factory): git_path = make_consuming_repo(tmpdir_factory, 'failing_hook_repo') - with local.cwd(git_path): + with cwd(git_path): yield git_path def stage_a_file(): - local['touch']('foo.py') - local['git']('add', 'foo.py') + cmd_output('touch', 'foo.py') + cmd_output('git', 'add', 'foo.py') def get_write_mock_output(write_mock): @@ -180,7 +181,7 @@ def test_merge_conflict_modified(in_merge_conflict, mock_out_store_directory): def test_merge_conflict_resolved(in_merge_conflict, mock_out_store_directory): - local['git']('add', '.') + cmd_output('git', 'add', '.') ret, printed = _do_run(in_merge_conflict, _get_opts()) for msg in ('Checking merge-conflict files only.', 'Bash hook', 'Passed'): assert msg in printed @@ -228,11 +229,11 @@ def test_hook_id_in_verbose_output( def test_multiple_hooks_same_id( repo_with_passing_hook, mock_out_store_directory, ): - with local.cwd(repo_with_passing_hook): + with cwd(repo_with_passing_hook): # Add bash hook on there again with io.open('.pre-commit-config.yaml', 'a+') as config_file: config_file.write(' - id: bash_hook\n') - local['git']('add', '.pre-commit-config.yaml') + cmd_output('git', 'add', '.pre-commit-config.yaml') stage_a_file() ret, output = _do_run(repo_with_passing_hook, _get_opts()) @@ -243,11 +244,11 @@ def test_multiple_hooks_same_id( def test_stdout_write_bug_py26( repo_with_failing_hook, mock_out_store_directory, tmpdir_factory, ): - with local.cwd(repo_with_failing_hook): + with cwd(repo_with_failing_hook): # Add bash hook on there again with io.open('.pre-commit-config.yaml', 'a+') as config_file: config_file.write(' args: ["☃"]\n') - local['git']('add', '.pre-commit-config.yaml') + cmd_output('git', 'add', '.pre-commit-config.yaml') stage_a_file() install(Runner(repo_with_failing_hook)) @@ -255,8 +256,8 @@ def test_stdout_write_bug_py26( # Don't want to write to home directory env = dict(os.environ, **{'PRE_COMMIT_HOME': tmpdir_factory.get()}) # Have to use subprocess because pytest monkeypatches sys.stdout - _, stdout, _ = local['git'].run( - ('commit', '-m', 'Commit!'), + _, stdout, _ = cmd_output( + 'git', 'commit', '-m', 'Commit!', # git commit puts pre-commit to stderr stderr=subprocess.STDOUT, env=env, diff --git a/tests/conftest.py b/tests/conftest.py index 9cc5f03b..2465f0d0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,19 +6,17 @@ import mock import os import os.path import pytest -from plumbum import local import pre_commit.constants as C from pre_commit import five from pre_commit.prefixed_command_runner import PrefixedCommandRunner from pre_commit.runner import Runner from pre_commit.store import Store +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.fixtures import make_consuming_repo -git = local['git'] - - @pytest.yield_fixture def tmpdir_factory(tmpdir): class TmpdirFactory(object): @@ -37,39 +35,39 @@ def tmpdir_factory(tmpdir): @pytest.yield_fixture def in_tmpdir(tmpdir_factory): path = tmpdir_factory.get() - with local.cwd(path): + with cwd(path): yield path @pytest.yield_fixture def in_merge_conflict(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') - with local.cwd(path): - local['touch']('dummy') - git('add', 'dummy') - git('add', C.CONFIG_FILE) - git('commit', '-m', 'Add config.') + with cwd(path): + cmd_output('touch', 'dummy') + cmd_output('git', 'add', 'dummy') + cmd_output('git', 'add', C.CONFIG_FILE) + cmd_output('git', 'commit', '-m', 'Add config.') conflict_path = tmpdir_factory.get() - git('clone', path, conflict_path) - with local.cwd(conflict_path): - git('checkout', 'origin/master', '-b', 'foo') + cmd_output('git', 'clone', path, conflict_path) + with cwd(conflict_path): + cmd_output('git', 'checkout', 'origin/master', '-b', 'foo') with io.open('conflict_file', 'w') as conflict_file: conflict_file.write('herp\nderp\n') - git('add', 'conflict_file') + cmd_output('git', 'add', 'conflict_file') with io.open('foo_only_file', 'w') as foo_only_file: foo_only_file.write('foo') - git('add', 'foo_only_file') - git('commit', '-m', 'conflict_file') - git('checkout', 'origin/master', '-b', 'bar') + cmd_output('git', 'add', 'foo_only_file') + cmd_output('git', 'commit', '-m', 'conflict_file') + cmd_output('git', 'checkout', 'origin/master', '-b', 'bar') with io.open('conflict_file', 'w') as conflict_file: conflict_file.write('harp\nddrp\n') - git('add', 'conflict_file') + cmd_output('git', 'add', 'conflict_file') with io.open('bar_only_file', 'w') as bar_only_file: bar_only_file.write('bar') - git('add', 'bar_only_file') - git('commit', '-m', 'conflict_file') - git('merge', 'foo', retcode=None) + cmd_output('git', 'add', 'bar_only_file') + cmd_output('git', 'commit', '-m', 'conflict_file') + cmd_output('git', 'merge', 'foo', retcode=None) yield os.path.join(conflict_path) diff --git a/tests/git_test.py b/tests/git_test.py index c3b728a6..86e18b34 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -3,16 +3,17 @@ from __future__ import unicode_literals import os.path import pytest -from plumbum import local from pre_commit import git from pre_commit.errors import FatalError +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.fixtures import git_dir def test_get_root_at_root(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): assert git.get_root() == path @@ -21,19 +22,19 @@ def test_get_root_deeper(tmpdir_factory): foo_path = os.path.join(path, 'foo') os.mkdir(foo_path) - with local.cwd(foo_path): + with cwd(foo_path): assert git.get_root() == path def test_get_root_not_git_dir(tmpdir_factory): - with local.cwd(tmpdir_factory.get()): + with cwd(tmpdir_factory.get()): with pytest.raises(FatalError): git.get_root() def test_is_not_in_merge_conflict(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): assert git.is_in_merge_conflict() is False @@ -42,9 +43,9 @@ def test_is_in_merge_conflict(in_merge_conflict): def test_cherry_pick_conflict(in_merge_conflict): - local['git']('merge', '--abort') - foo_ref = local['git']('rev-parse', 'foo').strip() - local['git']('cherry-pick', foo_ref, retcode=None) + cmd_output('git', 'merge', '--abort') + foo_ref = cmd_output('git', 'rev-parse', 'foo')[1].strip() + cmd_output('git', 'cherry-pick', foo_ref, retcode=None) assert git.is_in_merge_conflict() is False @@ -96,14 +97,14 @@ def test_exclude_removes_files(get_files_matching_func): def resolve_conflict(): with open('conflict_file', 'w') as conflicted_file: conflicted_file.write('herp\nderp\n') - local['git']('add', 'conflict_file') + cmd_output('git', 'add', 'conflict_file') def test_get_conflicted_files(in_merge_conflict): resolve_conflict() with open('other_file', 'w') as other_file: other_file.write('oh hai') - local['git']('add', 'other_file') + cmd_output('git', 'add', 'other_file') ret = set(git.get_conflicted_files()) assert ret == set(('conflict_file', 'other_file')) diff --git a/tests/main_test.py b/tests/main_test.py index b2579b89..ac1674f9 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -4,9 +4,9 @@ from __future__ import unicode_literals import argparse import mock import pytest -from plumbum import local from pre_commit import main +from pre_commit.util import cwd from testing.auto_namedtuple import auto_namedtuple @@ -133,7 +133,7 @@ def test_help_cmd_in_empty_directory( ): path = tmpdir_factory.get() - with local.cwd(path): + with cwd(path): with pytest.raises(CalledExit): main.main(['help', 'run']) diff --git a/tests/make_archives_test.py b/tests/make_archives_test.py index 290a0caf..91cb0af4 100644 --- a/tests/make_archives_test.py +++ b/tests/make_archives_test.py @@ -4,9 +4,10 @@ from __future__ import unicode_literals import mock import os.path import pytest -from plumbum import local from pre_commit import make_archives +from pre_commit.util import cmd_output +from pre_commit.util import cwd from pre_commit.util import tarfile_open from testing.fixtures import git_dir from testing.util import get_head_sha @@ -17,16 +18,16 @@ def test_make_archive(tmpdir_factory): output_dir = tmpdir_factory.get() git_path = git_dir(tmpdir_factory) # Add a files to the git directory - with local.cwd(git_path): - local['touch']('foo') - local['git']('add', '.') - local['git']('commit', '-m', 'foo') + with cwd(git_path): + cmd_output('touch', 'foo') + cmd_output('git', 'add', '.') + cmd_output('git', 'commit', '-m', 'foo') # We'll use this sha head_sha = get_head_sha('.') # And check that this file doesn't exist - local['touch']('bar') - local['git']('add', '.') - local['git']('commit', '-m', 'bar') + cmd_output('touch', 'bar') + cmd_output('git', 'add', '.') + cmd_output('git', 'commit', '-m', 'bar') # Do the thing archive_path = make_archives.make_archive( diff --git a/tests/prefixed_command_runner_test.py b/tests/prefixed_command_runner_test.py index 0d5e410e..ca6d0154 100644 --- a/tests/prefixed_command_runner_test.py +++ b/tests/prefixed_command_runner_test.py @@ -6,8 +6,8 @@ import pytest import subprocess from pre_commit.prefixed_command_runner import _replace_cmd -from pre_commit.prefixed_command_runner import CalledProcessError from pre_commit.prefixed_command_runner import PrefixedCommandRunner +from pre_commit.util import CalledProcessError def test_CalledProcessError_str(): @@ -65,7 +65,7 @@ def test_run_substitutes_prefix(popen_mock, makedirs_mock): ) ret = instance.run(['{prefix}bar', 'baz'], retcode=None) popen_mock.assert_called_once_with( - ['prefix/bar', 'baz'], + ('prefix/bar', 'baz'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -116,7 +116,7 @@ def test_from_command_runner_preserves_popen(popen_mock, makedirs_mock): second = PrefixedCommandRunner.from_command_runner(first, 'bar') second.run(['foo/bar/baz'], retcode=None) popen_mock.assert_called_once_with( - ['foo/bar/baz'], + ('foo/bar/baz',), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, diff --git a/tests/repository_test.py b/tests/repository_test.py index 93fe461a..868f2f59 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -5,12 +5,13 @@ import io import mock import os.path import pytest -from plumbum import local from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA from pre_commit.clientlib.validate_config import validate_config_extra from pre_commit.jsonschema_extensions import apply_defaults from pre_commit.repository import Repository +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.fixtures import git_dir from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo @@ -118,7 +119,7 @@ def test_run_hook_with_spaced_args(tmpdir_factory, store): @pytest.mark.integration def test_pcre_hook_no_match(tmpdir_factory, store): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): with io.open('herp', 'w') as herp: herp.write('foo') @@ -139,7 +140,7 @@ def test_pcre_hook_no_match(tmpdir_factory, store): @pytest.mark.integration def test_pcre_hook_matching(tmpdir_factory, store): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): with io.open('herp', 'w') as herp: herp.write("\nherpfoo'bard\n") @@ -165,7 +166,7 @@ def test_pcre_many_files(tmpdir_factory, store): # to make sure it still fails. This is not the case when naively using # a system hook with `grep -H -n '...'` and expected_return_code=123. path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): with io.open('herp', 'w') as herp: herp.write('[INFO] info\n') @@ -182,7 +183,7 @@ def test_pcre_many_files(tmpdir_factory, store): def test_cwd_of_hook(tmpdir_factory, store): # Note: this doubles as a test for `system` hooks path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): _test_hook_repo( tmpdir_factory, store, 'prints_cwd_repo', 'prints_cwd', ['-L'], path + '\n', @@ -248,12 +249,12 @@ def test_reinstall(tmpdir_factory, store): def test_really_long_file_paths(tmpdir_factory, store): base_path = tmpdir_factory.get() really_long_path = os.path.join(base_path, 'really_long' * 10) - local['git']('init', really_long_path) + cmd_output('git', 'init', really_long_path) path = make_repo(tmpdir_factory, 'python_hooks_repo') config = make_config_from_repo(path) - with local.cwd(really_long_path): + with cwd(really_long_path): repo = Repository.create(config, store) repo.require_installed() @@ -273,8 +274,8 @@ def test_config_overrides_repo_specifics(tmpdir_factory, store): def _create_repo_with_tags(tmpdir_factory, src, tag): path = make_repo(tmpdir_factory, src) - with local.cwd(path): - local['git']('tag', tag) + with cwd(path): + cmd_output('git', 'tag', tag) return path diff --git a/tests/runner_test.py b/tests/runner_test.py index 075f86d6..cc4c816a 100644 --- a/tests/runner_test.py +++ b/tests/runner_test.py @@ -3,10 +3,10 @@ from __future__ import unicode_literals import os import os.path -from plumbum import local import pre_commit.constants as C from pre_commit.runner import Runner +from pre_commit.util import cwd from testing.fixtures import git_dir from testing.fixtures import make_consuming_repo @@ -20,7 +20,7 @@ def test_init_has_no_side_effects(tmpdir): def test_create_sets_correct_directory(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): runner = Runner.create() assert runner.git_root == path assert os.getcwd() == path @@ -28,7 +28,7 @@ def test_create_sets_correct_directory(tmpdir_factory): def test_create_changes_to_git_root(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): # Change into some directory, create should set to root foo_path = os.path.join(path, 'foo') os.mkdir(foo_path) diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index a51d5016..620d7d92 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -8,9 +8,10 @@ import mock import os.path import pytest import shutil -from plumbum import local from pre_commit.staged_files_only import staged_files_only +from pre_commit.util import cmd_output +from pre_commit.util import cwd from testing.auto_namedtuple import auto_namedtuple from testing.fixtures import git_dir from testing.util import get_resource_path @@ -20,17 +21,17 @@ FOO_CONTENTS = '\n'.join(('1', '2', '3', '4', '5', '6', '7', '8', '')) def get_short_git_status(): - git_status = local['git']('status', '-s') + git_status = cmd_output('git', 'status', '-s')[1] return dict(reversed(line.split()) for line in git_status.splitlines()) @pytest.yield_fixture def foo_staged(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): with io.open('foo', 'w') as foo_file: foo_file.write(FOO_CONTENTS) - local['git']('add', 'foo') + cmd_output('git', 'add', 'foo') foo_filename = os.path.join(path, 'foo') yield auto_namedtuple(path=path, foo_filename=foo_filename) @@ -108,10 +109,10 @@ def test_foo_both_modify_conflicting(foo_staged, cmd_runner): @pytest.yield_fixture def img_staged(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): + with cwd(path): img_filename = os.path.join(path, 'img.jpg') shutil.copy(get_resource_path('img1.jpg'), img_filename) - local['git']('add', 'img.jpg') + cmd_output('git', 'add', 'img.jpg') yield auto_namedtuple(path=path, img_filename=img_filename) @@ -163,26 +164,28 @@ def test_img_conflict(img_staged, cmd_runner): @pytest.yield_fixture def submodule_with_commits(tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): - local['git']('commit', '--allow-empty', '-m', 'foo') - sha1 = local['git']('rev-parse', 'HEAD').strip() - local['git']('commit', '--allow-empty', '-m', 'bar') - sha2 = local['git']('rev-parse', 'HEAD').strip() + with cwd(path): + cmd_output('git', 'commit', '--allow-empty', '-m', 'foo') + sha1 = cmd_output('git', 'rev-parse', 'HEAD')[1].strip() + cmd_output('git', 'commit', '--allow-empty', '-m', 'bar') + sha2 = cmd_output('git', 'rev-parse', 'HEAD')[1].strip() yield auto_namedtuple(path=path, sha1=sha1, sha2=sha2) def checkout_submodule(sha): - with local.cwd('sub'): - local['git']('checkout', sha) + with cwd('sub'): + cmd_output('git', 'checkout', sha) @pytest.yield_fixture def sub_staged(submodule_with_commits, tmpdir_factory): path = git_dir(tmpdir_factory) - with local.cwd(path): - local['git']('submodule', 'add', submodule_with_commits.path, 'sub') + with cwd(path): + cmd_output( + 'git', 'submodule', 'add', submodule_with_commits.path, 'sub', + ) checkout_submodule(submodule_with_commits.sha1) - local['git']('add', 'sub') + cmd_output('git', 'add', 'sub') yield auto_namedtuple( path=path, sub_path=os.path.join(path, 'sub'), @@ -192,8 +195,8 @@ def sub_staged(submodule_with_commits, tmpdir_factory): def _test_sub_state(path, sha='sha1', status='A'): assert os.path.exists(path.sub_path) - with local.cwd(path.sub_path): - actual_sha = local['git']('rev-parse', 'HEAD').strip() + with cwd(path.sub_path): + actual_sha = cmd_output('git', 'rev-parse', 'HEAD')[1].strip() assert actual_sha == getattr(path.submodule, sha) actual_status = get_short_git_status()['sub'] assert actual_status == status diff --git a/tests/store_test.py b/tests/store_test.py index 4c767885..ecaee692 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -7,12 +7,13 @@ import os import os.path import pytest import shutil -from plumbum import local from pre_commit import five from pre_commit.store import _get_default_directory from pre_commit.store import logger from pre_commit.store import Store +from pre_commit.util import cmd_output +from pre_commit.util import cwd from pre_commit.util import hex_md5 from testing.fixtures import git_dir from testing.util import get_head_sha @@ -86,10 +87,10 @@ def log_info_mock(): def test_clone(store, tmpdir_factory, log_info_mock): path = git_dir(tmpdir_factory) - with local.cwd(path): - local['git']('commit', '--allow-empty', '-m', 'foo') + with cwd(path): + cmd_output('git', 'commit', '--allow-empty', '-m', 'foo') sha = get_head_sha(path) - local['git']('commit', '--allow-empty', '-m', 'bar') + cmd_output('git', 'commit', '--allow-empty', '-m', 'bar') ret = store.clone(path, sha) # Should have printed some stuff diff --git a/tests/util_test.py b/tests/util_test.py index 538ebf06..538040df 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -4,9 +4,9 @@ import pytest import os import os.path import random -from plumbum import local from pre_commit.util import clean_path_on_failure +from pre_commit.util import cwd from pre_commit.util import memoize_by_cwd from pre_commit.util import shell_escape from pre_commit.util import tmpdir @@ -37,7 +37,7 @@ def test_memoized_by_cwd_returns_different_for_different_args(memoized_by_cwd): def test_memoized_by_cwd_changes_with_different_cwd(memoized_by_cwd): ret = memoized_by_cwd('baz') - with local.cwd('.git'): + with cwd('.git'): ret2 = memoized_by_cwd('baz') assert ret != ret2