From 4b7f83212224b134ca8887b77ceae03fbd433002 Mon Sep 17 00:00:00 2001 From: Ofer Koren Date: Sun, 12 Jan 2020 21:18:56 +0200 Subject: [PATCH] support 'diff-only' hooks by passing diff via stdin (#1279) --- pre_commit/clientlib.py | 1 + pre_commit/commands/run.py | 10 +++++++--- pre_commit/languages/helpers.py | 4 ++++ pre_commit/util.py | 10 ++++++++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index d742ef4b..8dcb8c5d 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -67,6 +67,7 @@ MANIFEST_HOOK_DICT = cfgv.Map( cfgv.Optional('args', cfgv.check_array(cfgv.check_string), []), cfgv.Optional('always_run', cfgv.check_bool, False), cfgv.Optional('pass_filenames', cfgv.check_bool, True), + cfgv.Optional('pass_diff', cfgv.check_bool, False), cfgv.Optional('description', cfgv.check_string, ''), cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT), cfgv.Optional('log_file', cfgv.check_string, ''), diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index c5da7e3c..b41086c3 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -139,10 +139,14 @@ def _run_single_hook( diff_cmd = ('git', 'diff', '--no-ext-diff') diff_before = cmd_output_b(*diff_cmd, retcode=None) - if not hook.pass_filenames: - filenames = () + if hook.pass_diff: + inputs = (diff_before[1],) + elif hook.pass_filenames: + inputs = filenames + else: + inputs = () time_before = time.time() - retcode, out = hook.run(filenames, use_color) + retcode, out = hook.run(inputs, use_color) duration = round(time.time() - time_before, 2) or 0 diff_after = cmd_output_b(*diff_cmd, retcode=None) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index b39f57aa..3a95adac 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -106,4 +106,8 @@ def run_xargs( # but do it deterministically in case a hook cares about ordering. file_args = _shuffled(file_args) kwargs['target_concurrency'] = target_concurrency(hook) + if hook.pass_diff: + input_data, = file_args + kwargs['input_data'] = input_data + file_args = () return xargs(cmd, file_args, **kwargs) diff --git a/pre_commit/util.py b/pre_commit/util.py index 208ce497..c2d8fb1b 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -138,6 +138,7 @@ def cmd_output_b( **kwargs: Any, ) -> Tuple[int, bytes, Optional[bytes]]: retcode = kwargs.pop('retcode', 0) + input_data = kwargs.pop('input_data', None) cmd, kwargs = _cmd_kwargs(*cmd, **kwargs) try: @@ -146,7 +147,7 @@ def cmd_output_b( returncode, stdout_b, stderr_b = e.to_output() else: proc = subprocess.Popen(cmd, **kwargs) - stdout_b, stderr_b = proc.communicate() + stdout_b, stderr_b = proc.communicate(input_data) returncode = proc.returncode if retcode is not None and retcode != returncode: @@ -207,6 +208,7 @@ if os.name != 'nt': # pragma: windows no cover ) -> Tuple[int, bytes, Optional[bytes]]: assert kwargs.pop('retcode') is None assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr'] + input_data = kwargs.pop('input_data', None) cmd, kwargs = _cmd_kwargs(*cmd, **kwargs) try: @@ -216,8 +218,12 @@ if os.name != 'nt': # pragma: windows no cover with open(os.devnull) as devnull, Pty() as pty: assert pty.r is not None - kwargs.update({'stdin': devnull, 'stdout': pty.w, 'stderr': pty.w}) + stdin = subprocess.PIPE if input_data else devnull + kwargs.update({'stdin': stdin, 'stdout': pty.w, 'stderr': pty.w}) proc = subprocess.Popen(cmd, **kwargs) + if input_data: + proc.stdin.write(input_data) + proc.stdin.close() pty.close_w() buf = b''