mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-19 17:14:43 +04:00
Implement 'negate' to simplify pcre
This commit is contained in:
parent
b7d395410b
commit
a932315a15
5 changed files with 51 additions and 39 deletions
|
|
@ -2,7 +2,6 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from sys import platform
|
from sys import platform
|
||||||
|
|
||||||
from pre_commit.util import shell_escape
|
|
||||||
from pre_commit.xargs import xargs
|
from pre_commit.xargs import xargs
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -19,21 +18,12 @@ def install_environment(
|
||||||
|
|
||||||
|
|
||||||
def run_hook(repo_cmd_runner, hook, file_args):
|
def run_hook(repo_cmd_runner, hook, file_args):
|
||||||
grep_command = '{0} -H -n -P'.format(
|
|
||||||
'ggrep' if platform == 'darwin' else 'grep',
|
|
||||||
)
|
|
||||||
|
|
||||||
# For PCRE the entry is the regular expression to match
|
# For PCRE the entry is the regular expression to match
|
||||||
return xargs(
|
cmd = (
|
||||||
(
|
'ggrep' if platform == 'darwin' else 'grep',
|
||||||
'sh', '-c',
|
'-H', '-n', '-P',
|
||||||
# Grep usually returns 0 for matches, and nonzero for non-matches
|
) + tuple(hook['args']) + (hook['entry'],)
|
||||||
# so we flip it here.
|
|
||||||
'! {0} {1} {2} $@'.format(
|
# Grep usually returns 0 for matches, and nonzero for non-matches so we
|
||||||
grep_command, ' '.join(hook['args']),
|
# negate it here.
|
||||||
shell_escape(hook['entry']),
|
return xargs(cmd, file_args, negate=True)
|
||||||
),
|
|
||||||
'--',
|
|
||||||
),
|
|
||||||
file_args,
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -67,10 +67,6 @@ def noop_context():
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
def shell_escape(arg):
|
|
||||||
return "'" + arg.replace("'", "'\"'\"'".strip()) + "'"
|
|
||||||
|
|
||||||
|
|
||||||
def no_git_env():
|
def no_git_env():
|
||||||
# Too many bugs dealing with environment variables and GIT:
|
# Too many bugs dealing with environment variables and GIT:
|
||||||
# https://github.com/pre-commit/pre-commit/issues/300
|
# https://github.com/pre-commit/pre-commit/issues/300
|
||||||
|
|
|
||||||
|
|
@ -42,17 +42,31 @@ def partition(cmd, varargs, _max_length=MAX_LENGTH):
|
||||||
return tuple(ret)
|
return tuple(ret)
|
||||||
|
|
||||||
|
|
||||||
def xargs(cmd, varargs):
|
def xargs(cmd, varargs, **kwargs):
|
||||||
"""A simplified implementation of xargs."""
|
"""A simplified implementation of xargs.
|
||||||
|
|
||||||
|
negate: Make nonzero successful and zero a failure
|
||||||
|
"""
|
||||||
|
negate = kwargs.pop('negate', False)
|
||||||
retcode = 0
|
retcode = 0
|
||||||
stdout = b''
|
stdout = b''
|
||||||
stderr = b''
|
stderr = b''
|
||||||
|
|
||||||
for run_cmd in partition(cmd, varargs):
|
for run_cmd in partition(cmd, varargs, **kwargs):
|
||||||
proc_retcode, proc_out, proc_err = cmd_output(
|
proc_retcode, proc_out, proc_err = cmd_output(
|
||||||
*run_cmd, encoding=None, retcode=None
|
*run_cmd, encoding=None, retcode=None
|
||||||
)
|
)
|
||||||
retcode |= proc_retcode
|
# This is *slightly* too clever so I'll explain it.
|
||||||
|
# First the xor boolean table:
|
||||||
|
# T | F |
|
||||||
|
# +-------+
|
||||||
|
# T | F | T |
|
||||||
|
# --+-------+
|
||||||
|
# F | T | F |
|
||||||
|
# --+-------+
|
||||||
|
# When negate is True, it has the effect of flipping the return code
|
||||||
|
# Otherwise, the retuncode is unchanged
|
||||||
|
retcode |= bool(proc_retcode) ^ negate
|
||||||
stdout += proc_out
|
stdout += proc_out
|
||||||
stderr += proc_err
|
stderr += proc_err
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import pytest
|
||||||
from pre_commit.util import clean_path_on_failure
|
from pre_commit.util import clean_path_on_failure
|
||||||
from pre_commit.util import cwd
|
from pre_commit.util import cwd
|
||||||
from pre_commit.util import memoize_by_cwd
|
from pre_commit.util import memoize_by_cwd
|
||||||
from pre_commit.util import shell_escape
|
|
||||||
from pre_commit.util import tmpdir
|
from pre_commit.util import tmpdir
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,18 +78,6 @@ def test_clean_path_on_failure_cleans_for_system_exit(in_tmpdir):
|
||||||
assert not os.path.exists('foo')
|
assert not os.path.exists('foo')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
('input_str', 'expected'),
|
|
||||||
(
|
|
||||||
('', "''"),
|
|
||||||
('foo"bar', "'foo\"bar'"),
|
|
||||||
("foo'bar", "'foo'\"'\"'bar'")
|
|
||||||
),
|
|
||||||
)
|
|
||||||
def test_shell_escape(input_str, expected):
|
|
||||||
assert shell_escape(input_str) == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_tmpdir():
|
def test_tmpdir():
|
||||||
with tmpdir() as tempdir:
|
with tmpdir() as tempdir:
|
||||||
assert os.path.exists(tempdir)
|
assert os.path.exists(tempdir)
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,28 @@ def test_xargs_smoke():
|
||||||
assert ret == 0
|
assert ret == 0
|
||||||
assert out == b'hello world\n'
|
assert out == b'hello world\n'
|
||||||
assert err == b''
|
assert err == b''
|
||||||
|
|
||||||
|
|
||||||
|
exit_cmd = ('bash', '-c', 'exit $1', '--')
|
||||||
|
# Abuse max_length to control the exit code
|
||||||
|
max_length = len(' '.join(exit_cmd)) + 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_xargs_negate():
|
||||||
|
ret, _, _ = xargs.xargs(
|
||||||
|
exit_cmd, ('1',), negate=True, _max_length=max_length,
|
||||||
|
)
|
||||||
|
assert ret == 0
|
||||||
|
|
||||||
|
ret, _, _ = xargs.xargs(
|
||||||
|
exit_cmd, ('1', '0'), negate=True, _max_length=max_length,
|
||||||
|
)
|
||||||
|
assert ret == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_xargs_retcode_normal():
|
||||||
|
ret, _, _ = xargs.xargs(exit_cmd, ('0',), _max_length=max_length)
|
||||||
|
assert ret == 0
|
||||||
|
|
||||||
|
ret, _, _ = xargs.xargs(exit_cmd, ('0', '1'), _max_length=max_length)
|
||||||
|
assert ret == 1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue