WIP: progress dots

Based on @chriskuehl's branch here:
- f7213054ac
This commit is contained in:
Anthony Sottile 2019-10-19 13:30:02 -07:00
parent 4bd6529c05
commit f21257cdba
15 changed files with 69 additions and 31 deletions

View file

@ -110,16 +110,25 @@ def _run_single_hook(classifier, hook, args, skips, cols, use_color):
# Print the hook and the dots first in case the hook takes hella long to
# run.
output.write(
get_hook_message(
_hook_msg_start(hook, args.verbose), end_len=6, cols=cols,
),
msg, num_dots = get_hook_message(
_hook_msg_start(hook, args.verbose), end_len=6, cols=cols,
)
output.write(msg)
sys.stdout.flush()
dots_printed = [0]
def progress(perc):
dots_to_print = int(round(num_dots * perc))
sys.stdout.write('.' * (dots_to_print - dots_printed[0]))
sys.stdout.flush()
dots_printed[0] = dots_to_print
diff_before = cmd_output_b('git', 'diff', '--no-ext-diff', retcode=None)
filenames = tuple(filenames) if hook.pass_filenames else ()
retcode, out = hook.run(filenames, use_color)
retcode, out = hook.run(filenames, use_color, progress)
diff_after = cmd_output_b('git', 'diff', '--no-ext-diff', retcode=None)
file_modifications = diff_before != diff_after

View file

@ -38,7 +38,7 @@ from pre_commit.languages import system
# version - A version specified in the hook configuration or 'default'.
# """
#
# def run_hook(hook, file_args, color):
# def run_hook(hook, file_args, color, progress):
# """Runs a hook and returns the returncode and output of running that
# hook.
#
@ -46,6 +46,7 @@ from pre_commit.languages import system
# hook - `Hook`
# file_args - The files to be run
# color - whether the hook should be given a pty (when supported)
# progress - report progress as a float percentage
#
# Returns:
# (returncode, output)

View file

@ -95,7 +95,7 @@ def docker_cmd(): # pragma: windows no cover
)
def run_hook(hook, file_args, color): # pragma: windows no cover
def run_hook(hook, file_args, color, progress): # pragma: windows no cover
assert_docker_available()
# Rebuild the docker image in case it has gone missing, as many people do
# automated cleanup of docker images.
@ -106,4 +106,6 @@ def run_hook(hook, file_args, color): # pragma: windows no cover
entry_tag = ('--entrypoint', entry_exe, docker_tag(hook.prefix))
cmd = docker_cmd() + entry_tag + cmd_rest
return helpers.run_xargs(hook, cmd, file_args, color=color)
return helpers.run_xargs(
hook, cmd, file_args, color=color, progress=progress,
)

View file

@ -12,7 +12,9 @@ healthy = helpers.basic_healthy
install_environment = helpers.no_install
def run_hook(hook, file_args, color): # pragma: windows no cover
def run_hook(hook, file_args, color, progress): # pragma: windows no cover
assert_docker_available()
cmd = docker_cmd() + hook.cmd
return helpers.run_xargs(hook, cmd, file_args, color=color)
return helpers.run_xargs(
hook, cmd, file_args, color=color, progress=progress,
)

View file

@ -81,6 +81,8 @@ def install_environment(prefix, version, additional_dependencies):
rmtree(pkgdir)
def run_hook(hook, file_args, color):
def run_hook(hook, file_args, color, progress):
with in_env(hook.prefix):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)

View file

@ -78,6 +78,8 @@ def install_environment(
)
def run_hook(hook, file_args, color): # pragma: windows no cover
def run_hook(hook, file_args, color, progress): # pragma: windows no cover
with in_env(hook.prefix, hook.language_version):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)

View file

@ -151,9 +151,11 @@ def py_interface(_dir, _make_venv):
)
return retcode == 0
def run_hook(hook, file_args, color):
def run_hook(hook, file_args, color, progress):
with in_env(hook.prefix, hook.language_version):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)
def install_environment(prefix, version, additional_dependencies):
additional_dependencies = tuple(additional_dependencies)

View file

@ -124,6 +124,8 @@ def install_environment(
)
def run_hook(hook, file_args, color): # pragma: windows no cover
def run_hook(hook, file_args, color, progress): # pragma: windows no cover
with in_env(hook.prefix, hook.language_version):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)

View file

@ -89,6 +89,8 @@ def install_environment(prefix, version, additional_dependencies):
)
def run_hook(hook, file_args, color):
def run_hook(hook, file_args, color, progress):
with in_env(hook.prefix):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)

View file

@ -9,7 +9,9 @@ healthy = helpers.basic_healthy
install_environment = helpers.no_install
def run_hook(hook, file_args, color):
def run_hook(hook, file_args, color, progress):
cmd = hook.cmd
cmd = (hook.prefix.path(cmd[0]),) + cmd[1:]
return helpers.run_xargs(hook, cmd, file_args, color=color)
return helpers.run_xargs(
hook, cmd, file_args, color=color, progress=progress,
)

View file

@ -51,6 +51,8 @@ def install_environment(
)
def run_hook(hook, file_args, color): # pragma: windows no cover
def run_hook(hook, file_args, color, progress): # pragma: windows no cover
with in_env(hook.prefix):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)

View file

@ -9,5 +9,7 @@ healthy = helpers.basic_healthy
install_environment = helpers.no_install
def run_hook(hook, file_args, color):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
def run_hook(hook, file_args, color, progress):
return helpers.run_xargs(
hook, hook.cmd, file_args, color=color, progress=progress,
)

View file

@ -54,7 +54,10 @@ def get_hook_message(
)
if end_len:
return start + '.' * (cols - len(start) - end_len - 1)
num_dots = cols - len(start) - end_len - 1
if end_msg is None:
return start, num_dots
return start + '.' * num_dots
else:
return '{}{}{}{}\n'.format(
start,

View file

@ -100,9 +100,9 @@ class Hook(collections.namedtuple('Hook', ('src', 'prefix') + _KEYS)):
# Write our state to indicate we're installed
_write_state(self.prefix, venv, _state(self.additional_dependencies))
def run(self, file_args, color):
def run(self, file_args, color, progress):
lang = languages[self.language]
return lang.run_hook(self, file_args, color)
return lang.run_hook(self, file_args, color, progress)
@classmethod
def create(cls, src, prefix, dct):

View file

@ -112,6 +112,7 @@ def xargs(cmd, varargs, **kwargs):
color = kwargs.pop('color', False)
negate = kwargs.pop('negate', False)
target_concurrency = kwargs.pop('target_concurrency', 1)
progress = kwargs.pop('progress', lambda _: None)
max_length = kwargs.pop('_max_length', _get_platform_max_length())
cmd_fn = cmd_output_p if color else cmd_output_b
retcode = 0
@ -125,15 +126,17 @@ def xargs(cmd, varargs, **kwargs):
partitions = partition(cmd, varargs, target_concurrency, max_length)
def run_cmd_partition(run_cmd):
return cmd_fn(
ret = cmd_fn(
*run_cmd, retcode=None, stderr=subprocess.STDOUT, **kwargs
)
return ret, len(run_cmd) - len(cmd)
threads = min(len(partitions), target_concurrency)
with _thread_mapper(threads) as thread_map:
results = thread_map(run_cmd_partition, partitions)
for proc_retcode, proc_out, _ in results:
total_processed = 0
for (proc_retcode, proc_out, _), processed in results:
# This is *slightly* too clever so I'll explain it.
# First the xor boolean table:
# T | F |
@ -146,5 +149,7 @@ def xargs(cmd, varargs, **kwargs):
# code. Otherwise, the returncode is unchanged.
retcode |= bool(proc_retcode) ^ negate
stdout += proc_out
total_processed += processed
progress(float(total_processed) / len(varargs))
return retcode, stdout