From 09ffe421a9c1f35934ef1d6f7b14c15c6515381b Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 6 Sep 2021 15:01:42 -0400 Subject: [PATCH 001/416] add a bug report issue form --- .github/ISSUE_TEMPLATE/bug.yaml | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug.yaml diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml new file mode 100644 index 00000000..6cce5fef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -0,0 +1,41 @@ +name: bug report +description: something went wrong +body: + - type: markdown + attributes: + value: | + this is for issues for `pre-commit` (the framework). + if you are reporting an issue for [pre-commit.ci] please report it at [pre-commit-ci/issues] + + [pre-commit.ci]: https://pre-commit.ci + [pre-commit-ci/issues]: https://github.com/pre-commit-ci/issues + - type: textarea + id: freeform + attributes: + label: describe your issue + placeholder: 'I was doing ... I ran ... I expected ... I got ...' + validations: + required: true + - type: input + id: version + attributes: + label: pre-commit --version + placeholder: pre-commit x.x.x + validations: + required: true + - type: textarea + id: configuration + attributes: + label: .pre-commit-config.yaml + description: (auto-rendered as yaml, no need for backticks) + placeholder: 'repos: ...' + render: yaml + validations: + required: true + - type: textarea + id: error-log + attributes: + label: '~/.cache/pre-commit/pre-commit.log (if present)' + placeholder: "### version information\n..." + validations: + required: false From ab94dd69f8408e95c6a49a0e3aa21eeaf39d3f1c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 13 Sep 2021 20:01:25 -0400 Subject: [PATCH 002/416] fix pre-commit autoupdate for core.useBuiltinFSMonitor=true on windows --- pre_commit/commands/autoupdate.py | 22 +++++++++++++++++----- pre_commit/git.py | 9 ++++++--- tests/commands/autoupdate_test.py | 9 +++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 33a34730..5cb978e9 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -36,24 +36,36 @@ class RevInfo(NamedTuple): return cls(config['repo'], config['rev'], None) def update(self, tags_only: bool, freeze: bool) -> 'RevInfo': + git_cmd = ('git', *git.NO_FS_MONITOR) + if tags_only: - tag_cmd = ('git', 'describe', 'FETCH_HEAD', '--tags', '--abbrev=0') + tag_cmd = ( + *git_cmd, 'describe', + 'FETCH_HEAD', '--tags', '--abbrev=0', + ) else: - tag_cmd = ('git', 'describe', 'FETCH_HEAD', '--tags', '--exact') + tag_cmd = ( + *git_cmd, 'describe', + 'FETCH_HEAD', '--tags', '--exact', + ) with tmpdir() as tmp: git.init_repo(tmp, self.repo) - cmd_output_b('git', 'fetch', 'origin', 'HEAD', '--tags', cwd=tmp) + cmd_output_b( + *git_cmd, 'fetch', 'origin', 'HEAD', '--tags', + cwd=tmp, + ) try: rev = cmd_output(*tag_cmd, cwd=tmp)[1].strip() except CalledProcessError: - cmd = ('git', 'rev-parse', 'FETCH_HEAD') + cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD') rev = cmd_output(*cmd, cwd=tmp)[1].strip() frozen = None if freeze: - exact = cmd_output('git', 'rev-parse', rev, cwd=tmp)[1].strip() + exact_rev_cmd = (*git_cmd, 'rev-parse', rev) + exact = cmd_output(*exact_rev_cmd, cwd=tmp)[1].strip() if exact != rev: rev, frozen = exact, rev return self._replace(rev=rev, frozen=frozen) diff --git a/pre_commit/git.py b/pre_commit/git.py index 6264529d..883723ea 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -12,9 +12,11 @@ from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b - logger = logging.getLogger(__name__) +# see #2046 +NO_FS_MONITOR = ('-c', 'core.useBuiltinFSMonitor=false') + def zsplit(s: str) -> List[str]: s = s.strip('\0') @@ -185,10 +187,11 @@ def init_repo(path: str, remote: str) -> None: if os.path.isdir(remote): remote = os.path.abspath(remote) + git = ('git', *NO_FS_MONITOR) env = no_git_env() # avoid the user's template so that hooks do not recurse - cmd_output_b('git', 'init', '--template=', path, env=env) - cmd_output_b('git', 'remote', 'add', 'origin', remote, cwd=path, env=env) + cmd_output_b(*git, 'init', '--template=', path, env=env) + cmd_output_b(*git, 'remote', 'add', 'origin', remote, cwd=path, env=env) def commit(repo: str = '.') -> None: diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index b2bad601..7316eb97 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -5,6 +5,7 @@ import pytest import yaml import pre_commit.constants as C +from pre_commit import envcontext from pre_commit import git from pre_commit import util from pre_commit.commands.autoupdate import _check_hooks_still_exist_at_rev @@ -176,6 +177,14 @@ def test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store): assert cfg.read() == fmt.format(out_of_date.path, out_of_date.head_rev) +def test_autoupdate_with_core_useBuiltinFSMonitor(out_of_date, tmpdir, store): + # force the setting on "globally" for git + home = tmpdir.join('fakehome').ensure_dir() + home.join('.gitconfig').write('[core]\nuseBuiltinFSMonitor = true\n') + with envcontext.envcontext((('HOME', str(home)),)): + test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store) + + def test_autoupdate_pure_yaml(out_of_date, tmpdir, store): with mock.patch.object(util, 'Dumper', yaml.SafeDumper): test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store) From cef9c4af03e954e5fe3e8746a49ac59e4781747d Mon Sep 17 00:00:00 2001 From: Radek SPRTA Date: Fri, 17 Sep 2021 21:16:11 +0200 Subject: [PATCH 003/416] Add warning for regular expression with [\/] (#2043) --- pre_commit/clientlib.py | 24 ++++++++++++++ tests/clientlib_test.py | 72 ++++++++++++++++++++++++++++------------- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index bc7274a7..7d87ee04 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -143,6 +143,18 @@ class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault): f"regex, not a glob -- matching '/*' probably isn't what you " f'want here', ) + if r'[\/]' in dct.get(self.key, ''): + logger.warning( + fr'pre-commit normalizes slashes in the {self.key!r} field ' + fr'in hook {dct.get("id")!r} to forward slashes, so you ' + fr'can use / instead of [\/]', + ) + if r'[/\\]' in dct.get(self.key, ''): + logger.warning( + fr'pre-commit normalizes slashes in the {self.key!r} field ' + fr'in hook {dct.get("id")!r} to forward slashes, so you ' + fr'can use / instead of [/\\]', + ) class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): @@ -154,6 +166,18 @@ class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): f'The top-level {self.key!r} field is a regex, not a glob -- ' f"matching '/*' probably isn't what you want here", ) + if r'[\/]' in dct.get(self.key, ''): + logger.warning( + fr'pre-commit normalizes the slashes in the top-level ' + fr'{self.key!r} field to forward slashes, so you can use / ' + fr'instead of [\/]', + ) + if r'[/\\]' in dct.get(self.key, ''): + logger.warning( + fr'pre-commit normalizes the slashes in the top-level ' + fr'{self.key!r} field to forward slashes, so you can use / ' + fr'instead of [/\\]', + ) class MigrateShaToRev: diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index da794e6e..5427b1da 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -247,38 +247,64 @@ def test_warn_mutable_rev_conditional(): cfgv.validate(config_obj, CONFIG_REPO_DICT) -def test_validate_optional_sensible_regex_at_hook_level(caplog): - config_obj = { - 'id': 'flake8', - 'files': 'dir/*.py', - } - cfgv.validate(config_obj, CONFIG_HOOK_DICT) - - assert caplog.record_tuples == [ +@pytest.mark.parametrize( + ('regex', 'warning'), + ( ( - 'pre_commit', - logging.WARNING, + r'dir/*.py', "The 'files' field in hook 'flake8' is a regex, not a glob -- " "matching '/*' probably isn't what you want here", ), - ] - - -def test_validate_optional_sensible_regex_at_top_level(caplog): + ( + r'dir[\/].*\.py', + r"pre-commit normalizes slashes in the 'files' field in hook " + r"'flake8' to forward slashes, so you can use / instead of [\/]", + ), + ( + r'dir[/\\].*\.py', + r"pre-commit normalizes slashes in the 'files' field in hook " + r"'flake8' to forward slashes, so you can use / instead of [/\\]", + ), + ), +) +def test_validate_optional_sensible_regex_at_hook(caplog, regex, warning): config_obj = { - 'files': 'dir/*.py', + 'id': 'flake8', + 'files': regex, + } + cfgv.validate(config_obj, CONFIG_HOOK_DICT) + + assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)] + + +@pytest.mark.parametrize( + ('regex', 'warning'), + ( + ( + r'dir/*.py', + "The top-level 'files' field is a regex, not a glob -- " + "matching '/*' probably isn't what you want here", + ), + ( + r'dir[\/].*\.py', + r"pre-commit normalizes the slashes in the top-level 'files' " + r'field to forward slashes, so you can use / instead of [\/]', + ), + ( + r'dir[/\\].*\.py', + r"pre-commit normalizes the slashes in the top-level 'files' " + r'field to forward slashes, so you can use / instead of [/\\]', + ), + ), +) +def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning): + config_obj = { + 'files': regex, 'repos': [], } cfgv.validate(config_obj, CONFIG_SCHEMA) - assert caplog.record_tuples == [ - ( - 'pre_commit', - logging.WARNING, - "The top-level 'files' field is a regex, not a glob -- matching " - "'/*' probably isn't what you want here", - ), - ] + assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)] @pytest.mark.parametrize('fn', (validate_config_main, validate_manifest_main)) From e622f793c3de2276d6975358c7e35e9b890fbdfd Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 27 Sep 2021 19:34:04 -0400 Subject: [PATCH 004/416] port hook template to bash this avoids some version-specific code in python this also makes the bootstrap script slightly more portable --- pre_commit/commands/install_uninstall.py | 13 +++--- pre_commit/resources/hook-tmpl | 50 ++++++------------------ tests/commands/install_uninstall_test.py | 6 +-- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index 73c8d605..7974423b 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -1,6 +1,7 @@ import itertools import logging import os.path +import shlex import shutil import sys from typing import Optional @@ -100,19 +101,17 @@ def _install_hook_script( args = ['hook-impl', f'--config={config_file}', f'--hook-type={hook_type}'] if skip_on_missing_config: args.append('--skip-on-missing-config') - params = {'INSTALL_PYTHON': sys.executable, 'ARGS': args} with open(hook_path, 'w') as hook_file: contents = resource_text('hook-tmpl') before, rest = contents.split(TEMPLATE_START) - to_template, after = rest.split(TEMPLATE_END) - - before = before.replace('#!/usr/bin/env python3', shebang()) + _, after = rest.split(TEMPLATE_END) hook_file.write(before + TEMPLATE_START) - for line in to_template.splitlines(): - var = line.split()[0] - hook_file.write(f'{var} = {params[var]!r}\n') + hook_file.write(f'INSTALL_PYTHON={shlex.quote(sys.executable)}\n') + # TODO: python3.8+: shlex.join + args_s = ' '.join(shlex.quote(part) for part in args) + hook_file.write(f'ARGS=({args_s})\n') hook_file.write(TEMPLATE_END + after) make_executable(hook_path) diff --git a/pre_commit/resources/hook-tmpl b/pre_commit/resources/hook-tmpl index 299144ec..1dd66a2a 100755 --- a/pre_commit/resources/hook-tmpl +++ b/pre_commit/resources/hook-tmpl @@ -1,44 +1,20 @@ -#!/usr/bin/env python3 +#!/usr/bin/env bash # File generated by pre-commit: https://pre-commit.com # ID: 138fd403232d2ddd5efb44317e38bf03 -import os -import sys - -# we try our best, but the shebang of this script is difficult to determine: -# - macos doesn't ship with python3 -# - windows executables are almost always `python.exe` -# therefore we continue to support python2 for this small script -if sys.version_info < (3, 3): - from distutils.spawn import find_executable as which -else: - from shutil import which - -# work around https://github.com/Homebrew/homebrew-core/issues/30445 -os.environ.pop('__PYVENV_LAUNCHER__', None) # start templated -INSTALL_PYTHON = '' -ARGS = ['hook-impl'] +INSTALL_PYTHON='' +ARGS=(hook-impl) # end templated -ARGS.extend(('--hook-dir', os.path.realpath(os.path.dirname(__file__)))) -ARGS.append('--') -ARGS.extend(sys.argv[1:]) -DNE = '`pre-commit` not found. Did you forget to activate your virtualenv?' -if os.access(INSTALL_PYTHON, os.X_OK): - CMD = [INSTALL_PYTHON, '-mpre_commit'] -elif which('pre-commit'): - CMD = ['pre-commit'] -else: - raise SystemExit(DNE) +HERE="$(cd "$(dirname "$0")" && pwd)" +ARGS+=(--hook-dir "$HERE" -- "$@") -CMD.extend(ARGS) -if sys.platform == 'win32': # https://bugs.python.org/issue19124 - import subprocess - - if sys.version_info < (3, 7): # https://bugs.python.org/issue25942 - raise SystemExit(subprocess.Popen(CMD).wait()) - else: - raise SystemExit(subprocess.call(CMD)) -else: - os.execvp(CMD[0], CMD) +if [ -x "$INSTALL_PYTHON" ]; then + exec "$INSTALL_PYTHON" -mpre_commit "${ARGS[@]}" +elif command -v pre-commit; then + exec pre-commit "${ARGS[@]}" +else + echo '`pre-commit` not found. Did you forget to activate your virtualenv?' 1>&2 + exit 1 +fi diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 3c071242..83399034 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -278,11 +278,7 @@ def test_environment_not_sourced(tempdir_factory, store): hook = os.path.join(path, '.git/hooks/pre-commit') with open(hook) as f: src = f.read() - src = re.sub( - '\nINSTALL_PYTHON =.*\n', - '\nINSTALL_PYTHON = "/dne"\n', - src, - ) + src = re.sub('\nINSTALL_PYTHON=.*\n', '\nINSTALL_PYTHON="/dne"\n', src) with open(hook, 'w') as f: f.write(src) From 2fc00f73b640fa1ef149a38260b616f89d32a344 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 27 Sep 2021 19:59:58 -0400 Subject: [PATCH 005/416] un-xfail node on windows these have been reasonably stable for a while --- tests/repository_test.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/repository_test.py b/tests/repository_test.py index 4121fed4..6f4047c3 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -245,7 +245,6 @@ def test_run_a_docker_image_hook(tempdir_factory, store, hook_id): ) -@xfailif_windows # pragma: win32 no cover def test_run_a_node_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'node_hooks_repo', @@ -253,7 +252,6 @@ def test_run_a_node_hook(tempdir_factory, store): ) -@xfailif_windows # pragma: win32 no cover def test_run_a_node_hook_default_version(tempdir_factory, store): # make sure that this continues to work for platforms where node is not # installed at the system @@ -263,7 +261,6 @@ def test_run_a_node_hook_default_version(tempdir_factory, store): test_run_a_node_hook(tempdir_factory, store) -@xfailif_windows # pragma: win32 no cover def test_run_versioned_node_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'node_versioned_hooks_repo', @@ -271,7 +268,6 @@ def test_run_versioned_node_hook(tempdir_factory, store): ) -@xfailif_windows # pragma: win32 no cover def test_node_hook_with_npm_userconfig_set(tempdir_factory, store, tmpdir): cfg = tmpdir.join('cfg') cfg.write('cache=/dne\n') @@ -653,7 +649,6 @@ def test_additional_ruby_dependencies_installed(tempdir_factory, store): assert 'tins' in output -@xfailif_windows # pragma: win32 no cover def test_additional_node_dependencies_installed(tempdir_factory, store): path = make_repo(tempdir_factory, 'node_hooks_repo') config = make_config_from_repo(path) From e9ed248a15b89faeb0389877b02d1f78ffe24243 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 1 Oct 2021 18:45:36 -0400 Subject: [PATCH 006/416] make sure to not discard changes even if submodule.recurse=1 --- pre_commit/staged_files_only.py | 10 ++++++-- tests/staged_files_only_test.py | 43 +++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index 48cc1029..bad004cd 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -13,6 +13,12 @@ from pre_commit.xargs import xargs logger = logging.getLogger('pre_commit') +# without forcing submodule.recurse=0, changes in nested submodules will be +# discarded if `submodule.recurse=1` is configured +# we choose this instead of `--no-recurse-submodules` because it works on +# versions of git before that option was added to `git checkout` +_CHECKOUT_CMD = ('git', '-c', 'submodule.recurse=0', 'checkout', '--', '.') + def _git_apply(patch: str) -> None: args = ('apply', '--whitespace=nowarn', patch) @@ -58,7 +64,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: # prevent recursive post-checkout hooks (#1418) no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1') - cmd_output_b('git', 'checkout', '--', '.', env=no_checkout_env) + cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env) try: yield @@ -74,7 +80,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: # We failed to apply the patch, presumably due to fixes made # by hooks. # Roll back the changes made by hooks. - cmd_output_b('git', 'checkout', '--', '.', env=no_checkout_env) + cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env) _git_apply(patch_filename) logger.info(f'Restored changes from {patch_filename}.') diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index ddb95743..2e3f6209 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -181,9 +181,11 @@ def test_img_conflict(img_staged, patch_dir): @pytest.fixture -def submodule_with_commits(tempdir_factory): +def repo_with_commits(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): + open('foo', 'a+').close() + cmd_output('git', 'add', 'foo') git_commit() rev1 = cmd_output('git', 'rev-parse', 'HEAD')[1].strip() git_commit() @@ -196,18 +198,21 @@ def checkout_submodule(rev): @pytest.fixture -def sub_staged(submodule_with_commits, tempdir_factory): +def sub_staged(repo_with_commits, tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): + open('bar', 'a+').close() + cmd_output('git', 'add', 'bar') + git_commit() cmd_output( - 'git', 'submodule', 'add', submodule_with_commits.path, 'sub', + 'git', 'submodule', 'add', repo_with_commits.path, 'sub', ) - checkout_submodule(submodule_with_commits.rev1) + checkout_submodule(repo_with_commits.rev1) cmd_output('git', 'add', 'sub') yield auto_namedtuple( path=path, sub_path=os.path.join(path, 'sub'), - submodule=submodule_with_commits, + submodule=repo_with_commits, ) @@ -242,6 +247,34 @@ def test_sub_something_unstaged(sub_staged, patch_dir): _test_sub_state(sub_staged, 'rev2', 'AM') +def test_submodule_does_not_discard_changes(sub_staged, patch_dir): + with open('bar', 'w') as f: + f.write('unstaged changes') + + foo_path = os.path.join(sub_staged.sub_path, 'foo') + with open(foo_path, 'w') as f: + f.write('foo contents') + + with staged_files_only(patch_dir): + with open('bar') as f: + assert f.read() == '' + + with open(foo_path) as f: + assert f.read() == 'foo contents' + + with open('bar') as f: + assert f.read() == 'unstaged changes' + + with open(foo_path) as f: + assert f.read() == 'foo contents' + + +def test_submodule_does_not_discard_changes_recurse(sub_staged, patch_dir): + cmd_output('git', 'config', 'submodule.recurse', '1', cwd=sub_staged.path) + + test_submodule_does_not_discard_changes(sub_staged, patch_dir) + + def test_stage_utf8_changes(foo_staged, patch_dir): contents = '\u2603' with open('foo', 'w', encoding='UTF-8') as foo_file: From 0acf2e99c4e81757beff37cf399d066a57ae1ddf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Oct 2021 18:54:25 +0000 Subject: [PATCH 007/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.25.0 → v2.29.0](https://github.com/asottile/pyupgrade/compare/v2.25.0...v2.29.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 57466c70..eb1995b5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: hooks: - id: validate_manifest - repo: https://github.com/asottile/pyupgrade - rev: v2.25.0 + rev: v2.29.0 hooks: - id: pyupgrade args: [--py36-plus] From 247d892e69007de18d7b0c3fdd36056b50f43d02 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 18:53:36 +0000 Subject: [PATCH 008/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1) - [github.com/asottile/setup-cfg-fmt: v1.17.0 → v1.18.0](https://github.com/asottile/setup-cfg-fmt/compare/v1.17.0...v1.18.0) - [github.com/pre-commit/mirrors-mypy: v0.910 → v0.910-1](https://github.com/pre-commit/mirrors-mypy/compare/v0.910...v0.910-1) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eb1995b5..f635586b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: requirements-txt-fixer - id: double-quote-string-fixer - repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 + rev: 4.0.1 hooks: - id: flake8 additional_dependencies: [flake8-typing-imports==1.10.0] @@ -40,11 +40,11 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.17.0 + rev: v1.18.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910 + rev: v0.910-1 hooks: - id: mypy additional_dependencies: [types-all] From 69a4dbda68d3db74ad217277dac653ab68404bf4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 18:53:57 +0000 Subject: [PATCH 009/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index c0f4f0eb..26832b82 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,6 +17,7 @@ classifiers = Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy From 8c844c794d97a7be75c57f5b8d7df2a7674e768f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 11 Oct 2021 20:20:30 -0400 Subject: [PATCH 010/416] work around conda bug installing python3.1/site-packages https://github.com/conda/conda/issues/10969 --- tests/repository_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/repository_test.py b/tests/repository_test.py index 6f4047c3..5f259070 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -111,8 +111,8 @@ def test_local_conda_additional_dependencies(store): 'name': 'local-conda', 'entry': 'python', 'language': 'conda', - 'args': ['-c', 'import tzdata; print("OK")'], - 'additional_dependencies': ['python-tzdata'], + 'args': ['-c', 'import botocore; print("OK")'], + 'additional_dependencies': ['botocore'], }], } hook = _get_hook(config, store, 'local-conda') From d0c9e589ca41d8b2a072e518bbaecb0df28e33d6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 19 Oct 2021 19:02:36 -0700 Subject: [PATCH 011/416] ban broken importlib-resources versions --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 26832b82..975dd77b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,7 +31,7 @@ install_requires = toml virtualenv>=20.0.8 importlib-metadata;python_version<"3.8" - importlib-resources;python_version<"3.7" + importlib-resources<5.3;python_version<"3.7" python_requires = >=3.6.1 [options.packages.find] From 63ae399db0b220b0e59b7055b98391b6851c2246 Mon Sep 17 00:00:00 2001 From: Stojan Nedic Date: Tue, 19 Oct 2021 22:17:42 +0200 Subject: [PATCH 012/416] Add fail_fast support per-hook --- pre_commit/clientlib.py | 1 + pre_commit/commands/run.py | 2 +- pre_commit/hook.py | 1 + tests/commands/run_test.py | 12 ++++++++++++ tests/repository_test.py | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 7d87ee04..6377a8b6 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -70,6 +70,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('fail_fast', cfgv.check_bool, False), cfgv.Optional('pass_filenames', cfgv.check_bool, True), cfgv.Optional('description', cfgv.check_string, ''), cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT), diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 95ad5e96..2714faf4 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -290,7 +290,7 @@ def _run_hooks( verbose=args.verbose, use_color=args.color, ) retval |= current_retval - if retval and config['fail_fast']: + if retval and (config['fail_fast'] or hook.fail_fast): break if retval and args.show_diff_on_failure and prior_diff: if args.all_files: diff --git a/pre_commit/hook.py b/pre_commit/hook.py index ea773942..82e99c54 100644 --- a/pre_commit/hook.py +++ b/pre_commit/hook.py @@ -27,6 +27,7 @@ class Hook(NamedTuple): additional_dependencies: Sequence[str] args: Sequence[str] always_run: bool + fail_fast: bool pass_filenames: bool description: str language_version: str diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 8c153957..3a6fa2a1 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -985,6 +985,18 @@ def test_fail_fast(cap_out, store, repo_with_failing_hook): assert printed.count(b'Failing hook') == 1 +def test_fail_fast_per_hook(cap_out, store, repo_with_failing_hook): + with modify_config() as config: + # More than one hook + config['repos'][0]['hooks'] *= 2 + config['repos'][0]['hooks'][0]['fail_fast'] = True + stage_a_file() + + ret, printed = _do_run(cap_out, store, repo_with_failing_hook, run_opts()) + # it should have only run one hook + assert printed.count(b'Failing hook') == 1 + + def test_classifier_removes_dne(): classifier = Classifier(('this_file_does_not_exist',)) assert classifier.filenames == [] diff --git a/tests/repository_test.py b/tests/repository_test.py index 5f259070..96c54e83 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1002,6 +1002,7 @@ def test_manifest_hooks(tempdir_factory, store): types=['file'], types_or=[], verbose=False, + fail_fast=False, ) From c8cf74dc718ee42cb6db8c0ac7dccc25b219474d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 23 Oct 2021 13:23:48 -0400 Subject: [PATCH 013/416] replace exit(main()) with raise SystemExit(main()) Committed via https://github.com/asottile/all-repos --- pre_commit/__main__.py | 2 +- pre_commit/languages/pygrep.py | 2 +- pre_commit/main.py | 2 +- pre_commit/meta_hooks/check_hooks_apply.py | 2 +- pre_commit/meta_hooks/check_useless_excludes.py | 2 +- pre_commit/meta_hooks/identity.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pre_commit/__main__.py b/pre_commit/__main__.py index 54140687..83bd93ca 100644 --- a/pre_commit/__main__.py +++ b/pre_commit/__main__.py @@ -2,4 +2,4 @@ from pre_commit.main import main if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index c80d6794..a713c3fb 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -124,4 +124,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/pre_commit/main.py b/pre_commit/main.py index 2b50c91b..f1e8d03d 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -411,4 +411,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/pre_commit/meta_hooks/check_hooks_apply.py b/pre_commit/meta_hooks/check_hooks_apply.py index a1e93529..a6eb0e09 100644 --- a/pre_commit/meta_hooks/check_hooks_apply.py +++ b/pre_commit/meta_hooks/check_hooks_apply.py @@ -39,4 +39,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/pre_commit/meta_hooks/check_useless_excludes.py b/pre_commit/meta_hooks/check_useless_excludes.py index 61165973..60870f83 100644 --- a/pre_commit/meta_hooks/check_useless_excludes.py +++ b/pre_commit/meta_hooks/check_useless_excludes.py @@ -77,4 +77,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/pre_commit/meta_hooks/identity.py b/pre_commit/meta_hooks/identity.py index 730d0ec0..12eb02f9 100644 --- a/pre_commit/meta_hooks/identity.py +++ b/pre_commit/meta_hooks/identity.py @@ -13,4 +13,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) From 28cafc2273c4d331af1736151007833daa299749 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 24 Oct 2021 07:19:57 -0700 Subject: [PATCH 014/416] exit(main()) -> raise SystemExit(main()) pt2 Committed via https://github.com/asottile/all-repos --- testing/gen-languages-all | 2 +- testing/make-archives | 2 +- testing/zipapp/entry | 2 +- testing/zipapp/make | 2 +- testing/zipapp/python | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/gen-languages-all b/testing/gen-languages-all index 51e4bce6..c933c143 100755 --- a/testing/gen-languages-all +++ b/testing/gen-languages-all @@ -25,4 +25,4 @@ def main() -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/testing/make-archives b/testing/make-archives index cb0b0a40..707fd884 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -80,4 +80,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/testing/zipapp/entry b/testing/zipapp/entry index f0a345e6..87f9291d 100755 --- a/testing/zipapp/entry +++ b/testing/zipapp/entry @@ -68,4 +68,4 @@ def main() -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/testing/zipapp/make b/testing/zipapp/make index 8740b2f5..55b6d2c7 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -106,4 +106,4 @@ def main() -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) diff --git a/testing/zipapp/python b/testing/zipapp/python index 97c5928e..7184a1aa 100755 --- a/testing/zipapp/python +++ b/testing/zipapp/python @@ -45,4 +45,4 @@ def main() -> int: if __name__ == '__main__': - exit(main()) + raise SystemExit(main()) From 2b30fbcfd582d2685c401fa05cab3621f6fdf17b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Oct 2021 18:59:17 +0000 Subject: [PATCH 015/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/add-trailing-comma: v2.1.0 → v2.2.0](https://github.com/asottile/add-trailing-comma/compare/v2.1.0...v2.2.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f635586b..0ea04f70 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: - id: reorder-python-imports args: [--py3-plus] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.1.0 + rev: v2.2.0 hooks: - id: add-trailing-comma args: [--py36-plus] From 0b87867729501287937c633889a677437630353b Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 28 Oct 2021 21:21:59 -0700 Subject: [PATCH 016/416] silence the output of `command -v` --- pre_commit/resources/hook-tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/resources/hook-tmpl b/pre_commit/resources/hook-tmpl index 1dd66a2a..4ebeb2e1 100755 --- a/pre_commit/resources/hook-tmpl +++ b/pre_commit/resources/hook-tmpl @@ -12,7 +12,7 @@ ARGS+=(--hook-dir "$HERE" -- "$@") if [ -x "$INSTALL_PYTHON" ]; then exec "$INSTALL_PYTHON" -mpre_commit "${ARGS[@]}" -elif command -v pre-commit; then +elif command -v pre-commit > /dev/null; then exec pre-commit "${ARGS[@]}" else echo '`pre-commit` not found. Did you forget to activate your virtualenv?' 1>&2 From 087541cb2d7ec46e5271df53eb6edf747619e720 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 30 Oct 2021 12:11:52 -0400 Subject: [PATCH 017/416] fix indent in hook-tmpl --- pre_commit/resources/hook-tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/resources/hook-tmpl b/pre_commit/resources/hook-tmpl index 4ebeb2e1..53d29f95 100755 --- a/pre_commit/resources/hook-tmpl +++ b/pre_commit/resources/hook-tmpl @@ -15,6 +15,6 @@ if [ -x "$INSTALL_PYTHON" ]; then elif command -v pre-commit > /dev/null; then exec pre-commit "${ARGS[@]}" else - echo '`pre-commit` not found. Did you forget to activate your virtualenv?' 1>&2 - exit 1 + echo '`pre-commit` not found. Did you forget to activate your virtualenv?' 1>&2 + exit 1 fi From 141e18319a8863ed495e419e3d6d8731e98434ce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 19:35:28 +0000 Subject: [PATCH 018/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v1.18.0 → v1.19.0](https://github.com/asottile/setup-cfg-fmt/compare/v1.18.0...v1.19.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ea04f70..98571aaa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,7 +40,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.18.0 + rev: v1.19.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy From b2a35414aaadf9c1bd4b5770ed3afe445a7d4aa6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 22 Nov 2021 18:41:26 -0500 Subject: [PATCH 019/416] bump perltidy version --- tests/repository_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/repository_test.py b/tests/repository_test.py index 96c54e83..c787eb02 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1021,13 +1021,13 @@ def test_local_perl_additional_dependencies(store): 'name': 'hello', 'entry': 'perltidy --version', 'language': 'perl', - 'additional_dependencies': ['SHANCOCK/Perl-Tidy-20200110.tar.gz'], + 'additional_dependencies': ['SHANCOCK/Perl-Tidy-20211029.tar.gz'], }], } hook = _get_hook(config, store, 'hello') ret, out = _hook_run(hook, (), color=False) assert ret == 0 - assert _norm_out(out).startswith(b'This is perltidy, v20200110') + assert _norm_out(out).startswith(b'This is perltidy, v20211029') @pytest.mark.parametrize( From a064f248d7a48980393bb76d2d82eef55319df74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Nov 2021 19:51:34 +0000 Subject: [PATCH 020/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.29.0 → v2.29.1](https://github.com/asottile/pyupgrade/compare/v2.29.0...v2.29.1) - [github.com/asottile/add-trailing-comma: v2.2.0 → v2.2.1](https://github.com/asottile/add-trailing-comma/compare/v2.2.0...v2.2.1) - [github.com/asottile/setup-cfg-fmt: v1.19.0 → v1.20.0](https://github.com/asottile/setup-cfg-fmt/compare/v1.19.0...v1.20.0) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 98571aaa..2bdfee07 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: hooks: - id: validate_manifest - repo: https://github.com/asottile/pyupgrade - rev: v2.29.0 + rev: v2.29.1 hooks: - id: pyupgrade args: [--py36-plus] @@ -35,12 +35,12 @@ repos: - id: reorder-python-imports args: [--py3-plus] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.2.0 + rev: v2.2.1 hooks: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.19.0 + rev: v1.20.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy From 4eb91cdd8e45f968f70605c3a1568016a0d2d0e1 Mon Sep 17 00:00:00 2001 From: Marius Zwicker Date: Mon, 22 Nov 2021 21:54:58 +0100 Subject: [PATCH 021/416] support gitconfig from env Add exceptions to the git env so externally configured gitconfig values set via GIT_CONFIG_KEY_, GIT_CONFIG_VALUE_ and GIT_CONFIG_COUNT get passed through. --- pre_commit/git.py | 3 ++- tests/git_test.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index 883723ea..e9ec6014 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -41,9 +41,10 @@ def no_git_env( return { k: v for k, v in _env.items() if not k.startswith('GIT_') or + k.startswith(('GIT_CONFIG_KEY_', 'GIT_CONFIG_VALUE_')) or k in { 'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO', - 'GIT_SSL_NO_VERIFY', + 'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT', } } diff --git a/tests/git_test.py b/tests/git_test.py index aa218804..bcb3fd15 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -227,6 +227,11 @@ def test_no_git_env(): 'GIT_SSH': '/usr/bin/ssh', 'GIT_SSH_COMMAND': 'ssh -o', 'GIT_DIR': '/none/shall/pass', + 'GIT_CONFIG_KEY_0': 'user.name', + 'GIT_CONFIG_VALUE_0': 'anthony', + 'GIT_CONFIG_KEY_1': 'user.email', + 'GIT_CONFIG_VALUE_1': 'asottile@example.com', + 'GIT_CONFIG_COUNT': '2', } no_git_env = git.no_git_env(env) assert no_git_env == { @@ -234,6 +239,11 @@ def test_no_git_env(): 'GIT_EXEC_PATH': '/some/git/exec/path', 'GIT_SSH': '/usr/bin/ssh', 'GIT_SSH_COMMAND': 'ssh -o', + 'GIT_CONFIG_KEY_0': 'user.name', + 'GIT_CONFIG_VALUE_0': 'anthony', + 'GIT_CONFIG_KEY_1': 'user.email', + 'GIT_CONFIG_VALUE_1': 'asottile@example.com', + 'GIT_CONFIG_COUNT': '2', } From c45b84bd3914866711c4af01ce14870035a1aadc Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 23 Nov 2021 11:24:26 -0500 Subject: [PATCH 022/416] Use org-default .github/FUNDING.yml Committed via https://github.com/asottile/all-repos --- .github/FUNDING.yml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 9408e44d..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: asottile -open_collective: pre-commit From 270b539e8f1da3bf8a05ffc90a2f67952639f0f6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 29 Nov 2021 20:45:40 -0500 Subject: [PATCH 023/416] improve coverage pragmas with covdefaults 2.1 Committed via https://github.com/asottile/all-repos --- pre_commit/constants.py | 6 +++--- pre_commit/util.py | 4 ++-- requirements-dev.txt | 2 +- tests/repository_test.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 1a69c904..d2f93636 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -1,9 +1,9 @@ import sys -if sys.version_info < (3, 8): # pragma: no cover (= (3, 8): # pragma: >=3.8 cover import importlib.metadata as importlib_metadata +else: # pragma: <3.8 cover + import importlib_metadata CONFIG_FILE = '.pre-commit-config.yaml' MANIFEST_FILE = '.pre-commit-hooks.yaml' diff --git a/pre_commit/util.py b/pre_commit/util.py index 6bf8ae7a..6977acb2 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -21,10 +21,10 @@ import yaml from pre_commit import parse_shebang -if sys.version_info >= (3, 7): # pragma: no cover (PY37+) +if sys.version_info >= (3, 7): # pragma: >=3.7 cover from importlib.resources import open_binary from importlib.resources import read_text -else: # pragma: no cover (=2.1 coverage distlib pytest diff --git a/tests/repository_test.py b/tests/repository_test.py index c787eb02..36268e1e 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -164,7 +164,7 @@ def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store): ) -def test_python_venv(tempdir_factory, store): # pragma: no cover (no venv) +def test_python_venv(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'python_venv_hooks_repo', 'foo', [os.devnull], From d91a4c47f33788827e97888af50a893ee5fb79a8 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 30 Nov 2021 18:16:47 -0500 Subject: [PATCH 024/416] v2.16.0 --- .pre-commit-config.yaml | 2 +- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ setup.cfg | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2bdfee07..49517c34 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/pre-commit/pre-commit - rev: v2.15.0 + rev: v2.16.0 hooks: - id: validate_manifest - repo: https://github.com/asottile/pyupgrade diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b932566..55f46d9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,33 @@ +2.16.0 - 2021-11-30 +=================== + +### Features +- add warning for regexes containing `[\/]` or `[/\\]`. + - #2053 PR by @radek-sprta. + - #2043 issue by @asottile. +- move hook template back to `bash` resolving shebang-portability issues. + - #2065 PR by @asottile. +- add support for `fail_fast` at the individual hook level. + - #2097 PR by @colens3. + - #1143 issue by @potiuk. +- allow passthrough of `GIT_CONFIG_KEY_*`, `GIT_CONFIG_VALUE_*`, and + `GIT_CONFIG_COUNT`. + - #2136 PR by @emzeat. + +### Fixes +- fix pre-commit autoupdate for `core.useBuiltinFSMonitor=true` on windows. + - #2047 PR by @asottile. + - #2046 issue by @lcnittl. +- fix temporary file stashing with for `submodule.recurse=1`. + - #2071 PR by @asottile. + - #2063 issue by @a666. +- ban broken importlib-resources versions. + - #2098 PR by @asottile. +- replace `exit(...)` with `raise SystemExit(...)` for portability. + - #2103 PR by @asottile. + - #2104 PR by @asottile. + + 2.15.0 - 2021-09-02 =================== diff --git a/setup.cfg b/setup.cfg index 975dd77b..02669c70 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.15.0 +version = 2.16.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From a737d5fe2f083150b31425777eed0803a0ca23e0 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 30 Nov 2021 18:19:36 -0500 Subject: [PATCH 025/416] add setuptools to the zipapp. resolves #2122 --- testing/zipapp/make | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/zipapp/make b/testing/zipapp/make index 55b6d2c7..effc8123 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -71,7 +71,7 @@ def main() -> int: _msg('populating wheels...') _exit_if_retv( 'podman', 'run', '--rm', '--volume', f'{wheeldir}:/wheels:rw', IMG, - 'pip', 'wheel', f'pre_commit=={args.version}', + 'pip', 'wheel', f'pre_commit=={args.version}', 'setuptools', '--wheel-dir', '/wheels', ) From d4ffa5befb7725374be48fc7f78fcd438bd85361 Mon Sep 17 00:00:00 2001 From: Tony Rintala Date: Sat, 4 Dec 2021 22:22:21 +0200 Subject: [PATCH 026/416] fix: Add missing warning for regular expression with [\\/] test: Test case parameters for said regular expression refactor: For-loop for regex warnings instead of multiple if statements resolves #2151 --- pre_commit/clientlib.py | 38 ++++++++++++++------------------------ tests/clientlib_test.py | 10 ++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 6377a8b6..a224cc93 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -144,18 +144,13 @@ class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault): f"regex, not a glob -- matching '/*' probably isn't what you " f'want here', ) - if r'[\/]' in dct.get(self.key, ''): - logger.warning( - fr'pre-commit normalizes slashes in the {self.key!r} field ' - fr'in hook {dct.get("id")!r} to forward slashes, so you ' - fr'can use / instead of [\/]', - ) - if r'[/\\]' in dct.get(self.key, ''): - logger.warning( - fr'pre-commit normalizes slashes in the {self.key!r} field ' - fr'in hook {dct.get("id")!r} to forward slashes, so you ' - fr'can use / instead of [/\\]', - ) + for fwd_slash_re in [r'[\\/]', r'[\/]', r'[/\\]']: + if fwd_slash_re in dct.get(self.key, ''): + logger.warning( + fr'pre-commit normalizes slashes in the {self.key!r} ' + fr'field in hook {dct.get("id")!r} to forward slashes, ' + fr'so you can use / instead of {fwd_slash_re}', + ) class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): @@ -167,18 +162,13 @@ class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): f'The top-level {self.key!r} field is a regex, not a glob -- ' f"matching '/*' probably isn't what you want here", ) - if r'[\/]' in dct.get(self.key, ''): - logger.warning( - fr'pre-commit normalizes the slashes in the top-level ' - fr'{self.key!r} field to forward slashes, so you can use / ' - fr'instead of [\/]', - ) - if r'[/\\]' in dct.get(self.key, ''): - logger.warning( - fr'pre-commit normalizes the slashes in the top-level ' - fr'{self.key!r} field to forward slashes, so you can use / ' - fr'instead of [/\\]', - ) + for fwd_slash_re in [r'[\\/]', r'[\/]', r'[/\\]']: + if fwd_slash_re in dct.get(self.key, ''): + logger.warning( + fr'pre-commit normalizes the slashes in the top-level ' + fr'{self.key!r} field to forward slashes, so you ' + fr'can use / instead of {fwd_slash_re}', + ) class MigrateShaToRev: diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 5427b1da..a2be51b6 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -265,6 +265,11 @@ def test_warn_mutable_rev_conditional(): r"pre-commit normalizes slashes in the 'files' field in hook " r"'flake8' to forward slashes, so you can use / instead of [/\\]", ), + ( + r'dir[\\/].*\.py', + r"pre-commit normalizes slashes in the 'files' field in hook " + r"'flake8' to forward slashes, so you can use / instead of [\\/]", + ), ), ) def test_validate_optional_sensible_regex_at_hook(caplog, regex, warning): @@ -295,6 +300,11 @@ def test_validate_optional_sensible_regex_at_hook(caplog, regex, warning): r"pre-commit normalizes the slashes in the top-level 'files' " r'field to forward slashes, so you can use / instead of [/\\]', ), + ( + r'dir[\\/].*\.py', + r"pre-commit normalizes the slashes in the top-level 'files' " + r'field to forward slashes, so you can use / instead of [\\/]', + ), ), ) def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning): From b5088ceca6f51e46ca9406c8337602f2ca58c796 Mon Sep 17 00:00:00 2001 From: Tony Rintala Date: Sun, 5 Dec 2021 01:35:43 +0200 Subject: [PATCH 027/416] fix: regex lists to regex tuples --- pre_commit/clientlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index a224cc93..b8f23689 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -144,7 +144,7 @@ class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault): f"regex, not a glob -- matching '/*' probably isn't what you " f'want here', ) - for fwd_slash_re in [r'[\\/]', r'[\/]', r'[/\\]']: + for fwd_slash_re in (r'[\\/]', r'[\/]', r'[/\\]'): if fwd_slash_re in dct.get(self.key, ''): logger.warning( fr'pre-commit normalizes slashes in the {self.key!r} ' @@ -162,7 +162,7 @@ class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): f'The top-level {self.key!r} field is a regex, not a glob -- ' f"matching '/*' probably isn't what you want here", ) - for fwd_slash_re in [r'[\\/]', r'[\/]', r'[/\\]']: + for fwd_slash_re in (r'[\\/]', r'[\/]', r'[/\\]'): if fwd_slash_re in dct.get(self.key, ''): logger.warning( fr'pre-commit normalizes the slashes in the top-level ' From 379db4cb880b30b05863035d2d29a1f66b5795d9 Mon Sep 17 00:00:00 2001 From: Ralf Schmitt Date: Wed, 15 Dec 2021 02:21:23 +0100 Subject: [PATCH 028/416] Use 'go install' instead of 'go get' `go install` is the recommended way to install modules starting from go 1.16. In go 1.18 `go get` cannot be used anymore to install packages [1]. go 1.18 is not released yet. [1] https://tip.golang.org/doc/go1.18#go-command --- pre_commit/languages/golang.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index d6165d95..10ebc628 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -79,9 +79,11 @@ def install_environment( gopath = directory env = dict(os.environ, GOPATH=gopath) env.pop('GOBIN', None) - cmd_output_b('go', 'get', './...', cwd=repo_src_dir, env=env) + cmd_output_b('go', 'install', './...', cwd=repo_src_dir, env=env) for dependency in additional_dependencies: - cmd_output_b('go', 'get', dependency, cwd=repo_src_dir, env=env) + cmd_output_b( + 'go', 'install', dependency, cwd=repo_src_dir, env=env, + ) # Same some disk space, we don't need these after installation rmtree(prefix.path(directory, 'src')) pkgdir = prefix.path(directory, 'pkg') From a781bfb063e326d0b95df3c9c5277a9cb0b8aa08 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Dec 2021 19:42:45 +0000 Subject: [PATCH 029/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.910-1 → v0.920](https://github.com/pre-commit/mirrors-mypy/compare/v0.910-1...v0.920) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49517c34..4f024b41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,7 +44,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910-1 + rev: v0.920 hooks: - id: mypy additional_dependencies: [types-all] From f637ac860312e89c122a2fb3d146a8c339f883a2 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Dec 2021 17:01:51 -0500 Subject: [PATCH 030/416] minor py2 cleanup for sys.stderr.buffer --- tests/languages/helpers_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/languages/helpers_test.py b/tests/languages/helpers_test.py index 669cd334..fd9b9a45 100644 --- a/tests/languages/helpers_test.py +++ b/tests/languages/helpers_test.py @@ -72,8 +72,8 @@ def test_basic_healthy(): def test_failed_setup_command_does_not_unicode_error(): script = ( 'import sys\n' - "getattr(sys.stderr, 'buffer', sys.stderr).write(b'\\x81\\xfe')\n" - 'exit(1)\n' + "sys.stderr.buffer.write(b'\\x81\\xfe')\n" + 'raise SystemExit(1)\n' ) # an assertion that this does not raise `UnicodeError` From 3512e441f4d88e2892593db6f3eb9bba8ced5eb3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Dec 2021 17:38:59 -0500 Subject: [PATCH 031/416] replace echo image with focal --- testing/resources/docker_hooks_repo/Dockerfile | 2 +- .../resources/docker_image_hooks_repo/.pre-commit-hooks.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/resources/docker_hooks_repo/Dockerfile b/testing/resources/docker_hooks_repo/Dockerfile index 841b151b..0bd1de0c 100644 --- a/testing/resources/docker_hooks_repo/Dockerfile +++ b/testing/resources/docker_hooks_repo/Dockerfile @@ -1,3 +1,3 @@ -FROM cogniteev/echo +FROM ubuntu:focal CMD ["echo", "This is overwritten by the .pre-commit-hooks.yaml 'entry'"] diff --git a/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml index 1b385aa1..e9fb2456 100644 --- a/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml +++ b/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml @@ -1,8 +1,8 @@ - id: echo-entrypoint name: echo (via --entrypoint) language: docker_image - entry: --entrypoint echo cogniteev/echo + entry: --entrypoint echo ubuntu:focal - id: echo-cmd name: echo (via cmd) language: docker_image - entry: cogniteev/echo echo + entry: ubuntu:focal echo From 42b0a263a6701955c6af350addb1a1e85f5e6342 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 22 Dec 2021 11:30:55 -0800 Subject: [PATCH 032/416] run dead, remove dead code via https://github.com/asottile/dead --- pre_commit/commands/install_uninstall.py | 25 -------------- pre_commit/commands/run.py | 3 +- tests/commands/install_uninstall_test.py | 43 +----------------------- 3 files changed, 2 insertions(+), 69 deletions(-) diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index 7974423b..fad6c642 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -1,4 +1,3 @@ -import itertools import logging import os.path import shlex @@ -31,10 +30,6 @@ PRIOR_HASHES = ( CURRENT_HASH = b'138fd403232d2ddd5efb44317e38bf03' TEMPLATE_START = '# start templated\n' TEMPLATE_END = '# end templated\n' -# Homebrew/homebrew-core#35825: be more timid about appropriate `PATH` -# #1312 os.defpath is too restrictive on BSD -POSIX_SEARCH_PATH = ('/usr/local/bin', '/usr/bin', '/bin') -SYS_EXE = os.path.basename(os.path.realpath(sys.executable)) def _hook_paths( @@ -54,26 +49,6 @@ def is_our_script(filename: str) -> bool: return any(h in contents for h in (CURRENT_HASH,) + PRIOR_HASHES) -def shebang() -> str: - if sys.platform == 'win32': - py, _ = os.path.splitext(SYS_EXE) - else: - exe_choices = [ - f'python{sys.version_info[0]}.{sys.version_info[1]}', - f'python{sys.version_info[0]}', - ] - # avoid searching for bare `python` as it's likely to be python 2 - if SYS_EXE != 'python': - exe_choices.append(SYS_EXE) - for path, exe in itertools.product(POSIX_SEARCH_PATH, exe_choices): - if os.access(os.path.join(path, exe), os.X_OK): - py = exe - break - else: - py = SYS_EXE - return f'#!/usr/bin/env {py}' - - def _install_hook_script( config_file: str, hook_type: str, diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 2714faf4..f8ced0f9 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -275,7 +275,6 @@ def _run_hooks( hooks: Sequence[Hook], skips: Set[str], args: argparse.Namespace, - environ: MutableMapping[str, str], ) -> int: """Actually run the hooks.""" cols = _compute_cols(hooks) @@ -416,7 +415,7 @@ def run( to_install = [hook for hook in hooks if hook.id not in skips] install_hook_envs(to_install, store) - return _run_hooks(config, hooks, skips, args, environ) + return _run_hooks(config, hooks, skips, args) # https://github.com/python/mypy/issues/7726 raise AssertionError('unreachable') diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 83399034..0b2e248b 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -1,19 +1,15 @@ import os.path import re -import sys -from unittest import mock import re_assert import pre_commit.constants as C from pre_commit import git -from pre_commit.commands import install_uninstall from pre_commit.commands.install_uninstall import CURRENT_HASH from pre_commit.commands.install_uninstall import install from pre_commit.commands.install_uninstall import install_hooks from pre_commit.commands.install_uninstall import is_our_script from pre_commit.commands.install_uninstall import PRIOR_HASHES -from pre_commit.commands.install_uninstall import shebang from pre_commit.commands.install_uninstall import uninstall from pre_commit.parse_shebang import find_executable from pre_commit.util import cmd_output @@ -43,43 +39,6 @@ def test_is_previous_pre_commit(tmpdir): assert is_our_script(f.strpath) -def patch_platform(platform): - return mock.patch.object(sys, 'platform', platform) - - -def patch_lookup_path(path): - return mock.patch.object(install_uninstall, 'POSIX_SEARCH_PATH', path) - - -def patch_sys_exe(exe): - return mock.patch.object(install_uninstall, 'SYS_EXE', exe) - - -def test_shebang_windows(): - with patch_platform('win32'), patch_sys_exe('python'): - assert shebang() == '#!/usr/bin/env python' - - -def test_shebang_windows_drop_ext(): - with patch_platform('win32'), patch_sys_exe('python.exe'): - assert shebang() == '#!/usr/bin/env python' - - -def test_shebang_posix_not_on_path(): - with patch_platform('posix'), patch_lookup_path(()): - with patch_sys_exe('python3.6'): - assert shebang() == '#!/usr/bin/env python3.6' - - -def test_shebang_posix_on_path(tmpdir): - exe = tmpdir.join(f'python{sys.version_info[0]}').ensure() - make_executable(exe) - - with patch_platform('posix'), patch_lookup_path((tmpdir.strpath,)): - with patch_sys_exe('python'): - assert shebang() == f'#!/usr/bin/env python{sys.version_info[0]}' - - def test_install_pre_commit(in_git_dir, store): assert not install(C.CONFIG_FILE, store, hook_types=['pre-commit']) assert os.access(in_git_dir.join('.git/hooks/pre-commit').strpath, os.X_OK) @@ -336,7 +295,7 @@ EXISTING_COMMIT_RUN = re_assert.Matches( def _write_legacy_hook(path): os.makedirs(os.path.join(path, '.git/hooks'), exist_ok=True) with open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: - f.write(f'{shebang()}\nprint("legacy hook")\n') + f.write('#!/usr/bin/env bash\necho legacy hook\n') make_executable(f.name) From ba496b836911be1a5f139182fc118ef8b2f873a1 Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Sat, 11 Dec 2021 18:35:57 +0100 Subject: [PATCH 033/416] better r path detection --- pre_commit/languages/r.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index d573775f..74ecc6a8 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -54,6 +54,12 @@ def _prefix_if_non_local_file_entry( path = prefix.path(entry[1]) return (path,) +def _rscript_exec(): + """ + When invoked in a sub-process of R, use full path + """ + return os.path.join(os.getenv('R_HOME', ""), 'Rscript') + def _entry_validate(entry: Sequence[str]) -> None: """ @@ -95,8 +101,9 @@ def install_environment( os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) + cmd_output_b( - 'Rscript', '--vanilla', '-e', + _rscript_exec(), '--vanilla', '-e', f"""\ prefix_dir <- {prefix.prefix_dir!r} options( @@ -130,7 +137,7 @@ def install_environment( if additional_dependencies: with in_env(prefix, version): cmd_output_b( - 'Rscript', *RSCRIPT_OPTS, '-e', + _rscript_exec(), *RSCRIPT_OPTS, '-e', 'renv::install(commandArgs(trailingOnly = TRUE))', *additional_dependencies, cwd=env_dir, From b7331b653abca2f7dc711b452b60c29889888d89 Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Fri, 24 Dec 2021 14:36:43 +0100 Subject: [PATCH 034/416] unset renv project --- pre_commit/languages/r.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 74ecc6a8..98a8ec4f 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -8,6 +8,7 @@ from typing import Tuple from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT +from pre_commit.envcontext import UNSET from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix @@ -23,6 +24,7 @@ healthy = helpers.basic_healthy def get_env_patch(venv: str) -> PatchesT: return ( ('R_PROFILE_USER', os.path.join(venv, 'activate.R')), + ('RENV_PROJECT', UNSET), ) @@ -54,11 +56,12 @@ def _prefix_if_non_local_file_entry( path = prefix.path(entry[1]) return (path,) -def _rscript_exec(): + +def _rscript_exec() -> str: """ When invoked in a sub-process of R, use full path """ - return os.path.join(os.getenv('R_HOME', ""), 'Rscript') + return os.path.join(os.getenv('R_HOME', ''), 'Rscript') def _entry_validate(entry: Sequence[str]) -> None: @@ -101,7 +104,7 @@ def install_environment( os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) - + cmd_output_b( _rscript_exec(), '--vanilla', '-e', f"""\ From 1617692f12b8b67a471e6e810be49871b73ea056 Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Fri, 24 Dec 2021 14:52:46 +0100 Subject: [PATCH 035/416] no docs --- pre_commit/languages/r.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 98a8ec4f..e034e390 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -58,9 +58,6 @@ def _prefix_if_non_local_file_entry( def _rscript_exec() -> str: - """ - When invoked in a sub-process of R, use full path - """ return os.path.join(os.getenv('R_HOME', ''), 'Rscript') From d7ac975454d66ab1003d8522dbeb2054c3d86f31 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Dec 2021 20:06:12 +0000 Subject: [PATCH 036/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.0.1 → v4.1.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.0.1...v4.1.0) - [github.com/pre-commit/mirrors-mypy: v0.920 → v0.930](https://github.com/pre-commit/mirrors-mypy/compare/v0.920...v0.930) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4f024b41..e9b75d21 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -44,7 +44,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.920 + rev: v0.930 hooks: - id: mypy additional_dependencies: [types-all] From 83675fe7687def4b5a673fd794c9472c31fe69e4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 27 Dec 2021 18:32:56 -0500 Subject: [PATCH 037/416] work around python/mypy#11852 --- pre_commit/xargs.py | 3 ++- tests/xargs_test.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index 6b0fa208..9a397234 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -159,7 +159,8 @@ def xargs( ) threads = min(len(partitions), target_concurrency) - with _thread_mapper(threads) as thread_map: + # https://github.com/python/mypy/issues/11852 + with _thread_mapper(threads) as thread_map: # type: ignore results = thread_map(run_cmd_partition, partitions) for proc_retcode, proc_out, _ in results: diff --git a/tests/xargs_test.py b/tests/xargs_test.py index 7e83ef59..80bcd268 100644 --- a/tests/xargs_test.py +++ b/tests/xargs_test.py @@ -166,13 +166,15 @@ def test_xargs_concurrency(): def test_thread_mapper_concurrency_uses_threadpoolexecutor_map(): - with xargs._thread_mapper(10) as thread_map: + # https://github.com/python/mypy/issues/11852 + with xargs._thread_mapper(10) as thread_map: # type: ignore _self = thread_map.__self__ # type: ignore assert isinstance(_self, concurrent.futures.ThreadPoolExecutor) def test_thread_mapper_concurrency_uses_regular_map(): - with xargs._thread_mapper(1) as thread_map: + # https://github.com/python/mypy/issues/11852 + with xargs._thread_mapper(1) as thread_map: # type: ignore assert thread_map is map From d3b4f737b92eeae041d1125a42897075a1816f35 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 31 Dec 2021 17:31:12 -0800 Subject: [PATCH 038/416] forbid overriding `entry` for meta hooks --- pre_commit/clientlib.py | 9 +++++++++ tests/clientlib_test.py | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index b8f23689..47ebd54f 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -251,12 +251,21 @@ _meta = ( ), ) + +class NotAllowed(cfgv.OptionalNoDefault): + def check(self, dct: Dict[str, Any]) -> None: + if self.key in dct: + raise cfgv.ValidationError(f'{self.key!r} cannot be overridden') + + META_HOOK_DICT = cfgv.Map( 'Hook', 'id', cfgv.Required('id', cfgv.check_string), cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))), # language must be system cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'), + # entry cannot be overridden + NotAllowed('entry', cfgv.check_any), *( # default to the hook definition for the meta hooks cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id) diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index a2be51b6..39a37168 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -423,6 +423,13 @@ def test_migrate_to_sha_ok(): {'repo': 'meta', 'hooks': [{'id': 'identity', 'language': 'python'}]}, # name override must be string {'repo': 'meta', 'hooks': [{'id': 'identity', 'name': False}]}, + pytest.param( + { + 'repo': 'meta', + 'hooks': [{'id': 'identity', 'entry': 'echo hi'}], + }, + id='cannot override entry for meta hooks', + ), ), ) def test_meta_hook_invalid(config_repo): From 8be0a10e91a999c3271f1d7afd1eb930a06fffb6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 20:02:48 +0000 Subject: [PATCH 039/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-autopep8: v1.5.7 → v1.6.0](https://github.com/pre-commit/mirrors-autopep8/compare/v1.5.7...v1.6.0) - [github.com/asottile/pyupgrade: v2.29.1 → v2.31.0](https://github.com/asottile/pyupgrade/compare/v2.29.1...v2.31.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e9b75d21..48d9b106 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - id: flake8 additional_dependencies: [flake8-typing-imports==1.10.0] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.5.7 + rev: v1.6.0 hooks: - id: autopep8 - repo: https://github.com/pre-commit/pre-commit @@ -25,7 +25,7 @@ repos: hooks: - id: validate_manifest - repo: https://github.com/asottile/pyupgrade - rev: v2.29.1 + rev: v2.31.0 hooks: - id: pyupgrade args: [--py36-plus] From e3dc3f7934b206a1de16dc6800f9ae02ee73dd11 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 5 Jan 2022 08:14:43 -0800 Subject: [PATCH 040/416] always use #!/bin/sh on windows --- pre_commit/commands/install_uninstall.py | 7 +++++++ requirements-dev.txt | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index fad6c642..50c64432 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -82,6 +82,13 @@ def _install_hook_script( before, rest = contents.split(TEMPLATE_START) _, after = rest.split(TEMPLATE_END) + # on windows always use `/bin/sh` since `bash` might not be on PATH + # though we use bash-specific features `sh` on windows is actually + # bash in "POSIXLY_CORRECT" mode which still supports the features we + # use: subshells / arrays + if sys.platform == 'win32': # pragma: win32 cover + hook_file.write('#!/bin/sh\n') + hook_file.write(before + TEMPLATE_START) hook_file.write(f'INSTALL_PYTHON={shlex.quote(sys.executable)}\n') # TODO: python3.8+: shlex.join diff --git a/requirements-dev.txt b/requirements-dev.txt index 3a7b11cb..a23a3730 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ -covdefaults>=2.1 +covdefaults>=2.2 coverage distlib pytest From a33773182e9dab5d963274eb75ee2d5fd7313398 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Jan 2022 20:21:20 +0000 Subject: [PATCH 041/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.930 → v0.931](https://github.com/pre-commit/mirrors-mypy/compare/v0.930...v0.931) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48d9b106..49eab3fa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,7 +44,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.930 + rev: v0.931 hooks: - id: mypy additional_dependencies: [types-all] From bba6cf4296c7cb9c9ce0234aadf901de5210841f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 10 Jan 2022 15:35:33 -0500 Subject: [PATCH 042/416] Revert "work around python/mypy#11852" This reverts commit 83675fe7687def4b5a673fd794c9472c31fe69e4. --- pre_commit/xargs.py | 3 +-- tests/xargs_test.py | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index 9a397234..6b0fa208 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -159,8 +159,7 @@ def xargs( ) threads = min(len(partitions), target_concurrency) - # https://github.com/python/mypy/issues/11852 - with _thread_mapper(threads) as thread_map: # type: ignore + with _thread_mapper(threads) as thread_map: results = thread_map(run_cmd_partition, partitions) for proc_retcode, proc_out, _ in results: diff --git a/tests/xargs_test.py b/tests/xargs_test.py index 80bcd268..7e83ef59 100644 --- a/tests/xargs_test.py +++ b/tests/xargs_test.py @@ -166,15 +166,13 @@ def test_xargs_concurrency(): def test_thread_mapper_concurrency_uses_threadpoolexecutor_map(): - # https://github.com/python/mypy/issues/11852 - with xargs._thread_mapper(10) as thread_map: # type: ignore + with xargs._thread_mapper(10) as thread_map: _self = thread_map.__self__ # type: ignore assert isinstance(_self, concurrent.futures.ThreadPoolExecutor) def test_thread_mapper_concurrency_uses_regular_map(): - # https://github.com/python/mypy/issues/11852 - with xargs._thread_mapper(1) as thread_map: # type: ignore + with xargs._thread_mapper(1) as thread_map: assert thread_map is map From 428dc6e46eb68065bfc115419927949cdd056811 Mon Sep 17 00:00:00 2001 From: Jamie Alessio Date: Thu, 13 Jan 2022 12:14:58 -0800 Subject: [PATCH 043/416] Update rbenv / ruby-build versions --- pre_commit/resources/rbenv.tar.gz | Bin 32678 -> 32551 bytes pre_commit/resources/ruby-build.tar.gz | Bin 68689 -> 71151 bytes testing/make-archives | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/resources/rbenv.tar.gz b/pre_commit/resources/rbenv.tar.gz index 98b7e0f60d5437171a82991b983ac52455a328a7..da2514e71145e91debbad4bb1e11ca6d95ed3f63 100644 GIT binary patch literal 32551 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 a=}OwtU#r%WgsgY`KCtGVfIBL`f*%# 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 Uap-Hu_5aLPhT9%7Twr1V0Or+0_5c6? diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index afec5dbe5eab69fc879523b3a4ad4468f0a62c6a..01867bee6112203f21d1b808451070f6ad56f5c0 100644 GIT binary patch literal 71151 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 diff --git a/testing/make-archives b/testing/make-archives index 707fd884..ce098ba1 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -15,8 +15,8 @@ from typing import Sequence REPOS = ( - ('rbenv', 'https://github.com/rbenv/rbenv', '585ed84'), - ('ruby-build', 'https://github.com/rbenv/ruby-build', 'e9fa4bf'), + ('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'), + ('ruby-build', 'https://github.com/rbenv/ruby-build', '8663d2f'), ( 'ruby-download', 'https://github.com/garnieretienne/rvm-download', From 83aa65c4291b8a1a134cd024fbe071323f400c83 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Sat, 15 Jan 2022 09:33:40 +0100 Subject: [PATCH 044/416] Add mamba support to `language: conda` --- pre_commit/languages/conda.py | 15 ++++++++++++-- tests/languages/conda_test.py | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/languages/conda_test.py diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index d634e493..97e2f69e 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -50,6 +50,15 @@ def in_env( yield +def _conda_exe() -> str: + if os.environ.get('PRE_COMMIT_USE_MICROMAMBA'): + return 'micromamba' + elif os.environ.get('PRE_COMMIT_USE_MAMBA'): + return 'mamba' + else: + return 'conda' + + def install_environment( prefix: Prefix, version: str, @@ -58,15 +67,17 @@ def install_environment( helpers.assert_version_default('conda', version) directory = helpers.environment_dir(ENVIRONMENT_DIR, version) + conda_exe = _conda_exe() + env_dir = prefix.path(directory) with clean_path_on_failure(env_dir): cmd_output_b( - 'conda', 'env', 'create', '-p', env_dir, '--file', + conda_exe, 'env', 'create', '-p', env_dir, '--file', 'environment.yml', cwd=prefix.prefix_dir, ) if additional_dependencies: cmd_output_b( - 'conda', 'install', '-p', env_dir, *additional_dependencies, + conda_exe, 'install', '-p', env_dir, *additional_dependencies, cwd=prefix.prefix_dir, ) diff --git a/tests/languages/conda_test.py b/tests/languages/conda_test.py new file mode 100644 index 00000000..6faa78f2 --- /dev/null +++ b/tests/languages/conda_test.py @@ -0,0 +1,38 @@ +import pytest + +from pre_commit import envcontext +from pre_commit.languages.conda import _conda_exe + + +@pytest.mark.parametrize( + ('ctx', 'expected'), + ( + pytest.param( + ( + ('PRE_COMMIT_USE_MICROMAMBA', envcontext.UNSET), + ('PRE_COMMIT_USE_MAMBA', envcontext.UNSET), + ), + 'conda', + id='default', + ), + pytest.param( + ( + ('PRE_COMMIT_USE_MICROMAMBA', '1'), + ('PRE_COMMIT_USE_MAMBA', ''), + ), + 'micromamba', + id='default', + ), + pytest.param( + ( + ('PRE_COMMIT_USE_MICROMAMBA', ''), + ('PRE_COMMIT_USE_MAMBA', '1'), + ), + 'mamba', + id='default', + ), + ), +) +def test_conda_exe(ctx, expected): + with envcontext.envcontext(ctx): + assert _conda_exe() == expected From c05f58b776603dc2a5222f035c2dc058426497de Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 16 Jan 2022 07:20:12 -0800 Subject: [PATCH 045/416] add git version to error output --- pre_commit/error_handler.py | 5 +++++ tests/error_handler_test.py | 1 + 2 files changed, 6 insertions(+) diff --git a/pre_commit/error_handler.py b/pre_commit/error_handler.py index 023dd359..7e74b958 100644 --- a/pre_commit/error_handler.py +++ b/pre_commit/error_handler.py @@ -9,6 +9,7 @@ import pre_commit.constants as C from pre_commit import output from pre_commit.errors import FatalError from pre_commit.store import Store +from pre_commit.util import cmd_output_b from pre_commit.util import force_bytes @@ -21,6 +22,9 @@ def _log_and_exit( error_msg = f'{msg}: {type(exc).__name__}: '.encode() + force_bytes(exc) output.write_line_b(error_msg) + _, git_version_b, _ = cmd_output_b('git', '--version', retcode=None) + git_version = git_version_b.decode(errors='backslashreplace').rstrip() + storedir = Store().directory log_path = os.path.join(storedir, 'pre-commit.log') with contextlib.ExitStack() as ctx: @@ -38,6 +42,7 @@ def _log_and_exit( _log_line() _log_line('```') _log_line(f'pre-commit version: {C.VERSION}') + _log_line(f'git --version: {git_version}') _log_line('sys.version:') for line in sys.version.splitlines(): _log_line(f' {line}') diff --git a/tests/error_handler_test.py b/tests/error_handler_test.py index 6b0bb86d..cb76dcf4 100644 --- a/tests/error_handler_test.py +++ b/tests/error_handler_test.py @@ -122,6 +122,7 @@ def test_log_and_exit(cap_out, mock_store_dir): r'\n' r'```\n' r'pre-commit version: \d+\.\d+\.\d+\n' + r'git --version: git version .+\n' r'sys.version:\n' r'( .*\n)*' r'sys.executable: .*\n' From 3f8be7400d523fafe8c6d2d0fa4fb1560e7ae21d Mon Sep 17 00:00:00 2001 From: Matt Layman Date: Sun, 12 Dec 2021 01:57:54 -0500 Subject: [PATCH 046/416] Add naive and untested version of Lua language support. --- azure-pipelines.yml | 4 + pre_commit/languages/all.py | 2 + pre_commit/languages/lua.py | 150 ++++++++++++++++++ ...template_pre-commit-package-dev-1.rockspec | 12 ++ pre_commit/store.py | 3 +- testing/gen-languages-all | 2 +- testing/get-lua.sh | 5 + .../resources/lua_repo/.pre-commit-hooks.yaml | 4 + .../resources/lua_repo/bin/hello-world-lua | 3 + .../resources/lua_repo/hello-dev-1.rockspec | 15 ++ testing/util.py | 4 + tests/languages/lua_test.py | 55 +++++++ tests/repository_test.py | 29 ++++ 13 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 pre_commit/languages/lua.py create mode 100644 pre_commit/resources/empty_template_pre-commit-package-dev-1.rockspec create mode 100755 testing/get-lua.sh create mode 100644 testing/resources/lua_repo/.pre-commit-hooks.yaml create mode 100755 testing/resources/lua_repo/bin/hello-world-lua create mode 100644 testing/resources/lua_repo/hello-dev-1.rockspec create mode 100644 tests/languages/lua_test.py diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a468e8aa..d8cbd11d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -42,6 +42,8 @@ jobs: displayName: install coursier - bash: testing/get-dart.sh displayName: install dart + - bash: testing/get-lua.sh + displayName: install lua - bash: testing/get-swift.sh displayName: install swift - bash: testing/get-r.sh @@ -56,6 +58,8 @@ jobs: displayName: install coursier - bash: testing/get-dart.sh displayName: install dart + - bash: testing/get-lua.sh + displayName: install lua - bash: testing/get-swift.sh displayName: install swift - bash: testing/get-r.sh diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index d8a364c5..0bcedd66 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -13,6 +13,7 @@ from pre_commit.languages import docker_image from pre_commit.languages import dotnet from pre_commit.languages import fail from pre_commit.languages import golang +from pre_commit.languages import lua from pre_commit.languages import node from pre_commit.languages import perl from pre_commit.languages import pygrep @@ -51,6 +52,7 @@ languages = { 'dotnet': Language(name='dotnet', ENVIRONMENT_DIR=dotnet.ENVIRONMENT_DIR, get_default_version=dotnet.get_default_version, healthy=dotnet.healthy, install_environment=dotnet.install_environment, run_hook=dotnet.run_hook), # noqa: E501 'fail': Language(name='fail', ENVIRONMENT_DIR=fail.ENVIRONMENT_DIR, get_default_version=fail.get_default_version, healthy=fail.healthy, install_environment=fail.install_environment, run_hook=fail.run_hook), # noqa: E501 'golang': Language(name='golang', ENVIRONMENT_DIR=golang.ENVIRONMENT_DIR, get_default_version=golang.get_default_version, healthy=golang.healthy, install_environment=golang.install_environment, run_hook=golang.run_hook), # noqa: E501 + 'lua': Language(name='lua', ENVIRONMENT_DIR=lua.ENVIRONMENT_DIR, get_default_version=lua.get_default_version, healthy=lua.healthy, install_environment=lua.install_environment, run_hook=lua.run_hook), # noqa: E501 'node': Language(name='node', ENVIRONMENT_DIR=node.ENVIRONMENT_DIR, get_default_version=node.get_default_version, healthy=node.healthy, install_environment=node.install_environment, run_hook=node.run_hook), # noqa: E501 'perl': Language(name='perl', ENVIRONMENT_DIR=perl.ENVIRONMENT_DIR, get_default_version=perl.get_default_version, healthy=perl.healthy, install_environment=perl.install_environment, run_hook=perl.run_hook), # noqa: E501 'pygrep': Language(name='pygrep', ENVIRONMENT_DIR=pygrep.ENVIRONMENT_DIR, get_default_version=pygrep.get_default_version, healthy=pygrep.healthy, install_environment=pygrep.install_environment, run_hook=pygrep.run_hook), # noqa: E501 diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py new file mode 100644 index 00000000..ae322279 --- /dev/null +++ b/pre_commit/languages/lua.py @@ -0,0 +1,150 @@ +import contextlib +import os +import re +from typing import Generator +from typing import Sequence +from typing import Tuple + +import pre_commit.constants as C +from pre_commit.envcontext import envcontext +from pre_commit.envcontext import PatchesT +from pre_commit.envcontext import Var +from pre_commit.hook import Hook +from pre_commit.languages import helpers +from pre_commit.parse_shebang import find_executable +from pre_commit.prefix import Prefix +from pre_commit.util import clean_path_on_failure +from pre_commit.util import cmd_output + +ENVIRONMENT_DIR = 'lua_env' +get_default_version = helpers.basic_get_default_version +healthy = helpers.basic_healthy + + +def _find_lua(language_version: str) -> str: # pragma: win32 no cover + """Find a lua executable. + + Lua doesn't always have a plain `lua` executable. + Some OS vendors will ship the binary as `lua#.#` (e.g., lua5.3) + so discovery is needed to find a valid executable. + """ + if language_version == C.DEFAULT: + choices = ['lua'] + for path in os.environ.get('PATH', '').split(os.pathsep): + try: + candidates = os.listdir(path) + except OSError: + # Invalid path on PATH or lacking permissions. + continue + + for candidate in candidates: + # The Lua executable might look like `lua#.#` or `lua-#.#`. + if re.search(r'^lua[-]?\d+\.\d+', candidate): + choices.append(candidate) + else: + # Prefer version specific executables first if available. + # This should avoid the corner case where a user requests a language + # version, gets a `lua` executable, but that executable is actually + # for a different version and package.path would patch LUA_PATH + # incorrectly. + choices = [f'lua{language_version}', 'lua-{language_version}', 'lua'] + + found_exes = [exe for exe in choices if find_executable(exe)] + if found_exes: + return found_exes[0] + + raise ValueError( + 'No lua executable found on the system paths ' + f'for {language_version} version.', + ) + + +def _get_lua_path_version( + lua_executable: str, +) -> str: # pragma: win32 no cover + """Get the Lua version used in file paths.""" + # This could sniff out from _VERSION, but checking package.path should + # provide an answer for *exactly* where lua is looking for packages. + _, stdout, _ = cmd_output(lua_executable, '-e', 'print(package.path)') + sep = os.sep if os.name != 'nt' else os.sep * 2 + match = re.search(fr'{sep}lua{sep}(.*?){sep}', stdout) + if match: + return match[1] + + raise ValueError('Cannot determine lua version for file paths.') + + +def get_env_patch( + env: str, language_version: str, +) -> PatchesT: # pragma: win32 no cover + lua = _find_lua(language_version) + version = _get_lua_path_version(lua) + return ( + ('PATH', (os.path.join(env, 'bin'), os.pathsep, Var('PATH'))), + ( + 'LUA_PATH', ( + os.path.join(env, 'share', 'lua', version, '?.lua;'), + os.path.join(env, 'share', 'lua', version, '?', 'init.lua;;'), + ), + ), + ( + 'LUA_CPATH', ( + os.path.join(env, 'lib', 'lua', version, '?.so;;'), + ), + ), + ) + + +def _envdir(prefix: Prefix, version: str) -> str: # pragma: win32 no cover + directory = helpers.environment_dir(ENVIRONMENT_DIR, version) + return prefix.path(directory) + + +@contextlib.contextmanager # pragma: win32 no cover +def in_env( + prefix: Prefix, + language_version: str, +) -> Generator[None, None, None]: + with envcontext( + get_env_patch( + _envdir(prefix, language_version), language_version, + ), + ): + yield + + +def install_environment( + prefix: Prefix, + version: str, + additional_dependencies: Sequence[str], +) -> None: # pragma: win32 no cover + helpers.assert_version_default('lua', version) + + envdir = _envdir(prefix, version) + with clean_path_on_failure(envdir): + with in_env(prefix, version): + # luarocks doesn't bootstrap a tree prior to installing + # so ensure the directory exists. + os.makedirs(envdir, exist_ok=True) + + make_cmd = ['luarocks', '--tree', envdir, 'make'] + # Older luarocks (e.g., 2.4.2) expect the rockspec as an argument. + filenames = prefix.star('.rockspec') + make_cmd.extend(filenames[:1]) + + helpers.run_setup_cmd(prefix, tuple(make_cmd)) + + # luarocks can't install multiple packages at once + # so install them individually. + for dependency in additional_dependencies: + cmd = ('luarocks', '--tree', envdir, 'install', dependency) + helpers.run_setup_cmd(prefix, cmd) + + +def run_hook( + hook: Hook, + file_args: Sequence[str], + color: bool, +) -> Tuple[int, bytes]: # pragma: win32 no cover + with in_env(hook.prefix, hook.language_version): + return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/resources/empty_template_pre-commit-package-dev-1.rockspec b/pre_commit/resources/empty_template_pre-commit-package-dev-1.rockspec new file mode 100644 index 00000000..f063c8e2 --- /dev/null +++ b/pre_commit/resources/empty_template_pre-commit-package-dev-1.rockspec @@ -0,0 +1,12 @@ +package = "pre-commit-package" +version = "dev-1" + +source = { + url = "git+ssh://git@github.com/pre-commit/pre-commit.git" +} +description = {} +dependencies = {} +build = { + type = "builtin", + modules = {}, +} diff --git a/pre_commit/store.py b/pre_commit/store.py index fc3bc511..27d8553c 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -188,7 +188,8 @@ class Store: LOCAL_RESOURCES = ( 'Cargo.toml', 'main.go', 'go.mod', 'main.rs', '.npmignore', - 'package.json', 'pre_commit_placeholder_package.gemspec', 'setup.py', + 'package.json', 'pre-commit-package-dev-1.rockspec', + 'pre_commit_placeholder_package.gemspec', 'setup.py', 'environment.yml', 'Makefile.PL', 'pubspec.yaml', 'renv.lock', 'renv/activate.R', 'renv/LICENSE.renv', ) diff --git a/testing/gen-languages-all b/testing/gen-languages-all index c933c143..152cf3c6 100755 --- a/testing/gen-languages-all +++ b/testing/gen-languages-all @@ -3,7 +3,7 @@ import sys LANGUAGES = [ 'conda', 'coursier', 'dart', 'docker', 'docker_image', 'dotnet', 'fail', - 'golang', 'node', 'perl', 'pygrep', 'python', 'r', 'ruby', 'rust', + 'golang', 'lua', 'node', 'perl', 'pygrep', 'python', 'r', 'ruby', 'rust', 'script', 'swift', 'system', ] FIELDS = [ diff --git a/testing/get-lua.sh b/testing/get-lua.sh new file mode 100755 index 00000000..580e2477 --- /dev/null +++ b/testing/get-lua.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Install the runtime and package manager. +sudo apt install lua5.3 liblua5.3-dev luarocks diff --git a/testing/resources/lua_repo/.pre-commit-hooks.yaml b/testing/resources/lua_repo/.pre-commit-hooks.yaml new file mode 100644 index 00000000..767ef972 --- /dev/null +++ b/testing/resources/lua_repo/.pre-commit-hooks.yaml @@ -0,0 +1,4 @@ +- id: hello-world-lua + name: hello world lua + entry: hello-world-lua + language: lua diff --git a/testing/resources/lua_repo/bin/hello-world-lua b/testing/resources/lua_repo/bin/hello-world-lua new file mode 100755 index 00000000..2a0e0024 --- /dev/null +++ b/testing/resources/lua_repo/bin/hello-world-lua @@ -0,0 +1,3 @@ +#!/usr/bin/env lua + +print('hello world') diff --git a/testing/resources/lua_repo/hello-dev-1.rockspec b/testing/resources/lua_repo/hello-dev-1.rockspec new file mode 100644 index 00000000..82486e08 --- /dev/null +++ b/testing/resources/lua_repo/hello-dev-1.rockspec @@ -0,0 +1,15 @@ +package = "hello" +version = "dev-1" + +source = { + url = "git+ssh://git@github.com/pre-commit/pre-commit.git" +} +description = {} +dependencies = {} +build = { + type = "builtin", + modules = {}, + install = { + bin = {"bin/hello-world-lua"} + }, +} diff --git a/testing/util.py b/testing/util.py index 791a2b95..283ed477 100644 --- a/testing/util.py +++ b/testing/util.py @@ -48,6 +48,10 @@ skipif_cant_run_docker = pytest.mark.skipif( os.name == 'nt' or not docker_is_running(), reason="Docker isn't running or can't be accessed", ) +skipif_cant_run_lua = pytest.mark.skipif( + os.name == 'nt', + reason="lua isn't installed or can't be found", +) skipif_cant_run_swift = pytest.mark.skipif( parse_shebang.find_executable('swift') is None, reason="swift isn't installed or can't be found", diff --git a/tests/languages/lua_test.py b/tests/languages/lua_test.py new file mode 100644 index 00000000..fba23b22 --- /dev/null +++ b/tests/languages/lua_test.py @@ -0,0 +1,55 @@ +import os +from unittest import mock + +import pytest + +import pre_commit.constants as C +from pre_commit.languages import lua +from testing.util import xfailif_windows + + +@pytest.mark.parametrize( + 'lua_name', ('lua', 'lua5.4', 'lua-5.4', 'lua5.4.exe'), +) +def test_find_lua(tmp_path, lua_name): + """The language support can find common lua executable names.""" + lua_file = tmp_path / lua_name + lua_file.touch(0o555) + with mock.patch.dict(os.environ, {'PATH': str(tmp_path)}): + lua_executable = lua._find_lua(C.DEFAULT) + assert lua_name in lua_executable + + +def test_find_lua_language_version(tmp_path): + """Language discovery can find a specific version.""" + lua_file = tmp_path / 'lua5.99' + lua_file.touch(0o555) + with mock.patch.dict(os.environ, {'PATH': str(tmp_path)}): + lua_executable = lua._find_lua('5.99') + assert 'lua5.99' in lua_executable + + +@pytest.mark.parametrize( + ('invalid', 'mode'), + ( + ('foobar', 0o555), + ('luac', 0o555), + # Windows doesn't respect the executable checking. + pytest.param('lua5.4', 0o444, marks=xfailif_windows), + ), +) +def test_find_lua_fail(tmp_path, invalid, mode): + """No lua executable on the system will fail.""" + non_lua_file = tmp_path / invalid + non_lua_file.touch(mode) + with mock.patch.dict(os.environ, {'PATH': str(tmp_path)}): + with pytest.raises(ValueError): + lua._find_lua(C.DEFAULT) + + +@mock.patch.object(lua, 'cmd_output') +def test_bad_package_path(mock_cmd_output): + """A package path missing path info returns an unknown version.""" + mock_cmd_output.return_value = (0, '', '') + with pytest.raises(ValueError): + lua._get_lua_path_version('lua') diff --git a/tests/repository_test.py b/tests/repository_test.py index 36268e1e..5f5e17e5 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -17,6 +17,7 @@ from pre_commit.envcontext import envcontext from pre_commit.hook import Hook from pre_commit.languages import golang from pre_commit.languages import helpers +from pre_commit.languages import lua from pre_commit.languages import node from pre_commit.languages import python from pre_commit.languages import ruby @@ -34,6 +35,7 @@ from testing.util import cwd from testing.util import get_resource_path from testing.util import skipif_cant_run_coursier from testing.util import skipif_cant_run_docker +from testing.util import skipif_cant_run_lua from testing.util import skipif_cant_run_swift from testing.util import xfailif_windows @@ -1128,3 +1130,30 @@ def test_non_installable_hook_error_for_additional_dependencies(store, caplog): 'using language `system` which does not install an environment. ' 'Perhaps you meant to use a specific language?' ) + + +@skipif_cant_run_lua # pragma: win32 no cover +def test_lua_hook(tempdir_factory, store): + _test_hook_repo( + tempdir_factory, store, 'lua_repo', + 'hello-world-lua', [], b'hello world\n', + ) + + +@skipif_cant_run_lua # pragma: win32 no cover +def test_local_lua_additional_dependencies(store): + lua_entry = lua._find_lua(C.DEFAULT) + config = { + 'repo': 'local', + 'hooks': [{ + 'id': 'local-lua', + 'name': 'local-lua', + 'entry': lua_entry, + 'language': 'lua', + 'args': ['-e', 'require "inspect"; print("hello world")'], + 'additional_dependencies': ['inspect'], + }], + } + hook = _get_hook(config, store, 'local-lua') + ret, out = _hook_run(hook, (), color=False) + assert (ret, _norm_out(out)) == (0, b'hello world\n') From 54331dca6fcfff1a06c43defb29b395898c65ce8 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 17 Jan 2022 15:46:36 -0500 Subject: [PATCH 047/416] get lua version from luarocks itself --- pre_commit/languages/lua.py | 106 ++++++++---------------------------- tests/languages/lua_test.py | 55 ------------------- tests/repository_test.py | 10 ++-- 3 files changed, 27 insertions(+), 144 deletions(-) delete mode 100644 tests/languages/lua_test.py diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index ae322279..f6999371 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -1,6 +1,6 @@ import contextlib import os -import re +import sys from typing import Generator from typing import Sequence from typing import Tuple @@ -11,7 +11,6 @@ from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers -from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output @@ -21,95 +20,38 @@ get_default_version = helpers.basic_get_default_version healthy = helpers.basic_healthy -def _find_lua(language_version: str) -> str: # pragma: win32 no cover - """Find a lua executable. - - Lua doesn't always have a plain `lua` executable. - Some OS vendors will ship the binary as `lua#.#` (e.g., lua5.3) - so discovery is needed to find a valid executable. - """ - if language_version == C.DEFAULT: - choices = ['lua'] - for path in os.environ.get('PATH', '').split(os.pathsep): - try: - candidates = os.listdir(path) - except OSError: - # Invalid path on PATH or lacking permissions. - continue - - for candidate in candidates: - # The Lua executable might look like `lua#.#` or `lua-#.#`. - if re.search(r'^lua[-]?\d+\.\d+', candidate): - choices.append(candidate) - else: - # Prefer version specific executables first if available. - # This should avoid the corner case where a user requests a language - # version, gets a `lua` executable, but that executable is actually - # for a different version and package.path would patch LUA_PATH - # incorrectly. - choices = [f'lua{language_version}', 'lua-{language_version}', 'lua'] - - found_exes = [exe for exe in choices if find_executable(exe)] - if found_exes: - return found_exes[0] - - raise ValueError( - 'No lua executable found on the system paths ' - f'for {language_version} version.', - ) - - -def _get_lua_path_version( - lua_executable: str, -) -> str: # pragma: win32 no cover +def _get_lua_version() -> str: # pragma: win32 no cover """Get the Lua version used in file paths.""" - # This could sniff out from _VERSION, but checking package.path should - # provide an answer for *exactly* where lua is looking for packages. - _, stdout, _ = cmd_output(lua_executable, '-e', 'print(package.path)') - sep = os.sep if os.name != 'nt' else os.sep * 2 - match = re.search(fr'{sep}lua{sep}(.*?){sep}', stdout) - if match: - return match[1] - - raise ValueError('Cannot determine lua version for file paths.') + _, stdout, _ = cmd_output('luarocks', 'config', '--lua-ver') + return stdout.strip() -def get_env_patch( - env: str, language_version: str, -) -> PatchesT: # pragma: win32 no cover - lua = _find_lua(language_version) - version = _get_lua_path_version(lua) +def get_env_patch(d: str) -> PatchesT: # pragma: win32 no cover + version = _get_lua_version() + so_ext = 'dll' if sys.platform == 'win32' else 'so' return ( - ('PATH', (os.path.join(env, 'bin'), os.pathsep, Var('PATH'))), + ('PATH', (os.path.join(d, 'bin'), os.pathsep, Var('PATH'))), ( 'LUA_PATH', ( - os.path.join(env, 'share', 'lua', version, '?.lua;'), - os.path.join(env, 'share', 'lua', version, '?', 'init.lua;;'), + os.path.join(d, 'share', 'lua', version, '?.lua;'), + os.path.join(d, 'share', 'lua', version, '?', 'init.lua;;'), ), ), ( - 'LUA_CPATH', ( - os.path.join(env, 'lib', 'lua', version, '?.so;;'), - ), + 'LUA_CPATH', + (os.path.join(d, 'lib', 'lua', version, f'?.{so_ext};;'),), ), ) -def _envdir(prefix: Prefix, version: str) -> str: # pragma: win32 no cover - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) +def _envdir(prefix: Prefix) -> str: # pragma: win32 no cover + directory = helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT) return prefix.path(directory) @contextlib.contextmanager # pragma: win32 no cover -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - with envcontext( - get_env_patch( - _envdir(prefix, language_version), language_version, - ), - ): +def in_env(prefix: Prefix) -> Generator[None, None, None]: + with envcontext(get_env_patch(_envdir(prefix))): yield @@ -120,19 +62,17 @@ def install_environment( ) -> None: # pragma: win32 no cover helpers.assert_version_default('lua', version) - envdir = _envdir(prefix, version) + envdir = _envdir(prefix) with clean_path_on_failure(envdir): - with in_env(prefix, version): + with in_env(prefix): # luarocks doesn't bootstrap a tree prior to installing # so ensure the directory exists. os.makedirs(envdir, exist_ok=True) - make_cmd = ['luarocks', '--tree', envdir, 'make'] - # Older luarocks (e.g., 2.4.2) expect the rockspec as an argument. - filenames = prefix.star('.rockspec') - make_cmd.extend(filenames[:1]) - - helpers.run_setup_cmd(prefix, tuple(make_cmd)) + # Older luarocks (e.g., 2.4.2) expect the rockspec as an arg + for rockspec in prefix.star('.rockspec'): + make_cmd = ('luarocks', '--tree', envdir, 'make', rockspec) + helpers.run_setup_cmd(prefix, make_cmd) # luarocks can't install multiple packages at once # so install them individually. @@ -146,5 +86,5 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> Tuple[int, bytes]: # pragma: win32 no cover - with in_env(hook.prefix, hook.language_version): + with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/tests/languages/lua_test.py b/tests/languages/lua_test.py deleted file mode 100644 index fba23b22..00000000 --- a/tests/languages/lua_test.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -from unittest import mock - -import pytest - -import pre_commit.constants as C -from pre_commit.languages import lua -from testing.util import xfailif_windows - - -@pytest.mark.parametrize( - 'lua_name', ('lua', 'lua5.4', 'lua-5.4', 'lua5.4.exe'), -) -def test_find_lua(tmp_path, lua_name): - """The language support can find common lua executable names.""" - lua_file = tmp_path / lua_name - lua_file.touch(0o555) - with mock.patch.dict(os.environ, {'PATH': str(tmp_path)}): - lua_executable = lua._find_lua(C.DEFAULT) - assert lua_name in lua_executable - - -def test_find_lua_language_version(tmp_path): - """Language discovery can find a specific version.""" - lua_file = tmp_path / 'lua5.99' - lua_file.touch(0o555) - with mock.patch.dict(os.environ, {'PATH': str(tmp_path)}): - lua_executable = lua._find_lua('5.99') - assert 'lua5.99' in lua_executable - - -@pytest.mark.parametrize( - ('invalid', 'mode'), - ( - ('foobar', 0o555), - ('luac', 0o555), - # Windows doesn't respect the executable checking. - pytest.param('lua5.4', 0o444, marks=xfailif_windows), - ), -) -def test_find_lua_fail(tmp_path, invalid, mode): - """No lua executable on the system will fail.""" - non_lua_file = tmp_path / invalid - non_lua_file.touch(mode) - with mock.patch.dict(os.environ, {'PATH': str(tmp_path)}): - with pytest.raises(ValueError): - lua._find_lua(C.DEFAULT) - - -@mock.patch.object(lua, 'cmd_output') -def test_bad_package_path(mock_cmd_output): - """A package path missing path info returns an unknown version.""" - mock_cmd_output.return_value = (0, '', '') - with pytest.raises(ValueError): - lua._get_lua_path_version('lua') diff --git a/tests/repository_test.py b/tests/repository_test.py index 5f5e17e5..8569ba96 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -17,7 +17,6 @@ from pre_commit.envcontext import envcontext from pre_commit.hook import Hook from pre_commit.languages import golang from pre_commit.languages import helpers -from pre_commit.languages import lua from pre_commit.languages import node from pre_commit.languages import python from pre_commit.languages import ruby @@ -1142,18 +1141,17 @@ def test_lua_hook(tempdir_factory, store): @skipif_cant_run_lua # pragma: win32 no cover def test_local_lua_additional_dependencies(store): - lua_entry = lua._find_lua(C.DEFAULT) config = { 'repo': 'local', 'hooks': [{ 'id': 'local-lua', 'name': 'local-lua', - 'entry': lua_entry, + 'entry': 'luacheck --version', 'language': 'lua', - 'args': ['-e', 'require "inspect"; print("hello world")'], - 'additional_dependencies': ['inspect'], + 'additional_dependencies': ['luacheck'], }], } hook = _get_hook(config, store, 'local-lua') ret, out = _hook_run(hook, (), color=False) - assert (ret, _norm_out(out)) == (0, b'hello world\n') + assert b'Luacheck' in out + assert ret == 0 From d3bdf1403d92f8cf2dc77bd99a5da42f0a6cef17 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 18 Jan 2022 12:59:39 -0500 Subject: [PATCH 048/416] v2.17.0 --- .pre-commit-config.yaml | 2 +- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ setup.cfg | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49eab3fa..66b50a48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/pre-commit/pre-commit - rev: v2.16.0 + rev: v2.17.0 hooks: - id: validate_manifest - repo: https://github.com/asottile/pyupgrade diff --git a/CHANGELOG.md b/CHANGELOG.md index 55f46d9a..d0cccc6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +2.17.0 - 2022-01-18 +=================== + +### Features +- add warnings for regexes containing `[\\/]`. + - #2151 issue by @sanjioh. + - #2154 PR by @kuviokelluja. +- upgrade supported ruby versions. + - #2205 PR by @jalessio. +- allow `language: conda` to use `mamba` or `micromamba` via + `PRE_COMMIT_USE_MAMBA=1` or `PRE_COMMIT_USE_MICROMAMBA=1` respectively. + - #2204 issue by @janjagusch. + - #2207 PR by @xhochy. +- display `git --version` in error report. + - #2210 PR by @asottile. +- add `language: lua` as a supported language. + - #2158 PR by @mblayman. + +### Fixes +- temporarily add `setuptools` to the zipapp. + - #2122 issue by @andreoliwa. + - a737d5f commit by @asottile. +- use `go install` instead of `go get` for go 1.18+ support. + - #2161 PR by @schmir. +- fix `language: r` with a local renv and `RENV_PROJECT` set. + - #2170 PR by @lorenzwalthert. +- forbid overriding `entry` in `language: meta` hooks which breaks them. + - #2180 issue by @DanKaplanSES. + - #2181 PR by @asottile. +- always use `#!/bin/sh` on windows for hook script. + - #2182 issue by @hushigome-visco. + - #2187 PR by @asottile. + 2.16.0 - 2021-11-30 =================== diff --git a/setup.cfg b/setup.cfg index 02669c70..ef55b7cd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.16.0 +version = 2.17.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 04de6a2e57ffed4660918f8f480eaf50f98e3c94 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 18 Jan 2022 17:36:17 -0500 Subject: [PATCH 049/416] drop python 3.6 support python 3.6 reached end of life on 2021-12-23 --- .pre-commit-config.yaml | 5 +- azure-pipelines.yml | 2 +- pre_commit/__main__.py | 2 + pre_commit/clientlib.py | 26 ++++----- pre_commit/color.py | 2 + pre_commit/commands/autoupdate.py | 22 ++++---- pre_commit/commands/clean.py | 2 + pre_commit/commands/gc.py | 11 ++-- pre_commit/commands/hook_impl.py | 30 +++++------ pre_commit/commands/init_templatedir.py | 2 + pre_commit/commands/install_uninstall.py | 12 ++--- pre_commit/commands/migrate_config.py | 2 + pre_commit/commands/run.py | 26 +++++---- pre_commit/commands/sample_config.py | 1 + pre_commit/commands/try_repo.py | 6 +-- pre_commit/constants.py | 2 + pre_commit/envcontext.py | 5 +- pre_commit/error_handler.py | 2 + pre_commit/errors.py | 3 ++ pre_commit/file_lock.py | 5 +- pre_commit/git.py | 24 ++++----- pre_commit/hook.py | 10 ++-- pre_commit/languages/all.py | 8 +-- pre_commit/languages/conda.py | 5 +- pre_commit/languages/coursier.py | 5 +- pre_commit/languages/dart.py | 7 +-- pre_commit/languages/docker.py | 11 ++-- pre_commit/languages/docker_image.py | 5 +- pre_commit/languages/dotnet.py | 5 +- pre_commit/languages/fail.py | 5 +- pre_commit/languages/golang.py | 5 +- pre_commit/languages/helpers.py | 19 ++++--- pre_commit/languages/lua.py | 5 +- pre_commit/languages/node.py | 5 +- pre_commit/languages/perl.py | 5 +- pre_commit/languages/pygrep.py | 8 +-- pre_commit/languages/python.py | 17 +++--- pre_commit/languages/r.py | 7 +-- pre_commit/languages/ruby.py | 5 +- pre_commit/languages/rust.py | 10 ++-- pre_commit/languages/script.py | 5 +- pre_commit/languages/swift.py | 5 +- pre_commit/languages/system.py | 5 +- pre_commit/logging_handler.py | 2 + pre_commit/main.py | 10 ++-- pre_commit/meta_hooks/check_hooks_apply.py | 5 +- .../meta_hooks/check_useless_excludes.py | 5 +- pre_commit/meta_hooks/identity.py | 5 +- pre_commit/output.py | 9 ++-- pre_commit/parse_shebang.py | 16 +++--- pre_commit/prefix.py | 5 +- pre_commit/repository.py | 39 +++++++------- pre_commit/resources/empty_template_setup.py | 2 + pre_commit/staged_files_only.py | 2 + pre_commit/store.py | 17 +++--- pre_commit/util.py | 54 ++++++++----------- pre_commit/xargs.py | 21 ++++---- setup.cfg | 4 +- setup.py | 2 + testing/auto_namedtuple.py | 2 + testing/fixtures.py | 2 + testing/gen-languages-all | 2 + testing/make-archives | 5 +- testing/resources/python_hooks_repo/foo.py | 2 + testing/resources/python_hooks_repo/setup.py | 2 + .../resources/python_venv_hooks_repo/foo.py | 2 + .../resources/python_venv_hooks_repo/setup.py | 2 + testing/util.py | 2 + testing/zipapp/Dockerfile | 4 +- testing/zipapp/entry | 7 ++- testing/zipapp/make | 2 + testing/zipapp/python | 7 ++- tests/clientlib_test.py | 2 + tests/color_test.py | 2 + tests/commands/autoupdate_test.py | 2 + tests/commands/clean_test.py | 2 + tests/commands/gc_test.py | 2 + tests/commands/hook_impl_test.py | 2 + tests/commands/init_templatedir_test.py | 2 + tests/commands/install_uninstall_test.py | 2 + tests/commands/migrate_config_test.py | 2 + tests/commands/run_test.py | 2 + tests/commands/sample_config_test.py | 2 + tests/commands/try_repo_test.py | 2 + tests/conftest.py | 2 + tests/envcontext_test.py | 2 + tests/error_handler_test.py | 2 + tests/git_test.py | 2 + tests/languages/conda_test.py | 2 + tests/languages/docker_test.py | 2 + tests/languages/golang_test.py | 2 + tests/languages/helpers_test.py | 2 + tests/languages/node_test.py | 2 + tests/languages/pygrep_test.py | 2 + tests/languages/python_test.py | 10 ++-- tests/languages/r_test.py | 2 + tests/languages/ruby_test.py | 2 + tests/logging_handler_test.py | 2 + tests/main_test.py | 2 + tests/meta_hooks/check_hooks_apply_test.py | 2 + .../meta_hooks/check_useless_excludes_test.py | 2 + tests/meta_hooks/identity_test.py | 2 + tests/output_test.py | 2 + tests/parse_shebang_test.py | 2 + tests/prefix_test.py | 2 + tests/repository_test.py | 7 +-- tests/staged_files_only_test.py | 2 + tests/store_test.py | 2 + tests/util_test.py | 2 + tests/xargs_test.py | 5 +- tox.ini | 2 +- 111 files changed, 401 insertions(+), 286 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 66b50a48..5103e0be 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,12 +28,13 @@ repos: rev: v2.31.0 hooks: - id: pyupgrade - args: [--py36-plus] + args: [--py37-plus] - repo: https://github.com/asottile/reorder_python_imports rev: v2.6.0 hooks: - id: reorder-python-imports - args: [--py3-plus] + args: [--py37-plus, --add-import, 'from __future__ import annotations'] + exclude: ^testing/resources/python3_hooks_repo/ - repo: https://github.com/asottile/add-trailing-comma rev: v2.2.1 hooks: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d8cbd11d..d3336a46 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -50,7 +50,7 @@ jobs: displayName: install R - template: job--python-tox.yml@asottile parameters: - toxenvs: [pypy3, py36, py37, py38, py39] + toxenvs: [py37, py38, py39] os: linux pre_test: - task: UseRubyVersion@0 diff --git a/pre_commit/__main__.py b/pre_commit/__main__.py index 83bd93ca..bda61eec 100644 --- a/pre_commit/__main__.py +++ b/pre_commit/__main__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pre_commit.main import main diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 47ebd54f..1fcce4ea 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import functools import logging @@ -5,8 +7,6 @@ import re import shlex import sys from typing import Any -from typing import Dict -from typing import Optional from typing import Sequence import cfgv @@ -95,7 +95,7 @@ load_manifest = functools.partial( ) -def validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int: +def validate_manifest_main(argv: Sequence[str] | None = None) -> int: parser = _make_argparser('Manifest filenames.') args = parser.parse_args(argv) @@ -116,7 +116,7 @@ META = 'meta' # should inherit from cfgv.Conditional if sha support is dropped class WarnMutableRev(cfgv.ConditionalOptional): - def check(self, dct: Dict[str, Any]) -> None: + def check(self, dct: dict[str, Any]) -> None: super().check(dct) if self.key in dct: @@ -135,7 +135,7 @@ class WarnMutableRev(cfgv.ConditionalOptional): class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault): - def check(self, dct: Dict[str, Any]) -> None: + def check(self, dct: dict[str, Any]) -> None: super().check(dct) if '/*' in dct.get(self.key, ''): @@ -154,7 +154,7 @@ class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault): class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): - def check(self, dct: Dict[str, Any]) -> None: + def check(self, dct: dict[str, Any]) -> None: super().check(dct) if '/*' in dct.get(self.key, ''): @@ -183,7 +183,7 @@ class MigrateShaToRev: ensure_absent=True, ) - def check(self, dct: Dict[str, Any]) -> None: + def check(self, dct: dict[str, Any]) -> None: if dct.get('repo') in {LOCAL, META}: self._cond('rev').check(dct) self._cond('sha').check(dct) @@ -194,7 +194,7 @@ class MigrateShaToRev: else: self._cond('rev').check(dct) - def apply_default(self, dct: Dict[str, Any]) -> None: + def apply_default(self, dct: dict[str, Any]) -> None: if 'sha' in dct: dct['rev'] = dct.pop('sha') @@ -212,7 +212,7 @@ def _entry(modname: str) -> str: def warn_unknown_keys_root( extra: Sequence[str], orig_keys: Sequence[str], - dct: Dict[str, str], + dct: dict[str, str], ) -> None: logger.warning(f'Unexpected key(s) present at root: {", ".join(extra)}') @@ -220,7 +220,7 @@ def warn_unknown_keys_root( def warn_unknown_keys_repo( extra: Sequence[str], orig_keys: Sequence[str], - dct: Dict[str, str], + dct: dict[str, str], ) -> None: logger.warning( f'Unexpected key(s) present on {dct["repo"]}: {", ".join(extra)}', @@ -253,7 +253,7 @@ _meta = ( class NotAllowed(cfgv.OptionalNoDefault): - def check(self, dct: Dict[str, Any]) -> None: + def check(self, dct: dict[str, Any]) -> None: if self.key in dct: raise cfgv.ValidationError(f'{self.key!r} cannot be overridden') @@ -377,7 +377,7 @@ class InvalidConfigError(FatalError): pass -def ordered_load_normalize_legacy_config(contents: str) -> Dict[str, Any]: +def ordered_load_normalize_legacy_config(contents: str) -> dict[str, Any]: data = yaml_load(contents) if isinstance(data, list): logger.warning( @@ -398,7 +398,7 @@ load_config = functools.partial( ) -def validate_config_main(argv: Optional[Sequence[str]] = None) -> int: +def validate_config_main(argv: Sequence[str] | None = None) -> int: parser = _make_argparser('Config filenames.') args = parser.parse_args(argv) diff --git a/pre_commit/color.py b/pre_commit/color.py index 4ddfdf5b..2d6f248b 100644 --- a/pre_commit/color.py +++ b/pre_commit/color.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import os import sys diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 5cb978e9..938c2246 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -1,12 +1,10 @@ +from __future__ import annotations + import os.path import re from typing import Any -from typing import Dict -from typing import List from typing import NamedTuple -from typing import Optional from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit import git @@ -29,13 +27,13 @@ from pre_commit.util import yaml_load class RevInfo(NamedTuple): repo: str rev: str - frozen: Optional[str] + frozen: str | None @classmethod - def from_config(cls, config: Dict[str, Any]) -> 'RevInfo': + def from_config(cls, config: dict[str, Any]) -> RevInfo: return cls(config['repo'], config['rev'], None) - def update(self, tags_only: bool, freeze: bool) -> 'RevInfo': + def update(self, tags_only: bool, freeze: bool) -> RevInfo: git_cmd = ('git', *git.NO_FS_MONITOR) if tags_only: @@ -76,7 +74,7 @@ class RepositoryCannotBeUpdatedError(RuntimeError): def _check_hooks_still_exist_at_rev( - repo_config: Dict[str, Any], + repo_config: dict[str, Any], info: RevInfo, store: Store, ) -> None: @@ -101,9 +99,9 @@ REV_LINE_RE = re.compile(r'^(\s+)rev:(\s*)([\'"]?)([^\s#]+)(.*)(\r?\n)$') def _original_lines( path: str, - rev_infos: List[Optional[RevInfo]], + rev_infos: list[RevInfo | None], retry: bool = False, -) -> Tuple[List[str], List[int]]: +) -> tuple[list[str], list[int]]: """detect `rev:` lines or reformat the file""" with open(path, newline='') as f: original = f.read() @@ -120,7 +118,7 @@ def _original_lines( return _original_lines(path, rev_infos, retry=True) -def _write_new_config(path: str, rev_infos: List[Optional[RevInfo]]) -> None: +def _write_new_config(path: str, rev_infos: list[RevInfo | None]) -> None: lines, idxs = _original_lines(path, rev_infos) for idx, rev_info in zip(idxs, rev_infos): @@ -152,7 +150,7 @@ def autoupdate( """Auto-update the pre-commit config to the latest versions of repos.""" migrate_config(config_file, quiet=True) retv = 0 - rev_infos: List[Optional[RevInfo]] = [] + rev_infos: list[RevInfo | None] = [] changed = False config = load_config(config_file) diff --git a/pre_commit/commands/clean.py b/pre_commit/commands/clean.py index 2be6c16a..5119f645 100644 --- a/pre_commit/commands/clean.py +++ b/pre_commit/commands/clean.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path from pre_commit import output diff --git a/pre_commit/commands/gc.py b/pre_commit/commands/gc.py index 7f6d3111..6892e097 100644 --- a/pre_commit/commands/gc.py +++ b/pre_commit/commands/gc.py @@ -1,8 +1,7 @@ +from __future__ import annotations + import os.path from typing import Any -from typing import Dict -from typing import Set -from typing import Tuple import pre_commit.constants as C from pre_commit import output @@ -17,9 +16,9 @@ from pre_commit.store import Store def _mark_used_repos( store: Store, - all_repos: Dict[Tuple[str, str], str], - unused_repos: Set[Tuple[str, str]], - repo: Dict[str, Any], + all_repos: dict[tuple[str, str], str], + unused_repos: set[tuple[str, str]], + repo: dict[str, Any], ) -> None: if repo['repo'] == META: return diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index 90bb33b8..18e5e9f5 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -1,10 +1,10 @@ +from __future__ import annotations + import argparse import os.path import subprocess import sys -from typing import Optional from typing import Sequence -from typing import Tuple from pre_commit.commands.run import run from pre_commit.envcontext import envcontext @@ -18,7 +18,7 @@ def _run_legacy( hook_type: str, hook_dir: str, args: Sequence[str], -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: if os.environ.get('PRE_COMMIT_RUNNING_LEGACY'): raise SystemExit( f"bug: pre-commit's script is installed in migration mode\n" @@ -69,16 +69,16 @@ def _ns( color: bool, *, all_files: bool = False, - remote_branch: Optional[str] = None, - local_branch: Optional[str] = None, - from_ref: Optional[str] = None, - to_ref: Optional[str] = None, - remote_name: Optional[str] = None, - remote_url: Optional[str] = None, - commit_msg_filename: Optional[str] = None, - checkout_type: Optional[str] = None, - is_squash_merge: Optional[str] = None, - rewrite_command: Optional[str] = None, + remote_branch: str | None = None, + local_branch: str | None = None, + from_ref: str | None = None, + to_ref: str | None = None, + remote_name: str | None = None, + remote_url: str | None = None, + commit_msg_filename: str | None = None, + checkout_type: str | None = None, + is_squash_merge: str | None = None, + rewrite_command: str | None = None, ) -> argparse.Namespace: return argparse.Namespace( color=color, @@ -109,7 +109,7 @@ def _pre_push_ns( color: bool, args: Sequence[str], stdin: bytes, -) -> Optional[argparse.Namespace]: +) -> argparse.Namespace | None: remote_name = args[0] remote_url = args[1] @@ -197,7 +197,7 @@ def _run_ns( color: bool, args: Sequence[str], stdin: bytes, -) -> Optional[argparse.Namespace]: +) -> argparse.Namespace | None: _check_args_length(hook_type, args) if hook_type == 'pre-push': return _pre_push_ns(color, args, stdin) diff --git a/pre_commit/commands/init_templatedir.py b/pre_commit/commands/init_templatedir.py index 5f17d9c1..004e8ccf 100644 --- a/pre_commit/commands/init_templatedir.py +++ b/pre_commit/commands/init_templatedir.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging import os.path from typing import Sequence diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index 50c64432..cb2aaa5b 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -1,11 +1,11 @@ +from __future__ import annotations + import logging import os.path import shlex import shutil import sys -from typing import Optional from typing import Sequence -from typing import Tuple from pre_commit import git from pre_commit import output @@ -34,8 +34,8 @@ TEMPLATE_END = '# end templated\n' def _hook_paths( hook_type: str, - git_dir: Optional[str] = None, -) -> Tuple[str, str]: + git_dir: str | None = None, +) -> tuple[str, str]: git_dir = git_dir if git_dir is not None else git.get_git_dir() pth = os.path.join(git_dir, 'hooks', hook_type) return pth, f'{pth}.legacy' @@ -54,7 +54,7 @@ def _install_hook_script( hook_type: str, overwrite: bool = False, skip_on_missing_config: bool = False, - git_dir: Optional[str] = None, + git_dir: str | None = None, ) -> None: hook_path, legacy_path = _hook_paths(hook_type, git_dir=git_dir) @@ -107,7 +107,7 @@ def install( overwrite: bool = False, hooks: bool = False, skip_on_missing_config: bool = False, - git_dir: Optional[str] = None, + git_dir: str | None = None, ) -> int: if git_dir is None and git.has_core_hookpaths_set(): logger.error( diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index fef14cd3..c3d0a509 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import textwrap diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index f8ced0f9..37f989b5 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import contextlib import functools @@ -9,12 +11,8 @@ import time import unicodedata from typing import Any from typing import Collection -from typing import Dict -from typing import List from typing import MutableMapping from typing import Sequence -from typing import Set -from typing import Tuple from identify.identify import tags_from_path @@ -62,7 +60,7 @@ def filter_by_include_exclude( names: Collection[str], include: str, exclude: str, -) -> List[str]: +) -> list[str]: include_re, exclude_re = re.compile(include), re.compile(exclude) return [ filename for filename in names @@ -76,7 +74,7 @@ class Classifier: self.filenames = [f for f in filenames if os.path.lexists(f)] @functools.lru_cache(maxsize=None) - def _types_for_file(self, filename: str) -> Set[str]: + def _types_for_file(self, filename: str) -> set[str]: return tags_from_path(filename) def by_types( @@ -85,7 +83,7 @@ class Classifier: types: Collection[str], types_or: Collection[str], exclude_types: Collection[str], - ) -> List[str]: + ) -> list[str]: types = frozenset(types) types_or = frozenset(types_or) exclude_types = frozenset(exclude_types) @@ -100,7 +98,7 @@ class Classifier: ret.append(filename) return ret - def filenames_for_hook(self, hook: Hook) -> Tuple[str, ...]: + def filenames_for_hook(self, hook: Hook) -> tuple[str, ...]: names = self.filenames names = filter_by_include_exclude(names, hook.files, hook.exclude) names = self.by_types( @@ -117,7 +115,7 @@ class Classifier: filenames: Collection[str], include: str, exclude: str, - ) -> 'Classifier': + ) -> Classifier: # on windows we normalize all filenames to use forward slashes # this makes it easier to filter using the `files:` regex # this also makes improperly quoted shell-based hooks work better @@ -128,7 +126,7 @@ class Classifier: return Classifier(filenames) -def _get_skips(environ: MutableMapping[str, str]) -> Set[str]: +def _get_skips(environ: MutableMapping[str, str]) -> set[str]: skips = environ.get('SKIP', '') return {skip.strip() for skip in skips.split(',') if skip.strip()} @@ -144,12 +142,12 @@ def _subtle_line(s: str, use_color: bool) -> None: def _run_single_hook( classifier: Classifier, hook: Hook, - skips: Set[str], + skips: set[str], cols: int, diff_before: bytes, verbose: bool, use_color: bool, -) -> Tuple[bool, bytes]: +) -> tuple[bool, bytes]: filenames = classifier.filenames_for_hook(hook) if hook.id in skips or hook.alias in skips: @@ -271,9 +269,9 @@ def _get_diff() -> bytes: def _run_hooks( - config: Dict[str, Any], + config: dict[str, Any], hooks: Sequence[Hook], - skips: Set[str], + skips: set[str], args: argparse.Namespace, ) -> int: """Actually run the hooks.""" diff --git a/pre_commit/commands/sample_config.py b/pre_commit/commands/sample_config.py index 64617c33..82a1617f 100644 --- a/pre_commit/commands/sample_config.py +++ b/pre_commit/commands/sample_config.py @@ -2,6 +2,7 @@ # determine the latest revision? This adds ~200ms from my tests (and is # significantly faster than https:// or http://). For now, periodically # manually updating the revision is fine. +from __future__ import annotations SAMPLE_CONFIG = '''\ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks diff --git a/pre_commit/commands/try_repo.py b/pre_commit/commands/try_repo.py index 4aee209c..ef099f5e 100644 --- a/pre_commit/commands/try_repo.py +++ b/pre_commit/commands/try_repo.py @@ -1,8 +1,8 @@ +from __future__ import annotations + import argparse import logging import os.path -from typing import Optional -from typing import Tuple import pre_commit.constants as C from pre_commit import git @@ -18,7 +18,7 @@ from pre_commit.xargs import xargs logger = logging.getLogger(__name__) -def _repo_ref(tmpdir: str, repo: str, ref: Optional[str]) -> Tuple[str, str]: +def _repo_ref(tmpdir: str, repo: str, ref: str | None) -> tuple[str, str]: # if `ref` is explicitly passed, use it if ref is not None: return repo, ref diff --git a/pre_commit/constants.py b/pre_commit/constants.py index d2f93636..40127a05 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys if sys.version_info >= (3, 8): # pragma: >=3.8 cover diff --git a/pre_commit/envcontext.py b/pre_commit/envcontext.py index 92d975d0..4f595601 100644 --- a/pre_commit/envcontext.py +++ b/pre_commit/envcontext.py @@ -1,10 +1,11 @@ +from __future__ import annotations + import contextlib import enum import os from typing import Generator from typing import MutableMapping from typing import NamedTuple -from typing import Optional from typing import Tuple from typing import Union @@ -32,7 +33,7 @@ def format_env(parts: SubstitutionT, env: MutableMapping[str, str]) -> str: @contextlib.contextmanager def envcontext( patch: PatchesT, - _env: Optional[MutableMapping[str, str]] = None, + _env: MutableMapping[str, str] | None = None, ) -> Generator[None, None, None]: """In this context, `os.environ` is modified according to `patch`. diff --git a/pre_commit/error_handler.py b/pre_commit/error_handler.py index 7e74b958..a6a7329e 100644 --- a/pre_commit/error_handler.py +++ b/pre_commit/error_handler.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import functools import os.path diff --git a/pre_commit/errors.py b/pre_commit/errors.py index f84d3f18..eac34faa 100644 --- a/pre_commit/errors.py +++ b/pre_commit/errors.py @@ -1,2 +1,5 @@ +from __future__ import annotations + + class FatalError(RuntimeError): pass diff --git a/pre_commit/file_lock.py b/pre_commit/file_lock.py index 55a8eb29..f67a5864 100644 --- a/pre_commit/file_lock.py +++ b/pre_commit/file_lock.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import errno import sys @@ -20,13 +22,11 @@ if sys.platform == 'win32': # pragma: no cover (windows) blocked_cb: Callable[[], None], ) -> Generator[None, None, None]: try: - # TODO: https://github.com/python/typeshed/pull/3607 msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region) except OSError: blocked_cb() while True: try: - # TODO: https://github.com/python/typeshed/pull/3607 msvcrt.locking(fileno, msvcrt.LK_LOCK, _region) except OSError as e: # Locking violation. Returned when the _LK_LOCK or _LK_RLCK @@ -45,7 +45,6 @@ if sys.platform == 'win32': # pragma: no cover (windows) # The documentation however states: # "Regions should be locked only briefly and should be unlocked # before closing a file or exiting the program." - # TODO: https://github.com/python/typeshed/pull/3607 msvcrt.locking(fileno, msvcrt.LK_UNLCK, _region) else: # pragma: win32 no cover import fcntl diff --git a/pre_commit/git.py b/pre_commit/git.py index e9ec6014..67499cdb 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -1,11 +1,9 @@ +from __future__ import annotations + import logging import os.path import sys -from typing import Dict -from typing import List from typing import MutableMapping -from typing import Optional -from typing import Set from pre_commit.errors import FatalError from pre_commit.util import CalledProcessError @@ -18,7 +16,7 @@ logger = logging.getLogger(__name__) NO_FS_MONITOR = ('-c', 'core.useBuiltinFSMonitor=false') -def zsplit(s: str) -> List[str]: +def zsplit(s: str) -> list[str]: s = s.strip('\0') if s: return s.split('\0') @@ -27,8 +25,8 @@ def zsplit(s: str) -> List[str]: def no_git_env( - _env: Optional[MutableMapping[str, str]] = None, -) -> Dict[str, str]: + _env: MutableMapping[str, str] | None = None, +) -> dict[str, str]: # Too many bugs dealing with environment variables and GIT: # https://github.com/pre-commit/pre-commit/issues/300 # In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running @@ -95,7 +93,7 @@ def is_in_merge_conflict() -> bool: ) -def parse_merge_msg_for_conflicts(merge_msg: bytes) -> List[str]: +def parse_merge_msg_for_conflicts(merge_msg: bytes) -> list[str]: # Conflicted files start with tabs return [ line.lstrip(b'#').strip().decode() @@ -105,7 +103,7 @@ def parse_merge_msg_for_conflicts(merge_msg: bytes) -> List[str]: ] -def get_conflicted_files() -> Set[str]: +def get_conflicted_files() -> set[str]: logger.info('Checking merge-conflict files only.') # Need to get the conflicted files from the MERGE_MSG because they could # have resolved the conflict by choosing one side or the other @@ -126,7 +124,7 @@ def get_conflicted_files() -> Set[str]: return set(merge_conflict_filenames) | set(merge_diff_filenames) -def get_staged_files(cwd: Optional[str] = None) -> List[str]: +def get_staged_files(cwd: str | None = None) -> list[str]: return zsplit( cmd_output( 'git', 'diff', '--staged', '--name-only', '--no-ext-diff', '-z', @@ -137,7 +135,7 @@ def get_staged_files(cwd: Optional[str] = None) -> List[str]: ) -def intent_to_add_files() -> List[str]: +def intent_to_add_files() -> list[str]: _, stdout, _ = cmd_output( 'git', 'status', '--ignore-submodules', '--porcelain', '-z', ) @@ -153,11 +151,11 @@ def intent_to_add_files() -> List[str]: return intent_to_add -def get_all_files() -> List[str]: +def get_all_files() -> list[str]: return zsplit(cmd_output('git', 'ls-files', '-z')[1]) -def get_changed_files(old: str, new: str) -> List[str]: +def get_changed_files(old: str, new: str) -> list[str]: diff_cmd = ('git', 'diff', '--name-only', '--no-ext-diff', '-z') try: _, out, _ = cmd_output(*diff_cmd, f'{old}...{new}') diff --git a/pre_commit/hook.py b/pre_commit/hook.py index 82e99c54..202abb35 100644 --- a/pre_commit/hook.py +++ b/pre_commit/hook.py @@ -1,10 +1,10 @@ +from __future__ import annotations + import logging import shlex from typing import Any -from typing import Dict from typing import NamedTuple from typing import Sequence -from typing import Tuple from pre_commit.prefix import Prefix @@ -38,11 +38,11 @@ class Hook(NamedTuple): verbose: bool @property - def cmd(self) -> Tuple[str, ...]: + def cmd(self) -> tuple[str, ...]: return (*shlex.split(self.entry), *self.args) @property - def install_key(self) -> Tuple[Prefix, str, str, Tuple[str, ...]]: + def install_key(self) -> tuple[Prefix, str, str, tuple[str, ...]]: return ( self.prefix, self.language, @@ -51,7 +51,7 @@ class Hook(NamedTuple): ) @classmethod - def create(cls, src: str, prefix: Prefix, dct: Dict[str, Any]) -> 'Hook': + def create(cls, src: str, prefix: Prefix, dct: dict[str, Any]) -> Hook: # TODO: have cfgv do this (?) extra_keys = set(dct) - _KEYS if extra_keys: diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index 0bcedd66..cfcbf686 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -1,8 +1,8 @@ +from __future__ import annotations + from typing import Callable from typing import NamedTuple -from typing import Optional from typing import Sequence -from typing import Tuple from pre_commit.hook import Hook from pre_commit.languages import conda @@ -30,7 +30,7 @@ from pre_commit.prefix import Prefix class Language(NamedTuple): name: str # Use `None` for no installation / environment - ENVIRONMENT_DIR: Optional[str] + ENVIRONMENT_DIR: str | None # return a value to replace `'default` for `language_version` get_default_version: Callable[[], str] # return whether the environment is healthy (or should be rebuilt) @@ -38,7 +38,7 @@ class Language(NamedTuple): # install a repository for the given language and language_version install_environment: Callable[[Prefix, str, Sequence[str]], None] # execute a hook and return the exit code and output - run_hook: 'Callable[[Hook, Sequence[str], bool], Tuple[int, bytes]]' + run_hook: Callable[[Hook, Sequence[str], bool], tuple[int, bytes]] # TODO: back to modules + Protocol: https://github.com/python/mypy/issues/5018 diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 97e2f69e..88ac53f3 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import contextlib import os from typing import Generator from typing import Sequence -from typing import Tuple from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT @@ -86,7 +87,7 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: # TODO: Some rare commands need to be run using `conda run` but mostly we # can run them without which is much quicker and produces a better # output. diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 2841467f..e47f9c87 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import contextlib import os from typing import Generator from typing import Sequence -from typing import Tuple from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT @@ -66,6 +67,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: # pragma: win32 no cover +) -> tuple[int, bytes]: # pragma: win32 no cover with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 16e75546..65135f80 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -1,10 +1,11 @@ +from __future__ import annotations + import contextlib import os.path import shutil import tempfile from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -76,7 +77,7 @@ def install_environment( with tempfile.TemporaryDirectory() as dep_tmp: dep, _, version = dep_s.partition(':') if version: - dep_cmd: Tuple[str, ...] = (dep, '--version', version) + dep_cmd: tuple[str, ...] = (dep, '--version', version) else: dep_cmd = (dep,) @@ -104,6 +105,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 644d8d29..af1860c5 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import hashlib import json import os from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.hook import Hook @@ -76,7 +77,7 @@ def build_docker_image( *, pull: bool, ) -> None: # pragma: win32 no cover - cmd: Tuple[str, ...] = ( + cmd: tuple[str, ...] = ( 'docker', 'build', '--tag', docker_tag(prefix), '--label', PRE_COMMIT_LABEL, @@ -105,14 +106,14 @@ def install_environment( os.mkdir(directory) -def get_docker_user() -> Tuple[str, ...]: # pragma: win32 no cover +def get_docker_user() -> tuple[str, ...]: # pragma: win32 no cover try: return ('-u', f'{os.getuid()}:{os.getgid()}') except AttributeError: return () -def docker_cmd() -> Tuple[str, ...]: # pragma: win32 no cover +def docker_cmd() -> tuple[str, ...]: # pragma: win32 no cover return ( 'docker', 'run', '--rm', @@ -129,7 +130,7 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: # pragma: win32 no cover +) -> tuple[int, bytes]: # pragma: win32 no cover # Rebuild the docker image in case it has gone missing, as many people do # automated cleanup of docker images. build_docker_image(hook.prefix, pull=False) diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index 311d1277..ccc1d678 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from typing import Sequence -from typing import Tuple from pre_commit.hook import Hook from pre_commit.languages import helpers @@ -15,6 +16,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: # pragma: win32 no cover +) -> tuple[int, bytes]: # pragma: win32 no cover cmd = docker_cmd() + hook.cmd return helpers.run_xargs(hook, cmd, file_args, color=color) diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 094d2f1c..a16e7f07 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import contextlib import os.path from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -84,6 +85,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index d2b02d23..4cb95af5 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from typing import Sequence -from typing import Tuple from pre_commit.hook import Hook from pre_commit.languages import helpers @@ -14,7 +15,7 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: out = f'{hook.entry}\n\n'.encode() out += b'\n'.join(f.encode() for f in file_args) + b'\n' return 1, out diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 10ebc628..759c2684 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import contextlib import os.path import sys from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit import git @@ -95,6 +96,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 276ce161..dd219ffa 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -1,13 +1,12 @@ +from __future__ import annotations + import multiprocessing import os import random import re from typing import Any -from typing import List -from typing import Optional from typing import overload from typing import Sequence -from typing import Tuple from typing import TYPE_CHECKING import pre_commit.constants as C @@ -32,7 +31,7 @@ def exe_exists(exe: str) -> bool: homedir = os.path.expanduser('~') try: - common: Optional[str] = os.path.commonpath((found, homedir)) + common: str | None = os.path.commonpath((found, homedir)) except ValueError: # on windows, different drives raises ValueError common = None @@ -48,7 +47,7 @@ def exe_exists(exe: str) -> bool: ) -def run_setup_cmd(prefix: Prefix, cmd: Tuple[str, ...], **kwargs: Any) -> None: +def run_setup_cmd(prefix: Prefix, cmd: tuple[str, ...], **kwargs: Any) -> None: cmd_output_b(*cmd, cwd=prefix.prefix_dir, **kwargs) @@ -58,7 +57,7 @@ def environment_dir(d: None, language_version: str) -> None: ... def environment_dir(d: str, language_version: str) -> str: ... -def environment_dir(d: Optional[str], language_version: str) -> Optional[str]: +def environment_dir(d: str | None, language_version: str) -> str | None: if d is None: return None else: @@ -95,7 +94,7 @@ def no_install( prefix: Prefix, version: str, additional_dependencies: Sequence[str], -) -> 'NoReturn': +) -> NoReturn: raise AssertionError('This type is not installable') @@ -113,7 +112,7 @@ def target_concurrency(hook: Hook) -> int: return 1 -def _shuffled(seq: Sequence[str]) -> List[str]: +def _shuffled(seq: Sequence[str]) -> list[str]: """Deterministically shuffle""" fixed_random = random.Random() fixed_random.seed(FIXED_RANDOM_SEED, version=1) @@ -125,10 +124,10 @@ def _shuffled(seq: Sequence[str]) -> List[str]: def run_xargs( hook: Hook, - cmd: Tuple[str, ...], + cmd: tuple[str, ...], file_args: Sequence[str], **kwargs: Any, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: # Shuffle the files so that they more evenly fill out the xargs partitions, # but do it deterministically in case a hook cares about ordering. file_args = _shuffled(file_args) diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index f6999371..38bdf54b 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import contextlib import os import sys from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -85,6 +86,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: # pragma: win32 no cover +) -> tuple[int, bytes]: # pragma: win32 no cover with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 8dc4e8ba..b084e8f8 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -1,10 +1,11 @@ +from __future__ import annotations + import contextlib import functools import os import sys from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -122,6 +123,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index bbf55049..0eee258d 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import contextlib import os import shlex from typing import Generator from typing import Sequence -from typing import Tuple from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT @@ -62,6 +63,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index a713c3fb..f2758c58 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -1,11 +1,11 @@ +from __future__ import annotations + import argparse import re import sys from typing import NamedTuple -from typing import Optional from typing import Pattern from typing import Sequence -from typing import Tuple from pre_commit import output from pre_commit.hook import Hook @@ -90,12 +90,12 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: exe = (sys.executable, '-m', __name__) + tuple(hook.args) + (hook.entry,) return xargs(exe, file_args, color=color) -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser( description=( 'grep-like finder using python regexes. Unlike grep, this tool ' diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index faa60297..668ba358 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -1,12 +1,11 @@ +from __future__ import annotations + import contextlib import functools import os import sys -from typing import Dict from typing import Generator -from typing import Optional from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -35,7 +34,7 @@ def _version_info(exe: str) -> str: return f'<>' -def _read_pyvenv_cfg(filename: str) -> Dict[str, str]: +def _read_pyvenv_cfg(filename: str) -> dict[str, str]: ret = {} with open(filename, encoding='UTF-8') as f: for line in f: @@ -65,7 +64,7 @@ def get_env_patch(venv: str) -> PatchesT: def _find_by_py_launcher( version: str, -) -> Optional[str]: # pragma: no cover (windows only) +) -> str | None: # pragma: no cover (windows only) if version.startswith('python'): num = version[len('python'):] cmd = ('py', f'-{num}', '-c', 'import sys; print(sys.executable)') @@ -77,8 +76,8 @@ def _find_by_py_launcher( return None -def _find_by_sys_executable() -> Optional[str]: - def _norm(path: str) -> Optional[str]: +def _find_by_sys_executable() -> str | None: + def _norm(path: str) -> str | None: _, exe = os.path.split(path.lower()) exe, _, _ = exe.partition('.exe') if exe not in {'python', 'pythonw'} and find_executable(exe): @@ -133,7 +132,7 @@ def _sys_executable_matches(version: str) -> bool: return sys.version_info[:len(info)] == info -def norm_version(version: str) -> Optional[str]: +def norm_version(version: str) -> str | None: if version == C.DEFAULT: # use virtualenv's default return None elif _sys_executable_matches(version): # virtualenv defaults to our exe @@ -209,6 +208,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index e034e390..2ad8c411 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -1,10 +1,11 @@ +from __future__ import annotations + import contextlib import os import shlex import shutil from typing import Generator from typing import Sequence -from typing import Tuple from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT @@ -80,7 +81,7 @@ def _entry_validate(entry: Sequence[str]) -> None: ) -def _cmd_from_hook(hook: Hook) -> Tuple[str, ...]: +def _cmd_from_hook(hook: Hook) -> tuple[str, ...]: entry = shlex.split(hook.entry) _entry_validate(entry) @@ -148,7 +149,7 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix, hook.language_version): return helpers.run_xargs( hook, _cmd_from_hook(hook), file_args, color=color, diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 81bc9543..ae644927 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import functools import os.path @@ -5,7 +7,6 @@ import shutil import tarfile from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -146,6 +147,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 7ea3f540..39e36281 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -1,9 +1,9 @@ +from __future__ import annotations + import contextlib import os.path from typing import Generator from typing import Sequence -from typing import Set -from typing import Tuple import toml @@ -39,7 +39,7 @@ def in_env(prefix: Prefix) -> Generator[None, None, None]: def _add_dependencies( cargo_toml_path: str, - additional_dependencies: Set[str], + additional_dependencies: set[str], ) -> None: with open(cargo_toml_path, 'r+') as f: cargo_toml = toml.load(f) @@ -81,7 +81,7 @@ def install_environment( _add_dependencies(prefix.path('Cargo.toml'), lib_deps) with clean_path_on_failure(directory): - packages_to_install: Set[Tuple[str, ...]] = {('--path', '.')} + packages_to_install: set[tuple[str, ...]] = {('--path', '.')} for cli_dep in cli_deps: cli_dep = cli_dep[len('cli:'):] package, _, version = cli_dep.partition(':') @@ -101,6 +101,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index a5e1365c..2844b5e5 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from typing import Sequence -from typing import Tuple from pre_commit.hook import Hook from pre_commit.languages import helpers @@ -14,6 +15,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: cmd = (hook.prefix.path(hook.cmd[0]), *hook.cmd[1:]) return helpers.run_xargs(hook, cmd, file_args, color=color) diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index 66aadc8b..c6309531 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import contextlib import os from typing import Generator from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit.envcontext import envcontext @@ -59,6 +60,6 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: # pragma: win32 no cover +) -> tuple[int, bytes]: # pragma: win32 no cover with in_env(hook.prefix): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/system.py b/pre_commit/languages/system.py index 139f45d1..9846c98b 100644 --- a/pre_commit/languages/system.py +++ b/pre_commit/languages/system.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from typing import Sequence -from typing import Tuple from pre_commit.hook import Hook from pre_commit.languages import helpers @@ -15,5 +16,5 @@ def run_hook( hook: Hook, file_args: Sequence[str], color: bool, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/logging_handler.py b/pre_commit/logging_handler.py index ba05295d..1b68fc7d 100644 --- a/pre_commit/logging_handler.py +++ b/pre_commit/logging_handler.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import logging from typing import Generator diff --git a/pre_commit/main.py b/pre_commit/main.py index f1e8d03d..7ab9515c 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -1,11 +1,11 @@ +from __future__ import annotations + import argparse import logging import os import sys from typing import Any -from typing import Optional from typing import Sequence -from typing import Union import pre_commit.constants as C from pre_commit import git @@ -55,8 +55,8 @@ class AppendReplaceDefault(argparse.Action): self, parser: argparse.ArgumentParser, namespace: argparse.Namespace, - values: Union[str, Sequence[str], None], - option_string: Optional[str] = None, + values: str | Sequence[str] | None, + option_string: str | None = None, ) -> None: if not self.appended: setattr(namespace, self.dest, []) @@ -175,7 +175,7 @@ def _adjust_args_and_chdir(args: argparse.Namespace) -> None: args.repo = os.path.relpath(args.repo) -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: argv = argv if argv is not None else sys.argv[1:] parser = argparse.ArgumentParser(prog='pre-commit') diff --git a/pre_commit/meta_hooks/check_hooks_apply.py b/pre_commit/meta_hooks/check_hooks_apply.py index a6eb0e09..b05a7050 100644 --- a/pre_commit/meta_hooks/check_hooks_apply.py +++ b/pre_commit/meta_hooks/check_hooks_apply.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import argparse -from typing import Optional from typing import Sequence import pre_commit.constants as C @@ -27,7 +28,7 @@ def check_all_hooks_match_files(config_file: str) -> int: return retv -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE]) args = parser.parse_args(argv) diff --git a/pre_commit/meta_hooks/check_useless_excludes.py b/pre_commit/meta_hooks/check_useless_excludes.py index 60870f83..0a8249b8 100644 --- a/pre_commit/meta_hooks/check_useless_excludes.py +++ b/pre_commit/meta_hooks/check_useless_excludes.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import argparse import re -from typing import Optional from typing import Sequence from cfgv import apply_defaults @@ -65,7 +66,7 @@ def check_useless_excludes(config_file: str) -> int: return retv -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE]) args = parser.parse_args(argv) diff --git a/pre_commit/meta_hooks/identity.py b/pre_commit/meta_hooks/identity.py index 12eb02f9..72ee440b 100644 --- a/pre_commit/meta_hooks/identity.py +++ b/pre_commit/meta_hooks/identity.py @@ -1,11 +1,12 @@ +from __future__ import annotations + import sys -from typing import Optional from typing import Sequence from pre_commit import output -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: argv = argv if argv is not None else sys.argv[1:] for arg in argv: output.write_line(arg) diff --git a/pre_commit/output.py b/pre_commit/output.py index 24f9d846..4bcf27f9 100644 --- a/pre_commit/output.py +++ b/pre_commit/output.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import contextlib import sys from typing import Any from typing import IO -from typing import Optional def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None: @@ -11,9 +12,9 @@ def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None: def write_line_b( - s: Optional[bytes] = None, + s: bytes | None = None, stream: IO[bytes] = sys.stdout.buffer, - logfile_name: Optional[str] = None, + logfile_name: str | None = None, ) -> None: with contextlib.ExitStack() as exit_stack: output_streams = [stream] @@ -28,5 +29,5 @@ def write_line_b( output_stream.flush() -def write_line(s: Optional[str] = None, **kwargs: Any) -> None: +def write_line(s: str | None = None, **kwargs: Any) -> None: write_line_b(s.encode() if s is not None else s, **kwargs) diff --git a/pre_commit/parse_shebang.py b/pre_commit/parse_shebang.py index d344a1da..3fd3129f 100644 --- a/pre_commit/parse_shebang.py +++ b/pre_commit/parse_shebang.py @@ -1,7 +1,7 @@ +from __future__ import annotations + import os.path from typing import Mapping -from typing import Optional -from typing import Tuple from typing import TYPE_CHECKING from identify.identify import parse_shebang_from_file @@ -11,11 +11,11 @@ if TYPE_CHECKING: class ExecutableNotFoundError(OSError): - def to_output(self) -> Tuple[int, bytes, None]: + def to_output(self) -> tuple[int, bytes, None]: return (1, self.args[0].encode(), None) -def parse_filename(filename: str) -> Tuple[str, ...]: +def parse_filename(filename: str) -> tuple[str, ...]: if not os.path.exists(filename): return () else: @@ -23,8 +23,8 @@ def parse_filename(filename: str) -> Tuple[str, ...]: def find_executable( - exe: str, _environ: Optional[Mapping[str, str]] = None, -) -> Optional[str]: + exe: str, _environ: Mapping[str, str] | None = None, +) -> str | None: exe = os.path.normpath(exe) if os.sep in exe: return exe @@ -47,7 +47,7 @@ def find_executable( def normexe(orig: str) -> str: - def _error(msg: str) -> 'NoReturn': + def _error(msg: str) -> NoReturn: raise ExecutableNotFoundError(f'Executable `{orig}` {msg}') if os.sep not in orig and (not os.altsep or os.altsep not in orig): @@ -65,7 +65,7 @@ def normexe(orig: str) -> str: return orig -def normalize_cmd(cmd: Tuple[str, ...]) -> Tuple[str, ...]: +def normalize_cmd(cmd: tuple[str, ...]) -> tuple[str, ...]: """Fixes for the following issues on windows - https://bugs.python.org/issue8557 - windows does not parse shebangs diff --git a/pre_commit/prefix.py b/pre_commit/prefix.py index 0e3ebbd8..f1b28c1d 100644 --- a/pre_commit/prefix.py +++ b/pre_commit/prefix.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import os.path from typing import NamedTuple -from typing import Tuple class Prefix(NamedTuple): @@ -12,6 +13,6 @@ class Prefix(NamedTuple): def exists(self, *parts: str) -> bool: return os.path.exists(self.path(*parts)) - def star(self, end: str) -> Tuple[str, ...]: + def star(self, end: str) -> tuple[str, ...]: paths = os.listdir(self.prefix_dir) return tuple(path for path in paths if path.endswith(end)) diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 15827dde..ac5d294b 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -1,13 +1,10 @@ +from __future__ import annotations + import json import logging import os from typing import Any -from typing import Dict -from typing import List -from typing import Optional from typing import Sequence -from typing import Set -from typing import Tuple import pre_commit.constants as C from pre_commit.clientlib import load_manifest @@ -33,7 +30,7 @@ def _state_filename(prefix: Prefix, venv: str) -> str: return prefix.path(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}') -def _read_state(prefix: Prefix, venv: str) -> Optional[object]: +def _read_state(prefix: Prefix, venv: str) -> object | None: filename = _state_filename(prefix, venv) if not os.path.exists(filename): return None @@ -93,9 +90,9 @@ def _hook_install(hook: Hook) -> None: def _hook( - *hook_dicts: Dict[str, Any], - root_config: Dict[str, Any], -) -> Dict[str, Any]: + *hook_dicts: dict[str, Any], + root_config: dict[str, Any], +) -> dict[str, Any]: ret, rest = dict(hook_dicts[0]), hook_dicts[1:] for dct in rest: ret.update(dct) @@ -140,10 +137,10 @@ def _hook( def _non_cloned_repository_hooks( - repo_config: Dict[str, Any], + repo_config: dict[str, Any], store: Store, - root_config: Dict[str, Any], -) -> Tuple[Hook, ...]: + root_config: dict[str, Any], +) -> tuple[Hook, ...]: def _prefix(language_name: str, deps: Sequence[str]) -> Prefix: language = languages[language_name] # pygrep / script / system / docker_image do not have @@ -164,10 +161,10 @@ def _non_cloned_repository_hooks( def _cloned_repository_hooks( - repo_config: Dict[str, Any], + repo_config: dict[str, Any], store: Store, - root_config: Dict[str, Any], -) -> Tuple[Hook, ...]: + root_config: dict[str, Any], +) -> tuple[Hook, ...]: repo, rev = repo_config['repo'], repo_config['rev'] manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE) by_id = {hook['id']: hook for hook in load_manifest(manifest_path)} @@ -196,10 +193,10 @@ def _cloned_repository_hooks( def _repository_hooks( - repo_config: Dict[str, Any], + repo_config: dict[str, Any], store: Store, - root_config: Dict[str, Any], -) -> Tuple[Hook, ...]: + root_config: dict[str, Any], +) -> tuple[Hook, ...]: if repo_config['repo'] in {LOCAL, META}: return _non_cloned_repository_hooks(repo_config, store, root_config) else: @@ -207,8 +204,8 @@ def _repository_hooks( def install_hook_envs(hooks: Sequence[Hook], store: Store) -> None: - def _need_installed() -> List[Hook]: - seen: Set[Tuple[Prefix, str, str, Tuple[str, ...]]] = set() + def _need_installed() -> list[Hook]: + seen: set[tuple[Prefix, str, str, tuple[str, ...]]] = set() ret = [] for hook in hooks: if hook.install_key not in seen and not _hook_installed(hook): @@ -224,7 +221,7 @@ def install_hook_envs(hooks: Sequence[Hook], store: Store) -> None: _hook_install(hook) -def all_hooks(root_config: Dict[str, Any], store: Store) -> Tuple[Hook, ...]: +def all_hooks(root_config: dict[str, Any], store: Store) -> tuple[Hook, ...]: return tuple( hook for repo in root_config['repos'] diff --git a/pre_commit/resources/empty_template_setup.py b/pre_commit/resources/empty_template_setup.py index ef05eef8..870d0fba 100644 --- a/pre_commit/resources/empty_template_setup.py +++ b/pre_commit/resources/empty_template_setup.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from setuptools import setup diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index bad004cd..7e75080d 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import logging import os.path diff --git a/pre_commit/store.py b/pre_commit/store.py index 27d8553c..effebfb8 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import logging import os.path @@ -5,10 +7,7 @@ import sqlite3 import tempfile from typing import Callable from typing import Generator -from typing import List -from typing import Optional from typing import Sequence -from typing import Tuple import pre_commit.constants as C from pre_commit import file_lock @@ -40,7 +39,7 @@ def _get_default_directory() -> str: class Store: get_default_directory = staticmethod(_get_default_directory) - def __init__(self, directory: Optional[str] = None) -> None: + def __init__(self, directory: str | None = None) -> None: self.directory = directory or Store.get_default_directory() self.db_path = os.path.join(self.directory, 'db.db') self.readonly = ( @@ -92,7 +91,7 @@ class Store: @contextlib.contextmanager def connect( self, - db_path: Optional[str] = None, + db_path: str | None = None, ) -> Generator[sqlite3.Connection, None, None]: db_path = db_path or self.db_path # sqlite doesn't close its fd with its contextmanager >.< @@ -119,7 +118,7 @@ class Store: ) -> str: repo = self.db_repo_name(repo, deps) - def _get_result() -> Optional[str]: + def _get_result() -> str | None: # Check if we already exist with self.connect() as db: result = db.execute( @@ -239,18 +238,18 @@ class Store: self._create_config_table(db) db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,)) - def select_all_configs(self) -> List[str]: + def select_all_configs(self) -> list[str]: with self.connect() as db: self._create_config_table(db) rows = db.execute('SELECT path FROM configs').fetchall() return [path for path, in rows] - def delete_configs(self, configs: List[str]) -> None: + def delete_configs(self, configs: list[str]) -> None: with self.connect() as db: rows = [(path,) for path in configs] db.executemany('DELETE FROM configs WHERE path = ?', rows) - def select_all_repos(self) -> List[Tuple[str, str, str]]: + def select_all_repos(self) -> list[tuple[str, str, str]]: with self.connect() as db: return db.execute('SELECT repo, ref, path from repos').fetchall() diff --git a/pre_commit/util.py b/pre_commit/util.py index 6977acb2..40c53e51 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import contextlib import errno import functools +import importlib.resources import os.path import shutil import stat @@ -10,24 +13,13 @@ import tempfile from types import TracebackType from typing import Any from typing import Callable -from typing import Dict from typing import Generator from typing import IO -from typing import Optional -from typing import Tuple -from typing import Type import yaml from pre_commit import parse_shebang -if sys.version_info >= (3, 7): # pragma: >=3.7 cover - from importlib.resources import open_binary - from importlib.resources import read_text -else: # pragma: <3.7 cover - from importlib_resources import open_binary - from importlib_resources import read_text - Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) yaml_load = functools.partial(yaml.load, Loader=Loader) Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) @@ -73,11 +65,11 @@ def tmpdir() -> Generator[str, None, None]: def resource_bytesio(filename: str) -> IO[bytes]: - return open_binary('pre_commit.resources', filename) + return importlib.resources.open_binary('pre_commit.resources', filename) def resource_text(filename: str) -> str: - return read_text('pre_commit.resources', filename) + return importlib.resources.read_text('pre_commit.resources', filename) def make_executable(filename: str) -> None: @@ -90,10 +82,10 @@ class CalledProcessError(RuntimeError): def __init__( self, returncode: int, - cmd: Tuple[str, ...], + cmd: tuple[str, ...], expected_returncode: int, stdout: bytes, - stderr: Optional[bytes], + stderr: bytes | None, ) -> None: super().__init__(returncode, cmd, expected_returncode, stdout, stderr) self.returncode = returncode @@ -103,7 +95,7 @@ class CalledProcessError(RuntimeError): self.stderr = stderr def __bytes__(self) -> bytes: - def _indent_or_none(part: Optional[bytes]) -> bytes: + def _indent_or_none(part: bytes | None) -> bytes: if part: return b'\n ' + part.replace(b'\n', b'\n ') else: @@ -121,20 +113,20 @@ class CalledProcessError(RuntimeError): return self.__bytes__().decode() -def _setdefault_kwargs(kwargs: Dict[str, Any]) -> None: +def _setdefault_kwargs(kwargs: dict[str, Any]) -> None: for arg in ('stdin', 'stdout', 'stderr'): kwargs.setdefault(arg, subprocess.PIPE) -def _oserror_to_output(e: OSError) -> Tuple[int, bytes, None]: +def _oserror_to_output(e: OSError) -> tuple[int, bytes, None]: return 1, force_bytes(e).rstrip(b'\n') + b'\n', None def cmd_output_b( *cmd: str, - retcode: Optional[int] = 0, + retcode: int | None = 0, **kwargs: Any, -) -> Tuple[int, bytes, Optional[bytes]]: +) -> tuple[int, bytes, bytes | None]: _setdefault_kwargs(kwargs) try: @@ -156,7 +148,7 @@ def cmd_output_b( return returncode, stdout_b, stderr_b -def cmd_output(*cmd: str, **kwargs: Any) -> Tuple[int, str, Optional[str]]: +def cmd_output(*cmd: str, **kwargs: Any) -> tuple[int, str, str | None]: returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs) stdout = stdout_b.decode() if stdout_b is not None else None stderr = stderr_b.decode() if stderr_b is not None else None @@ -169,10 +161,10 @@ if os.name != 'nt': # pragma: win32 no cover class Pty: def __init__(self) -> None: - self.r: Optional[int] = None - self.w: Optional[int] = None + self.r: int | None = None + self.w: int | None = None - def __enter__(self) -> 'Pty': + def __enter__(self) -> Pty: self.r, self.w = openpty() # tty flags normally change \n to \r\n @@ -195,18 +187,18 @@ if os.name != 'nt': # pragma: win32 no cover def __exit__( self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, ) -> None: self.close_w() self.close_r() def cmd_output_p( *cmd: str, - retcode: Optional[int] = 0, + retcode: int | None = 0, **kwargs: Any, - ) -> Tuple[int, bytes, Optional[bytes]]: + ) -> tuple[int, bytes, bytes | None]: assert retcode is None assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr'] _setdefault_kwargs(kwargs) @@ -250,7 +242,7 @@ def rmtree(path: str) -> None: def handle_remove_readonly( func: Callable[..., Any], path: str, - exc: Tuple[Type[OSError], OSError, TracebackType], + exc: tuple[type[OSError], OSError, TracebackType], ) -> None: excvalue = exc[1] if ( @@ -265,7 +257,7 @@ def rmtree(path: str) -> None: shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly) -def parse_version(s: str) -> Tuple[int, ...]: +def parse_version(s: str) -> tuple[int, ...]: """poor man's version comparison""" return tuple(int(p) for p in s.split('.')) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index 6b0fa208..f2b3421a 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import concurrent.futures import contextlib import math @@ -8,11 +10,8 @@ from typing import Any from typing import Callable from typing import Generator from typing import Iterable -from typing import List from typing import MutableMapping -from typing import Optional from typing import Sequence -from typing import Tuple from typing import TypeVar from pre_commit import parse_shebang @@ -23,7 +22,7 @@ TArg = TypeVar('TArg') TRet = TypeVar('TRet') -def _environ_size(_env: Optional[MutableMapping[str, str]] = None) -> int: +def _environ_size(_env: MutableMapping[str, str] | None = None) -> int: environ = _env if _env is not None else getattr(os, 'environb', os.environ) size = 8 * len(environ) # number of pointers in `envp` for k, v in environ.items(): @@ -62,8 +61,8 @@ def partition( cmd: Sequence[str], varargs: Sequence[str], target_concurrency: int, - _max_length: Optional[int] = None, -) -> Tuple[Tuple[str, ...], ...]: + _max_length: int | None = None, +) -> tuple[tuple[str, ...], ...]: _max_length = _max_length or _get_platform_max_length() # Generally, we try to partition evenly into at least `target_concurrency` @@ -73,7 +72,7 @@ def partition( cmd = tuple(cmd) ret = [] - ret_cmd: List[str] = [] + ret_cmd: list[str] = [] # Reversed so arguments are in order varargs = list(reversed(varargs)) @@ -115,14 +114,14 @@ def _thread_mapper(maxsize: int) -> Generator[ def xargs( - cmd: Tuple[str, ...], + cmd: tuple[str, ...], varargs: Sequence[str], *, color: bool = False, target_concurrency: int = 1, _max_length: int = _get_platform_max_length(), **kwargs: Any, -) -> Tuple[int, bytes]: +) -> tuple[int, bytes]: """A simplified implementation of xargs. color: Make a pty if on a platform that supports it @@ -152,8 +151,8 @@ def xargs( partitions = partition(cmd, varargs, target_concurrency, _max_length) def run_cmd_partition( - run_cmd: Tuple[str, ...], - ) -> Tuple[int, bytes, Optional[bytes]]: + run_cmd: tuple[str, ...], + ) -> tuple[int, bytes, bytes | None]: return cmd_fn( *run_cmd, retcode=None, stderr=subprocess.STDOUT, **kwargs, ) diff --git a/setup.cfg b/setup.cfg index ef55b7cd..d712a3f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,7 +13,6 @@ classifiers = License :: OSI Approved :: MIT License Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -31,8 +30,7 @@ install_requires = toml virtualenv>=20.0.8 importlib-metadata;python_version<"3.8" - importlib-resources<5.3;python_version<"3.7" -python_requires = >=3.6.1 +python_requires = >=3.7 [options.packages.find] exclude = diff --git a/setup.py b/setup.py index 8bf1ba93..3d93aefb 100644 --- a/setup.py +++ b/setup.py @@ -1,2 +1,4 @@ +from __future__ import annotations + from setuptools import setup setup() diff --git a/testing/auto_namedtuple.py b/testing/auto_namedtuple.py index 0841094e..d5a43775 100644 --- a/testing/auto_namedtuple.py +++ b/testing/auto_namedtuple.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import collections diff --git a/testing/fixtures.py b/testing/fixtures.py index f7def081..ef5a0418 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import os.path import shutil diff --git a/testing/gen-languages-all b/testing/gen-languages-all index 152cf3c6..dfd92c0e 100755 --- a/testing/gen-languages-all +++ b/testing/gen-languages-all @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import sys LANGUAGES = [ diff --git a/testing/make-archives b/testing/make-archives index ce098ba1..ed95fb7c 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import argparse import gzip import os.path @@ -6,7 +8,6 @@ import shutil import subprocess import tarfile import tempfile -from typing import Optional from typing import Sequence @@ -69,7 +70,7 @@ def make_archive(name: str, repo: str, ref: str, destdir: str) -> str: return output_path -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument('--dest', default='pre_commit/resources') args = parser.parse_args(argv) diff --git a/testing/resources/python_hooks_repo/foo.py b/testing/resources/python_hooks_repo/foo.py index 9c4368e2..40efde39 100644 --- a/testing/resources/python_hooks_repo/foo.py +++ b/testing/resources/python_hooks_repo/foo.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys diff --git a/testing/resources/python_hooks_repo/setup.py b/testing/resources/python_hooks_repo/setup.py index 0559271e..cff6cadf 100644 --- a/testing/resources/python_hooks_repo/setup.py +++ b/testing/resources/python_hooks_repo/setup.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from setuptools import setup setup( diff --git a/testing/resources/python_venv_hooks_repo/foo.py b/testing/resources/python_venv_hooks_repo/foo.py index 9c4368e2..40efde39 100644 --- a/testing/resources/python_venv_hooks_repo/foo.py +++ b/testing/resources/python_venv_hooks_repo/foo.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys diff --git a/testing/resources/python_venv_hooks_repo/setup.py b/testing/resources/python_venv_hooks_repo/setup.py index 0559271e..cff6cadf 100644 --- a/testing/resources/python_venv_hooks_repo/setup.py +++ b/testing/resources/python_venv_hooks_repo/setup.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from setuptools import setup setup( diff --git a/testing/util.py b/testing/util.py index 283ed477..0dd17840 100644 --- a/testing/util.py +++ b/testing/util.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import os.path import subprocess diff --git a/testing/zipapp/Dockerfile b/testing/zipapp/Dockerfile index e21d5fe3..7c74c1b2 100644 --- a/testing/zipapp/Dockerfile +++ b/testing/zipapp/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:bionic +FROM ubuntu:focal RUN : \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ @@ -10,5 +10,5 @@ RUN : \ ENV LANG=C.UTF-8 PATH=/venv/bin:$PATH RUN : \ - && python3.6 -mvenv /venv \ + && python3 -mvenv /venv \ && pip install --no-cache-dir pip setuptools wheel no-manylinux --upgrade diff --git a/testing/zipapp/entry b/testing/zipapp/entry index 87f9291d..15758d93 100755 --- a/testing/zipapp/entry +++ b/testing/zipapp/entry @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import os.path import shutil import stat @@ -59,10 +61,7 @@ def main() -> int: if sys.platform == 'win32': # https://bugs.python.org/issue19124 import subprocess - if sys.version_info < (3, 7): # https://bugs.python.org/issue25942 - return subprocess.Popen(cmd).wait() - else: - return subprocess.call(cmd) + return subprocess.call(cmd) else: os.execvp(cmd[0], cmd) diff --git a/testing/zipapp/make b/testing/zipapp/make index effc8123..37b5c355 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import argparse import base64 import hashlib diff --git a/testing/zipapp/python b/testing/zipapp/python index 7184a1aa..67910fca 100755 --- a/testing/zipapp/python +++ b/testing/zipapp/python @@ -1,5 +1,7 @@ #!/usr/bin/env python3 """A shim executable to put dependencies on sys.path""" +from __future__ import annotations + import argparse import os.path import runpy @@ -36,10 +38,7 @@ def main() -> int: if sys.platform == 'win32': # https://bugs.python.org/issue19124 import subprocess - if sys.version_info < (3, 7): # https://bugs.python.org/issue25942 - return subprocess.Popen(cmd).wait() - else: - return subprocess.call(cmd) + return subprocess.call(cmd) else: os.execvp(cmd[0], cmd) diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 39a37168..3fb3af52 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging import re diff --git a/tests/color_test.py b/tests/color_test.py index 5cd226a9..89b4fd3e 100644 --- a/tests/color_test.py +++ b/tests/color_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from unittest import mock diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index 7316eb97..3a142661 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import shlex from unittest import mock diff --git a/tests/commands/clean_test.py b/tests/commands/clean_test.py index 955a6bc4..dd8e4a53 100644 --- a/tests/commands/clean_test.py +++ b/tests/commands/clean_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path from unittest import mock diff --git a/tests/commands/gc_test.py b/tests/commands/gc_test.py index 02b36945..c128e939 100644 --- a/tests/commands/gc_test.py +++ b/tests/commands/gc_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import pre_commit.constants as C diff --git a/tests/commands/hook_impl_test.py b/tests/commands/hook_impl_test.py index 37b78bc0..b0159f8e 100644 --- a/tests/commands/hook_impl_test.py +++ b/tests/commands/hook_impl_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import subprocess import sys from unittest import mock diff --git a/tests/commands/init_templatedir_test.py b/tests/commands/init_templatedir_test.py index 4e131dff..64bfc8b4 100644 --- a/tests/commands/init_templatedir_test.py +++ b/tests/commands/init_templatedir_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path from unittest import mock diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 0b2e248b..703ba03b 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import re diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py index f5eddd3d..b80244e1 100644 --- a/tests/commands/migrate_config_test.py +++ b/tests/commands/migrate_config_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pre_commit.constants as C from pre_commit.commands.migrate_config import migrate_config diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 3a6fa2a1..085b063f 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import shlex import sys diff --git a/tests/commands/sample_config_test.py b/tests/commands/sample_config_test.py index 8e3a9043..cf56e98c 100644 --- a/tests/commands/sample_config_test.py +++ b/tests/commands/sample_config_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pre_commit.commands.sample_config import sample_config diff --git a/tests/commands/try_repo_test.py b/tests/commands/try_repo_test.py index a157d163..0b2db7e5 100644 --- a/tests/commands/try_repo_test.py +++ b/tests/commands/try_repo_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import re import time diff --git a/tests/conftest.py b/tests/conftest.py index f38f9693..b68a1d00 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import functools import io import logging diff --git a/tests/envcontext_test.py b/tests/envcontext_test.py index f9d4dce6..c82d3267 100644 --- a/tests/envcontext_test.py +++ b/tests/envcontext_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from unittest import mock diff --git a/tests/error_handler_test.py b/tests/error_handler_test.py index cb76dcf4..31c71d28 100644 --- a/tests/error_handler_test.py +++ b/tests/error_handler_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import stat import sys diff --git a/tests/git_test.py b/tests/git_test.py index bcb3fd15..d9e497c5 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import pytest diff --git a/tests/languages/conda_test.py b/tests/languages/conda_test.py index 6faa78f2..5023b2af 100644 --- a/tests/languages/conda_test.py +++ b/tests/languages/conda_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pre_commit import envcontext diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index ec6bb83c..58387611 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import builtins import json import ntpath diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 9a64ed19..9e393cb3 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pre_commit.languages.golang import guess_go_dir diff --git a/tests/languages/helpers_test.py b/tests/languages/helpers_test.py index fd9b9a45..49d81226 100644 --- a/tests/languages/helpers_test.py +++ b/tests/languages/helpers_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import multiprocessing import os.path import sys diff --git a/tests/languages/node_test.py b/tests/languages/node_test.py index 8e52268f..fb5ae717 100644 --- a/tests/languages/node_test.py +++ b/tests/languages/node_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json import os import shutil diff --git a/tests/languages/pygrep_test.py b/tests/languages/pygrep_test.py index d8bacc48..8420046c 100644 --- a/tests/languages/pygrep_test.py +++ b/tests/languages/pygrep_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pre_commit.languages import pygrep diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index 8324cac2..61606696 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import sys from unittest import mock @@ -47,16 +49,16 @@ def test_norm_version_of_default_is_sys_executable(): assert python.norm_version('default') is None -@pytest.mark.parametrize('v', ('python3.6', 'python3', 'python')) +@pytest.mark.parametrize('v', ('python3.9', 'python3', 'python')) def test_sys_executable_matches(v): - with mock.patch.object(sys, 'version_info', (3, 6, 7)): + with mock.patch.object(sys, 'version_info', (3, 9, 10)): assert python._sys_executable_matches(v) assert python.norm_version(v) is None @pytest.mark.parametrize('v', ('notpython', 'python3.x')) def test_sys_executable_matches_does_not_match(v): - with mock.patch.object(sys, 'version_info', (3, 6, 7)): + with mock.patch.object(sys, 'version_info', (3, 9, 10)): assert not python._sys_executable_matches(v) @@ -65,7 +67,7 @@ def test_sys_executable_matches_does_not_match(v): ('/usr/bin/python3', '/usr/bin/python3.7', 'python3'), ('/usr/bin/python', '/usr/bin/python3.7', 'python3.7'), ('/usr/bin/python', '/usr/bin/python', None), - ('/usr/bin/python3.6m', '/usr/bin/python3.6m', 'python3.6m'), + ('/usr/bin/python3.7m', '/usr/bin/python3.7m', 'python3.7m'), ('v/bin/python', 'v/bin/pypy', 'pypy'), ), ) diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index 66aa7b38..bc302a79 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import pytest diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 7dff0466..dc55456e 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import tarfile from unittest import mock diff --git a/tests/logging_handler_test.py b/tests/logging_handler_test.py index fe68593b..dc43a99f 100644 --- a/tests/logging_handler_test.py +++ b/tests/logging_handler_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging from pre_commit import color diff --git a/tests/main_test.py b/tests/main_test.py index 1ad8d418..64b26a00 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import os.path from unittest import mock diff --git a/tests/meta_hooks/check_hooks_apply_test.py b/tests/meta_hooks/check_hooks_apply_test.py index 06bdd045..63f97152 100644 --- a/tests/meta_hooks/check_hooks_apply_test.py +++ b/tests/meta_hooks/check_hooks_apply_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pre_commit.meta_hooks import check_hooks_apply from testing.fixtures import add_config_to_repo diff --git a/tests/meta_hooks/check_useless_excludes_test.py b/tests/meta_hooks/check_useless_excludes_test.py index 703bd250..15b68b4c 100644 --- a/tests/meta_hooks/check_useless_excludes_test.py +++ b/tests/meta_hooks/check_useless_excludes_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pre_commit import git from pre_commit.meta_hooks import check_useless_excludes from pre_commit.util import cmd_output diff --git a/tests/meta_hooks/identity_test.py b/tests/meta_hooks/identity_test.py index 3eff00be..97c20ea6 100644 --- a/tests/meta_hooks/identity_test.py +++ b/tests/meta_hooks/identity_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pre_commit.meta_hooks import identity diff --git a/tests/output_test.py b/tests/output_test.py index 1cdacbbc..c806829a 100644 --- a/tests/output_test.py +++ b/tests/output_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import io from pre_commit import output diff --git a/tests/parse_shebang_test.py b/tests/parse_shebang_test.py index 0bb19c78..d7acbf57 100644 --- a/tests/parse_shebang_test.py +++ b/tests/parse_shebang_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import os.path import shutil diff --git a/tests/prefix_test.py b/tests/prefix_test.py index 6ce8be12..1eac087d 100644 --- a/tests/prefix_test.py +++ b/tests/prefix_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import pytest diff --git a/tests/repository_test.py b/tests/repository_test.py index 8569ba96..01373147 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import os.path import shutil import sys from typing import Any -from typing import Dict from unittest import mock import cfgv @@ -897,7 +898,7 @@ def test_local_python_repo(store, local_python_config): def test_default_language_version(store, local_python_config): - config: Dict[str, Any] = { + config: dict[str, Any] = { 'default_language_version': {'python': 'fake'}, 'default_stages': ['commit'], 'repos': [local_python_config], @@ -914,7 +915,7 @@ def test_default_language_version(store, local_python_config): def test_default_stages(store, local_python_config): - config: Dict[str, Any] = { + config: dict[str, Any] = { 'default_language_version': {'python': C.DEFAULT}, 'default_stages': ['commit'], 'repos': [local_python_config], diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index 2e3f6209..a91f3151 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import itertools import os.path import shutil diff --git a/tests/store_test.py b/tests/store_test.py index 5a5d69e0..ff671a83 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import sqlite3 import stat diff --git a/tests/util_test.py b/tests/util_test.py index 01afbd4b..6b00f9fc 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import stat import subprocess diff --git a/tests/xargs_test.py b/tests/xargs_test.py index 7e83ef59..0530e50d 100644 --- a/tests/xargs_test.py +++ b/tests/xargs_test.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import concurrent.futures import os import sys import time -from typing import Tuple from unittest import mock import pytest @@ -178,7 +179,7 @@ def test_thread_mapper_concurrency_uses_regular_map(): def test_xargs_propagate_kwargs_to_cmd(): env = {'PRE_COMMIT_TEST_VAR': 'Pre commit is awesome'} - cmd: Tuple[str, ...] = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--') + cmd: tuple[str, ...] = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--') cmd = parse_shebang.normalize_cmd(cmd) ret, stdout = xargs.xargs(cmd, ('1',), env=env) diff --git a/tox.ini b/tox.ini index 11b20d41..7f43e41e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py36,py37,py38,pypy3,pre-commit +envlist = py37,py38,pypy3,pre-commit [testenv] deps = -rrequirements-dev.txt From 1112c9f5ce4f2b0497efb4fe91ce8ae0681e049d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 23 Jan 2022 21:20:59 -0500 Subject: [PATCH 050/416] upgrade flake8-typing-imports Committed via https://github.com/asottile/all-repos --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5103e0be..ce2dd34f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: rev: 4.0.1 hooks: - id: flake8 - additional_dependencies: [flake8-typing-imports==1.10.0] + additional_dependencies: [flake8-typing-imports==1.12.0] - repo: https://github.com/pre-commit/mirrors-autopep8 rev: v1.6.0 hooks: From 8e9202acb41d4407b0af2766ee612576a4dcbcc3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Jan 2022 21:02:21 +0000 Subject: [PATCH 051/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v2.6.0 → v2.7.1](https://github.com/asottile/reorder_python_imports/compare/v2.6.0...v2.7.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce2dd34f..b0de2096 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/asottile/reorder_python_imports - rev: v2.6.0 + rev: v2.7.1 hooks: - id: reorder-python-imports args: [--py37-plus, --add-import, 'from __future__ import annotations'] From e58bcb51fc40c1006c7d932b46eb19ffaad14e29 Mon Sep 17 00:00:00 2001 From: Lee Trout Date: Wed, 2 Mar 2022 17:33:11 -0500 Subject: [PATCH 052/416] Fix typo in help docs for to-ref and from-ref --- pre_commit/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/main.py b/pre_commit/main.py index 7ab9515c..da96a011 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -106,7 +106,7 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None: parser.add_argument( '--from-ref', '--source', '-s', help=( - '(for usage with `--from-ref`) -- this option represents the ' + '(for usage with `--to-ref`) -- this option represents the ' 'original ref in a `from_ref...to_ref` diff expression. ' 'For `pre-push` hooks, this represents the branch you are pushing ' 'to. ' @@ -117,7 +117,7 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None: parser.add_argument( '--to-ref', '--origin', '-o', help=( - '(for usage with `--to-ref`) -- this option represents the ' + '(for usage with `--from-ref`) -- this option represents the ' 'destination ref in a `from_ref...to_ref` diff expression. ' 'For `pre-push` hooks, this represents the branch being pushed. ' 'For `post-checkout` hooks, this represents the branch that is ' From 07f441584b9e4111e31e857a6ee94fcadfb704c4 Mon Sep 17 00:00:00 2001 From: VincentBerthier <34085617+VincentBerthier@users.noreply.github.com> Date: Fri, 4 Mar 2022 20:18:27 +0100 Subject: [PATCH 053/416] GIT_HTTP_PROXY_AUTHMETHOD kept in env variables --- pre_commit/git.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pre_commit/git.py b/pre_commit/git.py index 67499cdb..853f4b0d 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -43,6 +43,7 @@ def no_git_env( k in { 'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO', 'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT', + 'GIT_HTTP_PROXY_AUTHMETHOD', } } From 65755af7e3890f7ee130c0c1fdaa0429a868030e Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Sat, 5 Mar 2022 21:04:01 +0100 Subject: [PATCH 054/416] inline options() to always install binaries --- pre_commit/languages/r.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 2ad8c411..9b32b2d7 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -103,9 +103,7 @@ def install_environment( shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) - cmd_output_b( - _rscript_exec(), '--vanilla', '-e', - f"""\ + r_code_inst_environment = f"""\ prefix_dir <- {prefix.prefix_dir!r} options( repos = c(CRAN = "https://cran.rstudio.com"), @@ -132,19 +130,36 @@ def install_environment( if (is_package) {{ renv::install(prefix_dir) }} - """, + """ + + cmd_output_b( + _rscript_exec(), '--vanilla', '-e', + _inline_r_setup(r_code_inst_environment), cwd=env_dir, ) if additional_dependencies: + r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' with in_env(prefix, version): cmd_output_b( _rscript_exec(), *RSCRIPT_OPTS, '-e', - 'renv::install(commandArgs(trailingOnly = TRUE))', + _inline_r_setup(r_code_inst_add), *additional_dependencies, cwd=env_dir, ) +def _inline_r_setup(code: str) -> str: + """ + Some behaviour of R cannot be configured via env variables, but can + only be configured via R options once R has started. These are set here. + """ + with_option = f"""\ + options(install.packages.compile.from.source = "never") + {code} + """ + return with_option + + def run_hook( hook: Hook, file_args: Sequence[str], From a85df8027b09bda436b4bba5154ae3bc474f6ceb Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 13 Mar 2022 19:55:30 -0400 Subject: [PATCH 055/416] remove unneeded gitignore lines - coverage-html: coverage>=6.2 writes a .gitignore file - mypy_cache: mypy>=0.770 writes a .gitignore file - pytest_cache: pytest>=3.8.1 writes a .gitignore file - venv: virtualenv>=20.0.21 writes a .gitignore file Committed via https://github.com/asottile/all-repos --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 4f4f6b94..c2021816 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ *.egg-info *.py[co] /.coverage -/.mypy_cache -/.pytest_cache /.tox /dist -/venv* .vscode/ From 9516ed41aa89904e9771b59c748cb3be90689d52 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 14 Mar 2022 22:18:01 +0000 Subject: [PATCH 056/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.31.0 → v2.31.1](https://github.com/asottile/pyupgrade/compare/v2.31.0...v2.31.1) - [github.com/asottile/reorder_python_imports: v2.7.1 → v3.0.1](https://github.com/asottile/reorder_python_imports/compare/v2.7.1...v3.0.1) - [github.com/pre-commit/mirrors-mypy: v0.931 → v0.940](https://github.com/pre-commit/mirrors-mypy/compare/v0.931...v0.940) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b0de2096..bea2466b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,12 +25,12 @@ repos: hooks: - id: validate_manifest - repo: https://github.com/asottile/pyupgrade - rev: v2.31.0 + rev: v2.31.1 hooks: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/asottile/reorder_python_imports - rev: v2.7.1 + rev: v3.0.1 hooks: - id: reorder-python-imports args: [--py37-plus, --add-import, 'from __future__ import annotations'] @@ -45,7 +45,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.931 + rev: v0.940 hooks: - id: mypy additional_dependencies: [types-all] From a8225a250b4e567f6881362db0304ca574b251a4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 14 Mar 2022 18:37:07 -0400 Subject: [PATCH 057/416] convince mypy that these are the same --- pre_commit/error_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pre_commit/error_handler.py b/pre_commit/error_handler.py index a6a7329e..992f5cdc 100644 --- a/pre_commit/error_handler.py +++ b/pre_commit/error_handler.py @@ -6,6 +6,7 @@ import os.path import sys import traceback from typing import Generator +from typing import IO import pre_commit.constants as C from pre_commit import output @@ -32,7 +33,7 @@ def _log_and_exit( with contextlib.ExitStack() as ctx: if os.access(storedir, os.W_OK): output.write_line(f'Check the log at {log_path}') - log = ctx.enter_context(open(log_path, 'wb')) + log: IO[bytes] = ctx.enter_context(open(log_path, 'wb')) else: # pragma: win32 no cover output.write_line(f'Failed to write to log at {log_path}') log = sys.stdout.buffer From 678ef6b9fd4f84e10486dc592e0939549591f919 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 17 Mar 2022 15:31:01 +0100 Subject: [PATCH 058/416] coursier: Add support for both `cs` and `coursier` executable names On some systems, the executable might be named `coursier` instead of `cs`. For example, this is the case on Arch Linux when using the AUR package, or when following the official instructions when installing the JAR-based launcher: https://get-coursier.io/docs/cli-installation#jar-based-launcher --- pre_commit/languages/coursier.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index e47f9c87..bb3e0b84 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -10,6 +10,7 @@ from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers +from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix from pre_commit.util import clean_path_on_failure @@ -27,6 +28,14 @@ def install_environment( helpers.assert_version_default('coursier', version) helpers.assert_no_additional_deps('coursier', additional_dependencies) + # Support both possible executable names (either "cs" or "coursier") + executable = find_executable('cs') or find_executable('coursier') + if executable is None: + raise AssertionError( + 'pre-commit requires system-installed "cs" or "coursier" ' + 'executables in the application search path', + ) + envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) channel = prefix.path('.pre-commit-channel') with clean_path_on_failure(envdir): @@ -36,7 +45,7 @@ def install_environment( helpers.run_setup_cmd( prefix, ( - 'cs', + executable, 'install', '--default-channels=false', f'--channel={channel}', From 28a5a28b396120202a19535e28475dec3c9acd92 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Mar 2022 22:31:22 +0000 Subject: [PATCH 059/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.940 → v0.941](https://github.com/pre-commit/mirrors-mypy/compare/v0.940...v0.941) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bea2466b..a80505b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.940 + rev: v0.941 hooks: - id: mypy additional_dependencies: [types-all] From 525191f34bcb26210ada2d90f76222920049f3ef Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 24 Mar 2022 13:52:25 -0400 Subject: [PATCH 060/416] update master to main --- CONTRIBUTING.md | 2 +- README.md | 6 +++--- azure-pipelines.yml | 2 +- pre_commit/main.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76df4370..adce08f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,7 +93,7 @@ language, for example: here are the apis that should be implemented for a language -Note that these are also documented in [`pre_commit/languages/all.py`](https://github.com/pre-commit/pre-commit/blob/master/pre_commit/languages/all.py) +Note that these are also documented in [`pre_commit/languages/all.py`](https://github.com/pre-commit/pre-commit/blob/main/pre_commit/languages/all.py) #### `ENVIRONMENT_DIR` diff --git a/README.md b/README.md index de7032cb..db1259c2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/pre-commit.pre-commit?branchName=master)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=master) -[![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/21/master.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=master) -[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit/master.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit/master) +[![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/pre-commit.pre-commit?branchName=main)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=main) +[![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/21/main.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=main) +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit/main.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit/main) ## pre-commit diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d3336a46..afb29828 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,6 +1,6 @@ trigger: branches: - include: [master, test-me-*] + include: [main, test-me-*] tags: include: ['*'] diff --git a/pre_commit/main.py b/pre_commit/main.py index da96a011..f3c55188 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -197,7 +197,7 @@ def main(argv: Sequence[str] | None = None) -> int: autoupdate_parser.add_argument( '--bleeding-edge', action='store_true', help=( - 'Update to the bleeding edge of `master` instead of the latest ' + 'Update to the bleeding edge of `HEAD` instead of the latest ' 'tagged version (the default behavior).' ), ) From 97419b34defbddcaea6aeab04e77dd5af14a25f3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 25 Mar 2022 14:12:02 -0400 Subject: [PATCH 061/416] reorder pre-commit config Committed via https://github.com/asottile/all-repos --- .pre-commit-config.yaml | 47 +++++++------------ .../resources/python3_hooks_repo/py3_hook.py | 2 + testing/resources/python3_hooks_repo/setup.py | 2 + 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a80505b0..6f1fafd2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,53 +4,40 @@ repos: hooks: - id: trailing-whitespace - id: end-of-file-fixer - - id: check-docstring-first - - id: check-json - id: check-yaml - id: debug-statements + - id: double-quote-string-fixer - id: name-tests-test - id: requirements-txt-fixer - - id: double-quote-string-fixer -- repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 +- repo: https://github.com/asottile/setup-cfg-fmt + rev: v1.20.0 hooks: - - id: flake8 - additional_dependencies: [flake8-typing-imports==1.12.0] -- repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.6.0 - hooks: - - id: autopep8 -- repo: https://github.com/pre-commit/pre-commit - rev: v2.17.0 - hooks: - - id: validate_manifest -- repo: https://github.com/asottile/pyupgrade - rev: v2.31.1 - hooks: - - id: pyupgrade - args: [--py37-plus] + - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports rev: v3.0.1 hooks: - id: reorder-python-imports args: [--py37-plus, --add-import, 'from __future__ import annotations'] - exclude: ^testing/resources/python3_hooks_repo/ - repo: https://github.com/asottile/add-trailing-comma rev: v2.2.1 hooks: - id: add-trailing-comma args: [--py36-plus] -- repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.20.0 +- repo: https://github.com/asottile/pyupgrade + rev: v2.31.1 hooks: - - id: setup-cfg-fmt + - id: pyupgrade + args: [--py37-plus] +- repo: https://github.com/pre-commit/mirrors-autopep8 + rev: v1.6.0 + hooks: + - id: autopep8 +- repo: https://github.com/PyCQA/flake8 + rev: 4.0.1 + hooks: + - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.941 + rev: v0.942 hooks: - id: mypy additional_dependencies: [types-all] - exclude: ^testing/resources/ -- repo: meta - hooks: - - id: check-hooks-apply - - id: check-useless-excludes diff --git a/testing/resources/python3_hooks_repo/py3_hook.py b/testing/resources/python3_hooks_repo/py3_hook.py index 8c9cda4c..fd64ce8d 100644 --- a/testing/resources/python3_hooks_repo/py3_hook.py +++ b/testing/resources/python3_hooks_repo/py3_hook.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys diff --git a/testing/resources/python3_hooks_repo/setup.py b/testing/resources/python3_hooks_repo/setup.py index 9125dc1d..49e1e2cc 100644 --- a/testing/resources/python3_hooks_repo/setup.py +++ b/testing/resources/python3_hooks_repo/setup.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from setuptools import setup setup( From 3b9804062334d69582ff04299d22a8d2df60460a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 25 Mar 2022 14:31:33 -0400 Subject: [PATCH 062/416] fix pre-commit issues --- .pre-commit-config.yaml | 2 ++ testing/resources/python3_hooks_repo/py3_hook.py | 2 -- testing/resources/python3_hooks_repo/setup.py | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6f1fafd2..5525d71d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,7 @@ repos: rev: v3.0.1 hooks: - id: reorder-python-imports + exclude: ^testing/resources/python3_hooks_repo/ args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v2.2.1 @@ -41,3 +42,4 @@ repos: hooks: - id: mypy additional_dependencies: [types-all] + exclude: ^testing/resources/ diff --git a/testing/resources/python3_hooks_repo/py3_hook.py b/testing/resources/python3_hooks_repo/py3_hook.py index fd64ce8d..8c9cda4c 100644 --- a/testing/resources/python3_hooks_repo/py3_hook.py +++ b/testing/resources/python3_hooks_repo/py3_hook.py @@ -1,5 +1,3 @@ -from __future__ import annotations - import sys diff --git a/testing/resources/python3_hooks_repo/setup.py b/testing/resources/python3_hooks_repo/setup.py index 49e1e2cc..9125dc1d 100644 --- a/testing/resources/python3_hooks_repo/setup.py +++ b/testing/resources/python3_hooks_repo/setup.py @@ -1,5 +1,3 @@ -from __future__ import annotations - from setuptools import setup setup( From 2188c0fd2c4feefefe6ab7b2b45e8b4c4fa93acc Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 30 Mar 2022 10:38:05 -0400 Subject: [PATCH 063/416] include the configured value in the language_version / additional_dependencies error --- pre_commit/languages/helpers.py | 8 +++++--- tests/languages/helpers_test.py | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index dd219ffa..80808266 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -67,7 +67,8 @@ def environment_dir(d: str | None, language_version: str) -> str | None: def assert_version_default(binary: str, version: str) -> None: if version != C.DEFAULT: raise AssertionError( - f'For now, pre-commit requires system-installed {binary}', + f'for now, pre-commit requires system-installed {binary} -- ' + f'you selected `language_version: {version}`', ) @@ -77,8 +78,9 @@ def assert_no_additional_deps( ) -> None: if additional_deps: raise AssertionError( - f'For now, pre-commit does not support ' - f'additional_dependencies for {lang}', + f'for now, pre-commit does not support ' + f'additional_dependencies for {lang} -- ' + f'you selected `additional_dependencies: {additional_deps}`', ) diff --git a/tests/languages/helpers_test.py b/tests/languages/helpers_test.py index 49d81226..259cb97c 100644 --- a/tests/languages/helpers_test.py +++ b/tests/languages/helpers_test.py @@ -88,7 +88,9 @@ def test_assert_no_additional_deps(): helpers.assert_no_additional_deps('lang', ['hmmm']) msg, = excinfo.value.args assert msg == ( - 'For now, pre-commit does not support additional_dependencies for lang' + 'for now, pre-commit does not support additional_dependencies for ' + 'lang -- ' + "you selected `additional_dependencies: ['hmmm']`" ) From e8b46c1b1660ed5556b519ecd478ae829bd51d9c Mon Sep 17 00:00:00 2001 From: Matt Layman Date: Wed, 30 Mar 2022 01:08:52 -0400 Subject: [PATCH 064/416] Pick a tag if multiple tags exist on a SHA. Fixes #2311 --- pre_commit/commands/autoupdate.py | 3 +++ pre_commit/git.py | 15 +++++++++++++++ tests/commands/autoupdate_test.py | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 938c2246..d5352e5e 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -59,6 +59,9 @@ class RevInfo(NamedTuple): except CalledProcessError: cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD') rev = cmd_output(*cmd, cwd=tmp)[1].strip() + else: + if tags_only: + rev = git.get_best_candidate_tag(rev, tmp) frozen = None if freeze: diff --git a/pre_commit/git.py b/pre_commit/git.py index 853f4b0d..6fff8d2a 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -229,3 +229,18 @@ def check_for_cygwin_mismatch() -> None: f' - python {exe_type[is_cygwin_python]}\n' f' - git {exe_type[is_cygwin_git]}\n', ) + + +def get_best_candidate_tag(rev: str, git_repo: str) -> str: + """Get the best tag candidate. + + Multiple tags can exist on a SHA. Sometimes a moving tag is attached + to a version tag. Try to pick the tag that looks like a version. + """ + tags = cmd_output( + 'git', *NO_FS_MONITOR, 'tag', '--points-at', rev, cwd=git_repo, + )[1].splitlines() + for tag in tags: + if '.' in tag: + return tag + return rev diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index 3a142661..3806b0e4 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -103,6 +103,24 @@ def test_rev_info_update_tags_only_does_not_pick_tip(tagged): assert new_info.rev == 'v1.2.3' +def test_rev_info_update_tags_prefers_version_tag(tagged, out_of_date): + cmd_output('git', 'tag', 'latest', cwd=out_of_date.path) + config = make_config_from_repo(tagged.path, rev=tagged.original_rev) + info = RevInfo.from_config(config) + new_info = info.update(tags_only=True, freeze=False) + assert new_info.rev == 'v1.2.3' + + +def test_rev_info_update_tags_non_version_tag(out_of_date): + cmd_output('git', 'tag', 'latest', cwd=out_of_date.path) + config = make_config_from_repo( + out_of_date.path, rev=out_of_date.original_rev, + ) + info = RevInfo.from_config(config) + new_info = info.update(tags_only=True, freeze=False) + assert new_info.rev == 'latest' + + def test_rev_info_update_freeze_tag(tagged): git_commit(cwd=tagged.path) config = make_config_from_repo(tagged.path, rev=tagged.original_rev) From 9021fa15dd1925b59634d660c0e5d429cb757a52 Mon Sep 17 00:00:00 2001 From: Jamie Alessio Date: Thu, 31 Mar 2022 10:33:36 -0700 Subject: [PATCH 065/416] Update ruby-build to latest available --- pre_commit/resources/ruby-build.tar.gz | Bin 71151 -> 72271 bytes testing/make-archives | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index 01867bee6112203f21d1b808451070f6ad56f5c0..e248c57ce6fc23ae3ac0f6794ba02f4270da89c1 100644 GIT binary patch literal 72271 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

%kAV|zFXV$H~&A_&9@)_$mjo&AO8El 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 bysv_#Uaj6o5{mox^*>{=Yl9L42M+@PnQ!nP literal 71151 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

Ic>4rPYCPrkRQ0`qRDI8#|2${EyKj}()OD)= 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 dqR~-!>B7oc%SlAfkJ|m0_u1^C% Date: Tue, 22 Mar 2022 21:52:46 -0400 Subject: [PATCH 066/416] use Rscript path relative to $R_HOME/bin/... Co-authored-by: Lorenz Walthert --- pre_commit/languages/r.py | 6 +++++- tests/languages/r_test.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 9b32b2d7..c736b386 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -59,7 +59,11 @@ def _prefix_if_non_local_file_entry( def _rscript_exec() -> str: - return os.path.join(os.getenv('R_HOME', ''), 'Rscript') + r_home = os.environ.get('R_HOME') + if r_home is None: + return 'Rscript' + else: + return os.path.join(r_home, 'bin', 'Rscript') def _entry_validate(entry: Sequence[str]) -> None: diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index bc302a79..5bc63b27 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -4,6 +4,7 @@ import os.path import pytest +from pre_commit import envcontext from pre_commit.languages import r from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo @@ -129,3 +130,14 @@ def test_r_parsing_file_local(tempdir_factory, store): config=config, expect_path_prefix=False, ) + + +def test_rscript_exec_relative_to_r_home(): + expected = os.path.join('r_home_dir', 'bin', 'Rscript') + with envcontext.envcontext((('R_HOME', 'r_home_dir'),)): + assert r._rscript_exec() == expected + + +def test_path_rscript_exec_no_r_home_set(): + with envcontext.envcontext((('R_HOME', envcontext.UNSET),)): + assert r._rscript_exec() == 'Rscript' From ba132f02007f6d185a33a80c2d537f4d29335c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 11 Jul 2021 07:59:33 +0200 Subject: [PATCH 067/416] Split get_git_dir() into get_git_dir() and get_git_common_dir() This fixes the conflicted state check when using work trees. #1972 --- pre_commit/commands/install_uninstall.py | 2 +- pre_commit/git.py | 26 ++++++++++++++------ tests/git_test.py | 30 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index cb2aaa5b..b1fd8d49 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -36,7 +36,7 @@ def _hook_paths( hook_type: str, git_dir: str | None = None, ) -> tuple[str, str]: - git_dir = git_dir if git_dir is not None else git.get_git_dir() + git_dir = git_dir if git_dir is not None else git.get_git_common_dir() pth = os.path.join(git_dir, 'hooks', hook_type) return pth, f'{pth}.legacy' diff --git a/pre_commit/git.py b/pre_commit/git.py index 6fff8d2a..35392b34 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -57,13 +57,15 @@ def get_root() -> str: root = os.path.abspath( cmd_output('git', 'rev-parse', '--show-cdup')[1].strip(), ) - git_dir = os.path.abspath(get_git_dir()) + inside_git_dir = cmd_output( + 'git', 'rev-parse', '--is-inside-git-dir', + )[1].strip() except CalledProcessError: raise FatalError( 'git failed. Is it installed, and are you in a Git repository ' 'directory?', ) - if os.path.samefile(root, git_dir): + if inside_git_dir != 'false': raise FatalError( 'git toplevel unexpectedly empty! make sure you are not ' 'inside the `.git` directory of your repository.', @@ -72,15 +74,25 @@ def get_root() -> str: def get_git_dir(git_root: str = '.') -> str: - opts = ('--git-common-dir', '--git-dir') - _, out, _ = cmd_output('git', 'rev-parse', *opts, cwd=git_root) - for line, opt in zip(out.splitlines(), opts): - if line != opt: # pragma: no branch (git < 2.5) - return os.path.normpath(os.path.join(git_root, line)) + opt = '--git-dir' + _, out, _ = cmd_output('git', 'rev-parse', opt, cwd=git_root) + git_dir = out.strip() + if git_dir != opt: + return os.path.normpath(os.path.join(git_root, git_dir)) else: raise AssertionError('unreachable: no git dir') +def get_git_common_dir(git_root: str = '.') -> str: + opt = '--git-common-dir' + _, out, _ = cmd_output('git', 'rev-parse', opt, cwd=git_root) + git_common_dir = out.strip() + if git_common_dir != opt: + return os.path.normpath(os.path.join(git_root, git_common_dir)) + else: # pragma: no cover (git < 2.5) + return get_git_dir(git_root) + + def get_remote_url(git_root: str) -> str: _, out, _ = cmd_output('git', 'config', 'remote.origin.url', cwd=git_root) return out.strip() diff --git a/tests/git_test.py b/tests/git_test.py index d9e497c5..b9f524a1 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -21,6 +21,20 @@ def test_get_root_deeper(in_git_dir): assert os.path.normcase(git.get_root()) == expected +def test_get_root_in_git_sub_dir(in_git_dir): + expected = os.path.normcase(in_git_dir.strpath) + with pytest.raises(FatalError): + with in_git_dir.join('.git/objects').ensure_dir().as_cwd(): + assert os.path.normcase(git.get_root()) == expected + + +def test_get_root_not_in_working_dir(in_git_dir): + expected = os.path.normcase(in_git_dir.strpath) + with pytest.raises(FatalError): + with in_git_dir.join('..').ensure_dir().as_cwd(): + assert os.path.normcase(git.get_root()) == expected + + def test_in_exactly_dot_git(in_git_dir): with in_git_dir.join('.git').as_cwd(), pytest.raises(FatalError): git.get_root() @@ -40,6 +54,22 @@ def test_get_root_bare_worktree(tmpdir): assert git.get_root() == os.path.abspath('.') +def test_get_git_dir(tmpdir): + """Regression test for #1972""" + src = tmpdir.join('src').ensure_dir() + cmd_output('git', 'init', str(src)) + git_commit(cwd=str(src)) + + worktree = tmpdir.join('worktree').ensure_dir() + cmd_output('git', 'worktree', 'add', '../worktree', cwd=src) + + with worktree.as_cwd(): + assert git.get_git_dir() == src.ensure_dir( + '.git/worktrees/worktree', + ) + assert git.get_git_common_dir() == src.ensure_dir('.git') + + def test_get_root_worktree_in_git(tmpdir): src = tmpdir.join('src').ensure_dir() cmd_output('git', 'init', str(src)) From fd0177ae3ae5f94b36aafb54ab496f76fcead7b9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 2 Apr 2022 14:00:23 -0400 Subject: [PATCH 068/416] implement default_install_hook_types this implements a configurable fallback for the default value of `pre-commit install` --- pre_commit/clientlib.py | 6 +++ pre_commit/commands/init_templatedir.py | 3 +- pre_commit/commands/install_uninstall.py | 22 +++++++--- pre_commit/constants.py | 6 +++ pre_commit/main.py | 34 +++------------ tests/commands/install_uninstall_test.py | 54 +++++++++++++++++++++--- tests/main_test.py | 16 +------ 7 files changed, 86 insertions(+), 55 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 1fcce4ea..bf4e2e45 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -336,6 +336,11 @@ CONFIG_SCHEMA = cfgv.Map( 'Config', None, cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)), + cfgv.Optional( + 'default_install_hook_types', + cfgv.check_array(cfgv.check_one_of(C.HOOK_TYPES)), + ['pre-commit'], + ), cfgv.OptionalRecurse( 'default_language_version', DEFAULT_LANGUAGE_VERSION, {}, ), @@ -355,6 +360,7 @@ CONFIG_SCHEMA = cfgv.Map( cfgv.WarnAdditionalKeys( ( 'repos', + 'default_install_hook_types', 'default_language_version', 'default_stages', 'files', diff --git a/pre_commit/commands/init_templatedir.py b/pre_commit/commands/init_templatedir.py index 004e8ccf..08af6561 100644 --- a/pre_commit/commands/init_templatedir.py +++ b/pre_commit/commands/init_templatedir.py @@ -2,7 +2,6 @@ from __future__ import annotations import logging import os.path -from typing import Sequence from pre_commit.commands.install_uninstall import install from pre_commit.store import Store @@ -16,7 +15,7 @@ def init_templatedir( config_file: str, store: Store, directory: str, - hook_types: Sequence[str], + hook_types: list[str] | None, skip_on_missing_config: bool = True, ) -> int: install( diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index cb2aaa5b..c80e17e5 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -5,10 +5,10 @@ import os.path import shlex import shutil import sys -from typing import Sequence from pre_commit import git from pre_commit import output +from pre_commit.clientlib import InvalidConfigError from pre_commit.clientlib import load_config from pre_commit.repository import all_hooks from pre_commit.repository import install_hook_envs @@ -32,6 +32,18 @@ TEMPLATE_START = '# start templated\n' TEMPLATE_END = '# end templated\n' +def _hook_types(cfg_filename: str, hook_types: list[str] | None) -> list[str]: + if hook_types is not None: + return hook_types + else: + try: + cfg = load_config(cfg_filename) + except InvalidConfigError: + return ['pre-commit'] + else: + return cfg['default_install_hook_types'] + + def _hook_paths( hook_type: str, git_dir: str | None = None, @@ -103,7 +115,7 @@ def _install_hook_script( def install( config_file: str, store: Store, - hook_types: Sequence[str], + hook_types: list[str] | None, overwrite: bool = False, hooks: bool = False, skip_on_missing_config: bool = False, @@ -116,7 +128,7 @@ def install( ) return 1 - for hook_type in hook_types: + for hook_type in _hook_types(config_file, hook_types): _install_hook_script( config_file, hook_type, overwrite=overwrite, @@ -150,7 +162,7 @@ def _uninstall_hook_script(hook_type: str) -> None: output.write_line(f'Restored previous hooks to {hook_path}') -def uninstall(hook_types: Sequence[str]) -> int: - for hook_type in hook_types: +def uninstall(config_file: str, hook_types: list[str] | None) -> int: + for hook_type in _hook_types(config_file, hook_types): _uninstall_hook_script(hook_type) return 0 diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 40127a05..5bc4ae98 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -24,4 +24,10 @@ STAGES = ( 'post-rewrite', ) +HOOK_TYPES = ( + 'pre-commit', 'pre-merge-commit', 'pre-push', 'prepare-commit-msg', + 'commit-msg', 'post-commit', 'post-checkout', 'post-merge', + 'post-rewrite', +) + DEFAULT = 'default' diff --git a/pre_commit/main.py b/pre_commit/main.py index f3c55188..645e97f7 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -4,7 +4,6 @@ import argparse import logging import os import sys -from typing import Any from typing import Sequence import pre_commit.constants as C @@ -46,34 +45,10 @@ def _add_config_option(parser: argparse.ArgumentParser) -> None: ) -class AppendReplaceDefault(argparse.Action): - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.appended = False - - def __call__( - self, - parser: argparse.ArgumentParser, - namespace: argparse.Namespace, - values: str | Sequence[str] | None, - option_string: str | None = None, - ) -> None: - if not self.appended: - setattr(namespace, self.dest, []) - self.appended = True - getattr(namespace, self.dest).append(values) - - def _add_hook_type_option(parser: argparse.ArgumentParser) -> None: parser.add_argument( - '-t', '--hook-type', choices=( - 'pre-commit', 'pre-merge-commit', 'pre-push', 'prepare-commit-msg', - 'commit-msg', 'post-commit', 'post-checkout', 'post-merge', - 'post-rewrite', - ), - action=AppendReplaceDefault, - default=['pre-commit'], - dest='hook_types', + '-t', '--hook-type', + choices=C.HOOK_TYPES, action='append', dest='hook_types', ) @@ -399,7 +374,10 @@ def main(argv: Sequence[str] | None = None) -> int: elif args.command == 'try-repo': return try_repo(args) elif args.command == 'uninstall': - return uninstall(hook_types=args.hook_types) + return uninstall( + config_file=args.config, + hook_types=args.hook_types, + ) else: raise NotImplementedError( f'Command {args.command} not implemented.', diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 703ba03b..ae668ac9 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -7,6 +7,7 @@ import re_assert import pre_commit.constants as C from pre_commit import git +from pre_commit.commands.install_uninstall import _hook_types from pre_commit.commands.install_uninstall import CURRENT_HASH from pre_commit.commands.install_uninstall import install from pre_commit.commands.install_uninstall import install_hooks @@ -27,6 +28,36 @@ from testing.util import cwd from testing.util import git_commit +def test_hook_types_explicitly_listed(): + assert _hook_types(os.devnull, ['pre-push']) == ['pre-push'] + + +def test_hook_types_default_value_when_not_specified(): + assert _hook_types(os.devnull, None) == ['pre-commit'] + + +def test_hook_types_configured(tmpdir): + cfg = tmpdir.join('t.cfg') + cfg.write('default_install_hook_types: [pre-push]\nrepos: []\n') + + assert _hook_types(str(cfg), None) == ['pre-push'] + + +def test_hook_types_configured_nonsense(tmpdir): + cfg = tmpdir.join('t.cfg') + cfg.write('default_install_hook_types: []\nrepos: []\n') + + # hopefully the user doesn't do this, but the code allows it! + assert _hook_types(str(cfg), None) == [] + + +def test_hook_types_configuration_has_error(tmpdir): + cfg = tmpdir.join('t.cfg') + cfg.write('[') + + assert _hook_types(str(cfg), None) == ['pre-commit'] + + def test_is_not_script(): assert is_our_script('setup.py') is False @@ -61,7 +92,7 @@ def test_install_multiple_hooks_at_once(in_git_dir, store): install(C.CONFIG_FILE, store, hook_types=['pre-commit', 'pre-push']) assert in_git_dir.join('.git/hooks/pre-commit').exists() assert in_git_dir.join('.git/hooks/pre-push').exists() - uninstall(hook_types=['pre-commit', 'pre-push']) + uninstall(C.CONFIG_FILE, hook_types=['pre-commit', 'pre-push']) assert not in_git_dir.join('.git/hooks/pre-commit').exists() assert not in_git_dir.join('.git/hooks/pre-push').exists() @@ -79,14 +110,14 @@ def test_install_hooks_dead_symlink(in_git_dir, store): def test_uninstall_does_not_blow_up_when_not_there(in_git_dir): - assert uninstall(hook_types=['pre-commit']) == 0 + assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0 def test_uninstall(in_git_dir, store): assert not in_git_dir.join('.git/hooks/pre-commit').exists() install(C.CONFIG_FILE, store, hook_types=['pre-commit']) assert in_git_dir.join('.git/hooks/pre-commit').exists() - uninstall(hook_types=['pre-commit']) + uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) assert not in_git_dir.join('.git/hooks/pre-commit').exists() @@ -416,7 +447,7 @@ def test_uninstall_restores_legacy_hooks(tempdir_factory, store): # Now install and uninstall pre-commit assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0 - assert uninstall(hook_types=['pre-commit']) == 0 + assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0 # Make sure we installed the "old" hook correctly ret, output = _get_commit_output(tempdir_factory, touch_file='baz') @@ -451,7 +482,7 @@ def test_uninstall_doesnt_remove_not_our_hooks(in_git_dir): pre_commit.write('#!/usr/bin/env bash\necho 1\n') make_executable(pre_commit.strpath) - assert uninstall(hook_types=['pre-commit']) == 0 + assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0 assert pre_commit.exists() @@ -1007,3 +1038,16 @@ def test_install_temporarily_allow_mising_config(tempdir_factory, store): 'Skipping `pre-commit`.' ) assert expected in output + + +def test_install_uninstall_default_hook_types(in_git_dir, store): + cfg_src = 'default_install_hook_types: [pre-commit, pre-push]\nrepos: []\n' + in_git_dir.join(C.CONFIG_FILE).write(cfg_src) + + assert not install(C.CONFIG_FILE, store, hook_types=None) + assert os.access(in_git_dir.join('.git/hooks/pre-commit').strpath, os.X_OK) + assert os.access(in_git_dir.join('.git/hooks/pre-push').strpath, os.X_OK) + + assert not uninstall(C.CONFIG_FILE, hook_types=None) + assert not in_git_dir.join('.git/hooks/pre-commit').exists() + assert not in_git_dir.join('.git/hooks/pre-push').exists() diff --git a/tests/main_test.py b/tests/main_test.py index 64b26a00..a645300a 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -14,20 +14,6 @@ from testing.auto_namedtuple import auto_namedtuple from testing.util import cwd -@pytest.mark.parametrize( - ('argv', 'expected'), - ( - ((), ['f']), - (('--f', 'x'), ['x']), - (('--f', 'x', '--f', 'y'), ['x', 'y']), - ), -) -def test_append_replace_default(argv, expected): - parser = argparse.ArgumentParser() - parser.add_argument('--f', action=main.AppendReplaceDefault, default=['f']) - assert parser.parse_args(argv).f == expected - - def _args(**kwargs): kwargs.setdefault('command', 'help') kwargs.setdefault('config', C.CONFIG_FILE) @@ -172,7 +158,7 @@ def test_init_templatedir(mock_store_dir): assert patch.call_count == 1 assert 'tdir' in patch.call_args[0] - assert patch.call_args[1]['hook_types'] == ['pre-commit'] + assert patch.call_args[1]['hook_types'] is None assert patch.call_args[1]['skip_on_missing_config'] is True From a138c85e64cb9ba7703565650504cff0bb339505 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 2 Apr 2022 16:20:16 -0400 Subject: [PATCH 069/416] move patch discarding inside `try` for staged_files_only there's a rare race outlined in #2287 --- pre_commit/staged_files_only.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index 7e75080d..83d8a03e 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -66,9 +66,9 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: # prevent recursive post-checkout hooks (#1418) no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1') - cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env) try: + cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env) yield finally: # Try to apply the patch we saved From c5a39ae77e1aff1df32034b27a3a900473698d46 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 2 Apr 2022 19:36:45 -0400 Subject: [PATCH 070/416] v2.18.0 --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cccc6d..e5991722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,46 @@ +2.18.0 - 2022-04-02 +=================== + +### Features +- Keep `GIT_HTTP_PROXY_AUTHMETHOD` in git environ. + - #2272 PR by @VincentBerthier. + - #2271 issue by @VincentBerthier. +- Support both `cs` and `coursier` executables for coursier hooks. + - #2293 PR by @Holzhaus. +- Include more information in errors for `language_version` / + `additional_dependencies` for languages which do not support them. + - #2315 PR by @asottile. +- Have autoupdate preferentially pick tags which look like versions when + there are multiple equivalent tags. + - #2312 PR by @mblayman. + - #2311 issue by @mblayman. +- Upgrade `ruby-build`. + - #2319 PR by @jalessio. +- Add top level `default_install_hook_types` which will be installed when + `--hook-types` is not specified in `pre-commit install`. + - #2322 PR by @asottile. + +### Fixes +- Fix typo in help message for `--from-ref` and `--to-ref`. + - #2266 PR by @leetrout. +- Prioritize binary builds for R dependencies. + - #2277 PR by @lorenzwalthert. +- Fix handling of git worktrees. + - #2252 PR by @daschuer. +- Fix handling of `$R_HOME` for R hooks. + - #2301 PR by @jeff-m-sullivan. + - #2300 issue by @jeff-m-sullivan. +- Fix a rare race condition in change stashing. + - #2323 PR by @asottile. + - #2287 issue by @ian-h-chamberlain. + +### Updating +- Remove python3.6 support. Note that pre-commit still supports running hooks + written in older versions, but pre-commit itself requires python 3.7+. + - #2215 PR by @asottile. +- pre-commit has migrated from the `master` branch to `main`. + - #2302 PR by @asottile. + 2.17.0 - 2022-01-18 =================== diff --git a/setup.cfg b/setup.cfg index d712a3f3..92b15459 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.17.0 +version = 2.18.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 1722448c3b26abdeb80f403ebe5f3171249e655f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 2 Apr 2022 20:26:03 -0400 Subject: [PATCH 071/416] fix python 2.7 `repo: local` hooks --- .pre-commit-config.yaml | 2 +- pre_commit/resources/empty_template_setup.py | 2 -- .../python3_hooks_repo/.pre-commit-hooks.yaml | 1 - tests/repository_test.py | 21 ++++++++++++------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5525d71d..1b93cff5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: rev: v3.0.1 hooks: - id: reorder-python-imports - exclude: ^testing/resources/python3_hooks_repo/ + exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v2.2.1 diff --git a/pre_commit/resources/empty_template_setup.py b/pre_commit/resources/empty_template_setup.py index 870d0fba..ef05eef8 100644 --- a/pre_commit/resources/empty_template_setup.py +++ b/pre_commit/resources/empty_template_setup.py @@ -1,5 +1,3 @@ -from __future__ import annotations - from setuptools import setup diff --git a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml index 2c237009..964cf836 100644 --- a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml +++ b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml @@ -2,5 +2,4 @@ name: Python 3 Hook entry: python3-hook language: python - language_version: python3 files: \.py$ diff --git a/tests/repository_test.py b/tests/repository_test.py index 01373147..cef68871 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -2,7 +2,6 @@ from __future__ import annotations import os.path import shutil -import sys from typing import Any from unittest import mock @@ -876,7 +875,7 @@ def test_tags_on_repositories(in_tmpdir, tempdir_factory, store): @pytest.fixture def local_python_config(): # Make a "local" hooks repo that just installs our other hooks repo - repo_path = get_resource_path('python_hooks_repo') + repo_path = get_resource_path('python3_hooks_repo') manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE)) hooks = [ dict(hook, additional_dependencies=[repo_path]) for hook in manifest @@ -884,17 +883,23 @@ def local_python_config(): return {'repo': 'local', 'hooks': hooks} -@pytest.mark.xfail( # pragma: win32 no cover - sys.platform == 'win32', - reason='microsoft/azure-pipelines-image-generation#989', -) def test_local_python_repo(store, local_python_config): - hook = _get_hook(local_python_config, store, 'foo') + hook = _get_hook(local_python_config, store, 'python3-hook') # language_version should have been adjusted to the interpreter version assert hook.language_version != C.DEFAULT ret, out = _hook_run(hook, ('filename',), color=False) assert ret == 0 - assert _norm_out(out) == b"['filename']\nHello World\n" + assert _norm_out(out) == b"3\n['filename']\nHello World\n" + + +def test_local_python_repo_python2(store, local_python_config): + local_python_config['hooks'][0]['language_version'] = 'python2' + hook = _get_hook(local_python_config, store, 'python3-hook') + # language_version should have been adjusted to the interpreter version + assert hook.language_version != C.DEFAULT + ret, out = _hook_run(hook, ('filename',), color=False) + assert ret == 0 + assert _norm_out(out) == b"2\n['filename']\nHello World\n" def test_default_language_version(store, local_python_config): From 0276e25f713ddfd66482f358d238186ca47a6eb4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 2 Apr 2022 21:32:54 -0400 Subject: [PATCH 072/416] v2.18.1 --- CHANGELOG.md | 7 +++++++ setup.cfg | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5991722..cd31c4b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +2.18.1 - 2022-04-02 +=================== + +### Fixes +- Fix regression for `repo: local` hooks running `python<3.7` + - #2324 PR by @asottile. + 2.18.0 - 2022-04-02 =================== diff --git a/setup.cfg b/setup.cfg index 92b15459..ca92af3e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.18.0 +version = 2.18.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From c8ce94b40ec7280517ed46b7808e1612f9ee5c40 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 20:00:42 +0000 Subject: [PATCH 073/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v1.20.0 → v1.20.1](https://github.com/asottile/setup-cfg-fmt/compare/v1.20.0...v1.20.1) - [github.com/asottile/add-trailing-comma: v2.2.1 → v2.2.2](https://github.com/asottile/add-trailing-comma/compare/v2.2.1...v2.2.2) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b93cff5..9fff994a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.20.0 + rev: v1.20.1 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports @@ -20,7 +20,7 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.2.1 + rev: v2.2.2 hooks: - id: add-trailing-comma args: [--py36-plus] From 9b3df4b90e287ae99658f684dd489eea3d0defd9 Mon Sep 17 00:00:00 2001 From: Walluce Pinkham Date: Wed, 6 Apr 2022 10:19:21 +0100 Subject: [PATCH 074/416] Handling multiple outputs from dotnet pack --- pre_commit/languages/dotnet.py | 27 ++++++++---------- .../.pre-commit-hooks.yaml | 12 ++++++++ .../dotnet_hooks_combo_repo.sln | 28 +++++++++++++++++++ .../dotnet_hooks_combo_repo/proj1/Program.cs | 12 ++++++++ .../proj1/proj1.csproj | 12 ++++++++ .../dotnet_hooks_combo_repo/proj2/Program.cs | 12 ++++++++ .../proj2/proj2.csproj | 12 ++++++++ tests/repository_test.py | 1 + 8 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml create mode 100644 testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln create mode 100644 testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs create mode 100644 testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj create mode 100644 testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs create mode 100644 testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index a16e7f07..9323f407 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -59,22 +59,19 @@ def install_environment( # Determine tool from the packaged file ..nupkg build_outputs = os.listdir(os.path.join(prefix.prefix_dir, build_dir)) - if len(build_outputs) != 1: - raise NotImplementedError( - f"Can't handle multiple build outputs. Got {build_outputs}", - ) - tool_name = build_outputs[0].split('.')[0] + for output in build_outputs: + tool_name = output.split('.')[0] - # Install to bin dir - helpers.run_setup_cmd( - prefix, - ( - 'dotnet', 'tool', 'install', - '--tool-path', os.path.join(envdir, BIN_DIR), - '--add-source', build_dir, - tool_name, - ), - ) + # Install to bin dir + helpers.run_setup_cmd( + prefix, + ( + 'dotnet', 'tool', 'install', + '--tool-path', os.path.join(envdir, BIN_DIR), + '--add-source', build_dir, + tool_name, + ), + ) # Clean the git dir, ignoring the environment dir clean_cmd = ('git', 'clean', '-ffxd', '-e', f'{ENVIRONMENT_DIR}-*') diff --git a/testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml b/testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml new file mode 100644 index 00000000..f221854a --- /dev/null +++ b/testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml @@ -0,0 +1,12 @@ +- id: dotnet-example-hook + name: Test Project 1 + description: Test Project 1 + entry: proj1 + language: dotnet + stages: [commit] +- id: proj2 + name: Test Project 2 + description: Test Project 2 + entry: proj2 + language: dotnet + stages: [commit] diff --git a/testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln b/testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln new file mode 100644 index 00000000..edb0fcbc --- /dev/null +++ b/testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proj1", "proj1\proj1.csproj", "{38A939C3-DEA4-47D7-9B75-0418C4249662}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proj2", "proj2\proj2.csproj", "{4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Release|Any CPU.Build.0 = Release|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs b/testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs new file mode 100644 index 00000000..03876f5c --- /dev/null +++ b/testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace proj1 +{ + class Program + { + static void Main(string[] args) + { + Console.Write("Hello from dotnet!\n"); + } + } +} diff --git a/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj b/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj new file mode 100644 index 00000000..4f714d33 --- /dev/null +++ b/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj @@ -0,0 +1,12 @@ + + + + Exe + net5.0 + + true + proj1 + ./nupkg + + + diff --git a/testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs b/testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs new file mode 100644 index 00000000..47a99a35 --- /dev/null +++ b/testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace proj2 +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj b/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj new file mode 100644 index 00000000..da451f7c --- /dev/null +++ b/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj @@ -0,0 +1,12 @@ + + + + Exe + net5.0 + + true + proj2 + ./nupkg + + + diff --git a/tests/repository_test.py b/tests/repository_test.py index cef68871..5c7909c5 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1042,6 +1042,7 @@ def test_local_perl_additional_dependencies(store): ( 'dotnet_hooks_csproj_repo', 'dotnet_hooks_sln_repo', + 'dotnet_hooks_combo_repo', ), ) def test_dotnet_hook(tempdir_factory, store, repo): From e3ae0664bb44445e49d16bdc0358f003cb78ed3e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 20:54:45 +0000 Subject: [PATCH 075/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.2.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.2.0) - [github.com/asottile/pyupgrade: v2.31.1 → v2.32.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.32.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9fff994a..887772b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.2.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.31.1 + rev: v2.32.0 hooks: - id: pyupgrade args: [--py37-plus] From b952c99898bacea651b4e39c8be57d987f64c094 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 13 Apr 2022 17:52:55 -0400 Subject: [PATCH 076/416] fix tests for golang 1.18 --- testing/resources/golang_hooks_repo/go.mod | 4 ++++ testing/resources/golang_hooks_repo/go.sum | 2 ++ tests/repository_test.py | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 testing/resources/golang_hooks_repo/go.sum diff --git a/testing/resources/golang_hooks_repo/go.mod b/testing/resources/golang_hooks_repo/go.mod index 523bfc9f..f37d4b67 100644 --- a/testing/resources/golang_hooks_repo/go.mod +++ b/testing/resources/golang_hooks_repo/go.mod @@ -1 +1,5 @@ module golang-hello-world + +go 1.18 + +require github.com/BurntSushi/toml v1.1.0 diff --git a/testing/resources/golang_hooks_repo/go.sum b/testing/resources/golang_hooks_repo/go.sum new file mode 100644 index 00000000..ec0c385a --- /dev/null +++ b/testing/resources/golang_hooks_repo/go.sum @@ -0,0 +1,2 @@ +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= diff --git a/tests/repository_test.py b/tests/repository_test.py index 5c7909c5..cfa69c9f 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -667,7 +667,7 @@ def test_additional_golang_dependencies_installed( path = make_repo(tempdir_factory, 'golang_hooks_repo') config = make_config_from_repo(path) # A small go package - deps = ['golang.org/x/example/hello'] + deps = ['golang.org/x/example/hello@latest'] config['hooks'][0]['additional_dependencies'] = deps hook = _get_hook(config, store, 'golang-hook') binaries = os.listdir( @@ -688,7 +688,7 @@ def test_local_golang_additional_dependencies(store): 'name': 'hello', 'entry': 'hello', 'language': 'golang', - 'additional_dependencies': ['golang.org/x/example/hello'], + 'additional_dependencies': ['golang.org/x/example/hello@latest'], }], } hook = _get_hook(config, store, 'hello') From feb0d342130c94908a8ecc63f919ee023c9c18af Mon Sep 17 00:00:00 2001 From: Wade Carpenter Date: Thu, 14 Apr 2022 14:27:46 -0700 Subject: [PATCH 077/416] pre-push: fix stdin line splitting when has whitespace From the `pre-push.sample` file: > Information about the commits which are being pushed is supplied as > lines to the standard input in the form: > > When `` is not simply a branch name, but a more general ref (see git-rev-parse(1)), it could contain whitespace, and that breaks the split() call that expected only 3 spaces in the line. Changed to use `rsplit(maxsplit=3)` since only the is likely to have embedded whitespace. Added a new test case for the same. --- pre_commit/commands/hook_impl.py | 3 ++- tests/commands/hook_impl_test.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index 18e5e9f5..f315c04d 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -114,7 +114,8 @@ def _pre_push_ns( remote_url = args[1] for line in stdin.decode().splitlines(): - local_branch, local_sha, remote_branch, remote_sha = line.split() + parts = line.rsplit(maxsplit=3) + local_branch, local_sha, remote_branch, remote_sha = parts if local_sha == Z40: continue elif remote_sha != Z40 and _rev_exists(remote_sha): diff --git a/tests/commands/hook_impl_test.py b/tests/commands/hook_impl_test.py index b0159f8e..3e20874e 100644 --- a/tests/commands/hook_impl_test.py +++ b/tests/commands/hook_impl_test.py @@ -242,6 +242,18 @@ def test_run_ns_pre_push_new_branch_existing_rev(push_example): assert ns is None +def test_run_ns_pre_push_ref_with_whitespace(push_example): + src, src_head, clone, _ = push_example + + with cwd(clone): + args = ('origin', src) + line = f'HEAD^{{/ }} {src_head} refs/heads/b2 {hook_impl.Z40}\n' + stdin = line.encode() + ns = hook_impl._run_ns('pre-push', False, args, stdin) + + assert ns is None + + def test_pushing_orphan_branch(push_example): src, src_head, clone, _ = push_example From 07554e952539e9a85e6e8c33987108911d49fb15 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 16 Apr 2022 14:59:46 -0400 Subject: [PATCH 078/416] add additional info to healthy-after-install check --- CONTRIBUTING.md | 7 ++-- pre_commit/languages/all.py | 40 ++++++++++----------- pre_commit/languages/conda.py | 2 +- pre_commit/languages/coursier.py | 2 +- pre_commit/languages/dart.py | 2 +- pre_commit/languages/docker.py | 2 +- pre_commit/languages/docker_image.py | 2 +- pre_commit/languages/dotnet.py | 2 +- pre_commit/languages/fail.py | 2 +- pre_commit/languages/golang.py | 2 +- pre_commit/languages/helpers.py | 4 +-- pre_commit/languages/lua.py | 2 +- pre_commit/languages/node.py | 7 ++-- pre_commit/languages/perl.py | 2 +- pre_commit/languages/pygrep.py | 2 +- pre_commit/languages/python.py | 35 +++++++++++++----- pre_commit/languages/r.py | 2 +- pre_commit/languages/ruby.py | 2 +- pre_commit/languages/rust.py | 2 +- pre_commit/languages/script.py | 2 +- pre_commit/languages/swift.py | 2 +- pre_commit/languages/system.py | 2 +- pre_commit/repository.py | 10 +++--- testing/gen-languages-all | 12 +++---- tests/languages/helpers_test.py | 4 +-- tests/languages/node_test.py | 9 ++--- tests/languages/python_test.py | 54 ++++++++++++++++++++++------ 27 files changed, 137 insertions(+), 79 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index adce08f9..fa1678ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,15 +117,16 @@ get_default_version = helpers.basic_default_version `python` is currently the only language which implements this api -#### `healthy` +#### `health_check` This is used to check whether the installed environment is considered healthy. -This function should return `True` or `False`. +This function should return a detailed message if unhealthy or `None` if +healthy. You generally don't need to implement this on a first pass and can just use: ```python -healthy = helpers.basic_healthy +health_check = helpers.basic_healthy_check ``` `python` is currently the only language which implements this api, for python diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index cfcbf686..cfd42ce2 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -34,7 +34,7 @@ class Language(NamedTuple): # return a value to replace `'default` for `language_version` get_default_version: Callable[[], str] # return whether the environment is healthy (or should be rebuilt) - healthy: Callable[[Prefix, str], bool] + health_check: Callable[[Prefix, str], str | None] # install a repository for the given language and language_version install_environment: Callable[[Prefix, str, Sequence[str]], None] # execute a hook and return the exit code and output @@ -44,25 +44,25 @@ class Language(NamedTuple): # TODO: back to modules + Protocol: https://github.com/python/mypy/issues/5018 languages = { # BEGIN GENERATED (testing/gen-languages-all) - 'conda': Language(name='conda', ENVIRONMENT_DIR=conda.ENVIRONMENT_DIR, get_default_version=conda.get_default_version, healthy=conda.healthy, install_environment=conda.install_environment, run_hook=conda.run_hook), # noqa: E501 - 'coursier': Language(name='coursier', ENVIRONMENT_DIR=coursier.ENVIRONMENT_DIR, get_default_version=coursier.get_default_version, healthy=coursier.healthy, install_environment=coursier.install_environment, run_hook=coursier.run_hook), # noqa: E501 - 'dart': Language(name='dart', ENVIRONMENT_DIR=dart.ENVIRONMENT_DIR, get_default_version=dart.get_default_version, healthy=dart.healthy, install_environment=dart.install_environment, run_hook=dart.run_hook), # noqa: E501 - 'docker': Language(name='docker', ENVIRONMENT_DIR=docker.ENVIRONMENT_DIR, get_default_version=docker.get_default_version, healthy=docker.healthy, install_environment=docker.install_environment, run_hook=docker.run_hook), # noqa: E501 - 'docker_image': Language(name='docker_image', ENVIRONMENT_DIR=docker_image.ENVIRONMENT_DIR, get_default_version=docker_image.get_default_version, healthy=docker_image.healthy, install_environment=docker_image.install_environment, run_hook=docker_image.run_hook), # noqa: E501 - 'dotnet': Language(name='dotnet', ENVIRONMENT_DIR=dotnet.ENVIRONMENT_DIR, get_default_version=dotnet.get_default_version, healthy=dotnet.healthy, install_environment=dotnet.install_environment, run_hook=dotnet.run_hook), # noqa: E501 - 'fail': Language(name='fail', ENVIRONMENT_DIR=fail.ENVIRONMENT_DIR, get_default_version=fail.get_default_version, healthy=fail.healthy, install_environment=fail.install_environment, run_hook=fail.run_hook), # noqa: E501 - 'golang': Language(name='golang', ENVIRONMENT_DIR=golang.ENVIRONMENT_DIR, get_default_version=golang.get_default_version, healthy=golang.healthy, install_environment=golang.install_environment, run_hook=golang.run_hook), # noqa: E501 - 'lua': Language(name='lua', ENVIRONMENT_DIR=lua.ENVIRONMENT_DIR, get_default_version=lua.get_default_version, healthy=lua.healthy, install_environment=lua.install_environment, run_hook=lua.run_hook), # noqa: E501 - 'node': Language(name='node', ENVIRONMENT_DIR=node.ENVIRONMENT_DIR, get_default_version=node.get_default_version, healthy=node.healthy, install_environment=node.install_environment, run_hook=node.run_hook), # noqa: E501 - 'perl': Language(name='perl', ENVIRONMENT_DIR=perl.ENVIRONMENT_DIR, get_default_version=perl.get_default_version, healthy=perl.healthy, install_environment=perl.install_environment, run_hook=perl.run_hook), # noqa: E501 - 'pygrep': Language(name='pygrep', ENVIRONMENT_DIR=pygrep.ENVIRONMENT_DIR, get_default_version=pygrep.get_default_version, healthy=pygrep.healthy, install_environment=pygrep.install_environment, run_hook=pygrep.run_hook), # noqa: E501 - 'python': Language(name='python', ENVIRONMENT_DIR=python.ENVIRONMENT_DIR, get_default_version=python.get_default_version, healthy=python.healthy, install_environment=python.install_environment, run_hook=python.run_hook), # noqa: E501 - 'r': Language(name='r', ENVIRONMENT_DIR=r.ENVIRONMENT_DIR, get_default_version=r.get_default_version, healthy=r.healthy, install_environment=r.install_environment, run_hook=r.run_hook), # noqa: E501 - 'ruby': Language(name='ruby', ENVIRONMENT_DIR=ruby.ENVIRONMENT_DIR, get_default_version=ruby.get_default_version, healthy=ruby.healthy, install_environment=ruby.install_environment, run_hook=ruby.run_hook), # noqa: E501 - 'rust': Language(name='rust', ENVIRONMENT_DIR=rust.ENVIRONMENT_DIR, get_default_version=rust.get_default_version, healthy=rust.healthy, install_environment=rust.install_environment, run_hook=rust.run_hook), # noqa: E501 - 'script': Language(name='script', ENVIRONMENT_DIR=script.ENVIRONMENT_DIR, get_default_version=script.get_default_version, healthy=script.healthy, install_environment=script.install_environment, run_hook=script.run_hook), # noqa: E501 - 'swift': Language(name='swift', ENVIRONMENT_DIR=swift.ENVIRONMENT_DIR, get_default_version=swift.get_default_version, healthy=swift.healthy, install_environment=swift.install_environment, run_hook=swift.run_hook), # noqa: E501 - 'system': Language(name='system', ENVIRONMENT_DIR=system.ENVIRONMENT_DIR, get_default_version=system.get_default_version, healthy=system.healthy, install_environment=system.install_environment, run_hook=system.run_hook), # noqa: E501 + 'conda': Language(name='conda', ENVIRONMENT_DIR=conda.ENVIRONMENT_DIR, get_default_version=conda.get_default_version, health_check=conda.health_check, install_environment=conda.install_environment, run_hook=conda.run_hook), # noqa: E501 + 'coursier': Language(name='coursier', ENVIRONMENT_DIR=coursier.ENVIRONMENT_DIR, get_default_version=coursier.get_default_version, health_check=coursier.health_check, install_environment=coursier.install_environment, run_hook=coursier.run_hook), # noqa: E501 + 'dart': Language(name='dart', ENVIRONMENT_DIR=dart.ENVIRONMENT_DIR, get_default_version=dart.get_default_version, health_check=dart.health_check, install_environment=dart.install_environment, run_hook=dart.run_hook), # noqa: E501 + 'docker': Language(name='docker', ENVIRONMENT_DIR=docker.ENVIRONMENT_DIR, get_default_version=docker.get_default_version, health_check=docker.health_check, install_environment=docker.install_environment, run_hook=docker.run_hook), # noqa: E501 + 'docker_image': Language(name='docker_image', ENVIRONMENT_DIR=docker_image.ENVIRONMENT_DIR, get_default_version=docker_image.get_default_version, health_check=docker_image.health_check, install_environment=docker_image.install_environment, run_hook=docker_image.run_hook), # noqa: E501 + 'dotnet': Language(name='dotnet', ENVIRONMENT_DIR=dotnet.ENVIRONMENT_DIR, get_default_version=dotnet.get_default_version, health_check=dotnet.health_check, install_environment=dotnet.install_environment, run_hook=dotnet.run_hook), # noqa: E501 + 'fail': Language(name='fail', ENVIRONMENT_DIR=fail.ENVIRONMENT_DIR, get_default_version=fail.get_default_version, health_check=fail.health_check, install_environment=fail.install_environment, run_hook=fail.run_hook), # noqa: E501 + 'golang': Language(name='golang', ENVIRONMENT_DIR=golang.ENVIRONMENT_DIR, get_default_version=golang.get_default_version, health_check=golang.health_check, install_environment=golang.install_environment, run_hook=golang.run_hook), # noqa: E501 + 'lua': Language(name='lua', ENVIRONMENT_DIR=lua.ENVIRONMENT_DIR, get_default_version=lua.get_default_version, health_check=lua.health_check, install_environment=lua.install_environment, run_hook=lua.run_hook), # noqa: E501 + 'node': Language(name='node', ENVIRONMENT_DIR=node.ENVIRONMENT_DIR, get_default_version=node.get_default_version, health_check=node.health_check, install_environment=node.install_environment, run_hook=node.run_hook), # noqa: E501 + 'perl': Language(name='perl', ENVIRONMENT_DIR=perl.ENVIRONMENT_DIR, get_default_version=perl.get_default_version, health_check=perl.health_check, install_environment=perl.install_environment, run_hook=perl.run_hook), # noqa: E501 + 'pygrep': Language(name='pygrep', ENVIRONMENT_DIR=pygrep.ENVIRONMENT_DIR, get_default_version=pygrep.get_default_version, health_check=pygrep.health_check, install_environment=pygrep.install_environment, run_hook=pygrep.run_hook), # noqa: E501 + 'python': Language(name='python', ENVIRONMENT_DIR=python.ENVIRONMENT_DIR, get_default_version=python.get_default_version, health_check=python.health_check, install_environment=python.install_environment, run_hook=python.run_hook), # noqa: E501 + 'r': Language(name='r', ENVIRONMENT_DIR=r.ENVIRONMENT_DIR, get_default_version=r.get_default_version, health_check=r.health_check, install_environment=r.install_environment, run_hook=r.run_hook), # noqa: E501 + 'ruby': Language(name='ruby', ENVIRONMENT_DIR=ruby.ENVIRONMENT_DIR, get_default_version=ruby.get_default_version, health_check=ruby.health_check, install_environment=ruby.install_environment, run_hook=ruby.run_hook), # noqa: E501 + 'rust': Language(name='rust', ENVIRONMENT_DIR=rust.ENVIRONMENT_DIR, get_default_version=rust.get_default_version, health_check=rust.health_check, install_environment=rust.install_environment, run_hook=rust.run_hook), # noqa: E501 + 'script': Language(name='script', ENVIRONMENT_DIR=script.ENVIRONMENT_DIR, get_default_version=script.get_default_version, health_check=script.health_check, install_environment=script.install_environment, run_hook=script.run_hook), # noqa: E501 + 'swift': Language(name='swift', ENVIRONMENT_DIR=swift.ENVIRONMENT_DIR, get_default_version=swift.get_default_version, health_check=swift.health_check, install_environment=swift.install_environment, run_hook=swift.run_hook), # noqa: E501 + 'system': Language(name='system', ENVIRONMENT_DIR=system.ENVIRONMENT_DIR, get_default_version=system.get_default_version, health_check=system.health_check, install_environment=system.install_environment, run_hook=system.run_hook), # noqa: E501 # END GENERATED } # TODO: fully deprecate `python_venv` diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 88ac53f3..f0195e4f 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -18,7 +18,7 @@ from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'conda' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def get_env_patch(env: str) -> PatchesT: diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index bb3e0b84..9fe43ebd 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -17,7 +17,7 @@ from pre_commit.util import clean_path_on_failure ENVIRONMENT_DIR = 'coursier' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def install_environment( diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 65135f80..55ecbf4f 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -21,7 +21,7 @@ from pre_commit.util import yaml_load ENVIRONMENT_DIR = 'dartenv' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def get_env_patch(venv: str) -> PatchesT: diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index af1860c5..eea9f768 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -16,7 +16,7 @@ from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'docker' PRE_COMMIT_LABEL = 'PRE_COMMIT' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def _is_in_docker() -> bool: diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index ccc1d678..daa4d1ba 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -8,7 +8,7 @@ from pre_commit.languages.docker import docker_cmd ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check install_environment = helpers.no_install diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 9323f407..3983c6f0 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -18,7 +18,7 @@ ENVIRONMENT_DIR = 'dotnetenv' BIN_DIR = 'bin' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def get_env_patch(venv: str) -> PatchesT: diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index 4cb95af5..00b06a9a 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -7,7 +7,7 @@ from pre_commit.languages import helpers ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check install_environment = helpers.no_install diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 759c2684..a5f9dba0 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -21,7 +21,7 @@ from pre_commit.util import rmtree ENVIRONMENT_DIR = 'golangenv' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def get_env_patch(venv: str) -> PatchesT: diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 80808266..05a71651 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -88,8 +88,8 @@ def basic_get_default_version() -> str: return C.DEFAULT -def basic_healthy(prefix: Prefix, language_version: str) -> bool: - return True +def basic_health_check(prefix: Prefix, language_version: str) -> str | None: + return None def no_install( diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index 38bdf54b..49aa7308 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -18,7 +18,7 @@ from pre_commit.util import cmd_output ENVIRONMENT_DIR = 'lua_env' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def _get_lua_version() -> str: # pragma: win32 no cover diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index b084e8f8..39f30006 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -73,10 +73,13 @@ def in_env( yield -def healthy(prefix: Prefix, language_version: str) -> bool: +def health_check(prefix: Prefix, language_version: str) -> str | None: with in_env(prefix, language_version): retcode, _, _ = cmd_output_b('node', '--version', retcode=None) - return retcode == 0 + if retcode != 0: # pragma: win32 no cover + return f'`node --version` returned {retcode}' + else: + return None def install_environment( diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 0eee258d..78bd65a2 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -16,7 +16,7 @@ from pre_commit.util import clean_path_on_failure ENVIRONMENT_DIR = 'perl_env' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def _envdir(prefix: Prefix, version: str) -> str: diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index f2758c58..2e2072b0 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -14,7 +14,7 @@ from pre_commit.xargs import xargs ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check install_environment = helpers.no_install diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 668ba358..19fa247e 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -163,27 +163,44 @@ def in_env( yield -def healthy(prefix: Prefix, language_version: str) -> bool: +def health_check(prefix: Prefix, language_version: str) -> str | None: directory = helpers.environment_dir(ENVIRONMENT_DIR, language_version) envdir = prefix.path(directory) pyvenv_cfg = os.path.join(envdir, 'pyvenv.cfg') # created with "old" virtualenv if not os.path.exists(pyvenv_cfg): - return False + return 'pyvenv.cfg does not exist (old virtualenv?)' exe_name = win_exe('python') py_exe = prefix.path(bin_dir(envdir), exe_name) cfg = _read_pyvenv_cfg(pyvenv_cfg) - return ( - 'version_info' in cfg and - # always use uncached lookup here in case we replaced an unhealthy env - _version_info.__wrapped__(py_exe) == cfg['version_info'] and ( - 'base-executable' not in cfg or - _version_info(cfg['base-executable']) == cfg['version_info'] + if 'version_info' not in cfg: + return "created virtualenv's pyvenv.cfg is missing `version_info`" + + # always use uncached lookup here in case we replaced an unhealthy env + virtualenv_version = _version_info.__wrapped__(py_exe) + if virtualenv_version != cfg['version_info']: + return ( + f'virtualenv python version did not match created version:\n' + f'- actual version: {virtualenv_version}\n' + f'- expected version: {cfg["version_info"]}\n' ) - ) + + # made with an older version of virtualenv? skip `base-executable` check + if 'base-executable' not in cfg: + return None + + base_exe_version = _version_info(cfg['base-executable']) + if base_exe_version != cfg['version_info']: + return ( + f'base executable python version does not match created version:\n' + f'- base-executable version: {base_exe_version}\n' + f'- expected version: {cfg["version_info"]}\n' + ) + else: + return None def install_environment( diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index c736b386..40a001db 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -19,7 +19,7 @@ from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'renv' RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ') get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def get_env_patch(venv: str) -> PatchesT: diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index ae644927..6c5cff28 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -21,7 +21,7 @@ from pre_commit.util import clean_path_on_failure from pre_commit.util import resource_bytesio ENVIRONMENT_DIR = 'rbenv' -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check @functools.lru_cache(maxsize=1) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 39e36281..01c37306 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -19,7 +19,7 @@ from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'rustenv' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check def get_env_patch(target_dir: str) -> PatchesT: diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index 2844b5e5..d5e7677f 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -7,7 +7,7 @@ from pre_commit.languages import helpers ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check install_environment = helpers.no_install diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index c6309531..4c687030 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -17,7 +17,7 @@ from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'swift_env' get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check BUILD_DIR = '.build' BUILD_CONFIG = 'release' diff --git a/pre_commit/languages/system.py b/pre_commit/languages/system.py index 9846c98b..c64fb365 100644 --- a/pre_commit/languages/system.py +++ b/pre_commit/languages/system.py @@ -8,7 +8,7 @@ from pre_commit.languages import helpers ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version -healthy = helpers.basic_healthy +health_check = helpers.basic_health_check install_environment = helpers.no_install diff --git a/pre_commit/repository.py b/pre_commit/repository.py index ac5d294b..4092277a 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -57,7 +57,7 @@ def _hook_installed(hook: Hook) -> bool: _read_state(hook.prefix, venv) == _state(hook.additional_dependencies) ) and - lang.healthy(hook.prefix, hook.language_version) + not lang.health_check(hook.prefix, hook.language_version) ) ) @@ -79,11 +79,13 @@ def _hook_install(hook: Hook) -> None: lang.install_environment( hook.prefix, hook.language_version, hook.additional_dependencies, ) - if not lang.healthy(hook.prefix, hook.language_version): + health_error = lang.health_check(hook.prefix, hook.language_version) + if health_error: raise AssertionError( - f'BUG: expected environment for {hook.language} to be healthy() ' + f'BUG: expected environment for {hook.language} to be healthy ' f'immediately after install, please open an issue describing ' - f'your environment', + f'your environment\n\n' + f'more info:\n\n{health_error}', ) # Write our state to indicate we're installed _write_state(hook.prefix, venv, _state(hook.additional_dependencies)) diff --git a/testing/gen-languages-all b/testing/gen-languages-all index dfd92c0e..05f89295 100755 --- a/testing/gen-languages-all +++ b/testing/gen-languages-all @@ -3,15 +3,15 @@ from __future__ import annotations import sys -LANGUAGES = [ +LANGUAGES = ( 'conda', 'coursier', 'dart', 'docker', 'docker_image', 'dotnet', 'fail', 'golang', 'lua', 'node', 'perl', 'pygrep', 'python', 'r', 'ruby', 'rust', 'script', 'swift', 'system', -] -FIELDS = [ - 'ENVIRONMENT_DIR', 'get_default_version', 'healthy', 'install_environment', - 'run_hook', -] +) +FIELDS = ( + 'ENVIRONMENT_DIR', 'get_default_version', 'health_check', + 'install_environment', 'run_hook', +) def main() -> int: diff --git a/tests/languages/helpers_test.py b/tests/languages/helpers_test.py index 259cb97c..f333e79d 100644 --- a/tests/languages/helpers_test.py +++ b/tests/languages/helpers_test.py @@ -67,8 +67,8 @@ def test_basic_get_default_version(): assert helpers.basic_get_default_version() == C.DEFAULT -def test_basic_healthy(): - assert helpers.basic_healthy(Prefix('.'), 'default') is True +def test_basic_health_check(): + assert helpers.basic_health_check(Prefix('.'), 'default') is None def test_failed_setup_command_does_not_unicode_error(): diff --git a/tests/languages/node_test.py b/tests/languages/node_test.py index fb5ae717..b69adfa6 100644 --- a/tests/languages/node_test.py +++ b/tests/languages/node_test.py @@ -62,7 +62,7 @@ def test_healthy_system_node(tmpdir): prefix = Prefix(str(tmpdir)) node.install_environment(prefix, 'system', ()) - assert node.healthy(prefix, 'system') + assert node.health_check(prefix, 'system') is None @xfailif_windows # pragma: win32 no cover @@ -78,10 +78,11 @@ def test_unhealthy_if_system_node_goes_missing(tmpdir): with envcontext.envcontext((path,)): prefix = Prefix(str(prefix_dir)) node.install_environment(prefix, 'system', ()) - assert node.healthy(prefix, 'system') + assert node.health_check(prefix, 'system') is None node_bin.remove() - assert not node.healthy(prefix, 'system') + ret = node.health_check(prefix, 'system') + assert ret == '`node --version` returned 127' @xfailif_windows # pragma: win32 no cover @@ -101,7 +102,7 @@ def test_installs_without_links_outside_env(tmpdir): prefix = Prefix(str(tmpdir)) node.install_environment(prefix, 'system', ()) - assert node.healthy(prefix, 'system') + assert node.health_check(prefix, 'system') is None # this directory shouldn't exist, make sure we succeed without it existing cmd_output('rm', '-rf', str(tmpdir.join('node_modules'))) diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index 61606696..54fb98fe 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -93,11 +93,11 @@ def test_healthy_default_creator(python_dir): python.install_environment(prefix, C.DEFAULT, ()) # should be healthy right after creation - assert python.healthy(prefix, C.DEFAULT) is True + assert python.health_check(prefix, C.DEFAULT) is None # even if a `types.py` file exists, should still be healthy tmpdir.join('types.py').ensure() - assert python.healthy(prefix, C.DEFAULT) is True + assert python.health_check(prefix, C.DEFAULT) is None def test_healthy_venv_creator(python_dir): @@ -107,7 +107,7 @@ def test_healthy_venv_creator(python_dir): with envcontext((('VIRTUALENV_CREATOR', 'venv'),)): python.install_environment(prefix, C.DEFAULT, ()) - assert python.healthy(prefix, C.DEFAULT) is True + assert python.health_check(prefix, C.DEFAULT) is None def test_unhealthy_python_goes_missing(python_dir): @@ -119,7 +119,12 @@ def test_unhealthy_python_goes_missing(python_dir): py_exe = prefix.path(python.bin_dir('py_env-default'), exe_name) os.remove(py_exe) - assert python.healthy(prefix, C.DEFAULT) is False + ret = python.health_check(prefix, C.DEFAULT) + assert ret == ( + f'virtualenv python version did not match created version:\n' + f'- actual version: <>\n' + f'- expected version: {python._version_info(sys.executable)}\n' + ) def test_unhealthy_with_version_change(python_dir): @@ -127,10 +132,15 @@ def test_unhealthy_with_version_change(python_dir): python.install_environment(prefix, C.DEFAULT, ()) - with open(prefix.path('py_env-default/pyvenv.cfg'), 'w') as f: + with open(prefix.path('py_env-default/pyvenv.cfg'), 'a+') as f: f.write('version_info = 1.2.3\n') - assert python.healthy(prefix, C.DEFAULT) is False + ret = python.health_check(prefix, C.DEFAULT) + assert ret == ( + f'virtualenv python version did not match created version:\n' + f'- actual version: {python._version_info(sys.executable)}\n' + f'- expected version: 1.2.3\n' + ) def test_unhealthy_system_version_changes(python_dir): @@ -141,7 +151,12 @@ def test_unhealthy_system_version_changes(python_dir): with open(prefix.path('py_env-default/pyvenv.cfg'), 'a') as f: f.write('base-executable = /does/not/exist\n') - assert python.healthy(prefix, C.DEFAULT) is False + ret = python.health_check(prefix, C.DEFAULT) + assert ret == ( + f'base executable python version does not match created version:\n' + f'- base-executable version: <>\n' # noqa: E501 + f'- expected version: {python._version_info(sys.executable)}\n' + ) def test_unhealthy_old_virtualenv(python_dir): @@ -152,7 +167,21 @@ def test_unhealthy_old_virtualenv(python_dir): # simulate "old" virtualenv by deleting this file os.remove(prefix.path('py_env-default/pyvenv.cfg')) - assert python.healthy(prefix, C.DEFAULT) is False + ret = python.health_check(prefix, C.DEFAULT) + assert ret == 'pyvenv.cfg does not exist (old virtualenv?)' + + +def test_unhealthy_unexpected_pyvenv(python_dir): + prefix, tmpdir = python_dir + + python.install_environment(prefix, C.DEFAULT, ()) + + # simulate a buggy environment build (I don't think this is possible) + with open(prefix.path('py_env-default/pyvenv.cfg'), 'w'): + pass + + ret = python.health_check(prefix, C.DEFAULT) + assert ret == "created virtualenv's pyvenv.cfg is missing `version_info`" def test_unhealthy_then_replaced(python_dir): @@ -170,9 +199,14 @@ def test_unhealthy_then_replaced(python_dir): make_executable(py_exe) # should be unhealthy due to version mismatch - assert python.healthy(prefix, C.DEFAULT) is False + ret = python.health_check(prefix, C.DEFAULT) + assert ret == ( + f'virtualenv python version did not match created version:\n' + f'- actual version: 1.2.3\n' + f'- expected version: {python._version_info(sys.executable)}\n' + ) # now put the exe back and it should be healthy again os.replace(f'{py_exe}.tmp', py_exe) - assert python.healthy(prefix, C.DEFAULT) is True + assert python.health_check(prefix, C.DEFAULT) is None From 392bc33466178dfe32ddcbfb728f398ff0fbf72e Mon Sep 17 00:00:00 2001 From: Jamie Alessio Date: Wed, 13 Apr 2022 10:19:57 -0700 Subject: [PATCH 079/416] Update ruby-build to v20220412 --- pre_commit/resources/ruby-build.tar.gz | Bin 72271 -> 72569 bytes testing/make-archives | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index e248c57ce6fc23ae3ac0f6794ba02f4270da89c1..8edb3caa3c27f1ccff9f0e0dc36e9863845c4efa 100644 GIT binary patch delta 63322 zcmX@Vh2`fqmJOXM_1bkhZ<_9!0w-pn)Uf{l9l zhqApp-rXtIHG93vV|uZi#`0g4Oj&dO?5Zm3my!w9yF2@2ZA+(qbA0_iZrOVUThz^` zznJ^<@k9o(l@eu+(ro`Z#Ao&VQdql-S?g@*sw;2!y1G_g+7sM;`t+W=`E#a5x;`AGE;Wa*i0j69%!(3ujWfLUw+M}nosQ#*~feto!9M*@Tzf67S(<`(Vutzr0*flH948idxX6# zex9&+ky`7)z~nu9R(qU}wa|Uuc|R7EEm&_Nc3!qEdDmYLp%n#tZ2NupS#h-QT(GY` zKk9#@X_9#5Rp+OMDW`h4)&Dn01#HYP&3(P*f?iC`=|@hx_jbisJ`UusXk$8Bnh>&z zl}Y2l@`EQo@Az-iw!ijb&&~)V-oC!h?NjX+tC}y`v9`5H&G*FCcSq-Ld$34n<2KVX zm$@SfEt)3oWuDTvbo%s|g+fs^m)-bg^Lr}1+ElNT!s{*=cYFi8_SQqo=KnuZ`L%21 z+t$7aMTzQGjcqCOOSA+pnFqV%&k3GpG^cDEZ|^kAS*}ms9cRAD^86e(+hdJ5Y1V&B zt>a#^)tMAsugKb3eU)4575m%^vRjt+c)k_U{N*Y5HdbVPboXiDTZS7RT|8C0sVMQz zyWR6{9XFhuRIhzx*7my>eKjf{Xh`_GF&lmMyYYz0Qnst}b&_S*{gZWTXQ(LNkTheO zv?dGTeEtBhDg%(Tf%)=pM5SD4qx+f`}&(XV7{Do@d-Dc$cjZJo;) zYv?{*X5o72{_e{ccV)PgvlYb_p1I`E>r(ajU#j#5#w%yctd#N>GVlJqe#L^Bg6Fb+ zJT)@rf4OU}1pnRG56m;V%Qw|8Qd=xqebG!a<#~B*z%~ZP4|n9!B6_b+7Lw5H`@GP5wSp`U&74Eqn{HZnavXeiyQE$C((_(+E~PEnr)O<8OZz%^JBv%y zu0ugT3=`IbIUH3ylyo_pOEdY}QHhsc&!wbZ79NuI`IVb*!Dyi{DTuk*yffLgUOoNO zx`HOQu#LYSWkhe`H!aw5Aa9SM@3*JDwhRx9-BvH+=vQn0yV#_MJ0bAmg45sl_`ZL< z^!xAO#ozwjdv`B+LD=PlcQaV7%xn7cuhwhhqlw3+9sj4;biRRw>&I3GWrtV4#R8n~ zZ!q54_U^%Xr;qo}xVWjU5x%!RdPR27nj)>$^^GFMFPG=~Jyw&rEX&nWTCrtg*ncG% z`8yq25XQs_Ej zVC+0wOMkM^v@4Du3%)bYVCcTAd-tc3nRc52Uq{7vR3 zwU?&)J@O7Q6kgV+cay6%`0|s*O0#=@&0A(0DVB9nKsM;4mDu}Bv4_eQE%a}gDx)${ z`CG*#w}RMrJ9z{SD$J4)cr-a*hq><6+GmTFo}2fxuifm4iB|mw$K}aMTLhPKB|8ee zH@>&|Xz14IA1pLXO_!tuH>64%-&x`&;(P3aQ*c*hp3JxFF$>Rm3wu91>hM`JH2ch} zH8Uh_eS$x&xKw=X>`a$Lv7O~pQGuT{FV8yjTBlLx`o8z!@^Muf z28)Y-9Q*Z_IZR)&SBG7}F74KWTfxtKM1GqHv#q#0?PT&TCGCh?$ENGE`YlrpS@mnH z^(_O#ec7)|vtJ)yygmPxdp+PP&?vrE0y!dWrTSBJ`Jwf8uQ#60zSb+?4)Zpwl@ zvoOx732Ve3pDvwdtzp3be%btWOCE0*IinOU=fd^rloU^|?*5zW)&;n2jcV0R?$hFy zh~jFp*nG4#*{NyPGVSZ4T*sfVEZV`7E0Fh|DQE9T)ws$o?KPX$K3`KL=lWd8DebLj zTBqjq`dP=<1nxMq%5>sc)q^#Gs*X>KUoy?gno+y_@q<$)i{?w8`f1H-{+ikI&Z^+k z8cFP*9WvgiuyN;_k!#t940XQtfI%c{2=(^E3|x4im`#U_7vU8IHKUoTJ?Ro$GZ6xpg*{6DD<=LODdO2}}rOSVVZjq(m(xz+`6pnr^#?~2g zfL|-;+=N}8A-ei%a-R;WTx%@&%*}IP#oAI)gKDptd;QN}e<1zs;S}`*8_~++{^!4n zlxp3a&+{tavf8zMy{qbDW`~O!E3joo{(Esv%9rg!u0UkQ_TU9VhYuGS>Hf0)uF72X z@RMr5!uZSuUb#+NG!)sstT!<0oB83)KkHhbeZMN|{L32swnxrr|H1Yn^nmq*m;I`y zA`$og?91ey;F$5{>Zwz^;x3o|+}`5x!{yNY6w}B5!6c<0r{52u2AhFc(E%VF0 zS5Dj1@7thdyQ z)a-4efab@u>dA*bpL@TQM{9z1T%KiV9e=y(H--883f(KVKHsIWTBxk9+i<7h#W~aN zKlxHWr;CwWY_Gx82cnz*T~K(s`MJS~YUy9+p6kzCchvgl-VfCe!*||KKEd0TAjF$aOHCKj-E*MqbEgbj|EEy-Hr+hd6mI+YH#js&lp7`rFYH- z;=(0NGk=C}JbBhJGx>tIt&!48uXBx)oTj@USaEW%^27RfOvO_-&krx{`jQ%uc8hbW z>O+z4!z+))biKV2Tz4v8^`_0s_{mkPL=B5=BA8x&krUKE^f);8?&cY9h1k5yKDW&f z-@jm!p-=v8m7?@(Gg^2YMY)?#-^{v|=zaP6S?d=r=jSi7+M2RBs!q=JaHUqDo#0ch z-8ITFlTB3<6Xcc7)Iaf13jfZowR-7^ExPQoPn6VTcb)#hW!JF9wA}1C=grj*HFoeV z_Pn$Es`1uSdY^9BZPD{P-Th?G^DUhUX)KKz+jF`;Kb3dTeX=0#QSJ=Jyj@>k-kcQ~ z`dm(^aC5R`!ndXDi9YtHTU(F0x0ybDBrd*Tm*}*l_+YmSK5ulMCZ*4;SDQMy^Q)~l z^YUP}mWfAJ1-jQTeV=mps=#~Zz_M#^wC7FU)bYcu?$n)=Z$mYYe=$vaQLI@rPpEG` z%k-VI8+KH@OF47E;NW{ZHbG%^hkH+oq}#KKGb-Tb|HJUIPZ=q z1ufNE4bL2pJNN!{`^>HzvT3@>;tf~oPY4CetF*~H*u-DQvo%Y^oFHt+M+y6f+K z!CJ6$nfRr$?S%_$_U`qGo4DoZnfxC*2X&J6nf^3gxxVw7Oy!)ImQ(!R59bTUl`Gt0 zh)7$t^GtxzhR_R1n{Msg9Cbo=%`KP9rGmLa!MAG5q^5^j%#S;9Vz!IDM4$dl!FM=VS; zmj6+(omW?;AH(zFl=Y6q8P=U96+PP)J~7FC?0i9N)0W;~ubZuE674Ek&x9=Y%yxY6 z<5;(W%lR0QvojvOetdaZu5cWGRYmfFGj1>5%4fXb~o4}d4KcW6Ynp`{(M$)Bq=DP(A2OpXd%O#;^n%9xuvY>VVM#w>%7dbZMoQb z@mag@Cb6zBYq`|zmeo#}8<^HGbC%4VuajrjTC(wL{`)>dWP<(kkGK4fR50$aU2AkQ zMayPW@UdThiC&j1>l-b#pLk{G%gN>aOUhEzRTdZ4_gbNDKS$NkOm*$WdnyZV%-EeC z;##pz)52|zQ?P9GvK?=&S2Zt`T^?{|j?-GRT}HPYzsz{9Co6o?@Zs~bhxg9i8~$3y z^kvVxw9ex?GLLl??B?|_MDhIa-Cv>hvu#sv$6D3s?_zIyJ}L<%%oDGlvhygn)1J)5 z#*Uv~$jbd?I3v+o;wsS1oNsh!_07t*)*JJCwf@8rqreOiA#s+h@om#(Iv|>T53hGvC`j z-8lPBdQXTiuX@~B$tg3ljGLox%&9u^>C|2Som%zj8*c6qVeQYas#QonrLOVU?F74r zmwuWZ-^)Ouxq3cJX3eTz`Ppyn!IIRiV!yP%1?=UIoo)6kAhUb*&s*Y-_F?KaDfK(| zZ2ce`u79-n;jC%;?}Ar+D_E^HFQIX7gVKW1A355unomiW9g^d!^iomGT6t%!@iC>U zKNHqG=e64zUH>wv;-iw#u33^b4V5?8V$)jteJoym^1rxfNq0i}`6E5elNZ{)vSG6d zc)0hVM!C?2#cwxWmyTCWQ95@ZZ-$7;ft!j3ZeM2{VmTHkpUh!n9PNKY-g8~S!$Y$b zHQwJ$I+vZga)q0CYM1Bfy|YcaecVYTeD707 z(e*{;vh#0noQt^kGxJy5X8vHlSV_f|1#iUoeV1vv?6RApB>ZKrpK129Pn`Q0>len} z(Ghqd8^p%7x{N*E$EvVREcof6!1P~Vol~w~uP_s;vzKYP!L97dZmC=4oL0(j$*=do zbaQKHscyVqp~}3xGb?uTXiv%vzr?!S&FSfbmy4B)^s5e*uIu=)=%H@9^1NvuBJEc# zvY0O$pT&OcYtt0DsLhYIAMjfcd;7;W|K;_EC$<#YtbWNDxLrre{@-T_7KuzfhB?y> zwDqPMH!vT0)8)O#MoVn5;r@q=`%ive_)%i-B_(zad$(;ZccYy4pAs_JFlDh!&*Fu@ zf4`Y|cK(h2Ir>@N=R&IXz6`xBTRC0PErTidWXDd)bor;5&qOb_YSe|Vp7H2kSAjt# zd%oWn=lTn^bsWE97hh{@I$#x;{h+iuLQXzu(vBydJ5ydweDvq6LQ?aGM@4sbKfS#4 z?(*5C-_$1F4Bq^2wcDbdo9(L49gX?7DtT`C&HkEiXRUumXGw&txLfS_f6tQ3*KA($ zXq;8Jo|kk>tB3boR>jR9MlTxPO1w_zyBzRj*O@m8n`Bip3&_DZO45h`=w7d1_iowbl)gAo$kH-sA?bEOcBQ`WnrlYYIwpj%I|2W zS?R=W55F$%H-D*hVV8m*cS!x+DZElz%iL@n6lNw&&GeG--4z>fUg*q%%lC8j+FpE8 z-P@C=*JTSx6ep{dAySzgv6a z*6v^>iOU@ei_@Df-qnt3Id$;-ZB{#$BTiR!f99C!c`%f(I_DJSHv7>xmg+34FJ*R2 ztqvuv2ZGl(v9tc>Np?4w?f!E~u6T&`B-^a@LKkO;$JNeW*Yf|vg^ihgt2UqLxpw66 zn}Wcww+~_!_Wi85YgqewNAfQ>9#&B?oBG}#0**_I4x~s=vHZKU)^urQX2P<|?pa3b zTNU@co^dbcw8Y82%3QD6-OF1{Up(sjpyH`}FY|bnqMzowqSm@q+ZJ@X)O-qg7R7lh zSa7%1#vS>#C%w7X?)KD+shNJ{??NRZp6Ye(*SWLGSzbK&Iwd<}2boC03yO7E~0D>+{ArSXZ}`JVN@Z%g958>54t zsLojFFriRo?^G$rUgbrK>%QH7=TZ5a@Z;amC+_P>9-4YV+8M9tPSN?SKf9~^> zZgn1wNN8AH_N7tHP^VMy&jF+5 z;k`Oux^wTx2fN>Ct>?E0WsEWno@DydH$_hK@J4pSUsJ^eYa>3Kw zjz>w8zO7fd85}FFZ{)sUByaT@nQz{FnXUSF>$GdGJ8oX;<t=EJ*%xAnS9FXJW-NxrxTwp$*I5AB?#((}eS9!W{Mk3;s;i z&QD`_bXLoA#kP49Rvqo8n)hE}o+kd|tLKR>tEAb=^~;=hWzAP^eOfwmW^DDbS5~?)6)&3`KS&3* zIh}o(8z-lB=YLB$zs!!g^EO^t*;rauQ=wq2K%o@l!IpI=zM{Q09I+o~h^I+BL-zMM^Cf0<#Jq0MU~YCLV% z>tO5plZL6+Q`-04wYqobrtPV;CsE65Ha3b?D%Vu~aXP-@Ht*gGOXE&jN`AEbX&oms zgZ23_i62TIS0zo)+4WJ{qqO(IQy=zw>dRuBW1e47oHy_LfvU|bZb{ue_jvhx&xUUs zier{PvD8f3w)^*G>1#V>*>8AS^BP}fxEFkveKt$~k><7aH~L-OC#P*~bYHxB#zVb* zXXD(>D}0|uZ9Dubi|K_#xPP_X-31)KmL{9O-DFzg6?*A;!YbCiUw(Ye=jXkbc6_3R z!XZUJ)0XcK1pdYCdKAXFvnF!K%BwyhPkGYPmg$PG?fWiyuc-XbuA_W>-{aqGyEmhX zE28V*k~>D5&)L0Rp`l;jUazZUG%YDA%5!#0S@MD~<7jc$2^?Fa(|<)@y~<_0QhL&< z1h4uPH_pynnYuZ4mM_np>0Iw0D{PPdwB_rYzNZp`;Rh20di32LE&lBlIQm|IRcEVv z_=I%nEi*mNl|D_VO#4~S=(3YDF{C7W(le(SwxQ&nagaQhc-6NyYMYfdRUD6?3HbKyfH z_wO1{S?_jy$~W8ot^eP>dwH^N-u-XdS#$gN?Dq9h$E9b;1i#$WIpZ{!s%!cGqiot8A$FPrzub3qW3*#5hk!OZc6;@aD0-R<&mREa$E zes|IOD}V3bG&#CUZXth4){Bx}+ke8Z`;+G#n&r>2w^h>dvr)O+k@l<%1%;!Yb z46gdp;AxEKPq|Lj(Kg?^W?7K>T8-Eb2d6FAW6`&A<)~^LAeMT(!N9rR>_tsk@I%(z*XKqxhZ9 zxg6QxBMnELWmh;hBz(N9&VBd^^XcWXI?H|3?_52YKec}Er0rEfYv*S2W=}qJ`|_9c znpv_3x@P)aKeu_7+SSjSw%VInNcCpLvYUBdId!|%MPyk6yrth=fqwYb&B zPl|Wu>R|D@Wt>xLTDNSSS-CjE`u=4f;Y%X*!m_6qUVmc8@>l2Y7K_96Ax9ft7XH5W z_VkJy$1B$IC?3+%%IaKRQ!%aY>@lGmN3IR)9da&v#yRl~4qDx0_i2qP@lR4^L@$*qewCkbn`!dX5 z3_8C|yW?0G&0X%{Ffh}#{bAJ zHR+3mnQ`U;pVk|hi_2tQ3w$s7U^ac?49lWbIV#O^YnSBJ?G;v?XTLrC{Z8(4g+{eY zqa$|BD2kiQb3ujWC(n_i`lrPFWsE8^7$yfjel}~>Kik=4=x^VW2A%AZ17tI_k)A^GB zej0oaTy14-`s*-Hh8ee)vd=8`T9J7fIT}k>EOpszws{8UCgZMkO^mDV_%C-SM;6-nTAhsi6Y+9N(xFYMu~xn-Z?8NU zusP_hi+cVh&c>h2(}S`WhZUYYBVK!R#(AA}x+?2-b;x{}n=)Je*~9|&4{thfW8KYh1VS(Q1VYr~tx8q<1?Dw-*!U)$JiRw$?Nb;+By!|oeYxA2Gy z&t<;4py1)PTkn6I-Osv~&7bdk-p6{i$*T{XkBsbO{q?9TePt@Ei!tXK)dNoTIvOF< za`o@2%EtU}+kfOp`L(Mng7-d`y~nrf-4b)ZzF(L4+P`XRcdnH@FB{-*F{!JX_13MHv%Qnd9=s?G=8v_$QPx?%c?CufM_IC&Tp!nTLmzQhGWiAG%)Naf|;9 zYrR>cfSkqgqx@ch_AcuT+QJiy7Co!!Wm=Uvxh0l$`@N;omkJfDIrx9*I+Q$^8?U;0 zt{>ko5$0*LelZ<7I;-SG{5)oNp-mrn@7eKX>CThe*tTYa_w&X)Zu_pZ$A<*(uL=Bn z-~so|3zHp+7>pI=58c>4DQe@jpk11`gzXsCM&yOmbFj{R(O)KZL`oyCMf&^}jtxmK zw+h@lZ_<6;e`2DDs{N)1d@*;n-8oSGxz0*+-b*39w&UfWR90CZd0dmcp><#S`odT? zg~oUH;@8FQJwD^zxkGoa?tPm4t-pGr>F%&1VF66@Wi!20p~kFz@$ zd^bw&(Mi9TJ;0LXRSN-PE;-;*WUz7v12 zGg)kQKe)bP>J<5n-#-N0+jf~#&q?>Iy!h=C^;5JYswX$Rbz67;P>uSk7fSmVU0Nm^ zA-p}y!$9|rx|nA zW%$p`7x@07-7wR2mH4U0OC17z)>YaZI`ETGb-7i&oOZ=E-Dtko_S|xpXa}EzNFce&%15EH|Z_& zsb?2@G}U=VgTzg350z~i3o@<;KH6IOr%L}RkIG7Izu=F5S=@7#B6e3Sn0q?4lAF;k zHq`(99M?zK~=wRZ~59^LeZI17|;)iT}tvZSh~^jqPJML0Mkj zWTR)5Z`Txm?3~9CSJ}32{+zGAzoyB&7wrr^*)XNvZ^i!fJC>I^n9f%B=%*gM!*ll8 zqiY8l&ubmj-9I;H>zv0^i>f28+%Z_5y^$r)?DM8gTjnpC=RSF(>Aq999#!<{i+<#l zNE4sbyg91==+DSqg)`16bSXbsC7&p>(7f00>~_)q-K>6&TvL{QJMbf4j=gic^{u0- ziL#&OrpoS$iOi{w-pP@+WwGCnRnvY5i_ zQ>RQLPHWF;i!WR$)zJ3OdhvYa6Ok0*ywr2ihlP*uBzH+qG)@%#@v46PtJ@wqvo7-M zZo50_`%le+lG+I;9`COx|MRTjINxXMQ=wt?Cs~h21^s-Vxp=O#;n(6T65B1`EZnvE zpeTc!z%S|OU+t-pXLNN8_iAloS=%-F3;&EqNuS)FMr}D1^7o8vV~ug$t4TrgPQSP6 z*?C=f^YbPFC);qlr`wp8vGDAEj!g3foHnq3CZ?pv}>;81mSi7VQ0VEgY0o2JZ{pTA|R^|Py; zStUDj4%@ta`@r|1#mrw9>!yB)-(!D@?J|dZyj0VTXRnW5&JS8>TH$MA(7lc8coqMu zq#v`**sQcB@B0!b%6D&JkJH?51=+pnjeL365+>HKKRF}Ub+@;|{LBZn2LF%gsTl|5 z*7k8)oSkET!&Okd_=az|)|#{o#g+XhHj3=u9?t##zW&mCCnob|Bt$9mE1x?bCO-W~ zzMu^ zvH979`In+H8|qJIr~ZnLTz%pGtEkci3?E9h=G;hUnEtCJIDh@WbM;(bKFeRwt#bPB zwEfrO4_6W|Y+fS#?yP9^E@5W7$dYq6jwNx5t=ziZ_r|Uo(FHd(xDJ$j-k=l7c&|zH z*t_X3=9SfcG;#YZ>LVeq_WoB=XZiIRJOP}HazB&)uTZT^-SoG6xmM)zAA5^G1grjx zGVYnl#Q3!BwxY6UM5e278+X{=`h&_}K5^D3R~r6j_1@TZ`0wAxCdd7^*TpLwb`;Ln zc2i?1;P|2U^<_lG_e+&^Cstb@?Q02BG5XeVhH1LQ`Lw25Ym?Sz$`=%C%_gZ#EC~Ow zhk4e938tH!R6O|?gue;wj<|MZ)zb|R{=5ngkv*SvBF&g%!$K#M%GT^v3=Yn;iQMG@Nqe8pC&wq^y}PEm6_$CT3MFC}ySgVXJQ z+_T%)-%AqEi_bhYCHj%keEpe+C*R0g~XZ6c)F%Q?I5?;|oqXQ**5Uj%~n8 ze$N2O>5NA&8+>3$SaxxxPmAT^I;IKiOszdn>K{#ZXPdiy;>-zdMb7MTQ_O99Lh^cr z!c`0dR5o``*I76@?$DQ=FWRT+?-ktJ1Hw6<8ST!;BUL% zuetWm`|Qae3EYWj~UISKBCaRKW(CqHENo~=^3 zvC~EK;l!4owFN#k!u`vR89rHgE9d?s0lT=6_$TewI(*mD!|VHW`3*T41vzf?Su{mo zW7m>A-JHGr`JR=RKTmxr$apNFLHn8V5$&%5pZ9wjU0kcE6v$%p{o3jU2GNJZ-j>8^ zt)+3q zek9j$_16a?&*YCiii>->r-jj$B`HulSB=Nqk$0ZEv12Dcmxs$6!4u7wCQReIoM^qZ z=w@Viruc)vIXi{@pG6&LV!H9oB}busieHVdi)uiDS>Ex2AVJ&cuAg#-Ph}Ih{dQgx zNa)MF{Htk47XS9kd79Sdxk^55A0_0zo~-{@we|b7!wz=F$HG$HbT^bV-&mQ^IRBaO z$BtJVQ_tRO`nJ-cH|Eqkr{x^UFV>e!cB$;+PU7xz=zJXRq`c|!@d!RL80ld>00zr%M@ciO>SlGhC$g?)c7U$i<=Zw_y1 z$ocC3ZFaN)%Be9Zu1}RIbW+c2#ac1fAySyqj|HZtXE##*&d($lS)7G={Dw1s#OX3 z@A+K(eb&wL5>aiRj$I3f4|}1-n-p; zKF-Iia-J+P5V~oxt!~+|Hgh|<&hx5Gf1>}IJl6ksO<3^$$$z%TEGM3wmmO<-LlBaD`}Fz4C{Ec^)ydw#_0_twW3wYPjtdM>7N?_J3w8^;(w(47h5g*wa>nM zmEXos;$eSegbfbvS#ZIIZL6(CVE>-;eDCHz+5Dl$BBO@$+4<-#@2|H`-8XTLipTQS zSc8y)!Zqm(jBiEWUw^hW_wa(h_YN3nY`tAybV_zs()p(JJO0*OmzGOT@N8r_(W20O zC)jC3xn>5oV0n#lyb&o`Sh#tQMF-fLbY^m^IW~4_^NNp|JNN<&iwrU{Newq zqWgWTy_@Pq+&WG>-YAd$oqz9*OmzF~>h)3gofCI<&e1yKJZ*l2#Iyt%?MB7C{Kq#h zetPSaroA`bLtgjQMS}wSRknQhdgqJ$SvPo-t1ioW4tTCfCe|H)lRj|KGH&oyY&1zQHE>?2v2`y?P_LjY}t&Zt!Wo`0J)n z-FsK_Kh{gtcRw}|6AP2<{~I8#vAoztjrrzLks^^8O=jy5(do;Ro4c!W!;?V=_k&*7Oq{=V|qz1A@17pzOW81)#V4iR8O3rdtvVT zJv;ZTog%isSLpWQl+`bO*1rjs5UH}e`uDU{&!3tlJC;m;_dw}Guw;%Vlg67e!~2RF zRw>NE1{vG49d{NQ+`4h6s(8hsi*15wk$fM|cvVkG;qYL;rsVfI;(F-qeg6Jie3~}z zD6xuI)KKPidv8m5dDOZS9lvCM=UHBjmb;o9>EL+T`lv+yri$$jtS{Zf1vk~No*St% z>HM7IX$O3QmWjQ2x~uh}-*=W15Zqo!UYW(gOBN*kK&%SMs(}U6$_uqUWtu} z71&)nN8rQF&#hOhOWRD3dZyj6*56nh{G&b~wXknRFuVWJz1++w=hJF55{IA58)N4;` z(^Zd9x@Nrj$4u5=8%$kQgq4@-d`wDBWh(jC#ncvX;rZR-FC50fmz)3S9IY#|jC?rd z-9iBu`Nq9%%yAO}EaJWNw#k+p4wO#`G0YF#n(F2!U{@mV{4{L`2mj-5WeO8tJ# z=1r6Qf8Nnl>xkpjkTlc(eC0;kCXSV}1I0pxTU}>~AIIH+Ll+} z<5rc{>`d;m@Ju@3S}FMX@7wKdrJSm|+*b{?R(&yY=JstYTK#hS%e9eOj*Z&&Gwbb| z|Eh1hXE*TzH*dZM!@?#lbcT7Hssne*izOL0i-mG^seT45S*U303y zxzz=KsxB=QO0jda+<3f4aPJKE24nq}Wkv=MHa_t@zf@87eg6CP#u@DO=TCpRt374z zhoYY6N?Up}_5}(r7M{Fo&W+WdE@@h+R$9KikQ?mSa3@|i^bpTUWt)QbPK%>Ud3P|& z$Ge$tv^eXlcw*7P(#sAWkHj~Z$sTr?J5zr9mb%I9Jc|M=7=_QMw|ZUp_289*;@d)d ziP#4hSq$7gG=Dwxdv|Ga)4BYr1xxCm1V}8uw&}-7p3}0I1KUJxQ{2O5@ZGw3Wb(2P zX>;e-UpU0fpfN-7Oz+K0kLI!z?4Kgs$$aC`)+r{pX0WaDis}=Ix~{r${SFq{DJ#z| zT*>>n>Z6}FztGG_R~LJpiT^zDncOXg(oM`6MSBB9)@7aD@jF+DEqS6yyyNcexobSG z@vGH8S8q*ucI3^&m6785?-nKN7xh*yI32`Rbnj2bcHKzbfTa0SJcVTMzGT)|S@~3Lep5P+!}i|WFAw`0 z^p{(zN19lqEn1y$dWWJ{mG#5iGyLj}JNIqea%$f3^X&EK^QU!ZFWq|S)aQJwirWV` zHv1nx*wgycy(+b*+9r1Dm*AX#Gi$V_Z810ay~R1pW0gnI@5A~Hza}kZc*yAI^PuJE z#Q3Ezg{zl`?l%|SG0jyyXw!qME9NgQ^Z0JG_V{EzxsdqExRQ_ipSY@j$`4QZvge$w z&7NYufImy8W*#^(@qhh^R=dsr_eY&O^}nc4@4x-?fAS}5H7{7LxTSwD_wAbc=9t0? zf44I+fB#*-@c*dn1G#-ab-uixk{$VXf7p7F=U@IW{ZfCDw`vdBpF7+bjBr1B|xzaEueezAMM+u|~NnFISbg-)zD)8w6W*?I5HbnkCMSxkH{ z#MyS30;`KEz;LEAJy_Z(9$1Q%$7AtUdZrbA4W?e_!4zDktt*|%t`pVL~ zRcjwxt6ko7xzUN)V#<8g!YYQDN0|-4z;SC)HvBR z{ZIeL|Ml_q^8fX(ohtrk|NOuFk^l8)jo4$kK1{ch2#Mn4KDOeCW7o>$Rh-A)?Y@4n z;fG?aw&(|KM=g~PCOaoTdtD;?-85kBYu2mAN3C%3 zpUSh+`{6Csx_HT9Ay882v>-V$#S67Ff3|=o5$exrx(tmwGoQZA}r_d~9>hiO7i?PnmdL>dsrK9(QH?<4vsh^OzDYtKNRQ zd%rvLceQ2G`wunB@7a9({jp_@A9qQ=aWL8aM`+fD=5psdGnRQzT9(qhld0yz+lPEF zcbvYlRCHcBzp*vfvi6&@?DadYc0}GkS{fz7v!!SD$CQ|4Uqq#ZIqZ$~hz@@ANmfsM0prB*irQN1`aKO( zW8&?r_HyRGIsIU+zyFV}hhhgdMTxBK*WPpe*28bSHlJ$lR26U7U3tgrZrPDjWq%c| zmuF00#J{n4!=5e0OzZEgtvb6a_~nkH>*7~d&Gib%xpLZ7{e{KTqO;o8Ul+WX-ZeLC z?<=dNSsSC)TkM;Sddar-kk#GOy{9YeceCgAEmh;d4{oncb zd&A%5>ajkNjqCWU9M8)>J~p$%WU_tghN2{mXU>i5H+emB6frEf+&BfAoUmLk>vB)ag^Q6uEtdl%z zp19W^eKIk1dG{tAx9M-&non96-oMXfx|;r6$YVP`JJL$H8}jCX4DEPuy;_NR|7+Wqo~Xq+xG;$d#Qu4ZnrgykGvI z{&mumT?^{|M*i6!ck0dmDRX8SZ~y=7&;QIn|D_w})jRNcaKt4noP4IRL~z3P`6kg) z909DnD*n?y`>Tk2O8X-C@Pb(AGbg2Zj}P2A`|UIrey(4%(Z2C`&5@t+%j4$G|Nr;S zxAvn!!KXuj9pTFu~el34f-xj;ItuOfB6Y`5=q{cG7%+rnFquDj|mU*p=Wqe+)n zS6%hm`9efm^?14Wy89(r`{F;{aoZ?Z@^?|Pn&i33(E%YV-2VyaHPz)jWR)y6e#&3J zT>MJu&&3n;^7{4b;x){r=B8cb&01QuGkSH{>Z4W1HIv?WuN7uFdtmMKrd{!wRZkZ@ z6X{->we?NK+_vyGrqcDD;gSnJ{yFdSf2zL2|EHFJ>r=nP|E&16UgH;glm2c;Xyg7x+ZT#qXk~na%R(ui5k7Po3Rs`M198m;ThbJOBKjzP$cGQ~%QX6{}wC4=%gY zc3*SX0gh9=>sh|kzqg7LUU5hFTC?BQSJP%+_1gP-cY>nG-lV0sbg!N6T@_q1YirTv z*_Z#PFaMwQQor8lZ}_I?^{L$OZ!#-XL$zh59ZgBmA~>o>U#Dx>8(+F z<2bWS*GH`_ZO%Ge*fllp>gU~lYgyhb2-4eic0uHN)~QjK84qcnTlv4Z{&M|W;h**L zOa6bl^3#6COUu9YwqN3ZYus9|xl6xnuhfZRfq!+%45o6Xe zi`GVzThDdd8>Z*fy6bVtsk?3g-~RrZ^KQSy-^D+}{!D&p@Be@P{QtjZy_mn@!Q&YW zp`mjYTr7~zTl;3Wo5WbF#KSGvBqb9skE4`Zxde|9I)Y*7E-UJOAEaQMEN~X&8Hwp81@%XkD{Yvg==8 z&&mtPGubVd(L6V6<1_Pz{jbBb?iTG0%QTZYuPM5F?zuVt_A~sg@BF)e=l}oNi~pZG zez|_r|N8L4y^G>?uFfr5`6$$JN4U4&#_09o%~{u(f5xwCK6JleZqo9|&)K}^-?KR` zk15_0wLOgSXrkZ$`E&nyKh#;>8`j z=o0UvyIxPRIM0b{x3#aXT78YWth=Z!;N6tjPiKjrdHH|y<@%rf?-=W@ z{QH0B-~U}N_W!x~X#X6K`t3I}ug%R`8MD^Rf$>E`ME+skro64UOQh>|UdfrFH8+Vh zrT*gEX?Kb)zP+MdcT;ofUbl-g-T&7}{>ne|^#7cH*}eVg481B$D;`gu&FeKkq+WAc zmfvSq|OHIeb@LXUc1@x!4>Uw@6C2UO}ePx*cniwt$O~mZGPRq=iV3UKYzYl zU%K!A|E(A6KRzU3FU?toysq8eC+= zJN#dN?s5G-vtR!!{_ekc;Zgmmt$mkQSUk;J8MOY|hi4r@dv9rmXYafH_S&8UtfCBG z7;H3RGV8DH65Y<761JM9mv04cG5-Pa1^=H-U+};3U;p}^f3xNN|DSF7H@i3O;%c_J zZkunG&Z^t`c&EZ=>!V)FABW8@y}yzrj@Lss!_3<;VBPgOUN=`>v0W}XW%k)c_7F!M z`Zxdh|C-z{|37}KH{ST)+x5Keq|^6xE$2nAGLzXJnO|>p*KPaDD#x2&Yu87<`f;}E z@at*WcZ0S^ew~xF`NoP}R~K2||NsBbmw3(E&L8`C{{3Hi(LUke@k{n0p-B;6=2dy4UT2Df9Y=*H+!-v(Ylms@oj(X<^0kFm5l^{V&C4-?jW( zANOm0eUq8pt3U5;{=Ki)Ui818`>*Gsx`t)md5goCWbGM>iuUg6{FuF0i zNquVH^B-5;Zmzx}y|id+(7UR;X=?*tiT#aQc{3wq*3o5;E#n%hPSy8+-d|du{o=~L zmOt|^|G)0?zlBx)ILnGvk60YHhA=WO2rKfcJGpYo9;H*|6TZ)j*Pa$5&tP7={`QNK z?4wCbB~50ni~e{gYIEaq2JL@yglp=4{a~!&ClKj(dYwmD|);TxIB8z^St!?sL|H%I2^eGlTz&FZ{2+ z@xT4||Mj_F;{R2!O?dPF`rZSpO|0eeUYmOPEq=IjYTx~pyN-Hol&JW6fIn+)-p0sv zyYDW0e?2DSgv0{aWRk^{(?D zoOM^NjNt9lFp|;&in>B4|2?Z>--n<^6@+ zvogF^ve-pu8ct(5!*rtday{$+8rQ$)-~IpD`SJYQEes!Y|1bB^I(zf-(fqeBe#G~! zt21+u`r3MIZNl>lhu`uqb6PFIvXi-whiBX0{Z0S5Kh>B0@AvQfUpMc6^gn;;w-L9Z z*VV4OrFE6-;`A&P6Yf>ZFXz`^5zCmZ`^@GJ!^$jC)u{<5pZ)*&^Zw8J+5aEwS)Bdf z{Aa)U*}s=IFzef7G4|K(&psP<#gzG97u!@L2?e`lOkZ3#E%S7=s%klvGy8w~b9?3W z&!5+S|Nr~Q5B-MppXZ(PXF3$0^NZDNt_e*lSQx?(Jx$2q^3(adW{GBS?z<_ml&8K# zQ(cxeey+1Ge(3pLoAj0ETj@EDCtv=1 z`&aij8F?&ccbYw6pX1$c|C#>jzx==Z`hPpaf2Uvm+5c(5fBo$|A5SxAIcr&GEZHwF zA}VMpb?(Ki7f-A!ZW;=k9E?}K<&nNHrnp*F!>%PAKAiKwWGUVjqm^M zpZ$Li_qosi75=mD`kitqq4%h#wTeYd=9xz#-A>kO<`x}0Ch#&w8SQa<{%(hMgWiL9 z{fPg!|NUQnZ2!FY|CiZ6@9+A;c=SWYg2t_48{)!+w(gp=T2{B7F-_CC^^t_2#q4D^ zOT=y*5M?$0FaDwaASh6NKlx$5|Nr{!f9q!nH)VTn=nq;T=(+3rMR9k5o@AkpB@%0H zwTLWejc{>|U(7S{#-I3u|KI)J`&0k<>-y7&f5kH`s56+V_*dkxQ}UXn-CtjD@;Gz1 z?e_5Ij1WDob7OjG+NQ(4^*8>+ANVi&yT1DW|KP{}|NOh({OkU~z=(wj7ndgYF3Y@Q z+0$PYua_J4{V0#}!Ret@UXCB0Echd2a_ZTCrhiW#e>#7t`rmo=BmevBtG~{u{W)_E zi+X%5%fHt@KJ(iz{Cu_|cYTm#-LH4if40?DzmYN!uY9xfH~;!;Za<12{J;01zW)3F zD$Z~JYkvG!`1L&?&*7BKuNb?~<8zj#Nlf_TD`2p4bAM2_59d}pv9qpBSFWYpx%gl8 zPyD6-$-n>4m-xT@a{ZTSf0J`lZ`^;B@y>Ru*6W;$ram>Q?^y5qu&tEsTcVIJ`f81D zdVFc<6RFw%xqsBl*8kS~*C#*m|1XVy%NM`>T>tF<ZtMiUuiskPzWYzRqZ8{{PFFKl%Uv2S1tr?(zR; zoIVRw+B4Ru-s=-MaO0VRrtfZRXp&o48*zat53 z<)1Tu-v9aUKe2va|Nq-|35)6*4y!RA-{QA<`jQoqnx@ZK`e&_ZUHbfdp~sO4^JYEt z^3qKg%Km2Rs8~3n{9+Kx=o}T#KKI5I~ z*%}_>^=EhMq~t1 z>F4t7ANODXpZ$ONCx7*y^%v$boL;g~ZOVflqp+hIn+sm5nBC*ikUss?Bi!t3SYew~ zSp5QX+cR}DpL_}Wp@03u{_FqE|NB4PKj+E+Z90}m*NV<+j$AZBA?esRhg}{ke6Q3P zrA<%HEIN1O+|F+&E*wxZo1uU4-)GZ5@4x;BIrcf&u?wU9)#a~QR0&ASht;dO$R7Tj zeM#A}Fl61rq|M8ee5TDh@0Ttwr$3>7XWRe1lWVeg>w8Z4&W?~aeq5)x{Hk>e57TkO zPRqqiL5?RCwqD<}!%j*)ZS(hEkA57t|0ii@_y7Hq|8mCe<{(dgsK2vnIm-i!4`Pf* z3@4vCbWEl#MB;|#|M`NNf$yJ5e%@YoM*aIfu7y2qrcxiz9RBqCybog?`+pDl@_+vG z;wqQ_>o5Di{%rmK$v@p+rHd-?@13g2tGi)AN2~Lc6uF9^nI&hm&0c?<;U&TxxXg7` z)0q`PE@J8hj=yeJGXDO!)UK}mpYU|o z%%$6|zRozbdUdjVi{T1M0me0E76ApJ85cCOZvWaZukZ1{``YvC|Lbl4=fD1c`Ro1+ z+tvRoUo`7DtdW^&x}s;{I)xjm3?VjJ0u`2ToGjKqJ3B$={X@}$9;21FPF?%|x5D$+ zeZ33+_x|7g^?%F1?Vo?uX9vaaT)tx3(k|I5`?4~IsO{6%?Jr)!$#JNy^s3uKSKF)G zeD%!Oum9lLeBfL1>;LOt*~f4E7hhlY@Bg*`>aXqR$NzuM{`x=T;?0jjbPr9vWjIe@ z;kKiTT9X5$S{D2MjJXijkvaEP%D1vF+LGBhfA9B;FZnND`S0`Z>;Jd^%l})y>)-Ut zk_vwkJW6Lj>a)0fpa0q}H_y`aKGI7K#AkV5xA0;;JKg#7 z7TylS1FQ4@-tV8j_`m$_|Jrg#@Adz(7rpy)J~$fu^MZbROMlqm`S#1D{(mW|{^vqh z99@*Pnsr&|3io&Aje)USs$Ds`?WM#yru7I!tjevo-XO2<`u}C**ZGO(|KI#oAN2pF z-QWGC%!=u6GFd$K%sM4yRpt8bt8bKse$cDH#~tC0QRQ*WuP&Z0@iYA@%l_v0^Y#DN z|5ZL;e=7RZ-JktC{{CP4-~a0WJ)!US`|A~J#eRc6t?zz58$+CMDVzNJa$y)t1 z>9RS0)Z@^?l+1dGX&X08Ubptw?~jYV%-6e6e+v{J%U|2iz4o8o`BV)@h>O-~5z!^t z8q*?Hsd8N2>A$-n^zvWx%?i_#<2JTDHe7A6?fQOsefR$_AAhf}od0j}n?Li{{`bFJ zZ*}{BtK7HxPMf>R&+XGbi(HteSGO^d$u>VE>`X%fug=RC{@e~Z^=lt2+0(kVdba<2 zhP(TgeG>U;fA7EB|7PC3eUFVFC%eq+J!h=5MR4oFOA=m&F&yr5KTS%$GVSZ1H)oAH zR_^#(Z(le4U-HivU-y5?`}hCb|Ly-QtW1p>dHY?`sSC(=kKqyAFO?FMjae(>{a{rCFYzv`X--+sxVz`wV&ah=lx zo5~FePiH=tFL@c0t>_n1##8%P=|cCU3i1!uxhv@vAjazw0+T3PjEP@$&Ee zZU5dMU%vW3>uuIw`$1_M;t`N3%@42GY0r>Mvij*h-@K&v-qhF4v_|q_)aCvh z`EtMf`wlfSzbp&R$kktRzs2Q!@p)jzN*7uG_y4zjt+%&J{ri8%@BIrncK`o;?f>$Z z|3U4Gh~M&aQuqDx_z{16e*F(mm;I9K--brD&ENN1Z2#N)a+!0cl-bC{^^hZ+dBUjuiXBxe*OQvzxA8`-M{?5_1@e6Oj{H0 zbt}3^F7Z%o?D?7~Qf?O)HPNTMj5`g;4gY5y*Z{@VW?lpa9Q@bCVw{a5@d)h=4|u{?9T{JY7MrLW9{ zt$wxankiR)Uko_Y6TVc>CNnZ_WiF_2Tm1iNzwy6sg3BT|6-eag3ILp z$*iyY^YQl;$se=+{c@Q8@89?R^?yHi=P!AAT>js$TaRbQ@B1&mOaAzio?X`-#64?S zwZK?ZxRS?CYIQ(%a>l92Vk-lde!CggezoeXzTw-m_4Ci{|NArje+u)zt95_M_WXOe z|M=>B`90q%CD+#fe5cRPb4_}iT+N}MulD~dt$Azz=cT%I>7VDXYd-PY%YIf1etQ3W zz)y)k^?&~Pv%a|d&wuy7-&Ozfvkz{z+VC`odG)6ajZ>qgk10-_e)?5zz_0p6z0Ics z56Qirk?ZwyV=@1_)%C8AzoeS}(mGqCzCP#w`{}>>733rTd)`0$|L*Vl^Phgy@B8(5 z_4`dFKPYv{zrZN>;KpO zGw-|n%isL(`OSte&#(p=9<@sBKPVR%bzV45`M;dXh6B+8MN77MnU-CTP}*V~xi97K z`#%%E|378@dVg#A|K)rC{ciQBd45^w{!g=QO7`0~%!``2Z%;+*;`H3NVW%~WyjIzT zXiu=}%t@8gJ*W7e&BLR3%h!9kr`PsJ|F8e=vo>zQf9wCrum4Y9`2Xbf$iL^E@4wm~ zaQKfxEU(Uv-c#MTa^~EtJIh}yc`ebsU+Z;8h->SXrOvw99uZI1{*V5DfA#<4pU!N4 zU4QfU{^KOM_b zwzVw_Q1_j@vRFGUe95^zS;rUF3htfBdG^){qlRGF8O!HCuk2Z0pnJ^hP{gv9YgV9I z`M>Gk{G!Hx@4xEM`Sgp$ zTSPY(Yfe#QtSIXt$?f;P%s;zu_KAnTC%ey0l`u%2dBk~#tpAxu0p7RTr#T*c z^3Hknq=ePh|BGM$U;nax|AGJa|H^OwSFic&{`uGS```XQcP;orr|sWA861nf>g)b( zb@H;=a&g8Q9*JkG_O9pQF9|tqz_@&}X3pRHzy8<#eO`v}V6pYu|25K4xltzme0`c% zve$~~OkrEVSoXlmmt*Opt|;~ilh25q7TjZg^{AD>yE9$jxTxnAAbu4YN zjA**R6*@mBg10egV?M<1;uUp&^*4R32dCYlU9aoqs$TyOSjITz4@>Z)Qr?zC8_kAU zE;H6;*u~E736t#;4A1XssBM$fe*cd@`hUIe|Bp<6@BfwG1`7QC=U@MuZ7XZ=7U|`g zTj*sSrIgIdC|AFfJNSv`s}x=1f=_2odsQ3Oh)$PWB>|25_~ZBYb?<+C{PO=#760TJ z51;#AKX3p4dH=s^-fWs5X`RhqXZL5Ca7$6nyH6oz)3!F<_K9xLJ6*Xp>{D@joatK@ z{mFVJQSFP{FLZ@Yf4}X2^#AzZbKm{X|NWoo{ki}5UfW0iuitO+*Z-Oys4cacMPSP{ zfdyB;eBfnATwyrJzF{r|p=W2d3b;XnD; z%D>DP-1hJN*ZJxh|8lo{yM6l`=i;p|qko9~+k5d={9oO;`tASTzFq&f=*RybpZ7a{ znEUhop1=FEfBe^pS$6(jy`Tykg zo5d9P_g?+qqmi=l$`!ZXMHlWAhIwA(-*9ibsl&xntfLYcJ{x|>;R4_*3Y{X=}M_=o+k?als|f1bbnUF5&d7qwiTCiUNmq}y2I))-WqLW^^8Z{=5Ayt^|L2zfe82tLEJd-vnyI&{ zv^7?*)SBfYYCEIf^i$O;-N|Z|k@acQ^f&Bs{*w1+=jZ$L=KtSxz25AbV|w^!mZdD0R=Bo3{9vh;Y$Ekl}7?$NoP#p}0~eBt4C zb8oIcKev8o!~ebi_y7FQ@aJ^pKlv?T^XzKB&J+CiqU6ifnM=d0)@4_GPCnul{#htz z)f%n9S#H^>DMtbp)xZ1mn)T27Kj+W>XMYfX{&T(eTAjEpfm6PGFckW{N5TEU2Gflq zgt}2@+Dv9zlFe}XU-pIFlvQ+uENp;;NFT58oIyqyv*q`pI zKY4$br(gRo`#*N^f9v}H-*?WvGXLi;|Nk$qajSeX{=SEmccTuAyp?N6*Xl2oUoM>K zkGcEnghSa%o#Xp_#6Ejm{@|$}_Wn5Qum3WC?N3{Ow9f;zKE)UQ_kZ#8r^he(Z+~ol zDWA`*lx(&<6n?5McPf{hWcLN-S4vXcyUI*?r(DbUvNIvUUk&wEOE60(jy&G{Jan!S&M5Xu*Hd19^7x601z}HO z|8D>K-}cx1Jv9yYKi+($Jw_7w_iCDDRz5G=*ITN z0;Nq>S!=a^o~+)n>-qf!T9whsCKK!1M2#I7c!O#e{Jwww>)yYo`|qE7ANPMp?}2Oo z=YRPx`RhOTp2z=IA`diQW_y0$i|Mh=NRcmf8W~iI}zx$KD+5g-Be+&KDFZ@%U zU-n@6XZxtui-|$fEiqM*oBczJH$|pSnKs?+POX=G=&b91K8Ww&n{DC#aIeswzx%(x z{9j!Ey#CFf`)mKlPx^Pc_E&v0=QXzMbF6`TBoo;$YTjBjHOTaFU2*3*rbCPMbxcm3 zINg7eH)GLpP?LuL>;FZ6`oUG3(wG09KjrsN_}BhZep^)4A3p6>u6thkOjX|{z$Pyo zzcf7VP_V#kjW3fJ8|98>Rz!4Jo(}uF_W%3K^?&La_CLM?DknC6{m*^jfAOvV3D?R^ zrOSNE6Bm1g*UNd^D}=Bv(wjfeZNZe(wdONyWB=az#AH|%d3E~xzx&tz|G)0vVfX9x zD}Lu8IentPeTwlTW@AU3}_xt{v|Ns86KF{^*wh6Nowlhw7xaquUl$XQ7 zNmUc(O}nbabBR&OHcYG7z=SPDSCi*-cFBSBhqnIG{dYR_PyX-yKlk_lFY5Zw&U|%M z`=zX$gC4erRo9z(F@|2YiI;8A^*MgXvTtTqkk*HYN@xAGoA+_l|NE)*ukw8T{Xh4Q z+s}XW|Jv7D(b$e_G5vh&Ta4Vg7=*4zynOB4!DjS@)mQUK_%G(AN6zTG%}&v8s^8i5 zKlcB|pZojkEsy?R`&wHd`PWzOSngjASMM2bYQNZW-6JurzL|Id9jnQvi`n~0%VY;xGUkS5J*h9QyeJtvhmpWpQ> zg+V4&WHn=&q}3jte_yr!eg8B4?El(7uQmVW$IfS;An!b{ChOSG)T@CTSe zU&3_H+pJ&dRrPOj=#mnj6QK@>D+cWN9&QkYW#vqxrUu;*>T+_3{R%{4*8<4e!;onQkU;Fpe|Ih!t|L6Yp z`YNw%(O=KXuB_eK<$N%t;ok48rv=~Lr$qS**1LZ2)jAN6)D(80nVUD%G@{!&SiDm5 zkG=bU{)gqi>fiiZKl}gXzxFR&{`3F3``3P7t@H7>x9jH|y#KlUN%s0@-wpTwoΜ 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 V{2zpK{^!p>_1x*<8Vnpf3;?|+r%V6< delta 63070 zcmeyljph6nmJOXM^{1D1&AjTdW7i!ckNvv!->(ZrCzMDYcoAi7&hnXem(?@&_rKQg zSh?!I;rOc|`dML~q1qxDvuQuSZMb!I3jdLRuU;r|_I+qBuUX%?rMAMk={>uo%EC&& zcMslH72e(XJSyi}=tRBeHUWNLKeJr1_*we(jhv~)s+e8olYesv$FuFPuMxM}^Dx6d zPw%4j>Ep_bIzfhSn#_3q3F?_heszp0We=IPI%MTdSrO6TrIpLYrcbZjecwV``&M<3 zz!X_=Da*%R+vWz}{<_FhVq%Veh`7RgUgxvB4)0Z+w)MxSxA&&qxO-VG?&Xga3@epp z6|Iol6#Tj5qNVA6)2|+U89(Jd_Dk3Mu-&`S6mt7rYqNG^ebfwrR~_u07yhs0ssFu5vUp>Pl#Hx!zIMHvcb-dOH1|`VSrfAFc3bBjbd5~P z&7QGbe8Zyx7UgPo4Owq}{hdy#TYfC-l`)f_R$u%7ou6Nc z2H)nE-RNZSjVmzcq}|I9r6u{xI__C4*GaW_nU%*tzG}!)|8T(A#yf)3O8Tfq6u3*{yt`8J%8hZ z=TFXfM88UMYv9~`)Otk=qs{6ItlxTnyq$B`_`&H5sX{m3>a}Wi`_?GFD|{<@s8)ou17PLHcEAVIrjIoSpxHlnYkq{_ng?vzQ+eT8Y|Da z`r&kHn%t#QYeTtRyC1L{h`&#%clCAC{B6>RwU1Qb6UEZ;Xry%n5&?iFWYbTObPJ=ixxRfe=95V z?(x#^zuVp4{@r_b?{SB<%MRW#?nT5uwsp_n3e)RAiy8)xv^5|X91J}v0J=-voRY|ke&69rz$Fw8gg4?*ZIP28! zQcd{7XHavto<(5RrWVyX9}~^97Z&tJ3wOEJo(|hnYqofkl(6N>$?=z5*G{QCct0h7 zQn=UYIY*|iNK*5Wjol>5wS3u0cULpXueQF`n{=)$QnXq!sZ{6Q(%mg@U7Y7LXj^(H zxxe|S()(c7onlFaCPx!Pg(K?sBiR02i9YMCc~?wf4bt-5EawS>jJBm9F|jA5fkUP&N$NP-`T7s zCr@1PT4tp7SwG2UgG*%NrTRI)CLV06J!Z5xbZ6^4qpgdc1TQn4c|DRTa$W8H^>%x{ z1SGgU|IqvOHv5`5BdJI}hnh269Jek%GgISRrW#McZr#bpx44FF*wU*X&o#%#dqv3C z?D8#%Nj2B6y}ov>-#!2Smi~KkGH>MNn3>Ns?Y#cQlqKFCo zh^DMLZNmD*vZg<+ep#$>>V_ikC;8fkM1nt0zAnG6?!%k#S4W$JzjjR1&VLwsz%1o` z;E7`MBPW-Al}~?jWNV%MW2tprNBo+ER7$2+y0eINZ0rz_+qYV7$(I+Kr@Zj_a&>p> z%6)ga&u-nZNULEL+uet0UX$uGR$VR1RAuk1H*qrEc`kglO$eW4tHzE~Q?KlPDY5IM z!`+-ULRtqS^p8z{ty3P5Aa~E#KGySizUBiroQ3pv_<+(a=H{s-cq=8kM%~?WA8nmM8YFdqt8b^wdp#i+H&TW z_8Fnzb@itGk&6pvhGr|x_HO#Q$gAnp^GmEIR}Fsq9X~iV)5YF=%I9*fyld=}c7!gU z7I=j3S>uHpo_t~}6Tcsxaj8J@(+NK2QvnkSC!NU_+vf8Qg-F~8~{;`?a{clx@^Mthvf8$5x;#QV z8{|W7%uy_zydo;j$L2}1=NjgR&%`Af0;6ARC48G=R6T#*`h(_g4r}@!sL=Y?N-(T;{u`RywqPr`dX~GzXqboBmu}YdVYP!EJ?27xI=nsJ68~O^Nza{mz^1 z%b};<3!L^}a+rFnB_q&@=S6&Cj*RicnSaZF&8YeM@z1BT;a03 zcb3M6JwIzNizzf;c(How)Y84nUVqBxocN*h&`NRTM=P!CyUWXVUs&UH@!y5|9-r%C zbK5yLUT_tWf6C}x&UihB;oy3fBVFwW9=HdDKFz3KAs?*3cKzk5Yx}Ng-(<~85Iu&Hp{G3FCLHZidk-tYhU?)y8F zRT-ypZ!s$dJ(}%*tmXOK``(fv3gLV16utT*$LIaV(XRG!--oR8rGa6pZ~llS7bP#U z)ZKsbWxb^+vzSg*qSis}w7&}-Po<(c;8 z8Ly#!onvb9jCcN?u>y zY`S^XIa`%SX~&HYyz%BgG^1`BH+OG8Pxh&!`g#ea+B!$~E$dk@^G4*Uqvwq3eYMnu zUsq3K^IOitq1+j|xbFwcJI(ghiuc$Ty;*ZJ+(tcB@MG_vDLW_MULDl;GW*Ph=RrSg zRAuZr^@`0I3qRgDIioSL>3%JblA2$`o|8|__^!X39DC-tNwtRM+N+Nb2VOY4;Ch(8 zRKZq<5U(waXPf)lr9SsQM}bI9?Ju%l5<$Ux~BW8RtdA!P7m2N zf7*g_B_Ut^C2#W{J5*Lx&)lPw**)|AhsdVLBQ@EdvV-D<*IItE*vT8WU>&iwbJ=U9TPn-8{C;Dix4OV??}UlwoplB>@kZ_~ z=a(%rsE=*@!832O^X#9lSzZ-)50#vq`ejbW=C$XyzB%;x@?6OhE(_msyYE%;4ar+wZd0siAT2Nu$ zeBfiRcw)!Aof@+Yk6u5%-1oNH9=R_cjy25ey>Q$9!UbWm`ezxJ0xLb|Z!ufx`+9l) z3~uHK86ll#C$-+mvG1OEf1&lKvoAZ2F1he1E9uh`Cq|3se$kI^z2Z8z=8^$N?9{w9 znTxp>pXFCi(G__aE$Ua}^IO4s@fikVQ_CH%)y;nw@yG@Jd2gtxP=D_6*7+SDnF^|- zQYW1ZsYqGg^L6f_DNBm$nTo?sOucr`#^%nSqgR}w-1OAqrUdxcS$H?)cttJV>*=u3 zu>Aart`9N61w9t6%dEEf6y7cmVRyFnTR6kAH7d6xbxZRL!}GCLYLk)=ouA!aZC$w7vDA5GW4gOX zc;U)}XJyVy`L#;@n(U^oxy!d-UVgUC0>$-nXKxf=m*>>nwP}T%)8E}K7we=1UWaen zF{djt#?Vywi${*yzfC{W%!?)ONS&_VshHQ>D6@IF8&}JME8B01{Q9#~)p*s1SC;}; z-nvj*DD@GScpS4GK`Xfb&IX7)sh4eLN_)9J6W40`~@|r!% z?n=MU!aI5&v^CRvn(saR*^nyP_0IXt$*d_aZtm>)#n@)Q_2|bb4fEHsM`wz#%$3l1 z^QxXnj&r-1`;}BzyFG=n?^CDzxx2aKdHRL6Q!|#fo!GxYli~Zyh=VPEwry)^cxw3X z%%SAJuFGfKK5?zB{WrUn%3j4zq1V&O4nNx4#dG^Y`_hG_g z?5EeAOS`t?yu`{`Qhs}88EY6{O=H`>!SZXz)2X}X7lqcJOW0hg$t8FH%P)sxQ~U#d z^-kcQFeUCxjm)LRDps*GJWNf$2R)w~)%@~QmhPAEHw&xecbVm$S$Ih-{PR}*rn)tL z6({}`Rc1f5UKiK({E(?`{GH_iZy$z*+8ku6W^{FU{o!WV751s-Z(3|cK27m(x)QWA zI=#pB%MZoK^U^g%+v_hK{qV?DrNq?u2gBzLyt~eD$aPwBuWp7aMJvLYKI4sMkG;<~0k)+0zFO3W{3 z*S4PylYMyg51){aesFI0@&$akvlyFeM88}t*W`aGT_|DNZ zT_)(*S}W$33{e(kzMMIqGBnp*s*9}G3l{@7f^iu5+;}bL0?Jqc{TvS;gYTDi)a;N&pw*FR) zbycUEwc?(>v$ESLIA`OY&zHaOrpqsr*=6Ju^zeqR+$^8qj*?mpSG5<`bF;3Uc`97P zT<^4dN2J09>m@uQVQ=~N%_w=qqr2=>>*8}?UbmlExBg>}%AYz5j*a4OU3^7RU)s*R zk}HynIgp*kz4}$uzB!LPZ0^noES3yYxx8)(w_k6|se_l@-JisLX?h(a_|Wxm^f@;h z-G`g&LR<^&toL2v>v_$pX}cxuXnx~dhuzyg=Fa!4Z&&7gToHDec~M@ZN!_34h8zZ$ zVi+v+6T@P((izx0Zi-H?s0`6@ORhW2TsQf-^JBxRrLKGebv-$pySKK~O;ycE&~&$y zaCiRx{igA3`;GFJ@mHqJS^1^v^6G8YpY)u2F0kC1Bv@>G&hFIZGun%|1OKcGGd%iN z^kKp$zI$_CwAU~A{YT)-Znw3(tc|6Mt{r&&ZG(;75tYJ|lZ#GXQ9k-}w&M}Dhex08 zC_la2d$+&&>o>kio0q5k4exa+POtqor+eq0(BoF`H_88eGrRoL_A3S}0(L)d`d8_> zd~M|=$$(jo>+T-e5-K4*=jw+|A5$+d-Zs2;US`?C6Qwh6I;L1&u}r8hI2G|Dv}Nnc zc`3=Rn`AF6c5#VuimPtD`lfJyYMs}~M$FmKDWyK(#5(G#WB*Z=xo zer=Yy?B%~swljYORo8QJ?(ki}-n6LDOoF|+Fs4HGYjckL4!8Cd1%`nf)^{V99=kN- z;!>5oz(wz+yH5wbSZK8S$Y(9tvTYvW5%JGw9qc^${HRTI)Wf!e(joi{?y3|TC0IRe ztdAE9SIQP&?qaY^(E0f}mc_fnw{T2tp1+;DhNGi(RrIHuIWZF$-i6F<-O^)r^eyMN zD>bh^-c0vUxHcxC(qk@E6P-=uf(Y?GGD*vmsu?5|Az~cFUy3c zPn2BS*?#lkqBXY;?slm8{Bc+EuWN>9jXrbcx>(8(3U98N^<^|O{FZw>dU_NO(PcnY? zt(SYIF>POV!rLIYQQ@&im9}Y*O?Nr`s&8<++q`xp`XCK7-bux2xYNPV8wqb)es8=9TPAjxNnL;`QDcyBh2h;(Q;e zmgzN$olCr!5OwZlb(ck@f61;pSLbJ`%m}M-;q<+oxXJuR>b=T6cy8a|ov25BywX|5$d>rk|zl=8;|4B>BIF#9G& z2r2()O!ZqY6*(o!YXAOaeLJ}8JU!RXV&aVHlC`NZj zly`{do|vTjwcqFNTyfZRvhkk}z4`@5rui9MzH#%Vx%aPZ-L>5Xo0m$9#_fu4F30r*`lFo*Au~A^X56f_d9>|Y1NmG`w>P-HZNzN<-2q-=|Y%P zidLFV>GkDh^^=lMtvktAySsGH&dt?R&Ysxn_cMuE_mkU?FF#uQ0=G+7E%e?yso3aI z@u%`V76#nsdJR9gJ_U{YLrjKDD!1%>8cR zhKFNoX7BCG`!MU&)|~dMS6MC?uABF*W|yPj7w_YFw^FlTOj)(${J{|Js+S*M-p(4ob7P8P@egNlFlmK)6@1qQ~|^Zk!Tp&bP-L)~0RK>rxQR+J5fK_EoDz z(}K)ZrXHN~FJR+r?G?9dmzcib^=|C7wuH)T&7Dy?fes2~yF*HrMQTCwZC zB3DFK|2l>9W*Np4=e$03@Y9)3|Cu_9gb%HFaZTlHt3maY$0F}+yFNQeGRM@rcpj=h z#&WXb{()0@of_w3dv;j%EsC4d+O?>4N6!(4UH6TaE6vvOG)okl_b5km)2TOXC*L$# zxwQ+6oJ>@2Igs4q!Cvocdv&tIQWl-M-NDP)_C3-I%Q4+8 zI{=}6FFQuygs9%#mZqsTyU!aQHxanEyJDZNz&mKS7 zRcWWybhh2q;L>BS-r1YD#3!(oN_VR<8{b?JY3Xg?%p39N*{AtiNBGV3+p)U&zE*v;YW~+HQP!8GuBo+d zU;gs^4-@MKQRBJm=BAtau6mxDU7u56B6W2aU(U1@Q@8)_(D1p)Fn_xICE06PcbBr> zZk|;awZwaQk3gf~%il}7nkEP{`FoUVt`;cOwfXpNv(1bcqdrfOgLB@srkMt*Ma_Rq=8D~BB@=EClOk3l%JUWE& z^fRu?IVMs@;mh^@_y}wKuYA@@=}uKmuEPBsmh+3O%9rg~ z`)Hp|>aX?O?-UkZlGWZ6{PK6_kX;x-$zIC)%0H%FYsl=r)t+Xsn6q>JSF&A>Xu-?&H9Hor{rB=`g4EZ z8M!01r;fZR%t^b{Fq3QJWw*B$*A(A9eUPiCY*_px4C-_`vW zwM@0|epJuUf6v?Dzybc_{bfPZeka%RuxS+OGQK(7rlxgPYUaFBm4&lcCd=J=_9FO3 zNS2-PpU;W!7KfFVWqoOvypSU{#chTO|1S-ji#Gzi0=+xaa?=cjQ_@9ZS(!t2-fk*- zdZozLMxVK(=k*mIA<<%G%Ztg&IQbiV4?5ay=kM?9E0e5`xL$Vn&uy)zmrrSKmp&BZ z=x8ix`pmAk^orZsN0Vmi|Jr0YKQboTBc@c)@`3e9Gy5~`?7Q^R)*n5y z%=}$K&++WvcM6v*l&P0fxnrO4mN6{F|I^Y%9w~0w`$FptBu@+8u;|S`!`+~L>7q-B zg-a_G zzTTCPyRh_@{MKKVa}72paw&MVoa^E%lD9IHtO$Smd2GY>(6F3y3b>b z;1ivu5S#mV_Sd6llr6Q_8}9M?)cA3!^|7PR56KiT=e*%Nq5o?3wbk;`?bU1Ve(RRC z2?sFCt)t z&h5B8-c~#Q@z!^CzF)ICaCy~v>pik1cRlmx$b4NY%lA4wOeorTp7nxx1uCN71s1tq zmyIcHe0q1?#kVXhZ<_qv`9IFtBCqh4sVG@?k33`IC&qOfEe^H1o{$hWKGeOeaI5?b z?)n@iMVo@YZuu#T>N;W)dDb6#;&S$<6l=(3HO}2!d3(Lhmppd*CLs4Ay5YqE>-}C~ z)^laPXtL>;er0XxHhp+aRnr;opp|88b4wqwnepy0cS3{y86e00;;Jx#=s>(Tp9tK$u)b-9`)kAP&X#gB z>=oZ#x8vCgb+ z#@C9QuDzFw^h`Hr24HykKg-`Iv33Rx)Zt;=q&p*D#os#qj3ZJv=(QnSaTP_>QJ~~)WKmAFJsb<%z zdG{>2uf5w_we-(|q-wVoz9zGUM+>xq{g$Q8FWuKL`*E(`hs)Cn|7qT+KGv&bB_(w% z<;>?>kc!?nEtnU)>rzi4Y$F-k++puD1qTlr-&O15JQd2YSU2Xf-lCx{3Zaw-@B3|o}w80rY z754P4|GGYJE_rM)*HOg%M5z5C3#WXkxwG=M<;uC|G>K?+zpY5{Oosd1523mr)wNz++IYIG^rT0Wkm;4B89yhu?)KPre~ZTC_BH!o zEKxEGpJZE5XkR?5aa?xyr37hSgI#9!)EX1TT}Yj5WMd-cw2#}1yq{hjr9Q+CUx z6rr+7I_?Wsz77bRcjdzQ;FFps)b5;`v%O8dL-Lr2xl;Netq)i0**_)=WRs{#;RAYBT+QsYLO5 z^|bS>iY-;^YEI>{`fy5=9qq2KW2yQs!18N`p854VW@__XIvxqgip^<=e=Dp*h5g&G2O0cC+pB z1x0C6yD!)4$J}4dJ!zAi?liq!dAfe_>(4c-sTCGkH1NG>+_yXA$8o2JH}mfwt7rZF zb-wFSEV|~(=-1;RW zTrkVBenYpC-?I&~*M&r!z2FoiKQUReE`Pn)z5VfCdnc+(UpTPEP0nr3{Iz;|AMYmx zUE*KZcy#F-tBya0xpvoob)AV?C}}#STKM%tpGnRBYP}0L2fv8^>iFZK?PiH3Jv{8f zmma42>J`>cW;J`YXY;AD&7GbS%;h59Dgw(`EKL?LI+}Y=uUP$~vovhOPu9oZK9u}? zl5&^7QQ-RdbAI7m-`;;)8GN9;`-AMhJ%`>eZ)Va~5#F`?D%-J*8;@G&_vWU>8m6B; zXuovpC5HdguAlm{eN))N{a3fXa$tP$I>ch*c?P|&oXhXU{heDc`r^6$g6Jh?VzT*k^k1O&pHnHn#r;D!`F*T@{$RP+r>$uc z#;i=Ic(*&dP1KV>E%ksM{gX^sO0_R^jDxOLY*FC6Y zH%U~?PHXj;BiQK{^R7-fnv{-dL)jvW3H7Bc zT&bt|R_d(u+qA@KNzP5Ksl4siMGg5}Hs&mxr4!=Kb#+;lhHujx))PGQO)Ta;Y~A)( z+>Aed?@@)AeV3+aZa8{Zy{{3?l+ccfI; zc_c0HNE6nNbW-2j^0N3Mzixb$cEQ4e^U2w13@7rG7Nt(NP3`~dQ^mw499|*9Q?V&g z?AYIhnH-N;PXrH6H!Ds$2gX{#vbaI;H{!Xb|eRzERfnrda)AbgwcK%P3k zSx}mEy>4skqziE|CcTa=tQWgk&t~+gt#By2ZZRt$>A8tVaQKlc2QK{jZMXbQ`TfYX zf2SYY|M25w@!9U{-}lxFr~J+TVN*K8Bsl!s1rxoGnl}&hJ=(J%Mp*qY`!qApPf5a^ zL5Gw%KmUF(i`$tjDXon01jRJ>ao?wGi(ZSAd>dqM&t zt(MQ-Vc7ltYXLX&-YC`G9S=7}&)CFNw%*%f}y>JoB4%3~wlDqFROcqwywvbzD z_Qs#rl*)bDAFHmby)0+BSNtKD$eClmj~;vB;=Ro|_gt9a?>Erd z*z1FuXY6~9?%i{#l9RcL~LAu(@mS# zUD7+S*rHf{-kGfptgIW}cHVH{)13QbR)^Pu2RV289xhR;+9vYZHtCf00kJtnYZVX3 zTweB-weYH3-txOaWqG$;X7D^Vw0SkT{_oeU_qy$kHEBI-Puvh^e95*k_#%`2S@lPP zR|U0Z?`3@(+$gnk%H38!!DAQV-y4Z|)`%Yw6KNDWzP`mRWqH5i-y63K^aY|$U7lT~ zdw*Hj=Yy~3p7@*h)Bog_8PN&PY%Nu;yXfzfofNIpTxz^7@yObD_wApA9geY(ezjuW z|J%Ox$rt`#{hj;c^@6*ka)U!ZOD~$b zeC^Ux+)TQQ}JazMGnd%%a-c+m=PX7M6AwuCFr>xi-P* zi7$`j?SF9_GJ-taB{QyUaee#uY5eoa7iLfU^;vj(V2l6WsHOWqocyO7ru|B`{$0r2 zq^J68epsp{G*vn-tmMh6E?6X2IbZgU{mJx)l7$z32%VX~J>&j*ZtYrSOV0^@+`AK2 zJa`mwo`LC>=Dqc2vv0RK{@&Y|7?8ES{^=BJlcV!k&+nLDCbGoeSYa{~;{;Aev7O8N z;_~ITEsIO7U3g*LIj^#BA@d$B*|&01A;$@$K`W1AO0 zz1?~ytZM%RyQnLR6Cc!tRLks^WMZKq}X3uaZMwpKE)=>`+ z*PZvH+{?f0c%qKZ8Y8*i3-tp0o_F}LZR*y1qOl{0t!#ysp8s*S*VA9E-!kDU^V@$< zRX!*G%5yLfV%ifs=YHqPSWEr$6J~cmit?1qUJ`p?&l-Q(wF07EevL1`E7{*(V12)` zxH4K(w@zAhoBPSIi=XRnE;rElQnTv!bW@3+KRpUP_3s{ZeX!isD{8oj)&QCQEwZ z%aRQ)jBlrGtLA+FZcEHW!LQce?iQ`uZnNt6riP|vMCao6%pmZk2p|FzGZ0hp?@u`hSD-e)}UI)KB}7 z+h^n8(#;xTNRHKGZKf^++agIp4glYVnK9o~wQ>()znZW_dxu z$@#(ec=xT`l=rYqD&usj_CDE)GA*@E^=^#Y~( z>MoyMpKta*xqf|Z2-~`SUz1<|$p7xykjJN9V|8p{%IqT|%YQCUmYKg|{)*i%{)OrA zM*D4WS(Bdj(U|*7Vs@8@nwwYTqob!zvAp;r%F45F!TH_KUkIixTgLt~vg_}YqD_Z1 z?>Z}X*fCY}vhPt?Sg>zOOpf)7w#9ZQRwUh9ly!RA9oFgfC;Lo`XU;pr($F(~dZ_=t zpJ}P8^FQqj_7T`C6kwDS_iW|Hvnhf>=8JV!sd06i=y%;0nE&mU(&crEO|=ggU4L<0 zeZM#4^^cc-A~P(-qkC*?$B#oiV7-9zUX{kddkf6P?Cpvr#Ek?D>)(tp@a zE6fRh_~YvmXVnumO+`ullFC(v{0!-F9KNXu2a-=tp6Bgsb?^SY`1A{W_4B5`+#RlA z{qU*8dDjf-i#3bY+|<=dEjNZgT^d~C^{MF6!rRN57%psyPPZP{ z8SFZ+m@}boLeQ7PbMGuwXPtZhi-TwV$%O`fYg0c?mYin2Y%z~^)rr0}2C`c=cdGk7 zJZokDe?codLx6$v4C&2Fk6Lp+sMAyzV&Bl3t(m#SkT+!N78%Vg>%5cV3puScf@eDi zOF#SiXl|ICiqX;4?vrQif2Mrab_?UH6!r^GsupX+T%A?;{k96vF(u7?O=bDFBPOnq z_o+YU&vo)l=gq^xoAu)ExE_ytBK6r}`cj@JdwyQbi{2Eq;E3JtGRB|Me5OYt#PMZ=Eys|ITbv@chAuMNH@W`6*A7ko zexW5AE~#EUyz63A-fP5uIr@It#q#=Ix3_f`4fUz3mHy`hNvSMvuiAWm+8fm?EHW4L zd5X54^l(4V`qfG}*?LaL?jz#wi)I}Z=G#<%A$;F*=G@QvFXkOSooD2%uX9Rk*)`2$ z)?1t2N!Eomyq39Nd;ONZkXQ%uzfh>oURYe5e3~cMfCI_kQ$+!KmBwyXWDoJNi2JKHhA0uksU`=5_mE2;1tCUnyHPw56fOEoW9Xp z+vdGoTA7Fs|7L5x`hwMhoA-6U-l8FqA!$B&wcpAONh=nAxlpsLN9x!o&z(WGoBjR% z2LFCDTeQ;Fw=qv=Ih%`@V5OElYiNyip@Hvm`4Ua1D(27p`!>t&NSpTUu!P3^#8@JC)PAn?Vhl0*^#H#F?tTnO6x!T`c+n6!Kl4+U)`4~ z;d?ixAGDr7?}O-J-GD_)83Qs+q6<+qr@uI${_0_7YrCwK) zwnnTJZ+6>wkw@#F{O00K!MRCnA-VO_-ieC|1@gRTY_EO7bFh3?(yW`Bb0U(T_3kYC zzVG+E(zmk%E%>(V+-GjE@ktEVxu^f9{JFmA*58}o;@3V~^0c0F-r2wZi+{go{O#|* zYsMy~Sotqa^Q@2c8VhEs)t^dudL-aXJ5zk>)FaIrN$-mC)O+35UFZHHce0~1BGxx* z$GiII%|7m$KL1w)2P_dd8CBoo%Q;7K^7Qm?nXZ*8VoiI_Z#SM?X?Jy!WW>q-e_bb) zPy30dM)v64=4GE;{%GHR(JY5}7oTq}@9*yGzb^2kZ=!R-MWZ?a7JUQe6J~b}SNu8{ zanDrEa)aYG_m9nY7iYNqZJMy1x$uQ}BPmSp&@9&z9Q;s0w#Pn0_T z{k8c={oW}z|7%*Brsw@X`}6Hk~w zI$k^U^yjbtFTH+$qn>wn7O(8`KgX}{4_kTW-2cF{H~#zWjhT1*|NQj7t<_%-eNJOZ zP>EQuGfcjxxlyXsC-kLN9K+RpVLD~A*Tt{7uEo2at2=geqg~({)9$0o!oRMXT69s< z%&YJHw3z)buhi^+va>fy`Nc2S<32`n)VD8K5zzlfF^1*ujYHfT#; zG4_sJ{GWXRc_vn87fE07`dYL-Y;9Qg*S_E*H>O9abIfXt)@Lo_$5B@3qMPIS+m=Pl~?}y?Y*+r zeAnDv(fMV}%LCV!>~`E9RPy?0+R|wLdMVchit8`unrY{44$%zNsw?*UAK&nAb$r9W z=l|xf@BO!0-v587>;I>ITZ8k>4sxvvu@>b~Z2j+b*6Zl%tFsRX{Ykp{a*7wDM1$#i z&N+*Mb1M9{zq)R7U)x-|_}Bk8U*ff_i+}#t_y6C(D)0S2AoODW@;5tp_Xn3W3Qm!Z z<9tznzjTjUz|QD3>~piO>YA^fT6Mkrpp!<`QLnAhYo<$wE`MQ?{dAf6^8e@k{$ITm z|1ag&`jqqkuXvlL`~8m>{TuEr@BQ!Uq(ybhX+;1{j<0K|JC%Oed596hK#FLSvW3!Xm%&+ zW_fek$;`65MT=kWGF@LE!?Kv6gy}kS<9o}id1v!WvU|M_uMY8^yX?A-=v=p(E6@I| zk8k?7zvZv}_5b_LewEwJ`zQQ+f8f`wvtDcYj>P0y@NSRFnPMGxef`xt3+`l;*)1c-k6~}!|Iq5F-{xo6rRLq|ZSvdstYT~4TBfeU zbN<;||DAp+-s%7R-~adP{bJYo5%H^iRoB1lqeZeVbr)Y&JzW>izpF2NWx18;_K=US zzouQ*zS<;|Ct&g?>hkA@g%`i><&$8)yDGSTW;N43mcQm%^XLE5-fH=`KK9G~6}2XR z&4v6I+&}PD&$RpKfx=Y|KO4Eb>MyUYSemtyZJWc&pp_Yb^LOD?8W`BEkng$Ebd#lzw!E)Jyi{Tw#%PcO)c6Q z`1(iP*7~s56}?ecSC_upx-8m-ci|mP^V6pKGcNy6U;h7-{9WchEB^l9`S*Y6#rmI% zkJejG{Fk@+@*3-_K|7;z8<;K}+;Fc=n&ocR_LpXVidNp#2(>!Ob>iQm+qyfSF1o!k z{LiLft?J%I#{K_(8hyDxoK<$3+yqRZc3JDzlucUT$pwVQYU z%WHQx#UDKL>8s!7==^JUywpF;zMHmE`p4Czi(gmw`Yn(8CR+|JGWIw8i=TV^e@*U} z{~v$VFJ5@`|CDUm<$;B#?glN5Tl?^=;L@tC!RxNoY`?v>vXNVh;RRzwz>Z7xYf82A z#80dVJR=sJPUz_~RI$rGf zth{Tg-|@9(ulEIW?va`hbs=Y3(}I}wmQyzcudMbn)-a##S`Tql%U}Ec|37cN`2YCr z|Foq4)4S$Ht4!Y?U1YO8B-bKu^S%0#UA=jizcy`p{X1^+m5;N(wq4h~zH4dT=2w4Z{u68Zo_y7OTm-~Z$34N?D{{8>;qWS|({Y&dtta`Cu>W72++_VcHtwNVSE?a%p zZ*hqBb?M#%*=%u#*M{zvtq94w@+WQU6X%b9YsIE`)m_##+g<$Y|DG@L|5!UokHe%o)a zWL|6ibXK^2*qoxRKi&7#neP6g7{Y(F^Hrnu)GWWljJNciw=->L@z;_)|8aHirtp>K zUQe@@-ub%gY}Dc_y1%vtZN9j|q}%s+@g9b+Q~t|6uYX;C?ZV1h&Y$+n|F7@-$H{Hi z#~BcMl(Q*oB@>&&+9y-~ObXVlbe-~E;l1ttFrA%t40*rewqJaCt?Q_lafV6k_D4In zrZM|7hW)Wr|MBO`fA`V`ke}Fpt*&5;*A9)mR z{$F3+7@k>XbLU$2lsRsPi?wC<2bXqFO)~uOs!{%m)!n4cG3C2`@2}r^VN&$Z|2M0r z%X#*xoG(82SF_`gOc|R-P>7t?D&rf$?+g98-(+r7aB+3rZF$)1n%e7nL)#hr`;$Dw zstk;7rp!ohOLbc{SwZ>EU8OTNZ@!BQhE}>LT|cwsP*?-^kNpe&&Hw)E|MFw@^PkU` zU-Lisy4fq4qp|l({>3?LE||IW(W=!ia;|z#nSQNu&3f1Q56-%~@5ugN|GB=ee$SHs z&(Hn;yXA+wO}G8MU-g@^f(~6^Ds{SA9}zU2!!Ne)n)3ca?m0(Af;nrG?-T&=sLB-!nK1N$x{kwee>UlPg!~41l7hkgcQt-QZ zV!=em1=dq0HXhveKm0?z){ycx;_0OO8|NdW_^hbEg=0DFD zZuePWnSOlT499(1MmrL;8g#umXT1F6AA6P~swv-$?V?7#-j&l0ixUsTG45!p-_!7a z@BjZRKlVTWxqmIgvgGCO*6vWwG?tn7ao_nM+veK2#)}Gm{l9Ygp17t_z;gFSGsW8G zU2p%h{)xZzzkEH&*2^#d*jHWnKRvqbhY3TbM=E>om+#Drrv+I=&Ae!O@nrdjP04B* zP5a%pOgzVwdH?tS@cIw+NB{j__y7NuAJ0Gkx&Q6IW{IfwCN`@kna_1>KG_HMUOZ7B zUL2v#w(d~rGznXWE$U@Vk_tKh=FhJ`c=rFZ_;bJi^Q$#{+i6kt>+_Y8moD3~7MC_E z@01t%`|NYV>9oI@$`gKG;P%xl5L`R^KlhLQi~fJV_y6~mAJ;$sxv#}=M7zG<%YA+S zL3WQzvx1&#NWM?kVK{o_QH9;4Z%6LG%DFgeVVL2iv;SHDy#Kd<_WwQH=Ri@yzUz0& zm4x1-p4KWBF@-)wJ*^A(s+gxL7%k*wj4|5d_WWIHI794#{c#)qZU6h|4LS~Q(RhLcP9L=zy80r z=+FH7|F7TvXMc|K;8dYEi$yYACcUfua#WDx@eCFvO}5o$j;tAqVu9W39i3Io{)d0q z|GPf_-^-f6`nGHSyE43C50<>-ztPF!Sk$hF{&@!srg-h>-ZG^jl-pOUHZtAK`c6wd z$aC=<|8M{P-`@1!`S<^ASNxZiIl>jN)>U|MLIFzyIpT{=fVpzc=-NM6~3$ z?H04D{nwtdiZ0<5j_$Df)XYxzISKKnOmF~1mV`$Fv_2Ln0N4$L}s?(U=wL5EIM z1$s1U9A6M1v77J1&Y#EApVj~VKVRv8h5UbW{{$vA%Z_B-k7X?k$IRHdOy3s0Xp}j8 zV6BP#(wjxkOM6(8G;C$t_VRzY^XIbh=ly^G`%kRj)&Kvt-GX{q&;7Ng)9beUQJ%L> z#RYv8p!Q^e*WVL9g4Q5hiA{=%eno}p8Nmb>>rQ+ZvT}3alKam_5Tar z{JH=7=YR9xm%rDyte;%pc>CM^`TyTmeB;&q+`fPRuYc^b@7MglYccQ7vv2>*=ct=l ztu51S?*A!wtv}U%OO!{3h4Q6|-}w#iX3zR5krp?*Jo41ig>t&=|9>2Re=U5y(zE{i za`ykiU07Nn6rNN|03T1*8j^t{}1_h+Vfxj=}DOzKVMf`{?)H4WXAI^Hj!GA zRZ~LO$ldLDHp5WTpuRo4X;;#go23^k8vi^t{qz3o|Fi#te;%Lw$3DY9AmdSlu!hCr zo>1=#D$Dwk9-nR4v@xcyBsDmH>zM#;(fSX*{F~#|Ecc51dnxtr`>+4c{;&LV8Ek3r z9jS*hXM|dUyiVSb3lQhp7HKlS=jPLhS#yjx7O%54GT9I*b!K|T|DSMupTYVrtX)2t zKU>DOqnCfRz3`&AL!Yy+C|eeWtXr70d6|;Wv{~o<(&gp!C)Dq3`@eT`O%`u`43~Ls zQtp|a->kCX?*)tm_Vjd~krZ9vHIXN%`fT^>#f3>`)$8^9{(m}dfB5+G|8xJ`Pk#2| zS^ek#BLDiMzfNJ0VZW!;V39T{^2UtATtdv&&;A=LxxTq;ll<>m-_Ixa#1ki8^y+Q1 z`MlxJKjYwr`v>a}_FMl~_wT>A^8ewx|Fi2q|4;eH{cSVXg!X%`9{=(iUcESJK|8M{LpYr#7 z^w%~2o-f?4HuY|`a7K*Gvnifi*T%UE$Hngb(x}R2#_ZB?mCb$PCM}Z}5?gcs-tQM* z@_)(KpI__i&w~so`K!J*{i{8H?F7~cE%#L3C5Bf-my~cai1u@F__fD!Jiodp((!b4 z1*^i z`%D-cmrmW4b+{nNe{1gKlg}PV%}*4&QJ3@gf9T)m+SmTqXFmU*|F?eAzt2Cv*4J(L zCvRYtJ#&>x%tqPAoZMHoMNF|^TjpqSYsz`n+}0V_R{EypyYHX0@z}Nhe=8h+{h#>U zet-Sn`q%%j{a^mte(pJjhwRR)Zi{>mO8fQuVAS;$LC-Es6Ld`czJ>LIVE?qQYrM}c zcfUL%YWI4(-*Nx%_lqz6U;mWp@BP>RqyPKAsJC4IpMO4lZI+JcfA!ta9u!2Q2{+5hWBBGvY<{=4k@Y`^`VedPc7cb0sc zZuX#X@~xLw`v0X&QGc#=BPns~)kRA}SGd13Ke$5g)?P7AZhI+lkA*z~5v%HRtvAT) zyZ-+e`E`Ec`TsY6)d&6mX!m!2DYN7AOP4toRG3aRE%_3)UQ{x$58ZwN*jCKA(vGwtvR@!2W4@ z#ov@{uU+Imv~^PWn+q40CqAjv)6ej0L^7>x?KQjG24mM!dzsH$> z>kXEiX?M_N&73L5`cf)NW11H0w32t1^`@+P`EPdQg42fUBMzN5Ty3!J`hIzR_x~Rs zf3L5c|4;npPy6Wq^Oyav*!G{>?#+Lp%3bc~>d!pWTwohpvni3uHb3OrB*ueMt(Pv& z7po8O$_`O`rkiv3c1;!gi*Kfvf}i}a_%HpJf7_!{nfa3P%Aayd<|QuV-N-xjm_tgc zsKu)((`6QKTk||Uf10C@ZuI}}kIP@yFYJ%|ul@en|NQ^;um4Z}YM*~~vzP+^-n9&Z zB|b;ZXKQ}oE@3n`nzh)cY-8rT?&Azj-%f6s(R^$PPd)c6llx`~_HmQ`nOD^Pz5no$=-m8l}XEU6-wOuDkJu zWZk6Ojejd7fBBzZ^Z)k$`=G4#((dp6vy5+Y1a*9NxEX$1;a7hzwo+`a#OcbVpZu;| z+nv_J5Uir&%&f65;1wt&-+cXV`D_21fA6FJ+c*51|Mq{={ulorRkrb-X%XG)n{YWO zFh`OvLW_@O@~RHOkSNEgwW%=%9eWCH$NjI{qx1K;_Luti|8xJ=gR|5Auk|ZsKl?2D zZp39^KIfjekIRRodiUfFw+?m$y?576O53AV_OSExC$HSs|LgWh{9SH;?#J!pSL;2# zzuNfE_}be4=Ra1s!Ryyw@)zMj|LH*uMK{g2n#{rPo2 z|JA>!lbLM%DyrG~EN7@=x>njl!yg%In%4F%)b#fXTIlt5^IE>uUuVTntKVW?Z}k7$ z^Z9=#^Zp3`{qgq4U+w?p*6*wRaO-*MmVZxo@3%3C$iGqbf%Ez5|G%z(-1`5+^7%Pe zKF(kN`K0}yk~6b?rq{p-K`*P7Bx6JF*pYggSkaB3~@ z;|Zrur+zgv_-lXh*uj!18;)D0%}%O&bEmofb=F0T+Q{C0D`vibGWG5Mzd`@GPq<&J zzf%6W{`K2 zgQi4F%lkE+C!F(z->xZ`FF3VYc%i6KU{>ZkIbMdl4y)Hb&D7k}$t5t!hhgy+#p3WS zH79@dhrjq=-}is}zx==U53JYzueki*Mtbr&p9x)>*EW8Ucq4eFYTgH_pWhuCS?@7% zyJxKqNiOeIZL*&H)ce~1bMlq{`|m~mSH1Ul{CpWxNto z?mJklEBU{0>C^(*pqw>9MwV|~Z-Wf^`z!tb&3XNc{ zuA8veAXv?&L`KjYD?bcNS-Ma z_4*FT-0NTVpJe^D|N8&!|LPTg-S=Dm{%ur;kDEMO8TR7RGM7`dr_KB#D#M-YliGi=|KS?!R<2>z zdFQ-((Uh?Af6uS|kH7rCuJQl=-}ZTb{|9~9KmYpwy4(Nfu3f%Bx%$`7i(EZgKkI*9 z=hFOm!7bTD%HT|Bb-bk9ixtxnoo4ne+wisi_5a^r=Y!foQ2(8OyXD{K+>EW7ne$|1 zf>&IR(v2|Sb!fiS_}b*4($+OAN*Sz9s|PN_kZH+|I-)! zf4b-2{bSeo3OFyFxUkbF)7|??kYfXTeQ9Ekjpy7oCX0RMRYqp&x9JznTo{!EYV&=6 z_5byc+vOj>fBN`kzTEl$&Ivbu{y+cu`~A=R?Np;b7-y%yJ$SzTeo<4G%-GKqPu@ED(tP)OT8v8~vRM~g{qljANzwl7qT@U>E-3|Yrp>))oKoaMY2poS$LRm}Z5lfbZ4Up*zgGTbK6lRF`>*Z&FZ{Wk@pk+6x594OkGFr&{ZqYo z>;7NSd;aD9y?s0W_tOvmKR&N-o>Km-{`0s0>mL5!TrktFy8if=#(=;7X5Rn#FTbwv zLG#BtUbWJa@^=Aq4A#4C(UV*w6ZolLfP1=sl-;yK;iYk(R`|`3|66UdZ@N~+?~fsW z_5UV6ukYTo`~UX8``7-DZ~LbnpRVg5SGD@Tq+`a$D_7ijgEHQwhIwA(-*9ibsm7%G zne)UYio3qOds@MMY{JIe`UBVge}83P_vO#~?=S4%{pklA^7#Gv|8;Br|4{fZ9d+SJ z;gj!?noA?Q!!}G)tvxp_+@#jGHBi^ZLLtV+Z5D%;@1mR6{;&Q2{_200?@WK6gObjE zj=$&mpMkn8`CsR!6?}NJP3(Hx>58p0W{4Z~3DvJVy-0(5ow;rOWvhA}M$Xx`jA#Dm z{k{L|f85{a{qz3+wflSj>-^~d`+5F8zd!%~--!P|9sh0bncBBMTURt%wwCX`Xtm>V zRozv5>ZeyXzPgs^kS(E|%ltV|c}og7;k>T@z2g`E);;R~^S}S!>-Il>+LmpfFWt(! z#1&N-CAB&(y*ch!j7xJ|gMxyZBbu)wK{C$!Is{owR|{r*Axmbe4| z*Zsfo=l3+@GjnlS2GEAGP!SeFtsVKA9<^53?SQPFXtkH{%jWIZy z6zMwQ-^|bVD?ji5`CsSf`$2BMCJ8?2&U)S3wPx9>qbjRj9IRP0@p^FXOp}wR z>y0+oG+vcmRQ~w<-2dPH{J9+W|K^{1hJUv!|K+c}y1FkpF7B+bNLSP1Nj%zzpU;R{ zw9{jGXhzp5uGc%BFqJo6J-|OBcC1<V+KNu|mBniklifNL5^@W#T-}nC`mEb% zYn7Mt(V*AQ&;ECR|9@Kj|Koq}dzAnE{_KD2_dh>X*g=im1H zJ9GW-FY@_&9hB^g&qrVIS{Qnu-A_=oXsTVm+^nAyS4YcBp3s~6bgBO2qc)dJYA$tO z{ax7j&))sNf0g<_eNgN3zw3+t!c}#4lm4~a+V}rEQ5+R_ETQki)J^fxu3GNLl)iNA z5;)$pF4lLkN4CYU7y~aC?dY%D|NXC@_3yFhul;}jul*n20qT|Qul)P+(euie5(jRa zc$)ET%KWcyO264W&3NcsC7e<0mA-7^^(V@d_dni#ZQuX> zf7Vjl|Fy6GcVGW+GynejzfWi14%~j_h-Y{1sZ~qc#U0;plwOGn{WSS|LFxJZj-g++ z9m}X!T6<*@BU8qLSIl?+*R6a1HooppS>5+v$8%Y>{rkV<|M?65;~&WWpP%^q|MeID zy3_M>|HliJf8_mhUu|IJlf%p%yxjD6 zh^hPRP`0gmOrE?8{o>IpY3zDe)%CA7SdgDd8U?siKs-4PtDZ0N=|>xrJYX8c{sjk_-VH6Zbcs>3gmzFoj;WiI)wC zn$Z{f%pz?SXXt~CpW5Q0(rfDl|9p1+^LgI?eLwg2*V`TazxMTSrP!qr#kN*^k|r7k zv2YdjPTgnMk|ENzZ-Hjp53l+LjkG$$TQ1dte@=(~dH<{b?El(7r#1iO$Hp`6ToS*( zOIuXlb?f(@H;E<>O@pMP+?a$bs&w?vUb1C~_Bv3?yWyYGkM-dn_kXW9`~Ur8e7*n2 z`q{shI8Vr6>D>5IYIBi0*RhD>0jaWvYTak-UcZ{mcxr)T81osUk_yQ`uS5U5|EWLw z|L-5yga6#$WykMe-)8gkO3&xatByM)64yJJo|9{B*jlZ}5|Ms8v|J*-pZ?|+SS6#97t7}n58@;p~-q)I1 z-T5mRvN}_zC%^mu>u3K<{`1>h z{Lfrp{=Yx}{)NKd-{jLjeE%c+^VaI0wP*7GtN#1)`1u6uzqkL?fB7e0Ao1J%>wTW; z|M{Qmm;bfD81;Ce@`t=^-o;TjR(_QXa9Pv)|E#yCvm3gyD z)V7Z~dj2B!54*u*@bCZU{<9YVjlys5c_4RZ>BU8qZONS zH&o3q{<<))N7817p2U3B|MGkP$!qP4{@;K5U;e-MPyc%^{kq@be`02Bi1upVX$DX2 zmX-GeZcw`;bx!NB_JI|m^()rz=~!vy9?irXEck2rUj84^f9#$AeqRTw26_IS-}paa ziI>M!uFUQod|M?steO@zmNwPso~>n^;B=|`pqIWvaT+>COe+7x_srcR#^LG2l4zB^;f)VzJ1+a z5&QT3y8pNT+&}(*=LUKCEB}{>?_cBe`sGP?k6r(6R7w5w40W1ftf9em@ysRH84_Wx z*<8)vw7wX<`5*dq|L%YJpX=5CmvsG){<~hgyZ;{BwU5(4_GhMzkG5=JX@d};Njg$DA z`lB{3<(g8$c#217vBzi4bzfaS)JOh(e-G@`{c|4u5BuM}qc2;bjNwVc!?bIQ%(R?8 zTj~Wq%HUvFcid;|v^<91D-CsDSePpW|HOy=-~IYOIM?}q1a$|gV*{Q3WUP|lePa;LRddveUC zbBpKPzh>yR{?aRnBc4^NG4*oK9<3C7(#E%uC;G|Ps|j_IU+Y0O{+SQ5@q6%}`>*O% zPfWM&y`{ZXBXrs$FaP}l(^4n!9b9G67jxf^qw(UAE!Ph%T=zlf*Z+&9U-!@cfA+ua zpUc6o>R*B?zaRHQx3u#fPDpoXzV`eB4_6g;r0PrY3uR}ba~PCe8}7cS-%)+ssB`*3 zP&|V4-uxAB75LwK_rLFd|HOy<-~Ii++5hre|AoKq=a+3Pe_b!>{#`C}o%{F{ok>0)<96@Viv9sxSNZ|Ji@P zf9GfZWxuws%4Akd^viSZv*M5Iy?((Q=gw}m&gawa2opEWtbpY~@8eDtmDWQN#%55q z`To&=`H%fq|8Hpvyga+V^J;d+=j12)W?st`LKC-GDSu^H_Iab_iI%zT&$oJ{*GvAi zFNytoJ`S7|?dOA{`0-}*6PHD@P8g>qct|Ijsh6&>o8Xpz>WWPtXQLHcmVCzz>r|f& zao{xd<|{Z&)q|>zulC;EpC{hTSFNpai!)pk7CP@SxPW zthY~Z0Hww^fBu8g2B->nRqt?CL#=mDkLj+yT`?QNv$rO7R#mXw`K%Rv;-a{~vkRf# z0SS$!@osnEt@8KRD#2y zYV#}KU3%?%PE4QpzZ|R&R4~+AAN{}f-}8)Dj_%&?pRJBoc`4(((r~GL!I@w0+SYm; zj{1D$^^^w;8I_^2l2_sx{{ON0`9I{_zyHgR*Z=$cO7oBW`~U3!c`he=7{*;?2|dQ+ zF}+eTMWf!f%CqT(M_(|zAWx5&yO}Q+Q{SR8`~QEY{Hg!xPH(zS-hRrr@RnV=|S*bX=DvrJ3|Epi|dp3Qnt@+Kiy>hG6AGQDCPygrt zGyk9d`TtLsfA;VH{QnMWtbshEaSx3lm|Ih zM}oO-xfrcm>U!*NgH^kD{pR=sY(m-7%$pBfONvjeI|rVZz5d_)zkCO1W;WVQp;3bG zOV=&yBeNgQyHcNdRpRJO!=!Vmt^IH7zgzxJQabm5?SR4I1?MOI?|$|_7nBe5|NGDS z|DF4b{JH;&165)xBWm?#Y+lsganZ>ni#NN=_@SKA>0>>iQE@E}jxz5gmd*e8$G&df zul?WG{D1#z{@#D(>i?hL*kAa5-=)j!t5q-Tn*3>s(1qU(l_kI0>ic4pw&?0hrLt~a z(8%j;E5!WQb@O*|{wf(D~ z#%wPFo_%_^^<3Br>4Yl7m#+@INP24=&~X2e{Q6D*!S#at|L4>G=B=*1pcGr}k-uN_ zh)#&f;+b3wT)Zer=8Sz4ez=OzzC~u~_y0)35lJzspzuxc?2(3IuCS;4--` zwQ7lbp8xg5zpryVY2yxg`r^;is3r&5#+`hbl8S4Z_Ho3q{I3!HU;Q^9)X1p;RYm&C z+3lS}B2T|?pIN{7nGpBtqYjFbOV~Dijfy(I+ThvCt+Ly#jOy2ZQu;A{^^g0%|AX39 z(}Vxm&-lOmsxixg2|_k&q}F7l_V#TpQ|(LUJ#aWGHeilwRs0Jn@AmU0TyZS_ziR#a z4k~c${z0k+*X#k2KkXEAdHQ!%mq(^&9Jr_6dzP>|F5^bRn$^A6*taqMQ2J3n z?N@x$+5gY}JAbZUzx>Db`k1EkQl~`^Uj7p9;>+ECIOg}M^;!FT%n~|N6%0(>vMU)k zEm`Z@&QT-wF2=FDT*(5EcDVD}O( z2kphh@rGWX@;@y5wBMooUf9Ou><#-_{yp9F>;K&U+kfuwuCMg^yT7K``jzhg%}c}m z8&Wf8R?14WukYWRWc)ttvd7n&(EjC4D)~{icUYHowLJP~^ke^ufAZ%4XaC>)^?%W# zfAM91|Ns8Ef5ku0+`+&4_gns}zxpq4#q@sVfBj3JjLvu`Yj2)*jCOy3+OZX4@sFIg3TtxrVXGM%MRwIm_SbVdrg%pa1P=D(vgTD5Ykf8^#PIXBc2KVG^W$a6vb%vW$@ARW>enD6(|pMO`a z>E&gIv;Ng9NX)pd5u9^TCrbUQ&GSgcq!l05v=|wm()XL}*Ck#bxiU!G>5%`CFzXGX z8#XPt+_8sY^Hp}YuZtNLJi5qoW{-y(MDXiUPdGd|==Th3HjTdK`1vscgeSm}_XrKn%8TlXf z-#Dpf!Ip1p%dKr{4!5?ZT`>F_ys+D2OImB#s^4K64)byMOlo=PUjv-ui5B{$GCGzvc5*{9jrBW74U*c?bR*U-_@_9&CKxfB!50 zZAw_~t^J>w9Hzc>XBLY?y55R}+z(k(jZHKH+@jaIGHcFzcyLulvhHdBX6=6uFKaXW zxcld^@#p=Y>&-xw#Gd~8nhSyopNulkp{&vYfDt_Zk@G~R9b~#mhhj&ZYY1ST* z%GkC;S7N^D|1W3$y#M?E?0@!0^WQz5FPFmNXl|l!wn1xJ-;>8XWSF*8En(?joOr@! z7UT2NtnOV-vG4Spt)`xz^gn&Yf88C=>+}BE+x+)m_5UyHFaFo{?C#|q*A|qlyLfrh zZ3D0R@B2$99zCL3#h}0H2}kLR8C4}4PAW8fa{j@xvR>+c1uJOc@z4G9_Vb?ofA*Ds zmczm0bLKmlR>~`1Z0Gr2Ss1>}Fsp8@WY~|l;oN#>cWB=~~R|T8J3R`^LPwU%C)$52b$R%^~cSdel+RUJz@}GbG zqx$FnbN;=5{D02d`VF_jH{3Fbjft@J@@h1-*b&bBd?QT$aecBUAxdoV zS0(+X`dwZB@BU8))eMlzs5mSuIaNXb?~Av=Y8!NCC{_9Vn>k01k>@Qd%Swyg&9aZ1 zF8ONgF{sC^RQ_)gdKc>c{->&<$UE5wGyWZCJ?vE5>#)3pEi6(eVsW9q;q=p1TnzCH z|BK+YQ4y#%s=sa-E-71R`f1Yq^#)rL`^&50> z;J-P1aNz&W1-w`JZXHg)^-t_-zz)mO?5zgXrMYv&UzKK>ynd;?<(9$W`leq-f9m&k z{oe)ZZy$v;@z!gpO)k}_3}}%#`!DRhNsgcF)Pn}~d2MXIQ#fABY!x!g3<}}i!}0Gn zXczIv6fPB#=jwH<~9k=EC!oh{{v<1j4M?x?<8- zD3)04VXfo*U0)UX_y4*7H~-u}y5DZ;zxe$-WlKN*KRe;7*ZPiW*Xqu6)}C!VzTm!O zY<=}+!Cr2z^)~g{FGAAlUVqgPsE`D8OZJ1(t^f7^uRDL$-~Iak{qz5lul`Gx|9$`L zfAj7C!e9S`J1hUyPbX+c8N|q(@L1$2z$;&=nz{8=Mo_xlS?-F=@Qn-3*(@wS=zl>O zn*Bgs9dK_2l>I{X8WzgdU#m!)P_^c-aAo@X&Fint+HU72FL?LaqgzWEi#fX`SsoWZ zn?G;n|GodW|NQUp=W^{I`x6{-7U?ci?@d|sOtr!ErNF*vh2LF|ZH$V%Cdj_zVm$BZ z6}F4EKKv5-=|9ic|L@QIzX9s8@gMj<`PKjW#(#%@{eP6yusA4b?;Vf1-npsuJ&&_u zmP}1+2~k=5H<0N;E~iKOscadGkNorB|KYEl_v`=nkNZKH|L>p2ng8Z9i#E}8Ky zQ2B7h6w@CPyj3Qwju}r^@GXigSjMp7w#((tg=@Rki_JF$Rb%ge-3N6e=5PMXANKo8 z#@Fj>vR)WIluqZ}CUvb@(lspiu1dYC;(bMnZnxPEOAF6`S9;KW@0o1MPLBku0<)i6qD`%-#S@Ikmu6XTk@K0A{Rztb{=^rB%FMt|GA z_FG^HhvlzdpJINdzVusQrm**a5fAID7X}LwPIF7AZT)t!$|tQkaPq8)qV=`EXSaUO zyz)6_?e@@^EJokzc<0kc76tF9(A~9%ZRy+jx5V3*?T1tj_3QtGMyle$&7%3G2J&}n zeVJZ;;`yIDwKU{=RAIrKG9IS+$`wyV-DFDZxAt68(J!2KeqQ}Asd?)E_rC!3kLo@C z-M_PI|MdSgpUt-~{#VFZAEuG!`Kx=n*y3>0&q6NU>033m7yr|EcIe3w8H3kdH5|9I z8t1qF{Ga=8{jC4num3mu|NPVc`}el_pZLE#Kk@nh{qz5OfBNqUUU=>I`~Qhoy*JjEc6cqcyH+i9qxUgwJ)cV7h;%B5jTYGoSO1+6z$Dh|v`~SP! z|KZ|i|EGgmjEg_^fB)G3f5!^D#aE-2bUpWEdhzDy633Fu40AkIyF}l6rerI|)g_^o zc86h8+J6;krhjJt&rkT@z3X$m`G5I&|J9%Tw{!Y0|8sw(X5pD1u~#lFl6Q7+bBs%P z6JgSk6qOpKwa!i;jc5G}*VdMWY%hOpslU!x*Zn{J8At?I35a_bBaSu|HoT5(#YFmc}hH)k^+7D#P0iPzL`1{K&B`9xT|ZgQC@nHrajvCa^mWERp&$C!--1?3 zeXi&K|5Wq$f6yd=`R{y%198c}9?bNb@ce$wS;OU#{`a<)M4DatIp0dfD(qonnGbu` zA^n#BtH1r<{`dZ$`FH>8tAG1{`riNgdi($9H~!xbE*&~!bGqS4H*Zr=4y6fwI&{)_0{{O`{ z_Ajk<<-OMCzC1te)vaeT*V;aEWC;sbInVQRzYX{O>i>T`KK|zXN2~4s{g}V+*So9sf9K!dTmS3z{~!MUzg!J}-*NbDU&YtE z`~SR--}is}_u_Bga_|57vn@aF`1gtXUmnljw|)PS{`#M3|2}*VzyCjh|NX}K_kSJ# zfAQ7!ssDdm5C8u+bl=PV`||3akJndzy*~fwQ~vn9wkqd8?EiPY{+IomulM&?m(F>o zzy7Iz{<^2DYktqylGl%~FR@Kq|2O_~)0^}4|Li=ginqPrJIy@&^VM+s*#E8Se?H4U z_&)D_{lAwXf7{>JSNy&Ezi0ia@cJM7Hg;zmH%D;^Tx0G&i~&Z^#5~+u3NJH zt^YUs`ij*0{~vn~{rR%(u;8EeNq>Hvo!wklms<1v)pGfwXq$`kG676KO}l(X@>JFlighf>Y0+s}tTPNDZ;?&o^N|9}4cdH;9*>YvYz|9n>d_f!6l{LD*7XB}8{uV7nPmTz|c7OBRy z57(YK6vwmBbXz@J)MZ@_gZ^V#7tQ{Mf6_mH{{OfC>z~D+`=H%8VOuTS+nBY0Pu4s3=h;JN|4;pMe=Gl==s&^-9)G>xbo*cY zx&QiQ0rmTtYGUtQY}h_~l|kUr2*d4%vW#|JPhJva#d@el=a0Nzy=MJ!;lr&_Uovh4 zCT>tO*@i3xnA-AuRow^o7F$B8~=H&{O_y$pY78e|4HQX9$R%t zt0JXst+i2; zh<|J?^})<|joyPqwOH%v589%5llu-%&8^Ix@bADX*=sLuNf@4bsKz6!9X93d|M%vax}hRI^H&bcqH z|7x?UH|V3rycQP>96m9dHLt{;tO;C>p%bh z`ui3Ce|3r#)nBZ;KI~Yxsl((|OySRrM6*?US8hI2KU-}oHrS#h({t4nG^&aPN+sz>GS-;AvqahIN$pEsAE%M|uyuUG-= z{~vq)y#Mpxzp>utwEe#J|J&K>`P$^xE;h6AVv_3bynN@@i|mY&Ak7!vnF_kEwjSA3 z^n~rp%eAMU{h#@B|9b8-E5Gi~{lEU%|0!?lbH3ld_2*t~R1m-9t(6bzCw}EWdb#@g ztzGAYiVIH|rY>aiy^wKbYe~kdjMO)O|9k&z??3(D`mel0*}wl!|IEL|pwVB>aO$=$ zgUcZ`!5w#w>{z&F%CEvH%+qT$Wl}ClO}l3=rnG9^##bxKzJ#s|+Qt%dtiCeu-|KV# z_s;oW%y+dwbX{?5+Qeo!mm(%Hjas?Qj6+}<9l_ovAJKQsPEa|^i7%X~duZe_#j1{USA zPuI>Cbjg@96pKz{Ou1t?*=LSseac}ucW;Ae!@0ZrBqG|r9=hmesAaU`%&uos<~}c% z{r~mm&-=gsPX`Z0$bbI7jkO`N_vxC2GwO?0YAe@A*g0H!=iIyEB}Ox`Ju_%>UeUD61{8sOsvha#-spH~p+fveh#~rq}GyZ@3Up>>G$DaQ_#{SDM zz8bqln}@f9hcPRCt47S#N%{Qqvm5;;@O9SASLBctU**m19iRBQp7DRVDTCG1|L_0R zPyf7r`HSnv-|Ww26yY>Kbn&Y&)8#ed@~Wl>>ZeUhHB(VtP-^o`J*(=!l<*p(9?xrY zbIt$nnDGDGn?LXW>_7c8fBBF6{-67|GDwDX76^%~w~5i3B;Q@VRBWw8_w^UeQM>9@ zCiFEFPf336e@&vh>`%Sy|GztbUZ4BF-17flk^g@U|NqT>B7bCc;V9@}+dX_i*(t9;!pnHeEt8MKmT9< zY&ZTUFMs|2gWJF4x7~BzJLTL;#v_jo3%`4jy{+VH_`V4CY45lWv(<;rjQjOTOp?td z>(I1@*FWmt{k6aG@&DI9^KbvR?yC-GzW46G>Ye1U3nicCy0D$|V1B?|dG*246Yi(p zGeu|b3YJ`_6m_MxB;jWBfpri5|9t(w?C<%ff95a#FZ(TDmm$o9SKDh_L|>zV==4aJ zSoT{}KZi{?Ry@O+D=0CRx9W>$SpA;20uQYI&ENko|N8%!bN^S~t*=REeX#Abz74O$ z!k060Ze5wG6_%eW$yxnfcX%|A)7Kt#=kXue3GXum8T(#PksPt&5B{@+N=KypwI3J?WVJS$mh`7gs18-S+?b z$Nzu6)>r?3U-a*($p8M=|3BpZm7kDk+CML>_C?U+E&oLfuImIm=bE!?$4)MbUZYsa z9oM`Rov)PreP8;=zW(ohaKTd5_5XPN*ZLpZ{;fYNm3iaxb9uRlDwnzdo4(!y=GlJ? z-AyOHJN$X=>Oiba(_#;u*)?7^$*dp>@*?j&W|#LxA-|I2m%&prMB_P768|NOW9 zui8`p>wDQpf9aBGvnJLpy1#6(n<&Tnii++1e(|GR(I|KPX#<<|e(8~dj_G+pJgd%S(bQpw3)%nNS)@;ZJ%V$mjE_HQSTzKT-K zncBnsY}2mE|JOZVIe>B+mcSFnn06@2;e@|(+?pU=Kiv^daQe!E}$Crt1Dc@O`8e0Bf! z(fxc@27>vVyMpV_%-~tPF*NHXtCIPySah}z|(wE@ZX4_35o-gZwX zqw4xh{YN%REE>Gq|L*Vl|IbwBe~rt(m3xf;@4nFYfBy6L^8fG0@2{4<|IhsQ?3ea` zyQKcqaNC&5K6rjuPUFz|^Lu1Dl!8{DaeT>dQQ#_n?RScxlk}p^g)5!IR_2;9XQZBa z;kw%4imr21JE|kPhaQ1$^ZC@_h`=kDSn?Hj5^Zp<0w^Ml}f5~C3&*E$BD~fHC7$PV3ANJPRJE{NW z+GB>+EXS9GiuC<$eH7>Dxo!6c!ym`fpVYtqUq9*3mp^k$suM5 z{Lb~!msUnz-4K{mrYZWXYo49++>5tXDIadnQZ@T8Kj;7Tx^0{%@;{w_|Kq>tcks03 zJ*M(U^X(tjetCYG|DpUNi)lV`9foUmhQ~c{!hLAOMYjsm|3A?v&7x! zTBVka{Q9vsS4yeBl;rU_WOOv6=jK!+6$>vmv*+iJ*xTCwum1o3@}v3ZKKj4^;BWq~ z`QSo7wfJN|&;9f2`&k-l)_uKnLUhi=3aM))9B(ruru?hx+4AMYyW8jM_5S_*`Sbo? zdpq5KKV|;^;rn0nxc+C>jXAnE-=AP{yA$5|fBxR`>`AXZKK=P}XFk)lTkUhFPUP9& zcD!%xNtMgZKHGN92>X3U?BT+n_~aMlAB+cQinpXNSf+Oo)J!&d1gJMsUYKyCEy~opPuzd6r4;(P;BcOJkN6DEj>nE{pj(gU4vauBq3ge_Z17PK*ETbK&y`{_Pk3 zzxnfj-jDXfU%v5C_JdzVe!<&ykN*(GR^>Py|+Lytlg!&t^3o}&AU_21YbwMMh{lu$OFSVZ+ zr!gK}b*p~)be^BPA9g(4n6qwictHX8;+yKOCL42^=C#&W!SxR>%#p*)IjUgSZ84+rH0w`!U9)|dQdb$>0jSmRNlmc;_^ z+nNVHfABwl4m2cT{O{$&KbM{Vtygh)E5Wg3P1hA!@vs#!#=jOX*4%LA%pZ5b+|<5T z4ep;AUdrw*IM1_Ss_cJz{{MfL{JGrx@BfbT|L;ium*;AzoBQMc-R<=&{?vcJvGvXV z5WOI0?MYMCX<10``hHKfzPNeUo^y{I;w9zGq{0~^m4n$E{`jY!W}M$wUs?9A{7-%Q zpVP}f>f0aOUvt9#yOFf0;aWq^Y;*fp|FR>)KmOUDlzC_8NkgF-Q`1)RhHlZ?wCyh6 zlb1iPr$4Vh{=fX#{yM4uzl8t1ZvP{HPmbM_`%v7kDD7!xhhN65Wa;0zr~hWX%q&-H zsalR_+e2P#-gq)k@JGoXkml?E-}n6gmHFrT{0IB%PV6r`5_){o6S=Bo|3j)ihw)a; z4%xYUzkKo$t;x$+zlB~ClAq{*#zx!|fxvq59YW0jj z`8T~8krO5Fymr!dEjaUX>&1+slCP&C%4%gZY2VpUZatzxSW}ue|-g{JVeg zx&JOlEIB@B|3)@>cAD7PE}0VkuG=lHW8gIDgFk{pb4s zFaCUf{Np+MpZK}|ze*;&?f6w{;x+%?njnLK$a$5vYtMXWRbT&%=Tf@PoXZlk7xi6; z{Zp^^FTcLvU-|3$_uciCGXFm{{9pZff5yS?sx^i)qDu=q7YkZ!x|Y?vfC?|=RO`%(RVyT1Rw8va+Q{+s-+ zH0j^J@LiwNTBDx*ToL5>+-1VHT|9ZKU1qL3c*`dD=#((6XWr)j&mY-uYyW@uzxwz; zw;%u5&i?0i=%4t$WqTj2{ral8hV$%tn4R~)hh2;k$*i+4rdDdZ zb1jf$)A^p77%Wti6R=YAYh+vT+ThR#6Z@0Vr+$2&{rmZ&|D3<;{~r0df7kQ+`umFi z<;@wac@EBx-}@*3VSe1XpG)iiF0KFk>9?iQy_+rjYh>&HzWV>8{{AV(_&)ik^&hAI zc=mMu{@(ZZ_Dp84yBxp&r~duj$6sH6{X75P_3hi^>c2jFef96z@b!;ozgYixA!p?c zubkOU>W}|-{;pSi_j7;wdHb5Cf8y(ZHT+fhUt9nC!q#8c|E%~IE`2~Id#VqIO9zAa zj0xhM84jB=*52IPmz1&i+sYjrZv~k1m_M}qvETmx{;&JLAOFw$W1sW?|DHegx&Q5N z{QYmo{7-%-BLjaqgIxv#$J(nw+6z`s+M_1%Z zD&)MI-&|jjSO2g4|Nh;N<>gM=+dTQdigCeLgE_KRt0YXm@cchIn@QmMtYr?zqiU_B z+S7vqL{vPEPq_Hps)`~1A4qrFzw&?e^?wd4|7>snbNIKULcomK(p_N-7B3B#S^IZS zNUD+6*6X2CFM?KdpMJ$+v+CwWvn?mToc&+?q5u3l&b91TC|6|PP^<(KoQNaojUL!RC1GTXm@S4?qdP55@}x*VZpHyFW;{Vlp$%I2IOafTK8WS=fChpOC_+jH38R=#dEuOin&lz?Laq`cL$eyzC zblv$w|1W?0-?HiF{`!AUC;mC@{Lg*{;~dWaYo7E7r_H~XJ$c>bmA#cmn6}wGu8j&^ zyn*?SB@BV*&@5lB1PvYf2)t9nGR3*gLAJC2cw@7rZ zxS{7~!&ipy-P304zI8aNIFqZwx~e{S@~x;|$JF2dpFh}dXARLFFMqPW7VPaPZXcml z&AY_TZirjD+pkb>Vd%3re=Ay#zYyN4Tyk~6z4U!5`BOlloqzt^|7)P?;G4(4w~GJE zYFRvXRjgJ`{>OH$-kD=Vm#5k<8%0@1ZlRT?lj~&IN_$PS+*sybSor?e|IHun&zt?< z_W$#DKl1yZ?6-aL{}qqHnp0_)3NO7%%Kh2V$ZNgzYVFljtENTjuNTW)k}sL+Ipcil zK7(t|{!9KizUeEdV0^6nb^nim|J~ug?r-e+eCW%!wwSg2T%RJRyGz$62)oSwkdpQ=+zA?LDL-y+(^p?{;Q#N#_IYOo7*4O*vtV7AP_BB|cPq7otvf|BE$i1@ z5SrUo@zS&ISG!TFI;e29*$-MqDEYsC%75FC|FNC_uNhvxyhft!yVoLvaO0>~i@&&; zK5qWAC0IT6p)>c4N~WnZES@Rl&Hn%VVf_5L|84(2zW1Yk$)EQNf4%qm6YkwU^`_mG zdpTd$iR@iy9x*vbmt$g|t4WHN?B0URd2RI#YTGm%i$DLj0e8yg|KAJtaP^9RyM_Lr zjg#F~u_Z{s`S-=^Paf`_pkUUQqFqOtNyP$QonfDj5MYT8Jy+wucfKJF%w%}|2}ZnX7iNIE4_~y%FocK=;dK~b>n9} zv`(n~_x>Eh)z1wxdlL;R5~FXu?&@0F7RJr?@aB=dAA7bf*^>P3yH?QEU42&>%>JK0 zXm9)VPygNjzu)~_-v6xrkJV59*j~n;j(*IOlE-B=9jmB+Q*U~mNXkC5 zHg$!t?mu*7nW6;A&?{``6WQCzD&zld5 zvU5L{`#+j5_sL)WlmBMvS^W;HkH4{>93*aGwcIu0Rd>aX327Vbx1RP%Zd}UOa`9Tp z&8P$FPv*~`|9>qgiT<4Y<9Yj^&+UJ>Q=QIF-cYvsxI;p*_8x~7kIx9yKNV-~vwQe} z`MFDeNa4oJi3?}{U;gO-$Kw5Un*UGLe`Wl?;qU*=H5K);`v30k|Nn3IzuY}P9(}dn z`{UQ{`+uLW-~anx{J)pw`f-1Fvp+0<@%fawnel(PfI6EMH$)E`4;he0#;- zf3If$Q@f<_CqnVZt52Wz{iv(?e|Pr#{T6*}pWT)B#_jp>y#C+a|JUOGetrGEul(!Z z*FO%=kE^efejNJeE5H7KnfrU|{+>17e=~pg{+ho>cZ>hIGW#$8@!wyj-``X7_3Qql z+!Y^x|NnLO_51&So=;zY??}zW{GXxqpTCyZ*L?gHAHTmd|NrB!U;o$EJzib$`S0rY zaR+wK7hS*m|2wrm^|$~3@QsuBapdj)`A_AaD*mtjcl~pX&4OqD>)+J>IdA{(QvHKx z8sAlg;?Mv1)c-Me-=F>acNg9l{de!KYJ6<{{iWN@#XH1qSxrpSm>;>*AA2AFXY2l7@AyA{nl1kR-?X=P@(=xA-uwSgnSpea^r8b^lI2{ICDu|Kh*)D?-cv{x|#h|Em7q7K<=cF+o@zY4y7gH`-x}s?g)7RXC+vPSKkp!@N22@x z%j+NevtF?u4UIgslsEF(?P#|113yZ~E2wxnDwY&m^}6n|4^84{LMmd{TdBiD-l}n~U$~3z|E&s_H7Y zDQjrV{=fUN{Ji=9_x`WX{`c_u$N&3Q#vl9mmg7mY(U$i|PFncBH`ufNR?5nAJYQB{ z7mRvlGwb)o2~Bp!x(_z}+^_%dy7^1|8+n5Q~&Q@( zEM<1pEtCLLPx@qbH~R^f-8Eo7w;Jrg%Q9W`b46jwk3G{GzN;z=H@XFTy1#8tU2yHnjk6~+3@V;6*M6=q z|MU3s`~PqM{*V6LzrU}(=KhKFs*~}F6Z|F^%*eac@=NN*)XbE$07tFxZI-9D%$WGS z;keXd@r4_I?$`eJ((HG=^}qe9|G&Jh|Mvey)&KP;SDgLx;vDP74ZcR)GN}u~hSgd5+W_EEWVf$>{&v@~{SW_Fm}st2 z+Irc9kxMTBYkxok^G4AZCmt^S9+^0mHQV={EmhzD z)K{^5*!=gu+`RvjH~syu`=kE&{_gYcd|wX7Mdinrd_CEpyXD^Z^S@5-mj7_o-Ts5E zXUU7EE&M$f7xK={tFd6ZYWP4v=vl4N#MMSmxG%?TFn21;J+d`wr=jQmt3TxJ3%`R- zSX(3i`TXwx|6@P(&+o9W^RVC7zQ1_(rIMwWpC}zX&6-g5G_kg|<@c-Xswd0$)^8P5 zkaY9E)U)Am;TPWjmp}S%e^5XF|9FNJ?D=l{9<`yc+KEBCgVrk*jWO#5>``}A?C z=4pwN?)^KpymFsZnrrf{S^Vix>)q?m{=fY3Jo>}_@BiOVtpDfo@2B&>pSJ%?#pZem z7i{B*=bn}JOy^3=F%ccU(%y@1?|Bazm$RK$sjreuh~nxz`~UJs{p}Cxpa1`UVtpFQFz7yF}>n3>q=V+U7sY^lQ zc!SgI|Mkls@4wdsszu%Zy;lDeZ~tWfzUTG~Gux-l*gDm3?uzgeZ{pWjd44bXY*3rv zD0A&b2TM=1Wl78B{$+`vdh~wY0sH*F|7}0z&p)xh_Qd|Z&+DzW@qFXXNa=_-zOp>> znoD5jo9@##uU;`nZ+^CP%eExd9}l@%r`-kxSN`?~_4VKX?{xonTm930yC?f&zx{V> zj1zvAw7^u0_u!vqXO$4g>FG)rR=F%=J$BBR*F|UXOh<<_K5J0Ug zA+vVznh*P4|M#yyW`Do!|JwgM?f?B0{`s8$=X33UYcEbbb3SwCzuyagRaVyoe9T}y zIg_WOV;V^50j>l)qL zRk87E*74*s=2Ob%h%B49u>RTqEpsBKJH>Vj!|na?KWJH6hW#p`b52H_g5KR;x1e7pD-n=RZGb~j(gh9MXf!8u7b<5(|()Cq%Y%at!jTf z<;RKZ+pjHr|LeZ+r~1jC?W6yf_y4)94r;8`TmHZN>(R=I|7^3Y%7QJqYOSJru5~Zu z4>p>7a_=uCt7ohsr{2sLb()qBcJ!S8H-GJ~elp*FV*S4f|4;v%Uq3^XOa69MsnxC? zg=-VyI;9&j8#5R8Tw3X-#;ILfxAmqV+uDb-|1W>?U+j7Pwtw&Seops)5^wk9f6+ho zg{w>+Ka-8Uyjgy&oz1Ig!wJ(~x^3d9)_q{h+Z>^LrD3o1xu)NL-V1-K?*_Yh`k&Y8 zpVrHN0=b!YTFCXfE!=GNNA78zXEi=HrE(6ZhFuif|3|@>Un+~tY%k4l@81x#{oixW zpZkygl)v|De)W_6bxQxgg2OAPq+9FdQ|ISO$qSb{Pd_z7c=k8J#^T7&37Z4Hm;7_R zb>W1_ft1hxOa9n@{VDHy=imRlpZ|5g{-46nXHe_J9I(@F*OF#Nqtuss>o069-g&{u zKGAcwYUW~wD80<7(*k=Ih0O{2dgB5|w&L4u3s0Z_yng5WV~79saMHdy$pnot;qqPdjc2(I*=X?(Qo;dW%OrqA7k=`nE@*JDLl5GcG=F zIp0`su;tJDmp`WWKd(=;+xE47_W#d6|38egJIV9s!{xdyZ1W$>9XbCwfBv6xn^XVa z|Ed36Z}ne2_5buc`vaHspWk5rUnh0h?M0cJZ!Po>k?m2dm9=_yGs;k%Gx5qJhnafy zF0cvfBxIkZD##{y-hV+?OfJYecqg2DVcX` zN>m~od==6{U#(rRvomzEQg?&TD&xxkf7cqf*3W+~pLZBsnJxd!|NKL}|P&m{f*TnAD`bcKk9$|-2b%kUwg{@|M&mQ zKmXs8@xaw9hxBItly?_R|5aMd<~D!Js@ErS8r)Vob47|SQj&^&z2=g!TErD&i3ifr z4e^Km2iJf9AJD-5Oa9LD|9J=N|E~R9KZ|ikR;*HYXRXMi6)nfTR`cjDHhpN+vir-< zw5s2Uo3Cr`^%1*jXd7O)MQ`sy)*q^W4(tB7|7-r)|H2>Y!`K4!EF0W6KNi@OrVw!V z*#t?GT9?ctJh6#wN@vZCwFKq_o|Q6jUA|PR?E9a`yg!!jt^dFMXFb!uk2?SK*Lv&3 z{tIB;7|C}-Hd$&tN4CekYceM`SH6@K%2*M^&CNL}qD&+9-Mso;tp7oqpZ~M`xg7Z? zK5BZ0wa1}(8vGla|1CckT)3?G{FVjh_Z|9m$m~~AyyX98=L$Ej*SY44cR!z>4{Dd^ z|C`@XZ`b|b`}L$JyXqUNJUW$(q=ipQu+7yj*f@{#V8&;O1U6HnH}b1LN3CG0)zrRY z`@e|$A9y1a=a1=|f9&6)r+C=s|IRgH0elnZA6?Y*b#iHTukqB_c^mDPo{!IDZsL#L zP{rL7bZf!x=kfUm|6ltLw$rxz|7pnsk8}_Jewh_#TeL7QQ&6kEyhGuQU}&1{v1!}i z&Aq9i@4UUHO5m&Mv%8-`I^X@@4GNyuk$>XPF>E^LQlGGl!R_^mZ~RlDwqCnr{QJ7z z%fH;E3G?@)O*|?S;QnKU!nJpE|NDzE*m?cm3~Jx}U;DcLoYw!?RrL~PVjPTy(@$_L z5b!v$#4qf)(PuTLu=*WSyf)wRdR6VoeIdE=(T@7R{P$Y^zx{9i|M}*CQJ!SId%JmL*G1wS(T2e`QOjm-);H7_Wx~ALX3R6 z-}~$O$A(K86d2D}>}OaZeVHfohD_6*vaGd+y*I@kO)_Ox-LkIEXXl3c-_PggANqgo zf9}8Y&;PIabbskD_O%A8UlY~N9d{5qai%`g_sYz*Jr@@qdXsCk^!oX&J2=yYE?Drg zzWV!FfBS>@?VzpMcK_3-{@1%|AIx96Xi{9g7&<_!&V$T z7`(h|%d?H|=GX7#{2%>)`%nA%|2Lniub=)(-r}Q7%b~=O9Z#)JEKIrgo}pHBqpPS} z%T&>szrDSS8LKo}E{BQis{i-e_s4zEPU)Y2=7;{<9rFKE?CTH994h{$E`5bno2_Q-fS3Qj2_BA94mMoLSoiXO?A485 zcZuEG|9^k)zjDz2^XH%IC;by&|7CyKneVSxhxLS}gl5MWeT!F)wVmmGdcgw6(3b7K z^=|SzBXn8o4Vznb{Qo1Lzxe-MXwXh&h%ssibF=RI*2}f;TFJXqzpeMedCtq!AN&+K z`*DHp#Ak^H`rl)MW*)ile*XX4FY32L(t!HQ`j3nL%Nhpm2|r%)v7K+ns-po{?WXth zFfG$_s>!H})yYmEZ!`bi`oHq`-2U%=4X(oMJ;CF# z^-jkp-tT#1yz~6h((HXXKPJf?=eTevOC-iftf9-GGD$V6W$Uce8wLOW+;{uG8vy>&*`NclZ_+I}{92Bx&|DXN; z^UwSx|BrV6+isSa(0f9pVey5+KkgIiMLSl@7B$4gt>1e#)u?~5z3B`iMvk`3p81Xc z-kbfp9}BHoe#P&3QNQ(eM3`;B?r%zWPtCc}-*Nw}xpC%<{+duvXN^qFOw>kF#> z=S|+qwe5^p*ipgxjsK?SE&hM^-+!?`uk+{ppZsNi$;JO_XZGw^am`H9!CQXf%Z9^I zJ9n%)r*dU=NZ^rI>v$JDiCU^BmoHxS{vS%b#5b+}C%^Ujsw?haU2iSt<8ku-)1SBB z`Dm7_#5A#_nI^Mm@^PFG>aXuuP{;Q1f9{w4&>{h1rQYV1!r8r|8~TF&ziD8#xv}>4 ztgDw5N^-i6_8-}19M17dHR;fv|9|awbwZN7|AGIJ(hSpO84@NQOSLRr;hg-`NT;~I zDQ0b^yKaK%u@{S9E38>#e75yC$AhqU@&DboUj!Y9_3VFr%|HK3|1Vzsa(>gjZ(o;N z#_as)v7CSBtr)lLAU2=LF;>}n(JQLt-K!ti@i4PbEka8N{^EcCuX!QHCtH)%aNXFKuQ7XLaISFV(|-~zq8WaA-E?T}`HSCao z@5dKhQ@Uqw;5rwi7~iyMOOM&r+;xk&9kvEO{dfNVMfAW)E6G>d8}exJ>+@HvmMm1e z$);oWd2#hg{lMoDR&%4a+i427E>>2!WB-5q#sBX>$3lbsI4Sn*f1MOT_Z{yAjZRHD z_3q5AbXo3npUp3}R-D;x%pksE>b*}W&O)V|6_LD> z&abB|w)I&1q33VsC3IdB=`Uuwj4T&SJ-GkuVo#6N$q76E|E#Z(1{WWoN=xOhe*BmH zFF$f!Nqq!Uu2xM-ILBDaPjcF{r}FxQVh(o z-Fl{XYeY9JUM;UJe(4O`9c?Mz{3CN6>rE!NTnk^4%TS`5bSCG*^S__#5l&shd*C$R zg6$e+1_@!)ZmpT_XpwZaiig=sCi3dDrD}55w;d$u<{cT2p-smok|Cl==1lL++RTyFpFx`SqYe zqvqm&rijjUb1$tu{Nd)T#XMPi+ywOlBocJyncPsCCCRZhv32EffxY#A!4|&$59(9c zd;UNDHtSzF+ou=WX(Fo=a~XB@5`|u!-7C3$3*%myUWXato6l?QZNH}QgXh=(`cL2P zKmM}c`rm%m|N9I7zW2OcKmD%#fcG@Ic{rHlY=BBuBg^1MR#|3#o z?79*^Q}o^xzxb~Wip~G~|3XUTsonpsr)_^_JL5H%?A`vA_qG-?@z-W59`E^cx=?9> z&UB;aA_oexH6;ETfB0_>EjT!T*n9rh7XSOcM>FO?jJNj=Z;{5(xkW4Mn~x@)Q9R6V z>0s&Bs^KeP?6%bOQ}wmK-~UelC3kpL`E=3$(3P2tSDux;V^P|y@_y01QlV>Cw;V~7 z&Jp7};gQg>*fePU@#Wvw|DTGkkN0@Q;&V;6B$KwjS}d6mEYZD6H0p}M^&s67(?q`2 zcg971QHY!G_+Nh~a{39^`xXBrZSLL=UHjbDTQu4V|5<#uUGmEV!`w;L?{iZoJh*23 z^S#|KpT`@Hp(a_T1524UEXryXRQ|hX+4J>*8w8i?dTi(SaQ9v?Z%^}UEJi$z%0 z?hBLZvXtsQpYR`)Y~dAq{LUBkvhCede1801vMAwLQkv>Vb+hc_arbquO?Q2Ipz;bc zM~+}XsLc2Jf8n4y3tGq4FZn-p^}qdTp<+GH7WZ~}c&s*dnwu*a&a-l_>vh9K-t<>d z$px`&y3CCozn}kC`*nX8Jo#yd|E*76@g>xF$@;<-)xQnau07(oOL9kgQNYPtS_Wb5 zmu5c>>ACj%P2vB~|LrXQ*3bD@e*FLT2mj62{kPTpyFcZ>hO?AR{iAy|=NSSf|E~G$ z6EypGQO1)8a~A%WS$MHBU~Z<;vge<^JiA+8CkRbP-~Rg_`0x2Ee(#I=mAZ?cnmX4l zWvlf};;VJiV_iFI`V5}c?AtlsK0EEEnEN+F!03tb2T-A&_xJuYNTK=4^}qKrk9`ZC zCb?Fos_Mcq#(=^V&D8Pz6wzesr+3Z_htXg2b-hT z`>u{UYr-I_U{L(m=l|;6)0SR~i0ZUcQf@VKGWr?6WUs=#`v3WRQBsorultX4^p}0k z55AN+)vhoE)aPS+=!ZMpP%QR9V6Oegl#|6LDialxBStHXs4Xc%0} z3DDv{_|jmjBZKmJLpHZ#fA8&hF+uGoNBF{w;w()8!}sz3SA#MrvNvyAPX4pdE>Upd z_A`G{ecT#+-W|1CmiZz%v2?NB%JnPSV`oU}%t(Cwz5YC?F|qq!Irl$M3uZG{!*s3$ zJ%*KKGk&gr;Bo4-L?HKaL5Z~|CE~I?B$dS0EM2c^Q))5w+NwMI|G9(OYS32jlK)q` z|84hn`xxwady~=h1*Pksa2wxbKm8=Z)BH`)-s#CN#7%9NH9a&mTEO?4=T$wdT&M>Z z46DWezQ1@$c;#%5w|B$Tl`XfeUuzz>S3m0P(X92y6&d-I}$>#h&>e$WmzH z1zRe<{JemCX$eQb)1}JyEq<9??Ob%{l9|lWePL&+OO8L_`P-FaAB`60zdlGe8$0H)+$QQmT|DW#@VNSZ)u}$o1pX6_2 z$$K$>zjyxtwMc&dfBXOZ^ZzP;^Y^}}S3Y=rYl-7*)8P7(u-{1cSIT#*FYsLTOuT3shj~3j!#!As`UH#U+E!?yGRlaM_NY@m+ z#Gz~yc!G6p(AtQfJiqF%pcG}VUH?ZvpB1HR{O9D_!rr908;&iwX!KJ5T<*&UekcDw zQOxP?^^R&aVO&v%*6NDZ|8;-y`}ED7R?}79B^VjAI+*h5zwx$SB!B#0y~(WyvnD!C zzNl)H_~7w^2PlP^%HRB_uYcM%o;%3wc`$v?+dq*W*9sK`j&Z534yce7w%@ws^m|8- znErS5h5!Hle~r@c`nu@9?XRDQ3!?WboT<70_Xh8Wt83hQlC=~RrI%P9h~#gN-?P*; z<5~Sy)(d~HgZ1wI2kzuf{<8n;qW`Tm+l4=7d}QBnV&fsL#~J^Vul$+8!`JM-&P=)4 zs_V0l^#zHD>?qdXJm3B!wNR!pJXpja;V!=aV8hv|(Yca;!%t1QzmV~0l<@*Fjp7rN zyd*_?PAy%V{6~KBwBOhNU%&mL9;xB>+V#KnMHSgyimzT->3Xiu_KNS5WA^Rd5VSR_ zu%%jF!6qk!H6`pn&mTyZ*$?WHLtHDGFx~0K#A8Jt`i!TwtKIgqt*w3Un(>W?d(n>v zrf%&gxfhtL@B07uzkk{P{)_*EZhri)`{RG_>w5p9`v2nZ?@uaVlD+VJmD3}g8(N2F zm}IS(#=~|@hV|0>-7V)jW~6@A$dx$o{KEh1pmO_P{qO&uf7*Ng&ldl?{^uKBgW$i; zZ`zYtmU;#huZ#Nq#`MC5rE?3uMO|?%yl_#r!n8Ew`~3g6QKF{o;{Rv2V^%YJyM1Y? zKU{dos_nnSX^Hw9MRR}FL~fa8we6tH+CbYB=8J3Z)c-vXvJ{?tw|4&vU(uh~bYa%i znVs2hLk*SxH)t;Xxu)jLZ{B#D$lHe8CDTsnX8EoTd{_T({axffV0QT5`iW}BiUnKW zNk02+FntSSt)G5sz23XMQwy?VjkzzB{NEw;FFCP2;svDr5AT~_U-xCd>Ej=*GTB*r zYQ}#S^ENPkHhjh3a`DxiX+O5F+UfLs*7~#SrTNZeJV4i}_bYybp3$N+0amkqUA-Fd zJL%JmdD|GWd0id8ZQ*pCz*bmqYsB*Mk<@(0KlP9vHl%~SzwF}wUtaU|Q%zP08{Lm@ zy2m3v!=;UNCV$Gj{Np+dkqg#oOy*sEoGD`0yZ!(7qx$n})_?sru{X<9Y{dkf+y1mH zzHHF3;@;7$z|<(FC954i-*gr?ZoFUr-+p)Rzw&y}NmS22*H2@3v50}IfMI3ZqQx@8 z_1)_;ZY1f+UkV9ZDYcp_IR8cIw1D_I+Uvr?|MR>8)oF;1$}QLbs}D}=Ru*AebuUf0 z`^@{x96FqgKFR^bcQ-FPJbyF)`UR)e0>4s@{GR_Pt-v4g^)Kct%1+GLR#fuy zLC??jAaR+}sf$%3Hb(9)wDXKno_?(;k>Q+2vff{wFZ%aCi*{M|3=Z+Fxz zzSD2~|MQGb^(Va*)`SF3>fq{a^6rgeySlP*ZQmcJXGiXNUq>6dxLi?pqyxV%e;)P%ARN2~9YM8Nb zrr3hw&0CvZeb{Mm#q@4{o&MF=h72x+nRSgzzx;mx{~}6y&lUgsKBCPwyftUFNW;ao zrI#93cBcl}ie1eSlRCQ6%z*FEEJmluqhE|~{NIo0TYLTjx%Jn9qbqb2W6tR2-|Knp zy_)HGqFXHINcEa< z9Oqzoerdsm=f@`ORZ5@cc}~ z{;TW6j2IkJ`9k#!3yPlHYX5XmucN(%@3GZ_d%OQX*SG&0R@d@Ryd2c+nf-sy^z#So z>(5NB{}rDjWl%9WX8N=ywG@s`Mgj&~+muvyoq6TF=7pio0)z53yR;78eO>?4dk5&M zsQZ8BpR=EH_`mDl@Yu!+Ujlx4eF^JZs==qdLCZS)P-p9>nYY}|)J)tc>GHa`RPC3{ zkNuth;>-R(%4#Nt9WD$O+FN}7bAGY-{GRPmR8@VxvqErl(1OUhqAykTvB^8LO?lwX{Kt8 z@1s(V#_2z1{QdV6WaGAf<)GNC5c(hfcmMQhJpXQ6sr_0pO?7YSw`;4m9rQNX5b=y7 z>BPjJ_4~zTPq+tvn0L_OFAvzUP^~3G|Hc3A-=Xr|-DQ1@(I$O8i-Z<8H`e3d6!e_C zw$E+~UG?2re~Pxvvj#6U&hO{{=YIJg{eSmQ`}y^Do&Q(=yZ`dd!p){}d&{RRKA3*= zP}Gv@>zxd&XA?8m%e=9Q=v>SF^iT_^w5<32{~pry-9P8Zf7k#04{evYWxhLQVcF|& zzGJ_8MEJ_ZPndJhYBlYj&!F=p55k-?lcaJ~740HZAu`RgygSUN&y`kB~mZ-T&#I|FitL?fECZ{>%O| znG6OW*Oewj-ksuZ^{eN1Z=c%!D?U=+eg5T|@yK3jOxeO_yywI&u$6cJ)|>tJKTvNC z^5cHaEkSHwcX+K^TV+!6qSyKC^oFRw7E9~1Y%l*^w%c-T(X9ZTyN}=f{Qu|Stu3UrAPyjpJ|sJ=l|^=JCRYijN* zACx@dcDHWY{r!K9^uO((vCMP-J)i#f{wiN}bn#Vlc86n(%UFnX84=WAXHEibh|fR#|JwgN$Pg&#^ij8G-y=%4+>BZI<;$;)v)s>@ z=h|5n#V*TT`hC8E`{aGQW)(2bkeJW-|Et)a;G3YcYhM1jUi@SKtbe_Xt~{Z#B0ag7&zx&fJ`M&@5`*Vckns4BmRH*2MfdGWlQry59W%^3U~? z{ybmwPx9G>nKpsbzr4DfecIaAnepAapFCl1VzDz7W=t~8F~|^||4wjk`OfNpPs9HH zH~T;P|Ky+3i+}w;8T#Kozy6|Eicf!b#LAs>F0JWgYFP68xv1TwiUn#-x`*qQPS{>+ zZ~P;E^&Rv7fTfked%>SmdOkLzJ5Ah{PSz``2Bz0t=|7zuWpO}(bIDd&t&@=ap%(gbB)I( zWjH3D**5c4)0u1Gn$F>NX42s)ORcV5`uJPC{_XmGzn%B|dFFcWTm6rRK}S~4-=|UE zlOO;5_l17e*8KSu**x`s9R2`(9RW zeg6Lx&%W6aT*)58qq=d3yfkH+7u*x2b$E{=>{v zcf|hMrt|-8PPc!*{_)ZMzrWw_e|`U0w|?CJ%iZhu|Gr!Q@7M14|DVpU`~K)?bHjuD z`-0&Y56JJY`@H=9@!cE`?q=8h`7bUP|0ltvzV1%R|5wKw9<2Uu|LWJ(|7-s*y)AxU zCjUkEzqcX(9-7+ks*St*`I}_By||fjMDWp9b8MFS>L34DZ9L)LMuAHYcBPpdG~*Y{ zThhBr=Ow@WpQAfJ)&F~b|8M@^tMU8)z1zWae}A9-pO;U!8^#@tzdv2_-Sbyxw&#CQ z*XQruwyZMZSiS3l8wYi!=U?+Gy?X7GOh@h1ttOjQ&U?(^k~!P8GCj%VPr2UtdW&^E z`~N(9x_bS8-M9nY_y1piA6NhXx&8i{uWHY__js)THGBR3-;cYm|Nr&Nx8}F}`uvUe zpPTRN`XY6IZ$r7gc3k=Wyhp_w|NqeWR)4&He*fR&pLJyZG5zirXRcqql(S;(o2@gx zcNiv?8U^cTerDY2b6VVE@{GVemaS3Jfzz$!f1O^w{l9;0sol2!;nSBN7J4$PF7U>6 z7d5e~p_f?0mUPWDe!g`vTke+!*KSWq;_enT>a^MhDz*>)^*NvP|NGDV=a2upTq)L9 z*Z6n&>L2k(e#fvajbdyKto$bCCHW$~yxhv_B$~}=44-9ewBX)!`P21@5tmn^+ql=l6Ecx^T`gcuUa95#z zmG}7Al8NYPFGm=5f^nD|;`$N{=%!x)<*>*^PJO(Vr$qxBb8U&wj`J`3e8$%isE6 z`|tnfjsFYgwf^pu&1>kFJ@A#U{BX~gR`p*D^>YvRSIBQ&>l}0Wvh9~GRoTAh8^Qxc zRCr!mJ(Q{sHWO1zBccl*0Lto>xA_5NsovG`BdU+4C8 zi9XNJO-Q+m9miY8l|H>^( z`=|ZyNp@Iz?PQb8#OW(t=C9UQP<=aN=H#E}t$ELhQ4@E2^jz8_7sS-lW-6;zxqj(|H%Z6tdCI@GuRrqEKJG-d(E6Vozx~fA z{onrY`}XwzFKs5goPOi~>bV844Ep$FR(nY4JG|ceJ0r|iQBL*3nrmCWT$>(L$e_PL zjZxv8+iLsPzxC@*7jFC?F3wWlP*FKSvGkzf<*t*fwq_e&zb8I*OUlAa>RZct^juyF z{M0p0+r?Vt_WS>n>o1dk*O$&T@{(As#~b-ly1&Y+iov_wzLi-;t zk|d)n#qwjXvhE5j)}F~a!}IixMeDS3PrY&F6tDkUYO;9_ce`Bkp$YF!EB}f5{eQ+~ z2mAE@o~N6C#Fza)e}Bf`^VZMBi)XK|J@Ag7z2~0tpYOW$|61f5Z11Mo-*&3oaBY8v z=JH!Nm&ZS37yBlz`$2Ef)A}2K|8Kv$=al$*8M(xpb?5#y*VO!z)_VW<|L=AGzYec9TvFWjRI);g&)RQK;_R7sN}_5t zCbS4loT7YPGt~C+wW*4G&KjvLxac3#8++&OxBu$-4i##@K|AWj>wojBN80?5HoxP4 zvp%GF)6|{H2W8$US9KKjpS##mlA(XWTIYND?Rb;`#Y2w|ce_4Fju`Euwp8J3M-~UU$${+kR{Q-rwUMTR5lw%c@%6^~C z095k)5BlwYKIMP;-|xj6|CdZUx_E!#;lCw+?tAbih;`4HYCNYjURAi^mE@!1`g-fe zZfBX=H8VHrHC_tQ>9)*$dimym_5D)zqW|TUMY&wJyqfjXH*Rj#md}}rDTQA?A8b9h zbg8;bdz`Ai&v(P)5l#p8z5T!K|NblgJ{#ZsfA{~x;*I}nCLMhYvU1Ab{$po2{GQG@ zuxr`joVYIjg%c0v$p=2a_PYS+AT|LlKW{ju`L{L3FFmaH^x zSlOG<=(%+T-&(Os%}cNRfBe7wdzXagq_=CPK49eHQ&oN+q;`*?tXRhR8P9E}fv)!xr(xdfL%DE9U)Q`LRCr zPq{z)|Lp(gi<|$ynwNfQla>m5BMwd(OFr1HKxjnsd-AT*t z75*#FHg~ii;#}do=mej6y~Y3ig;^mF_iO8jK2ZEp)84v}-&yH?+MQzN%Tp#Dwzuo; z5Eht!TWNyQ7F+o??upU=P;J2{5wDQzvF>BO%uq;72EKEI=0RrB$~ zV+ZOFFIh3`r(x~0mWl3r8*c2&EX;F@OK@*8IQd6G$nVMQm|1GvHcq~$7cb=5@pv;s z!u{o6&-nNLKYqCW^_CC&md`2U)i z$~G-|SHgR1lLbawbnf%iI8J%I|F!G1qlS0t4<7pfvV7jpkG}3MdQ;b_sC-zdFlqKQ z=erG-EzwsB4PCT)_$9up8nS+!sWNZM4zYyEQvb96*o*zMUf%lu>!1IY2mhP;R)n7~ z5BL9fTdn`j3I3G_D)Za2_b6`l5u3Sy%R!taL6DiN%8AXuZbR@99<^B7C=$ zR=oW$^}oOU|2xfx`@_%wpD+9;{&GwC*P8ODPwW@-ZFCl5WjvNv%%oU5JyApcn2cYJ z+MNq(`&|CZ^NX~W*y=S+a8pw8`E~A@+5fy5BB4L{E$ZcOCj1muPio|5mX~?!a%Rzo z`Db@NXa2DH!la4^OV2Oea`?jLh320QB)8lGCHH!rKi~bh|9kfSf6n}W@7IQT;ktRD zKjgjc3-w9vykojk+1cQiZ!inf;=i}e+BEr?PxrYTuoN{aie>W1uE=R4#p8b#|Hx;Cpid&^e|mv^eR9!+_{JTvCfd?GgZ1^c3!aB}M~nWOy-(Bk`cgU7eP?a7cH~bwu$@yl?Ziw^ z8977g1?RYTyq?9k-RE?f@&(3qnbwWl!GW&zA)ZOp>GmThi%a$W9qt|JO#h6fEPEJU zvG=Jf=`Xp`x=~>1Jog>UU5B1#buT@h^=JLZ{}Dgr=ZO8g{;~cX=Rfw>jC&VE-O+mf z-?Ck?q22x0FFz3$!Hufvjl74M8ooDdKEa>Bq9Bdi8vi5@8bBX?))9%dq{JhOG zu<^geepi++ikVy)kr}Sb>XSXs)xKo8lGOBgRYxncN&vG=Ig`Z#m7N?ig0mLBzw#sg z@&BwJ@-qML+@Jb!{<)w3FW>tA{LJI}4L?$DPZjik8mO2Nx}o1u?t=>7=~T76^shQX zE^@*Nx7a22-0!Z*x~Zd}rat8o!$v)>vj>zE1w&X~xBu-8TEO&np=ZSo5e>8Ym!~u~ z9XOQU_&WGi^*UDDGlsSHQmU5- z^8ZgtUFbivSbpWPdi6)^LBC@!AXQx6Mjg zq+JseS}$?Wy5lmO7Ux-23>bg- zTo4s{ll06gLEnAa6BQoG`xC@&=*X@r`)4F{s-tR|cBI0N`rMfl-+JV6>G$kmcyPZZ zaFTRnV?l=}D-XYtxZTG$0Y=`fE7z4e*2=Q~Uwe7W|Lp(&iyQu5lUfs>eec)SRd4Hs zJX=bi1@srGe>!-_eCFvE-5D=$PjRzb+^4Wm--pZUfO~s@*umZpOP=N`J$vq^8Blso zoLA<)Q76Yz%@rc+1RCmp&v9RP*75GmBWZolJtSCmDv2!6jODX3C|Y~sE7Nhq>@(}v ziy!*WcbDT|_|5-cf4$#%;6Gn1`@hnRr5i%eF}3y`&uMFqWKDEo{_?g^=eBatj0_7F zpGS)CTG*Q+gM_jkg-j^P5!=-xyiHMeL!?#6izbaNGI~DK1N>UtcVu(g*FWjwkg-;& z6WG8ImEEeCZpW+a=p0?tb-PLTp;6RJmgv__QvatvvbT(sRNwUf_22mCjQ>wc1@wn- zL_M7uzs=XRCBiLHMS#_=lS7USqJSrt#gpZNj&X zi1eLL;5lI9=-X3#SXJ4=n8n;ctRp35X7=&_XM+}Gor^cRuejh>&h+SgFFE~|sMn`R z7#Q;;&S3V)k6t0~RPuMpLe4Ug$IJSIodhR-{gq$4m*L<1RsWX<|E`}``$s+7!QQC9 zj{A?ju0@!O8Gih@uO*Sw$@m13i3YzV1 z`tSPnlOO+w{I#EZ>;LCBkL_cbe_gEn68+#m=d%4vOo}=8|Ue#FPCAO9cx^?zaZ|M{Ey|6h~3aDJBie%62X z>kd@b_D9UQx$o`l#tHKl$e@9E8pIJPvn&d4`@+4SV+Isu6}#eaY7 zcjOA0`95A@sun{ppI3&j-0IIPyp*D&H1Rz{<&NB&JDksb zS!;ExzILv}|C5^M|6l)XpDz3Vq*U7elYicrN1FW4j||NCeWiHk>)_MMjiMe-IpPa^ ztMtD5co%uI%*&i@*Y>AG=YCIy#D)`}c4%IE|9@vBSIC3?Z=2OV&*Av~|JOcw)@i9m z62A=kKb|O-;WWtauAeYlrrbHY(V5eRr*ngk^z#E*f7Y*`{Mdfw^ZKkm`rb#l7t7Cd z-_QE_|D{QXI2UVt5q#$3XmeXV&Lj5xM^0{+BYQf2oDsgm&GN9XMUZiGtpC~i-+?kSs!>mIe8EytFC{f^@&k9d zqjM7>QC^??`G24D>%Z~(FQvZTG?D7#FPpV<-Ce);{0nAhi%wMW5q0^!^8LGA-?XZl z)-kHSwDHo5Qa?~BsOWtD*);jWtfI7PL5Ah8i@FQD+44>}UthXS((C-@IUXJ!a=#|A z1s+(vCgpCzv12v=*KCQnuKKyYw^YgGQ!6)fgTey~77p2Wx5AFhJlT0#Mf`$aM!bj0 zlCQFEvh9xHn=M`(Z{1~h{HgG&6TFiaWp(v|5qM z-F@hLNJ)r<;LVoZ3qD-%zp-6M%bDxO`%fp>?^(wk>3F*166>#-TmSB7_#e1GPvf6+ z?*ILle#m>D<8E@8EQ`@N!QhYjA*RWFGa5cm)7|;BvOeK{q+DW|i)OL2pb@)B zvuwl0=eyQ%eBh8Ym~&SAI@9v&?-uDL%zNz3Z6)|U*4tv?aT#IehFwmqe!UAyFNr$v zoO6A^Zr7XOlj5pabBH->xAbM!wBbyS?b6w|exQX{L|-_w7!; zYNnXHs^9wDp?~(}{yCQyu9x(?``=&qzv%y)75QZf?3X>&Q!bzU^<%%yzv%jxf81^U zZH)VGJN5OU*LQEG+~KWmUMFK?HsNJ2ThiplM;mtQ|5molGr4y--mTbRj#QDsoVRbK zS1yofFmO|I^L=dTaE7%d+*z(?*?ES*gFaK+CIseRnEkDdIoZfWVR>zd&dtdanCmP| zZ#=ju+{STTzUbQdrR;aV{P}mhoNxE4hWfH^OohIm{w})#*0-3jIJBzo?dm;!pBo-zTfdTdx8&p zeCpXMZ&Ojob@iO-bAkU?-%4%#pYb<;wt<)aiVyzuJ*5ce{W~ef8_(p4Sjm)HSuPXr^v_u{PuM&^S9PB_BZy{KL59OZrbnS z=4G7gl*&TU4$5(XSBjc~t{}VKN%;zubSEzPn-N>yZ%G7f%eCMR588*pnVH}1Wif6UyPfBU1|&X4bw^YXg1xw>zbO>mPy{dVU< z>8IJ^OKZ%p%{DwZ^^WQGfM*L=u43{{j@EwO{>yUG!^F)OE|_G_xp^^OB7e`qB}UZ@ z`O&R)7k%$<4VjwEyKdgQLzj0P%aBR%JIg9>e)^PsI-_ked+lO#Pq%XhEWSAkxqn4| zxA@&ZCZV3U`O(^W=YyrQr8qUerns!O_4KG;q^1ycGF#@L_^+Bq^{MBJnE$T$F5-5q zvODLJtcRvr?wX8i?@sm zbI6!lyETHrpK-?ex+?;EHJEs+5+v8$zb#!-@hN}t-Mr=JS9tE(Cb^|EH(*mP+ijB< zOTP7eRQn}sdavg5*`Htf60L6c?atj@{Ic}tagp<1rf1!8TT&l7d9AI{Lu&zjzRapN zBf%+aR$MhH-jd zKdS7TX(E&*waV*wX7o>+=(DP^$--$G)Anu(tTH+O;N#?bCHrN!Z|rqByFK4@UZ1LP z*1gZJKW3$DYS@1AwNSlxe5#F}q2b!3Q%5gNU;9i+?$C?O@bjDFIav3P4v;9drofVod0clbC%is z8Rx9$Y3j-4KTC-1+S(Or`{Y_k(bl`tCtBH;CLH@W`CLPPnrG4OuU#Mf%?pM9 zY>A&RU%qE)&HsB_#UEtOIef}T)ik(2Nh{K7w&HTFM@>P&T>+kQ9tJKUX)+8uzTNU~ zOHO?7^?keh#Ci}KOWLCaT0=>C0hO#S=CPghP)JCPOhnltnSv%{C?U)W4eujo#`$A$01pr_2!A!7sqTCVKoX3G`RQe z!_&g28!eaHY*O41B_6gjtb0Y({wW;&Hy2!gzq#xU@6LdKgFYeR1m2*a*R+L6=kmW4mUBzLdP%oE~f2-?Z63t5<5rG~bD4 zg=e=c+!tTi*#E}@W+PVF`;kQ zHs7N%m-C0sguJ>M)&Y0X^OZ(A84Q=h7k{77A2;q|JI?w(b1UhGJi#(6_X$6I*m zlpz0AjJb*~r9qLtHc3XR`P&3HT2X};U)#Snd@|lS(B4x>|D2Y`>kVUlr8KM zu6vy7#%=7Ef_D>GKqt+@JpPaKm&&&GymRq?FcQ`kh$Zk+uKS})~`)8@oFKlLU zrIysI8kx^~?y5g`JNHqW9IfN?w)Y-Z-c#dQT{FR+hkLo(>$~NX z-}Jvy_gtPg<=254f6J&v#)f{3JC-otH~VoS!@a!M@8?-b(OZQ!4KCeF>>c@@X4lTh zn9_7O`i#H>U+3C&C#0DTpKUHJ{FS3J(W?4m$}e%Zs?Sp!ckk{o+i4OXap)V@;pJCf zKA0W0*ksY_RRucJ>ifCQ)pSqN&5)6>4~mNJDNdmg2lcGY3=hk)75uVT{#l=`{$ty0$!dZM7c;lY%(L1t{W zdQ*1=N4u(VPf(b?x~(z8;*CS?m0FHi7YD7{|Ej-aWp+1Qw9HvRiEKGZ}Gxcja!}9bRyGb6Kf~CYfK+29Sv*xb}mu-X5=Yx`u*9euJ)`of~$TYR_8zWU|O!Hya;QG*2{`YspKBIj?jJAeH_;^dM$eLKBR9!@)5@tyb9 zpIw3VALBMLEex_UjqbKOkaJ}o-|Z8d#2-bhKC`jN)+Uz!N!aV2BJG10WtM*Gy>NQ6 z)L(`AsI(o0zpvSDaoK%=z0{Q@OL8Zfar!wp z{9hw*!Mc>GO7m@j_QA@m$y%KX)j7Q`2(#&(uoG;0gvslhg{(SK6 z?4t(eruV~`H<)?b$@WzjZCdoYK`H6aPruEzmk;b* z_WOI;`}qCk_2OBjuTLGn&cECL+s!T7^8S9;^^d>kUUB}L+U^T$P6`H_)mwxrJyUmN zn0-pyP3!6=vsI#ttxS%4cm7}aq?Gxi{j?+Xn^s2m{eM^yC;R`s&+-2|zQ2_&FSFm* zIN9F%iNr@ot)xnw5*LOQz8lPrZSFkCa9I7#MiGw7CsQ`N-Aog!c0BqgW841pE$zor z7uWv0m#Tcs?&lQQo?k&n-|Xfw(~y^}XI($*-Ql&*`#yyl$mK;IFRzJw*R%c1n(o;v z{;(La)J=)rb|~y==b}>YN1u|8lp0RjHRZ)Z8{W`>$u-sDQ+H3$eBPsQEcwEPMO|u> zYuoImB$PU-erdAduCZ51%m_X%5;QAOp+z<4VW1T2ovqGNMskJsOISE#C5`wuXp5X# zJfXhN`s{S)ccGbk6BL!d?yuUCcP?e!m#!=Bg{#apK5+xM5h(FuFKwEp;ndzN zr``U4M5XxK{?`H9xBZV7{9S*p%Utfx-pVOktHjoRU!0h`F*7Rfm-l9G|K1JKi(d(C zwRV5H$@iz$CCj|zdeObc-+O)Ty3Jlvp0#w*`{M~S1T6df?EU}#^q3p3{qf47PDO8R z77_X9OD=C;qHWV}HL0no#5c=$5uc^lCG*(x)t;Bwx8AYQTsUEA$(djSLE9QL{qn01 z6ZeZ0654{~+VCm*W6k$ZX85{32t z-=3Hh-_T+8)4LrvHQDj+b_21V@V8=l{HN^#4V&2As*4uQTw7yzJocnk%6#3lr>goh zRoAUK)heFW)o5*T)#%2rs&|~J0bkVS^tOt)=?C%EvhRo&wYOfBeEhP{(acqU4sXt6 z*(+kXewO9wAf1^itDaWHtrMT!RezYnj_KRW1*Wx@H)g-f&oZglHOF(-4(pz>&1&z| zeAg)aJ}Gi1>G%wp#NevekGAtlNr+Fs_TiF{`P;Nv>oa3mvb9gXxD?&y+S@H3U;H4? z!Ytn^YWYK$L`(rxqy3RgT39p zqOaff`j@Sb-Cz9qTYqiM-)n#G{tkavS0U?vuwvhf`q*j%o0yZvM&G`-FbVHw-@eGv zR&1J;#JSejYf_jDub*a3y5{5I?Yc7NP#foiPYlV&Y!Z{dl+Aq-5$Lz?yox*%Pe99<$_^3vhJjw=y2JFR*1CT&f0>{;sKCRG^CuxVOb?5f<| zlW)}TjNGwxW`p~W`l@wLr@pc8Z`v7gyFUHczujLSBwq-Zzq6y%Ik*1tk;99w>ixFV zf0wrX@=R-wJ3mfU9O^BTKUUBA;CuB4@$~JdmPa4+TKnX~{d1N-{rff>wlvI5-|DWi zVR~=sXG7j;DyQ>f0w4eRHsf+yT^CEp9afh!Cznr`mo@9%<`TX{=wlb-#77Gz?UYnw z*`2HWe(vT22YH3xEooHV{Ih8j`_%e*MjFPd+;JO>=6(#gusFN#BFC?vFaKP9HQ&DU z{fkrjGv==LyL&Zg!8a+{{bzsnZ@$J{edTB6vBz?!%~u_G@v2PRdeXMePqGOQ-=x^R zXJt8|YFRTeP5$Q6NioyA{~hgCeQ18qmJK>3#`P%R^H%0zie~oGn={dJ@np9J8dWxKBs=s!yJXKE-m>lQWdKY&3LSL zqhgKa%?WBA%NCV~=&-C`_-~uLobNlG^O+fT96v4gH5(p#Jg>&-(fs6jcY4n}X$x51 zXnQ+p-!b!9-Sc;!&o}@1tRk2fd``6A zUV3Vo*T>9;{?q+y9=R?y|9-6JtGxV{m63jP>qXtej~d%Ip5GC(bE<)g?W(U5yQ*Gq zd{^=+=327$>n$(R6uA=WwL&BKT>n1IDdI}%ocj8E`DCN%Z&?`?>(?&cS9)c8->++d z_pM$U)bXTd&udXSMjLk+l7*3qRYREZG$6Fr!B{j#YB{gylC% z-b;M-)|&V}vGU@rdKdk}A8)R@o2|p&)<0F%;BfP7i5@4v3w!%a*u#QYvrXoNd#!w6 z9~o)4(^33<)5@Z)UY2V;*L?cpuVVP_r{??rTc7{=@B8TLXZ!U%|Lg0{zxS%Mn*1>5 z%u}JYvx^UFW>j4}{Q3Ch+JlSCCBNR>+^Kl=-a+OURi{!PRkqgO?R36VFE6Y7KKAjB zb;{nh`Wtj_yWP3=$Lz(cIiD8VZrXDB;f8pJXN&T$x_^Iv|K{GR&&R$-YianzZ#uZH z>j4k53+oS|tdfEQY)PBC58HhWnjBoIv8k{>u+Gyl`OGby$2|*%sgbsKxsx!OgQb@xruYSI*f+-}Lnj)%yR? zi!UppH7)4r6~^4FTXPf`gR+kn70o$SEchzwtn-o+f-)^JpJPS7Hzr@3p2)!{SD(qf z{guOxt-Q5j_x&^0?tdv}zp}DcW&LZ_TbH-~-83kaldEm>Lc|#&Q$%Wm%4su8T*qWX?5AVXHH1i z9$w!1S=L~Kyxp6$mz#?Z+}feZnVKekf8Fm57wV%j=a>CIKY!=W#((}D;qU(UMgOkf zJLg~g_p`hHPybz?X#I`t%YN5WfA4S3`uo4=*Z;_yeNp9Sjj#PbotS2J^MCH?jj#XJ z+x@QBQQy68@9FP1XM9{K^M2Xyp0mp9cm1D#_TPN|*v)Cb?`warKdn~!XMgdn|NT9| zq2J$szVZLF_u<#|a{r^B#r!XS1vcdF-uT{s@keh9Pb&=hzdb|qAG_+Z@Z0~F7yX?% z|CjUnzgzSF-kE#--+}tSU+@20{Qt*Z`Jdizw)52&edFH$EB@bQ{`)__T$=yqX8ou4 zb>AC5tN(lOUH{+5`}Ik8f3TZ>``7+`|G&Tb|9ba-eX;%jDgXcH^Z(TU>96_!+rIpz z{htf}uEzhpDX(n*qci@~{?FU%KRmAgb-ezu{{L?M`VZap@B3?h_3PC>=l|b&|L?=Y z@4vp>EdTG6{@+`h|9^k{|9SpD*IzI5|9$BH`)U3E+4C!Ym)E`iZU6cA+WN27_1~A* z|J+~y_}lxxx2Esk`Mdnq|KIcL9-q|zQ~$jFUv>Te_5bg?|Npf9-|hQ9&ere!y6(s3 z+yCFN=hyu9|9j>9_q4y}^`FB3Jq+6?`9Jsf*8D%m`F~`Kzn1%(^jDtWclMlh|Mi!q z{`HT!yzcpb|EE!B|8Kw4{Qd9i?fWKMe9ShVSIANMWX@0fUA4b&yB@zcZ{vBjS1J2G z*yo=tkvDs16n)Ui3$ zDl$Yqh_$xF`Sxe^JmtFt4y+&&3g)K{KzxS_- z6QA<%k%(lEUDlLy%T{sdJ}STS?Zl_GJB!ymyVR%3x4h8Z%9JxfR<|YO!q;>4zPlej zJ9ABhXW8*fGv1y4^YB7qewEdhWAC>cT$^$6nH#sn{ddYAS3CXjiRAyn*J|Cj@BN%D zr5#(eo`3rG!?XI%vHzd9yJ{=mY|p!d4I_SB;)b%trb>xD1;FN^#i+u6Q@*D;^SsgWYGLQxUoNXTx3j&zJKLeYUZgQ@$_AUe4t>^_ z)z_=M5A~0)vH7_A`pN#&zeKn{#N2=4GWW9*$8pP*RhMUcxRmlnRr|ThgG!x<1AANr z)r!h4YtGO3_o>gIJ?4CO=!Cq;*faUoiYu$WG-kaFU*PfKt{&I3bwX#H*6pV8|H406-|t1KRY*7?sxZ7?lzmKUN3g*(sNEni&EcZ zPfgj#F1jb@nZSw-QFCohYed(r@Ql3Z@YU*C(#ezgHzTvP&F7eS@40OGYRallS6d<* zRaS3}nmRpuzMZ>9=b1<@%hL|Cf-D_cPFLi#FGUwAlZ*0x|XVipTf0NTOgJCDDbg4*e-OjXm zN3RF|T>Q%9UInwWrXTMuE7qi!8Q0xe%X?ogd37V>&i(0bCPy4rN~9VjZWm;4FqNxY zW|W)QQ&KXs{@~>Q+Z2ya+2^)yQ|~cb&8vzbpP81V=gZYC`|Ue%?^?gbg~~xc)ni}Y zELg@Qw{UCKh1m&DZftL0JKu9NBY%za;%9!B9EuWLj(-bHZv5VCIP2&|f&K@7-48Rb zv{=J^Dg8ljdQH?D)+nx7Cr?(*od2rkBWNlz$Mm|A_D_N7*$?XfdOr#CNow5qcHv#t zuIE33QY4mHZF(*BIWInIgUPG&2^*%&X$!Nut-ajpQc1tqrW{9=Kgp{$JbI|dUbM7J zzbL6sxODNu4=W7*O}*cm6Z126Cd1hu9+z0tg)-;dvSV7lN^_G#nDpxK9UHBDz19_a zy`IbcD|}VI_>NkOuO#d06`ykalia9zKYxXA@8O3oW|ubi`nSKY5Su2$lV1Is zP5S*=z5_h7S8R^rTC!q`hj+57MD|(!sncd(p7}_Jk56HBjOcP_n}~`JZ?0&qs5h8A zWn%HxQ-0st{dq#Kw7tG@Z@ti|)KKkQ_hjMZw&$KNZY|0@y5r2bl-tvJj{AtufAjrE z-NrZG-sj3QY!BFM?`<-?Y~}U9Yu@X#I~#W_@~&GR#F~2Pdba3>($K8CPFuHC%?+7Q zWc|QT!RzJq)!f0qJhkT@)j9t^aqe}gKfkvM*B|}AtmWFr`SHj8tbbnpS*Dm>f75K;mj8G37F=Fl!PR#wq3G?gSc#QV@wKThMPgX-(@zRMNaMg`q=va2ireuUP;af&^LONW?ygn{h7e5|7Lz}Je#(zo>E}3F=x+j zx0l^+SF%keE&Tsl(vvUQYn7+OC5@?UCZ57J$L{JxpD)&b^s@Rv{ei^t*Of7iht0}< zo4t@;QUAE9koh>%n)|X4e>M&V{3Vy?dKHGkkcCuaVXIZHaCXFpz( z7-O(c`>Wv2%)2G2^G{rpSZy=a!0SkCr0t3={~pOHT)ZOTCg^vz*=fG)gOHG%z!xr6 zDLWT`D_!mHR{Owinm}-pmB|7XGr7&_6N1ml&E|XT&sVS`<-xVGX?aES`9$3x*2_;| zHDtb(?d&8jwft75RCI(_ux&_7R^HL~vyQ#C_L%r1UEF7xkRy-HJ!z?4_l3(|?)&NM zQSozw^dE9@XqVS*5(~4Pomr_e?3?k5xM&j zzjW`651GHcrs{6hbZ7cnAE+uhVMb{0ocze@{8=V{XY~Hj%PVtx;2RlnVME(Tn~f4& zQDK=IlXSOOT~>vDMwY*ifck@n9okM$~mU}`v2t5zXCpH`6>Qu z&%XTWUwnU5>7Vt%JCn}KN$@m?%`RUOxOj8d+r9kn?)CUv&8?ql{iI}hr(S)@$$}M; z1%JAIkNq^7EHI^Y;UqoP|9{V2%HN#-X%NF;)uoZaO9DRNN>U!@Bmifuos_sl-$?Xn~xnY;Hthx2u zL_Zal8@&D={MksG-6uBr^&_pDHA~lgxc21hyXE!!e!uv1?e+TYA7)zFl$U9mZM|?R z^y+&}ZI7u9Y?%nrAnaYzb zmhAmyXKy~)ih0^{p$jEhdjBMz=Ze*>UZyBk*ClLd{nVg7Q)~W?!%ETW7n?pP-Bd|8 z{vW%J@6@M@6Mg!!WVqNPCPx|F51zze(l*gz%D=NG4?70)PhGHo&u*Lb5p4|`u}t1~O?>!oWFO};+J zx_v=V!f~Tw`PBEp-*UfBfBENR$%?j&qc$OnEV`ecJn+`ZSn}8FHzL1pzdT{v_~`qr zn+kso!otp;+$Og8ZTrXl)m5(@wHBykmu*s+VfyfLjs@$T36Y{9o+mZ*FHWANaqFmW z@6j*I-K>~?-;2+-FU;EbW|6y_j`ys#qff7~_MW`F zd6I2ma?#t2bqj;E5`s5+sl4;u66twoiPP=O^jD>MtN&a! zSwY;(X_|_|g)pXaPvHcm&+9$1w8Wf)a#b^D-JCalC)d)|`=^?E7oAtzwb_PSSZtQm z)zhcyUlsV`(uN(3OL?v08$&H>%_gnb^gU#O@z>|tdym{zo8I${z11o; zOl{GX&t7`RHebE*Q`rB3PP^ATy*Kjh@tbcfE`I#KIk5b0s!aXg`(<;h{{CP3asOua zYiI8zSWH_k^k3BZz_jcCW4o_?wqITtyH36M_0Rh;|NCR>)35Jh{<7l7`DM?i{oe1p zXV?GvbN|lgt=Y%jStfQYTld}e9IfXI$cgezRa8cY-)9R-o1Tgu{W3IAGb4F`?E0TnfAVt z_D9z~Clz106Z_@?XX`WDdh5;o8_cejUirN=$|Bo(s)e9b_3hUjoS6}_9=q(hub!)X zx_{+55@H`Vws-Om%gb#M3gi&LL0(VeAn>*=QsKDn0{}ZTKM@$fS*C#_D}H@iB2lge|P= Date: Mon, 18 Apr 2022 19:50:30 +0000 Subject: [PATCH 080/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/add-trailing-comma: v2.2.2 → v2.2.3](https://github.com/asottile/add-trailing-comma/compare/v2.2.2...v2.2.3) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 887772b8..4d8dd1e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.2.2 + rev: v2.2.3 hooks: - id: add-trailing-comma args: [--py36-plus] From 777ffdd692b81db2432feccf8de16a6407a1d12a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 24 Apr 2022 18:04:19 -0400 Subject: [PATCH 081/416] deprecate pre-commit-validate-{config,manifest} --- .pre-commit-hooks.yaml | 4 ++-- pre_commit/clientlib.py | 30 +++++++++++------------- pre_commit/commands/validate_config.py | 16 +++++++++++++ pre_commit/commands/validate_manifest.py | 16 +++++++++++++ pre_commit/main.py | 26 ++++++++++++++++++-- tests/clientlib_test.py | 16 +++++++++++-- tests/main_test.py | 1 + 7 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 pre_commit/commands/validate_config.py create mode 100644 pre_commit/commands/validate_manifest.py diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 3d1ffbcb..e1aaf583 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,6 +1,6 @@ - id: validate_manifest name: validate pre-commit manifest description: This validator validates a pre-commit hooks manifest file - entry: pre-commit-validate-manifest + entry: pre-commit validate-manifest language: python - files: ^(\.pre-commit-hooks\.yaml|hooks\.yaml)$ + files: ^\.pre-commit-hooks\.yaml$ diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index bf4e2e45..9b53e810 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -14,6 +14,8 @@ from identify.identify import ALL_TAGS import pre_commit.constants as C from pre_commit.color import add_color_option +from pre_commit.commands.validate_config import validate_config +from pre_commit.commands.validate_manifest import validate_manifest from pre_commit.errors import FatalError from pre_commit.languages.all import all_languages from pre_commit.logging_handler import logging_handler @@ -100,14 +102,12 @@ def validate_manifest_main(argv: Sequence[str] | None = None) -> int: args = parser.parse_args(argv) with logging_handler(args.color): - ret = 0 - for filename in args.filenames: - try: - load_manifest(filename) - except InvalidManifestError as e: - print(e) - ret = 1 - return ret + logger.warning( + 'pre-commit-validate-manifest is deprecated -- ' + 'use `pre-commit validate-manifest` instead.', + ) + + return validate_manifest(args.filenames) LOCAL = 'local' @@ -409,11 +409,9 @@ def validate_config_main(argv: Sequence[str] | None = None) -> int: args = parser.parse_args(argv) with logging_handler(args.color): - ret = 0 - for filename in args.filenames: - try: - load_config(filename) - except InvalidConfigError as e: - print(e) - ret = 1 - return ret + logger.warning( + 'pre-commit-validate-config is deprecated -- ' + 'use `pre-commit validate-config` instead.', + ) + + return validate_config(args.filenames) diff --git a/pre_commit/commands/validate_config.py b/pre_commit/commands/validate_config.py new file mode 100644 index 00000000..91bb017a --- /dev/null +++ b/pre_commit/commands/validate_config.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from pre_commit import clientlib + + +def validate_config(filenames: list[str]) -> int: + ret = 0 + + for filename in filenames: + try: + clientlib.load_config(filename) + except clientlib.InvalidConfigError as e: + print(e) + ret = 1 + + return ret diff --git a/pre_commit/commands/validate_manifest.py b/pre_commit/commands/validate_manifest.py new file mode 100644 index 00000000..372a6380 --- /dev/null +++ b/pre_commit/commands/validate_manifest.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from pre_commit import clientlib + + +def validate_manifest(filenames: list[str]) -> int: + ret = 0 + + for filename in filenames: + try: + clientlib.load_manifest(filename) + except clientlib.InvalidManifestError as e: + print(e) + ret = 1 + + return ret diff --git a/pre_commit/main.py b/pre_commit/main.py index 645e97f7..6d2814b3 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -21,6 +21,8 @@ from pre_commit.commands.migrate_config import migrate_config from pre_commit.commands.run import run from pre_commit.commands.sample_config import sample_config from pre_commit.commands.try_repo import try_repo +from pre_commit.commands.validate_config import validate_config +from pre_commit.commands.validate_manifest import validate_manifest from pre_commit.error_handler import error_handler from pre_commit.logging_handler import logging_handler from pre_commit.store import Store @@ -34,8 +36,10 @@ logger = logging.getLogger('pre_commit') # pyvenv os.environ.pop('__PYVENV_LAUNCHER__', None) - -COMMANDS_NO_GIT = {'clean', 'gc', 'init-templatedir', 'sample-config'} +COMMANDS_NO_GIT = { + 'clean', 'gc', 'init-templatedir', 'sample-config', + 'validate-config', 'validate-manifest', +} def _add_config_option(parser: argparse.ArgumentParser) -> None: @@ -304,6 +308,20 @@ def main(argv: Sequence[str] | None = None) -> int: _add_config_option(uninstall_parser) _add_hook_type_option(uninstall_parser) + validate_config_parser = subparsers.add_parser( + 'validate-config', help='Validate .pre-commit-config.yaml files', + ) + add_color_option(validate_config_parser) + _add_config_option(validate_config_parser) + validate_config_parser.add_argument('filenames', nargs='*') + + validate_manifest_parser = subparsers.add_parser( + 'validate-manifest', help='Validate .pre-commit-hooks.yaml files', + ) + add_color_option(validate_manifest_parser) + _add_config_option(validate_manifest_parser) + validate_manifest_parser.add_argument('filenames', nargs='*') + help = subparsers.add_parser( 'help', help='Show help for a specific command.', ) @@ -378,6 +396,10 @@ def main(argv: Sequence[str] | None = None) -> int: config_file=args.config, hook_types=args.hook_types, ) + elif args.command == 'validate-config': + return validate_config(args.filenames) + elif args.command == 'validate-manifest': + return validate_manifest(args.filenames) else: raise NotImplementedError( f'Command {args.command} not implemented.', diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 3fb3af52..fb36bb55 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -122,8 +122,8 @@ def test_validate_config_old_list_format_ok(tmpdir, cap_out): f = tmpdir.join('cfg.yaml') f.write('- {repo: meta, hooks: [{id: identity}]}') assert not validate_config_main((f.strpath,)) - start = '[WARNING] normalizing pre-commit configuration to a top-level map' - assert cap_out.get().startswith(start) + msg = '[WARNING] normalizing pre-commit configuration to a top-level map' + assert msg in cap_out.get() def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog): @@ -139,6 +139,12 @@ def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog): ret_val = validate_config_main((f.strpath,)) assert not ret_val assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + 'pre-commit-validate-config is deprecated -- ' + 'use `pre-commit validate-config` instead.', + ), ( 'pre_commit', logging.WARNING, @@ -162,6 +168,12 @@ def test_validate_warn_on_unknown_keys_at_top_level(tmpdir, caplog): ret_val = validate_config_main((f.strpath,)) assert not ret_val assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + 'pre-commit-validate-config is deprecated -- ' + 'use `pre-commit validate-config` instead.', + ), ( 'pre_commit', logging.WARNING, diff --git a/tests/main_test.py b/tests/main_test.py index a645300a..a7afd6da 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -79,6 +79,7 @@ def test_adjust_args_try_repo_repo_relative(in_git_dir): FNS = ( 'autoupdate', 'clean', 'gc', 'hook_impl', 'install', 'install_hooks', 'migrate_config', 'run', 'sample_config', 'uninstall', + 'validate_config', 'validate_manifest', ) CMDS = tuple(fn.replace('_', '-') for fn in FNS) From 3929fe4a6323e68ee5e6f9a185a18bbacfd311b9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 24 Apr 2022 19:09:05 -0400 Subject: [PATCH 082/416] upgrade CI to ubuntu-latest / windows-latest --- azure-pipelines.yml | 2 +- testing/get-swift.sh | 6 +++--- tests/repository_test.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index afb29828..454f6f13 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,7 +10,7 @@ resources: type: github endpoint: github name: asottile/azure-pipeline-templates - ref: refs/tags/v2.1.0 + ref: refs/tags/v2.4.1 jobs: - template: job--python-tox.yml@asottile diff --git a/testing/get-swift.sh b/testing/get-swift.sh index a05b7b9e..b77e18c0 100755 --- a/testing/get-swift.sh +++ b/testing/get-swift.sh @@ -3,9 +3,9 @@ set -euo pipefail . /etc/lsb-release -if [ "$DISTRIB_CODENAME" = "bionic" ]; then - SWIFT_URL='https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz' - SWIFT_HASH='ac82ccd773fe3d586fc340814e31e120da1ff695c6a712f6634e9cc720769610' +if [ "$DISTRIB_CODENAME" = "focal" ]; then + SWIFT_URL='https://download.swift.org/swift-5.6.1-release/ubuntu2004/swift-5.6.1-RELEASE/swift-5.6.1-RELEASE-ubuntu20.04.tar.gz' + SWIFT_HASH='2b4f22d4a8b59fe8e050f0b7f020f8d8f12553cbda56709b2340a4a3bb90cfea' else echo "unknown dist: ${DISTRIB_CODENAME}" 1>&2 exit 1 diff --git a/tests/repository_test.py b/tests/repository_test.py index cfa69c9f..3729ab1d 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -173,6 +173,7 @@ def test_python_venv(tempdir_factory, store): ) +@xfailif_windows # pragma: win32 no cover # no python 2 in GHA def test_switch_language_versions_doesnt_clobber(tempdir_factory, store): # We're using the python3 repo because it prints the python version path = make_repo(tempdir_factory, 'python3_hooks_repo') @@ -892,6 +893,7 @@ def test_local_python_repo(store, local_python_config): assert _norm_out(out) == b"3\n['filename']\nHello World\n" +@xfailif_windows # pragma: win32 no cover # no python2 in GHA def test_local_python_repo_python2(store, local_python_config): local_python_config['hooks'][0]['language_version'] = 'python2' hook = _get_hook(local_python_config, store, 'python3-hook') From 81129cefa550ad01d3b485f6a3015201948d33c8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 20:18:58 +0000 Subject: [PATCH 083/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v3.0.1 → v3.1.0](https://github.com/asottile/reorder_python_imports/compare/v3.0.1...v3.1.0) - [github.com/pre-commit/mirrors-mypy: v0.942 → v0.950](https://github.com/pre-commit/mirrors-mypy/compare/v0.942...v0.950) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4d8dd1e2..7791f765 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.0.1 + rev: v3.1.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.942 + rev: v0.950 hooks: - id: mypy additional_dependencies: [types-all] From af467017c21d4b4e36da87a7b6e933fbc8e48cb6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 4 May 2022 11:49:47 -0700 Subject: [PATCH 084/416] add search term required input to issue template --- .github/ISSUE_TEMPLATE/bug.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index 6cce5fef..9ee61d18 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -9,6 +9,13 @@ body: [pre-commit.ci]: https://pre-commit.ci [pre-commit-ci/issues]: https://github.com/pre-commit-ci/issues + - type: input + id: version + attributes: + label: search tried in the issue tracker + placeholder: ... + validations: + required: true - type: textarea id: freeform attributes: From 96bf685380e3a89f3a03b5d542249f31a4bdfe53 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 4 May 2022 21:22:24 -0400 Subject: [PATCH 085/416] fix non-unique id --- .github/ISSUE_TEMPLATE/bug.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index 9ee61d18..bfced0f2 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -10,7 +10,7 @@ body: [pre-commit.ci]: https://pre-commit.ci [pre-commit-ci/issues]: https://github.com/pre-commit-ci/issues - type: input - id: version + id: search attributes: label: search tried in the issue tracker placeholder: ... From cc9d950601cd3eba27e8395a7edcd455262705d9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 5 May 2022 06:54:43 -0700 Subject: [PATCH 086/416] v2.19.0 --- CHANGELOG.md | 24 ++++++++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd31c4b1..1b6d8b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +2.19.0 - 2022-05-05 +=================== + +### Features +- Allow multiple outputs from `language: dotnet` hooks. + - #2332 PR by @WallucePinkham. +- Add more information to `healthy()` failure. + - #2348 PR by @asottile. +- Upgrade ruby-build. + - #2342 PR by @jalessio. +- Add `pre-commit validate-config` / `pre-commit validate-manifest` and + deprecate `pre-commit-validate-config` and `pre-commit-validate-manifest`. + - #2362 PR by @asottile. + +### Fixes +- Fix `pre-push` when pushed ref contains spaces. + - #2345 PR by @wwade. + - #2344 issue by @wwade. + +### Updating +- Change `pre-commit-validate-config` / `pre-commit-validate-manifest` to + `pre-commit validate-config` / `pre-commit validate-manifest`. + - #2362 PR by @asottile. + 2.18.1 - 2022-04-02 =================== diff --git a/setup.cfg b/setup.cfg index ca92af3e..93a485c5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.18.1 +version = 2.19.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From a54391e96f27b8a75acfa14bac5dc39ea96994da Mon Sep 17 00:00:00 2001 From: Paul Gey Date: Sat, 7 May 2022 20:44:02 +0200 Subject: [PATCH 087/416] Force gem installation into `GEM_HOME` When `--user-install` is set in the gemrc config file, `gem` ignores `GEM_HOME`. `--no-user-install` prevents this behaviour. --- pre_commit/languages/ruby.py | 1 + tests/repository_test.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 6c5cff28..8955dd01 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -138,6 +138,7 @@ def install_environment( ( 'gem', 'install', '--no-document', '--no-format-executable', + '--no-user-install', *prefix.star('.gem'), *additional_dependencies, ), ) diff --git a/tests/repository_test.py b/tests/repository_test.py index 3729ab1d..11d452ca 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -332,6 +332,13 @@ def test_run_a_ruby_hook(tempdir_factory, store): ) +def test_run_a_ruby_hook_with_user_install_set(tempdir_factory, store, tmpdir): + gemrc = tmpdir.join('gemrc') + gemrc.write('gem: --user-install\n') + with envcontext((('GEMRC', str(gemrc)),)): + test_run_a_ruby_hook(tempdir_factory, store) + + @xfailif_windows # pragma: win32 no cover def test_run_versioned_ruby_hook(tempdir_factory, store): _test_hook_repo( From 323fd0d18819322359c7479c31f8921f96fac995 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 20:28:33 +0000 Subject: [PATCH 088/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.32.0 → v2.32.1](https://github.com/asottile/pyupgrade/compare/v2.32.0...v2.32.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7791f765..c4cf5b46 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.32.0 + rev: v2.32.1 hooks: - id: pyupgrade args: [--py37-plus] From a84136d070d7f010ad187f808bac2d57bf822506 Mon Sep 17 00:00:00 2001 From: "Gaige B. Paulsen" Date: Sat, 14 May 2022 09:15:03 +0000 Subject: [PATCH 089/416] Switch pty use to fix solaris Use the child instead of parent fd when manipulating pty for color. --- pre_commit/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/util.py b/pre_commit/util.py index 40c53e51..8c296f4d 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -168,10 +168,10 @@ if os.name != 'nt': # pragma: win32 no cover self.r, self.w = openpty() # tty flags normally change \n to \r\n - attrs = termios.tcgetattr(self.r) + attrs = termios.tcgetattr(self.w) assert isinstance(attrs[1], int) attrs[1] &= ~(termios.ONLCR | termios.OPOST) - termios.tcsetattr(self.r, termios.TCSANOW, attrs) + termios.tcsetattr(self.w, termios.TCSANOW, attrs) return self From 34e97023f4b0383abec38d484631daef80d96a6c Mon Sep 17 00:00:00 2001 From: "Gaige B. Paulsen" Date: Sat, 14 May 2022 08:28:08 -0400 Subject: [PATCH 090/416] force default branch name for tests --- testing/fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/fixtures.py b/testing/fixtures.py index ef5a0418..5182a083 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -38,7 +38,7 @@ def copy_tree_to_path(src_dir, dest_dir): def git_dir(tempdir_factory): path = tempdir_factory.get() - cmd_output('git', 'init', path) + cmd_output('git', '-c', 'init.defaultBranch=master', 'init', path) return path From fb0ccf3546a9cb34ec3692e403270feb6d6033a2 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 26 May 2022 09:43:30 -0400 Subject: [PATCH 091/416] correct one slight inaccuracy in language docs --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fa1678ca..310c17ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,7 +72,7 @@ to implement. The current implemented languages are at varying levels: - 3rd class - pre-commit requires the user to install both the tool and the language globally (current examples: script, system) -"third class" is usually the easiest to implement first and is perfectly +"second class" is usually the easiest to implement first and is perfectly acceptable. Ideally the language works on the supported platforms for pre-commit (linux, From 50589386af364c9d3f2c46f5f6e328ee9a500c24 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 20:32:51 +0000 Subject: [PATCH 092/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.950 → v0.960](https://github.com/pre-commit/mirrors-mypy/compare/v0.950...v0.960) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c4cf5b46..e50b1b95 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.950 + rev: v0.960 hooks: - id: mypy additional_dependencies: [types-all] From 702ebf402cac8f1914b689ea198bcf3d68422d03 Mon Sep 17 00:00:00 2001 From: Matt Whitaker Date: Fri, 27 May 2022 17:03:21 +0100 Subject: [PATCH 093/416] Expose prepare-commit-msg arguments as environment vars --- pre_commit/commands/hook_impl.py | 18 +++++++++++++++- pre_commit/commands/run.py | 10 +++++++++ pre_commit/main.py | 14 +++++++++++++ testing/util.py | 4 ++++ tests/commands/hook_impl_test.py | 36 ++++++++++++++++++++++++++++++++ tests/commands/run_test.py | 7 ++++++- 6 files changed, 87 insertions(+), 2 deletions(-) diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index f315c04d..f5995e9a 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -76,6 +76,8 @@ def _ns( remote_name: str | None = None, remote_url: str | None = None, commit_msg_filename: str | None = None, + prepare_commit_message_source: str | None = None, + commit_object_name: str | None = None, checkout_type: str | None = None, is_squash_merge: str | None = None, rewrite_command: str | None = None, @@ -90,6 +92,8 @@ def _ns( remote_name=remote_name, remote_url=remote_url, commit_msg_filename=commit_msg_filename, + prepare_commit_message_source=prepare_commit_message_source, + commit_object_name=commit_object_name, all_files=all_files, checkout_type=checkout_type, is_squash_merge=is_squash_merge, @@ -202,8 +206,20 @@ def _run_ns( _check_args_length(hook_type, args) if hook_type == 'pre-push': return _pre_push_ns(color, args, stdin) - elif hook_type in {'commit-msg', 'prepare-commit-msg'}: + elif hook_type in 'commit-msg': return _ns(hook_type, color, commit_msg_filename=args[0]) + elif hook_type == 'prepare-commit-msg' and len(args) == 1: + return _ns(hook_type, color, commit_msg_filename=args[0]) + elif hook_type == 'prepare-commit-msg' and len(args) == 2: + return _ns( + hook_type, color, commit_msg_filename=args[0], + prepare_commit_message_source=args[1], + ) + elif hook_type == 'prepare-commit-msg' and len(args) == 3: + return _ns( + hook_type, color, commit_msg_filename=args[0], + prepare_commit_message_source=args[1], commit_object_name=args[2], + ) elif hook_type in {'post-commit', 'pre-merge-commit', 'pre-commit'}: return _ns(hook_type, color) elif hook_type == 'post-checkout': diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 37f989b5..ad3d766e 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -361,6 +361,16 @@ def run( ): return 0 + # Expose prepare_commit_message_source / commit_object_name + # as environment variables for the hooks + if args.prepare_commit_message_source: + environ['PRE_COMMIT_COMMIT_MSG_SOURCE'] = ( + args.prepare_commit_message_source + ) + + if args.commit_object_name: + environ['PRE_COMMIT_COMMIT_OBJECT_NAME'] = args.commit_object_name + # Expose from-ref / to-ref as environment variables for hooks to consume if args.from_ref and args.to_ref: # legacy names diff --git a/pre_commit/main.py b/pre_commit/main.py index 6d2814b3..41278ca9 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -107,6 +107,20 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None: '--commit-msg-filename', help='Filename to check when running during `commit-msg`', ) + parser.add_argument( + '--prepare-commit-message-source', + help=( + 'Source of the commit message ' + '(typically the second argument to .git/hooks/prepare-commit-msg)' + ), + ) + parser.add_argument( + '--commit-object-name', + help=( + 'Commit object name ' + '(typically the third argument to .git/hooks/prepare-commit-msg)' + ), + ) parser.add_argument( '--remote-name', help='Remote name used by `git push`.', ) diff --git a/testing/util.py b/testing/util.py index 0dd17840..e807f048 100644 --- a/testing/util.py +++ b/testing/util.py @@ -76,6 +76,8 @@ def run_opts( hook_stage='commit', show_diff_on_failure=False, commit_msg_filename='', + prepare_commit_message_source='', + commit_object_name='', checkout_type='', is_squash_merge='', rewrite_command='', @@ -97,6 +99,8 @@ def run_opts( hook_stage=hook_stage, show_diff_on_failure=show_diff_on_failure, commit_msg_filename=commit_msg_filename, + prepare_commit_message_source=prepare_commit_message_source, + commit_object_name=commit_object_name, checkout_type=checkout_type, is_squash_merge=is_squash_merge, rewrite_command=rewrite_command, diff --git a/tests/commands/hook_impl_test.py b/tests/commands/hook_impl_test.py index 3e20874e..aa321dab 100644 --- a/tests/commands/hook_impl_test.py +++ b/tests/commands/hook_impl_test.py @@ -154,6 +154,42 @@ def test_run_ns_commit_msg(): assert ns.commit_msg_filename == '.git/COMMIT_MSG' +def test_run_ns_prepare_commit_msg_one_arg(): + ns = hook_impl._run_ns( + 'prepare-commit-msg', False, + ('.git/COMMIT_MSG',), b'', + ) + assert ns is not None + assert ns.hook_stage == 'prepare-commit-msg' + assert ns.color is False + assert ns.commit_msg_filename == '.git/COMMIT_MSG' + + +def test_run_ns_prepare_commit_msg_two_arg(): + ns = hook_impl._run_ns( + 'prepare-commit-msg', False, + ('.git/COMMIT_MSG', 'message'), b'', + ) + assert ns is not None + assert ns.hook_stage == 'prepare-commit-msg' + assert ns.color is False + assert ns.commit_msg_filename == '.git/COMMIT_MSG' + assert ns.prepare_commit_message_source == 'message' + + +def test_run_ns_prepare_commit_msg_three_arg(): + ns = hook_impl._run_ns( + 'prepare-commit-msg', False, + ('.git/COMMIT_MSG', 'message', 'HEAD'), b'', + ) + assert ns is not None + assert ns.hook_stage == 'prepare-commit-msg' + assert ns.color is False + assert ns.commit_msg_filename == '.git/COMMIT_MSG' + assert ns.prepare_commit_message_source == 'message' + assert ns.commit_object_name == 'HEAD' + + def test_run_ns_post_commit(): ns = hook_impl._run_ns('post-commit', True, (), b'') assert ns is not None diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 085b063f..2634c0c5 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -810,7 +810,12 @@ def test_prepare_commit_msg_hook(cap_out, store, prepare_commit_msg_repo): cap_out, store, prepare_commit_msg_repo, - {'hook_stage': 'prepare-commit-msg', 'commit_msg_filename': filename}, + { + 'hook_stage': 'prepare-commit-msg', + 'commit_msg_filename': filename, + 'prepare_commit_message_source': 'commit', + 'commit_object_name': 'HEAD', + }, expected_outputs=[b'Add "Signed off by:"', b'Passed'], expected_ret=0, stage=False, From efc1d059fa3f0b650810ccebd6aa306c7df5a7f3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 21:57:06 +0000 Subject: [PATCH 094/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.2.0 → v4.3.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.2.0...v4.3.0) - [github.com/asottile/pyupgrade: v2.32.1 → v2.34.0](https://github.com/asottile/pyupgrade/compare/v2.32.1...v2.34.0) - [github.com/pre-commit/mirrors-mypy: v0.960 → v0.961](https://github.com/pre-commit/mirrors-mypy/compare/v0.960...v0.961) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e50b1b95..1bdabc1c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.3.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.32.1 + rev: v2.34.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.960 + rev: v0.961 hooks: - id: mypy additional_dependencies: [types-all] From 53643def070f8b106d08727b35fd9b7dc4a7b1a7 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 22 Jun 2022 15:56:50 -0700 Subject: [PATCH 095/416] remove unused --config options from commands which don't use it --- pre_commit/main.py | 83 ++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/pre_commit/main.py b/pre_commit/main.py index 41278ca9..b4fa9661 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -181,11 +181,15 @@ def main(argv: Sequence[str] | None = None) -> int: subparsers = parser.add_subparsers(dest='command') - autoupdate_parser = subparsers.add_parser( + def _add_cmd(name: str, *, help: str) -> argparse.ArgumentParser: + parser = subparsers.add_parser(name, help=help) + add_color_option(parser) + return parser + + autoupdate_parser = _add_cmd( 'autoupdate', help="Auto-update pre-commit config to the latest repos' versions.", ) - add_color_option(autoupdate_parser) _add_config_option(autoupdate_parser) autoupdate_parser.add_argument( '--bleeding-edge', action='store_true', @@ -203,34 +207,17 @@ def main(argv: Sequence[str] | None = None) -> int: help='Only update this repository -- may be specified multiple times.', ) - clean_parser = subparsers.add_parser( - 'clean', help='Clean out pre-commit files.', - ) - add_color_option(clean_parser) - _add_config_option(clean_parser) + _add_cmd('clean', help='Clean out pre-commit files.') - hook_impl_parser = subparsers.add_parser('hook-impl') - add_color_option(hook_impl_parser) - _add_config_option(hook_impl_parser) - hook_impl_parser.add_argument('--hook-type') - hook_impl_parser.add_argument('--hook-dir') - hook_impl_parser.add_argument( - '--skip-on-missing-config', action='store_true', - ) - hook_impl_parser.add_argument(dest='rest', nargs=argparse.REMAINDER) + _add_cmd('gc', help='Clean unused cached repos.') - gc_parser = subparsers.add_parser('gc', help='Clean unused cached repos.') - add_color_option(gc_parser) - _add_config_option(gc_parser) - - init_templatedir_parser = subparsers.add_parser( + init_templatedir_parser = _add_cmd( 'init-templatedir', help=( 'Install hook script in a directory intended for use with ' '`git config init.templateDir`.' ), ) - add_color_option(init_templatedir_parser) _add_config_option(init_templatedir_parser) init_templatedir_parser.add_argument( 'directory', help='The directory in which to write the hook script.', @@ -243,10 +230,7 @@ def main(argv: Sequence[str] | None = None) -> int: ) _add_hook_type_option(init_templatedir_parser) - install_parser = subparsers.add_parser( - 'install', help='Install the pre-commit script.', - ) - add_color_option(install_parser) + install_parser = _add_cmd('install', help='Install the pre-commit script.') _add_config_option(install_parser) install_parser.add_argument( '-f', '--overwrite', action='store_true', @@ -268,7 +252,7 @@ def main(argv: Sequence[str] | None = None) -> int: ), ) - install_hooks_parser = subparsers.add_parser( + install_hooks_parser = _add_cmd( 'install-hooks', help=( 'Install hook environments for all environments in the config ' @@ -276,32 +260,24 @@ def main(argv: Sequence[str] | None = None) -> int: 'useful.' ), ) - add_color_option(install_hooks_parser) _add_config_option(install_hooks_parser) - migrate_config_parser = subparsers.add_parser( + migrate_config_parser = _add_cmd( 'migrate-config', help='Migrate list configuration to new map configuration.', ) - add_color_option(migrate_config_parser) _add_config_option(migrate_config_parser) - run_parser = subparsers.add_parser('run', help='Run hooks.') - add_color_option(run_parser) + run_parser = _add_cmd('run', help='Run hooks.') _add_config_option(run_parser) _add_run_options(run_parser) - sample_config_parser = subparsers.add_parser( - 'sample-config', help=f'Produce a sample {C.CONFIG_FILE} file', - ) - add_color_option(sample_config_parser) - _add_config_option(sample_config_parser) + _add_cmd('sample-config', help=f'Produce a sample {C.CONFIG_FILE} file') - try_repo_parser = subparsers.add_parser( + try_repo_parser = _add_cmd( 'try-repo', help='Try the hooks in a repository, useful for developing new hooks.', ) - add_color_option(try_repo_parser) _add_config_option(try_repo_parser) try_repo_parser.add_argument( 'repo', help='Repository to source hooks from.', @@ -315,32 +291,39 @@ def main(argv: Sequence[str] | None = None) -> int: ) _add_run_options(try_repo_parser) - uninstall_parser = subparsers.add_parser( + uninstall_parser = _add_cmd( 'uninstall', help='Uninstall the pre-commit script.', ) - add_color_option(uninstall_parser) _add_config_option(uninstall_parser) _add_hook_type_option(uninstall_parser) - validate_config_parser = subparsers.add_parser( + validate_config_parser = _add_cmd( 'validate-config', help='Validate .pre-commit-config.yaml files', ) - add_color_option(validate_config_parser) - _add_config_option(validate_config_parser) validate_config_parser.add_argument('filenames', nargs='*') - validate_manifest_parser = subparsers.add_parser( + validate_manifest_parser = _add_cmd( 'validate-manifest', help='Validate .pre-commit-hooks.yaml files', ) - add_color_option(validate_manifest_parser) - _add_config_option(validate_manifest_parser) validate_manifest_parser.add_argument('filenames', nargs='*') + # does not use `_add_cmd` because it doesn't use `--color` help = subparsers.add_parser( 'help', help='Show help for a specific command.', ) help.add_argument('help_cmd', nargs='?', help='Command to show help for.') + # not intended for users to call this directly + hook_impl_parser = subparsers.add_parser('hook-impl') + add_color_option(hook_impl_parser) + _add_config_option(hook_impl_parser) + hook_impl_parser.add_argument('--hook-type') + hook_impl_parser.add_argument('--hook-dir') + hook_impl_parser.add_argument( + '--skip-on-missing-config', action='store_true', + ) + hook_impl_parser.add_argument(dest='rest', nargs=argparse.REMAINDER) + # argparse doesn't really provide a way to use a `default` subparser if len(argv) == 0: argv = ['run'] @@ -354,11 +337,11 @@ def main(argv: Sequence[str] | None = None) -> int: with error_handler(), logging_handler(args.color): git.check_for_cygwin_mismatch() + store = Store() + if args.command not in COMMANDS_NO_GIT: _adjust_args_and_chdir(args) - - store = Store() - store.mark_config_used(args.config) + store.mark_config_used(args.config) if args.command == 'autoupdate': return autoupdate( From d8b59300ce44918bcfa070eff06d2f861222c3fa Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 4 Jul 2022 17:57:38 -0400 Subject: [PATCH 096/416] remove imports from TYPE_CHECKING (py37+) Committed via https://github.com/asottile/all-repos --- pre_commit/languages/helpers.py | 5 +---- pre_commit/parse_shebang.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 05a71651..0be08b54 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -5,9 +5,9 @@ import os import random import re from typing import Any +from typing import NoReturn from typing import overload from typing import Sequence -from typing import TYPE_CHECKING import pre_commit.constants as C from pre_commit import parse_shebang @@ -16,9 +16,6 @@ from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b from pre_commit.xargs import xargs -if TYPE_CHECKING: - from typing import NoReturn - FIXED_RANDOM_SEED = 1542676187 SHIMS_RE = re.compile(r'[/\\]shims[/\\]') diff --git a/pre_commit/parse_shebang.py b/pre_commit/parse_shebang.py index 3fd3129f..3ac933c0 100644 --- a/pre_commit/parse_shebang.py +++ b/pre_commit/parse_shebang.py @@ -2,13 +2,10 @@ from __future__ import annotations import os.path from typing import Mapping -from typing import TYPE_CHECKING +from typing import NoReturn from identify.identify import parse_shebang_from_file -if TYPE_CHECKING: - from typing import NoReturn - class ExecutableNotFoundError(OSError): def to_output(self) -> tuple[int, bytes, None]: From 3ebd101eb5e450c9e9d2345ffe72c78838fb2316 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 21:58:49 +0000 Subject: [PATCH 097/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v3.1.0 → v3.3.0](https://github.com/asottile/reorder_python_imports/compare/v3.1.0...v3.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1bdabc1c..94a35a76 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.1.0 + rev: v3.3.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) From 901e831313e897e3b9313f5efbb5ef589b3e279c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Sun, 10 Jul 2022 02:03:56 +0200 Subject: [PATCH 098/416] Tests: Adjust traceback regexes to allow Python 3.11+ ^^^^^^^ Fixes https://github.com/pre-commit/pre-commit/issues/2451 --- tests/error_handler_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/error_handler_test.py b/tests/error_handler_test.py index 31c71d28..47e2afaa 100644 --- a/tests/error_handler_test.py +++ b/tests/error_handler_test.py @@ -45,9 +45,11 @@ def test_error_handler_fatal_error(mocked_log_and_exit): r'Traceback \(most recent call last\):\n' r' File ".+pre_commit.error_handler.py", line \d+, in error_handler\n' r' yield\n' + r'( \^\^\^\^\^\n)?' r' File ".+tests.error_handler_test.py", line \d+, ' r'in test_error_handler_fatal_error\n' r' raise exc\n' + r'( \^\^\^\^\^\^\^\^\^\n)?' r'(pre_commit\.errors\.)?FatalError: just a test\n', ) pattern.assert_matches(mocked_log_and_exit.call_args[0][3]) @@ -69,9 +71,11 @@ def test_error_handler_uncaught_error(mocked_log_and_exit): r'Traceback \(most recent call last\):\n' r' File ".+pre_commit.error_handler.py", line \d+, in error_handler\n' r' yield\n' + r'( \^\^\^\^\^\n)?' r' File ".+tests.error_handler_test.py", line \d+, ' r'in test_error_handler_uncaught_error\n' r' raise exc\n' + r'( \^\^\^\^\^\^\^\^\^\n)?' r'ValueError: another test\n', ) pattern.assert_matches(mocked_log_and_exit.call_args[0][3]) @@ -93,9 +97,11 @@ def test_error_handler_keyboardinterrupt(mocked_log_and_exit): r'Traceback \(most recent call last\):\n' r' File ".+pre_commit.error_handler.py", line \d+, in error_handler\n' r' yield\n' + r'( \^\^\^\^\^\n)?' r' File ".+tests.error_handler_test.py", line \d+, ' r'in test_error_handler_keyboardinterrupt\n' r' raise exc\n' + r'( \^\^\^\^\^\^\^\^\^\n)?' r'KeyboardInterrupt\n', ) pattern.assert_matches(mocked_log_and_exit.call_args[0][3]) From ebce88c13d09000f6d1c04a6232ad14fe9c5e33d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 10 Jul 2022 14:20:14 -0400 Subject: [PATCH 099/416] remove warnings checks this wasn't all that useful -- and most of it was for checking python 2 things --- tests/conftest.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index b68a1d00..40c0c050 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,24 +21,6 @@ from testing.util import cwd from testing.util import git_commit -@pytest.fixture(autouse=True) -def no_warnings(recwarn): - yield - warnings = [] - for warning in recwarn: # pragma: no cover - message = str(warning.message) - # ImportWarning: Not importing directory '...' missing __init__(.py) - if not ( - isinstance(warning.message, ImportWarning) and - message.startswith('Not importing directory ') and - ' missing __init__' in message - ): - warnings.append( - f'{warning.filename}:{warning.lineno} {message}', - ) - assert not warnings - - @pytest.fixture def tempdir_factory(tmpdir): class TmpdirFactory: From 78a2d867feac2c1602a608c1fa4eeecb2f8bb415 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 10 Jul 2022 20:55:02 -0400 Subject: [PATCH 100/416] v2.20.0 --- CHANGELOG.md | 20 ++++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6d8b65..03a7c800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +2.20.0 - 2022-07-10 +=================== + +### Features +- Expose `source` and `object-name` (positional args) of `prepare-commit-msg` + hook as `PRE_COMMIT_COMIT_MSG_SOURCE` and `PRE_COMMIT_COMMIT_OBJECT_NAME`. + - #2407 PR by @M-Whitaker. + - #2406 issue by @M-Whitaker. + +### Fixes +- Fix `language: ruby` installs when `--user-install` is set in gemrc. + - #2394 PR by @narpfel. + - #2393 issue by @narpfel. +- Adjust pty setup for solaris. + - #2390 PR by @gaige. + - #2389 issue by @gaige. +- Remove unused `--config` option from `gc`, `sample-config`, + `validate-config`, `validate-manifest` sub-commands. + - #2429 PR by @asottile. + 2.19.0 - 2022-05-05 =================== diff --git a/setup.cfg b/setup.cfg index 93a485c5..ae214f65 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.19.0 +version = 2.20.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 0cef48edbfac863771aad34e43637e05fd57e56a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 21:25:15 +0000 Subject: [PATCH 101/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v3.3.0 → v3.8.1](https://github.com/asottile/reorder_python_imports/compare/v3.3.0...v3.8.1) - [github.com/asottile/pyupgrade: v2.34.0 → v2.37.1](https://github.com/asottile/pyupgrade/compare/v2.34.0...v2.37.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94a35a76..511ffd52 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.3.0 + rev: v3.8.1 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.34.0 + rev: v2.37.1 hooks: - id: pyupgrade args: [--py37-plus] From db51d3009f5cbeee6aafdc3e7c0cbbd2627a1a78 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 12 Jul 2022 14:08:57 -0400 Subject: [PATCH 102/416] adjust relative --commit-msg-filename if in subdir --- pre_commit/main.py | 8 +++++++ tests/main_test.py | 53 ++++++++++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/pre_commit/main.py b/pre_commit/main.py index b4fa9661..3915993f 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -155,6 +155,10 @@ def _adjust_args_and_chdir(args: argparse.Namespace) -> None: args.config = os.path.abspath(args.config) if args.command in {'run', 'try-repo'}: args.files = [os.path.abspath(filename) for filename in args.files] + if args.commit_msg_filename is not None: + args.commit_msg_filename = os.path.abspath( + args.commit_msg_filename, + ) if args.command == 'try-repo' and os.path.exists(args.repo): args.repo = os.path.abspath(args.repo) @@ -164,6 +168,10 @@ def _adjust_args_and_chdir(args: argparse.Namespace) -> None: args.config = os.path.relpath(args.config) if args.command in {'run', 'try-repo'}: args.files = [os.path.relpath(filename) for filename in args.files] + if args.commit_msg_filename is not None: + args.commit_msg_filename = os.path.relpath( + args.commit_msg_filename, + ) if args.command == 'try-repo' and os.path.exists(args.repo): args.repo = os.path.relpath(args.repo) diff --git a/tests/main_test.py b/tests/main_test.py index a7afd6da..51159262 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -17,6 +17,8 @@ from testing.util import cwd def _args(**kwargs): kwargs.setdefault('command', 'help') kwargs.setdefault('config', C.CONFIG_FILE) + if kwargs['command'] in {'run', 'try-repo'}: + kwargs.setdefault('commit_msg_filename', None) return argparse.Namespace(**kwargs) @@ -35,13 +37,24 @@ def test_adjust_args_and_chdir_noop(in_git_dir): def test_adjust_args_and_chdir_relative_things(in_git_dir): in_git_dir.join('foo/cfg.yaml').ensure() - in_git_dir.join('foo').chdir() + with in_git_dir.join('foo').as_cwd(): + args = _args(command='run', files=['f1', 'f2'], config='cfg.yaml') + main._adjust_args_and_chdir(args) + assert os.getcwd() == in_git_dir + assert args.config == os.path.join('foo', 'cfg.yaml') + assert args.files == [ + os.path.join('foo', 'f1'), + os.path.join('foo', 'f2'), + ] - args = _args(command='run', files=['f1', 'f2'], config='cfg.yaml') - main._adjust_args_and_chdir(args) - assert os.getcwd() == in_git_dir - assert args.config == os.path.join('foo', 'cfg.yaml') - assert args.files == [os.path.join('foo', 'f1'), os.path.join('foo', 'f2')] + +def test_adjust_args_and_chdir_relative_commit_msg(in_git_dir): + in_git_dir.join('foo/cfg.yaml').ensure() + with in_git_dir.join('foo').as_cwd(): + args = _args(command='run', files=[], commit_msg_filename='t.txt') + main._adjust_args_and_chdir(args) + assert os.getcwd() == in_git_dir + assert args.commit_msg_filename == os.path.join('foo', 't.txt') @pytest.mark.skipif(os.name != 'nt', reason='windows feature') @@ -56,24 +69,22 @@ def test_install_on_subst(in_git_dir, store): # pragma: posix no cover def test_adjust_args_and_chdir_non_relative_config(in_git_dir): - in_git_dir.join('foo').ensure_dir().chdir() - - args = _args() - main._adjust_args_and_chdir(args) - assert os.getcwd() == in_git_dir - assert args.config == C.CONFIG_FILE + with in_git_dir.join('foo').ensure_dir().as_cwd(): + args = _args() + main._adjust_args_and_chdir(args) + assert os.getcwd() == in_git_dir + assert args.config == C.CONFIG_FILE def test_adjust_args_try_repo_repo_relative(in_git_dir): - in_git_dir.join('foo').ensure_dir().chdir() - - args = _args(command='try-repo', repo='../foo', files=[]) - assert args.repo is not None - assert os.path.exists(args.repo) - main._adjust_args_and_chdir(args) - assert os.getcwd() == in_git_dir - assert os.path.exists(args.repo) - assert args.repo == 'foo' + with in_git_dir.join('foo').ensure_dir().as_cwd(): + args = _args(command='try-repo', repo='../foo', files=[]) + assert args.repo is not None + assert os.path.exists(args.repo) + main._adjust_args_and_chdir(args) + assert os.getcwd() == in_git_dir + assert os.path.exists(args.repo) + assert args.repo == 'foo' FNS = ( From 7c14405f8bc2e11a80ff7397e86177081fa1ea65 Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Tue, 12 Jul 2022 22:44:31 +0100 Subject: [PATCH 103/416] just bump failing CI From a568f3c818eea994ac22ebe3fb3f4aec7886a26f Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Tue, 12 Jul 2022 22:47:19 +0100 Subject: [PATCH 104/416] enforce binary installs also for dependencies of R packages Similar problem seems to be found in https://github.com/r-lib/devtools/issues/1724 --- pre_commit/languages/r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 40a001db..22b5f253 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -158,7 +158,7 @@ def _inline_r_setup(code: str) -> str: only be configured via R options once R has started. These are set here. """ with_option = f"""\ - options(install.packages.compile.from.source = "never") + options(install.packages.compile.from.source = "never", pkgType = "binary") {code} """ return with_option From a8bfaab0913901cbb9c7b7be3210a76c14478538 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Jul 2022 21:46:05 +0000 Subject: [PATCH 105/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v1.20.1 → v1.20.2](https://github.com/asottile/setup-cfg-fmt/compare/v1.20.1...v1.20.2) - [github.com/asottile/reorder_python_imports: v3.8.1 → v3.8.2](https://github.com/asottile/reorder_python_imports/compare/v3.8.1...v3.8.2) - [github.com/asottile/pyupgrade: v2.37.1 → v2.37.2](https://github.com/asottile/pyupgrade/compare/v2.37.1...v2.37.2) - [github.com/pre-commit/mirrors-mypy: v0.961 → v0.971](https://github.com/pre-commit/mirrors-mypy/compare/v0.961...v0.971) --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 511ffd52..01c8c844 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,11 +10,11 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.20.1 + rev: v1.20.2 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.8.1 + rev: v3.8.2 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.37.1 + rev: v2.37.2 hooks: - id: pyupgrade args: [--py37-plus] @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.961 + rev: v0.971 hooks: - id: mypy additional_dependencies: [types-all] From f4e658fc6e84fd4578833de58e2701fcb1b543ee Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 25 Jul 2022 19:29:09 -0400 Subject: [PATCH 106/416] require a version of virtualenv which is less broken in 3.10+ --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index ae214f65..f86b3143 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,7 +28,7 @@ install_requires = nodeenv>=0.11.1 pyyaml>=5.1 toml - virtualenv>=20.0.8 + virtualenv>=20.10.0 importlib-metadata;python_version<"3.8" python_requires = >=3.7 From 3e920b5ba763cd22caf4b58a7a37be23ae476076 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:40:58 +0000 Subject: [PATCH 107/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v1.20.2 → v2.0.0](https://github.com/asottile/setup-cfg-fmt/compare/v1.20.2...v2.0.0) - [github.com/asottile/pyupgrade: v2.37.2 → v2.37.3](https://github.com/asottile/pyupgrade/compare/v2.37.2...v2.37.3) - [github.com/PyCQA/flake8: 4.0.1 → 5.0.2](https://github.com/PyCQA/flake8/compare/4.0.1...5.0.2) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 01c8c844..cd411e5d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.20.2 + rev: v2.0.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.37.2 + rev: v2.37.3 hooks: - id: pyupgrade args: [--py37-plus] @@ -34,7 +34,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 5.0.2 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From d4b73c9e889806a9ec50b401876602d8a3517113 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 22:41:21 +0000 Subject: [PATCH 108/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.cfg | 4 ---- 1 file changed, 4 deletions(-) diff --git a/setup.cfg b/setup.cfg index f86b3143..afe56848 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,10 +13,6 @@ classifiers = License :: OSI Approved :: MIT License Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy From 317c9e037a185c2c30e1e1220744f0f9bb3fc025 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 22:24:53 +0000 Subject: [PATCH 109/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 5.0.2 → 5.0.4](https://github.com/PyCQA/flake8/compare/5.0.2...5.0.4) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd411e5d..7fca524c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,7 +34,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 5.0.2 + rev: 5.0.4 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From 587c6b97e77fea48a8bb88dce6aa9a0a6687a4fa Mon Sep 17 00:00:00 2001 From: Mark Korondi Date: Wed, 10 Aug 2022 17:04:05 +0200 Subject: [PATCH 110/416] respect aliases in SKIP when installing environments --- pre_commit/commands/run.py | 6 +++++- tests/commands/run_test.py | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index ad3d766e..8d11882c 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -420,7 +420,11 @@ def run( return 1 skips = _get_skips(environ) - to_install = [hook for hook in hooks if hook.id not in skips] + to_install = [ + hook + for hook in hooks + if hook.id not in skips and hook.alias not in skips + ] install_hook_envs(to_install, store) return _run_hooks(config, hooks, skips, args) diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 2634c0c5..3ae3b537 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -635,6 +635,32 @@ def test_skip_bypasses_installation(cap_out, store, repo_with_passing_hook): assert ret == 0 +def test_skip_alias_bypasses_installation( + cap_out, store, repo_with_passing_hook, +): + config = { + 'repo': 'local', + 'hooks': [ + { + 'id': 'skipme', + 'name': 'skipme-1', + 'alias': 'skipme-1', + 'entry': 'skipme', + 'language': 'python', + 'additional_dependencies': ['/pre-commit-does-not-exist'], + }, + ], + } + add_config_to_repo(repo_with_passing_hook, config) + + ret, printed = _do_run( + cap_out, store, repo_with_passing_hook, + run_opts(all_files=True), + {'SKIP': 'skipme-1'}, + ) + assert ret == 0 + + def test_hook_id_not_in_non_verbose_output( cap_out, store, repo_with_passing_hook, ): From 2405caa352924aa6148b0e4dc52f97291b3ff2b7 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 15 Aug 2022 13:46:17 -0400 Subject: [PATCH 111/416] allow `pre-commit run --files ...` against unmerged files --- pre_commit/commands/run.py | 2 +- tests/commands/run_test.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 8d11882c..37f78f74 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -333,7 +333,7 @@ def run( stash = not args.all_files and not args.files # Check if we have unresolved merge conflict files and fail fast. - if _has_unmerged_paths(): + if stash and _has_unmerged_paths(): logger.error('Unmerged files. Resolve before committing.') return 1 if bool(args.from_ref) != bool(args.to_ref): diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 3ae3b537..ef865330 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -536,6 +536,13 @@ def test_merge_conflict(cap_out, store, in_merge_conflict): assert b'Unmerged files. Resolve before committing.' in printed +def test_files_during_merge_conflict(cap_out, store, in_merge_conflict): + opts = run_opts(files=['placeholder']) + ret, printed = _do_run(cap_out, store, in_merge_conflict, opts) + assert ret == 0 + assert b'Bash hook' in printed + + def test_merge_conflict_modified(cap_out, store, in_merge_conflict): # Touch another file so we have unstaged non-conflicting things assert os.path.exists('placeholder') From 7a62bf7be2564ccc4f98456192bfa4e608741411 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Aug 2022 21:15:11 +0000 Subject: [PATCH 112/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-autopep8: v1.6.0 → v1.7.0](https://github.com/pre-commit/mirrors-autopep8/compare/v1.6.0...v1.7.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7fca524c..e6c63ae8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.6.0 + rev: v1.7.0 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From fb608ee1b45607e35a386aa104f434879b78c962 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Sep 2022 22:48:22 +0000 Subject: [PATCH 113/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.37.3 → v2.38.0](https://github.com/asottile/pyupgrade/compare/v2.37.3...v2.38.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e6c63ae8..af68fee9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v2.38.0 hooks: - id: pyupgrade args: [--py37-plus] From a95f488e71f6226696926c43140659fbbcad964b Mon Sep 17 00:00:00 2001 From: chrisRedwine Date: Thu, 22 Sep 2022 21:55:26 -0500 Subject: [PATCH 114/416] extend warning if globs are used instead of regex to local hooks --- pre_commit/clientlib.py | 10 +++++++++- tests/clientlib_test.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 9b53e810..da6ca2be 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -298,6 +298,14 @@ CONFIG_HOOK_DICT = cfgv.Map( OptionalSensibleRegexAtHook('files', cfgv.check_string), OptionalSensibleRegexAtHook('exclude', cfgv.check_string), ) +LOCAL_HOOK_DICT = cfgv.Map( + 'Hook', 'id', + + *MANIFEST_HOOK_DICT.items, + + OptionalSensibleRegexAtHook('files', cfgv.check_string), + OptionalSensibleRegexAtHook('exclude', cfgv.check_string), +) CONFIG_REPO_DICT = cfgv.Map( 'Repository', 'repo', @@ -308,7 +316,7 @@ CONFIG_REPO_DICT = cfgv.Map( 'repo', cfgv.NotIn(LOCAL, META), ), cfgv.ConditionalRecurse( - 'hooks', cfgv.Array(MANIFEST_HOOK_DICT), + 'hooks', cfgv.Array(LOCAL_HOOK_DICT), 'repo', LOCAL, ), cfgv.ConditionalRecurse( diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index fb36bb55..9fea7e16 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -15,6 +15,8 @@ from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION from pre_commit.clientlib import MANIFEST_SCHEMA from pre_commit.clientlib import META_HOOK_DICT from pre_commit.clientlib import MigrateShaToRev +from pre_commit.clientlib import OptionalSensibleRegexAtHook +from pre_commit.clientlib import OptionalSensibleRegexAtTop from pre_commit.clientlib import validate_config_main from pre_commit.clientlib import validate_manifest_main from testing.fixtures import sample_local_config @@ -261,6 +263,27 @@ def test_warn_mutable_rev_conditional(): cfgv.validate(config_obj, CONFIG_REPO_DICT) +@pytest.mark.parametrize( + 'validator_cls', + ( + OptionalSensibleRegexAtHook, + OptionalSensibleRegexAtTop, + ), +) +def test_sensible_regex_validators_dont_pass_none(validator_cls): + key = 'files' + with pytest.raises(cfgv.ValidationError) as excinfo: + validator = validator_cls(key, cfgv.check_string) + validator.check({key: None}) + + assert str(excinfo.value) == ( + '\n' + f'==> At key: {key}' + '\n' + '=====> Expected string got NoneType' + ) + + @pytest.mark.parametrize( ('regex', 'warning'), ( @@ -296,6 +319,22 @@ def test_validate_optional_sensible_regex_at_hook(caplog, regex, warning): assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)] +def test_validate_optional_sensible_regex_at_local_hook(caplog): + config_obj = sample_local_config() + config_obj['hooks'][0]['files'] = r'dir/*.py' + + cfgv.validate(config_obj, CONFIG_REPO_DICT) + + assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + "The 'files' field in hook 'do_not_commit' is a regex, not a glob " + "-- matching '/*' probably isn't what you want here", + ), + ] + + @pytest.mark.parametrize( ('regex', 'warning'), ( From 6d5de9feaf9086f96021d5d63606de54262ca85e Mon Sep 17 00:00:00 2001 From: chrisRedwine Date: Mon, 26 Sep 2022 17:53:14 -0500 Subject: [PATCH 115/416] remove extraneous raw string literal in test --- tests/clientlib_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 9fea7e16..b4c3c4e0 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -321,7 +321,7 @@ def test_validate_optional_sensible_regex_at_hook(caplog, regex, warning): def test_validate_optional_sensible_regex_at_local_hook(caplog): config_obj = sample_local_config() - config_obj['hooks'][0]['files'] = r'dir/*.py' + config_obj['hooks'][0]['files'] = 'dir/*.py' cfgv.validate(config_obj, CONFIG_REPO_DICT) From 404f2dccd57aec10a1fefddb3dba41156c6bc971 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 22:58:40 +0000 Subject: [PATCH 116/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v3.8.2 → v3.8.3](https://github.com/asottile/reorder_python_imports/compare/v3.8.2...v3.8.3) - [github.com/asottile/add-trailing-comma: v2.2.3 → v2.3.0](https://github.com/asottile/add-trailing-comma/compare/v2.2.3...v2.3.0) - [github.com/asottile/pyupgrade: v2.38.0 → v2.38.2](https://github.com/asottile/pyupgrade/compare/v2.38.0...v2.38.2) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index af68fee9..6ec15b71 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,18 +14,18 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.8.2 + rev: v3.8.3 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.2.3 + rev: v2.3.0 hooks: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.38.0 + rev: v2.38.2 hooks: - id: pyupgrade args: [--py37-plus] From 495b5991cfa7aeeb35b0dcc44814bffd8d2d04e1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 29 Sep 2022 16:51:19 -0400 Subject: [PATCH 117/416] "yes" is not a valid search --- .github/ISSUE_TEMPLATE/bug.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index bfced0f2..96cd6c75 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -12,7 +12,7 @@ body: - type: input id: search attributes: - label: search tried in the issue tracker + label: search you tried in the issue tracker placeholder: ... validations: required: true From 68be295b759f64e9cc820577c26955f661b81145 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Oct 2022 22:51:41 +0000 Subject: [PATCH 118/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.971 → v0.981](https://github.com/pre-commit/mirrors-mypy/compare/v0.971...v0.981) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ec15b71..97212802 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.971 + rev: v0.981 hooks: - id: mypy additional_dependencies: [types-all] From 3d4f6db2a01e687659fef8bf4de66d43b39f2d48 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:49:52 +0000 Subject: [PATCH 119/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder_python_imports: v3.8.3 → v3.8.4](https://github.com/asottile/reorder_python_imports/compare/v3.8.3...v3.8.4) - [github.com/asottile/pyupgrade: v2.38.2 → v3.1.0](https://github.com/asottile/pyupgrade/compare/v2.38.2...v3.1.0) - [github.com/pre-commit/mirrors-mypy: v0.981 → v0.982](https://github.com/pre-commit/mirrors-mypy/compare/v0.981...v0.982) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 97212802..02d662cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.8.3 + rev: v3.8.4 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.38.2 + rev: v3.1.0 hooks: - id: pyupgrade args: [--py37-plus] @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.981 + rev: v0.982 hooks: - id: mypy additional_dependencies: [types-all] From eb469c756de4282e37da52cc346e70ba9d116e06 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 30 Sep 2022 11:44:18 +0200 Subject: [PATCH 120/416] Rust as 1st class language --- CONTRIBUTING.md | 4 +- azure-pipelines.yml | 2 + pre_commit/languages/rust.py | 118 +++++++++++++++++++++++++++++------ tests/languages/rust_test.py | 70 +++++++++++++++++++++ tests/repository_test.py | 4 +- 5 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 tests/languages/rust_test.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 310c17ee..0817681a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,9 +65,9 @@ to implement. The current implemented languages are at varying levels: - 0th class - pre-commit does not require any dependencies for these languages as they're not actually languages (current examples: fail, pygrep) - 1st class - pre-commit will bootstrap a full interpreter requiring nothing to - be installed globally (current examples: node, ruby) + be installed globally (current examples: node, ruby, rust) - 2nd class - pre-commit requires the user to install the language globally but - will install tools in an isolated fashion (current examples: python, go, rust, + will install tools in an isolated fashion (current examples: python, go, swift, docker). - 3rd class - pre-commit requires the user to install both the tool and the language globally (current examples: script, system) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 454f6f13..34c94f54 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,6 +17,8 @@ jobs: parameters: toxenvs: [py37] os: windows + additional_variables: + TEMP: C:\Temp pre_test: - task: UseRubyVersion@0 - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 01c37306..5e4ecafa 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -1,13 +1,20 @@ from __future__ import annotations import contextlib +import functools import os.path +import platform +import shutil +import sys +import tempfile +import urllib.request from typing import Generator from typing import Sequence import toml import pre_commit.constants as C +from pre_commit import parse_shebang from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -16,24 +23,61 @@ from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b +from pre_commit.util import make_executable +from pre_commit.util import win_exe ENVIRONMENT_DIR = 'rustenv' -get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check -def get_env_patch(target_dir: str) -> PatchesT: +@functools.lru_cache(maxsize=1) +def get_default_version() -> str: + # If rust is already installed, we can save a bunch of setup time by + # using the installed version. + # + # Just detecting the executable does not suffice, because if rustup is + # installed but no toolchain is available, then `cargo` exists but + # cannot be used without installing a toolchain first. + if cmd_output_b('cargo', '--version', retcode=None)[0] == 0: + return 'system' + else: + return C.DEFAULT + + +def _rust_toolchain(language_version: str) -> str: + """Transform the language version into a rust toolchain version.""" + if language_version == C.DEFAULT: + return 'stable' + else: + return language_version + + +def _envdir(prefix: Prefix, version: str) -> str: + directory = helpers.environment_dir(ENVIRONMENT_DIR, version) + return prefix.path(directory) + + +def get_env_patch(target_dir: str, version: str) -> PatchesT: return ( + ('CARGO_HOME', target_dir), ('PATH', (os.path.join(target_dir, 'bin'), os.pathsep, Var('PATH'))), + # Only set RUSTUP_TOOLCHAIN if we don't want use the system's default + # toolchain + *( + (('RUSTUP_TOOLCHAIN', _rust_toolchain(version)),) + if version != 'system' else () + ), ) @contextlib.contextmanager -def in_env(prefix: Prefix) -> Generator[None, None, None]: - target_dir = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) - with envcontext(get_env_patch(target_dir)): +def in_env( + prefix: Prefix, + language_version: str, +) -> Generator[None, None, None]: + with envcontext( + get_env_patch(_envdir(prefix, language_version), language_version), + ): yield @@ -52,15 +96,45 @@ def _add_dependencies( f.truncate() +def install_rust_with_toolchain(toolchain: str) -> None: + with tempfile.TemporaryDirectory() as rustup_dir: + with envcontext((('RUSTUP_HOME', rustup_dir),)): + # acquire `rustup` if not present + if parse_shebang.find_executable('rustup') is None: + # We did not detect rustup and need to download it first. + if sys.platform == 'win32': # pragma: win32 cover + if platform.machine() == 'x86_64': + url = 'https://win.rustup.rs/x86_64' + else: + url = 'https://win.rustup.rs/i686' + else: # pragma: win32 no cover + url = 'https://sh.rustup.rs' + + resp = urllib.request.urlopen(url) + + rustup_init = os.path.join(rustup_dir, win_exe('rustup-init')) + with open(rustup_init, 'wb') as f: + shutil.copyfileobj(resp, f) + make_executable(rustup_init) + + # install rustup into `$CARGO_HOME/bin` + cmd_output_b( + rustup_init, '-y', '--quiet', '--no-modify-path', + '--default-toolchain', 'none', + ) + + cmd_output_b( + 'rustup', 'toolchain', 'install', '--no-self-update', + toolchain, + ) + + def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('rust', version) - directory = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) + directory = _envdir(prefix, version) # There are two cases where we might want to specify more dependencies: # as dependencies for the library being built, and as binary packages @@ -84,17 +158,21 @@ def install_environment( packages_to_install: set[tuple[str, ...]] = {('--path', '.')} for cli_dep in cli_deps: cli_dep = cli_dep[len('cli:'):] - package, _, version = cli_dep.partition(':') - if version != '': - packages_to_install.add((package, '--version', version)) + package, _, crate_version = cli_dep.partition(':') + if crate_version != '': + packages_to_install.add((package, '--version', crate_version)) else: packages_to_install.add((package,)) - for args in packages_to_install: - cmd_output_b( - 'cargo', 'install', '--bins', '--root', directory, *args, - cwd=prefix.prefix_dir, - ) + with in_env(prefix, version): + if version != 'system': + install_rust_with_toolchain(_rust_toolchain(version)) + + for args in packages_to_install: + cmd_output_b( + 'cargo', 'install', '--bins', '--root', directory, *args, + cwd=prefix.prefix_dir, + ) def run_hook( @@ -102,5 +180,5 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - with in_env(hook.prefix): + with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py new file mode 100644 index 00000000..9bf97830 --- /dev/null +++ b/tests/languages/rust_test.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from unittest import mock + +import pytest + +import pre_commit.constants as C +from pre_commit import parse_shebang +from pre_commit.languages import rust +from pre_commit.prefix import Prefix +from pre_commit.util import cmd_output + +ACTUAL_GET_DEFAULT_VERSION = rust.get_default_version.__wrapped__ + + +@pytest.fixture +def cmd_output_b_mck(): + with mock.patch.object(rust, 'cmd_output_b') as mck: + yield mck + + +def test_sets_system_when_rust_is_available(cmd_output_b_mck): + cmd_output_b_mck.return_value = (0, b'', b'') + assert ACTUAL_GET_DEFAULT_VERSION() == 'system' + + +def test_uses_default_when_rust_is_not_available(cmd_output_b_mck): + cmd_output_b_mck.return_value = (127, b'', b'error: not found') + assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT + + +@pytest.mark.parametrize('language_version', (C.DEFAULT, '1.56.0')) +def test_installs_with_bootstrapped_rustup(tmpdir, language_version): + tmpdir.join('src', 'main.rs').ensure().write( + 'fn main() {\n' + ' println!("Hello, world!");\n' + '}\n', + ) + tmpdir.join('Cargo.toml').ensure().write( + '[package]\n' + 'name = "hello_world"\n' + 'version = "0.1.0"\n' + 'edition = "2021"\n', + ) + prefix = Prefix(str(tmpdir)) + + find_executable_exes = [] + + original_find_executable = parse_shebang.find_executable + + def mocked_find_executable(exe: str) -> str | None: + """ + Return `None` the first time `find_executable` is called to ensure + that the bootstrapping code is executed, then just let the function + work as normal. + + Also log the arguments to ensure that everything works as expected. + """ + find_executable_exes.append(exe) + if len(find_executable_exes) == 1: + return None + return original_find_executable(exe) + + with mock.patch.object(parse_shebang, 'find_executable') as find_exe_mck: + find_exe_mck.side_effect = mocked_find_executable + rust.install_environment(prefix, language_version, ()) + assert find_executable_exes == ['rustup', 'rustup', 'cargo'] + + with rust.in_env(prefix, language_version): + assert cmd_output('hello_world')[1] == 'Hello, world!\n' diff --git a/tests/repository_test.py b/tests/repository_test.py index 11d452ca..0d4cb651 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -471,7 +471,7 @@ def test_additional_rust_cli_dependencies_installed( hook = _get_hook(config, store, 'rust-hook') binaries = os.listdir( hook.prefix.path( - helpers.environment_dir(rust.ENVIRONMENT_DIR, C.DEFAULT), 'bin', + helpers.environment_dir(rust.ENVIRONMENT_DIR, 'system'), 'bin', ), ) # normalize for windows @@ -490,7 +490,7 @@ def test_additional_rust_lib_dependencies_installed( hook = _get_hook(config, store, 'rust-hook') binaries = os.listdir( hook.prefix.path( - helpers.environment_dir(rust.ENVIRONMENT_DIR, C.DEFAULT), 'bin', + helpers.environment_dir(rust.ENVIRONMENT_DIR, 'system'), 'bin', ), ) # normalize for windows From f9532fb59ab302d8782640c4c1652dc27ab09ec5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 23:10:12 +0000 Subject: [PATCH 121/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.0.0 → v2.1.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.0.0...v2.1.0) - [github.com/asottile/reorder_python_imports: v3.8.4 → v3.8.5](https://github.com/asottile/reorder_python_imports/compare/v3.8.4...v3.8.5) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 02d662cc..08ed35b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,11 +10,11 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.0.0 + rev: v2.1.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.8.4 + rev: v3.8.5 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) From bc96b0bcf688f8c5e6494e8bcf67ef72780f4c20 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 22 Oct 2022 09:34:43 -0700 Subject: [PATCH 122/416] fix tests for submodules for CVE-2022-39253 --- pre_commit/git.py | 7 +++---- tox.ini | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index 35392b34..40b12f01 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging import os.path import sys -from typing import MutableMapping +from typing import Mapping from pre_commit.errors import FatalError from pre_commit.util import CalledProcessError @@ -24,9 +24,7 @@ def zsplit(s: str) -> list[str]: return [] -def no_git_env( - _env: MutableMapping[str, str] | None = None, -) -> dict[str, str]: +def no_git_env(_env: Mapping[str, str] | None = None) -> dict[str, str]: # Too many bugs dealing with environment variables and GIT: # https://github.com/pre-commit/pre-commit/issues/300 # In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running @@ -44,6 +42,7 @@ def no_git_env( 'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO', 'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT', 'GIT_HTTP_PROXY_AUTHMETHOD', + 'GIT_ALLOW_PROTOCOL', } } diff --git a/tox.ini b/tox.ini index 7f43e41e..463b72f3 100644 --- a/tox.ini +++ b/tox.ini @@ -23,5 +23,6 @@ env = GIT_COMMITTER_NAME=test GIT_AUTHOR_EMAIL=test@example.com GIT_COMMITTER_EMAIL=test@example.com + GIT_ALLOW_PROTOCOL=file VIRTUALENV_NO_DOWNLOAD=1 PRE_COMMIT_NO_CONCURRENCY=1 From 8ebb7ae2f574cfda9721865d4399fd273a370dec Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Thu, 27 Oct 2022 15:32:38 -0400 Subject: [PATCH 123/416] add GIT_ASKPASS as a passthrough env var documented via man gitcredentials, it is used to provide a script/input for git to fetch creds in a no-tty usecase. used among other things by jenkins to pass credentials down to git for authentication. https://github.com/jenkinsci/git-plugin/blob/1e3488a730a169778ba0863dd4edbb1dc29154a1/README.adoc#git-bindings https://github.com/jenkinsci/git-plugin/blob/9429e7d05df3dbb4060ac6ab4da6538bb0eb50ba/src/main/java/jenkins/plugins/git/GitUsernamePasswordBinding.java#L130 --- pre_commit/git.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pre_commit/git.py b/pre_commit/git.py index 40b12f01..439da7ad 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -43,6 +43,7 @@ def no_git_env(_env: Mapping[str, str] | None = None) -> dict[str, str]: 'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT', 'GIT_HTTP_PROXY_AUTHMETHOD', 'GIT_ALLOW_PROTOCOL', + 'GIT_ASKPASS', } } From e703982de45ac64492897b25fa4edbdb8da10e62 Mon Sep 17 00:00:00 2001 From: marsha Date: Fri, 28 Oct 2022 20:23:00 -0500 Subject: [PATCH 124/416] Change Rust to install environment with `cargo add` over `toml` --- pre_commit/languages/rust.py | 26 +++++++++++--------------- setup.cfg | 1 - tests/repository_test.py | 2 +- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 5e4ecafa..0c347b49 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -11,8 +11,6 @@ import urllib.request from typing import Generator from typing import Sequence -import toml - import pre_commit.constants as C from pre_commit import parse_shebang from pre_commit.envcontext import envcontext @@ -82,18 +80,16 @@ def in_env( def _add_dependencies( - cargo_toml_path: str, + prefix: Prefix, additional_dependencies: set[str], ) -> None: - with open(cargo_toml_path, 'r+') as f: - cargo_toml = toml.load(f) - cargo_toml.setdefault('dependencies', {}) - for dep in additional_dependencies: - name, _, spec = dep.partition(':') - cargo_toml['dependencies'][name] = spec or '*' - f.seek(0) - toml.dump(cargo_toml, f) - f.truncate() + crates = [] + for dep in additional_dependencies: + name, _, spec = dep.partition(':') + crate = f'{name}@{spec or "*"}' + crates.append(crate) + + helpers.run_setup_cmd(prefix, ('cargo', 'add', *crates)) def install_rust_with_toolchain(toolchain: str) -> None: @@ -151,9 +147,6 @@ def install_environment( } lib_deps = set(additional_dependencies) - cli_deps - if len(lib_deps) > 0: - _add_dependencies(prefix.path('Cargo.toml'), lib_deps) - with clean_path_on_failure(directory): packages_to_install: set[tuple[str, ...]] = {('--path', '.')} for cli_dep in cli_deps: @@ -168,6 +161,9 @@ def install_environment( if version != 'system': install_rust_with_toolchain(_rust_toolchain(version)) + if len(lib_deps) > 0: + _add_dependencies(prefix, lib_deps) + for args in packages_to_install: cmd_output_b( 'cargo', 'install', '--bins', '--root', directory, *args, diff --git a/setup.cfg b/setup.cfg index afe56848..ab95cc04 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,7 +23,6 @@ install_requires = identify>=1.0.0 nodeenv>=0.11.1 pyyaml>=5.1 - toml virtualenv>=20.10.0 importlib-metadata;python_version<"3.8" python_requires = >=3.7 diff --git a/tests/repository_test.py b/tests/repository_test.py index 0d4cb651..252c126c 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -485,7 +485,7 @@ def test_additional_rust_lib_dependencies_installed( path = make_repo(tempdir_factory, 'rust_hooks_repo') config = make_config_from_repo(path) # A small rust package with no dependencies. - deps = ['shellharden:3.1.0'] + deps = ['shellharden:3.1.0', 'git-version'] config['hooks'][0]['additional_dependencies'] = deps hook = _get_hook(config, store, 'rust-hook') binaries = os.listdir( From 84b38f7b89fa22bea8bc70b03e664cd6cda9db84 Mon Sep 17 00:00:00 2001 From: marsha Date: Sun, 30 Oct 2022 14:47:42 -0500 Subject: [PATCH 125/416] Change `cmd_output_b`s `retcode` arg to a boolean `check` --- pre_commit/commands/run.py | 4 ++-- pre_commit/error_handler.py | 2 +- pre_commit/git.py | 4 ++-- pre_commit/languages/node.py | 2 +- pre_commit/languages/rust.py | 2 +- pre_commit/staged_files_only.py | 2 +- pre_commit/util.py | 11 ++++++----- pre_commit/xargs.py | 2 +- tests/commands/init_templatedir_test.py | 2 +- tests/commands/install_uninstall_test.py | 6 +++--- tests/commands/run_test.py | 4 ++-- tests/conftest.py | 2 +- tests/error_handler_test.py | 3 ++- tests/git_test.py | 2 +- tests/util_test.py | 6 +++--- 15 files changed, 28 insertions(+), 26 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 37f78f74..429e04c6 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -263,7 +263,7 @@ def _all_filenames(args: argparse.Namespace) -> Collection[str]: def _get_diff() -> bytes: _, out, _ = cmd_output_b( - 'git', 'diff', '--no-ext-diff', '--ignore-submodules', retcode=None, + 'git', 'diff', '--no-ext-diff', '--ignore-submodules', check=False, ) return out @@ -318,7 +318,7 @@ def _has_unmerged_paths() -> bool: def _has_unstaged_config(config_file: str) -> bool: retcode, _, _ = cmd_output_b( 'git', 'diff', '--no-ext-diff', '--exit-code', config_file, - retcode=None, + check=False, ) # be explicit, other git errors don't mean it has an unstaged config. return retcode == 1 diff --git a/pre_commit/error_handler.py b/pre_commit/error_handler.py index 992f5cdc..d740ee3e 100644 --- a/pre_commit/error_handler.py +++ b/pre_commit/error_handler.py @@ -25,7 +25,7 @@ def _log_and_exit( error_msg = f'{msg}: {type(exc).__name__}: '.encode() + force_bytes(exc) output.write_line_b(error_msg) - _, git_version_b, _ = cmd_output_b('git', '--version', retcode=None) + _, git_version_b, _ = cmd_output_b('git', '--version', check=False) git_version = git_version_b.decode(errors='backslashreplace').rstrip() storedir = Store().directory diff --git a/pre_commit/git.py b/pre_commit/git.py index 439da7ad..37ed3a71 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -187,11 +187,11 @@ def head_rev(remote: str) -> str: def has_diff(*args: str, repo: str = '.') -> bool: cmd = ('git', 'diff', '--quiet', '--no-ext-diff', *args) - return cmd_output_b(*cmd, cwd=repo, retcode=None)[0] == 1 + return cmd_output_b(*cmd, cwd=repo, check=False)[0] == 1 def has_core_hookpaths_set() -> bool: - _, out, _ = cmd_output_b('git', 'config', 'core.hooksPath', retcode=None) + _, out, _ = cmd_output_b('git', 'config', 'core.hooksPath', check=False) return bool(out.strip()) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 39f30006..37a5b63f 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -75,7 +75,7 @@ def in_env( def health_check(prefix: Prefix, language_version: str) -> str | None: with in_env(prefix, language_version): - retcode, _, _ = cmd_output_b('node', '--version', retcode=None) + retcode, _, _ = cmd_output_b('node', '--version', check=False) if retcode != 0: # pragma: win32 no cover return f'`node --version` returned {retcode}' else: diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 0c347b49..ef603bc0 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -36,7 +36,7 @@ def get_default_version() -> str: # Just detecting the executable does not suffice, because if rustup is # installed but no toolchain is available, then `cargo` exists but # cannot be used without installing a toolchain first. - if cmd_output_b('cargo', '--version', retcode=None)[0] == 0: + if cmd_output_b('cargo', '--version', check=False)[0] == 0: return 'system' else: return C.DEFAULT diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index 83d8a03e..172fb20b 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -52,7 +52,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: retcode, diff_stdout_binary, _ = cmd_output_b( 'git', 'diff-index', '--ignore-submodules', '--binary', '--exit-code', '--no-color', '--no-ext-diff', tree, '--', - retcode=None, + check=False, ) if retcode and diff_stdout_binary.strip(): patch_filename = f'patch{int(time.time())}-{os.getpid()}' diff --git a/pre_commit/util.py b/pre_commit/util.py index 8c296f4d..a935c2d8 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -124,7 +124,7 @@ def _oserror_to_output(e: OSError) -> tuple[int, bytes, None]: def cmd_output_b( *cmd: str, - retcode: int | None = 0, + check: bool = True, **kwargs: Any, ) -> tuple[int, bytes, bytes | None]: _setdefault_kwargs(kwargs) @@ -142,8 +142,9 @@ def cmd_output_b( stdout_b, stderr_b = proc.communicate() returncode = proc.returncode - if retcode is not None and retcode != returncode: - raise CalledProcessError(returncode, cmd, retcode, stdout_b, stderr_b) + SUCCESS = 0 + if check and returncode != SUCCESS: + raise CalledProcessError(returncode, cmd, SUCCESS, stdout_b, stderr_b) return returncode, stdout_b, stderr_b @@ -196,10 +197,10 @@ if os.name != 'nt': # pragma: win32 no cover def cmd_output_p( *cmd: str, - retcode: int | None = 0, + check: bool = True, **kwargs: Any, ) -> tuple[int, bytes, bytes | None]: - assert retcode is None + assert check is False assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr'] _setdefault_kwargs(kwargs) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index f2b3421a..e3af90ef 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -154,7 +154,7 @@ def xargs( run_cmd: tuple[str, ...], ) -> tuple[int, bytes, bytes | None]: return cmd_fn( - *run_cmd, retcode=None, stderr=subprocess.STDOUT, **kwargs, + *run_cmd, check=False, stderr=subprocess.STDOUT, **kwargs, ) threads = min(len(partitions), target_concurrency) diff --git a/tests/commands/init_templatedir_test.py b/tests/commands/init_templatedir_test.py index 64bfc8b4..28f29b77 100644 --- a/tests/commands/init_templatedir_test.py +++ b/tests/commands/init_templatedir_test.py @@ -135,7 +135,7 @@ def test_init_templatedir_skip_on_missing_config( retcode, output = git_commit( fn=cmd_output_mocked_pre_commit_home, tempdir_factory=tempdir_factory, - retcode=None, + check=False, ) assert retcode == commit_retcode diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index ae668ac9..379c03a4 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -126,7 +126,7 @@ def _get_commit_output(tempdir_factory, touch_file='foo', **kwargs): cmd_output('git', 'add', touch_file) return git_commit( fn=cmd_output_mocked_pre_commit_home, - retcode=None, + check=False, tempdir_factory=tempdir_factory, **kwargs, ) @@ -286,7 +286,7 @@ def test_environment_not_sourced(tempdir_factory, store): 'GIT_AUTHOR_EMAIL': os.environ['GIT_AUTHOR_EMAIL'], 'GIT_COMMITTER_EMAIL': os.environ['GIT_COMMITTER_EMAIL'], }, - retcode=None, + check=False, ) assert ret == 1 assert out == ( @@ -551,7 +551,7 @@ def _get_push_output(tempdir_factory, remote='origin', opts=()): return cmd_output_mocked_pre_commit_home( 'git', 'push', remote, 'HEAD:new_branch', *opts, tempdir_factory=tempdir_factory, - retcode=None, + check=False, )[:2] diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index ef865330..03d741e0 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -718,7 +718,7 @@ def test_non_ascii_hook_id(repo_with_passing_hook, tempdir_factory): with cwd(repo_with_passing_hook): _, stdout, _ = cmd_output_mocked_pre_commit_home( sys.executable, '-m', 'pre_commit.main', 'run', '☃', - retcode=None, tempdir_factory=tempdir_factory, + check=False, tempdir_factory=tempdir_factory, ) assert 'UnicodeDecodeError' not in stdout # Doesn't actually happen, but a reasonable assertion @@ -737,7 +737,7 @@ def test_stdout_write_bug_py26(repo_with_failing_hook, store, tempdir_factory): _, out = git_commit( fn=cmd_output_mocked_pre_commit_home, tempdir_factory=tempdir_factory, - retcode=None, + check=False, ) assert 'UnicodeEncodeError' not in out # Doesn't actually happen, but a reasonable assertion diff --git a/tests/conftest.py b/tests/conftest.py index 40c0c050..30761715 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -68,7 +68,7 @@ def _make_conflict(): bar_only_file.write('bar') cmd_output('git', 'add', 'bar_only_file') git_commit(msg=_make_conflict.__name__) - cmd_output('git', 'merge', 'foo', retcode=None) + cmd_output('git', 'merge', 'foo', check=False) @pytest.fixture diff --git a/tests/error_handler_test.py b/tests/error_handler_test.py index 47e2afaa..068149e3 100644 --- a/tests/error_handler_test.py +++ b/tests/error_handler_test.py @@ -183,10 +183,11 @@ def test_error_handler_no_tty(tempdir_factory): 'from pre_commit.error_handler import error_handler\n' 'with error_handler():\n' ' raise ValueError("\\u2603")\n', - retcode=3, + check=False, tempdir_factory=tempdir_factory, pre_commit_home=pre_commit_home, ) + assert ret == 3 log_file = os.path.join(pre_commit_home, 'pre-commit.log') out_lines = out.splitlines() assert out_lines[-2] == 'An unexpected error has occurred: ValueError: ☃' diff --git a/tests/git_test.py b/tests/git_test.py index b9f524a1..93f5a1c6 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -104,7 +104,7 @@ def test_is_in_merge_conflict_submodule(in_conflicting_submodule): def test_cherry_pick_conflict(in_merge_conflict): cmd_output('git', 'merge', '--abort') foo_ref = cmd_output('git', 'rev-parse', 'foo')[1].strip() - cmd_output('git', 'cherry-pick', foo_ref, retcode=None) + cmd_output('git', 'cherry-pick', foo_ref, check=False) assert git.is_in_merge_conflict() is False diff --git a/tests/util_test.py b/tests/util_test.py index 6b00f9fc..bc8f585f 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -83,14 +83,14 @@ def test_tmpdir(): def test_cmd_output_exe_not_found(): - ret, out, _ = cmd_output('dne', retcode=None) + ret, out, _ = cmd_output('dne', check=False) assert ret == 1 assert out == 'Executable `dne` not found' @pytest.mark.parametrize('fn', (cmd_output_b, cmd_output_p)) def test_cmd_output_exe_not_found_bytes(fn): - ret, out, _ = fn('dne', retcode=None, stderr=subprocess.STDOUT) + ret, out, _ = fn('dne', check=False, stderr=subprocess.STDOUT) assert ret == 1 assert out == b'Executable `dne` not found' @@ -101,7 +101,7 @@ def test_cmd_output_no_shebang(tmpdir, fn): make_executable(f) # previously this raised `OSError` -- the output is platform specific - ret, out, _ = fn(str(f), retcode=None, stderr=subprocess.STDOUT) + ret, out, _ = fn(str(f), check=False, stderr=subprocess.STDOUT) assert ret == 1 assert isinstance(out, bytes) assert out.endswith(b'\n') From 42102a1bfd96f70ae817f90ac2e7e1b07eae933d Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Sun, 30 Oct 2022 15:18:13 -0500 Subject: [PATCH 126/416] Remove `expected_returncode` from `CalledProcessError` --- pre_commit/util.py | 10 +++------- tests/error_handler_test.py | 2 +- tests/languages/docker_test.py | 2 +- tests/store_test.py | 2 +- tests/util_test.py | 6 ++---- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/pre_commit/util.py b/pre_commit/util.py index a935c2d8..b8507688 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -83,14 +83,12 @@ class CalledProcessError(RuntimeError): self, returncode: int, cmd: tuple[str, ...], - expected_returncode: int, stdout: bytes, stderr: bytes | None, ) -> None: - super().__init__(returncode, cmd, expected_returncode, stdout, stderr) + super().__init__(returncode, cmd, stdout, stderr) self.returncode = returncode self.cmd = cmd - self.expected_returncode = expected_returncode self.stdout = stdout self.stderr = stderr @@ -104,7 +102,6 @@ class CalledProcessError(RuntimeError): return b''.join(( f'command: {self.cmd!r}\n'.encode(), f'return code: {self.returncode}\n'.encode(), - f'expected return code: {self.expected_returncode}\n'.encode(), b'stdout:', _indent_or_none(self.stdout), b'\n', b'stderr:', _indent_or_none(self.stderr), )) @@ -142,9 +139,8 @@ def cmd_output_b( stdout_b, stderr_b = proc.communicate() returncode = proc.returncode - SUCCESS = 0 - if check and returncode != SUCCESS: - raise CalledProcessError(returncode, cmd, SUCCESS, stdout_b, stderr_b) + if check and returncode: + raise CalledProcessError(returncode, cmd, stdout_b, stderr_b) return returncode, stdout_b, stderr_b diff --git a/tests/error_handler_test.py b/tests/error_handler_test.py index 068149e3..a79d9c1a 100644 --- a/tests/error_handler_test.py +++ b/tests/error_handler_test.py @@ -162,7 +162,7 @@ def test_error_handler_non_ascii_exception(mock_store_dir): def test_error_handler_non_utf8_exception(mock_store_dir): with pytest.raises(SystemExit): with error_handler.error_handler(): - raise CalledProcessError(1, ('exe',), 0, b'error: \xa0\xe1', b'') + raise CalledProcessError(1, ('exe',), b'error: \xa0\xe1', b'') def test_error_handler_non_stringable_exception(mock_store_dir): diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index 58387611..5f7c85e7 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -178,6 +178,6 @@ def test_get_docker_path_in_docker_windows(in_docker): def test_get_docker_path_in_docker_docker_in_docker(in_docker): # won't be able to discover "self" container in true docker-in-docker - err = CalledProcessError(1, (), 0, b'', b'') + err = CalledProcessError(1, (), b'', b'') with mock.patch.object(docker, 'cmd_output_b', side_effect=err): assert docker._get_docker_path('/project') == '/project' diff --git a/tests/store_test.py b/tests/store_test.py index ff671a83..81877662 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -127,7 +127,7 @@ def test_clone_shallow_failure_fallback_to_complete( # Force shallow clone failure def fake_shallow_clone(self, *args, **kwargs): - raise CalledProcessError(1, (), 0, b'', None) + raise CalledProcessError(1, (), b'', None) store._shallow_clone = fake_shallow_clone ret = store.clone(path, rev) diff --git a/tests/util_test.py b/tests/util_test.py index bc8f585f..b3f18b4c 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -18,11 +18,10 @@ from pre_commit.util import tmpdir def test_CalledProcessError_str(): - error = CalledProcessError(1, ('exe',), 0, b'output', b'errors') + error = CalledProcessError(1, ('exe',), b'output', b'errors') assert str(error) == ( "command: ('exe',)\n" 'return code: 1\n' - 'expected return code: 0\n' 'stdout:\n' ' output\n' 'stderr:\n' @@ -31,11 +30,10 @@ def test_CalledProcessError_str(): def test_CalledProcessError_str_nooutput(): - error = CalledProcessError(1, ('exe',), 0, b'', b'') + error = CalledProcessError(1, ('exe',), b'', b'') assert str(error) == ( "command: ('exe',)\n" 'return code: 1\n' - 'expected return code: 0\n' 'stdout: (none)\n' 'stderr: (none)' ) From 3b3cf8c1f1536e69a9cc536f0f2f41d3847b6237 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 23:27:34 +0000 Subject: [PATCH 127/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.1.0 → v2.2.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.1.0...v2.2.0) - [github.com/asottile/reorder_python_imports: v3.8.5 → v3.9.0](https://github.com/asottile/reorder_python_imports/compare/v3.8.5...v3.9.0) - [github.com/asottile/pyupgrade: v3.1.0 → v3.2.0](https://github.com/asottile/pyupgrade/compare/v3.1.0...v3.2.0) - [github.com/pre-commit/mirrors-autopep8: v1.7.0 → v2.0.0](https://github.com/pre-commit/mirrors-autopep8/compare/v1.7.0...v2.0.0) --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08ed35b0..1a4b5677 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,11 +10,11 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.1.0 + rev: v2.2.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder_python_imports - rev: v3.8.5 + rev: v3.9.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -25,12 +25,12 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.1.0 + rev: v3.2.0 hooks: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.7.0 + rev: v2.0.0 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From 4bca29ee2cb6631a4d9420e443674c6905a81705 Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Wed, 2 Nov 2022 17:00:32 -0500 Subject: [PATCH 128/416] Change `intent_to_add_files` from using `git status` to `git diff` --- pre_commit/git.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index 37ed3a71..f84eb06b 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -150,18 +150,10 @@ def get_staged_files(cwd: str | None = None) -> list[str]: def intent_to_add_files() -> list[str]: _, stdout, _ = cmd_output( - 'git', 'status', '--ignore-submodules', '--porcelain', '-z', + 'git', 'diff', '--ignore-submodules', '--diff-filter=A', + '--name-only', '-z', ) - parts = list(reversed(zsplit(stdout))) - intent_to_add = [] - while parts: - line = parts.pop() - status, filename = line[:3], line[3:] - if status[0] in {'C', 'R'}: # renames / moves have an additional arg - parts.pop() - if status[1] == 'A': - intent_to_add.append(filename) - return intent_to_add + return zsplit(stdout) def get_all_files() -> list[str]: From 97ad4f89ecc9a7462baf78b29d1ee47f121304a1 Mon Sep 17 00:00:00 2001 From: mishaschwartz Date: Tue, 1 Nov 2022 13:09:29 -0400 Subject: [PATCH 129/416] ruby: update ruby-build to 20220710 to ensure that the correct openssl version is used --- pre_commit/resources/ruby-build.tar.gz | Bin 72569 -> 74032 bytes testing/make-archives | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index 8edb3caa3c27f1ccff9f0e0dc36e9863845c4efa..35419f63aebe33b6710851aef70937cd9ef163ba 100644 GIT binary patch literal 74032 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%0AnpW@&C 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%0AjiYK?V4{m8)M>y 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 QyZ`ocT>npFFyLVT0DovyN&o-= literal 72569 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 Q^XH#>?(}dC1`Zwu0Oqmj_5c6? diff --git a/testing/make-archives b/testing/make-archives index 04b42dd9..704101f5 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -17,7 +17,7 @@ from typing import Sequence REPOS = ( ('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'), - ('ruby-build', 'https://github.com/rbenv/ruby-build', '2004fd7'), + ('ruby-build', 'https://github.com/rbenv/ruby-build', '98c0337'), ( 'ruby-download', 'https://github.com/garnieretienne/rvm-download', From 4399c2dbc6b7571489a524eedecfba9cd53d93a8 Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Thu, 10 Nov 2022 20:09:56 -0600 Subject: [PATCH 130/416] Add `--no-ext-diff` to `git diff` call --- pre_commit/git.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index f84eb06b..a76118f0 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -150,8 +150,8 @@ def get_staged_files(cwd: str | None = None) -> list[str]: def intent_to_add_files() -> list[str]: _, stdout, _ = cmd_output( - 'git', 'diff', '--ignore-submodules', '--diff-filter=A', - '--name-only', '-z', + 'git', 'diff', '--no-ext-diff', '--ignore-submodules', + '--diff-filter=A', '--name-only', '-z', ) return zsplit(stdout) From 371b4fc1fd33267c0ca0fe6962eee4fa76c4305d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 14 Nov 2022 23:36:47 +0000 Subject: [PATCH 131/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.2.0 → v3.2.2](https://github.com/asottile/pyupgrade/compare/v3.2.0...v3.2.2) - [github.com/pre-commit/mirrors-mypy: v0.982 → v0.990](https://github.com/pre-commit/mirrors-mypy/compare/v0.982...v0.990) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1a4b5677..ad5fecb4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.2.0 + rev: v3.2.2 hooks: - id: pyupgrade args: [--py37-plus] @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.982 + rev: v0.990 hooks: - id: mypy additional_dependencies: [types-all] From 318296d8c5427430510620bc443393a290f6db92 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 16 Nov 2022 19:19:49 -0500 Subject: [PATCH 132/416] remove no_implicit_optional this is the default in mypy 0.990 Committed via https://github.com/asottile/all-repos --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index ab95cc04..dd0f9c9a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -56,7 +56,6 @@ check_untyped_defs = true disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_defs = true -no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = true From 391d05e2f30916677919bcea2128414e807d0ff0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 23:11:57 +0000 Subject: [PATCH 133/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.990 → v0.991](https://github.com/pre-commit/mirrors-mypy/compare/v0.990...v0.991) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ad5fecb4..44172896 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.990 + rev: v0.991 hooks: - id: mypy additional_dependencies: [types-all] From 50c217964b0f00e38d67cac858b597501a86e22b Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 27 Nov 2022 16:30:58 -0500 Subject: [PATCH 134/416] remove obsolete comment --- pre_commit/commands/sample_config.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pre_commit/commands/sample_config.py b/pre_commit/commands/sample_config.py index 82a1617f..ce22f65e 100644 --- a/pre_commit/commands/sample_config.py +++ b/pre_commit/commands/sample_config.py @@ -1,7 +1,3 @@ -# TODO: maybe `git ls-remote git://github.com/pre-commit/pre-commit-hooks` to -# determine the latest revision? This adds ~200ms from my tests (and is -# significantly faster than https:// or http://). For now, periodically -# manually updating the revision is fine. from __future__ import annotations SAMPLE_CONFIG = '''\ # See https://pre-commit.com for more information From df7bcf78c3b1c056150b5476a5a58b6bd0d8c8d5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Nov 2022 01:09:52 +0000 Subject: [PATCH 135/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0) - [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 44172896..ee1492c6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -34,7 +34,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + rev: 6.0.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From 5becd50974ea39caea357be2d62c940120ead91a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 5 Dec 2022 23:55:06 -0500 Subject: [PATCH 136/416] update swift for jammy --- testing/get-swift.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/get-swift.sh b/testing/get-swift.sh index b77e18c0..3e780824 100755 --- a/testing/get-swift.sh +++ b/testing/get-swift.sh @@ -3,9 +3,9 @@ set -euo pipefail . /etc/lsb-release -if [ "$DISTRIB_CODENAME" = "focal" ]; then - SWIFT_URL='https://download.swift.org/swift-5.6.1-release/ubuntu2004/swift-5.6.1-RELEASE/swift-5.6.1-RELEASE-ubuntu20.04.tar.gz' - SWIFT_HASH='2b4f22d4a8b59fe8e050f0b7f020f8d8f12553cbda56709b2340a4a3bb90cfea' +if [ "$DISTRIB_CODENAME" = "jammy" ]; then + SWIFT_URL='https://download.swift.org/swift-5.7.1-release/ubuntu2204/swift-5.7.1-RELEASE/swift-5.7.1-RELEASE-ubuntu22.04.tar.gz' + SWIFT_HASH='7f60291f5088d3e77b0c2364beaabd29616ee7b37260b7b06bdbeb891a7fe161' else echo "unknown dist: ${DISTRIB_CODENAME}" 1>&2 exit 1 From 6c524f7a554f03a247eb76ac48da78b8eef27389 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 23 Nov 2022 14:45:08 -0500 Subject: [PATCH 137/416] fix rust platform detection on windows --- pre_commit/languages/rust.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index ef603bc0..204f2aa7 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -3,7 +3,6 @@ from __future__ import annotations import contextlib import functools import os.path -import platform import shutil import sys import tempfile @@ -99,10 +98,7 @@ def install_rust_with_toolchain(toolchain: str) -> None: if parse_shebang.find_executable('rustup') is None: # We did not detect rustup and need to download it first. if sys.platform == 'win32': # pragma: win32 cover - if platform.machine() == 'x86_64': - url = 'https://win.rustup.rs/x86_64' - else: - url = 'https://win.rustup.rs/i686' + url = 'https://win.rustup.rs/x86_64' else: # pragma: win32 no cover url = 'https://sh.rustup.rs' From 46c64efd9d8da13e20292f26429d228e4f76958f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 6 Dec 2022 15:00:06 -0500 Subject: [PATCH 138/416] update .net framework target --- testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj | 2 +- testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj | 2 +- .../dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj | 2 +- .../dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj b/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj index 4f714d33..861ced6d 100644 --- a/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj +++ b/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6 true proj1 diff --git a/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj b/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj index da451f7c..dfce2cad 100644 --- a/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj +++ b/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6 true proj2 diff --git a/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj b/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj index d2e556ac..fa9879b0 100644 --- a/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj +++ b/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj @@ -1,7 +1,7 @@ Exe - netcoreapp3.1 + net6 true testeroni ./nupkg diff --git a/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj b/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj index e3729648..a4e2d005 100644 --- a/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj +++ b/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj @@ -1,7 +1,7 @@ Exe - netcoreapp3.1 + net6 true testeroni ./nupkg From 0b45ecc8a40d7d980b43a7f37d4f18b8e390aa8d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 6 Dec 2022 15:35:10 -0500 Subject: [PATCH 139/416] remove python 2.x cross version tests --- CONTRIBUTING.md | 1 - .../python3_hooks_repo/.pre-commit-hooks.yaml | 1 + tests/repository_test.py | 34 ++----------------- 3 files changed, 4 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0817681a..a9bcb79e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,6 @@ - The complete test suite depends on having at least the following installed (possibly not a complete list) - git (Version 2.24.0 or above is required to run pre-merge-commit tests) - - python2 (Required by a test which checks different python versions) - python3 (Required by a test which checks different python versions) - tox (or virtualenv) - ruby + gem diff --git a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml index 964cf836..2c237009 100644 --- a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml +++ b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml @@ -2,4 +2,5 @@ name: Python 3 Hook entry: python3-hook language: python + language_version: python3 files: \.py$ diff --git a/tests/repository_test.py b/tests/repository_test.py index 252c126c..64d8a170 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -173,23 +173,6 @@ def test_python_venv(tempdir_factory, store): ) -@xfailif_windows # pragma: win32 no cover # no python 2 in GHA -def test_switch_language_versions_doesnt_clobber(tempdir_factory, store): - # We're using the python3 repo because it prints the python version - path = make_repo(tempdir_factory, 'python3_hooks_repo') - - def run_on_version(version, expected_output): - config = make_config_from_repo(path) - config['hooks'][0]['language_version'] = version - hook = _get_hook(config, store, 'python3-hook') - ret, out = _hook_run(hook, [], color=False) - assert ret == 0 - assert _norm_out(out) == expected_output - - run_on_version('python2', b'2\n[]\nHello World\n') - run_on_version('python3', b'3\n[]\nHello World\n') - - def test_versioned_python_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'python3_hooks_repo', @@ -883,7 +866,7 @@ def test_tags_on_repositories(in_tmpdir, tempdir_factory, store): @pytest.fixture def local_python_config(): # Make a "local" hooks repo that just installs our other hooks repo - repo_path = get_resource_path('python3_hooks_repo') + repo_path = get_resource_path('python_hooks_repo') manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE)) hooks = [ dict(hook, additional_dependencies=[repo_path]) for hook in manifest @@ -892,23 +875,12 @@ def local_python_config(): def test_local_python_repo(store, local_python_config): - hook = _get_hook(local_python_config, store, 'python3-hook') + hook = _get_hook(local_python_config, store, 'foo') # language_version should have been adjusted to the interpreter version assert hook.language_version != C.DEFAULT ret, out = _hook_run(hook, ('filename',), color=False) assert ret == 0 - assert _norm_out(out) == b"3\n['filename']\nHello World\n" - - -@xfailif_windows # pragma: win32 no cover # no python2 in GHA -def test_local_python_repo_python2(store, local_python_config): - local_python_config['hooks'][0]['language_version'] = 'python2' - hook = _get_hook(local_python_config, store, 'python3-hook') - # language_version should have been adjusted to the interpreter version - assert hook.language_version != C.DEFAULT - ret, out = _hook_run(hook, ('filename',), color=False) - assert ret == 0 - assert _norm_out(out) == b"2\n['filename']\nHello World\n" + assert _norm_out(out) == b"['filename']\nHello World\n" def test_default_language_version(store, local_python_config): From 92c70766fd2db34fa025c2d8c7dad25f6cb0b17e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 6 Dec 2022 16:47:56 -0500 Subject: [PATCH 140/416] fix rust coverage on windows it's a complete mystery why this isn't needed on other platforms, the branch is legitimately uncovered there --- tests/languages/rust_test.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py index 9bf97830..f011e719 100644 --- a/tests/languages/rust_test.py +++ b/tests/languages/rust_test.py @@ -68,3 +68,23 @@ def test_installs_with_bootstrapped_rustup(tmpdir, language_version): with rust.in_env(prefix, language_version): assert cmd_output('hello_world')[1] == 'Hello, world!\n' + + +def test_installs_with_existing_rustup(tmpdir): + tmpdir.join('src', 'main.rs').ensure().write( + 'fn main() {\n' + ' println!("Hello, world!");\n' + '}\n', + ) + tmpdir.join('Cargo.toml').ensure().write( + '[package]\n' + 'name = "hello_world"\n' + 'version = "0.1.0"\n' + 'edition = "2021"\n', + ) + prefix = Prefix(str(tmpdir)) + + assert parse_shebang.find_executable('rustup') is not None + rust.install_environment(prefix, '1.56.0', ()) + with rust.in_env(prefix, '1.56.0'): + assert cmd_output('hello_world')[1] == 'Hello, world!\n' From b92fe017559d93061c8c259db389ecd8e4f39b00 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 10 Dec 2022 23:33:20 -0500 Subject: [PATCH 141/416] force the `-p` branch to run for language: python under test --- tests/repository_test.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/repository_test.py b/tests/repository_test.py index 64d8a170..6d50cb84 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -173,13 +173,20 @@ def test_python_venv(tempdir_factory, store): ) -def test_versioned_python_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'python3_hooks_repo', - 'python3-hook', - [os.devnull], - f'3\n[{os.devnull!r}]\nHello World\n'.encode(), - ) +def test_language_versioned_python_hook(tempdir_factory, store): + # we patch this force virtualenv executing with `-p` since we can't + # reliably have multiple pythons available in CI + with mock.patch.object( + python, + '_sys_executable_matches', + return_value=False, + ): + _test_hook_repo( + tempdir_factory, store, 'python3_hooks_repo', + 'python3-hook', + [os.devnull], + f'3\n[{os.devnull!r}]\nHello World\n'.encode(), + ) @skipif_cant_run_coursier # pragma: win32 no cover From 8cc3a6d8aa45b9984972bb0f73b9b6dcb3227273 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 10 Dec 2022 23:45:04 -0500 Subject: [PATCH 142/416] passenv is stupid anyway --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 463b72f3..e06be115 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ envlist = py37,py38,pypy3,pre-commit [testenv] deps = -rrequirements-dev.txt -passenv = APPDATA HOME LOCALAPPDATA PROGRAMFILES RUSTUP_HOME +passenv = * commands = coverage erase coverage run -m pytest {posargs:tests} From b00c31cf9e917b5ac62e093e9cca6a59d3677992 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 12 Dec 2022 12:22:39 -0500 Subject: [PATCH 143/416] use a newer version of ruby which builds cleanly --- .../ruby_versioned_hooks_repo/.pre-commit-hooks.yaml | 2 +- tests/languages/ruby_test.py | 4 ++-- tests/repository_test.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml index 63e1dd4c..364d47d8 100644 --- a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml +++ b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml @@ -2,5 +2,5 @@ name: Ruby Hook entry: ruby_hook language: ruby - language_version: 2.5.1 + language_version: 3.1.0 files: \.rb$ diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index dc55456e..29f3c802 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -71,10 +71,10 @@ def test_install_ruby_default(fake_gem_prefix): @xfailif_windows # pragma: win32 no cover def test_install_ruby_with_version(fake_gem_prefix): - ruby.install_environment(fake_gem_prefix, '2.7.2', ()) + ruby.install_environment(fake_gem_prefix, '3.1.0', ()) # Should be able to activate and use rbenv install - with ruby.in_env(fake_gem_prefix, '2.7.2'): + with ruby.in_env(fake_gem_prefix, '3.1.0'): cmd_output('rbenv', 'install', '--help') diff --git a/tests/repository_test.py b/tests/repository_test.py index 6d50cb84..8705d886 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -335,7 +335,7 @@ def test_run_versioned_ruby_hook(tempdir_factory, store): tempdir_factory, store, 'ruby_versioned_hooks_repo', 'ruby_hook', [os.devnull], - b'2.5.1\nHello world from a ruby hook\n', + b'3.1.0\nHello world from a ruby hook\n', ) @@ -357,7 +357,7 @@ def test_run_ruby_hook_with_disable_shared_gems( tempdir_factory, store, 'ruby_versioned_hooks_repo', 'ruby_hook', [os.devnull], - b'2.5.1\nHello world from a ruby hook\n', + b'3.1.0\nHello world from a ruby hook\n', ) From 6ab7fc25d56872824252ff7357c2d7a754bfcb1e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Dec 2022 23:51:53 +0000 Subject: [PATCH 144/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.2.2 → v3.3.0](https://github.com/asottile/pyupgrade/compare/v3.2.2...v3.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee1492c6..3aecdc13 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.2.2 + rev: v3.3.0 hooks: - id: pyupgrade args: [--py37-plus] From 52948f610c458cad95f60fbc7b0337780a98c9f0 Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Tue, 6 Dec 2022 12:23:47 +0100 Subject: [PATCH 145/416] When R executable is an explicit path, we need to appene `.exe` on Windows --- pre_commit/languages/r.py | 3 ++- tests/languages/r_test.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 22b5f253..d281102b 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -15,6 +15,7 @@ from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b +from pre_commit.util import win_exe ENVIRONMENT_DIR = 'renv' RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ') @@ -63,7 +64,7 @@ def _rscript_exec() -> str: if r_home is None: return 'Rscript' else: - return os.path.join(r_home, 'bin', 'Rscript') + return os.path.join(r_home, 'bin', win_exe('Rscript')) def _entry_validate(entry: Sequence[str]) -> None: diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index 5bc63b27..c52d5acd 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -6,6 +6,7 @@ import pytest from pre_commit import envcontext from pre_commit.languages import r +from pre_commit.util import win_exe from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo from tests.repository_test import _get_hook_no_install @@ -133,7 +134,7 @@ def test_r_parsing_file_local(tempdir_factory, store): def test_rscript_exec_relative_to_r_home(): - expected = os.path.join('r_home_dir', 'bin', 'Rscript') + expected = os.path.join('r_home_dir', 'bin', win_exe('Rscript')) with envcontext.envcontext((('R_HOME', 'r_home_dir'),)): assert r._rscript_exec() == expected From a179808bfeb63094b2127402da8cb4eeccb5be2d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Dec 2022 00:40:31 +0000 Subject: [PATCH 146/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/add-trailing-comma: v2.3.0 → v2.4.0](https://github.com/asottile/add-trailing-comma/compare/v2.3.0...v2.4.0) - [github.com/asottile/pyupgrade: v3.3.0 → v3.3.1](https://github.com/asottile/pyupgrade/compare/v3.3.0...v3.3.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3aecdc13..c3b261bd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,12 +20,12 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.3.0 + rev: v2.4.0 hooks: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.3.0 + rev: v3.3.1 hooks: - id: pyupgrade args: [--py37-plus] From 94b617890624fc760a91289019ef4608e1a386fe Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 Dec 2022 00:30:07 +0000 Subject: [PATCH 147/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-autopep8: v2.0.0 → v2.0.1](https://github.com/pre-commit/mirrors-autopep8/compare/v2.0.0...v2.0.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c3b261bd..7e58bdd8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v2.0.0 + rev: v2.0.1 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From e904628830490042426e411512bfb4d519de891b Mon Sep 17 00:00:00 2001 From: Ruairidh MacLeod Date: Tue, 6 Dec 2022 12:04:19 +0000 Subject: [PATCH 148/416] fix dotnet hooks with prefixes --- pre_commit/languages/dotnet.py | 32 ++++++++++++++++--- .../.gitignore | 3 ++ .../.pre-commit-hooks.yaml | 5 +++ .../Program.cs | 12 +++++++ .../dotnet_hooks_csproj_prefix_repo.csproj | 9 ++++++ tests/repository_test.py | 1 + 6 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore create mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml create mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs create mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 3983c6f0..9ebda2f7 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -2,6 +2,9 @@ from __future__ import annotations import contextlib import os.path +import re +import xml.etree.ElementTree +import zipfile from typing import Generator from typing import Sequence @@ -57,10 +60,29 @@ def install_environment( ), ) - # Determine tool from the packaged file ..nupkg - build_outputs = os.listdir(os.path.join(prefix.prefix_dir, build_dir)) - for output in build_outputs: - tool_name = output.split('.')[0] + nupkg_dir = prefix.path(build_dir) + nupkgs = [x for x in os.listdir(nupkg_dir) if x.endswith('.nupkg')] + + if not nupkgs: + raise AssertionError('could not find any build outputs to install') + + for nupkg in nupkgs: + with zipfile.ZipFile(os.path.join(nupkg_dir, nupkg)) as f: + nuspec, = (x for x in f.namelist() if x.endswith('.nuspec')) + with f.open(nuspec) as spec: + tree = xml.etree.ElementTree.parse(spec) + + namespace = re.match(r'{.*}', tree.getroot().tag) + if not namespace: + raise AssertionError('could not parse namespace from nuspec') + + tool_id_element = tree.find(f'.//{namespace[0]}id') + if tool_id_element is None: + raise AssertionError('expected to find an "id" element') + + tool_id = tool_id_element.text + if not tool_id: + raise AssertionError('"id" element missing tool name') # Install to bin dir helpers.run_setup_cmd( @@ -69,7 +91,7 @@ def install_environment( 'dotnet', 'tool', 'install', '--tool-path', os.path.join(envdir, BIN_DIR), '--add-source', build_dir, - tool_name, + tool_id, ), ) diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore b/testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore new file mode 100644 index 00000000..edcd28f4 --- /dev/null +++ b/testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore @@ -0,0 +1,3 @@ +bin/ +obj/ +nupkg/ diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml b/testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml new file mode 100644 index 00000000..6626627d --- /dev/null +++ b/testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml @@ -0,0 +1,5 @@ +- id: dotnet-example-hook + name: dotnet example hook + entry: testeroni.tool + language: dotnet + files: '' diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs b/testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs new file mode 100644 index 00000000..1456e8ef --- /dev/null +++ b/testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace dotnet_hooks_repo +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello from dotnet!"); + } + } +} diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj b/testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj new file mode 100644 index 00000000..754b7600 --- /dev/null +++ b/testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj @@ -0,0 +1,9 @@ + + + Exe + net7.0 + true + testeroni.tool + ./nupkg + + diff --git a/tests/repository_test.py b/tests/repository_test.py index 8705d886..c3936bf2 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1031,6 +1031,7 @@ def test_local_perl_additional_dependencies(store): 'dotnet_hooks_csproj_repo', 'dotnet_hooks_sln_repo', 'dotnet_hooks_combo_repo', + 'dotnet_hooks_csproj_prefix_repo', ), ) def test_dotnet_hook(tempdir_factory, store, repo): From c38e0c7ba8e8a98338a3ed492f83b896337244e6 Mon Sep 17 00:00:00 2001 From: Ruairidh MacLeod Date: Tue, 6 Dec 2022 12:45:44 +0000 Subject: [PATCH 149/416] dotnet: ignore nuget source during tool install --- pre_commit/languages/dotnet.py | 37 +++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 9ebda2f7..e26b45c3 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -3,6 +3,7 @@ from __future__ import annotations import contextlib import os.path import re +import tempfile import xml.etree.ElementTree import zipfile from typing import Generator @@ -38,6 +39,22 @@ def in_env(prefix: Prefix) -> Generator[None, None, None]: yield +@contextlib.contextmanager +def _nuget_config_no_sources() -> Generator[str, None, None]: + with tempfile.TemporaryDirectory() as tmpdir: + nuget_config = os.path.join(tmpdir, 'nuget.config') + with open(nuget_config, 'w') as f: + f.write( + '' + '' + ' ' + ' ' + ' ' + '', + ) + yield nuget_config + + def install_environment( prefix: Prefix, version: str, @@ -85,15 +102,17 @@ def install_environment( raise AssertionError('"id" element missing tool name') # Install to bin dir - helpers.run_setup_cmd( - prefix, - ( - 'dotnet', 'tool', 'install', - '--tool-path', os.path.join(envdir, BIN_DIR), - '--add-source', build_dir, - tool_id, - ), - ) + with _nuget_config_no_sources() as nuget_config: + helpers.run_setup_cmd( + prefix, + ( + 'dotnet', 'tool', 'install', + '--configfile', nuget_config, + '--tool-path', os.path.join(envdir, BIN_DIR), + '--add-source', build_dir, + tool_id, + ), + ) # Clean the git dir, ignoring the environment dir clean_cmd = ('git', 'clean', '-ffxd', '-e', f'{ENVIRONMENT_DIR}-*') From 40c5bdad65da4015af0e5ffe88227053109aecf3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 25 Dec 2022 17:52:05 -0500 Subject: [PATCH 150/416] v2.21.0 --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03a7c800..cd0de5f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,43 @@ +2.21.0 - 2022-12-25 +=================== + +### Features +- Require new-enough virtualenv to prevent 3.10 breakage + - #2467 PR by @asottile. +- Respect aliases with `SKIP` for environment install. + - #2480 PR by @kmARC. + - #2478 issue by @kmARC. +- Allow `pre-commit run --files` against unmerged paths. + - #2484 PR by @asottile. +- Also apply regex warnings to `repo: local` hooks. + - #2524 PR by @chrisRedwine. + - #2521 issue by @asottile. +- `rust` is now a "first class" language -- supporting `language_version` and + installation when not present. + - #2534 PR by @Holzhaus. +- `r` now uses more-reliable binary installation. + - #2460 PR by @lorenzwalthert. +- `GIT_ALLOW_PROTOCOL` is now passed through for git operations. + - #2555 PR by @asottile. +- `GIT_ASKPASS` is now passed through for git operations. + - #2564 PR by @mattp-. +- Remove `toml` dependency by using `cargo add` directly. + - #2568 PR by @m-rsha. +- Support `dotnet` hooks which have dotted prefixes. + - #2641 PR by @rkm. + - #2629 issue by @rkm. + +### Fixes +- Properly adjust `--commit-msg-filename` if run from a sub directory. + - #2459 PR by @asottile. +- Simplify `--intent-to-add` detection by using `git diff`. + - #2580 PR by @m-rsha. +- Fix `R.exe` selection on windows. + - #2605 PR by @lorenzwalthert. + - #2599 issue by @SInginc. +- Skip default `nuget` source when installing `dotnet` packages. + - #2642 PR by @rkm. + 2.20.0 - 2022-07-10 =================== diff --git a/setup.cfg b/setup.cfg index dd0f9c9a..a8988921 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.20.0 +version = 2.21.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 524a23607217e115c2f1f51b3bbb869f186040ad Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 23 Dec 2022 18:37:33 -0500 Subject: [PATCH 151/416] drop python<3.8 --- .pre-commit-config.yaml | 4 ++-- azure-pipelines.yml | 6 +++--- pre_commit/constants.py | 9 ++------- setup.cfg | 3 +-- tox.ini | 2 +- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e58bdd8..b7d7f1f0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) - args: [--py37-plus, --add-import, 'from __future__ import annotations'] + args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v2.4.0 hooks: @@ -28,7 +28,7 @@ repos: rev: v3.3.1 hooks: - id: pyupgrade - args: [--py37-plus] + args: [--py38-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 rev: v2.0.1 hooks: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 34c94f54..911ef32d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ resources: jobs: - template: job--python-tox.yml@asottile parameters: - toxenvs: [py37] + toxenvs: [py38] os: windows additional_variables: TEMP: C:\Temp @@ -34,7 +34,7 @@ jobs: displayName: install R - template: job--python-tox.yml@asottile parameters: - toxenvs: [py37] + toxenvs: [py38] os: linux name_postfix: _latest_git pre_test: @@ -52,7 +52,7 @@ jobs: displayName: install R - template: job--python-tox.yml@asottile parameters: - toxenvs: [py37, py38, py39] + toxenvs: [py38, py39, py310] os: linux pre_test: - task: UseRubyVersion@0 diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 5bc4ae98..8fc5e55d 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -1,11 +1,6 @@ from __future__ import annotations -import sys - -if sys.version_info >= (3, 8): # pragma: >=3.8 cover - import importlib.metadata as importlib_metadata -else: # pragma: <3.8 cover - import importlib_metadata +import importlib.metadata CONFIG_FILE = '.pre-commit-config.yaml' MANIFEST_FILE = '.pre-commit-hooks.yaml' @@ -15,7 +10,7 @@ INSTALLED_STATE_VERSION = '1' # Bump when modifying `empty_template` LOCAL_REPO_VERSION = '1' -VERSION = importlib_metadata.version('pre_commit') +VERSION = importlib.metadata.version('pre_commit') # `manual` is not invoked by any installed git hook. See #719 STAGES = ( diff --git a/setup.cfg b/setup.cfg index a8988921..1d28a41c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,8 +24,7 @@ install_requires = nodeenv>=0.11.1 pyyaml>=5.1 virtualenv>=20.10.0 - importlib-metadata;python_version<"3.8" -python_requires = >=3.7 +python_requires = >=3.8 [options.packages.find] exclude = diff --git a/tox.ini b/tox.ini index e06be115..a44f93d4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py37,py38,pypy3,pre-commit +envlist = py,pypy3,pre-commit [testenv] deps = -rrequirements-dev.txt From 0024484f5b6b0b8a811c0bed4773c1fd28a98503 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 27 Dec 2022 11:15:45 -0500 Subject: [PATCH 152/416] remove support for top-level list format --- pre_commit/clientlib.py | 15 +-- tests/clientlib_test.py | 8 -- tests/commands/install_uninstall_test.py | 122 ++++++++++++----------- 3 files changed, 66 insertions(+), 79 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index da6ca2be..df8d2e2d 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -391,23 +391,10 @@ class InvalidConfigError(FatalError): pass -def ordered_load_normalize_legacy_config(contents: str) -> dict[str, Any]: - data = yaml_load(contents) - if isinstance(data, list): - logger.warning( - 'normalizing pre-commit configuration to a top-level map. ' - 'support for top level list will be removed in a future version. ' - 'run: `pre-commit migrate-config` to automatically fix this.', - ) - return {'repos': data} - else: - return data - - load_config = functools.partial( cfgv.load_from_filename, schema=CONFIG_SCHEMA, - load_strategy=ordered_load_normalize_legacy_config, + load_strategy=yaml_load, exc_tp=InvalidConfigError, ) diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index b4c3c4e0..23d9352f 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -120,14 +120,6 @@ def test_validate_config_main_ok(): assert not validate_config_main(('.pre-commit-config.yaml',)) -def test_validate_config_old_list_format_ok(tmpdir, cap_out): - f = tmpdir.join('cfg.yaml') - f.write('- {repo: meta, hooks: [{id: identity}]}') - assert not validate_config_main((f.strpath,)) - msg = '[WARNING] normalizing pre-commit configuration to a top-level map' - assert msg in cap_out.get() - - def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog): f = tmpdir.join('cfg.yaml') f.write( diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 379c03a4..e3943773 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -739,20 +739,22 @@ def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store): def test_post_commit_integration(tempdir_factory, store): path = git_dir(tempdir_factory) - config = [ - { - 'repo': 'local', - 'hooks': [{ - 'id': 'post-commit', - 'name': 'Post commit', - 'entry': 'touch post-commit.tmp', - 'language': 'system', - 'always_run': True, - 'verbose': True, - 'stages': ['post-commit'], - }], - }, - ] + config = { + 'repos': [ + { + 'repo': 'local', + 'hooks': [{ + 'id': 'post-commit', + 'name': 'Post commit', + 'entry': 'touch post-commit.tmp', + 'language': 'system', + 'always_run': True, + 'verbose': True, + 'stages': ['post-commit'], + }], + }, + ], + } write_config(path, config) with cwd(path): _get_commit_output(tempdir_factory) @@ -765,20 +767,22 @@ def test_post_commit_integration(tempdir_factory, store): def test_post_merge_integration(tempdir_factory, store): path = git_dir(tempdir_factory) - config = [ - { - 'repo': 'local', - 'hooks': [{ - 'id': 'post-merge', - 'name': 'Post merge', - 'entry': 'touch post-merge.tmp', - 'language': 'system', - 'always_run': True, - 'verbose': True, - 'stages': ['post-merge'], - }], - }, - ] + config = { + 'repos': [ + { + 'repo': 'local', + 'hooks': [{ + 'id': 'post-merge', + 'name': 'Post merge', + 'entry': 'touch post-merge.tmp', + 'language': 'system', + 'always_run': True, + 'verbose': True, + 'stages': ['post-merge'], + }], + }, + ], + } write_config(path, config) with cwd(path): # create a simple diamond of commits for a non-trivial merge @@ -807,20 +811,22 @@ def test_post_merge_integration(tempdir_factory, store): def test_post_rewrite_integration(tempdir_factory, store): path = git_dir(tempdir_factory) - config = [ - { - 'repo': 'local', - 'hooks': [{ - 'id': 'post-rewrite', - 'name': 'Post rewrite', - 'entry': 'touch post-rewrite.tmp', - 'language': 'system', - 'always_run': True, - 'verbose': True, - 'stages': ['post-rewrite'], - }], - }, - ] + config = { + 'repos': [ + { + 'repo': 'local', + 'hooks': [{ + 'id': 'post-rewrite', + 'name': 'Post rewrite', + 'entry': 'touch post-rewrite.tmp', + 'language': 'system', + 'always_run': True, + 'verbose': True, + 'stages': ['post-rewrite'], + }], + }, + ], + } write_config(path, config) with cwd(path): open('init', 'a').close() @@ -836,21 +842,23 @@ def test_post_rewrite_integration(tempdir_factory, store): def test_post_checkout_integration(tempdir_factory, store): path = git_dir(tempdir_factory) - config = [ - { - 'repo': 'local', - 'hooks': [{ - 'id': 'post-checkout', - 'name': 'Post checkout', - 'entry': 'bash -c "echo ${PRE_COMMIT_TO_REF}"', - 'language': 'system', - 'always_run': True, - 'verbose': True, - 'stages': ['post-checkout'], - }], - }, - {'repo': 'meta', 'hooks': [{'id': 'identity'}]}, - ] + config = { + 'repos': [ + { + 'repo': 'local', + 'hooks': [{ + 'id': 'post-checkout', + 'name': 'Post checkout', + 'entry': 'bash -c "echo ${PRE_COMMIT_TO_REF}"', + 'language': 'system', + 'always_run': True, + 'verbose': True, + 'stages': ['post-checkout'], + }], + }, + {'repo': 'meta', 'hooks': [{'id': 'identity'}]}, + ], + } write_config(path, config) with cwd(path): cmd_output('git', 'add', '.') From ff3150d58a2ca9441ed6f0a9f3dcc2623301124a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 27 Dec 2022 11:29:00 -0500 Subject: [PATCH 153/416] remove support for sha to specify rev --- pre_commit/clientlib.py | 44 +++++------------------------------------ tests/clientlib_test.py | 43 ---------------------------------------- 2 files changed, 5 insertions(+), 82 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index da6ca2be..bbb4915f 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -114,8 +114,7 @@ LOCAL = 'local' META = 'meta' -# should inherit from cfgv.Conditional if sha support is dropped -class WarnMutableRev(cfgv.ConditionalOptional): +class WarnMutableRev(cfgv.Conditional): def check(self, dct: dict[str, Any]) -> None: super().check(dct) @@ -171,36 +170,6 @@ class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault): ) -class MigrateShaToRev: - key = 'rev' - - @staticmethod - def _cond(key: str) -> cfgv.Conditional: - return cfgv.Conditional( - key, cfgv.check_string, - condition_key='repo', - condition_value=cfgv.NotIn(LOCAL, META), - ensure_absent=True, - ) - - def check(self, dct: dict[str, Any]) -> None: - if dct.get('repo') in {LOCAL, META}: - self._cond('rev').check(dct) - self._cond('sha').check(dct) - elif 'sha' in dct and 'rev' in dct: - raise cfgv.ValidationError('Cannot specify both sha and rev') - elif 'sha' in dct: - self._cond('sha').check(dct) - else: - self._cond('rev').check(dct) - - def apply_default(self, dct: dict[str, Any]) -> None: - if 'sha' in dct: - dct['rev'] = dct.pop('sha') - - remove_default = cfgv.Required.remove_default - - def _entry(modname: str) -> str: """the hook `entry` is passed through `shlex.split()` by the command runner, so to prevent issues with spaces and backslashes (on Windows) @@ -324,14 +293,11 @@ CONFIG_REPO_DICT = cfgv.Map( 'repo', META, ), - MigrateShaToRev(), WarnMutableRev( - 'rev', - cfgv.check_string, - '', - 'repo', - cfgv.NotIn(LOCAL, META), - True, + 'rev', cfgv.check_string, + condition_key='repo', + condition_value=cfgv.NotIn(LOCAL, META), + ensure_absent=True, ), cfgv.WarnAdditionalKeys(('repo', 'rev', 'hooks'), warn_unknown_keys_repo), ) diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index b4c3c4e0..98586046 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -14,7 +14,6 @@ from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION from pre_commit.clientlib import MANIFEST_SCHEMA from pre_commit.clientlib import META_HOOK_DICT -from pre_commit.clientlib import MigrateShaToRev from pre_commit.clientlib import OptionalSensibleRegexAtHook from pre_commit.clientlib import OptionalSensibleRegexAtTop from pre_commit.clientlib import validate_config_main @@ -425,48 +424,6 @@ def test_valid_manifests(manifest_obj, expected): assert ret is expected -@pytest.mark.parametrize( - 'dct', - ( - {'repo': 'local'}, {'repo': 'meta'}, - {'repo': 'wat', 'sha': 'wat'}, {'repo': 'wat', 'rev': 'wat'}, - ), -) -def test_migrate_sha_to_rev_ok(dct): - MigrateShaToRev().check(dct) - - -def test_migrate_sha_to_rev_dont_specify_both(): - with pytest.raises(cfgv.ValidationError) as excinfo: - MigrateShaToRev().check({'repo': 'a', 'sha': 'b', 'rev': 'c'}) - msg, = excinfo.value.args - assert msg == 'Cannot specify both sha and rev' - - -@pytest.mark.parametrize( - 'dct', - ( - {'repo': 'a'}, - {'repo': 'meta', 'sha': 'a'}, {'repo': 'meta', 'rev': 'a'}, - ), -) -def test_migrate_sha_to_rev_conditional_check_failures(dct): - with pytest.raises(cfgv.ValidationError): - MigrateShaToRev().check(dct) - - -def test_migrate_to_sha_apply_default(): - dct = {'repo': 'a', 'sha': 'b'} - MigrateShaToRev().apply_default(dct) - assert dct == {'repo': 'a', 'rev': 'b'} - - -def test_migrate_to_sha_ok(): - dct = {'repo': 'a', 'rev': 'b'} - MigrateShaToRev().apply_default(dct) - assert dct == {'repo': 'a', 'rev': 'b'} - - @pytest.mark.parametrize( 'config_repo', ( From 40e69ce8e3fed20290d031c8b660c74da5d4ca3d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 29 Aug 2022 18:58:03 -0400 Subject: [PATCH 154/416] use modules as protocols --- pre_commit/languages/all.py | 84 ++++++++++++++++++++++--------------- testing/gen-languages-all | 30 ------------- tests/repository_test.py | 16 ++++--- 3 files changed, 60 insertions(+), 70 deletions(-) delete mode 100755 testing/gen-languages-all diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index cfd42ce2..7c7c58bd 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -1,7 +1,6 @@ from __future__ import annotations -from typing import Callable -from typing import NamedTuple +from typing import Protocol from typing import Sequence from pre_commit.hook import Hook @@ -27,44 +26,61 @@ from pre_commit.languages import system from pre_commit.prefix import Prefix -class Language(NamedTuple): - name: str +class Language(Protocol): # Use `None` for no installation / environment - ENVIRONMENT_DIR: str | None + @property + def ENVIRONMENT_DIR(self) -> str | None: ... # return a value to replace `'default` for `language_version` - get_default_version: Callable[[], str] + def get_default_version(self) -> str: ... + # return whether the environment is healthy (or should be rebuilt) - health_check: Callable[[Prefix, str], str | None] + def health_check( + self, + prefix: Prefix, + language_version: str, + ) -> str | None: + ... + # install a repository for the given language and language_version - install_environment: Callable[[Prefix, str, Sequence[str]], None] + def install_environment( + self, + prefix: Prefix, + version: str, + additional_dependencies: Sequence[str], + ) -> None: + ... + # execute a hook and return the exit code and output - run_hook: Callable[[Hook, Sequence[str], bool], tuple[int, bytes]] + def run_hook( + self, + hook: Hook, + file_args: Sequence[str], + color: bool, + ) -> tuple[int, bytes]: + ... -# TODO: back to modules + Protocol: https://github.com/python/mypy/issues/5018 -languages = { - # BEGIN GENERATED (testing/gen-languages-all) - 'conda': Language(name='conda', ENVIRONMENT_DIR=conda.ENVIRONMENT_DIR, get_default_version=conda.get_default_version, health_check=conda.health_check, install_environment=conda.install_environment, run_hook=conda.run_hook), # noqa: E501 - 'coursier': Language(name='coursier', ENVIRONMENT_DIR=coursier.ENVIRONMENT_DIR, get_default_version=coursier.get_default_version, health_check=coursier.health_check, install_environment=coursier.install_environment, run_hook=coursier.run_hook), # noqa: E501 - 'dart': Language(name='dart', ENVIRONMENT_DIR=dart.ENVIRONMENT_DIR, get_default_version=dart.get_default_version, health_check=dart.health_check, install_environment=dart.install_environment, run_hook=dart.run_hook), # noqa: E501 - 'docker': Language(name='docker', ENVIRONMENT_DIR=docker.ENVIRONMENT_DIR, get_default_version=docker.get_default_version, health_check=docker.health_check, install_environment=docker.install_environment, run_hook=docker.run_hook), # noqa: E501 - 'docker_image': Language(name='docker_image', ENVIRONMENT_DIR=docker_image.ENVIRONMENT_DIR, get_default_version=docker_image.get_default_version, health_check=docker_image.health_check, install_environment=docker_image.install_environment, run_hook=docker_image.run_hook), # noqa: E501 - 'dotnet': Language(name='dotnet', ENVIRONMENT_DIR=dotnet.ENVIRONMENT_DIR, get_default_version=dotnet.get_default_version, health_check=dotnet.health_check, install_environment=dotnet.install_environment, run_hook=dotnet.run_hook), # noqa: E501 - 'fail': Language(name='fail', ENVIRONMENT_DIR=fail.ENVIRONMENT_DIR, get_default_version=fail.get_default_version, health_check=fail.health_check, install_environment=fail.install_environment, run_hook=fail.run_hook), # noqa: E501 - 'golang': Language(name='golang', ENVIRONMENT_DIR=golang.ENVIRONMENT_DIR, get_default_version=golang.get_default_version, health_check=golang.health_check, install_environment=golang.install_environment, run_hook=golang.run_hook), # noqa: E501 - 'lua': Language(name='lua', ENVIRONMENT_DIR=lua.ENVIRONMENT_DIR, get_default_version=lua.get_default_version, health_check=lua.health_check, install_environment=lua.install_environment, run_hook=lua.run_hook), # noqa: E501 - 'node': Language(name='node', ENVIRONMENT_DIR=node.ENVIRONMENT_DIR, get_default_version=node.get_default_version, health_check=node.health_check, install_environment=node.install_environment, run_hook=node.run_hook), # noqa: E501 - 'perl': Language(name='perl', ENVIRONMENT_DIR=perl.ENVIRONMENT_DIR, get_default_version=perl.get_default_version, health_check=perl.health_check, install_environment=perl.install_environment, run_hook=perl.run_hook), # noqa: E501 - 'pygrep': Language(name='pygrep', ENVIRONMENT_DIR=pygrep.ENVIRONMENT_DIR, get_default_version=pygrep.get_default_version, health_check=pygrep.health_check, install_environment=pygrep.install_environment, run_hook=pygrep.run_hook), # noqa: E501 - 'python': Language(name='python', ENVIRONMENT_DIR=python.ENVIRONMENT_DIR, get_default_version=python.get_default_version, health_check=python.health_check, install_environment=python.install_environment, run_hook=python.run_hook), # noqa: E501 - 'r': Language(name='r', ENVIRONMENT_DIR=r.ENVIRONMENT_DIR, get_default_version=r.get_default_version, health_check=r.health_check, install_environment=r.install_environment, run_hook=r.run_hook), # noqa: E501 - 'ruby': Language(name='ruby', ENVIRONMENT_DIR=ruby.ENVIRONMENT_DIR, get_default_version=ruby.get_default_version, health_check=ruby.health_check, install_environment=ruby.install_environment, run_hook=ruby.run_hook), # noqa: E501 - 'rust': Language(name='rust', ENVIRONMENT_DIR=rust.ENVIRONMENT_DIR, get_default_version=rust.get_default_version, health_check=rust.health_check, install_environment=rust.install_environment, run_hook=rust.run_hook), # noqa: E501 - 'script': Language(name='script', ENVIRONMENT_DIR=script.ENVIRONMENT_DIR, get_default_version=script.get_default_version, health_check=script.health_check, install_environment=script.install_environment, run_hook=script.run_hook), # noqa: E501 - 'swift': Language(name='swift', ENVIRONMENT_DIR=swift.ENVIRONMENT_DIR, get_default_version=swift.get_default_version, health_check=swift.health_check, install_environment=swift.install_environment, run_hook=swift.run_hook), # noqa: E501 - 'system': Language(name='system', ENVIRONMENT_DIR=system.ENVIRONMENT_DIR, get_default_version=system.get_default_version, health_check=system.health_check, install_environment=system.install_environment, run_hook=system.run_hook), # noqa: E501 - # END GENERATED +languages: dict[str, Language] = { + 'conda': conda, + 'coursier': coursier, + 'dart': dart, + 'docker': docker, + 'docker_image': docker_image, + 'dotnet': dotnet, + 'fail': fail, + 'golang': golang, + 'lua': lua, + 'node': node, + 'perl': perl, + 'pygrep': pygrep, + 'python': python, + 'r': r, + 'ruby': ruby, + 'rust': rust, + 'script': script, + 'swift': swift, + 'system': system, + # TODO: fully deprecate `python_venv` + 'python_venv': python, } -# TODO: fully deprecate `python_venv` -languages['python_venv'] = languages['python'] all_languages = sorted(languages) diff --git a/testing/gen-languages-all b/testing/gen-languages-all deleted file mode 100755 index 05f89295..00000000 --- a/testing/gen-languages-all +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import sys - -LANGUAGES = ( - 'conda', 'coursier', 'dart', 'docker', 'docker_image', 'dotnet', 'fail', - 'golang', 'lua', 'node', 'perl', 'pygrep', 'python', 'r', 'ruby', 'rust', - 'script', 'swift', 'system', -) -FIELDS = ( - 'ENVIRONMENT_DIR', 'get_default_version', 'health_check', - 'install_environment', 'run_hook', -) - - -def main() -> int: - print(f' # BEGIN GENERATED ({sys.argv[0]})') - for lang in LANGUAGES: - parts = [f' {lang!r}: Language(name={lang!r}'] - for k in FIELDS: - parts.append(f', {k}={lang}.{k}') - parts.append('), # noqa: E501') - print(''.join(parts)) - print(' # END GENERATED') - return 0 - - -if __name__ == '__main__': - raise SystemExit(main()) diff --git a/tests/repository_test.py b/tests/repository_test.py index c3936bf2..6aa0f007 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -133,9 +133,11 @@ def test_python_hook(tempdir_factory, store): def test_python_hook_default_version(tempdir_factory, store): # make sure that this continues to work for platforms where default # language detection does not work - returns_default = mock.Mock(return_value=C.DEFAULT) - lang = languages['python']._replace(get_default_version=returns_default) - with mock.patch.dict(languages, python=lang): + with mock.patch.object( + python, + 'get_default_version', + return_value=C.DEFAULT, + ): test_python_hook(tempdir_factory, store) @@ -247,9 +249,11 @@ def test_run_a_node_hook(tempdir_factory, store): def test_run_a_node_hook_default_version(tempdir_factory, store): # make sure that this continues to work for platforms where node is not # installed at the system - returns_default = mock.Mock(return_value=C.DEFAULT) - lang = languages['node']._replace(get_default_version=returns_default) - with mock.patch.dict(languages, node=lang): + with mock.patch.object( + node, + 'get_default_version', + return_value=C.DEFAULT, + ): test_run_a_node_hook(tempdir_factory, store) From 4a50859936b71a2f38c407a1eb56e74a6978c0a5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 27 Dec 2022 11:47:15 -0500 Subject: [PATCH 155/416] remove pre-commit-validate-config and pre-commit-validate-manifest --- pre_commit/clientlib.py | 39 ------------ pre_commit/commands/validate_config.py | 4 +- pre_commit/commands/validate_manifest.py | 4 +- setup.cfg | 2 - tests/clientlib_test.py | 78 ------------------------ tests/commands/validate_config_test.py | 64 +++++++++++++++++++ tests/commands/validate_manifest_test.py | 18 ++++++ 7 files changed, 88 insertions(+), 121 deletions(-) create mode 100644 tests/commands/validate_config_test.py create mode 100644 tests/commands/validate_manifest_test.py diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index df8d2e2d..deb160a0 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -1,6 +1,5 @@ from __future__ import annotations -import argparse import functools import logging import re @@ -13,12 +12,8 @@ import cfgv from identify.identify import ALL_TAGS import pre_commit.constants as C -from pre_commit.color import add_color_option -from pre_commit.commands.validate_config import validate_config -from pre_commit.commands.validate_manifest import validate_manifest from pre_commit.errors import FatalError from pre_commit.languages.all import all_languages -from pre_commit.logging_handler import logging_handler from pre_commit.util import parse_version from pre_commit.util import yaml_load @@ -44,14 +39,6 @@ def check_min_version(version: str) -> None: ) -def _make_argparser(filenames_help: str) -> argparse.ArgumentParser: - parser = argparse.ArgumentParser() - parser.add_argument('filenames', nargs='*', help=filenames_help) - parser.add_argument('-V', '--version', action='version', version=C.VERSION) - add_color_option(parser) - return parser - - MANIFEST_HOOK_DICT = cfgv.Map( 'Hook', 'id', @@ -97,19 +84,6 @@ load_manifest = functools.partial( ) -def validate_manifest_main(argv: Sequence[str] | None = None) -> int: - parser = _make_argparser('Manifest filenames.') - args = parser.parse_args(argv) - - with logging_handler(args.color): - logger.warning( - 'pre-commit-validate-manifest is deprecated -- ' - 'use `pre-commit validate-manifest` instead.', - ) - - return validate_manifest(args.filenames) - - LOCAL = 'local' META = 'meta' @@ -397,16 +371,3 @@ load_config = functools.partial( load_strategy=yaml_load, exc_tp=InvalidConfigError, ) - - -def validate_config_main(argv: Sequence[str] | None = None) -> int: - parser = _make_argparser('Config filenames.') - args = parser.parse_args(argv) - - with logging_handler(args.color): - logger.warning( - 'pre-commit-validate-config is deprecated -- ' - 'use `pre-commit validate-config` instead.', - ) - - return validate_config(args.filenames) diff --git a/pre_commit/commands/validate_config.py b/pre_commit/commands/validate_config.py index 91bb017a..24bd3135 100644 --- a/pre_commit/commands/validate_config.py +++ b/pre_commit/commands/validate_config.py @@ -1,9 +1,11 @@ from __future__ import annotations +from typing import Sequence + from pre_commit import clientlib -def validate_config(filenames: list[str]) -> int: +def validate_config(filenames: Sequence[str]) -> int: ret = 0 for filename in filenames: diff --git a/pre_commit/commands/validate_manifest.py b/pre_commit/commands/validate_manifest.py index 372a6380..419031a9 100644 --- a/pre_commit/commands/validate_manifest.py +++ b/pre_commit/commands/validate_manifest.py @@ -1,9 +1,11 @@ from __future__ import annotations +from typing import Sequence + from pre_commit import clientlib -def validate_manifest(filenames: list[str]) -> int: +def validate_manifest(filenames: Sequence[str]) -> int: ret = 0 for filename in filenames: diff --git a/setup.cfg b/setup.cfg index 1d28a41c..ca1f7d8b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,8 +34,6 @@ exclude = [options.entry_points] console_scripts = pre-commit = pre_commit.main:main - pre-commit-validate-config = pre_commit.clientlib:validate_config_main - pre-commit-validate-manifest = pre_commit.clientlib:validate_manifest_main [options.package_data] pre_commit.resources = diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 23d9352f..2afeaece 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -17,8 +17,6 @@ from pre_commit.clientlib import META_HOOK_DICT from pre_commit.clientlib import MigrateShaToRev from pre_commit.clientlib import OptionalSensibleRegexAtHook from pre_commit.clientlib import OptionalSensibleRegexAtTop -from pre_commit.clientlib import validate_config_main -from pre_commit.clientlib import validate_manifest_main from testing.fixtures import sample_local_config @@ -112,70 +110,6 @@ def test_config_schema_does_not_contain_defaults(): assert not isinstance(item, cfgv.Optional) -def test_validate_manifest_main_ok(): - assert not validate_manifest_main(('.pre-commit-hooks.yaml',)) - - -def test_validate_config_main_ok(): - assert not validate_config_main(('.pre-commit-config.yaml',)) - - -def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog): - f = tmpdir.join('cfg.yaml') - f.write( - 'repos:\n' - '- repo: https://gitlab.com/pycqa/flake8\n' - ' rev: 3.7.7\n' - ' hooks:\n' - ' - id: flake8\n' - ' args: [--some-args]\n', - ) - ret_val = validate_config_main((f.strpath,)) - assert not ret_val - assert caplog.record_tuples == [ - ( - 'pre_commit', - logging.WARNING, - 'pre-commit-validate-config is deprecated -- ' - 'use `pre-commit validate-config` instead.', - ), - ( - 'pre_commit', - logging.WARNING, - 'Unexpected key(s) present on https://gitlab.com/pycqa/flake8: ' - 'args', - ), - ] - - -def test_validate_warn_on_unknown_keys_at_top_level(tmpdir, caplog): - f = tmpdir.join('cfg.yaml') - f.write( - 'repos:\n' - '- repo: https://gitlab.com/pycqa/flake8\n' - ' rev: 3.7.7\n' - ' hooks:\n' - ' - id: flake8\n' - 'foo:\n' - ' id: 1.0.0\n', - ) - ret_val = validate_config_main((f.strpath,)) - assert not ret_val - assert caplog.record_tuples == [ - ( - 'pre_commit', - logging.WARNING, - 'pre-commit-validate-config is deprecated -- ' - 'use `pre-commit validate-config` instead.', - ), - ( - 'pre_commit', - logging.WARNING, - 'Unexpected key(s) present at root: foo', - ), - ] - - def test_ci_map_key_allowed_at_top_level(caplog): cfg = { 'ci': {'skip': ['foo']}, @@ -362,18 +296,6 @@ def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning): assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)] -@pytest.mark.parametrize('fn', (validate_config_main, validate_manifest_main)) -def test_mains_not_ok(tmpdir, fn): - not_yaml = tmpdir.join('f.notyaml') - not_yaml.write('{') - not_schema = tmpdir.join('notconfig.yaml') - not_schema.write('{}') - - assert fn(('does-not-exist',)) - assert fn((not_yaml.strpath,)) - assert fn((not_schema.strpath,)) - - @pytest.mark.parametrize( ('manifest_obj', 'expected'), ( diff --git a/tests/commands/validate_config_test.py b/tests/commands/validate_config_test.py new file mode 100644 index 00000000..a475cd81 --- /dev/null +++ b/tests/commands/validate_config_test.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import logging + +from pre_commit.commands.validate_config import validate_config + + +def test_validate_config_ok(): + assert not validate_config(('.pre-commit-config.yaml',)) + + +def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog): + f = tmpdir.join('cfg.yaml') + f.write( + 'repos:\n' + '- repo: https://gitlab.com/pycqa/flake8\n' + ' rev: 3.7.7\n' + ' hooks:\n' + ' - id: flake8\n' + ' args: [--some-args]\n', + ) + ret_val = validate_config((f.strpath,)) + assert not ret_val + assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + 'Unexpected key(s) present on https://gitlab.com/pycqa/flake8: ' + 'args', + ), + ] + + +def test_validate_warn_on_unknown_keys_at_top_level(tmpdir, caplog): + f = tmpdir.join('cfg.yaml') + f.write( + 'repos:\n' + '- repo: https://gitlab.com/pycqa/flake8\n' + ' rev: 3.7.7\n' + ' hooks:\n' + ' - id: flake8\n' + 'foo:\n' + ' id: 1.0.0\n', + ) + ret_val = validate_config((f.strpath,)) + assert not ret_val + assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + 'Unexpected key(s) present at root: foo', + ), + ] + + +def test_mains_not_ok(tmpdir): + not_yaml = tmpdir.join('f.notyaml') + not_yaml.write('{') + not_schema = tmpdir.join('notconfig.yaml') + not_schema.write('{}') + + assert validate_config(('does-not-exist',)) + assert validate_config((not_yaml.strpath,)) + assert validate_config((not_schema.strpath,)) diff --git a/tests/commands/validate_manifest_test.py b/tests/commands/validate_manifest_test.py new file mode 100644 index 00000000..a4bc8ac0 --- /dev/null +++ b/tests/commands/validate_manifest_test.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from pre_commit.commands.validate_manifest import validate_manifest + + +def test_validate_manifest_ok(): + assert not validate_manifest(('.pre-commit-hooks.yaml',)) + + +def test_not_ok(tmpdir): + not_yaml = tmpdir.join('f.notyaml') + not_yaml.write('{') + not_schema = tmpdir.join('notconfig.yaml') + not_schema.write('{}') + + assert validate_manifest(('does-not-exist',)) + assert validate_manifest((not_yaml.strpath,)) + assert validate_manifest((not_schema.strpath,)) From 887c5e1142ea9022407e85e7319bec3a403e1572 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 29 Dec 2022 20:54:03 -0500 Subject: [PATCH 156/416] azure pipelines -> github actions --- .github/actions/pre-test/action.yml | 41 +++++++++++++++++ .github/workflows/main.yml | 23 ++++++++++ README.md | 3 +- azure-pipelines.yml | 68 ----------------------------- testing/get-coursier.sh | 2 +- testing/get-dart.sh | 4 +- testing/get-lua.sh | 5 --- testing/get-swift.sh | 2 +- 8 files changed, 69 insertions(+), 79 deletions(-) create mode 100644 .github/actions/pre-test/action.yml create mode 100644 .github/workflows/main.yml delete mode 100644 azure-pipelines.yml delete mode 100755 testing/get-lua.sh diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml new file mode 100644 index 00000000..f230df7b --- /dev/null +++ b/.github/actions/pre-test/action.yml @@ -0,0 +1,41 @@ +inputs: + env: + default: ${{ matrix.env }} + +runs: + using: composite + steps: + - name: setup (windows) + shell: bash + if: runner.os == 'Windows' + run: | + set -x + + echo 'TEMP=C:\TEMP' >> "$GITHUB_ENV" + + echo "$CONDA\Scripts" >> "$GITHUB_PATH" + + echo 'C:\Strawberry\perl\bin' >> "$GITHUB_PATH" + echo 'C:\Strawberry\perl\site\bin' >> "$GITHUB_PATH" + echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" + + testing/get-dart.sh + pwsh testing/get-r.ps1 + - name: setup (linux) + shell: bash + if: runner.os == 'Linux' + run: | + set -x + + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + lua5.3 \ + liblua5.3-dev \ + luarocks \ + r-base + + testing/get-coursier.sh + testing/get-dart.sh + testing/get-swift.sh + - uses: asottile/workflows/.github/actions/latest-git@v1.2.0 + if: inputs.env == 'py38' && runner.os == 'Linux' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..c78d1051 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,23 @@ +name: main + +on: + push: + branches: [main, test-me-*] + tags: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + main-windows: + uses: asottile/workflows/.github/workflows/tox.yml@v1.2.0 + with: + env: '["py38"]' + os: windows-latest + main-linux: + uses: asottile/workflows/.github/workflows/tox.yml@v1.2.0 + with: + env: '["py38", "py39", "py310"]' + os: ubuntu-latest diff --git a/README.md b/README.md index db1259c2..0c81a789 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -[![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/pre-commit.pre-commit?branchName=main)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=main) -[![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/21/main.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=21&branchName=main) +[![build status](https://github.com/pre-commit/pre-commit/actions/workflows/main.yml/badge.svg)](https://github.com/pre-commit/pre-commit/actions/workflows/main.yml) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pre-commit/pre-commit/main.svg)](https://results.pre-commit.ci/latest/github/pre-commit/pre-commit/main) ## pre-commit diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 911ef32d..00000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,68 +0,0 @@ -trigger: - branches: - include: [main, test-me-*] - tags: - include: ['*'] - -resources: - repositories: - - repository: asottile - type: github - endpoint: github - name: asottile/azure-pipeline-templates - ref: refs/tags/v2.4.1 - -jobs: -- template: job--python-tox.yml@asottile - parameters: - toxenvs: [py38] - os: windows - additional_variables: - TEMP: C:\Temp - pre_test: - - task: UseRubyVersion@0 - - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" - displayName: Add conda to PATH - - powershell: | - Write-Host "##vso[task.prependpath]C:\Strawberry\perl\bin" - Write-Host "##vso[task.prependpath]C:\Strawberry\perl\site\bin" - Write-Host "##vso[task.prependpath]C:\Strawberry\c\bin" - displayName: Add strawberry perl to PATH - - bash: testing/get-dart.sh - displayName: install dart - - powershell: testing/get-r.ps1 - displayName: install R -- template: job--python-tox.yml@asottile - parameters: - toxenvs: [py38] - os: linux - name_postfix: _latest_git - pre_test: - - task: UseRubyVersion@0 - - template: step--git-install.yml - - bash: testing/get-coursier.sh - displayName: install coursier - - bash: testing/get-dart.sh - displayName: install dart - - bash: testing/get-lua.sh - displayName: install lua - - bash: testing/get-swift.sh - displayName: install swift - - bash: testing/get-r.sh - displayName: install R -- template: job--python-tox.yml@asottile - parameters: - toxenvs: [py38, py39, py310] - os: linux - pre_test: - - task: UseRubyVersion@0 - - bash: testing/get-coursier.sh - displayName: install coursier - - bash: testing/get-dart.sh - displayName: install dart - - bash: testing/get-lua.sh - displayName: install lua - - bash: testing/get-swift.sh - displayName: install swift - - bash: testing/get-r.sh - displayName: install R diff --git a/testing/get-coursier.sh b/testing/get-coursier.sh index 4c5e955d..6033c3e3 100755 --- a/testing/get-coursier.sh +++ b/testing/get-coursier.sh @@ -12,4 +12,4 @@ curl --location --silent --output "$ARTIFACT" "$COURSIER_URL" echo "$COURSIER_HASH $ARTIFACT" | sha256sum --check chmod ugo+x /tmp/coursier/cs -echo '##vso[task.prependpath]/tmp/coursier' +echo '/tmp/coursier' >> "$GITHUB_PATH" diff --git a/testing/get-dart.sh b/testing/get-dart.sh index b655e1a8..998b9d98 100755 --- a/testing/get-dart.sh +++ b/testing/get-dart.sh @@ -5,10 +5,10 @@ VERSION=2.13.4 if [ "$OSTYPE" = msys ]; then URL="https://storage.googleapis.com/dart-archive/channels/stable/release/${VERSION}/sdk/dartsdk-windows-x64-release.zip" - echo "##vso[task.prependpath]$(cygpath -w /tmp/dart-sdk/bin)" + cygpath -w /tmp/dart-sdk/bin >> "$GITHUB_PATH" else URL="https://storage.googleapis.com/dart-archive/channels/stable/release/${VERSION}/sdk/dartsdk-linux-x64-release.zip" - echo '##vso[task.prependpath]/tmp/dart-sdk/bin' + echo '/tmp/dart-sdk/bin' >> "$GITHUB_PATH" fi curl --silent --location --output /tmp/dart.zip "$URL" diff --git a/testing/get-lua.sh b/testing/get-lua.sh deleted file mode 100755 index 580e2477..00000000 --- a/testing/get-lua.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Install the runtime and package manager. -sudo apt install lua5.3 liblua5.3-dev luarocks diff --git a/testing/get-swift.sh b/testing/get-swift.sh index 3e780824..dfe09391 100755 --- a/testing/get-swift.sh +++ b/testing/get-swift.sh @@ -26,4 +26,4 @@ fi mkdir -p /tmp/swift tar -xf "$TGZ" --strip 1 --directory /tmp/swift -echo '##vso[task.prependpath]/tmp/swift/usr/bin' +echo '/tmp/swift/usr/bin' >> "$GITHUB_PATH" From cddaa0dddc7e1fab506795287007aff50e88b592 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 29 Dec 2022 22:56:58 -0500 Subject: [PATCH 157/416] r is installed by default on GHA --- .github/actions/pre-test/action.yml | 4 +--- testing/get-r.ps1 | 6 ------ testing/get-r.sh | 9 --------- 3 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 testing/get-r.ps1 delete mode 100755 testing/get-r.sh diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index f230df7b..a7bf0abe 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -20,7 +20,6 @@ runs: echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" testing/get-dart.sh - pwsh testing/get-r.ps1 - name: setup (linux) shell: bash if: runner.os == 'Linux' @@ -31,8 +30,7 @@ runs: sudo apt-get install -y --no-install-recommends \ lua5.3 \ liblua5.3-dev \ - luarocks \ - r-base + luarocks testing/get-coursier.sh testing/get-dart.sh diff --git a/testing/get-r.ps1 b/testing/get-r.ps1 deleted file mode 100644 index e7b7b619..00000000 --- a/testing/get-r.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -$dir = $Env:Temp -$urlR = "https://cran.r-project.org/bin/windows/base/old/4.0.4/R-4.0.4-win.exe" -$outputR = "$dir\R-win.exe" -$wcR = New-Object System.Net.WebClient -$wcR.DownloadFile($urlR, $outputR) -Start-Process -FilePath $outputR -ArgumentList "/S /v/qn" diff --git a/testing/get-r.sh b/testing/get-r.sh deleted file mode 100755 index 5d09828e..00000000 --- a/testing/get-r.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -sudo apt install r-base -# create empty folder for user library. -# necessary for non-root users who have -# never installed an R package before. -# Alternatively, we require the renv -# package to be installed already, then we can -# omit that. -Rscript -e 'dir.create(Sys.getenv("R_LIBS_USER"), recursive = TRUE)' From 0a0754e44a3b6bc3d2e56353f5143d5905d45f97 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 17:12:28 -0500 Subject: [PATCH 158/416] special rmtree is not needed for TemporaryDirectory in 3.8+ --- pre_commit/commands/autoupdate.py | 4 ++-- pre_commit/commands/try_repo.py | 4 ++-- pre_commit/util.py | 13 ------------- tests/util_test.py | 7 ------- 4 files changed, 4 insertions(+), 24 deletions(-) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index d5352e5e..6da53112 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -2,6 +2,7 @@ from __future__ import annotations import os.path import re +import tempfile from typing import Any from typing import NamedTuple from typing import Sequence @@ -19,7 +20,6 @@ from pre_commit.store import Store from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b -from pre_commit.util import tmpdir from pre_commit.util import yaml_dump from pre_commit.util import yaml_load @@ -47,7 +47,7 @@ class RevInfo(NamedTuple): 'FETCH_HEAD', '--tags', '--exact', ) - with tmpdir() as tmp: + with tempfile.TemporaryDirectory() as tmp: git.init_repo(tmp, self.repo) cmd_output_b( *git_cmd, 'fetch', 'origin', 'HEAD', '--tags', diff --git a/pre_commit/commands/try_repo.py b/pre_commit/commands/try_repo.py index ef099f5e..5244aeff 100644 --- a/pre_commit/commands/try_repo.py +++ b/pre_commit/commands/try_repo.py @@ -3,6 +3,7 @@ from __future__ import annotations import argparse import logging import os.path +import tempfile import pre_commit.constants as C from pre_commit import git @@ -11,7 +12,6 @@ from pre_commit.clientlib import load_manifest from pre_commit.commands.run import run from pre_commit.store import Store from pre_commit.util import cmd_output_b -from pre_commit.util import tmpdir from pre_commit.util import yaml_dump from pre_commit.xargs import xargs @@ -49,7 +49,7 @@ def _repo_ref(tmpdir: str, repo: str, ref: str | None) -> tuple[str, str]: def try_repo(args: argparse.Namespace) -> int: - with tmpdir() as tempdir: + with tempfile.TemporaryDirectory() as tempdir: repo, ref = _repo_ref(tempdir, args.repo, args.ref) store = Store(tempdir) diff --git a/pre_commit/util.py b/pre_commit/util.py index b8507688..bca89bb7 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -9,7 +9,6 @@ import shutil import stat import subprocess import sys -import tempfile from types import TracebackType from typing import Any from typing import Callable @@ -52,18 +51,6 @@ def clean_path_on_failure(path: str) -> Generator[None, None, None]: raise -@contextlib.contextmanager -def tmpdir() -> Generator[str, None, None]: - """Contextmanager to create a temporary directory. It will be cleaned up - afterwards. - """ - tempdir = tempfile.mkdtemp() - try: - yield tempdir - finally: - rmtree(tempdir) - - def resource_bytesio(filename: str) -> IO[bytes]: return importlib.resources.open_binary('pre_commit.resources', filename) diff --git a/tests/util_test.py b/tests/util_test.py index b3f18b4c..415982d0 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -14,7 +14,6 @@ from pre_commit.util import cmd_output_p from pre_commit.util import make_executable from pre_commit.util import parse_version from pre_commit.util import rmtree -from pre_commit.util import tmpdir def test_CalledProcessError_str(): @@ -74,12 +73,6 @@ def test_clean_path_on_failure_cleans_for_system_exit(in_tmpdir): assert not os.path.exists('foo') -def test_tmpdir(): - with tmpdir() as tempdir: - assert os.path.exists(tempdir) - assert not os.path.exists(tempdir) - - def test_cmd_output_exe_not_found(): ret, out, _ = cmd_output('dne', check=False) assert ret == 1 From 5425c754a0cdfe9f35df6d5de49c41bc9fb3413c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 17:17:00 -0500 Subject: [PATCH 159/416] move parse_version to pre_commit.clientlib --- pre_commit/clientlib.py | 6 +++++- pre_commit/repository.py | 2 +- pre_commit/util.py | 5 ----- tests/clientlib_test.py | 7 +++++++ tests/util_test.py | 7 ------- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 5b0bdbbd..e03d5d66 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -14,7 +14,6 @@ from identify.identify import ALL_TAGS import pre_commit.constants as C from pre_commit.errors import FatalError from pre_commit.languages.all import all_languages -from pre_commit.util import parse_version from pre_commit.util import yaml_load logger = logging.getLogger('pre_commit') @@ -30,6 +29,11 @@ def check_type_tag(tag: str) -> None: ) +def parse_version(s: str) -> tuple[int, ...]: + """poor man's version comparison""" + return tuple(int(p) for p in s.split('.')) + + def check_min_version(version: str) -> None: if parse_version(version) > parse_version(C.VERSION): raise cfgv.ValidationError( diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 4092277a..7670f997 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -10,12 +10,12 @@ import pre_commit.constants as C from pre_commit.clientlib import load_manifest from pre_commit.clientlib import LOCAL from pre_commit.clientlib import META +from pre_commit.clientlib import parse_version from pre_commit.hook import Hook from pre_commit.languages.all import languages from pre_commit.languages.helpers import environment_dir from pre_commit.prefix import Prefix from pre_commit.store import Store -from pre_commit.util import parse_version from pre_commit.util import rmtree diff --git a/pre_commit/util.py b/pre_commit/util.py index b8507688..0aa6cccb 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -254,10 +254,5 @@ def rmtree(path: str) -> None: shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly) -def parse_version(s: str) -> tuple[int, ...]: - """poor man's version comparison""" - return tuple(int(p) for p in s.split('.')) - - def win_exe(s: str) -> str: return s if sys.platform != 'win32' else f'{s}.exe' diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 12694e4d..efb2aa84 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -16,6 +16,7 @@ from pre_commit.clientlib import MANIFEST_SCHEMA from pre_commit.clientlib import META_HOOK_DICT from pre_commit.clientlib import OptionalSensibleRegexAtHook from pre_commit.clientlib import OptionalSensibleRegexAtTop +from pre_commit.clientlib import parse_version from testing.fixtures import sample_local_config @@ -384,6 +385,12 @@ def test_default_language_version_invalid(mapping): cfgv.validate(mapping, DEFAULT_LANGUAGE_VERSION) +def test_parse_version(): + assert parse_version('0.0') == parse_version('0.0') + assert parse_version('0.1') > parse_version('0.0') + assert parse_version('2.1') >= parse_version('2') + + def test_minimum_pre_commit_version_failing(): with pytest.raises(cfgv.ValidationError) as excinfo: cfg = {'repos': [], 'minimum_pre_commit_version': '999'} diff --git a/tests/util_test.py b/tests/util_test.py index b3f18b4c..26dafc34 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -12,7 +12,6 @@ from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b from pre_commit.util import cmd_output_p from pre_commit.util import make_executable -from pre_commit.util import parse_version from pre_commit.util import rmtree from pre_commit.util import tmpdir @@ -105,12 +104,6 @@ def test_cmd_output_no_shebang(tmpdir, fn): assert out.endswith(b'\n') -def test_parse_version(): - assert parse_version('0.0') == parse_version('0.0') - assert parse_version('0.1') > parse_version('0.0') - assert parse_version('2.1') >= parse_version('2') - - def test_rmtree_read_only_directories(tmpdir): """Simulates the go module tree. See #1042""" tmpdir.join('x/y/z').ensure_dir().join('a').ensure() From 8e57e8075dc4adcacf9b8dd49abc8c0b6e50f9e0 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 18:14:55 -0500 Subject: [PATCH 160/416] avoid using hook.src in R language this wasn't meant to be read -- hook.prefix works fine for local too --- pre_commit/languages/r.py | 18 ++++----------- tests/languages/r_test.py | 48 ++++++++++++++------------------------- 2 files changed, 22 insertions(+), 44 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index d281102b..c050d451 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -44,19 +44,11 @@ def _get_env_dir(prefix: Prefix, version: str) -> str: return prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) -def _prefix_if_non_local_file_entry( - entry: Sequence[str], - prefix: Prefix, - src: str, -) -> Sequence[str]: +def _prefix_if_file_entry(entry: list[str], prefix: Prefix) -> Sequence[str]: if entry[1] == '-e': return entry[1:] else: - if src == 'local': - path = entry[1] - else: - path = prefix.path(entry[1]) - return (path,) + return (prefix.path(entry[1]),) def _rscript_exec() -> str: @@ -67,7 +59,7 @@ def _rscript_exec() -> str: return os.path.join(r_home, 'bin', win_exe('Rscript')) -def _entry_validate(entry: Sequence[str]) -> None: +def _entry_validate(entry: list[str]) -> None: """ Allowed entries: # Rscript -e expr @@ -91,8 +83,8 @@ def _cmd_from_hook(hook: Hook) -> tuple[str, ...]: _entry_validate(entry) return ( - *entry[:1], *RSCRIPT_OPTS, - *_prefix_if_non_local_file_entry(entry, hook.prefix, hook.src), + entry[0], *RSCRIPT_OPTS, + *_prefix_if_file_entry(entry, hook.prefix), *hook.args, ) diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index c52d5acd..c653a3cc 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -16,27 +16,18 @@ def _test_r_parsing( tempdir_factory, store, hook_id, - expected_hook_expr={}, - expected_args={}, - config={}, - expect_path_prefix=True, + expected_hook_expr=(), + expected_args=(), + config=None, ): - repo_path = 'r_hooks_repo' - path = make_repo(tempdir_factory, repo_path) - config = config or make_config_from_repo(path) + repo = make_repo(tempdir_factory, 'r_hooks_repo') + config = make_config_from_repo(repo) hook = _get_hook_no_install(config, store, hook_id) ret = r._cmd_from_hook(hook) - expected_cmd = 'Rscript' - expected_opts = ( - '--no-save', '--no-restore', '--no-site-file', '--no-environ', - ) - expected_path = os.path.join( - hook.prefix.prefix_dir if expect_path_prefix else '', - f'{hook_id}.R', - ) + expected_path = os.path.join(hook.prefix.prefix_dir, f'{hook_id}.R') expected = ( - expected_cmd, - *expected_opts, + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', *(expected_hook_expr or (expected_path,)), *expected_args, ) @@ -84,9 +75,7 @@ def test_r_parsing_expr_no_opts_no_args2(tempdir_factory, store): def test_r_parsing_expr_opts_no_args2(tempdir_factory, store): with pytest.raises(ValueError) as execinfo: r._entry_validate( - [ - 'Rscript', '--vanilla', '-e', '1+1', '-e', 'letters', - ], + ['Rscript', '--vanilla', '-e', '1+1', '-e', 'letters'], ) msg = execinfo.value.args assert msg == ( @@ -112,24 +101,21 @@ def test_r_parsing_expr_non_Rscirpt(tempdir_factory, store): def test_r_parsing_file_local(tempdir_factory, store): - path = 'path/to/script.R' - hook_id = 'local-r' config = { 'repo': 'local', 'hooks': [{ - 'id': hook_id, + 'id': 'local-r', 'name': 'local-r', - 'entry': f'Rscript {path}', + 'entry': 'Rscript path/to/script.R', 'language': 'r', }], } - _test_r_parsing( - tempdir_factory, - store, - hook_id=hook_id, - expected_hook_expr=(path,), - config=config, - expect_path_prefix=False, + hook = _get_hook_no_install(config, store, 'local-r') + ret = r._cmd_from_hook(hook) + assert ret == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + hook.prefix.path('path/to/script.R'), ) From f0baffb01fe8efe200f103fccd4a5842860095cd Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 19:20:40 -0500 Subject: [PATCH 161/416] remove None overload for environment_dir --- pre_commit/languages/helpers.py | 14 ++------------ pre_commit/repository.py | 15 ++++++++------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 0be08b54..d462e86c 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -6,7 +6,6 @@ import random import re from typing import Any from typing import NoReturn -from typing import overload from typing import Sequence import pre_commit.constants as C @@ -48,17 +47,8 @@ def run_setup_cmd(prefix: Prefix, cmd: tuple[str, ...], **kwargs: Any) -> None: cmd_output_b(*cmd, cwd=prefix.prefix_dir, **kwargs) -@overload -def environment_dir(d: None, language_version: str) -> None: ... -@overload -def environment_dir(d: str, language_version: str) -> str: ... - - -def environment_dir(d: str | None, language_version: str) -> str | None: - if d is None: - return None - else: - return f'{d}-{language_version}' +def environment_dir(d: str, language_version: str) -> str: + return f'{d}-{language_version}' def assert_version_default(binary: str, version: str) -> None: diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 7670f997..50bc6455 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -50,15 +50,16 @@ def _write_state(prefix: Prefix, venv: str, state: object) -> None: def _hook_installed(hook: Hook) -> bool: lang = languages[hook.language] + if lang.ENVIRONMENT_DIR is None: + return True + venv = environment_dir(lang.ENVIRONMENT_DIR, hook.language_version) return ( - venv is None or ( - ( - _read_state(hook.prefix, venv) == - _state(hook.additional_dependencies) - ) and - not lang.health_check(hook.prefix, hook.language_version) - ) + ( + _read_state(hook.prefix, venv) == + _state(hook.additional_dependencies) + ) and + not lang.health_check(hook.prefix, hook.language_version) ) From d05b7888ab7fa4cc74f55e050f0f57442df2250d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 19:46:17 -0500 Subject: [PATCH 162/416] move clean_path_on_failure out of each hook install --- pre_commit/languages/conda.py | 16 +++--- pre_commit/languages/coursier.py | 30 +++++------ pre_commit/languages/dart.py | 56 ++++++++++--------- pre_commit/languages/docker.py | 6 +-- pre_commit/languages/dotnet.py | 88 +++++++++++++++--------------- pre_commit/languages/golang.py | 46 ++++++++-------- pre_commit/languages/lua.py | 28 +++++----- pre_commit/languages/node.py | 45 +++++++--------- pre_commit/languages/perl.py | 10 ++-- pre_commit/languages/python.py | 8 ++- pre_commit/languages/r.py | 92 ++++++++++++++++---------------- pre_commit/languages/ruby.py | 50 ++++++++--------- pre_commit/languages/rust.py | 38 +++++++------ pre_commit/languages/swift.py | 16 +++--- pre_commit/repository.py | 60 ++++++++++----------- 15 files changed, 277 insertions(+), 312 deletions(-) diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index f0195e4f..76ae0781 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -13,7 +13,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'conda' @@ -71,16 +70,15 @@ def install_environment( conda_exe = _conda_exe() env_dir = prefix.path(directory) - with clean_path_on_failure(env_dir): + cmd_output_b( + conda_exe, 'env', 'create', '-p', env_dir, '--file', + 'environment.yml', cwd=prefix.prefix_dir, + ) + if additional_dependencies: cmd_output_b( - conda_exe, 'env', 'create', '-p', env_dir, '--file', - 'environment.yml', cwd=prefix.prefix_dir, + conda_exe, 'install', '-p', env_dir, *additional_dependencies, + cwd=prefix.prefix_dir, ) - if additional_dependencies: - cmd_output_b( - conda_exe, 'install', '-p', env_dir, *additional_dependencies, - cwd=prefix.prefix_dir, - ) def run_hook( diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 9fe43ebd..0d520f0f 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -12,7 +12,6 @@ from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure ENVIRONMENT_DIR = 'coursier' @@ -38,21 +37,20 @@ def install_environment( envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) channel = prefix.path('.pre-commit-channel') - with clean_path_on_failure(envdir): - for app_descriptor in os.listdir(channel): - _, app_file = os.path.split(app_descriptor) - app, _ = os.path.splitext(app_file) - helpers.run_setup_cmd( - prefix, - ( - executable, - 'install', - '--default-channels=false', - f'--channel={channel}', - app, - f'--dir={envdir}', - ), - ) + for app_descriptor in os.listdir(channel): + _, app_file = os.path.split(app_descriptor) + app, _ = os.path.splitext(app_file) + helpers.run_setup_cmd( + prefix, + ( + executable, + 'install', + '--default-channels=false', + f'--channel={channel}', + app, + f'--dir={envdir}', + ), + ) def get_env_patch(target_dir: str) -> PatchesT: # pragma: win32 no cover diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 55ecbf4f..73fffdb8 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -14,7 +14,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import win_exe from pre_commit.util import yaml_load @@ -67,39 +66,38 @@ def install_environment( env=dart_env, ) - with clean_path_on_failure(envdir): - os.makedirs(bin_dir) + os.makedirs(bin_dir) - with tempfile.TemporaryDirectory() as tmp: - _install_dir(prefix, tmp) + with tempfile.TemporaryDirectory() as tmp: + _install_dir(prefix, tmp) - for dep_s in additional_dependencies: - with tempfile.TemporaryDirectory() as dep_tmp: - dep, _, version = dep_s.partition(':') - if version: - dep_cmd: tuple[str, ...] = (dep, '--version', version) - else: - dep_cmd = (dep,) + for dep_s in additional_dependencies: + with tempfile.TemporaryDirectory() as dep_tmp: + dep, _, version = dep_s.partition(':') + if version: + dep_cmd: tuple[str, ...] = (dep, '--version', version) + else: + dep_cmd = (dep,) - helpers.run_setup_cmd( - prefix, - ('dart', 'pub', 'cache', 'add', *dep_cmd), - env={**os.environ, 'PUB_CACHE': dep_tmp}, + helpers.run_setup_cmd( + prefix, + ('dart', 'pub', 'cache', 'add', *dep_cmd), + env={**os.environ, 'PUB_CACHE': dep_tmp}, + ) + + # try and find the 'pubspec.yaml' that just got added + for root, _, filenames in os.walk(dep_tmp): + if 'pubspec.yaml' in filenames: + with tempfile.TemporaryDirectory() as copied: + pkg = os.path.join(copied, 'pkg') + shutil.copytree(root, pkg) + _install_dir(Prefix(pkg), dep_tmp) + break + else: + raise AssertionError( + f'could not find pubspec.yaml for {dep_s}', ) - # try and find the 'pubspec.yaml' that just got added - for root, _, filenames in os.walk(dep_tmp): - if 'pubspec.yaml' in filenames: - with tempfile.TemporaryDirectory() as copied: - pkg = os.path.join(copied, 'pkg') - shutil.copytree(root, pkg) - _install_dir(Prefix(pkg), dep_tmp) - break - else: - raise AssertionError( - f'could not find pubspec.yaml for {dep_s}', - ) - def run_hook( hook: Hook, diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index eea9f768..5d614674 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -10,7 +10,6 @@ from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'docker' @@ -101,9 +100,8 @@ def install_environment( # Docker doesn't really have relevant disk environment, but pre-commit # still needs to cleanup its state files on failure - with clean_path_on_failure(directory): - build_docker_image(prefix, pull=True) - os.mkdir(directory) + build_docker_image(prefix, pull=True) + os.mkdir(directory) def get_docker_user() -> tuple[str, ...]: # pragma: win32 no cover diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index e26b45c3..d748c813 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -16,7 +16,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure ENVIRONMENT_DIR = 'dotnetenv' BIN_DIR = 'bin' @@ -64,59 +63,58 @@ def install_environment( helpers.assert_no_additional_deps('dotnet', additional_dependencies) envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) - with clean_path_on_failure(envdir): - build_dir = 'pre-commit-build' + build_dir = 'pre-commit-build' - # Build & pack nupkg file - helpers.run_setup_cmd( - prefix, - ( - 'dotnet', 'pack', - '--configuration', 'Release', - '--output', build_dir, - ), - ) + # Build & pack nupkg file + helpers.run_setup_cmd( + prefix, + ( + 'dotnet', 'pack', + '--configuration', 'Release', + '--output', build_dir, + ), + ) - nupkg_dir = prefix.path(build_dir) - nupkgs = [x for x in os.listdir(nupkg_dir) if x.endswith('.nupkg')] + nupkg_dir = prefix.path(build_dir) + nupkgs = [x for x in os.listdir(nupkg_dir) if x.endswith('.nupkg')] - if not nupkgs: - raise AssertionError('could not find any build outputs to install') + if not nupkgs: + raise AssertionError('could not find any build outputs to install') - for nupkg in nupkgs: - with zipfile.ZipFile(os.path.join(nupkg_dir, nupkg)) as f: - nuspec, = (x for x in f.namelist() if x.endswith('.nuspec')) - with f.open(nuspec) as spec: - tree = xml.etree.ElementTree.parse(spec) + for nupkg in nupkgs: + with zipfile.ZipFile(os.path.join(nupkg_dir, nupkg)) as f: + nuspec, = (x for x in f.namelist() if x.endswith('.nuspec')) + with f.open(nuspec) as spec: + tree = xml.etree.ElementTree.parse(spec) - namespace = re.match(r'{.*}', tree.getroot().tag) - if not namespace: - raise AssertionError('could not parse namespace from nuspec') + namespace = re.match(r'{.*}', tree.getroot().tag) + if not namespace: + raise AssertionError('could not parse namespace from nuspec') - tool_id_element = tree.find(f'.//{namespace[0]}id') - if tool_id_element is None: - raise AssertionError('expected to find an "id" element') + tool_id_element = tree.find(f'.//{namespace[0]}id') + if tool_id_element is None: + raise AssertionError('expected to find an "id" element') - tool_id = tool_id_element.text - if not tool_id: - raise AssertionError('"id" element missing tool name') + tool_id = tool_id_element.text + if not tool_id: + raise AssertionError('"id" element missing tool name') - # Install to bin dir - with _nuget_config_no_sources() as nuget_config: - helpers.run_setup_cmd( - prefix, - ( - 'dotnet', 'tool', 'install', - '--configfile', nuget_config, - '--tool-path', os.path.join(envdir, BIN_DIR), - '--add-source', build_dir, - tool_id, - ), - ) + # Install to bin dir + with _nuget_config_no_sources() as nuget_config: + helpers.run_setup_cmd( + prefix, + ( + 'dotnet', 'tool', 'install', + '--configfile', nuget_config, + '--tool-path', os.path.join(envdir, BIN_DIR), + '--add-source', build_dir, + tool_id, + ), + ) - # Clean the git dir, ignoring the environment dir - clean_cmd = ('git', 'clean', '-ffxd', '-e', f'{ENVIRONMENT_DIR}-*') - helpers.run_setup_cmd(prefix, clean_cmd) + # Clean the git dir, ignoring the environment dir + clean_cmd = ('git', 'clean', '-ffxd', '-e', f'{ENVIRONMENT_DIR}-*') + helpers.run_setup_cmd(prefix, clean_cmd) def run_hook( diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index a5f9dba0..36792393 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -14,7 +14,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b from pre_commit.util import rmtree @@ -65,31 +64,30 @@ def install_environment( helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), ) - with clean_path_on_failure(directory): - remote = git.get_remote_url(prefix.prefix_dir) - repo_src_dir = os.path.join(directory, 'src', guess_go_dir(remote)) + remote = git.get_remote_url(prefix.prefix_dir) + repo_src_dir = os.path.join(directory, 'src', guess_go_dir(remote)) - # Clone into the goenv we'll create - cmd = ('git', 'clone', '--recursive', '.', repo_src_dir) - helpers.run_setup_cmd(prefix, cmd) + # Clone into the goenv we'll create + cmd = ('git', 'clone', '--recursive', '.', repo_src_dir) + helpers.run_setup_cmd(prefix, cmd) - if sys.platform == 'cygwin': # pragma: no cover - _, gopath, _ = cmd_output('cygpath', '-w', directory) - gopath = gopath.strip() - else: - gopath = directory - env = dict(os.environ, GOPATH=gopath) - env.pop('GOBIN', None) - cmd_output_b('go', 'install', './...', cwd=repo_src_dir, env=env) - for dependency in additional_dependencies: - cmd_output_b( - 'go', 'install', dependency, cwd=repo_src_dir, env=env, - ) - # Same some disk space, we don't need these after installation - rmtree(prefix.path(directory, 'src')) - pkgdir = prefix.path(directory, 'pkg') - if os.path.exists(pkgdir): # pragma: no cover (go<1.10) - rmtree(pkgdir) + if sys.platform == 'cygwin': # pragma: no cover + _, gopath, _ = cmd_output('cygpath', '-w', directory) + gopath = gopath.strip() + else: + gopath = directory + env = dict(os.environ, GOPATH=gopath) + env.pop('GOBIN', None) + cmd_output_b('go', 'install', './...', cwd=repo_src_dir, env=env) + for dependency in additional_dependencies: + cmd_output_b( + 'go', 'install', dependency, cwd=repo_src_dir, env=env, + ) + # Same some disk space, we don't need these after installation + rmtree(prefix.path(directory, 'src')) + pkgdir = prefix.path(directory, 'pkg') + if os.path.exists(pkgdir): # pragma: no cover (go<1.10) + rmtree(pkgdir) def run_hook( diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index 49aa7308..cd38a297 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -13,7 +13,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output ENVIRONMENT_DIR = 'lua_env' @@ -64,22 +63,21 @@ def install_environment( helpers.assert_version_default('lua', version) envdir = _envdir(prefix) - with clean_path_on_failure(envdir): - with in_env(prefix): - # luarocks doesn't bootstrap a tree prior to installing - # so ensure the directory exists. - os.makedirs(envdir, exist_ok=True) + with in_env(prefix): + # luarocks doesn't bootstrap a tree prior to installing + # so ensure the directory exists. + os.makedirs(envdir, exist_ok=True) - # Older luarocks (e.g., 2.4.2) expect the rockspec as an arg - for rockspec in prefix.star('.rockspec'): - make_cmd = ('luarocks', '--tree', envdir, 'make', rockspec) - helpers.run_setup_cmd(prefix, make_cmd) + # Older luarocks (e.g., 2.4.2) expect the rockspec as an arg + for rockspec in prefix.star('.rockspec'): + make_cmd = ('luarocks', '--tree', envdir, 'make', rockspec) + helpers.run_setup_cmd(prefix, make_cmd) - # luarocks can't install multiple packages at once - # so install them individually. - for dependency in additional_dependencies: - cmd = ('luarocks', '--tree', envdir, 'install', dependency) - helpers.run_setup_cmd(prefix, cmd) + # luarocks can't install multiple packages at once + # so install them individually. + for dependency in additional_dependencies: + cmd = ('luarocks', '--tree', envdir, 'install', dependency) + helpers.run_setup_cmd(prefix, cmd) def run_hook( diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 37a5b63f..353fa152 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -16,7 +16,6 @@ from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.languages.python import bin_dir from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b from pre_commit.util import rmtree @@ -85,41 +84,37 @@ def health_check(prefix: Prefix, language_version: str) -> str | None: def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: - additional_dependencies = tuple(additional_dependencies) assert prefix.exists('package.json') envdir = _envdir(prefix, version) # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath if sys.platform == 'win32': # pragma: no cover envdir = fr'\\?\{os.path.normpath(envdir)}' - with clean_path_on_failure(envdir): - cmd = [ - sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir, - ] - if version != C.DEFAULT: - cmd.extend(['-n', version]) - cmd_output_b(*cmd) + cmd = [sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir] + if version != C.DEFAULT: + cmd.extend(['-n', version]) + cmd_output_b(*cmd) - with in_env(prefix, version): - # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449 - # install as if we installed from git + with in_env(prefix, version): + # https://npm.community/t/npm-install-g-git-vs-git-clone-cd-npm-install-g/5449 + # install as if we installed from git - local_install_cmd = ( - 'npm', 'install', '--dev', '--prod', - '--ignore-prepublish', '--no-progress', '--no-save', - ) - helpers.run_setup_cmd(prefix, local_install_cmd) + local_install_cmd = ( + 'npm', 'install', '--dev', '--prod', + '--ignore-prepublish', '--no-progress', '--no-save', + ) + helpers.run_setup_cmd(prefix, local_install_cmd) - _, pkg, _ = cmd_output('npm', 'pack', cwd=prefix.prefix_dir) - pkg = prefix.path(pkg.strip()) + _, pkg, _ = cmd_output('npm', 'pack', cwd=prefix.prefix_dir) + pkg = prefix.path(pkg.strip()) - install = ('npm', 'install', '-g', pkg, *additional_dependencies) - helpers.run_setup_cmd(prefix, install) + install = ('npm', 'install', '-g', pkg, *additional_dependencies) + helpers.run_setup_cmd(prefix, install) - # clean these up after installation - if prefix.exists('node_modules'): # pragma: win32 no cover - rmtree(prefix.path('node_modules')) - os.remove(pkg) + # clean these up after installation + if prefix.exists('node_modules'): # pragma: win32 no cover + rmtree(prefix.path('node_modules')) + os.remove(pkg) def run_hook( diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 78bd65a2..25c01676 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -12,7 +12,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure ENVIRONMENT_DIR = 'perl_env' get_default_version = helpers.basic_get_default_version @@ -52,11 +51,10 @@ def install_environment( ) -> None: helpers.assert_version_default('perl', version) - with clean_path_on_failure(_envdir(prefix, version)): - with in_env(prefix, version): - helpers.run_setup_cmd( - prefix, ('cpan', '-T', '.', *additional_dependencies), - ) + with in_env(prefix, version): + helpers.run_setup_cmd( + prefix, ('cpan', '-T', '.', *additional_dependencies), + ) def run_hook( diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 19fa247e..6770499d 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -17,7 +17,6 @@ from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b from pre_commit.util import win_exe @@ -215,10 +214,9 @@ def install_environment( venv_cmd.extend(('-p', python)) install_cmd = ('python', '-mpip', 'install', '.', *additional_dependencies) - with clean_path_on_failure(envdir): - cmd_output_b(*venv_cmd, cwd='/') - with in_env(prefix, version): - helpers.run_setup_cmd(prefix, install_cmd) + cmd_output_b(*venv_cmd, cwd='/') + with in_env(prefix, version): + helpers.run_setup_cmd(prefix, install_cmd) def run_hook( diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index c050d451..9bbfdbe2 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -13,7 +13,6 @@ from pre_commit.envcontext import UNSET from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b from pre_commit.util import win_exe @@ -95,54 +94,53 @@ def install_environment( additional_dependencies: Sequence[str], ) -> None: env_dir = _get_env_dir(prefix, version) - with clean_path_on_failure(env_dir): - os.makedirs(env_dir, exist_ok=True) - shutil.copy(prefix.path('renv.lock'), env_dir) - shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) + os.makedirs(env_dir, exist_ok=True) + shutil.copy(prefix.path('renv.lock'), env_dir) + shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) - r_code_inst_environment = f"""\ - prefix_dir <- {prefix.prefix_dir!r} - options( - repos = c(CRAN = "https://cran.rstudio.com"), - renv.consent = TRUE - ) - source("renv/activate.R") - renv::restore() - activate_statement <- paste0( - 'suppressWarnings({{', - 'old <- setwd("', getwd(), '"); ', - 'source("renv/activate.R"); ', - 'setwd(old); ', - 'renv::load("', getwd(), '");}})' - ) - writeLines(activate_statement, 'activate.R') - is_package <- tryCatch( - {{ - path_desc <- file.path(prefix_dir, 'DESCRIPTION') - suppressWarnings(desc <- read.dcf(path_desc)) - "Package" %in% colnames(desc) - }}, - error = function(...) FALSE - ) - if (is_package) {{ - renv::install(prefix_dir) - }} - """ - - cmd_output_b( - _rscript_exec(), '--vanilla', '-e', - _inline_r_setup(r_code_inst_environment), - cwd=env_dir, + r_code_inst_environment = f"""\ + prefix_dir <- {prefix.prefix_dir!r} + options( + repos = c(CRAN = "https://cran.rstudio.com"), + renv.consent = TRUE ) - if additional_dependencies: - r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' - with in_env(prefix, version): - cmd_output_b( - _rscript_exec(), *RSCRIPT_OPTS, '-e', - _inline_r_setup(r_code_inst_add), - *additional_dependencies, - cwd=env_dir, - ) + source("renv/activate.R") + renv::restore() + activate_statement <- paste0( + 'suppressWarnings({{', + 'old <- setwd("', getwd(), '"); ', + 'source("renv/activate.R"); ', + 'setwd(old); ', + 'renv::load("', getwd(), '");}})' + ) + writeLines(activate_statement, 'activate.R') + is_package <- tryCatch( + {{ + path_desc <- file.path(prefix_dir, 'DESCRIPTION') + suppressWarnings(desc <- read.dcf(path_desc)) + "Package" %in% colnames(desc) + }}, + error = function(...) FALSE + ) + if (is_package) {{ + renv::install(prefix_dir) + }} + """ + + cmd_output_b( + _rscript_exec(), '--vanilla', '-e', + _inline_r_setup(r_code_inst_environment), + cwd=env_dir, + ) + if additional_dependencies: + r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' + with in_env(prefix, version): + cmd_output_b( + _rscript_exec(), *RSCRIPT_OPTS, '-e', + _inline_r_setup(r_code_inst_add), + *additional_dependencies, + cwd=env_dir, + ) def _inline_r_setup(code: str) -> str: diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 8955dd01..379427b0 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -17,7 +17,6 @@ from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError -from pre_commit.util import clean_path_on_failure from pre_commit.util import resource_bytesio ENVIRONMENT_DIR = 'rbenv' @@ -115,33 +114,30 @@ def _install_ruby( def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: - additional_dependencies = tuple(additional_dependencies) - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) - with clean_path_on_failure(prefix.path(directory)): - if version != 'system': # pragma: win32 no cover - _install_rbenv(prefix, version) - with in_env(prefix, version): - # Need to call this before installing so rbenv's directories - # are set up - helpers.run_setup_cmd(prefix, ('rbenv', 'init', '-')) - if version != C.DEFAULT: - _install_ruby(prefix, version) - # Need to call this after installing to set up the shims - helpers.run_setup_cmd(prefix, ('rbenv', 'rehash')) - + if version != 'system': # pragma: win32 no cover + _install_rbenv(prefix, version) with in_env(prefix, version): - helpers.run_setup_cmd( - prefix, ('gem', 'build', *prefix.star('.gemspec')), - ) - helpers.run_setup_cmd( - prefix, - ( - 'gem', 'install', - '--no-document', '--no-format-executable', - '--no-user-install', - *prefix.star('.gem'), *additional_dependencies, - ), - ) + # Need to call this before installing so rbenv's directories + # are set up + helpers.run_setup_cmd(prefix, ('rbenv', 'init', '-')) + if version != C.DEFAULT: + _install_ruby(prefix, version) + # Need to call this after installing to set up the shims + helpers.run_setup_cmd(prefix, ('rbenv', 'rehash')) + + with in_env(prefix, version): + helpers.run_setup_cmd( + prefix, ('gem', 'build', *prefix.star('.gemspec')), + ) + helpers.run_setup_cmd( + prefix, + ( + 'gem', 'install', + '--no-document', '--no-format-executable', + '--no-user-install', + *prefix.star('.gem'), *additional_dependencies, + ), + ) def run_hook( diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 204f2aa7..67e7ae85 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -18,7 +18,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b from pre_commit.util import make_executable from pre_commit.util import win_exe @@ -143,28 +142,27 @@ def install_environment( } lib_deps = set(additional_dependencies) - cli_deps - with clean_path_on_failure(directory): - packages_to_install: set[tuple[str, ...]] = {('--path', '.')} - for cli_dep in cli_deps: - cli_dep = cli_dep[len('cli:'):] - package, _, crate_version = cli_dep.partition(':') - if crate_version != '': - packages_to_install.add((package, '--version', crate_version)) - else: - packages_to_install.add((package,)) + packages_to_install: set[tuple[str, ...]] = {('--path', '.')} + for cli_dep in cli_deps: + cli_dep = cli_dep[len('cli:'):] + package, _, crate_version = cli_dep.partition(':') + if crate_version != '': + packages_to_install.add((package, '--version', crate_version)) + else: + packages_to_install.add((package,)) - with in_env(prefix, version): - if version != 'system': - install_rust_with_toolchain(_rust_toolchain(version)) + with in_env(prefix, version): + if version != 'system': + install_rust_with_toolchain(_rust_toolchain(version)) - if len(lib_deps) > 0: - _add_dependencies(prefix, lib_deps) + if len(lib_deps) > 0: + _add_dependencies(prefix, lib_deps) - for args in packages_to_install: - cmd_output_b( - 'cargo', 'install', '--bins', '--root', directory, *args, - cwd=prefix.prefix_dir, - ) + for args in packages_to_install: + cmd_output_b( + 'cargo', 'install', '--bins', '--root', directory, *args, + cwd=prefix.prefix_dir, + ) def run_hook( diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index 4c687030..0fab596c 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -12,7 +12,6 @@ from pre_commit.envcontext import Var from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix -from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'swift_env' @@ -46,14 +45,13 @@ def install_environment( ) # Build the swift package - with clean_path_on_failure(directory): - os.mkdir(directory) - cmd_output_b( - 'swift', 'build', - '-C', prefix.prefix_dir, - '-c', BUILD_CONFIG, - '--build-path', os.path.join(directory, BUILD_DIR), - ) + os.mkdir(directory) + cmd_output_b( + 'swift', 'build', + '-C', prefix.prefix_dir, + '-c', BUILD_CONFIG, + '--build-path', os.path.join(directory, BUILD_DIR), + ) def run_hook( diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 50bc6455..fa5322dc 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -16,6 +16,7 @@ from pre_commit.languages.all import languages from pre_commit.languages.helpers import environment_dir from pre_commit.prefix import Prefix from pre_commit.store import Store +from pre_commit.util import clean_path_on_failure from pre_commit.util import rmtree @@ -26,12 +27,12 @@ def _state(additional_deps: Sequence[str]) -> object: return {'additional_dependencies': sorted(additional_deps)} -def _state_filename(prefix: Prefix, venv: str) -> str: - return prefix.path(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}') +def _state_filename(venv: str) -> str: + return os.path.join(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}') -def _read_state(prefix: Prefix, venv: str) -> object | None: - filename = _state_filename(prefix, venv) +def _read_state(venv: str) -> object | None: + filename = _state_filename(venv) if not os.path.exists(filename): return None else: @@ -39,26 +40,15 @@ def _read_state(prefix: Prefix, venv: str) -> object | None: return json.load(f) -def _write_state(prefix: Prefix, venv: str, state: object) -> None: - state_filename = _state_filename(prefix, venv) - staging = f'{state_filename}staging' - with open(staging, 'w') as state_file: - state_file.write(json.dumps(state)) - # Move the file into place atomically to indicate we've installed - os.replace(staging, state_filename) - - def _hook_installed(hook: Hook) -> bool: lang = languages[hook.language] if lang.ENVIRONMENT_DIR is None: return True venv = environment_dir(lang.ENVIRONMENT_DIR, hook.language_version) + venv = hook.prefix.path(venv) return ( - ( - _read_state(hook.prefix, venv) == - _state(hook.additional_dependencies) - ) and + _read_state(venv) == _state(hook.additional_dependencies) and not lang.health_check(hook.prefix, hook.language_version) ) @@ -70,26 +60,34 @@ def _hook_install(hook: Hook) -> None: lang = languages[hook.language] assert lang.ENVIRONMENT_DIR is not None + venv = environment_dir(lang.ENVIRONMENT_DIR, hook.language_version) + venv = hook.prefix.path(venv) # There's potentially incomplete cleanup from previous runs # Clean it up! - if hook.prefix.exists(venv): - rmtree(hook.prefix.path(venv)) + if os.path.exists(venv): + rmtree(venv) - lang.install_environment( - hook.prefix, hook.language_version, hook.additional_dependencies, - ) - health_error = lang.health_check(hook.prefix, hook.language_version) - if health_error: - raise AssertionError( - f'BUG: expected environment for {hook.language} to be healthy ' - f'immediately after install, please open an issue describing ' - f'your environment\n\n' - f'more info:\n\n{health_error}', + with clean_path_on_failure(venv): + lang.install_environment( + hook.prefix, hook.language_version, hook.additional_dependencies, ) - # Write our state to indicate we're installed - _write_state(hook.prefix, venv, _state(hook.additional_dependencies)) + health_error = lang.health_check(hook.prefix, hook.language_version) + if health_error: + raise AssertionError( + f'BUG: expected environment for {hook.language} to be healthy ' + f'immediately after install, please open an issue describing ' + f'your environment\n\n' + f'more info:\n\n{health_error}', + ) + # Write our state to indicate we're installed + state_filename = _state_filename(venv) + staging = f'{state_filename}staging' + with open(staging, 'w') as state_file: + state_file.write(json.dumps(_state(hook.additional_dependencies))) + # Move the file into place atomically to indicate we've installed + os.replace(staging, state_filename) def _hook( From 05c8911363a84ec062c2ccfde6d1279f0b5634b3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 21:11:56 -0500 Subject: [PATCH 163/416] simplify environment_dir --- pre_commit/languages/conda.py | 6 ++--- pre_commit/languages/coursier.py | 11 ++++---- pre_commit/languages/dart.py | 5 ++-- pre_commit/languages/docker.py | 4 +-- pre_commit/languages/dotnet.py | 5 ++-- pre_commit/languages/golang.py | 8 ++---- pre_commit/languages/helpers.py | 4 +-- pre_commit/languages/lua.py | 10 +++----- pre_commit/languages/node.py | 10 +++----- pre_commit/languages/perl.py | 8 ++---- pre_commit/languages/python.py | 8 +++--- pre_commit/languages/r.py | 8 ++---- pre_commit/languages/ruby.py | 10 +++----- pre_commit/languages/rust.py | 14 +++-------- pre_commit/languages/swift.py | 12 +++------ pre_commit/repository.py | 14 ++++++++--- tests/repository_test.py | 43 +++++++++++++++++++------------- 17 files changed, 77 insertions(+), 103 deletions(-) diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 76ae0781..5a0a720f 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -44,8 +44,7 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - directory = helpers.environment_dir(ENVIRONMENT_DIR, language_version) - envdir = prefix.path(directory) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) with envcontext(get_env_patch(envdir)): yield @@ -65,11 +64,10 @@ def install_environment( additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default('conda', version) - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) conda_exe = _conda_exe() - env_dir = prefix.path(directory) + env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) cmd_output_b( conda_exe, 'env', 'create', '-p', env_dir, '--file', 'environment.yml', cwd=prefix.prefix_dir, diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 0d520f0f..fdea3cd7 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -35,7 +35,7 @@ def install_environment( 'executables in the application search path', ) - envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) channel = prefix.path('.pre-commit-channel') for app_descriptor in os.listdir(channel): _, app_file = os.path.split(app_descriptor) @@ -62,11 +62,10 @@ def get_env_patch(target_dir: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager def in_env( prefix: Prefix, + language_version: str, ) -> Generator[None, None, None]: # pragma: win32 no cover - target_dir = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, get_default_version()), - ) - with envcontext(get_env_patch(target_dir)): + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) + with envcontext(get_env_patch(envdir)): yield @@ -75,5 +74,5 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover - with in_env(hook.prefix): + with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 73fffdb8..9fbb63cc 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -31,8 +31,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix) -> Generator[None, None, None]: - directory = helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT) - envdir = prefix.path(directory) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) with envcontext(get_env_patch(envdir)): yield @@ -44,7 +43,7 @@ def install_environment( ) -> None: helpers.assert_version_default('dart', version) - envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) bin_dir = os.path.join(envdir, 'bin') def _install_dir(prefix_p: Prefix, pub_cache: str) -> None: diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 5d614674..c51cf7c1 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -94,9 +94,7 @@ def install_environment( helpers.assert_version_default('docker', version) helpers.assert_no_additional_deps('docker', additional_dependencies) - directory = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) + directory = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) # Docker doesn't really have relevant disk environment, but pre-commit # still needs to cleanup its state files on failure diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index d748c813..0bb0210c 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -32,8 +32,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix) -> Generator[None, None, None]: - directory = helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT) - envdir = prefix.path(directory) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) with envcontext(get_env_patch(envdir)): yield @@ -62,7 +61,7 @@ def install_environment( helpers.assert_version_default('dotnet', version) helpers.assert_no_additional_deps('dotnet', additional_dependencies) - envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) build_dir = 'pre-commit-build' # Build & pack nupkg file diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 36792393..70f0e65d 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -31,9 +31,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) with envcontext(get_env_patch(envdir)): yield @@ -60,9 +58,7 @@ def install_environment( additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default('golang', version) - directory = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) + directory = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) remote = git.get_remote_url(prefix.prefix_dir) repo_src_dir = os.path.join(directory, 'src', guess_go_dir(remote)) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index d462e86c..098e95c5 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -47,8 +47,8 @@ def run_setup_cmd(prefix: Prefix, cmd: tuple[str, ...], **kwargs: Any) -> None: cmd_output_b(*cmd, cwd=prefix.prefix_dir, **kwargs) -def environment_dir(d: str, language_version: str) -> str: - return f'{d}-{language_version}' +def environment_dir(prefix: Prefix, d: str, language_version: str) -> str: + return prefix.path(f'{d}-{language_version}') def assert_version_default(binary: str, version: str) -> None: diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index cd38a297..26c8f1b7 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -44,14 +44,10 @@ def get_env_patch(d: str) -> PatchesT: # pragma: win32 no cover ) -def _envdir(prefix: Prefix) -> str: # pragma: win32 no cover - directory = helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT) - return prefix.path(directory) - - @contextlib.contextmanager # pragma: win32 no cover def in_env(prefix: Prefix) -> Generator[None, None, None]: - with envcontext(get_env_patch(_envdir(prefix))): + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) + with envcontext(get_env_patch(envdir)): yield @@ -62,7 +58,7 @@ def install_environment( ) -> None: # pragma: win32 no cover helpers.assert_version_default('lua', version) - envdir = _envdir(prefix) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) with in_env(prefix): # luarocks doesn't bootstrap a tree prior to installing # so ensure the directory exists. diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 353fa152..8facfe00 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -36,11 +36,6 @@ def get_default_version() -> str: return C.DEFAULT -def _envdir(prefix: Prefix, version: str) -> str: - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) - return prefix.path(directory) - - def get_env_patch(venv: str) -> PatchesT: if sys.platform == 'cygwin': # pragma: no cover _, win_venv, _ = cmd_output('cygpath', '-w', venv) @@ -68,7 +63,8 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - with envcontext(get_env_patch(_envdir(prefix, language_version))): + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) + with envcontext(get_env_patch(envdir)): yield @@ -85,7 +81,7 @@ def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: assert prefix.exists('package.json') - envdir = _envdir(prefix, version) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath if sys.platform == 'win32': # pragma: no cover diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 25c01676..95be6559 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -18,11 +18,6 @@ get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check -def _envdir(prefix: Prefix, version: str) -> str: - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) - return prefix.path(directory) - - def get_env_patch(venv: str) -> PatchesT: return ( ('PATH', (os.path.join(venv, 'bin'), os.pathsep, Var('PATH'))), @@ -42,7 +37,8 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - with envcontext(get_env_patch(_envdir(prefix, language_version))): + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) + with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 6770499d..a7744d64 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -156,15 +156,13 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - directory = helpers.environment_dir(ENVIRONMENT_DIR, language_version) - envdir = prefix.path(directory) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) with envcontext(get_env_patch(envdir)): yield def health_check(prefix: Prefix, language_version: str) -> str | None: - directory = helpers.environment_dir(ENVIRONMENT_DIR, language_version) - envdir = prefix.path(directory) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) pyvenv_cfg = os.path.join(envdir, 'pyvenv.cfg') # created with "old" virtualenv @@ -207,7 +205,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - envdir = prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) venv_cmd = [sys.executable, '-mvirtualenv', envdir] python = norm_version(version) if python is not None: diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 9bbfdbe2..d2ec83da 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -34,15 +34,11 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - envdir = _get_env_dir(prefix, language_version) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) with envcontext(get_env_patch(envdir)): yield -def _get_env_dir(prefix: Prefix, version: str) -> str: - return prefix.path(helpers.environment_dir(ENVIRONMENT_DIR, version)) - - def _prefix_if_file_entry(entry: list[str], prefix: Prefix) -> Sequence[str]: if entry[1] == '-e': return entry[1:] @@ -93,7 +89,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - env_dir = _get_env_dir(prefix, version) + env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 379427b0..89af2545 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -71,9 +71,7 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - envdir = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, language_version), - ) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) with envcontext(get_env_patch(envdir, language_version)): yield @@ -88,14 +86,14 @@ def _install_rbenv( prefix: Prefix, version: str, ) -> None: # pragma: win32 no cover - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) _extract_resource('rbenv.tar.gz', prefix.path('.')) - shutil.move(prefix.path('rbenv'), prefix.path(directory)) + shutil.move(prefix.path('rbenv'), envdir) # Only install ruby-build if the version is specified if version != C.DEFAULT: - plugins_dir = prefix.path(directory, 'plugins') + plugins_dir = os.path.join(envdir, 'plugins') _extract_resource('ruby-download.tar.gz', plugins_dir) _extract_resource('ruby-build.tar.gz', plugins_dir) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 67e7ae85..0f6cd332 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -48,11 +48,6 @@ def _rust_toolchain(language_version: str) -> str: return language_version -def _envdir(prefix: Prefix, version: str) -> str: - directory = helpers.environment_dir(ENVIRONMENT_DIR, version) - return prefix.path(directory) - - def get_env_patch(target_dir: str, version: str) -> PatchesT: return ( ('CARGO_HOME', target_dir), @@ -71,9 +66,8 @@ def in_env( prefix: Prefix, language_version: str, ) -> Generator[None, None, None]: - with envcontext( - get_env_patch(_envdir(prefix, language_version), language_version), - ): + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) + with envcontext(get_env_patch(envdir, language_version)): yield @@ -125,7 +119,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - directory = _envdir(prefix, version) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) # There are two cases where we might want to specify more dependencies: # as dependencies for the library being built, and as binary packages @@ -160,7 +154,7 @@ def install_environment( for args in packages_to_install: cmd_output_b( - 'cargo', 'install', '--bins', '--root', directory, *args, + 'cargo', 'install', '--bins', '--root', envdir, *args, cwd=prefix.prefix_dir, ) diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index 0fab596c..7cc61d95 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -28,9 +28,7 @@ def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) with envcontext(get_env_patch(envdir)): yield @@ -40,17 +38,15 @@ def install_environment( ) -> None: # pragma: win32 no cover helpers.assert_version_default('swift', version) helpers.assert_no_additional_deps('swift', additional_dependencies) - directory = prefix.path( - helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT), - ) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) # Build the swift package - os.mkdir(directory) + os.mkdir(envdir) cmd_output_b( 'swift', 'build', '-C', prefix.prefix_dir, '-c', BUILD_CONFIG, - '--build-path', os.path.join(directory, BUILD_DIR), + '--build-path', os.path.join(envdir, BUILD_DIR), ) diff --git a/pre_commit/repository.py b/pre_commit/repository.py index fa5322dc..ac6b8446 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -45,8 +45,11 @@ def _hook_installed(hook: Hook) -> bool: if lang.ENVIRONMENT_DIR is None: return True - venv = environment_dir(lang.ENVIRONMENT_DIR, hook.language_version) - venv = hook.prefix.path(venv) + venv = environment_dir( + hook.prefix, + lang.ENVIRONMENT_DIR, + hook.language_version, + ) return ( _read_state(venv) == _state(hook.additional_dependencies) and not lang.health_check(hook.prefix, hook.language_version) @@ -61,8 +64,11 @@ def _hook_install(hook: Hook) -> None: lang = languages[hook.language] assert lang.ENVIRONMENT_DIR is not None - venv = environment_dir(lang.ENVIRONMENT_DIR, hook.language_version) - venv = hook.prefix.path(venv) + venv = environment_dir( + hook.prefix, + lang.ENVIRONMENT_DIR, + hook.language_version, + ) # There's potentially incomplete cleanup from previous runs # Clean it up! diff --git a/tests/repository_test.py b/tests/repository_test.py index 6aa0f007..fa8bf431 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -463,11 +463,12 @@ def test_additional_rust_cli_dependencies_installed( # A small rust package with no dependencies. config['hooks'][0]['additional_dependencies'] = [dep] hook = _get_hook(config, store, 'rust-hook') - binaries = os.listdir( - hook.prefix.path( - helpers.environment_dir(rust.ENVIRONMENT_DIR, 'system'), 'bin', - ), + envdir = helpers.environment_dir( + hook.prefix, + rust.ENVIRONMENT_DIR, + 'system', ) + binaries = os.listdir(os.path.join(envdir, 'bin')) # normalize for windows binaries = [os.path.splitext(binary)[0] for binary in binaries] assert 'shellharden' in binaries @@ -482,11 +483,12 @@ def test_additional_rust_lib_dependencies_installed( deps = ['shellharden:3.1.0', 'git-version'] config['hooks'][0]['additional_dependencies'] = deps hook = _get_hook(config, store, 'rust-hook') - binaries = os.listdir( - hook.prefix.path( - helpers.environment_dir(rust.ENVIRONMENT_DIR, 'system'), 'bin', - ), + envdir = helpers.environment_dir( + hook.prefix, + rust.ENVIRONMENT_DIR, + 'system', ) + binaries = os.listdir(os.path.join(envdir, 'bin')) # normalize for windows binaries = [os.path.splitext(binary)[0] for binary in binaries] assert 'rust-hello-world' in binaries @@ -672,11 +674,12 @@ def test_additional_golang_dependencies_installed( deps = ['golang.org/x/example/hello@latest'] config['hooks'][0]['additional_dependencies'] = deps hook = _get_hook(config, store, 'golang-hook') - binaries = os.listdir( - hook.prefix.path( - helpers.environment_dir(golang.ENVIRONMENT_DIR, C.DEFAULT), 'bin', - ), + envdir = helpers.environment_dir( + hook.prefix, + golang.ENVIRONMENT_DIR, + C.DEFAULT, ) + binaries = os.listdir(os.path.join(envdir, 'bin')) # normalize for windows binaries = [os.path.splitext(binary)[0] for binary in binaries] assert 'hello' in binaries @@ -792,10 +795,14 @@ def test_control_c_control_c_on_install(tempdir_factory, store): # Should have made an environment, however this environment is broken! hook, = hooks - assert hook.prefix.exists( - helpers.environment_dir(python.ENVIRONMENT_DIR, hook.language_version), + envdir = helpers.environment_dir( + hook.prefix, + python.ENVIRONMENT_DIR, + hook.language_version, ) + assert os.path.exists(envdir) + # However, it should be perfectly runnable (reinstall after botched # install) install_hook_envs(hooks, store) @@ -811,10 +818,12 @@ def test_invalidated_virtualenv(tempdir_factory, store): hook = _get_hook(config, store, 'foo') # Simulate breaking of the virtualenv - libdir = hook.prefix.path( - helpers.environment_dir(python.ENVIRONMENT_DIR, hook.language_version), - 'lib', hook.language_version, + envdir = helpers.environment_dir( + hook.prefix, + python.ENVIRONMENT_DIR, + hook.language_version, ) + libdir = os.path.join(envdir, 'lib', hook.language_version) paths = [ os.path.join(libdir, p) for p in ('site.py', 'site.pyc', '__pycache__') ] From 0920cb33ee3faf614dec5ab83dd9f99a682e6a75 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 2 Jan 2023 16:00:27 -0500 Subject: [PATCH 164/416] simplify install state the additional bookkeeping has been unnecessary since b827694520be0f39bfc0599f3680b6c08b4516cf unfortunately this will cause a rebuild of all hooks in order to be forward/backward compatible -- shrugs --- pre_commit/constants.py | 2 -- pre_commit/repository.py | 27 ++++----------------------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 8fc5e55d..3f03ceed 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -5,8 +5,6 @@ import importlib.metadata CONFIG_FILE = '.pre-commit-config.yaml' MANIFEST_FILE = '.pre-commit-hooks.yaml' -# Bump when installation changes in a backwards / forwards incompatible way -INSTALLED_STATE_VERSION = '1' # Bump when modifying `empty_template` LOCAL_REPO_VERSION = '1' diff --git a/pre_commit/repository.py b/pre_commit/repository.py index ac6b8446..dfa1a2fd 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -1,6 +1,5 @@ from __future__ import annotations -import json import logging import os from typing import Any @@ -23,21 +22,8 @@ from pre_commit.util import rmtree logger = logging.getLogger('pre_commit') -def _state(additional_deps: Sequence[str]) -> object: - return {'additional_dependencies': sorted(additional_deps)} - - def _state_filename(venv: str) -> str: - return os.path.join(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}') - - -def _read_state(venv: str) -> object | None: - filename = _state_filename(venv) - if not os.path.exists(filename): - return None - else: - with open(filename) as f: - return json.load(f) + return os.path.join(venv, '.install_state_v2') def _hook_installed(hook: Hook) -> bool: @@ -51,7 +37,7 @@ def _hook_installed(hook: Hook) -> bool: hook.language_version, ) return ( - _read_state(venv) == _state(hook.additional_dependencies) and + os.path.exists(_state_filename(venv)) and not lang.health_check(hook.prefix, hook.language_version) ) @@ -87,13 +73,8 @@ def _hook_install(hook: Hook) -> None: f'your environment\n\n' f'more info:\n\n{health_error}', ) - # Write our state to indicate we're installed - state_filename = _state_filename(venv) - staging = f'{state_filename}staging' - with open(staging, 'w') as state_file: - state_file.write(json.dumps(_state(hook.additional_dependencies))) - # Move the file into place atomically to indicate we've installed - os.replace(staging, state_filename) + # touch state file to indicate we're installed + open(_state_filename(venv), 'a+').close() def _hook( From 990643c1e089a7924697b32d4f2dd57dbe37785f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 2 Jan 2023 18:39:42 -0500 Subject: [PATCH 165/416] Revert "simplify install state" --- pre_commit/constants.py | 2 ++ pre_commit/repository.py | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 3f03ceed..8fc5e55d 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -5,6 +5,8 @@ import importlib.metadata CONFIG_FILE = '.pre-commit-config.yaml' MANIFEST_FILE = '.pre-commit-hooks.yaml' +# Bump when installation changes in a backwards / forwards incompatible way +INSTALLED_STATE_VERSION = '1' # Bump when modifying `empty_template` LOCAL_REPO_VERSION = '1' diff --git a/pre_commit/repository.py b/pre_commit/repository.py index dfa1a2fd..ac6b8446 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -1,5 +1,6 @@ from __future__ import annotations +import json import logging import os from typing import Any @@ -22,8 +23,21 @@ from pre_commit.util import rmtree logger = logging.getLogger('pre_commit') +def _state(additional_deps: Sequence[str]) -> object: + return {'additional_dependencies': sorted(additional_deps)} + + def _state_filename(venv: str) -> str: - return os.path.join(venv, '.install_state_v2') + return os.path.join(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}') + + +def _read_state(venv: str) -> object | None: + filename = _state_filename(venv) + if not os.path.exists(filename): + return None + else: + with open(filename) as f: + return json.load(f) def _hook_installed(hook: Hook) -> bool: @@ -37,7 +51,7 @@ def _hook_installed(hook: Hook) -> bool: hook.language_version, ) return ( - os.path.exists(_state_filename(venv)) and + _read_state(venv) == _state(hook.additional_dependencies) and not lang.health_check(hook.prefix, hook.language_version) ) @@ -73,8 +87,13 @@ def _hook_install(hook: Hook) -> None: f'your environment\n\n' f'more info:\n\n{health_error}', ) - # touch state file to indicate we're installed - open(_state_filename(venv), 'a+').close() + # Write our state to indicate we're installed + state_filename = _state_filename(venv) + staging = f'{state_filename}staging' + with open(staging, 'w') as state_file: + state_file.write(json.dumps(_state(hook.additional_dependencies))) + # Move the file into place atomically to indicate we've installed + os.replace(staging, state_filename) def _hook( From 8529a0c1d35e422304a54cc2c01d18541287e171 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 1 Jan 2023 16:58:16 -0500 Subject: [PATCH 166/416] add pre_commit.yaml module --- pre_commit/clientlib.py | 2 +- pre_commit/commands/autoupdate.py | 4 ++-- pre_commit/commands/migrate_config.py | 2 +- pre_commit/commands/try_repo.py | 2 +- pre_commit/languages/dart.py | 2 +- pre_commit/util.py | 15 --------------- pre_commit/yaml.py | 18 ++++++++++++++++++ testing/fixtures.py | 4 ++-- tests/commands/autoupdate_test.py | 5 ++--- 9 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 pre_commit/yaml.py diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index e03d5d66..e191d3a0 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -14,7 +14,7 @@ from identify.identify import ALL_TAGS import pre_commit.constants as C from pre_commit.errors import FatalError from pre_commit.languages.all import all_languages -from pre_commit.util import yaml_load +from pre_commit.yaml import yaml_load logger = logging.getLogger('pre_commit') diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 6da53112..7ed6e776 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -20,8 +20,8 @@ from pre_commit.store import Store from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b -from pre_commit.util import yaml_dump -from pre_commit.util import yaml_load +from pre_commit.yaml import yaml_dump +from pre_commit.yaml import yaml_load class RevInfo(NamedTuple): diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index c3d0a509..836936b2 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -5,7 +5,7 @@ import textwrap import yaml -from pre_commit.util import yaml_load +from pre_commit.yaml import yaml_load def _is_header_line(line: str) -> bool: diff --git a/pre_commit/commands/try_repo.py b/pre_commit/commands/try_repo.py index 5244aeff..539ed3c2 100644 --- a/pre_commit/commands/try_repo.py +++ b/pre_commit/commands/try_repo.py @@ -12,8 +12,8 @@ from pre_commit.clientlib import load_manifest from pre_commit.commands.run import run from pre_commit.store import Store from pre_commit.util import cmd_output_b -from pre_commit.util import yaml_dump from pre_commit.xargs import xargs +from pre_commit.yaml import yaml_dump logger = logging.getLogger(__name__) diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 9fbb63cc..223567a5 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -15,7 +15,7 @@ from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import win_exe -from pre_commit.util import yaml_load +from pre_commit.yaml import yaml_load ENVIRONMENT_DIR = 'dartenv' diff --git a/pre_commit/util.py b/pre_commit/util.py index 324544c7..d51fd32d 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -2,7 +2,6 @@ from __future__ import annotations import contextlib import errno -import functools import importlib.resources import os.path import shutil @@ -15,22 +14,8 @@ from typing import Callable from typing import Generator from typing import IO -import yaml - from pre_commit import parse_shebang -Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) -yaml_load = functools.partial(yaml.load, Loader=Loader) -Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) - - -def yaml_dump(o: Any, **kwargs: Any) -> str: - # when python/mypy#1484 is solved, this can be `functools.partial` - return yaml.dump( - o, Dumper=Dumper, default_flow_style=False, indent=4, sort_keys=False, - **kwargs, - ) - def force_bytes(exc: Any) -> bytes: with contextlib.suppress(TypeError): diff --git a/pre_commit/yaml.py b/pre_commit/yaml.py new file mode 100644 index 00000000..bdf4ec47 --- /dev/null +++ b/pre_commit/yaml.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +import functools +from typing import Any + +import yaml + +Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) +yaml_load = functools.partial(yaml.load, Loader=Loader) +Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) + + +def yaml_dump(o: Any, **kwargs: Any) -> str: + # when python/mypy#1484 is solved, this can be `functools.partial` + return yaml.dump( + o, Dumper=Dumper, default_flow_style=False, indent=4, sort_keys=False, + **kwargs, + ) diff --git a/testing/fixtures.py b/testing/fixtures.py index 5182a083..79a11605 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -12,8 +12,8 @@ from pre_commit import git from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import load_manifest from pre_commit.util import cmd_output -from pre_commit.util import yaml_dump -from pre_commit.util import yaml_load +from pre_commit.yaml import yaml_dump +from pre_commit.yaml import yaml_load from testing.util import get_resource_path from testing.util import git_commit diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index 3806b0e4..4bcb5d82 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -4,12 +4,11 @@ import shlex from unittest import mock import pytest -import yaml import pre_commit.constants as C from pre_commit import envcontext from pre_commit import git -from pre_commit import util +from pre_commit import yaml from pre_commit.commands.autoupdate import _check_hooks_still_exist_at_rev from pre_commit.commands.autoupdate import autoupdate from pre_commit.commands.autoupdate import RepositoryCannotBeUpdatedError @@ -206,7 +205,7 @@ def test_autoupdate_with_core_useBuiltinFSMonitor(out_of_date, tmpdir, store): def test_autoupdate_pure_yaml(out_of_date, tmpdir, store): - with mock.patch.object(util, 'Dumper', yaml.SafeDumper): + with mock.patch.object(yaml, 'Dumper', yaml.yaml.SafeDumper): test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store) From 60a42e94195492fa27e869e5034f296989cfc4a7 Mon Sep 17 00:00:00 2001 From: taoufik07 Date: Mon, 2 Jan 2023 21:14:50 +0100 Subject: [PATCH 167/416] Remove `GOPATH` special build --- pre_commit/git.py | 5 ---- pre_commit/languages/golang.py | 47 ++++++++-------------------------- tests/languages/golang_test.py | 22 ---------------- 3 files changed, 10 insertions(+), 64 deletions(-) delete mode 100644 tests/languages/golang_test.py diff --git a/pre_commit/git.py b/pre_commit/git.py index a76118f0..333dc7ba 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -93,11 +93,6 @@ def get_git_common_dir(git_root: str = '.') -> str: return get_git_dir(git_root) -def get_remote_url(git_root: str) -> str: - _, out, _ = cmd_output('git', 'config', 'remote.origin.url', cwd=git_root) - return out.strip() - - def is_in_merge_conflict() -> bool: git_dir = get_git_dir('.') return ( diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 70f0e65d..a57c38dc 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -7,7 +7,6 @@ from typing import Generator from typing import Sequence import pre_commit.constants as C -from pre_commit import git from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -15,7 +14,6 @@ from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output -from pre_commit.util import cmd_output_b from pre_commit.util import rmtree ENVIRONMENT_DIR = 'golangenv' @@ -36,53 +34,28 @@ def in_env(prefix: Prefix) -> Generator[None, None, None]: yield -def guess_go_dir(remote_url: str) -> str: - if remote_url.endswith('.git'): - remote_url = remote_url[:-1 * len('.git')] - looks_like_url = ( - not remote_url.startswith('file://') and - ('//' in remote_url or '@' in remote_url) - ) - remote_url = remote_url.replace(':', '/') - if looks_like_url: - _, _, remote_url = remote_url.rpartition('//') - _, _, remote_url = remote_url.rpartition('@') - return remote_url - else: - return 'unknown_src_dir' - - def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: helpers.assert_version_default('golang', version) - directory = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) - - remote = git.get_remote_url(prefix.prefix_dir) - repo_src_dir = os.path.join(directory, 'src', guess_go_dir(remote)) - - # Clone into the goenv we'll create - cmd = ('git', 'clone', '--recursive', '.', repo_src_dir) - helpers.run_setup_cmd(prefix, cmd) + env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) if sys.platform == 'cygwin': # pragma: no cover - _, gopath, _ = cmd_output('cygpath', '-w', directory) - gopath = gopath.strip() + gopath = cmd_output('cygpath', '-w', env_dir)[1].strip() else: - gopath = directory + gopath = env_dir env = dict(os.environ, GOPATH=gopath) env.pop('GOBIN', None) - cmd_output_b('go', 'install', './...', cwd=repo_src_dir, env=env) + + helpers.run_setup_cmd(prefix, ('go', 'install', './...'), env=env) for dependency in additional_dependencies: - cmd_output_b( - 'go', 'install', dependency, cwd=repo_src_dir, env=env, - ) - # Same some disk space, we don't need these after installation - rmtree(prefix.path(directory, 'src')) - pkgdir = prefix.path(directory, 'pkg') - if os.path.exists(pkgdir): # pragma: no cover (go<1.10) + helpers.run_setup_cmd(prefix, ('go', 'install', dependency), env=env) + + # save some disk space -- we don't need this after installation + pkgdir = os.path.join(env_dir, 'pkg') + if os.path.exists(pkgdir): # pragma: no branch (always true on windows?) rmtree(pkgdir) diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py deleted file mode 100644 index 9e393cb3..00000000 --- a/tests/languages/golang_test.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import annotations - -import pytest - -from pre_commit.languages.golang import guess_go_dir - - -@pytest.mark.parametrize( - ('url', 'expected'), - ( - ('/im/a/path/on/disk', 'unknown_src_dir'), - ('file:///im/a/path/on/disk', 'unknown_src_dir'), - ('git@github.com:golang/lint', 'github.com/golang/lint'), - ('git://github.com/golang/lint', 'github.com/golang/lint'), - ('http://github.com/golang/lint', 'github.com/golang/lint'), - ('https://github.com/golang/lint', 'github.com/golang/lint'), - ('ssh://git@github.com/golang/lint', 'github.com/golang/lint'), - ('git@github.com:golang/lint.git', 'github.com/golang/lint'), - ), -) -def test_guess_go_dir(url, expected): - assert guess_go_dir(url) == expected From bf1a1fa5fd6de3633b033847964b51a60ffbd0d5 Mon Sep 17 00:00:00 2001 From: taoufik07 Date: Thu, 5 Jan 2023 13:31:28 +0100 Subject: [PATCH 168/416] Fix command normalization when a custom env is passed --- pre_commit/parse_shebang.py | 18 +++++++++------ pre_commit/util.py | 2 +- tests/commands/install_uninstall_test.py | 29 ++++++++++++------------ tests/languages/rust_test.py | 7 ++++-- tests/parse_shebang_test.py | 6 ++--- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/pre_commit/parse_shebang.py b/pre_commit/parse_shebang.py index 3ac933c0..3ee04e8d 100644 --- a/pre_commit/parse_shebang.py +++ b/pre_commit/parse_shebang.py @@ -20,13 +20,13 @@ def parse_filename(filename: str) -> tuple[str, ...]: def find_executable( - exe: str, _environ: Mapping[str, str] | None = None, + exe: str, *, env: Mapping[str, str] | None = None, ) -> str | None: exe = os.path.normpath(exe) if os.sep in exe: return exe - environ = _environ if _environ is not None else os.environ + environ = env if env is not None else os.environ if 'PATHEXT' in environ: exts = environ['PATHEXT'].split(os.pathsep) @@ -43,12 +43,12 @@ def find_executable( return None -def normexe(orig: str) -> str: +def normexe(orig: str, *, env: Mapping[str, str] | None = None) -> str: def _error(msg: str) -> NoReturn: raise ExecutableNotFoundError(f'Executable `{orig}` {msg}') if os.sep not in orig and (not os.altsep or os.altsep not in orig): - exe = find_executable(orig) + exe = find_executable(orig, env=env) if exe is None: _error('not found') return exe @@ -62,7 +62,11 @@ def normexe(orig: str) -> str: return orig -def normalize_cmd(cmd: tuple[str, ...]) -> tuple[str, ...]: +def normalize_cmd( + cmd: tuple[str, ...], + *, + env: Mapping[str, str] | None = None, +) -> tuple[str, ...]: """Fixes for the following issues on windows - https://bugs.python.org/issue8557 - windows does not parse shebangs @@ -70,12 +74,12 @@ def normalize_cmd(cmd: tuple[str, ...]) -> tuple[str, ...]: This function also makes deep-path shebangs work just fine """ # Use PATH to determine the executable - exe = normexe(cmd[0]) + exe = normexe(cmd[0], env=env) # Figure out the shebang from the resulting command cmd = parse_filename(exe) + (exe,) + cmd[1:] # This could have given us back another bare executable - exe = normexe(cmd[0]) + exe = normexe(cmd[0], env=env) return (exe,) + cmd[1:] diff --git a/pre_commit/util.py b/pre_commit/util.py index d51fd32d..8ea48446 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -99,7 +99,7 @@ def cmd_output_b( _setdefault_kwargs(kwargs) try: - cmd = parse_shebang.normalize_cmd(cmd) + cmd = parse_shebang.normalize_cmd(cmd, env=kwargs.get('env')) except parse_shebang.ExecutableNotFoundError as e: returncode, stdout_b, stderr_b = e.to_output() else: diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index e3943773..a1ecda86 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -248,7 +248,7 @@ def test_install_idempotent(tempdir_factory, store): def _path_without_us(): # Choose a path which *probably* doesn't include us env = dict(os.environ) - exe = find_executable('pre-commit', _environ=env) + exe = find_executable('pre-commit', env=env) while exe: parts = env['PATH'].split(os.pathsep) after = [ @@ -258,7 +258,7 @@ def _path_without_us(): if parts == after: raise AssertionError(exe, parts) env['PATH'] = os.pathsep.join(after) - exe = find_executable('pre-commit', _environ=env) + exe = find_executable('pre-commit', env=env) return env['PATH'] @@ -276,18 +276,19 @@ def test_environment_not_sourced(tempdir_factory, store): # Use a specific homedir to ignore --user installs homedir = tempdir_factory.get() - ret, out = git_commit( - env={ - 'HOME': homedir, - 'PATH': _path_without_us(), - # Git needs this to make a commit - 'GIT_AUTHOR_NAME': os.environ['GIT_AUTHOR_NAME'], - 'GIT_COMMITTER_NAME': os.environ['GIT_COMMITTER_NAME'], - 'GIT_AUTHOR_EMAIL': os.environ['GIT_AUTHOR_EMAIL'], - 'GIT_COMMITTER_EMAIL': os.environ['GIT_COMMITTER_EMAIL'], - }, - check=False, - ) + env = { + 'HOME': homedir, + 'PATH': _path_without_us(), + # Git needs this to make a commit + 'GIT_AUTHOR_NAME': os.environ['GIT_AUTHOR_NAME'], + 'GIT_COMMITTER_NAME': os.environ['GIT_COMMITTER_NAME'], + 'GIT_AUTHOR_EMAIL': os.environ['GIT_AUTHOR_EMAIL'], + 'GIT_COMMITTER_EMAIL': os.environ['GIT_COMMITTER_EMAIL'], + } + if os.name == 'nt' and 'PATHEXT' in os.environ: # pragma: no cover + env['PATHEXT'] = os.environ['PATHEXT'] + + ret, out = git_commit(env=env, check=False) assert ret == 1 assert out == ( '`pre-commit` not found. ' diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py index f011e719..b8167a9e 100644 --- a/tests/languages/rust_test.py +++ b/tests/languages/rust_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +from typing import Mapping from unittest import mock import pytest @@ -48,7 +49,9 @@ def test_installs_with_bootstrapped_rustup(tmpdir, language_version): original_find_executable = parse_shebang.find_executable - def mocked_find_executable(exe: str) -> str | None: + def mocked_find_executable( + exe: str, *, env: Mapping[str, str] | None = None, + ) -> str | None: """ Return `None` the first time `find_executable` is called to ensure that the bootstrapping code is executed, then just let the function @@ -59,7 +62,7 @@ def test_installs_with_bootstrapped_rustup(tmpdir, language_version): find_executable_exes.append(exe) if len(find_executable_exes) == 1: return None - return original_find_executable(exe) + return original_find_executable(exe, env=env) with mock.patch.object(parse_shebang, 'find_executable') as find_exe_mck: find_exe_mck.side_effect = mocked_find_executable diff --git a/tests/parse_shebang_test.py b/tests/parse_shebang_test.py index d7acbf57..2fcb29ee 100644 --- a/tests/parse_shebang_test.py +++ b/tests/parse_shebang_test.py @@ -75,10 +75,10 @@ def test_find_executable_path_ext(in_tmpdir): env_path = {'PATH': os.path.dirname(exe_path)} env_path_ext = dict(env_path, PATHEXT=os.pathsep.join(('.exe', '.myext'))) assert parse_shebang.find_executable('run') is None - assert parse_shebang.find_executable('run', _environ=env_path) is None - ret = parse_shebang.find_executable('run.myext', _environ=env_path) + assert parse_shebang.find_executable('run', env=env_path) is None + ret = parse_shebang.find_executable('run.myext', env=env_path) assert ret == exe_path - ret = parse_shebang.find_executable('run', _environ=env_path_ext) + ret = parse_shebang.find_executable('run', env=env_path_ext) assert ret == exe_path From 619f2bf5a9a4b03766c3304ad4e01ec90bea17f1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 9 Jan 2023 12:31:05 -0500 Subject: [PATCH 169/416] eagerly catch invalid yaml in migrate-config --- pre_commit/commands/migrate_config.py | 9 +++++++++ tests/commands/migrate_config_test.py | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index 836936b2..6f7af4eb 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -3,8 +3,10 @@ from __future__ import annotations import re import textwrap +import cfgv import yaml +from pre_commit.clientlib import InvalidConfigError from pre_commit.yaml import yaml_load @@ -44,6 +46,13 @@ def migrate_config(config_file: str, quiet: bool = False) -> int: with open(config_file) as f: orig_contents = contents = f.read() + with cfgv.reraise_as(InvalidConfigError): + with cfgv.validate_context(f'File {config_file}'): + try: + yaml_load(orig_contents) + except Exception as e: + raise cfgv.ValidationError(str(e)) + contents = _migrate_map(contents) contents = _migrate_sha_to_rev(contents) diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py index b80244e1..fca1ad92 100644 --- a/tests/commands/migrate_config_test.py +++ b/tests/commands/migrate_config_test.py @@ -1,6 +1,9 @@ from __future__ import annotations +import pytest + import pre_commit.constants as C +from pre_commit.clientlib import InvalidConfigError from pre_commit.commands.migrate_config import migrate_config @@ -129,3 +132,13 @@ def test_migrate_config_sha_to_rev(tmpdir): ' rev: v1.2.0\n' ' hooks: []\n' ) + + +def test_migrate_config_invalid_yaml(tmpdir): + contents = '[' + cfg = tmpdir.join(C.CONFIG_FILE) + cfg.write(contents) + with tmpdir.as_cwd(), pytest.raises(InvalidConfigError) as excinfo: + migrate_config(C.CONFIG_FILE) + expected = '\n==> File .pre-commit-config.yaml\n=====> ' + assert str(excinfo.value).startswith(expected) From 9afd63948e2ba76cd0e351d022efd82534383146 Mon Sep 17 00:00:00 2001 From: taoufik07 Date: Tue, 3 Jan 2023 01:48:43 +0100 Subject: [PATCH 170/416] Make Go a first class language --- pre_commit/languages/golang.py | 116 ++++++++++++++++-- .../golang-hello-world/main.go | 8 +- tests/languages/golang_test.py | 43 +++++++ tests/repository_test.py | 27 +++- 4 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 tests/languages/golang_test.py diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index a57c38dc..756aa164 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -1,9 +1,21 @@ from __future__ import annotations import contextlib +import functools +import json import os.path +import platform +import shutil import sys +import tarfile +import tempfile +import urllib.error +import urllib.request +import zipfile +from typing import ContextManager from typing import Generator +from typing import IO +from typing import Protocol from typing import Sequence import pre_commit.constants as C @@ -17,20 +29,100 @@ from pre_commit.util import cmd_output from pre_commit.util import rmtree ENVIRONMENT_DIR = 'golangenv' -get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +_ARCH_ALIASES = { + 'x86_64': 'amd64', + 'i386': '386', + 'aarch64': 'arm64', + 'armv8': 'arm64', + 'armv7l': 'armv6l', +} +_ARCH = platform.machine().lower() +_ARCH = _ARCH_ALIASES.get(_ARCH, _ARCH) + + +class ExtractAll(Protocol): + def extractall(self, path: str) -> None: ... + + +if sys.platform == 'win32': # pragma: win32 cover + _EXT = 'zip' + + def _open_archive(bio: IO[bytes]) -> ContextManager[ExtractAll]: + return zipfile.ZipFile(bio) +else: # pragma: win32 no cover + _EXT = 'tar.gz' + + def _open_archive(bio: IO[bytes]) -> ContextManager[ExtractAll]: + return tarfile.open(fileobj=bio) + + +@functools.lru_cache(maxsize=1) +def get_default_version() -> str: + if helpers.exe_exists('go'): + return 'system' + else: + return C.DEFAULT + + +def get_env_patch(venv: str, version: str) -> PatchesT: + if version == 'system': + return ( + ('PATH', (os.path.join(venv, 'bin'), os.pathsep, Var('PATH'))), + ) -def get_env_patch(venv: str) -> PatchesT: return ( - ('PATH', (os.path.join(venv, 'bin'), os.pathsep, Var('PATH'))), + ('GOROOT', os.path.join(venv, '.go')), + ( + 'PATH', ( + os.path.join(venv, 'bin'), os.pathsep, + os.path.join(venv, '.go', 'bin'), os.pathsep, Var('PATH'), + ), + ), ) +@functools.lru_cache +def _infer_go_version(version: str) -> str: + if version != C.DEFAULT: + return version + resp = urllib.request.urlopen('https://go.dev/dl/?mode=json') + # TODO: 3.9+ .removeprefix('go') + return json.load(resp)[0]['version'][2:] + + +def _get_url(version: str) -> str: + os_name = platform.system().lower() + version = _infer_go_version(version) + return f'https://dl.google.com/go/go{version}.{os_name}-{_ARCH}.{_EXT}' + + +def _install_go(version: str, dest: str) -> None: + try: + resp = urllib.request.urlopen(_get_url(version)) + except urllib.error.HTTPError as e: # pragma: no cover + if e.code == 404: + raise ValueError( + f'Could not find a version matching your system requirements ' + f'(os={platform.system().lower()}; arch={_ARCH})', + ) from e + else: + raise + else: + with tempfile.TemporaryFile() as f: + shutil.copyfileobj(resp, f) + f.seek(0) + + with _open_archive(f) as archive: + archive.extractall(dest) + shutil.move(os.path.join(dest, 'go'), os.path.join(dest, '.go')) + + @contextlib.contextmanager -def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) - with envcontext(get_env_patch(envdir)): +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + with envcontext(get_env_patch(envdir, version)): yield @@ -39,15 +131,23 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('golang', version) env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + if version != 'system': + _install_go(version, env_dir) + if sys.platform == 'cygwin': # pragma: no cover gopath = cmd_output('cygpath', '-w', env_dir)[1].strip() else: gopath = env_dir + env = dict(os.environ, GOPATH=gopath) env.pop('GOBIN', None) + if version != 'system': + env['GOROOT'] = os.path.join(env_dir, '.go') + env['PATH'] = os.pathsep.join(( + os.path.join(env_dir, '.go', 'bin'), os.environ['PATH'], + )) helpers.run_setup_cmd(prefix, ('go', 'install', './...'), env=env) for dependency in additional_dependencies: @@ -64,5 +164,5 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - with in_env(hook.prefix): + with in_env(hook.prefix, hook.language_version): return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/testing/resources/golang_hooks_repo/golang-hello-world/main.go b/testing/resources/golang_hooks_repo/golang-hello-world/main.go index 1e3c591a..16857438 100644 --- a/testing/resources/golang_hooks_repo/golang-hello-world/main.go +++ b/testing/resources/golang_hooks_repo/golang-hello-world/main.go @@ -3,7 +3,9 @@ package main import ( "fmt" + "runtime" "github.com/BurntSushi/toml" + "os" ) type Config struct { @@ -11,7 +13,11 @@ type Config struct { } func main() { + message := runtime.Version() + if len(os.Args) > 1 { + message = os.Args[1] + } var conf Config toml.Decode("What = 'world'\n", &conf) - fmt.Printf("hello %v\n", conf.What) + fmt.Printf("hello %v from %s\n", conf.What, message) } diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py new file mode 100644 index 00000000..0219261f --- /dev/null +++ b/tests/languages/golang_test.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +import re +from unittest import mock + +import pytest + +import pre_commit.constants as C +from pre_commit.languages import golang +from pre_commit.languages import helpers + + +ACTUAL_GET_DEFAULT_VERSION = golang.get_default_version.__wrapped__ + + +@pytest.fixture +def exe_exists_mck(): + with mock.patch.object(helpers, 'exe_exists') as mck: + yield mck + + +def test_golang_default_version_system_available(exe_exists_mck): + exe_exists_mck.return_value = True + assert ACTUAL_GET_DEFAULT_VERSION() == 'system' + + +def test_golang_default_version_system_not_available(exe_exists_mck): + exe_exists_mck.return_value = False + assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT + + +ACTUAL_INFER_GO_VERSION = golang._infer_go_version.__wrapped__ + + +def test_golang_infer_go_version_not_default(): + assert ACTUAL_INFER_GO_VERSION('1.19.4') == '1.19.4' + + +def test_golang_infer_go_version_default(): + version = ACTUAL_INFER_GO_VERSION(C.DEFAULT) + + assert version != C.DEFAULT + assert re.match(r'^\d+\.\d+\.\d+$', version) diff --git a/tests/repository_test.py b/tests/repository_test.py index fa8bf431..2fa1ccce 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -380,17 +380,36 @@ def test_swift_hook(tempdir_factory, store): ) -def test_golang_hook(tempdir_factory, store): +def test_golang_system_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'golang_hooks_repo', - 'golang-hook', [], b'hello world\n', + 'golang-hook', ['system'], b'hello world from system\n', + config_kwargs={ + 'hooks': [{ + 'id': 'golang-hook', + 'language_version': 'system', + }], + }, + ) + + +def test_golang_versioned_hook(tempdir_factory, store): + _test_hook_repo( + tempdir_factory, store, 'golang_hooks_repo', + 'golang-hook', [], b'hello world from go1.18.4\n', + config_kwargs={ + 'hooks': [{ + 'id': 'golang-hook', + 'language_version': '1.18.4', + }], + }, ) def test_golang_hook_still_works_when_gobin_is_set(tempdir_factory, store): gobin_dir = tempdir_factory.get() with envcontext((('GOBIN', gobin_dir),)): - test_golang_hook(tempdir_factory, store) + test_golang_system_hook(tempdir_factory, store) assert os.listdir(gobin_dir) == [] @@ -677,7 +696,7 @@ def test_additional_golang_dependencies_installed( envdir = helpers.environment_dir( hook.prefix, golang.ENVIRONMENT_DIR, - C.DEFAULT, + golang.get_default_version(), ) binaries = os.listdir(os.path.join(envdir, 'bin')) # normalize for windows From 37685a7f4200c50cf707ebf9cddd5700ab66f31a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 15 Jan 2023 09:56:30 -0500 Subject: [PATCH 171/416] the local repo no longer needs to be a git repo --- pre_commit/store.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pre_commit/store.py b/pre_commit/store.py index effebfb8..e42cc489 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -204,16 +204,6 @@ class Store: with open(target_file, 'w') as f: f.write(contents) - env = git.no_git_env() - - # initialize the git repository so it looks more like cloned repos - def _git_cmd(*args: str) -> None: - cmd_output_b('git', *args, cwd=directory, env=env) - - git.init_repo(directory, '<>') - _git_cmd('add', '.') - git.commit(repo=directory) - return self._new_repo( 'local', C.LOCAL_REPO_VERSION, deps, make_local_strategy, ) From ae34a962d79d4e823214028c353f690dd2ad4306 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 2 Jan 2023 19:02:38 -0500 Subject: [PATCH 172/416] make in_env part of the language api --- pre_commit/commands/run.py | 3 ++- pre_commit/languages/all.py | 9 +++++++++ pre_commit/languages/conda.py | 10 +++------- pre_commit/languages/coursier.py | 12 ++++-------- pre_commit/languages/dart.py | 8 +++----- pre_commit/languages/docker.py | 4 ++-- pre_commit/languages/docker_image.py | 1 + pre_commit/languages/dotnet.py | 8 +++----- pre_commit/languages/fail.py | 1 + pre_commit/languages/golang.py | 3 +-- pre_commit/languages/helpers.py | 9 ++++++++- pre_commit/languages/lua.py | 12 +++++------- pre_commit/languages/node.py | 10 +++------- pre_commit/languages/perl.py | 10 +++------- pre_commit/languages/pygrep.py | 1 + pre_commit/languages/python.py | 10 +++------- pre_commit/languages/r.py | 14 +++++--------- pre_commit/languages/ruby.py | 12 ++++-------- pre_commit/languages/rust.py | 12 ++++-------- pre_commit/languages/script.py | 1 + pre_commit/languages/swift.py | 10 ++++------ pre_commit/languages/system.py | 2 +- tests/repository_test.py | 3 ++- 23 files changed, 73 insertions(+), 92 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 429e04c6..a398e84c 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -189,7 +189,8 @@ def _run_single_hook( filenames = () time_before = time.time() language = languages[hook.language] - retcode, out = language.run_hook(hook, filenames, use_color) + with language.in_env(hook.prefix, hook.language_version): + retcode, out = language.run_hook(hook, filenames, use_color) duration = round(time.time() - time_before, 2) or 0 diff_after = _get_diff() diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index 7c7c58bd..6135272a 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -1,5 +1,6 @@ from __future__ import annotations +from typing import ContextManager from typing import Protocol from typing import Sequence @@ -50,6 +51,14 @@ class Language(Protocol): ) -> None: ... + # modify the environment for hook execution + def in_env( + self, + prefix: Prefix, + version: str, + ) -> ContextManager[None]: + ... + # execute a hook and return the exit code and output def run_hook( self, diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 5a0a720f..612a8242 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -40,11 +40,8 @@ def get_env_patch(env: str) -> PatchesT: @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -88,5 +85,4 @@ def run_hook( # can run them without which is much quicker and produces a better # output. # cmd = ('conda', 'run', '-p', env_dir) + hook.cmd - 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) diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index fdea3cd7..46eb4e0a 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -59,12 +59,9 @@ def get_env_patch(target_dir: str) -> PatchesT: # pragma: win32 no cover ) -@contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: # pragma: win32 no cover - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +@contextlib.contextmanager # pragma: win32 no cover +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -74,5 +71,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: # pragma: win32 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) diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 223567a5..7d1322b0 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -7,7 +7,6 @@ import tempfile from typing import Generator from typing import Sequence -import pre_commit.constants as C from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -30,8 +29,8 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -103,5 +102,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index c51cf7c1..dbdfd35c 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -5,7 +5,6 @@ import json import os from typing import Sequence -import pre_commit.constants as C from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix @@ -16,6 +15,7 @@ ENVIRONMENT_DIR = 'docker' PRE_COMMIT_LABEL = 'PRE_COMMIT' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +in_env = helpers.no_env # no special environment for docker def _is_in_docker() -> bool: @@ -94,7 +94,7 @@ def install_environment( helpers.assert_version_default('docker', version) helpers.assert_no_additional_deps('docker', additional_dependencies) - directory = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) + directory = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) # Docker doesn't really have relevant disk environment, but pre-commit # still needs to cleanup its state files on failure diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index daa4d1ba..b1cd3caf 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -10,6 +10,7 @@ ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check install_environment = helpers.no_install +in_env = helpers.no_env def run_hook( diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 0bb0210c..8d4d48e3 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -9,7 +9,6 @@ import zipfile from typing import Generator from typing import Sequence -import pre_commit.constants as C from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -31,8 +30,8 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -121,5 +120,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index 00b06a9a..f051d5e4 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -9,6 +9,7 @@ ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check install_environment = helpers.no_install +in_env = helpers.no_env def run_hook( diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 756aa164..b38e4994 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -164,5 +164,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 098e95c5..5b3a54ff 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -1,10 +1,12 @@ from __future__ import annotations +import contextlib import multiprocessing import os import random import re from typing import Any +from typing import Generator from typing import NoReturn from typing import Sequence @@ -84,7 +86,12 @@ def no_install( version: str, additional_dependencies: Sequence[str], ) -> NoReturn: - raise AssertionError('This type is not installable') + raise AssertionError('This language is not installable') + + +@contextlib.contextmanager +def no_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + yield def target_concurrency(hook: Hook) -> int: diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index 26c8f1b7..1c872f36 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -6,7 +6,6 @@ import sys from typing import Generator from typing import Sequence -import pre_commit.constants as C from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -45,8 +44,8 @@ def get_env_patch(d: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover -def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -58,8 +57,8 @@ def install_environment( ) -> None: # pragma: win32 no cover helpers.assert_version_default('lua', version) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) - with in_env(prefix): + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + with in_env(prefix, version): # luarocks doesn't bootstrap a tree prior to installing # so ensure the directory exists. os.makedirs(envdir, exist_ok=True) @@ -81,5 +80,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: # pragma: win32 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) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 8facfe00..7b4d2e7d 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -59,11 +59,8 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -118,5 +115,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 95be6559..622c8a12 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -33,11 +33,8 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -58,5 +55,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index 2e2072b0..d9f779f7 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -16,6 +16,7 @@ ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check install_environment = helpers.no_install +in_env = helpers.no_env def _process_filename_by_line(pattern: Pattern[bytes], filename: str) -> int: diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index a7744d64..28f4ab5d 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -152,11 +152,8 @@ def norm_version(version: str) -> str | None: @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -222,5 +219,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index d2ec83da..f5e1eaba 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -30,11 +30,8 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -156,7 +153,6 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - with in_env(hook.prefix, hook.language_version): - return helpers.run_xargs( - hook, _cmd_from_hook(hook), file_args, color=color, - ) + return helpers.run_xargs( + hook, _cmd_from_hook(hook), file_args, color=color, + ) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 89af2545..2805aca6 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -67,12 +67,9 @@ def get_env_patch( @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) - with envcontext(get_env_patch(envdir, language_version)): +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + with envcontext(get_env_patch(envdir, version)): yield @@ -143,5 +140,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 0f6cd332..9da8f82c 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -62,12 +62,9 @@ def get_env_patch(target_dir: str, version: str) -> PatchesT: @contextlib.contextmanager -def in_env( - prefix: Prefix, - language_version: str, -) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) - with envcontext(get_env_patch(envdir, language_version)): +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + with envcontext(get_env_patch(envdir, version)): yield @@ -164,5 +161,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: - 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) diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index d5e7677f..5b7bdd5f 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -9,6 +9,7 @@ ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check install_environment = helpers.no_install +in_env = helpers.no_env def run_hook( diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index 7cc61d95..ad00b94a 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -5,7 +5,6 @@ import os from typing import Generator from typing import Sequence -import pre_commit.constants as C from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var @@ -27,8 +26,8 @@ def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover -def in_env(prefix: Prefix) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -38,7 +37,7 @@ def install_environment( ) -> None: # pragma: win32 no cover helpers.assert_version_default('swift', version) helpers.assert_no_additional_deps('swift', additional_dependencies) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, C.DEFAULT) + envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) # Build the swift package os.mkdir(envdir) @@ -55,5 +54,4 @@ def run_hook( file_args: Sequence[str], color: bool, ) -> tuple[int, bytes]: # pragma: win32 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) diff --git a/pre_commit/languages/system.py b/pre_commit/languages/system.py index c64fb365..9cc94f8c 100644 --- a/pre_commit/languages/system.py +++ b/pre_commit/languages/system.py @@ -5,11 +5,11 @@ from typing import Sequence from pre_commit.hook import Hook from pre_commit.languages import helpers - ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check install_environment = helpers.no_install +in_env = helpers.no_env def run_hook( diff --git a/tests/repository_test.py b/tests/repository_test.py index 2fa1ccce..236c7983 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -44,7 +44,8 @@ def _norm_out(b): def _hook_run(hook, filenames, color): - return languages[hook.language].run_hook(hook, filenames, color) + with languages[hook.language].in_env(hook.prefix, hook.language_version): + return languages[hook.language].run_hook(hook, filenames, color) def _get_hook_no_install(repo_config, store, hook_id): From 628c876b2d0e1fce25c38e6455a61351d57c714f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 16 Jan 2023 16:34:01 -0500 Subject: [PATCH 173/416] adjust the run_hook api to no longer take Hook --- pre_commit/commands/run.py | 9 +++++- pre_commit/hook.py | 5 --- pre_commit/languages/all.py | 7 +++-- pre_commit/languages/conda.py | 14 +-------- pre_commit/languages/coursier.py | 10 +----- pre_commit/languages/dart.py | 10 +----- pre_commit/languages/docker.py | 20 ++++++++---- pre_commit/languages/docker_image.py | 17 +++++++--- pre_commit/languages/dotnet.py | 10 +----- pre_commit/languages/fail.py | 10 ++++-- pre_commit/languages/golang.py | 10 +----- pre_commit/languages/helpers.py | 46 ++++++++++++++++++++++------ pre_commit/languages/lua.py | 10 +----- pre_commit/languages/node.py | 10 +----- pre_commit/languages/perl.py | 10 +----- pre_commit/languages/pygrep.py | 12 +++++--- pre_commit/languages/python.py | 10 +----- pre_commit/languages/r.py | 29 +++++++++++------- pre_commit/languages/ruby.py | 10 +----- pre_commit/languages/rust.py | 10 +----- pre_commit/languages/script.py | 18 ++++++++--- pre_commit/languages/swift.py | 15 +++------ pre_commit/languages/system.py | 12 +------- tests/languages/helpers_test.py | 28 ++++++++--------- tests/languages/r_test.py | 4 +-- tests/repository_test.py | 9 +++++- 26 files changed, 163 insertions(+), 192 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index a398e84c..85fa59aa 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -190,7 +190,14 @@ def _run_single_hook( time_before = time.time() language = languages[hook.language] with language.in_env(hook.prefix, hook.language_version): - retcode, out = language.run_hook(hook, filenames, use_color) + retcode, out = language.run_hook( + hook.prefix, + hook.entry, + hook.args, + filenames, + require_serial=hook.require_serial, + color=use_color, + ) duration = round(time.time() - time_before, 2) or 0 diff_after = _get_diff() diff --git a/pre_commit/hook.py b/pre_commit/hook.py index 202abb35..6d436ca3 100644 --- a/pre_commit/hook.py +++ b/pre_commit/hook.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -import shlex from typing import Any from typing import NamedTuple from typing import Sequence @@ -37,10 +36,6 @@ class Hook(NamedTuple): stages: Sequence[str] verbose: bool - @property - def cmd(self) -> tuple[str, ...]: - return (*shlex.split(self.entry), *self.args) - @property def install_key(self) -> tuple[Prefix, str, str, tuple[str, ...]]: return ( diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index 6135272a..c7aab65e 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -4,7 +4,6 @@ from typing import ContextManager from typing import Protocol from typing import Sequence -from pre_commit.hook import Hook from pre_commit.languages import conda from pre_commit.languages import coursier from pre_commit.languages import dart @@ -62,8 +61,12 @@ class Language(Protocol): # execute a hook and return the exit code and output def run_hook( self, - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: ... diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 612a8242..e2fb0196 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -10,7 +10,6 @@ from pre_commit.envcontext import PatchesT from pre_commit.envcontext import SubstitutionT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b @@ -18,6 +17,7 @@ from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'conda' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook def get_env_patch(env: str) -> PatchesT: @@ -74,15 +74,3 @@ def install_environment( conda_exe, 'install', '-p', env_dir, *additional_dependencies, cwd=prefix.prefix_dir, ) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - # TODO: Some rare commands need to be run using `conda run` but mostly we - # can run them without which is much quicker and produces a better - # output. - # cmd = ('conda', 'run', '-p', env_dir) + hook.cmd - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 46eb4e0a..a6aea3fb 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -8,7 +8,6 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix @@ -17,6 +16,7 @@ ENVIRONMENT_DIR = 'coursier' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook def install_environment( @@ -64,11 +64,3 @@ def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: # pragma: win32 no cover - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 7d1322b0..e3c1c585 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -10,7 +10,6 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import win_exe @@ -20,6 +19,7 @@ ENVIRONMENT_DIR = 'dartenv' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook def get_env_patch(venv: str) -> PatchesT: @@ -95,11 +95,3 @@ def install_environment( raise AssertionError( f'could not find pubspec.yaml for {dep_s}', ) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index dbdfd35c..18234567 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -5,7 +5,6 @@ import json import os from typing import Sequence -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError @@ -123,16 +122,25 @@ def docker_cmd() -> tuple[str, ...]: # pragma: win32 no cover def run_hook( - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover # Rebuild the docker image in case it has gone missing, as many people do # automated cleanup of docker images. - build_docker_image(hook.prefix, pull=False) + build_docker_image(prefix, pull=False) - entry_exe, *cmd_rest = hook.cmd + entry_exe, *cmd_rest = helpers.hook_cmd(entry, args) - entry_tag = ('--entrypoint', entry_exe, docker_tag(hook.prefix)) + entry_tag = ('--entrypoint', entry_exe, docker_tag(prefix)) cmd = (*docker_cmd(), *entry_tag, *cmd_rest) - return helpers.run_xargs(hook, cmd, file_args, color=color) + return helpers.run_xargs( + cmd, + file_args, + require_serial=require_serial, + color=color, + ) diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index b1cd3caf..23098382 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -2,9 +2,9 @@ from __future__ import annotations from typing import Sequence -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.languages.docker import docker_cmd +from pre_commit.prefix import Prefix ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version @@ -14,9 +14,18 @@ in_env = helpers.no_env def run_hook( - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover - cmd = docker_cmd() + hook.cmd - return helpers.run_xargs(hook, cmd, file_args, color=color) + cmd = docker_cmd() + helpers.hook_cmd(entry, args) + return helpers.run_xargs( + cmd, + file_args, + require_serial=require_serial, + color=color, + ) diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 8d4d48e3..4c3955e8 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -12,7 +12,6 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix @@ -21,6 +20,7 @@ BIN_DIR = 'bin' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook def get_env_patch(venv: str) -> PatchesT: @@ -113,11 +113,3 @@ def install_environment( # Clean the git dir, ignoring the environment dir clean_cmd = ('git', 'clean', '-ffxd', '-e', f'{ENVIRONMENT_DIR}-*') helpers.run_setup_cmd(prefix, clean_cmd) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index f051d5e4..13b2bc12 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -2,8 +2,8 @@ from __future__ import annotations from typing import Sequence -from pre_commit.hook import Hook from pre_commit.languages import helpers +from pre_commit.prefix import Prefix ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version @@ -13,10 +13,14 @@ in_env = helpers.no_env def run_hook( - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: - out = f'{hook.entry}\n\n'.encode() + out = f'{entry}\n\n'.encode() out += b'\n'.join(f.encode() for f in file_args) + b'\n' return 1, out diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index b38e4994..3c4b652f 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -22,7 +22,6 @@ import pre_commit.constants as C from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output @@ -30,6 +29,7 @@ from pre_commit.util import rmtree ENVIRONMENT_DIR = 'golangenv' health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook _ARCH_ALIASES = { 'x86_64': 'amd64', @@ -157,11 +157,3 @@ def install_environment( pkgdir = os.path.join(env_dir, 'pkg') if os.path.exists(pkgdir): # pragma: no branch (always true on windows?) rmtree(pkgdir) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 5b3a54ff..074f98e9 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -5,6 +5,7 @@ import multiprocessing import os import random import re +import shlex from typing import Any from typing import Generator from typing import NoReturn @@ -12,7 +13,6 @@ from typing import Sequence import pre_commit.constants as C from pre_commit import parse_shebang -from pre_commit.hook import Hook from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b from pre_commit.xargs import xargs @@ -94,8 +94,8 @@ def no_env(prefix: Prefix, version: str) -> Generator[None, None, None]: yield -def target_concurrency(hook: Hook) -> int: - if hook.require_serial or 'PRE_COMMIT_NO_CONCURRENCY' in os.environ: +def target_concurrency() -> int: + if 'PRE_COMMIT_NO_CONCURRENCY' in os.environ: return 1 else: # Travis appears to have a bunch of CPUs, but we can't use them all. @@ -119,13 +119,39 @@ def _shuffled(seq: Sequence[str]) -> list[str]: def run_xargs( - hook: Hook, cmd: tuple[str, ...], file_args: Sequence[str], - **kwargs: Any, + *, + require_serial: bool, + color: bool, ) -> tuple[int, bytes]: - # Shuffle the files so that they more evenly fill out the xargs partitions, - # but do it deterministically in case a hook cares about ordering. - file_args = _shuffled(file_args) - kwargs['target_concurrency'] = target_concurrency(hook) - return xargs(cmd, file_args, **kwargs) + if require_serial: + jobs = 1 + else: + # Shuffle the files so that they more evenly fill out the xargs + # partitions, but do it deterministically in case a hook cares about + # ordering. + file_args = _shuffled(file_args) + jobs = target_concurrency() + return xargs(cmd, file_args, target_concurrency=jobs, color=color) + + +def hook_cmd(entry: str, args: Sequence[str]) -> tuple[str, ...]: + return (*shlex.split(entry), *args) + + +def basic_run_hook( + prefix: Prefix, + entry: str, + args: Sequence[str], + file_args: Sequence[str], + *, + require_serial: bool, + color: bool, +) -> tuple[int, bytes]: + return run_xargs( + hook_cmd(entry, args), + file_args, + require_serial=require_serial, + color=color, + ) diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index 1c872f36..ffc40b50 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -9,7 +9,6 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output @@ -17,6 +16,7 @@ from pre_commit.util import cmd_output ENVIRONMENT_DIR = 'lua_env' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook def _get_lua_version() -> str: # pragma: win32 no cover @@ -73,11 +73,3 @@ def install_environment( for dependency in additional_dependencies: cmd = ('luarocks', '--tree', envdir, 'install', dependency) helpers.run_setup_cmd(prefix, cmd) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: # pragma: win32 no cover - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 7b4d2e7d..9688da35 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -12,7 +12,6 @@ from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.languages.python import bin_dir from pre_commit.prefix import Prefix @@ -21,6 +20,7 @@ from pre_commit.util import cmd_output_b from pre_commit.util import rmtree ENVIRONMENT_DIR = 'node_env' +run_hook = helpers.basic_run_hook @functools.lru_cache(maxsize=1) @@ -108,11 +108,3 @@ def install_environment( if prefix.exists('node_modules'): # pragma: win32 no cover rmtree(prefix.path('node_modules')) os.remove(pkg) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 622c8a12..2530c0ee 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -9,13 +9,13 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix ENVIRONMENT_DIR = 'perl_env' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook def get_env_patch(venv: str) -> PatchesT: @@ -48,11 +48,3 @@ def install_environment( helpers.run_setup_cmd( prefix, ('cpan', '-T', '.', *additional_dependencies), ) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index d9f779f7..93e2a65b 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -8,8 +8,8 @@ from typing import Pattern from typing import Sequence from pre_commit import output -from pre_commit.hook import Hook from pre_commit.languages import helpers +from pre_commit.prefix import Prefix from pre_commit.xargs import xargs ENVIRONMENT_DIR = None @@ -88,12 +88,16 @@ FNS = { def run_hook( - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: - exe = (sys.executable, '-m', __name__) + tuple(hook.args) + (hook.entry,) - return xargs(exe, file_args, color=color) + cmd = (sys.executable, '-m', __name__, *args, entry) + return xargs(cmd, file_args, color=color) def main(argv: Sequence[str] | None = None) -> int: diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 28f4ab5d..c373646b 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -12,7 +12,6 @@ from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix @@ -22,6 +21,7 @@ from pre_commit.util import cmd_output_b from pre_commit.util import win_exe ENVIRONMENT_DIR = 'py_env' +run_hook = helpers.basic_run_hook @functools.lru_cache(maxsize=None) @@ -212,11 +212,3 @@ def install_environment( cmd_output_b(*venv_cmd, cwd='/') with in_env(prefix, version): helpers.run_setup_cmd(prefix, install_cmd) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index f5e1eaba..7ed3eafc 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -10,7 +10,6 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b @@ -70,15 +69,15 @@ def _entry_validate(entry: list[str]) -> None: ) -def _cmd_from_hook(hook: Hook) -> tuple[str, ...]: - entry = shlex.split(hook.entry) - _entry_validate(entry) +def _cmd_from_hook( + prefix: Prefix, + entry: str, + args: Sequence[str], +) -> tuple[str, ...]: + cmd = shlex.split(entry) + _entry_validate(cmd) - return ( - entry[0], *RSCRIPT_OPTS, - *_prefix_if_file_entry(entry, hook.prefix), - *hook.args, - ) + return (cmd[0], *RSCRIPT_OPTS, *_prefix_if_file_entry(cmd, prefix), *args) def install_environment( @@ -149,10 +148,18 @@ def _inline_r_setup(code: str) -> str: def run_hook( - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: + cmd = _cmd_from_hook(prefix, entry, args) return helpers.run_xargs( - hook, _cmd_from_hook(hook), file_args, color=color, + cmd, + file_args, + require_serial=require_serial, + color=color, ) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 2805aca6..4416f728 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -13,7 +13,6 @@ from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError @@ -21,6 +20,7 @@ from pre_commit.util import resource_bytesio ENVIRONMENT_DIR = 'rbenv' health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook @functools.lru_cache(maxsize=1) @@ -133,11 +133,3 @@ def install_environment( *prefix.star('.gem'), *additional_dependencies, ), ) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 9da8f82c..391fd865 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -15,7 +15,6 @@ from pre_commit import parse_shebang from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b @@ -24,6 +23,7 @@ from pre_commit.util import win_exe ENVIRONMENT_DIR = 'rustenv' health_check = helpers.basic_health_check +run_hook = helpers.basic_run_hook @functools.lru_cache(maxsize=1) @@ -154,11 +154,3 @@ def install_environment( 'cargo', 'install', '--bins', '--root', envdir, *args, cwd=prefix.prefix_dir, ) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index 5b7bdd5f..41fffdf0 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -2,8 +2,8 @@ from __future__ import annotations from typing import Sequence -from pre_commit.hook import Hook from pre_commit.languages import helpers +from pre_commit.prefix import Prefix ENVIRONMENT_DIR = None get_default_version = helpers.basic_get_default_version @@ -13,9 +13,19 @@ in_env = helpers.no_env def run_hook( - hook: Hook, + prefix: Prefix, + entry: str, + args: Sequence[str], file_args: Sequence[str], + *, + require_serial: bool, color: bool, ) -> tuple[int, bytes]: - cmd = (hook.prefix.path(hook.cmd[0]), *hook.cmd[1:]) - return helpers.run_xargs(hook, cmd, file_args, color=color) + cmd = helpers.hook_cmd(entry, args) + cmd = (prefix.path(cmd[0]), *cmd[1:]) + return helpers.run_xargs( + cmd, + file_args, + require_serial=require_serial, + color=color, + ) diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index ad00b94a..c66ad5fb 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -8,16 +8,17 @@ from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.hook import Hook from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b +BUILD_DIR = '.build' +BUILD_CONFIG = 'release' + ENVIRONMENT_DIR = 'swift_env' get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check -BUILD_DIR = '.build' -BUILD_CONFIG = 'release' +run_hook = helpers.basic_run_hook def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover @@ -47,11 +48,3 @@ def install_environment( '-c', BUILD_CONFIG, '--build-path', os.path.join(envdir, BUILD_DIR), ) - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: # pragma: win32 no cover - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) diff --git a/pre_commit/languages/system.py b/pre_commit/languages/system.py index 9cc94f8c..204cad72 100644 --- a/pre_commit/languages/system.py +++ b/pre_commit/languages/system.py @@ -1,8 +1,5 @@ from __future__ import annotations -from typing import Sequence - -from pre_commit.hook import Hook from pre_commit.languages import helpers ENVIRONMENT_DIR = None @@ -10,11 +7,4 @@ get_default_version = helpers.basic_get_default_version health_check = helpers.basic_health_check install_environment = helpers.no_install in_env = helpers.no_env - - -def run_hook( - hook: Hook, - file_args: Sequence[str], - color: bool, -) -> tuple[int, bytes]: - return helpers.run_xargs(hook, hook.cmd, file_args, color=color) +run_hook = helpers.basic_run_hook diff --git a/tests/languages/helpers_test.py b/tests/languages/helpers_test.py index f333e79d..c209e7e6 100644 --- a/tests/languages/helpers_test.py +++ b/tests/languages/helpers_test.py @@ -12,7 +12,6 @@ from pre_commit import parse_shebang from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError -from testing.auto_namedtuple import auto_namedtuple @pytest.fixture @@ -94,31 +93,22 @@ def test_assert_no_additional_deps(): ) -SERIAL_FALSE = auto_namedtuple(require_serial=False) -SERIAL_TRUE = auto_namedtuple(require_serial=True) - - def test_target_concurrency_normal(): with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency(SERIAL_FALSE) == 123 - - -def test_target_concurrency_cpu_count_require_serial_true(): - with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency(SERIAL_TRUE) == 1 + assert helpers.target_concurrency() == 123 def test_target_concurrency_testing_env_var(): with mock.patch.dict( os.environ, {'PRE_COMMIT_NO_CONCURRENCY': '1'}, clear=True, ): - assert helpers.target_concurrency(SERIAL_FALSE) == 1 + assert helpers.target_concurrency() == 1 def test_target_concurrency_on_travis(): with mock.patch.dict(os.environ, {'TRAVIS': '1'}, clear=True): - assert helpers.target_concurrency(SERIAL_FALSE) == 2 + assert helpers.target_concurrency() == 2 def test_target_concurrency_cpu_count_not_implemented(): @@ -126,10 +116,20 @@ def test_target_concurrency_cpu_count_not_implemented(): multiprocessing, 'cpu_count', side_effect=NotImplementedError, ): with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency(SERIAL_FALSE) == 1 + assert helpers.target_concurrency() == 1 def test_shuffled_is_deterministic(): seq = [str(i) for i in range(10)] expected = ['4', '0', '5', '1', '8', '6', '2', '3', '7', '9'] assert helpers._shuffled(seq) == expected + + +def test_xargs_require_serial_is_not_shuffled(): + ret, out = helpers.run_xargs( + ('echo',), [str(i) for i in range(10)], + require_serial=True, + color=False, + ) + assert ret == 0 + assert out.strip() == b'0 1 2 3 4 5 6 7 8 9' diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index c653a3cc..d2344140 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -23,7 +23,7 @@ def _test_r_parsing( repo = make_repo(tempdir_factory, 'r_hooks_repo') config = make_config_from_repo(repo) hook = _get_hook_no_install(config, store, hook_id) - ret = r._cmd_from_hook(hook) + ret = r._cmd_from_hook(hook.prefix, hook.entry, hook.args) expected_path = os.path.join(hook.prefix.prefix_dir, f'{hook_id}.R') expected = ( 'Rscript', @@ -111,7 +111,7 @@ def test_r_parsing_file_local(tempdir_factory, store): }], } hook = _get_hook_no_install(config, store, 'local-r') - ret = r._cmd_from_hook(hook) + ret = r._cmd_from_hook(hook.prefix, hook.entry, hook.args) assert ret == ( 'Rscript', '--no-save', '--no-restore', '--no-site-file', '--no-environ', diff --git a/tests/repository_test.py b/tests/repository_test.py index 236c7983..4043491b 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -45,7 +45,14 @@ def _norm_out(b): def _hook_run(hook, filenames, color): with languages[hook.language].in_env(hook.prefix, hook.language_version): - return languages[hook.language].run_hook(hook, filenames, color) + return languages[hook.language].run_hook( + hook.prefix, + hook.entry, + hook.args, + filenames, + require_serial=hook.require_serial, + color=color, + ) def _get_hook_no_install(repo_config, store, hook_id): From 70bfd76ced283f48ab8c8a5f17e9218c0b0b5d37 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 16 Jan 2023 18:33:40 -0500 Subject: [PATCH 174/416] coursier: additional_dependencies support --- .github/actions/pre-test/action.yml | 1 + pre_commit/languages/coursier.py | 47 ++++++++++++------- testing/get-coursier.ps1 | 11 ----- testing/get-coursier.sh | 34 ++++++++++---- testing/language_helpers.py | 33 +++++++++++++ .../.pre-commit-channel/echo-java.json | 8 ---- .../.pre-commit-hooks.yaml | 5 -- testing/util.py | 4 -- tests/languages/coursier_test.py | 45 ++++++++++++++++++ tests/repository_test.py | 10 ---- 10 files changed, 132 insertions(+), 66 deletions(-) delete mode 100755 testing/get-coursier.ps1 create mode 100644 testing/language_helpers.py delete mode 100644 testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json delete mode 100644 testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml create mode 100644 tests/languages/coursier_test.py diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index a7bf0abe..608c0cd1 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -19,6 +19,7 @@ runs: echo 'C:\Strawberry\perl\site\bin' >> "$GITHUB_PATH" echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" + testing/get-coursier.sh testing/get-dart.sh - name: setup (linux) shell: bash diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index a6aea3fb..69c877d3 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -1,13 +1,14 @@ from __future__ import annotations import contextlib -import os +import os.path from typing import Generator from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var +from pre_commit.errors import FatalError from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix @@ -23,9 +24,8 @@ def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], -) -> None: # pragma: win32 no cover +) -> None: helpers.assert_version_default('coursier', version) - helpers.assert_no_additional_deps('coursier', additional_dependencies) # Support both possible executable names (either "cs" or "coursier") executable = find_executable('cs') or find_executable('coursier') @@ -37,29 +37,40 @@ def install_environment( envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) channel = prefix.path('.pre-commit-channel') - for app_descriptor in os.listdir(channel): - _, app_file = os.path.split(app_descriptor) - app, _ = os.path.splitext(app_file) - helpers.run_setup_cmd( - prefix, - ( - executable, - 'install', - '--default-channels=false', - f'--channel={channel}', - app, - f'--dir={envdir}', - ), + if os.path.isdir(channel): + for app_descriptor in os.listdir(channel): + _, app_file = os.path.split(app_descriptor) + app, _ = os.path.splitext(app_file) + helpers.run_setup_cmd( + prefix, + ( + executable, + 'install', + '--default-channels=false', + '--channel', channel, + '--dir', envdir, + app, + ), + ) + elif not additional_dependencies: + raise FatalError( + 'expected .pre-commit-channel dir or additional_dependencies', ) + if additional_dependencies: + install_cmd = ( + executable, 'install', '--dir', envdir, *additional_dependencies, + ) + helpers.run_setup_cmd(prefix, install_cmd) -def get_env_patch(target_dir: str) -> PatchesT: # pragma: win32 no cover + +def get_env_patch(target_dir: str) -> PatchesT: return ( ('PATH', (target_dir, os.pathsep, Var('PATH'))), ) -@contextlib.contextmanager # pragma: win32 no cover +@contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): diff --git a/testing/get-coursier.ps1 b/testing/get-coursier.ps1 deleted file mode 100755 index 42e56354..00000000 --- a/testing/get-coursier.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -$wc = New-Object System.Net.WebClient - -$coursier_url = "https://github.com/coursier/coursier/releases/download/v2.0.5/cs-x86_64-pc-win32.exe" -$coursier_dest = "C:\coursier\cs.exe" -$coursier_hash ="d63d497f7805261e1cd657b8aaa626f6b8f7264cdb68219b2e6be9dd882033a9" - -New-Item -Path "C:\" -Name "coursier" -ItemType "directory" -$wc.DownloadFile($coursier_url, $coursier_dest) -if ((Get-FileHash $coursier_dest -Algorithm SHA256).Hash -ne $coursier_hash) { - throw "Invalid coursier file" -} diff --git a/testing/get-coursier.sh b/testing/get-coursier.sh index 6033c3e3..958e73b2 100755 --- a/testing/get-coursier.sh +++ b/testing/get-coursier.sh @@ -1,15 +1,29 @@ #!/usr/bin/env bash -# This is a script used in CI to install coursier set -euo pipefail -COURSIER_URL="https://github.com/coursier/coursier/releases/download/v2.0.0/cs-x86_64-pc-linux" -COURSIER_HASH="e2e838b75bc71b16bcb77ce951ad65660c89bda7957c79a0628ec7146d35122f" -ARTIFACT="/tmp/coursier/cs" +if [ "$OSTYPE" = msys ]; then + URL='https://github.com/coursier/coursier/releases/download/v2.1.0-RC4/cs-x86_64-pc-win32.zip' + SHA256='0d07386ff0f337e3e6264f7dde29d137dda6eaa2385f29741435e0b93ccdb49d' + TARGET='/tmp/coursier/cs.zip' + + unpack() { + unzip "$TARGET" -d /tmp/coursier + mv /tmp/coursier/cs-*.exe /tmp/coursier/cs.exe + cygpath -w /tmp/coursier >> "$GITHUB_PATH" + } +else + URL='https://github.com/coursier/coursier/releases/download/v2.1.0-RC4/cs-x86_64-pc-linux.gz' + SHA256='176e92e08ab292531aa0c4993dbc9f2c99dec79578752f3b9285f54f306db572' + TARGET=/tmp/coursier/cs.gz + + unpack() { + gunzip "$TARGET" + chmod +x /tmp/coursier/cs + echo /tmp/coursier >> "$GITHUB_PATH" + } +fi mkdir -p /tmp/coursier -rm -f "$ARTIFACT" -curl --location --silent --output "$ARTIFACT" "$COURSIER_URL" -echo "$COURSIER_HASH $ARTIFACT" | sha256sum --check -chmod ugo+x /tmp/coursier/cs - -echo '/tmp/coursier' >> "$GITHUB_PATH" +curl --location --silent --output "$TARGET" "$URL" +echo "$SHA256 $TARGET" | sha256sum --check +unpack diff --git a/testing/language_helpers.py b/testing/language_helpers.py new file mode 100644 index 00000000..02e47a00 --- /dev/null +++ b/testing/language_helpers.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import os +from typing import Sequence + +import pre_commit.constants as C +from pre_commit.languages.all import Language +from pre_commit.prefix import Prefix + + +def run_language( + path: os.PathLike[str], + language: Language, + exe: str, + args: Sequence[str] = (), + file_args: Sequence[str] = (), + version: str = C.DEFAULT, + deps: Sequence[str] = (), +) -> tuple[int, bytes]: + prefix = Prefix(str(path)) + + language.install_environment(prefix, version, deps) + with language.in_env(prefix, version): + ret, out = language.run_hook( + prefix, + exe, + args, + file_args, + require_serial=True, + color=False, + ) + out = out.replace(b'\r\n', b'\n') + return ret, out diff --git a/testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json b/testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json deleted file mode 100644 index 37f401e2..00000000 --- a/testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "repositories": [ - "central" - ], - "dependencies": [ - "io.get-coursier:echo:latest.stable" - ] -} diff --git a/testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index d4a143b3..00000000 --- a/testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: echo-java - name: echo-java - description: echo from java - entry: echo-java - language: coursier diff --git a/testing/util.py b/testing/util.py index e807f048..324f1f6c 100644 --- a/testing/util.py +++ b/testing/util.py @@ -42,10 +42,6 @@ def cmd_output_mocked_pre_commit_home( return ret, out.replace('\r\n', '\n'), None -skipif_cant_run_coursier = pytest.mark.skipif( - os.name == 'nt' or parse_shebang.find_executable('cs') is None, - reason="coursier isn't installed or can't be found", -) skipif_cant_run_docker = pytest.mark.skipif( os.name == 'nt' or not docker_is_running(), reason="Docker isn't running or can't be accessed", diff --git a/tests/languages/coursier_test.py b/tests/languages/coursier_test.py new file mode 100644 index 00000000..dbb746ca --- /dev/null +++ b/tests/languages/coursier_test.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import pytest + +from pre_commit.errors import FatalError +from pre_commit.languages import coursier +from testing.language_helpers import run_language + + +def test_coursier_hook(tmp_path): + echo_java_json = '''\ +{ + "repositories": ["central"], + "dependencies": ["io.get-coursier:echo:latest.stable"] +} +''' + + channel_dir = tmp_path.joinpath('.pre-commit-channel') + channel_dir.mkdir() + channel_dir.joinpath('echo-java.json').write_text(echo_java_json) + + ret = run_language( + tmp_path, + coursier, + 'echo-java', + args=('Hello', 'World', 'from', 'coursier'), + ) + assert ret == (0, b'Hello World from coursier\n') + + +def test_coursier_hook_additional_dependencies(tmp_path): + ret = run_language( + tmp_path, + coursier, + 'scalafmt --version', + deps=('scalafmt:3.6.1',), + ) + assert ret == (0, b'scalafmt 3.6.1\n') + + +def test_error_if_no_deps_or_channel(tmp_path): + with pytest.raises(FatalError) as excinfo: + run_language(tmp_path, coursier, 'dne') + msg, = excinfo.value.args + assert msg == 'expected .pre-commit-channel dir or additional_dependencies' diff --git a/tests/repository_test.py b/tests/repository_test.py index 4043491b..5e4dff1e 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -32,7 +32,6 @@ from testing.fixtures import make_repo from testing.fixtures import modify_manifest from testing.util import cwd from testing.util import get_resource_path -from testing.util import skipif_cant_run_coursier from testing.util import skipif_cant_run_docker from testing.util import skipif_cant_run_lua from testing.util import skipif_cant_run_swift @@ -199,15 +198,6 @@ def test_language_versioned_python_hook(tempdir_factory, store): ) -@skipif_cant_run_coursier # pragma: win32 no cover -def test_run_a_coursier_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'coursier_hooks_repo', - 'echo-java', - ['Hello World from coursier'], b'Hello World from coursier\n', - ) - - @skipif_cant_run_docker # pragma: win32 no cover def test_run_a_docker_hook(tempdir_factory, store): _test_hook_repo( From f1b5f6637481704b687b2f3bbda49500af7849c1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 17 Jan 2023 11:39:48 -0500 Subject: [PATCH 175/416] test conda language directly --- pre_commit/store.py | 40 +++++++++--------- .../conda_hooks_repo/.pre-commit-hooks.yaml | 10 ----- .../conda_hooks_repo/environment.yml | 6 --- tests/languages/conda_test.py | 36 +++++++++++++++- tests/repository_test.py | 41 ------------------- tests/store_test.py | 3 +- 6 files changed, 57 insertions(+), 79 deletions(-) delete mode 100644 testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/conda_hooks_repo/environment.yml diff --git a/pre_commit/store.py b/pre_commit/store.py index e42cc489..6ddc7c48 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -36,6 +36,26 @@ def _get_default_directory() -> str: return os.path.realpath(ret) +_LOCAL_RESOURCES = ( + 'Cargo.toml', 'main.go', 'go.mod', 'main.rs', '.npmignore', + 'package.json', 'pre-commit-package-dev-1.rockspec', + 'pre_commit_placeholder_package.gemspec', 'setup.py', + 'environment.yml', 'Makefile.PL', 'pubspec.yaml', + 'renv.lock', 'renv/activate.R', 'renv/LICENSE.renv', +) + + +def _make_local_repo(directory: str) -> None: + for resource in _LOCAL_RESOURCES: + resource_dirname, resource_basename = os.path.split(resource) + contents = resource_text(f'empty_template_{resource_basename}') + target_dir = os.path.join(directory, resource_dirname) + target_file = os.path.join(target_dir, resource_basename) + os.makedirs(target_dir, exist_ok=True) + with open(target_file, 'w') as f: + f.write(contents) + + class Store: get_default_directory = staticmethod(_get_default_directory) @@ -185,27 +205,9 @@ class Store: return self._new_repo(repo, ref, deps, clone_strategy) - LOCAL_RESOURCES = ( - 'Cargo.toml', 'main.go', 'go.mod', 'main.rs', '.npmignore', - 'package.json', 'pre-commit-package-dev-1.rockspec', - 'pre_commit_placeholder_package.gemspec', 'setup.py', - 'environment.yml', 'Makefile.PL', 'pubspec.yaml', - 'renv.lock', 'renv/activate.R', 'renv/LICENSE.renv', - ) - def make_local(self, deps: Sequence[str]) -> str: - def make_local_strategy(directory: str) -> None: - for resource in self.LOCAL_RESOURCES: - resource_dirname, resource_basename = os.path.split(resource) - contents = resource_text(f'empty_template_{resource_basename}') - target_dir = os.path.join(directory, resource_dirname) - target_file = os.path.join(target_dir, resource_basename) - os.makedirs(target_dir, exist_ok=True) - with open(target_file, 'w') as f: - f.write(contents) - return self._new_repo( - 'local', C.LOCAL_REPO_VERSION, deps, make_local_strategy, + 'local', C.LOCAL_REPO_VERSION, deps, _make_local_repo, ) def _create_config_table(self, db: sqlite3.Connection) -> None: diff --git a/testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index a0d274c2..00000000 --- a/testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,10 +0,0 @@ -- id: sys-exec - name: sys-exec - entry: python -c 'import os; import sys; print(sys.executable.split(os.path.sep)[-2]) if os.name == "nt" else print(sys.executable.split(os.path.sep)[-3])' - language: conda - files: \.py$ -- id: additional-deps - name: additional-deps - entry: python - language: conda - files: \.py$ diff --git a/testing/resources/conda_hooks_repo/environment.yml b/testing/resources/conda_hooks_repo/environment.yml deleted file mode 100644 index e23c079f..00000000 --- a/testing/resources/conda_hooks_repo/environment.yml +++ /dev/null @@ -1,6 +0,0 @@ -channels: - - conda-forge - - defaults -dependencies: - - python - - pip diff --git a/tests/languages/conda_test.py b/tests/languages/conda_test.py index 5023b2af..83aaebed 100644 --- a/tests/languages/conda_test.py +++ b/tests/languages/conda_test.py @@ -1,9 +1,13 @@ from __future__ import annotations +import os.path + import pytest from pre_commit import envcontext -from pre_commit.languages.conda import _conda_exe +from pre_commit.languages import conda +from pre_commit.store import _make_local_repo +from testing.language_helpers import run_language @pytest.mark.parametrize( @@ -37,4 +41,32 @@ from pre_commit.languages.conda import _conda_exe ) def test_conda_exe(ctx, expected): with envcontext.envcontext(ctx): - assert _conda_exe() == expected + assert conda._conda_exe() == expected + + +def test_conda_language(tmp_path): + environment_yml = '''\ +channels: [conda-forge, defaults] +dependencies: [python, pip] +''' + tmp_path.joinpath('environment.yml').write_text(environment_yml) + + ret, out = run_language( + tmp_path, + conda, + 'python -c "import sys; print(sys.prefix)"', + ) + assert ret == 0 + assert os.path.basename(out.strip()) == b'conda-default' + + +def test_conda_additional_deps(tmp_path): + _make_local_repo(tmp_path) + + ret = run_language( + tmp_path, + conda, + 'python -c "import botocore; print(1)"', + deps=('botocore',), + ) + assert ret == (0, b'1\n') diff --git a/tests/repository_test.py b/tests/repository_test.py index 5e4dff1e..0bf27967 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -88,47 +88,6 @@ def _test_hook_repo( assert _norm_out(out) == expected -def test_conda_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'conda_hooks_repo', - 'sys-exec', [os.devnull], - b'conda-default\n', - ) - - -def test_conda_with_additional_dependencies_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'conda_hooks_repo', - 'additional-deps', [os.devnull], - b'OK\n', - config_kwargs={ - 'hooks': [{ - 'id': 'additional-deps', - 'args': ['-c', 'import tzdata; print("OK")'], - 'additional_dependencies': ['python-tzdata'], - }], - }, - ) - - -def test_local_conda_additional_dependencies(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'local-conda', - 'name': 'local-conda', - 'entry': 'python', - 'language': 'conda', - 'args': ['-c', 'import botocore; print("OK")'], - 'additional_dependencies': ['botocore'], - }], - } - hook = _get_hook(config, store, 'local-conda') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - assert _norm_out(out) == b'OK\n' - - def test_python_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'python_hooks_repo', diff --git a/tests/store_test.py b/tests/store_test.py index 81877662..c42ce653 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -9,6 +9,7 @@ import pytest from pre_commit import git from pre_commit.store import _get_default_directory +from pre_commit.store import _LOCAL_RESOURCES from pre_commit.store import Store from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output @@ -188,7 +189,7 @@ def test_local_resources_reflects_reality(): for res in os.listdir('pre_commit/resources') if res.startswith('empty_template_') } - assert on_disk == {os.path.basename(x) for x in Store.LOCAL_RESOURCES} + assert on_disk == {os.path.basename(x) for x in _LOCAL_RESOURCES} def test_mark_config_as_used(store, tmpdir): From c36f03cd2e8ae948b35516affa8a4b71c6fd3289 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 16 Jan 2023 17:10:58 -0500 Subject: [PATCH 176/416] test swift language directly --- testing/resources/swift_hooks_repo/.gitignore | 4 --- .../swift_hooks_repo/.pre-commit-hooks.yaml | 6 ---- .../resources/swift_hooks_repo/Package.swift | 7 ----- .../Sources/swift_hooks_repo/main.swift | 1 - testing/util.py | 5 --- tests/languages/swift_test.py | 31 +++++++++++++++++++ tests/repository_test.py | 9 ------ 7 files changed, 31 insertions(+), 32 deletions(-) delete mode 100644 testing/resources/swift_hooks_repo/.gitignore delete mode 100644 testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/swift_hooks_repo/Package.swift delete mode 100644 testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift create mode 100644 tests/languages/swift_test.py diff --git a/testing/resources/swift_hooks_repo/.gitignore b/testing/resources/swift_hooks_repo/.gitignore deleted file mode 100644 index 02c08753..00000000 --- a/testing/resources/swift_hooks_repo/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj diff --git a/testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index c08df87d..00000000 --- a/testing/resources/swift_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- id: swift-hooks-repo - name: Swift hooks repo example - description: Runs the hello world app generated by swift package init --type executable (binary called swift_hooks_repo here) - entry: swift_hooks_repo - language: swift - files: \.(swift)$ diff --git a/testing/resources/swift_hooks_repo/Package.swift b/testing/resources/swift_hooks_repo/Package.swift deleted file mode 100644 index 04976d3f..00000000 --- a/testing/resources/swift_hooks_repo/Package.swift +++ /dev/null @@ -1,7 +0,0 @@ -// swift-tools-version:5.0 -import PackageDescription - -let package = Package( - name: "swift_hooks_repo", - targets: [.target(name: "swift_hooks_repo")] -) diff --git a/testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift b/testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift deleted file mode 100644 index f7cf60e1..00000000 --- a/testing/resources/swift_hooks_repo/Sources/swift_hooks_repo/main.swift +++ /dev/null @@ -1 +0,0 @@ -print("Hello, world!") diff --git a/testing/util.py b/testing/util.py index 324f1f6c..a5ae06d0 100644 --- a/testing/util.py +++ b/testing/util.py @@ -6,7 +6,6 @@ import subprocess import pytest -from pre_commit import parse_shebang from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b @@ -50,10 +49,6 @@ skipif_cant_run_lua = pytest.mark.skipif( os.name == 'nt', reason="lua isn't installed or can't be found", ) -skipif_cant_run_swift = pytest.mark.skipif( - parse_shebang.find_executable('swift') is None, - reason="swift isn't installed or can't be found", -) xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows') diff --git a/tests/languages/swift_test.py b/tests/languages/swift_test.py new file mode 100644 index 00000000..e0a8ea42 --- /dev/null +++ b/tests/languages/swift_test.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import sys + +import pytest + +from pre_commit.languages import swift +from testing.language_helpers import run_language + + +@pytest.mark.skipif( + sys.platform == 'win32', + reason='swift is not supported on windows', +) +def test_swift_language(tmp_path): # pragma: win32 no cover + package_swift = '''\ +// swift-tools-version:5.0 +import PackageDescription + +let package = Package( + name: "swift_hooks_repo", + targets: [.target(name: "swift_hooks_repo")] +) +''' + tmp_path.joinpath('Package.swift').write_text(package_swift) + src_dir = tmp_path.joinpath('Sources/swift_hooks_repo') + src_dir.mkdir(parents=True) + src_dir.joinpath('main.swift').write_text('print("Hello, world!")\n') + + expected = (0, b'Hello, world!\n') + assert run_language(tmp_path, swift, 'swift_hooks_repo') == expected diff --git a/tests/repository_test.py b/tests/repository_test.py index 0bf27967..fc276984 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -34,7 +34,6 @@ from testing.util import cwd from testing.util import get_resource_path from testing.util import skipif_cant_run_docker from testing.util import skipif_cant_run_lua -from testing.util import skipif_cant_run_swift from testing.util import xfailif_windows @@ -329,14 +328,6 @@ def test_system_hook_with_spaces(tempdir_factory, store): ) -@skipif_cant_run_swift # pragma: win32 no cover -def test_swift_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'swift_hooks_repo', - 'swift-hooks-repo', [], b'Hello, world!\n', - ) - - def test_golang_system_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'golang_hooks_repo', From 966c67a8321e301d844f776cb438c4b5808abbc6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 17 Jan 2023 14:16:13 -0500 Subject: [PATCH 177/416] speed up R unit tests --- pre_commit/languages/r.py | 2 +- .../r_hooks_repo/.pre-commit-hooks.yaml | 23 ---- tests/languages/r_test.py | 117 +++++++----------- 3 files changed, 44 insertions(+), 98 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 7ed3eafc..dc398605 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -64,7 +64,7 @@ def _entry_validate(entry: list[str]) -> None: raise ValueError('You can supply at most one expression.') elif len(entry) > 2: raise ValueError( - 'The only valid syntax is `Rscript -e {expr}`', + 'The only valid syntax is `Rscript -e {expr}`' 'or `Rscript path/to/hook/script`', ) diff --git a/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml index b3545d96..ef46cc0a 100644 --- a/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml +++ b/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml @@ -1,26 +1,3 @@ -# parsing file -- id: parse-file-no-opts-no-args - name: Say hi - entry: Rscript parse-file-no-opts-no-args.R - language: r - types: [r] -- id: parse-file-no-opts-args - name: Say hi - entry: Rscript parse-file-no-opts-args.R - args: [--no-cache] - language: r - types: [r] -## parsing expr -- id: parse-expr-no-opts-no-args-1 - name: Say hi - entry: Rscript -e '1+1' - language: r - types: [r] -- id: parse-expr-args-in-entry-2 - name: Say hi - entry: Rscript -e '1+1' -e '3' --no-cache3 - language: r - types: [r] # real world - id: hello-world name: Say hi diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index d2344140..0c5e5638 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -6,117 +6,86 @@ import pytest from pre_commit import envcontext from pre_commit.languages import r +from pre_commit.prefix import Prefix from pre_commit.util import win_exe -from testing.fixtures import make_config_from_repo -from testing.fixtures import make_repo -from tests.repository_test import _get_hook_no_install -def _test_r_parsing( - tempdir_factory, - store, - hook_id, - expected_hook_expr=(), - expected_args=(), - config=None, -): - repo = make_repo(tempdir_factory, 'r_hooks_repo') - config = make_config_from_repo(repo) - hook = _get_hook_no_install(config, store, hook_id) - ret = r._cmd_from_hook(hook.prefix, hook.entry, hook.args) - expected_path = os.path.join(hook.prefix.prefix_dir, f'{hook_id}.R') - expected = ( +def test_r_parsing_file_no_opts_no_args(tmp_path): + cmd = r._cmd_from_hook(Prefix(str(tmp_path)), 'Rscript some-script.R', ()) + assert cmd == ( 'Rscript', '--no-save', '--no-restore', '--no-site-file', '--no-environ', - *(expected_hook_expr or (expected_path,)), - *expected_args, + str(tmp_path.joinpath('some-script.R')), ) - assert ret == expected -def test_r_parsing_file_no_opts_no_args(tempdir_factory, store): - hook_id = 'parse-file-no-opts-no-args' - _test_r_parsing(tempdir_factory, store, hook_id) - - -def test_r_parsing_file_opts_no_args(tempdir_factory, store): +def test_r_parsing_file_opts_no_args(): with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '--no-init', '/path/to/file']) - msg = excinfo.value.args + msg, = excinfo.value.args assert msg == ( - 'The only valid syntax is `Rscript -e {expr}`', - 'or `Rscript path/to/hook/script`', + 'The only valid syntax is `Rscript -e {expr}`' + 'or `Rscript path/to/hook/script`' ) -def test_r_parsing_file_no_opts_args(tempdir_factory, store): - hook_id = 'parse-file-no-opts-args' - expected_args = ['--no-cache'] - _test_r_parsing( - tempdir_factory, store, hook_id, expected_args=expected_args, +def test_r_parsing_file_no_opts_args(tmp_path): + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + 'Rscript some-script.R', + ('--no-cache',), + ) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + str(tmp_path.joinpath('some-script.R')), + '--no-cache', ) -def test_r_parsing_expr_no_opts_no_args1(tempdir_factory, store): - hook_id = 'parse-expr-no-opts-no-args-1' - _test_r_parsing( - tempdir_factory, store, hook_id, expected_hook_expr=('-e', '1+1'), +def test_r_parsing_expr_no_opts_no_args1(tmp_path): + cmd = r._cmd_from_hook(Prefix(str(tmp_path)), "Rscript -e '1+1'", ()) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + '-e', '1+1', ) -def test_r_parsing_expr_no_opts_no_args2(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_no_opts_no_args2(): + with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '-e', '1+1', '-e', 'letters']) - msg = execinfo.value.args - assert msg == ('You can supply at most one expression.',) + msg, = excinfo.value.args + assert msg == 'You can supply at most one expression.' -def test_r_parsing_expr_opts_no_args2(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_opts_no_args2(): + with pytest.raises(ValueError) as excinfo: r._entry_validate( ['Rscript', '--vanilla', '-e', '1+1', '-e', 'letters'], ) - msg = execinfo.value.args + msg, = excinfo.value.args assert msg == ( - 'The only valid syntax is `Rscript -e {expr}`', - 'or `Rscript path/to/hook/script`', + 'The only valid syntax is `Rscript -e {expr}`' + 'or `Rscript path/to/hook/script`' ) -def test_r_parsing_expr_args_in_entry2(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_args_in_entry2(): + with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '-e', 'expr1', '--another-arg']) - msg = execinfo.value.args - assert msg == ('You can supply at most one expression.',) + msg, = excinfo.value.args + assert msg == 'You can supply at most one expression.' -def test_r_parsing_expr_non_Rscirpt(tempdir_factory, store): - with pytest.raises(ValueError) as execinfo: +def test_r_parsing_expr_non_Rscirpt(): + with pytest.raises(ValueError) as excinfo: r._entry_validate(['AnotherScript', '-e', '{{}}']) - msg = execinfo.value.args - assert msg == ('entry must start with `Rscript`.',) - - -def test_r_parsing_file_local(tempdir_factory, store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'local-r', - 'name': 'local-r', - 'entry': 'Rscript path/to/script.R', - 'language': 'r', - }], - } - hook = _get_hook_no_install(config, store, 'local-r') - ret = r._cmd_from_hook(hook.prefix, hook.entry, hook.args) - assert ret == ( - 'Rscript', - '--no-save', '--no-restore', '--no-site-file', '--no-environ', - hook.prefix.path('path/to/script.R'), - ) + msg, = excinfo.value.args + assert msg == 'entry must start with `Rscript`.' def test_rscript_exec_relative_to_r_home(): From d24055cb40a4473754cb7560408a2c15544b387b Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 17 Jan 2023 17:34:04 -0500 Subject: [PATCH 178/416] test perl language directly --- testing/resources/perl_hooks_repo/.gitignore | 7 -- .../perl_hooks_repo/.pre-commit-hooks.yaml | 5 -- testing/resources/perl_hooks_repo/MANIFEST | 4 -- testing/resources/perl_hooks_repo/Makefile.PL | 10 --- .../perl_hooks_repo/bin/pre-commit-perl-hello | 7 -- .../perl_hooks_repo/lib/PreCommitHello.pm | 12 ---- tests/languages/perl_test.py | 69 +++++++++++++++++++ tests/repository_test.py | 24 ------- 8 files changed, 69 insertions(+), 69 deletions(-) delete mode 100644 testing/resources/perl_hooks_repo/.gitignore delete mode 100644 testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/perl_hooks_repo/MANIFEST delete mode 100644 testing/resources/perl_hooks_repo/Makefile.PL delete mode 100755 testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello delete mode 100644 testing/resources/perl_hooks_repo/lib/PreCommitHello.pm create mode 100644 tests/languages/perl_test.py diff --git a/testing/resources/perl_hooks_repo/.gitignore b/testing/resources/perl_hooks_repo/.gitignore deleted file mode 100644 index 7af99404..00000000 --- a/testing/resources/perl_hooks_repo/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/MYMETA.json -/MYMETA.yml -/Makefile -/PreCommitHello-*.tar.* -/PreCommitHello-*/ -/blib/ -/pm_to_blib diff --git a/testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 11e6f6cd..00000000 --- a/testing/resources/perl_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: perl-hook - name: perl example hook - entry: pre-commit-perl-hello - language: perl - files: '' diff --git a/testing/resources/perl_hooks_repo/MANIFEST b/testing/resources/perl_hooks_repo/MANIFEST deleted file mode 100644 index 4a20084c..00000000 --- a/testing/resources/perl_hooks_repo/MANIFEST +++ /dev/null @@ -1,4 +0,0 @@ -MANIFEST -Makefile.PL -bin/pre-commit-perl-hello -lib/PreCommitHello.pm diff --git a/testing/resources/perl_hooks_repo/Makefile.PL b/testing/resources/perl_hooks_repo/Makefile.PL deleted file mode 100644 index 6c70e107..00000000 --- a/testing/resources/perl_hooks_repo/Makefile.PL +++ /dev/null @@ -1,10 +0,0 @@ -use strict; -use warnings; - -use ExtUtils::MakeMaker; - -WriteMakefile( - NAME => "PreCommitHello", - VERSION_FROM => "lib/PreCommitHello.pm", - EXE_FILES => [qw(bin/pre-commit-perl-hello)], -); diff --git a/testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello b/testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello deleted file mode 100755 index 9474009a..00000000 --- a/testing/resources/perl_hooks_repo/bin/pre-commit-perl-hello +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use PreCommitHello; - -PreCommitHello::hello(); diff --git a/testing/resources/perl_hooks_repo/lib/PreCommitHello.pm b/testing/resources/perl_hooks_repo/lib/PreCommitHello.pm deleted file mode 100644 index c76521ce..00000000 --- a/testing/resources/perl_hooks_repo/lib/PreCommitHello.pm +++ /dev/null @@ -1,12 +0,0 @@ -package PreCommitHello; - -use strict; -use warnings; - -our $VERSION = "0.1.0"; - -sub hello { - print "Hello from perl-commit Perl!\n"; -} - -1; diff --git a/tests/languages/perl_test.py b/tests/languages/perl_test.py new file mode 100644 index 00000000..042478db --- /dev/null +++ b/tests/languages/perl_test.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from pre_commit.languages import perl +from pre_commit.store import _make_local_repo +from pre_commit.util import make_executable +from testing.language_helpers import run_language + + +def test_perl_install(tmp_path): + makefile_pl = '''\ +use strict; +use warnings; + +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => "PreCommitHello", + VERSION_FROM => "lib/PreCommitHello.pm", + EXE_FILES => [qw(bin/pre-commit-perl-hello)], +); +''' + bin_perl_hello = '''\ +#!/usr/bin/env perl + +use strict; +use warnings; +use PreCommitHello; + +PreCommitHello::hello(); +''' + lib_hello_pm = '''\ +package PreCommitHello; + +use strict; +use warnings; + +our $VERSION = "0.1.0"; + +sub hello { + print "Hello from perl-commit Perl!\n"; +} + +1; +''' + tmp_path.joinpath('Makefile.PL').write_text(makefile_pl) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + exe = bin_dir.joinpath('pre-commit-perl-hello') + exe.write_text(bin_perl_hello) + make_executable(exe) + lib_dir = tmp_path.joinpath('lib') + lib_dir.mkdir() + lib_dir.joinpath('PreCommitHello.pm').write_text(lib_hello_pm) + + ret = run_language(tmp_path, perl, 'pre-commit-perl-hello') + assert ret == (0, b'Hello from perl-commit Perl!\n') + + +def test_perl_additional_dependencies(tmp_path): + _make_local_repo(str(tmp_path)) + + ret, out = run_language( + tmp_path, + perl, + 'perltidy --version', + deps=('SHANCOCK/Perl-Tidy-20211029.tar.gz',), + ) + assert ret == 0 + assert out.startswith(b'This is perltidy, v20211029') diff --git a/tests/repository_test.py b/tests/repository_test.py index fc276984..2389c448 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -981,30 +981,6 @@ def test_manifest_hooks(tempdir_factory, store): ) -def test_perl_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'perl_hooks_repo', - 'perl-hook', [], b'Hello from perl-commit Perl!\n', - ) - - -def test_local_perl_additional_dependencies(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'hello', - 'name': 'hello', - 'entry': 'perltidy --version', - 'language': 'perl', - 'additional_dependencies': ['SHANCOCK/Perl-Tidy-20211029.tar.gz'], - }], - } - hook = _get_hook(config, store, 'hello') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - assert _norm_out(out).startswith(b'This is perltidy, v20211029') - - @pytest.mark.parametrize( 'repo', ( From 043565d28a0cccda9892baa414ee52c2f5b61372 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 17 Jan 2023 18:44:14 -0500 Subject: [PATCH 179/416] test dart directly --- .../dart_repo/.pre-commit-hooks.yaml | 4 -- .../dart_repo/bin/hello-world-dart.dart | 6 -- testing/resources/dart_repo/pubspec.yaml | 10 --- tests/languages/dart_test.py | 62 +++++++++++++++++++ tests/repository_test.py | 40 ------------ 5 files changed, 62 insertions(+), 60 deletions(-) delete mode 100644 testing/resources/dart_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/dart_repo/bin/hello-world-dart.dart delete mode 100644 testing/resources/dart_repo/pubspec.yaml create mode 100644 tests/languages/dart_test.py diff --git a/testing/resources/dart_repo/.pre-commit-hooks.yaml b/testing/resources/dart_repo/.pre-commit-hooks.yaml deleted file mode 100644 index e0dc5a2a..00000000 --- a/testing/resources/dart_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,4 +0,0 @@ -- id: hello-world-dart - name: hello world dart - entry: hello-world-dart - language: dart diff --git a/testing/resources/dart_repo/bin/hello-world-dart.dart b/testing/resources/dart_repo/bin/hello-world-dart.dart deleted file mode 100644 index 5d8d6a6a..00000000 --- a/testing/resources/dart_repo/bin/hello-world-dart.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:ansicolor/ansicolor.dart'; - -void main() { - AnsiPen pen = new AnsiPen()..red(); - print("hello hello " + pen("world")); -} diff --git a/testing/resources/dart_repo/pubspec.yaml b/testing/resources/dart_repo/pubspec.yaml deleted file mode 100644 index bc719d05..00000000 --- a/testing/resources/dart_repo/pubspec.yaml +++ /dev/null @@ -1,10 +0,0 @@ -environment: - sdk: '>=2.10.0 <3.0.0' - -name: hello_world_dart - -executables: - hello-world-dart: - -dependencies: - ansicolor: ^2.0.1 diff --git a/tests/languages/dart_test.py b/tests/languages/dart_test.py new file mode 100644 index 00000000..5bb5aa68 --- /dev/null +++ b/tests/languages/dart_test.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +import re_assert + +from pre_commit.languages import dart +from pre_commit.store import _make_local_repo +from testing.language_helpers import run_language + + +def test_dart(tmp_path): + pubspec_yaml = '''\ +environment: + sdk: '>=2.10.0 <3.0.0' + +name: hello_world_dart + +executables: + hello-world-dart: + +dependencies: + ansicolor: ^2.0.1 +''' + hello_world_dart_dart = '''\ +import 'package:ansicolor/ansicolor.dart'; + +void main() { + AnsiPen pen = new AnsiPen()..red(); + print("hello hello " + pen("world")); +} +''' + tmp_path.joinpath('pubspec.yaml').write_text(pubspec_yaml) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + bin_dir.joinpath('hello-world-dart.dart').write_text(hello_world_dart_dart) + + expected = (0, b'hello hello world\n') + assert run_language(tmp_path, dart, 'hello-world-dart') == expected + + +def test_dart_additional_deps(tmp_path): + _make_local_repo(str(tmp_path)) + + ret = run_language( + tmp_path, + dart, + 'hello-world-dart', + deps=('hello_world_dart',), + ) + assert ret == (0, b'hello hello world\n') + + +def test_dart_additional_deps_versioned(tmp_path): + _make_local_repo(str(tmp_path)) + + ret, out = run_language( + tmp_path, + dart, + 'secure-random -l 4 -b 16', + deps=('encrypt:5.0.0',), + ) + assert ret == 0 + re_assert.Matches('^[a-f0-9]{8}\n$').assert_matches(out.decode()) diff --git a/tests/repository_test.py b/tests/repository_test.py index 2389c448..0d01f0f6 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -997,46 +997,6 @@ def test_dotnet_hook(tempdir_factory, store, repo): ) -def test_dart_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'dart_repo', - 'hello-world-dart', [], b'hello hello world\n', - ) - - -def test_local_dart_additional_dependencies(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'local-dart', - 'name': 'local-dart', - 'entry': 'hello-world-dart', - 'language': 'dart', - 'additional_dependencies': ['hello_world_dart'], - }], - } - hook = _get_hook(config, store, 'local-dart') - ret, out = _hook_run(hook, (), color=False) - assert (ret, _norm_out(out)) == (0, b'hello hello world\n') - - -def test_local_dart_additional_dependencies_versioned(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'local-dart', - 'name': 'local-dart', - 'entry': 'secure-random -l 4 -b 16', - 'language': 'dart', - 'additional_dependencies': ['encrypt:5.0.0'], - }], - } - hook = _get_hook(config, store, 'local-dart') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - re_assert.Matches('^[a-f0-9]{8}\r?\n$').assert_matches(out.decode()) - - def test_non_installable_hook_error_for_language_version(store, caplog): config = { 'repo': 'local', From 7512e3b7e1d367464a3b8acad63166a1e55119d1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 17 Jan 2023 23:25:00 -0500 Subject: [PATCH 180/416] test r language directly --- .../r_hooks_repo/.pre-commit-hooks.yaml | 25 - testing/resources/r_hooks_repo/DESCRIPTION | 19 - .../resources/r_hooks_repo/additional-deps.R | 2 - testing/resources/r_hooks_repo/hello-world.R | 5 - testing/resources/r_hooks_repo/renv.lock | 27 -- testing/resources/r_hooks_repo/renv/LICENSE | 7 - .../resources/r_hooks_repo/renv/activate.R | 440 ------------------ tests/languages/r_test.py | 99 ++++ tests/repository_test.py | 48 -- 9 files changed, 99 insertions(+), 573 deletions(-) delete mode 100644 testing/resources/r_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/r_hooks_repo/DESCRIPTION delete mode 100755 testing/resources/r_hooks_repo/additional-deps.R delete mode 100755 testing/resources/r_hooks_repo/hello-world.R delete mode 100644 testing/resources/r_hooks_repo/renv.lock delete mode 100644 testing/resources/r_hooks_repo/renv/LICENSE delete mode 100644 testing/resources/r_hooks_repo/renv/activate.R diff --git a/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index ef46cc0a..00000000 --- a/testing/resources/r_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# real world -- id: hello-world - name: Say hi - entry: Rscript hello-world.R - args: [blibla] - language: r - types: [r] -- id: hello-world-inline - name: Say hi - entry: | - Rscript -e - 'stopifnot( - packageVersion("rprojroot") == "1.0", - packageVersion("gli.clu") == "0.0.0.9000" - ) - cat(commandArgs(trailingOnly = TRUE), "from R!\n", sep = ", ") - ' - args: ['Hi-there'] - language: r - types: [r] -- id: additional-deps - name: Check additional deps - entry: Rscript additional-deps.R - language: r - types: [r] diff --git a/testing/resources/r_hooks_repo/DESCRIPTION b/testing/resources/r_hooks_repo/DESCRIPTION deleted file mode 100644 index 0e597a8a..00000000 --- a/testing/resources/r_hooks_repo/DESCRIPTION +++ /dev/null @@ -1,19 +0,0 @@ -Package: gli.clu -Title: What the Package Does (One Line, Title Case) -Type: Package -Version: 0.0.0.9000 -Authors@R: - person(given = "First", - family = "Last", - role = c("aut", "cre"), - email = "first.last@example.com", - comment = c(ORCID = "YOUR-ORCID-ID")) -Description: What the package does (one paragraph). -License: `use_mit_license()`, `use_gpl3_license()` or friends to - pick a license -Encoding: UTF-8 -LazyData: true -Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.1 -Imports: - rprojroot diff --git a/testing/resources/r_hooks_repo/additional-deps.R b/testing/resources/r_hooks_repo/additional-deps.R deleted file mode 100755 index bc145951..00000000 --- a/testing/resources/r_hooks_repo/additional-deps.R +++ /dev/null @@ -1,2 +0,0 @@ -suppressPackageStartupMessages(library("cachem")) -cat("OK\n") diff --git a/testing/resources/r_hooks_repo/hello-world.R b/testing/resources/r_hooks_repo/hello-world.R deleted file mode 100755 index bf8d92f4..00000000 --- a/testing/resources/r_hooks_repo/hello-world.R +++ /dev/null @@ -1,5 +0,0 @@ -stopifnot( - packageVersion('rprojroot') == '1.0', - packageVersion('gli.clu') == '0.0.0.9000' -) -cat("Hello, World, from R!\n") diff --git a/testing/resources/r_hooks_repo/renv.lock b/testing/resources/r_hooks_repo/renv.lock deleted file mode 100644 index d7d5fdcc..00000000 --- a/testing/resources/r_hooks_repo/renv.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "R": { - "Version": "4.0.3", - "Repositories": [ - { - "Name": "CRAN", - "URL": "https://cloud.r-project.org" - } - ] - }, - "Packages": { - "renv": { - "Package": "renv", - "Version": "0.12.5", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5c0cdb37f063c58cdab3c7e9fbb8bd2c" - }, - "rprojroot": { - "Package": "rprojroot", - "Version": "1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "86704667fe0860e4fec35afdfec137f3" - } - } -} diff --git a/testing/resources/r_hooks_repo/renv/LICENSE b/testing/resources/r_hooks_repo/renv/LICENSE deleted file mode 100644 index 253c5d1a..00000000 --- a/testing/resources/r_hooks_repo/renv/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2021 RStudio, PBC - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/testing/resources/r_hooks_repo/renv/activate.R b/testing/resources/r_hooks_repo/renv/activate.R deleted file mode 100644 index d8d092cc..00000000 --- a/testing/resources/r_hooks_repo/renv/activate.R +++ /dev/null @@ -1,440 +0,0 @@ - -local({ - - # the requested version of renv - version <- "0.12.5" - - # the project directory - project <- getwd() - - # avoid recursion - if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) - return(invisible(TRUE)) - - # signal that we're loading renv during R startup - Sys.setenv("RENV_R_INITIALIZING" = "true") - on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) - - # signal that we've consented to use renv - options(renv.consent = TRUE) - - # load the 'utils' package eagerly -- this ensures that renv shims, which - # mask 'utils' packages, will come first on the search path - library(utils, lib.loc = .Library) - - # check to see if renv has already been loaded - if ("renv" %in% loadedNamespaces()) { - - # if renv has already been loaded, and it's the requested version of renv, - # nothing to do - spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") - if (identical(spec[["version"]], version)) - return(invisible(TRUE)) - - # otherwise, unload and attempt to load the correct version of renv - unloadNamespace("renv") - - } - - # load bootstrap tools - bootstrap <- function(version, library) { - - # attempt to download renv - tarball <- tryCatch(renv_bootstrap_download(version), error = identity) - if (inherits(tarball, "error")) - stop("failed to download renv ", version) - - # now attempt to install - status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) - if (inherits(status, "error")) - stop("failed to install renv ", version) - - } - - renv_bootstrap_tests_running <- function() { - getOption("renv.tests.running", default = FALSE) - } - - renv_bootstrap_repos <- function() { - - # check for repos override - repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) - if (!is.na(repos)) - return(repos) - - # if we're testing, re-use the test repositories - if (renv_bootstrap_tests_running()) - return(getOption("renv.tests.repos")) - - # retrieve current repos - repos <- getOption("repos") - - # ensure @CRAN@ entries are resolved - repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" - - # add in renv.bootstrap.repos if set - default <- c(CRAN = "https://cloud.r-project.org") - extra <- getOption("renv.bootstrap.repos", default = default) - repos <- c(repos, extra) - - # remove duplicates that might've snuck in - dupes <- duplicated(repos) | duplicated(names(repos)) - repos[!dupes] - - } - - renv_bootstrap_download <- function(version) { - - # if the renv version number has 4 components, assume it must - # be retrieved via github - nv <- numeric_version(version) - components <- unclass(nv)[[1]] - - methods <- if (length(components) == 4L) { - list( - renv_bootstrap_download_github - ) - } else { - list( - renv_bootstrap_download_cran_latest, - renv_bootstrap_download_cran_archive - ) - } - - for (method in methods) { - path <- tryCatch(method(version), error = identity) - if (is.character(path) && file.exists(path)) - return(path) - } - - stop("failed to download renv ", version) - - } - - renv_bootstrap_download_impl <- function(url, destfile) { - - mode <- "wb" - - # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 - fixup <- - Sys.info()[["sysname"]] == "Windows" && - substring(url, 1L, 5L) == "file:" - - if (fixup) - mode <- "w+b" - - utils::download.file( - url = url, - destfile = destfile, - mode = mode, - quiet = TRUE - ) - - } - - renv_bootstrap_download_cran_latest <- function(version) { - - repos <- renv_bootstrap_download_cran_latest_find(version) - - message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE) - - info <- tryCatch( - utils::download.packages( - pkgs = "renv", - repos = repos, - destdir = tempdir(), - quiet = TRUE - ), - condition = identity - ) - - if (inherits(info, "condition")) { - message("FAILED") - return(FALSE) - } - - message("OK") - info[1, 2] - - } - - renv_bootstrap_download_cran_latest_find <- function(version) { - - all <- renv_bootstrap_repos() - - for (repos in all) { - - db <- tryCatch( - as.data.frame( - x = utils::available.packages(repos = repos), - stringsAsFactors = FALSE - ), - error = identity - ) - - if (inherits(db, "error")) - next - - entry <- db[db$Package %in% "renv" & db$Version %in% version, ] - if (nrow(entry) == 0) - next - - return(repos) - - } - - fmt <- "renv %s is not available from your declared package repositories" - stop(sprintf(fmt, version)) - - } - - renv_bootstrap_download_cran_archive <- function(version) { - - name <- sprintf("renv_%s.tar.gz", version) - repos <- renv_bootstrap_repos() - urls <- file.path(repos, "src/contrib/Archive/renv", name) - destfile <- file.path(tempdir(), name) - - message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE) - - for (url in urls) { - - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (identical(status, 0L)) { - message("OK") - return(destfile) - } - - } - - message("FAILED") - return(FALSE) - - } - - renv_bootstrap_download_github <- function(version) { - - enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") - if (!identical(enabled, "TRUE")) - return(FALSE) - - # prepare download options - pat <- Sys.getenv("GITHUB_PAT") - if (nzchar(Sys.which("curl")) && nzchar(pat)) { - fmt <- "--location --fail --header \"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "curl", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { - fmt <- "--header=\"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "wget", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } - - message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) - - url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) - name <- sprintf("renv_%s.tar.gz", version) - destfile <- file.path(tempdir(), name) - - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (!identical(status, 0L)) { - message("FAILED") - return(FALSE) - } - - message("OK") - return(destfile) - - } - - renv_bootstrap_install <- function(version, tarball, library) { - - # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(library, showWarnings = FALSE, recursive = TRUE) - - # invoke using system2 so we can capture and report output - bin <- R.home("bin") - exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) - args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball)) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - header <- "Error installing renv:" - lines <- paste(rep.int("=", nchar(header)), collapse = "") - text <- c(header, lines, output) - writeLines(text, con = stderr()) - } - - status - - } - - renv_bootstrap_prefix <- function() { - - # construct version prefix - version <- paste(R.version$major, R.version$minor, sep = ".") - prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") - - # include SVN revision for development versions of R - # (to avoid sharing platform-specific artefacts with released versions of R) - devel <- - identical(R.version[["status"]], "Under development (unstable)") || - identical(R.version[["nickname"]], "Unsuffered Consequences") - - if (devel) - prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - - # build list of path components - components <- c(prefix, R.version$platform) - - # include prefix if provided by user - prefix <- Sys.getenv("RENV_PATHS_PREFIX") - if (nzchar(prefix)) - components <- c(prefix, components) - - # build prefix - paste(components, collapse = "/") - - } - - renv_bootstrap_library_root_name <- function(project) { - - # use project name as-is if requested - asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") - if (asis) - return(basename(project)) - - # otherwise, disambiguate based on project's path - id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) - paste(basename(project), id, sep = "-") - - } - - renv_bootstrap_library_root <- function(project) { - - path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) - if (!is.na(path)) - return(path) - - path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) - if (!is.na(path)) { - name <- renv_bootstrap_library_root_name(project) - return(file.path(path, name)) - } - - file.path(project, "renv/library") - - } - - renv_bootstrap_validate_version <- function(version) { - - loadedversion <- utils::packageDescription("renv", fields = "Version") - if (version == loadedversion) - return(TRUE) - - # assume four-component versions are from GitHub; three-component - # versions are from CRAN - components <- strsplit(loadedversion, "[.-]")[[1]] - remote <- if (length(components) == 4L) - paste("rstudio/renv", loadedversion, sep = "@") - else - paste("renv", loadedversion, sep = "@") - - fmt <- paste( - "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", - "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", - "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", - sep = "\n" - ) - - msg <- sprintf(fmt, loadedversion, version, remote) - warning(msg, call. = FALSE) - - FALSE - - } - - renv_bootstrap_hash_text <- function(text) { - - hashfile <- tempfile("renv-hash-") - on.exit(unlink(hashfile), add = TRUE) - - writeLines(text, con = hashfile) - tools::md5sum(hashfile) - - } - - renv_bootstrap_load <- function(project, libpath, version) { - - # try to load renv from the project library - if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) - return(FALSE) - - # warn if the version of renv loaded does not match - renv_bootstrap_validate_version(version) - - # load the project - renv::load(project) - - TRUE - - } - - # construct path to library root - root <- renv_bootstrap_library_root(project) - - # construct library prefix for platform - prefix <- renv_bootstrap_prefix() - - # construct full libpath - libpath <- file.path(root, prefix) - - # attempt to load - if (renv_bootstrap_load(project, libpath, version)) - return(TRUE) - - # load failed; inform user we're about to bootstrap - prefix <- paste("# Bootstrapping renv", version) - postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") - header <- paste(prefix, postfix) - message(header) - - # perform bootstrap - bootstrap(version, libpath) - - # exit early if we're just testing bootstrap - if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) - return(TRUE) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("* Successfully installed and loaded renv ", version, ".") - return(renv::load()) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) - - warning(paste(msg, collapse = "\n"), call. = FALSE) - -}) diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index 0c5e5638..763fe8e9 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -1,13 +1,16 @@ from __future__ import annotations import os.path +import shutil import pytest from pre_commit import envcontext from pre_commit.languages import r from pre_commit.prefix import Prefix +from pre_commit.store import _make_local_repo from pre_commit.util import win_exe +from testing.language_helpers import run_language def test_r_parsing_file_no_opts_no_args(tmp_path): @@ -97,3 +100,99 @@ def test_rscript_exec_relative_to_r_home(): def test_path_rscript_exec_no_r_home_set(): with envcontext.envcontext((('R_HOME', envcontext.UNSET),)): assert r._rscript_exec() == 'Rscript' + + +def test_r_hook(tmp_path): + renv_lock = '''\ +{ + "R": { + "Version": "4.0.3", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + } + ] + }, + "Packages": { + "renv": { + "Package": "renv", + "Version": "0.12.5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5c0cdb37f063c58cdab3c7e9fbb8bd2c" + }, + "rprojroot": { + "Package": "rprojroot", + "Version": "1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "86704667fe0860e4fec35afdfec137f3" + } + } +} +''' + description = '''\ +Package: gli.clu +Title: What the Package Does (One Line, Title Case) +Type: Package +Version: 0.0.0.9000 +Authors@R: + person(given = "First", + family = "Last", + role = c("aut", "cre"), + email = "first.last@example.com", + comment = c(ORCID = "YOUR-ORCID-ID")) +Description: What the package does (one paragraph). +License: `use_mit_license()`, `use_gpl3_license()` or friends to + pick a license +Encoding: UTF-8 +LazyData: true +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.1.1 +Imports: + rprojroot +''' + hello_world_r = '''\ +stopifnot( + packageVersion('rprojroot') == '1.0', + packageVersion('gli.clu') == '0.0.0.9000' +) +cat("Hello, World, from R!\n") +''' + + tmp_path.joinpath('renv.lock').write_text(renv_lock) + tmp_path.joinpath('DESCRIPTION').write_text(description) + tmp_path.joinpath('hello-world.R').write_text(hello_world_r) + renv_dir = tmp_path.joinpath('renv') + renv_dir.mkdir() + shutil.copy( + os.path.join( + os.path.dirname(__file__), + '../../pre_commit/resources/empty_template_activate.R', + ), + renv_dir.joinpath('activate.R'), + ) + + expected = (0, b'Hello, World, from R!\n') + assert run_language(tmp_path, r, 'Rscript hello-world.R') == expected + + +def test_r_inline(tmp_path): + _make_local_repo(str(tmp_path)) + + cmd = '''\ +Rscript -e ' + stopifnot(packageVersion("rprojroot") == "1.0") + cat(commandArgs(trailingOnly = TRUE), "from R!\n", sep=", ") +' +''' + + ret = run_language( + tmp_path, + r, + cmd, + deps=('rprojroot@1.0',), + args=('hi', 'hello'), + ) + assert ret == (0, b'hi, hello, from R!\n') diff --git a/tests/repository_test.py b/tests/repository_test.py index 0d01f0f6..bcb67126 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -227,54 +227,6 @@ def test_node_hook_with_npm_userconfig_set(tempdir_factory, store, tmpdir): test_run_a_node_hook(tempdir_factory, store) -def test_r_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'r_hooks_repo', - 'hello-world', [os.devnull], - b'Hello, World, from R!\n', - ) - - -def test_r_inline_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'r_hooks_repo', - 'hello-world-inline', ['some-file'], - b'Hi-there, some-file, from R!\n', - ) - - -def test_r_with_additional_dependencies_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'r_hooks_repo', - 'additional-deps', [os.devnull], - b'OK\n', - config_kwargs={ - 'hooks': [{ - 'id': 'additional-deps', - 'additional_dependencies': ['cachem@1.0.4'], - }], - }, - ) - - -def test_r_local_with_additional_dependencies_hook(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'local-r', - 'name': 'local-r', - 'entry': 'Rscript -e', - 'language': 'r', - 'args': ['if (packageVersion("R6") == "2.1.3") cat("OK\n")'], - 'additional_dependencies': ['R6@2.1.3'], - }], - } - hook = _get_hook(config, store, 'local-r') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - assert _norm_out(out) == b'OK\n' - - def test_run_a_ruby_hook(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'ruby_hooks_repo', From f042540311b9c23ba56fa12b87211fb495219c81 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 17 Jan 2023 23:43:31 -0500 Subject: [PATCH 181/416] test lua directly --- .../resources/lua_repo/.pre-commit-hooks.yaml | 4 -- .../resources/lua_repo/bin/hello-world-lua | 3 - .../resources/lua_repo/hello-dev-1.rockspec | 15 ----- testing/util.py | 4 -- tests/languages/lua_test.py | 58 +++++++++++++++++++ tests/repository_test.py | 27 --------- 6 files changed, 58 insertions(+), 53 deletions(-) delete mode 100644 testing/resources/lua_repo/.pre-commit-hooks.yaml delete mode 100755 testing/resources/lua_repo/bin/hello-world-lua delete mode 100644 testing/resources/lua_repo/hello-dev-1.rockspec create mode 100644 tests/languages/lua_test.py diff --git a/testing/resources/lua_repo/.pre-commit-hooks.yaml b/testing/resources/lua_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 767ef972..00000000 --- a/testing/resources/lua_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,4 +0,0 @@ -- id: hello-world-lua - name: hello world lua - entry: hello-world-lua - language: lua diff --git a/testing/resources/lua_repo/bin/hello-world-lua b/testing/resources/lua_repo/bin/hello-world-lua deleted file mode 100755 index 2a0e0024..00000000 --- a/testing/resources/lua_repo/bin/hello-world-lua +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env lua - -print('hello world') diff --git a/testing/resources/lua_repo/hello-dev-1.rockspec b/testing/resources/lua_repo/hello-dev-1.rockspec deleted file mode 100644 index 82486e08..00000000 --- a/testing/resources/lua_repo/hello-dev-1.rockspec +++ /dev/null @@ -1,15 +0,0 @@ -package = "hello" -version = "dev-1" - -source = { - url = "git+ssh://git@github.com/pre-commit/pre-commit.git" -} -description = {} -dependencies = {} -build = { - type = "builtin", - modules = {}, - install = { - bin = {"bin/hello-world-lua"} - }, -} diff --git a/testing/util.py b/testing/util.py index a5ae06d0..b6c3804e 100644 --- a/testing/util.py +++ b/testing/util.py @@ -45,10 +45,6 @@ skipif_cant_run_docker = pytest.mark.skipif( os.name == 'nt' or not docker_is_running(), reason="Docker isn't running or can't be accessed", ) -skipif_cant_run_lua = pytest.mark.skipif( - os.name == 'nt', - reason="lua isn't installed or can't be found", -) xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows') diff --git a/tests/languages/lua_test.py b/tests/languages/lua_test.py new file mode 100644 index 00000000..b2767b72 --- /dev/null +++ b/tests/languages/lua_test.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import sys + +import pytest + +from pre_commit.languages import lua +from pre_commit.util import make_executable +from testing.language_helpers import run_language + +pytestmark = pytest.mark.skipif( + sys.platform == 'win32', + reason='lua is not supported on windows', +) + + +def test_lua(tmp_path): # pragma: win32 no cover + rockspec = '''\ +package = "hello" +version = "dev-1" + +source = { + url = "git+ssh://git@github.com/pre-commit/pre-commit.git" +} +description = {} +dependencies = {} +build = { + type = "builtin", + modules = {}, + install = { + bin = {"bin/hello-world-lua"} + }, +} +''' + hello_world_lua = '''\ +#!/usr/bin/env lua +print('hello world') +''' + tmp_path.joinpath('hello-dev-1.rockspec').write_text(rockspec) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + bin_file = bin_dir.joinpath('hello-world-lua') + bin_file.write_text(hello_world_lua) + make_executable(bin_file) + + expected = (0, b'hello world\n') + assert run_language(tmp_path, lua, 'hello-world-lua') == expected + + +def test_lua_additional_dependencies(tmp_path): # pragma: win32 no cover + ret, out = run_language( + tmp_path, + lua, + 'luacheck --version', + deps=('luacheck',), + ) + assert ret == 0 + assert out.startswith(b'Luacheck: ') diff --git a/tests/repository_test.py b/tests/repository_test.py index 0d01f0f6..a617da1d 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -33,7 +33,6 @@ from testing.fixtures import modify_manifest from testing.util import cwd from testing.util import get_resource_path from testing.util import skipif_cant_run_docker -from testing.util import skipif_cant_run_lua from testing.util import xfailif_windows @@ -1041,29 +1040,3 @@ def test_non_installable_hook_error_for_additional_dependencies(store, caplog): 'using language `system` which does not install an environment. ' 'Perhaps you meant to use a specific language?' ) - - -@skipif_cant_run_lua # pragma: win32 no cover -def test_lua_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'lua_repo', - 'hello-world-lua', [], b'hello world\n', - ) - - -@skipif_cant_run_lua # pragma: win32 no cover -def test_local_lua_additional_dependencies(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'local-lua', - 'name': 'local-lua', - 'entry': 'luacheck --version', - 'language': 'lua', - 'additional_dependencies': ['luacheck'], - }], - } - hook = _get_hook(config, store, 'local-lua') - ret, out = _hook_run(hook, (), color=False) - assert b'Luacheck' in out - assert ret == 0 From 14c38d18fcc608644db077f7c862f9892a981668 Mon Sep 17 00:00:00 2001 From: Jamie Alessio Date: Sat, 21 Jan 2023 11:05:13 -0800 Subject: [PATCH 182/416] Upgrade to ruby-build v20221225 --- pre_commit/resources/ruby-build.tar.gz | Bin 74032 -> 76466 bytes testing/make-archives | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index 35419f63aebe33b6710851aef70937cd9ef163ba..b6eacf59ba31c87032e76c2d1f39a87bb2b52489 100644 GIT binary patch delta 76354 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 czR{aVMfxm!gA4;>XvotkA=eM0Hbt8%0N{)h_r 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 G9tHsZ-Yql$ delta 73892 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�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 Date: Mon, 23 Jan 2023 19:24:10 -0500 Subject: [PATCH 183/416] introduce install state v2 to replace v1 the v1 state is unnecessary since new repos are created for new additional_dependencies --- pre_commit/constants.py | 2 -- pre_commit/repository.py | 25 ++++++++++++++++++------- tests/repository_test.py | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 8fc5e55d..3f03ceed 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -5,8 +5,6 @@ import importlib.metadata CONFIG_FILE = '.pre-commit-config.yaml' MANIFEST_FILE = '.pre-commit-hooks.yaml' -# Bump when installation changes in a backwards / forwards incompatible way -INSTALLED_STATE_VERSION = '1' # Bump when modifying `empty_template` LOCAL_REPO_VERSION = '1' diff --git a/pre_commit/repository.py b/pre_commit/repository.py index ac6b8446..616faf54 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -23,16 +23,20 @@ from pre_commit.util import rmtree logger = logging.getLogger('pre_commit') +def _state_filename_v1(venv: str) -> str: + return os.path.join(venv, '.install_state_v1') + + +def _state_filename_v2(venv: str) -> str: + return os.path.join(venv, '.install_state_v2') + + def _state(additional_deps: Sequence[str]) -> object: return {'additional_dependencies': sorted(additional_deps)} -def _state_filename(venv: str) -> str: - return os.path.join(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}') - - def _read_state(venv: str) -> object | None: - filename = _state_filename(venv) + filename = _state_filename_v1(venv) if not os.path.exists(filename): return None else: @@ -51,7 +55,10 @@ def _hook_installed(hook: Hook) -> bool: hook.language_version, ) return ( - _read_state(venv) == _state(hook.additional_dependencies) and + ( + os.path.exists(_state_filename_v2(venv)) or + _read_state(venv) == _state(hook.additional_dependencies) + ) and not lang.health_check(hook.prefix, hook.language_version) ) @@ -87,14 +94,18 @@ def _hook_install(hook: Hook) -> None: f'your environment\n\n' f'more info:\n\n{health_error}', ) + + # TODO: remove v1 state writing, no longer needed after pre-commit 3.0 # Write our state to indicate we're installed - state_filename = _state_filename(venv) + state_filename = _state_filename_v1(venv) staging = f'{state_filename}staging' with open(staging, 'w') as state_file: state_file.write(json.dumps(_state(hook.additional_dependencies))) # Move the file into place atomically to indicate we've installed os.replace(staging, state_filename) + open(_state_filename_v2(venv), 'a+').close() + def _hook( *hook_dicts: dict[str, Any], diff --git a/tests/repository_test.py b/tests/repository_test.py index 8d3034bb..da878596 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -23,6 +23,7 @@ from pre_commit.languages import ruby from pre_commit.languages import rust from pre_commit.languages.all import languages from pre_commit.prefix import Prefix +from pre_commit.repository import _hook_installed from pre_commit.repository import all_hooks from pre_commit.repository import install_hook_envs from pre_commit.util import cmd_output @@ -562,6 +563,21 @@ def test_additional_dependencies_roll_forward(tempdir_factory, store): assert 'mccabe' not in cmd_output('pip', 'freeze', '-l')[1] +@pytest.mark.parametrize('v', ('v1', 'v2')) +def test_repository_state_compatibility(tempdir_factory, store, v): + path = make_repo(tempdir_factory, 'python_hooks_repo') + + config = make_config_from_repo(path) + hook = _get_hook(config, store, 'foo') + envdir = helpers.environment_dir( + hook.prefix, + python.ENVIRONMENT_DIR, + hook.language_version, + ) + os.remove(os.path.join(envdir, f'.install_state_{v}')) + assert _hook_installed(hook) is True + + def test_additional_ruby_dependencies_installed(tempdir_factory, store): path = make_repo(tempdir_factory, 'ruby_hooks_repo') config = make_config_from_repo(path) From 6b88fe577c44472d234e8d4d8ee89ca36e03ae2a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 23 Jan 2023 20:40:13 -0500 Subject: [PATCH 184/416] v3.0.0 --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0de5f7..59e0e202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +3.0.0 - 2023-01-23 +================== + +### Features +- Make `language: golang` bootstrap `go` if not present. + - #2651 PR by @taoufik07. + - #2649 issue by @taoufik07. +- `language: coursier` now supports `additional_dependencies` and `repo: local` + - #2702 PR by @asottile. +- Upgrade `ruby-build` to `20221225`. + - #2718 PR by @jalessio. + +### Fixes +- Improve error message for invalid yaml for `pre-commit autoupdate`. + - #2686 PR by @asottile. + - #2685 issue by @CarstenGrohmann. +- `repo: local` no longer provisions an empty `git` repo. + - #2699 PR by @asottile. + +### Updating +- Drop support for python<3.8 + - #2655 PR by @asottile. +- Drop support for top-level list, use `pre-commit migrate-config` to update. + - #2656 PR by @asottile. +- Drop support for `sha` to specify revision, use `pre-commit migrate-config` + to update. + - #2657 PR by @asottile. +- Remove `pre-commit-validate-config` and `pre-commit-validate-manifest`, use + `pre-commit validate-config` and `pre-commit validate-manifest` instead. + - #2658 PR by @asottile. +- `language: golang` hooks must use `go.mod` to specify dependencies + - #2672 PR by @taoufik07. + + 2.21.0 - 2022-12-25 =================== diff --git a/setup.cfg b/setup.cfg index ca1f7d8b..929f4c32 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 2.21.0 +version = 3.0.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 83e05e607e6b8cfde97c05e067d156be09a298a9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 25 Jan 2023 14:03:39 -0500 Subject: [PATCH 185/416] ensure coursier hooks are available offline after install --- pre_commit/languages/coursier.py | 45 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 69c877d3..60757588 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -28,45 +28,44 @@ def install_environment( helpers.assert_version_default('coursier', version) # Support both possible executable names (either "cs" or "coursier") - executable = find_executable('cs') or find_executable('coursier') - if executable is None: + cs = find_executable('cs') or find_executable('coursier') + if cs is None: raise AssertionError( 'pre-commit requires system-installed "cs" or "coursier" ' 'executables in the application search path', ) envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) - channel = prefix.path('.pre-commit-channel') - if os.path.isdir(channel): - for app_descriptor in os.listdir(channel): - _, app_file = os.path.split(app_descriptor) - app, _ = os.path.splitext(app_file) - helpers.run_setup_cmd( - prefix, - ( - executable, - 'install', + + def _install(*opts: str) -> None: + assert cs is not None + helpers.run_setup_cmd(prefix, (cs, 'fetch', *opts)) + helpers.run_setup_cmd(prefix, (cs, 'install', '--dir', envdir, *opts)) + + with in_env(prefix, version): + channel = prefix.path('.pre-commit-channel') + if os.path.isdir(channel): + for app_descriptor in os.listdir(channel): + _, app_file = os.path.split(app_descriptor) + app, _ = os.path.splitext(app_file) + _install( '--default-channels=false', '--channel', channel, - '--dir', envdir, app, - ), + ) + elif not additional_dependencies: + raise FatalError( + 'expected .pre-commit-channel dir or additional_dependencies', ) - elif not additional_dependencies: - raise FatalError( - 'expected .pre-commit-channel dir or additional_dependencies', - ) - if additional_dependencies: - install_cmd = ( - executable, 'install', '--dir', envdir, *additional_dependencies, - ) - helpers.run_setup_cmd(prefix, install_cmd) + if additional_dependencies: + _install(*additional_dependencies) def get_env_patch(target_dir: str) -> PatchesT: return ( ('PATH', (target_dir, os.pathsep, Var('PATH'))), + ('COURSIER_CACHE', os.path.join(target_dir, '.cs-cache')), ) From dd8e717ed6022209a2b0cecf5c75460eb60e548e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 26 Jan 2023 11:09:17 -0500 Subject: [PATCH 186/416] v3.0.1 --- CHANGELOG.md | 7 +++++++ setup.cfg | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e0e202..d55ff732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +3.0.1 - 2023-01-26 +================== + +### Fixes +- Ensure coursier hooks are available offline after install. + - #2723 PR by @asottile. + 3.0.0 - 2023-01-23 ================== diff --git a/setup.cfg b/setup.cfg index 929f4c32..1dbace59 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.0.0 +version = 3.0.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From f4bd44996c888f48bc3a37d5ab19514325cb3f01 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Jan 2023 16:44:44 -0500 Subject: [PATCH 187/416] also ignore Gemfile in project this starts failing with ruby 3.2.0 --- pre_commit/languages/ruby.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 4416f728..b4d4b45a 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -39,6 +39,7 @@ def get_env_patch( ('GEM_HOME', os.path.join(venv, 'gems')), ('GEM_PATH', UNSET), ('BUNDLE_IGNORE_CONFIG', '1'), + ('BUNDLE_GEMFILE', os.devnull), ) if language_version == 'system': patches += ( From 6e8051b9e644505f2755ed576cb4b7220f6db8b4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Jan 2023 16:20:50 -0500 Subject: [PATCH 188/416] speed up ruby tests by picking a prebuilt in 22.04 --- .../ruby_versioned_hooks_repo/.pre-commit-hooks.yaml | 2 +- tests/languages/ruby_test.py | 4 ++-- tests/repository_test.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml index 364d47d8..c97939ad 100644 --- a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml +++ b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml @@ -2,5 +2,5 @@ name: Ruby Hook entry: ruby_hook language: ruby - language_version: 3.1.0 + language_version: 3.2.0 files: \.rb$ diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 29f3c802..63a16eb1 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -71,10 +71,10 @@ def test_install_ruby_default(fake_gem_prefix): @xfailif_windows # pragma: win32 no cover def test_install_ruby_with_version(fake_gem_prefix): - ruby.install_environment(fake_gem_prefix, '3.1.0', ()) + ruby.install_environment(fake_gem_prefix, '3.2.0', ()) # Should be able to activate and use rbenv install - with ruby.in_env(fake_gem_prefix, '3.1.0'): + with ruby.in_env(fake_gem_prefix, '3.2.0'): cmd_output('rbenv', 'install', '--help') diff --git a/tests/repository_test.py b/tests/repository_test.py index da878596..ff2d7c32 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -247,7 +247,7 @@ def test_run_versioned_ruby_hook(tempdir_factory, store): tempdir_factory, store, 'ruby_versioned_hooks_repo', 'ruby_hook', [os.devnull], - b'3.1.0\nHello world from a ruby hook\n', + b'3.2.0\nHello world from a ruby hook\n', ) @@ -269,7 +269,7 @@ def test_run_ruby_hook_with_disable_shared_gems( tempdir_factory, store, 'ruby_versioned_hooks_repo', 'ruby_hook', [os.devnull], - b'3.1.0\nHello world from a ruby hook\n', + b'3.2.0\nHello world from a ruby hook\n', ) From 420902f67cbd2117e93f797191eaa9dab4be6904 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 29 Jan 2023 17:27:42 -0500 Subject: [PATCH 189/416] fix r local hooks `language: r` acts more like `language: script` so we have to *not* append the prefix when run with `repo: local` --- pre_commit/commands/run.py | 1 + pre_commit/languages/all.py | 1 + pre_commit/languages/docker.py | 1 + pre_commit/languages/docker_image.py | 1 + pre_commit/languages/fail.py | 1 + pre_commit/languages/helpers.py | 1 + pre_commit/languages/pygrep.py | 1 + pre_commit/languages/r.py | 17 ++++++++++++---- pre_commit/languages/script.py | 1 + testing/language_helpers.py | 2 ++ tests/languages/r_test.py | 29 ++++++++++++++++++++++++++-- tests/repository_test.py | 1 + 12 files changed, 51 insertions(+), 6 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 85fa59aa..e44e7036 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -195,6 +195,7 @@ def _run_single_hook( hook.entry, hook.args, filenames, + is_local=hook.src == 'local', require_serial=hook.require_serial, color=use_color, ) diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index c7aab65e..d952ae1a 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -66,6 +66,7 @@ class Language(Protocol): args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 18234567..e80c9597 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -127,6 +127,7 @@ def run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index 23098382..8e5f2c04 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -19,6 +19,7 @@ def run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index 13b2bc12..33df067e 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -18,6 +18,7 @@ def run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: diff --git a/pre_commit/languages/helpers.py b/pre_commit/languages/helpers.py index 074f98e9..d1be409c 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/languages/helpers.py @@ -146,6 +146,7 @@ def basic_run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index 93e2a65b..f0eb9a95 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -93,6 +93,7 @@ def run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index dc398605..e2383658 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -35,8 +35,13 @@ def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: yield -def _prefix_if_file_entry(entry: list[str], prefix: Prefix) -> Sequence[str]: - if entry[1] == '-e': +def _prefix_if_file_entry( + entry: list[str], + prefix: Prefix, + *, + is_local: bool, +) -> Sequence[str]: + if entry[1] == '-e' or is_local: return entry[1:] else: return (prefix.path(entry[1]),) @@ -73,11 +78,14 @@ def _cmd_from_hook( prefix: Prefix, entry: str, args: Sequence[str], + *, + is_local: bool, ) -> tuple[str, ...]: cmd = shlex.split(entry) _entry_validate(cmd) - return (cmd[0], *RSCRIPT_OPTS, *_prefix_if_file_entry(cmd, prefix), *args) + cmd_part = _prefix_if_file_entry(cmd, prefix, is_local=is_local) + return (cmd[0], *RSCRIPT_OPTS, *cmd_part, *args) def install_environment( @@ -153,10 +161,11 @@ def run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: - cmd = _cmd_from_hook(prefix, entry, args) + cmd = _cmd_from_hook(prefix, entry, args, is_local=is_local) return helpers.run_xargs( cmd, file_args, diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index 41fffdf0..08325f46 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -18,6 +18,7 @@ def run_hook( args: Sequence[str], file_args: Sequence[str], *, + is_local: bool, require_serial: bool, color: bool, ) -> tuple[int, bytes]: diff --git a/testing/language_helpers.py b/testing/language_helpers.py index 02e47a00..f9ae0b1d 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -16,6 +16,7 @@ def run_language( file_args: Sequence[str] = (), version: str = C.DEFAULT, deps: Sequence[str] = (), + is_local: bool = False, ) -> tuple[int, bytes]: prefix = Prefix(str(path)) @@ -26,6 +27,7 @@ def run_language( exe, args, file_args, + is_local=is_local, require_serial=True, color=False, ) diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index 763fe8e9..02c559cb 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -14,7 +14,12 @@ from testing.language_helpers import run_language def test_r_parsing_file_no_opts_no_args(tmp_path): - cmd = r._cmd_from_hook(Prefix(str(tmp_path)), 'Rscript some-script.R', ()) + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + 'Rscript some-script.R', + (), + is_local=False, + ) assert cmd == ( 'Rscript', '--no-save', '--no-restore', '--no-site-file', '--no-environ', @@ -38,6 +43,7 @@ def test_r_parsing_file_no_opts_args(tmp_path): Prefix(str(tmp_path)), 'Rscript some-script.R', ('--no-cache',), + is_local=False, ) assert cmd == ( 'Rscript', @@ -48,7 +54,12 @@ def test_r_parsing_file_no_opts_args(tmp_path): def test_r_parsing_expr_no_opts_no_args1(tmp_path): - cmd = r._cmd_from_hook(Prefix(str(tmp_path)), "Rscript -e '1+1'", ()) + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + "Rscript -e '1+1'", + (), + is_local=False, + ) assert cmd == ( 'Rscript', '--no-save', '--no-restore', '--no-site-file', '--no-environ', @@ -56,6 +67,20 @@ def test_r_parsing_expr_no_opts_no_args1(tmp_path): ) +def test_r_parsing_local_hook_path_is_not_expanded(tmp_path): + cmd = r._cmd_from_hook( + Prefix(str(tmp_path)), + 'Rscript path/to/thing.R', + (), + is_local=True, + ) + assert cmd == ( + 'Rscript', + '--no-save', '--no-restore', '--no-site-file', '--no-environ', + 'path/to/thing.R', + ) + + def test_r_parsing_expr_no_opts_no_args2(): with pytest.raises(ValueError) as excinfo: r._entry_validate(['Rscript', '-e', '1+1', '-e', 'letters']) diff --git a/tests/repository_test.py b/tests/repository_test.py index ff2d7c32..85cf4581 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -48,6 +48,7 @@ def _hook_run(hook, filenames, color): hook.entry, hook.args, filenames, + is_local=hook.src == 'local', require_serial=hook.require_serial, color=color, ) From 2adca78c6feb99d0e9b14158fa38e599ec7e84a6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 29 Jan 2023 18:27:10 -0500 Subject: [PATCH 190/416] test rust directly --- testing/language_helpers.py | 4 +- .../rust_hooks_repo/.pre-commit-hooks.yaml | 5 - testing/resources/rust_hooks_repo/Cargo.lock | 3 - testing/resources/rust_hooks_repo/Cargo.toml | 3 - testing/resources/rust_hooks_repo/src/main.rs | 3 - tests/languages/rust_test.py | 105 ++++++++++-------- tests/repository_test.py | 66 ----------- 7 files changed, 61 insertions(+), 128 deletions(-) delete mode 100644 testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/rust_hooks_repo/Cargo.lock delete mode 100644 testing/resources/rust_hooks_repo/Cargo.toml delete mode 100644 testing/resources/rust_hooks_repo/src/main.rs diff --git a/testing/language_helpers.py b/testing/language_helpers.py index 02e47a00..45fefbab 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -3,7 +3,6 @@ from __future__ import annotations import os from typing import Sequence -import pre_commit.constants as C from pre_commit.languages.all import Language from pre_commit.prefix import Prefix @@ -14,10 +13,11 @@ def run_language( exe: str, args: Sequence[str] = (), file_args: Sequence[str] = (), - version: str = C.DEFAULT, + version: str | None = None, deps: Sequence[str] = (), ) -> tuple[int, bytes]: prefix = Prefix(str(path)) + version = version or language.get_default_version() language.install_environment(prefix, version, deps) with language.in_env(prefix, version): diff --git a/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index df1269ff..00000000 --- a/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: rust-hook - name: rust example hook - entry: rust-hello-world - language: rust - files: '' diff --git a/testing/resources/rust_hooks_repo/Cargo.lock b/testing/resources/rust_hooks_repo/Cargo.lock deleted file mode 100644 index 36fbfda2..00000000 --- a/testing/resources/rust_hooks_repo/Cargo.lock +++ /dev/null @@ -1,3 +0,0 @@ -[[package]] -name = "rust-hello-world" -version = "0.1.0" diff --git a/testing/resources/rust_hooks_repo/Cargo.toml b/testing/resources/rust_hooks_repo/Cargo.toml deleted file mode 100644 index cd83b435..00000000 --- a/testing/resources/rust_hooks_repo/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "rust-hello-world" -version = "0.1.0" diff --git a/testing/resources/rust_hooks_repo/src/main.rs b/testing/resources/rust_hooks_repo/src/main.rs deleted file mode 100644 index ad379d6e..00000000 --- a/testing/resources/rust_hooks_repo/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("hello world"); -} diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py index b8167a9e..5c17f5b6 100644 --- a/tests/languages/rust_test.py +++ b/tests/languages/rust_test.py @@ -1,6 +1,5 @@ from __future__ import annotations -from typing import Mapping from unittest import mock import pytest @@ -8,8 +7,8 @@ import pytest import pre_commit.constants as C from pre_commit import parse_shebang from pre_commit.languages import rust -from pre_commit.prefix import Prefix -from pre_commit.util import cmd_output +from pre_commit.store import _make_local_repo +from testing.language_helpers import run_language ACTUAL_GET_DEFAULT_VERSION = rust.get_default_version.__wrapped__ @@ -30,64 +29,78 @@ def test_uses_default_when_rust_is_not_available(cmd_output_b_mck): assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT -@pytest.mark.parametrize('language_version', (C.DEFAULT, '1.56.0')) -def test_installs_with_bootstrapped_rustup(tmpdir, language_version): - tmpdir.join('src', 'main.rs').ensure().write( +def _make_hello_world(tmp_path): + src_dir = tmp_path.joinpath('src') + src_dir.mkdir() + src_dir.joinpath('main.rs').write_text( 'fn main() {\n' ' println!("Hello, world!");\n' '}\n', ) - tmpdir.join('Cargo.toml').ensure().write( + tmp_path.joinpath('Cargo.toml').write_text( '[package]\n' 'name = "hello_world"\n' 'version = "0.1.0"\n' 'edition = "2021"\n', ) - prefix = Prefix(str(tmpdir)) - find_executable_exes = [] - original_find_executable = parse_shebang.find_executable +def test_installs_rust_missing_rustup(tmp_path): + _make_hello_world(tmp_path) - def mocked_find_executable( - exe: str, *, env: Mapping[str, str] | None = None, - ) -> str | None: - """ - Return `None` the first time `find_executable` is called to ensure - that the bootstrapping code is executed, then just let the function - work as normal. + # pretend like `rustup` doesn't exist so it gets bootstrapped + calls = [] + orig = parse_shebang.find_executable - Also log the arguments to ensure that everything works as expected. - """ - find_executable_exes.append(exe) - if len(find_executable_exes) == 1: + def mck(exe, env=None): + calls.append(exe) + if len(calls) == 1: + assert exe == 'rustup' return None - return original_find_executable(exe, env=env) + return orig(exe, env=env) - with mock.patch.object(parse_shebang, 'find_executable') as find_exe_mck: - find_exe_mck.side_effect = mocked_find_executable - rust.install_environment(prefix, language_version, ()) - assert find_executable_exes == ['rustup', 'rustup', 'cargo'] - - with rust.in_env(prefix, language_version): - assert cmd_output('hello_world')[1] == 'Hello, world!\n' + with mock.patch.object(parse_shebang, 'find_executable', side_effect=mck): + ret = run_language(tmp_path, rust, 'hello_world', version='1.56.0') + assert calls == ['rustup', 'rustup', 'cargo', 'hello_world'] + assert ret == (0, b'Hello, world!\n') -def test_installs_with_existing_rustup(tmpdir): - tmpdir.join('src', 'main.rs').ensure().write( - 'fn main() {\n' - ' println!("Hello, world!");\n' - '}\n', - ) - tmpdir.join('Cargo.toml').ensure().write( - '[package]\n' - 'name = "hello_world"\n' - 'version = "0.1.0"\n' - 'edition = "2021"\n', - ) - prefix = Prefix(str(tmpdir)) - +@pytest.mark.parametrize('version', (C.DEFAULT, '1.56.0')) +def test_language_version_with_rustup(tmp_path, version): assert parse_shebang.find_executable('rustup') is not None - rust.install_environment(prefix, '1.56.0', ()) - with rust.in_env(prefix, '1.56.0'): - assert cmd_output('hello_world')[1] == 'Hello, world!\n' + + _make_hello_world(tmp_path) + + ret = run_language(tmp_path, rust, 'hello_world', version=version) + assert ret == (0, b'Hello, world!\n') + + +@pytest.mark.parametrize('dep', ('cli:shellharden:4.2.0', 'cli:shellharden')) +def test_rust_cli_additional_dependencies(tmp_path, dep): + _make_local_repo(str(tmp_path)) + + t_sh = tmp_path.joinpath('t.sh') + t_sh.write_text('echo $hi\n') + + assert rust.get_default_version() == 'system' + ret = run_language( + tmp_path, + rust, + 'shellharden --transform', + deps=(dep,), + args=(str(t_sh),), + ) + assert ret == (0, b'echo "$hi"\n') + + +def test_run_lib_additional_dependencies(tmp_path): + _make_hello_world(tmp_path) + + deps = ('shellharden:4.2.0', 'git-version') + ret = run_language(tmp_path, rust, 'hello_world', deps=deps) + assert ret == (0, b'Hello, world!\n') + + bin_dir = tmp_path.joinpath('rustenv-system', 'bin') + assert bin_dir.is_dir() + assert not bin_dir.joinpath('shellharden').exists() + assert not bin_dir.joinpath('shellharden.exe').exists() diff --git a/tests/repository_test.py b/tests/repository_test.py index ff2d7c32..aea7ffbc 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -20,7 +20,6 @@ from pre_commit.languages import helpers from pre_commit.languages import node from pre_commit.languages import python from pre_commit.languages import ruby -from pre_commit.languages import rust from pre_commit.languages.all import languages from pre_commit.prefix import Prefix from pre_commit.repository import _hook_installed @@ -366,54 +365,6 @@ func main() { assert _norm_out(out) == b'hello hello world\n' -def test_rust_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'rust_hooks_repo', - 'rust-hook', [], b'hello world\n', - ) - - -@pytest.mark.parametrize('dep', ('cli:shellharden:3.1.0', 'cli:shellharden')) -def test_additional_rust_cli_dependencies_installed( - tempdir_factory, store, dep, -): - path = make_repo(tempdir_factory, 'rust_hooks_repo') - config = make_config_from_repo(path) - # A small rust package with no dependencies. - config['hooks'][0]['additional_dependencies'] = [dep] - hook = _get_hook(config, store, 'rust-hook') - envdir = helpers.environment_dir( - hook.prefix, - rust.ENVIRONMENT_DIR, - 'system', - ) - binaries = os.listdir(os.path.join(envdir, 'bin')) - # normalize for windows - binaries = [os.path.splitext(binary)[0] for binary in binaries] - assert 'shellharden' in binaries - - -def test_additional_rust_lib_dependencies_installed( - tempdir_factory, store, -): - path = make_repo(tempdir_factory, 'rust_hooks_repo') - config = make_config_from_repo(path) - # A small rust package with no dependencies. - deps = ['shellharden:3.1.0', 'git-version'] - config['hooks'][0]['additional_dependencies'] = deps - hook = _get_hook(config, store, 'rust-hook') - envdir = helpers.environment_dir( - hook.prefix, - rust.ENVIRONMENT_DIR, - 'system', - ) - binaries = os.listdir(os.path.join(envdir, 'bin')) - # normalize for windows - binaries = [os.path.splitext(binary)[0] for binary in binaries] - assert 'rust-hello-world' in binaries - assert 'shellharden' not in binaries - - def test_missing_executable(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'not_found_exe', @@ -636,23 +587,6 @@ def test_local_golang_additional_dependencies(store): assert _norm_out(out) == b'Hello, Go examples!\n' -def test_local_rust_additional_dependencies(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'hello', - 'name': 'hello', - 'entry': 'hello', - 'language': 'rust', - 'additional_dependencies': ['cli:hello-cli:0.2.2'], - }], - } - hook = _get_hook(config, store, 'hello') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - assert _norm_out(out) == b'Hello World!\n' - - def test_fail_hooks(store): config = { 'repo': 'local', From 6abb05a60c4087a10c6ce196cd3a8bce065fa6f1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 29 Jan 2023 18:36:45 -0500 Subject: [PATCH 191/416] v3.0.2 --- CHANGELOG.md | 10 ++++++++++ setup.cfg | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d55ff732..c0657e63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +3.0.2 - 2023-01-29 +================== + +### Fixes +- Prevent local `Gemfile` from interfering with hook execution. + - #2727 PR by @asottile. +- Fix `language: r`, `repo: local` hooks + - pre-commit-ci/issues#107 by @lorenzwalthert. + - #2728 PR by @asottile. + 3.0.1 - 2023-01-26 ================== diff --git a/setup.cfg b/setup.cfg index 1dbace59..37511c09 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.0.1 +version = 3.0.2 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 5b50acbd2c3f52f0e8dee3f11e08905430c4aef7 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Jan 2023 21:36:13 -0500 Subject: [PATCH 192/416] test ruby directly --- testing/resources/ruby_hooks_repo/.gitignore | 1 - .../ruby_hooks_repo/.pre-commit-hooks.yaml | 5 - .../resources/ruby_hooks_repo/bin/ruby_hook | 3 - .../resources/ruby_hooks_repo/lib/.gitignore | 0 .../ruby_hooks_repo/ruby_hook.gemspec | 9 -- .../ruby_versioned_hooks_repo/.gitignore | 1 - .../.pre-commit-hooks.yaml | 6 - .../ruby_versioned_hooks_repo/bin/ruby_hook | 4 - .../ruby_versioned_hooks_repo/lib/.gitignore | 0 .../ruby_hook.gemspec | 9 -- tests/languages/ruby_test.py | 143 ++++++++++++------ tests/repository_test.py | 58 ------- 12 files changed, 96 insertions(+), 143 deletions(-) delete mode 100644 testing/resources/ruby_hooks_repo/.gitignore delete mode 100644 testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml delete mode 100755 testing/resources/ruby_hooks_repo/bin/ruby_hook delete mode 100644 testing/resources/ruby_hooks_repo/lib/.gitignore delete mode 100644 testing/resources/ruby_hooks_repo/ruby_hook.gemspec delete mode 100644 testing/resources/ruby_versioned_hooks_repo/.gitignore delete mode 100644 testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml delete mode 100755 testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook delete mode 100644 testing/resources/ruby_versioned_hooks_repo/lib/.gitignore delete mode 100644 testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec diff --git a/testing/resources/ruby_hooks_repo/.gitignore b/testing/resources/ruby_hooks_repo/.gitignore deleted file mode 100644 index c111b331..00000000 --- a/testing/resources/ruby_hooks_repo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.gem diff --git a/testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index aa15872f..00000000 --- a/testing/resources/ruby_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: ruby_hook - name: Ruby Hook - entry: ruby_hook - language: ruby - files: \.rb$ diff --git a/testing/resources/ruby_hooks_repo/bin/ruby_hook b/testing/resources/ruby_hooks_repo/bin/ruby_hook deleted file mode 100755 index 5a7e5ed2..00000000 --- a/testing/resources/ruby_hooks_repo/bin/ruby_hook +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ruby - -puts 'Hello world from a ruby hook' diff --git a/testing/resources/ruby_hooks_repo/lib/.gitignore b/testing/resources/ruby_hooks_repo/lib/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/testing/resources/ruby_hooks_repo/ruby_hook.gemspec b/testing/resources/ruby_hooks_repo/ruby_hook.gemspec deleted file mode 100644 index 75f4e8f7..00000000 --- a/testing/resources/ruby_hooks_repo/ruby_hook.gemspec +++ /dev/null @@ -1,9 +0,0 @@ -Gem::Specification.new do |s| - s.name = 'ruby_hook' - s.version = '0.1.0' - s.authors = ['Anthony Sottile'] - s.summary = 'A ruby hook!' - s.description = 'A ruby hook!' - s.files = ['bin/ruby_hook'] - s.executables = ['ruby_hook'] -end diff --git a/testing/resources/ruby_versioned_hooks_repo/.gitignore b/testing/resources/ruby_versioned_hooks_repo/.gitignore deleted file mode 100644 index c111b331..00000000 --- a/testing/resources/ruby_versioned_hooks_repo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.gem diff --git a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index c97939ad..00000000 --- a/testing/resources/ruby_versioned_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- id: ruby_hook - name: Ruby Hook - entry: ruby_hook - language: ruby - language_version: 3.2.0 - files: \.rb$ diff --git a/testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook b/testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook deleted file mode 100755 index 2406f04c..00000000 --- a/testing/resources/ruby_versioned_hooks_repo/bin/ruby_hook +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env ruby - -puts RUBY_VERSION -puts 'Hello world from a ruby hook' diff --git a/testing/resources/ruby_versioned_hooks_repo/lib/.gitignore b/testing/resources/ruby_versioned_hooks_repo/lib/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec b/testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec deleted file mode 100644 index 75f4e8f7..00000000 --- a/testing/resources/ruby_versioned_hooks_repo/ruby_hook.gemspec +++ /dev/null @@ -1,9 +0,0 @@ -Gem::Specification.new do |s| - s.name = 'ruby_hook' - s.version = '0.1.0' - s.authors = ['Anthony Sottile'] - s.summary = 'A ruby hook!' - s.description = 'A ruby hook!' - s.files = ['bin/ruby_hook'] - s.executables = ['ruby_hook'] -end diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 63a16eb1..b312c7fd 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -1,6 +1,5 @@ from __future__ import annotations -import os.path import tarfile from unittest import mock @@ -8,10 +7,12 @@ import pytest import pre_commit.constants as C from pre_commit import parse_shebang +from pre_commit.envcontext import envcontext from pre_commit.languages import ruby -from pre_commit.prefix import Prefix -from pre_commit.util import cmd_output +from pre_commit.store import _make_local_repo from pre_commit.util import resource_bytesio +from testing.language_helpers import run_language +from testing.util import cwd from testing.util import xfailif_windows @@ -34,50 +35,6 @@ def test_uses_system_if_both_gem_and_ruby_are_available(find_exe_mck): assert ACTUAL_GET_DEFAULT_VERSION() == 'system' -@pytest.fixture -def fake_gem_prefix(tmpdir): - gemspec = '''\ -Gem::Specification.new do |s| - s.name = 'pre_commit_placeholder_package' - s.version = '0.0.0' - s.summary = 'placeholder gem for pre-commit hooks' - s.authors = ['Anthony Sottile'] -end -''' - tmpdir.join('placeholder_gem.gemspec').write(gemspec) - yield Prefix(tmpdir) - - -@xfailif_windows # pragma: win32 no cover -def test_install_ruby_system(fake_gem_prefix): - ruby.install_environment(fake_gem_prefix, 'system', ()) - - # Should be able to activate and use rbenv install - with ruby.in_env(fake_gem_prefix, 'system'): - _, out, _ = cmd_output('gem', 'list') - assert 'pre_commit_placeholder_package' in out - - -@xfailif_windows # pragma: win32 no cover -def test_install_ruby_default(fake_gem_prefix): - ruby.install_environment(fake_gem_prefix, C.DEFAULT, ()) - # Should have created rbenv directory - assert os.path.exists(fake_gem_prefix.path('rbenv-default')) - - # Should be able to activate using our script and access rbenv - with ruby.in_env(fake_gem_prefix, 'default'): - cmd_output('rbenv', '--help') - - -@xfailif_windows # pragma: win32 no cover -def test_install_ruby_with_version(fake_gem_prefix): - ruby.install_environment(fake_gem_prefix, '3.2.0', ()) - - # Should be able to activate and use rbenv install - with ruby.in_env(fake_gem_prefix, '3.2.0'): - cmd_output('rbenv', 'install', '--help') - - @pytest.mark.parametrize( 'filename', ('rbenv.tar.gz', 'ruby-build.tar.gz', 'ruby-download.tar.gz'), @@ -87,3 +44,95 @@ def test_archive_root_stat(filename): with tarfile.open(fileobj=f) as tarf: root, _, _ = filename.partition('.') assert oct(tarf.getmember(root).mode) == '0o755' + + +def _setup_hello_world(tmp_path): + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + bin_dir.joinpath('ruby_hook').write_text( + '#!/usr/bin/env ruby\n' + "puts 'Hello world from a ruby hook'\n", + ) + gemspec = '''\ +Gem::Specification.new do |s| + s.name = 'ruby_hook' + s.version = '0.1.0' + s.authors = ['Anthony Sottile'] + s.summary = 'A ruby hook!' + s.description = 'A ruby hook!' + s.files = ['bin/ruby_hook'] + s.executables = ['ruby_hook'] +end +''' + tmp_path.joinpath('ruby_hook.gemspec').write_text(gemspec) + + +def test_ruby_hook_system(tmp_path): + assert ruby.get_default_version() == 'system' + + _setup_hello_world(tmp_path) + + ret = run_language(tmp_path, ruby, 'ruby_hook') + assert ret == (0, b'Hello world from a ruby hook\n') + + +def test_ruby_with_user_install_set(tmp_path): + gemrc = tmp_path.joinpath('gemrc') + gemrc.write_text('gem: --user-install\n') + + with envcontext((('GEMRC', str(gemrc)),)): + test_ruby_hook_system(tmp_path) + + +def test_ruby_additional_deps(tmp_path): + _make_local_repo(tmp_path) + + ret = run_language( + tmp_path, + ruby, + 'ruby -e', + args=('require "tins"',), + deps=('tins',), + ) + assert ret == (0, b'') + + +@xfailif_windows # pragma: win32 no cover +def test_ruby_hook_default(tmp_path): + _setup_hello_world(tmp_path) + + out, ret = run_language(tmp_path, ruby, 'rbenv --help', version='default') + assert out == 0 + assert ret.startswith(b'Usage: rbenv ') + + +@xfailif_windows # pragma: win32 no cover +def test_ruby_hook_language_version(tmp_path): + _setup_hello_world(tmp_path) + tmp_path.joinpath('bin', 'ruby_hook').write_text( + '#!/usr/bin/env ruby\n' + 'puts RUBY_VERSION\n' + "puts 'Hello world from a ruby hook'\n", + ) + + ret = run_language(tmp_path, ruby, 'ruby_hook', version='3.2.0') + assert ret == (0, b'3.2.0\nHello world from a ruby hook\n') + + +@xfailif_windows # pragma: win32 no cover +def test_ruby_with_bundle_disable_shared_gems(tmp_path): + workdir = tmp_path.joinpath('workdir') + workdir.mkdir() + # this Gemfile is missing `source` + workdir.joinpath('Gemfile').write_text('gem "lol_hai"\n') + # this bundle config causes things to be written elsewhere + bundle = workdir.joinpath('.bundle') + bundle.mkdir() + bundle.joinpath('config').write_text( + 'BUNDLE_DISABLE_SHARED_GEMS: true\n' + 'BUNDLE_PATH: vendor/gem\n', + ) + + with cwd(workdir): + # `3.2.0` has new enough `gem` requiring `source` and reading `.bundle` + test_ruby_hook_language_version(tmp_path) diff --git a/tests/repository_test.py b/tests/repository_test.py index 6565e106..2cd4c0fa 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -19,7 +19,6 @@ from pre_commit.languages import golang from pre_commit.languages import helpers from pre_commit.languages import node from pre_commit.languages import python -from pre_commit.languages import ruby from pre_commit.languages.all import languages from pre_commit.prefix import Prefix from pre_commit.repository import _hook_installed @@ -33,7 +32,6 @@ from testing.fixtures import modify_manifest from testing.util import cwd from testing.util import get_resource_path from testing.util import skipif_cant_run_docker -from testing.util import xfailif_windows def _norm_out(b): @@ -227,52 +225,6 @@ def test_node_hook_with_npm_userconfig_set(tempdir_factory, store, tmpdir): test_run_a_node_hook(tempdir_factory, store) -def test_run_a_ruby_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'ruby_hooks_repo', - 'ruby_hook', [os.devnull], b'Hello world from a ruby hook\n', - ) - - -def test_run_a_ruby_hook_with_user_install_set(tempdir_factory, store, tmpdir): - gemrc = tmpdir.join('gemrc') - gemrc.write('gem: --user-install\n') - with envcontext((('GEMRC', str(gemrc)),)): - test_run_a_ruby_hook(tempdir_factory, store) - - -@xfailif_windows # pragma: win32 no cover -def test_run_versioned_ruby_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'ruby_versioned_hooks_repo', - 'ruby_hook', - [os.devnull], - b'3.2.0\nHello world from a ruby hook\n', - ) - - -@xfailif_windows # pragma: win32 no cover -def test_run_ruby_hook_with_disable_shared_gems( - tempdir_factory, - store, - tmpdir, -): - """Make sure a Gemfile in the project doesn't interfere.""" - tmpdir.join('Gemfile').write('gem "lol_hai"') - tmpdir.join('.bundle').mkdir() - tmpdir.join('.bundle', 'config').write( - 'BUNDLE_DISABLE_SHARED_GEMS: true\n' - 'BUNDLE_PATH: vendor/gem\n', - ) - with cwd(tmpdir.strpath): - _test_hook_repo( - tempdir_factory, store, 'ruby_versioned_hooks_repo', - 'ruby_hook', - [os.devnull], - b'3.2.0\nHello world from a ruby hook\n', - ) - - def test_system_hook_with_spaces(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'system_hook_with_spaces_repo', @@ -530,16 +482,6 @@ def test_repository_state_compatibility(tempdir_factory, store, v): assert _hook_installed(hook) is True -def test_additional_ruby_dependencies_installed(tempdir_factory, store): - path = make_repo(tempdir_factory, 'ruby_hooks_repo') - config = make_config_from_repo(path) - config['hooks'][0]['additional_dependencies'] = ['tins'] - hook = _get_hook(config, store, 'ruby_hook') - with ruby.in_env(hook.prefix, hook.language_version): - output = cmd_output('gem', 'list', '--local')[1] - assert 'tins' in output - - def test_additional_node_dependencies_installed(tempdir_factory, store): path = make_repo(tempdir_factory, 'node_hooks_repo') config = make_config_from_repo(path) From f54386203eebe320175638b3c89dd71fdc2e8674 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Jan 2023 23:04:25 -0500 Subject: [PATCH 193/416] upgrade asottile/workflows to get fast-checkout --- .github/actions/pre-test/action.yml | 2 +- .github/workflows/main.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index 608c0cd1..42bbf00b 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -36,5 +36,5 @@ runs: testing/get-coursier.sh testing/get-dart.sh testing/get-swift.sh - - uses: asottile/workflows/.github/actions/latest-git@v1.2.0 + - uses: asottile/workflows/.github/actions/latest-git@v1.4.0 if: inputs.env == 'py38' && runner.os == 'Linux' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c78d1051..f281dcf2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,12 +12,12 @@ concurrency: jobs: main-windows: - uses: asottile/workflows/.github/workflows/tox.yml@v1.2.0 + uses: asottile/workflows/.github/workflows/tox.yml@v1.4.0 with: env: '["py38"]' os: windows-latest main-linux: - uses: asottile/workflows/.github/workflows/tox.yml@v1.2.0 + uses: asottile/workflows/.github/workflows/tox.yml@v1.4.0 with: env: '["py38", "py39", "py310"]' os: ubuntu-latest From 2530913fad5c648d2614daf5c1a5583fb609fbd8 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 31 Jan 2023 20:40:19 -0500 Subject: [PATCH 194/416] ensure languages are healthy after creation --- testing/language_helpers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/language_helpers.py b/testing/language_helpers.py index b20803bc..b9c53840 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -21,6 +21,8 @@ def run_language( version = version or language.get_default_version() language.install_environment(prefix, version, deps) + health_error = language.health_check(prefix, version) + assert health_error is None, health_error with language.in_env(prefix, version): ret, out = language.run_hook( prefix, From 909dd0e8a1984300b37611a79cf33ad3dd92aa98 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 31 Jan 2023 19:37:37 -0500 Subject: [PATCH 195/416] test node directly --- .../node_hooks_repo/.pre-commit-hooks.yaml | 5 --- testing/resources/node_hooks_repo/bin/main.js | 3 -- .../resources/node_hooks_repo/package.json | 5 --- .../.pre-commit-hooks.yaml | 6 --- .../node_versioned_hooks_repo/bin/main.js | 4 -- .../node_versioned_hooks_repo/package.json | 5 --- tests/languages/node_test.py | 41 +++++++++++++++++ tests/repository_test.py | 44 ------------------- 8 files changed, 41 insertions(+), 72 deletions(-) delete mode 100644 testing/resources/node_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/node_hooks_repo/bin/main.js delete mode 100644 testing/resources/node_hooks_repo/package.json delete mode 100644 testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/node_versioned_hooks_repo/bin/main.js delete mode 100644 testing/resources/node_versioned_hooks_repo/package.json diff --git a/testing/resources/node_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/node_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 257698a4..00000000 --- a/testing/resources/node_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: foo - name: Foo - entry: foo - language: node - files: \.js$ diff --git a/testing/resources/node_hooks_repo/bin/main.js b/testing/resources/node_hooks_repo/bin/main.js deleted file mode 100644 index 8e0f025a..00000000 --- a/testing/resources/node_hooks_repo/bin/main.js +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -console.log('Hello World'); diff --git a/testing/resources/node_hooks_repo/package.json b/testing/resources/node_hooks_repo/package.json deleted file mode 100644 index 050b6300..00000000 --- a/testing/resources/node_hooks_repo/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "foo", - "version": "0.0.1", - "bin": {"foo": "./bin/main.js"} -} diff --git a/testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index e7ad5ea7..00000000 --- a/testing/resources/node_versioned_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- id: versioned-node-hook - name: Versioned node hook - entry: versioned-node-hook - language: node - language_version: 9.3.0 - files: \.js$ diff --git a/testing/resources/node_versioned_hooks_repo/bin/main.js b/testing/resources/node_versioned_hooks_repo/bin/main.js deleted file mode 100644 index df12cbeb..00000000 --- a/testing/resources/node_versioned_hooks_repo/bin/main.js +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env node - -console.log(process.version); -console.log('Hello World'); diff --git a/testing/resources/node_versioned_hooks_repo/package.json b/testing/resources/node_versioned_hooks_repo/package.json deleted file mode 100644 index 18c7787c..00000000 --- a/testing/resources/node_versioned_hooks_repo/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "versioned-node-hook", - "version": "0.0.1", - "bin": {"versioned-node-hook": "./bin/main.js"} -} diff --git a/tests/languages/node_test.py b/tests/languages/node_test.py index b69adfa6..cba0228b 100644 --- a/tests/languages/node_test.py +++ b/tests/languages/node_test.py @@ -13,7 +13,9 @@ from pre_commit import envcontext from pre_commit import parse_shebang from pre_commit.languages import node from pre_commit.prefix import Prefix +from pre_commit.store import _make_local_repo from pre_commit.util import cmd_output +from testing.language_helpers import run_language from testing.util import xfailif_windows @@ -109,3 +111,42 @@ def test_installs_without_links_outside_env(tmpdir): with node.in_env(prefix, 'system'): assert cmd_output('foo')[1] == 'success!\n' + + +def _make_hello_world(tmp_path): + package_json = '''\ +{"name": "t", "version": "0.0.1", "bin": {"node-hello": "./bin/main.js"}} +''' + tmp_path.joinpath('package.json').write_text(package_json) + bin_dir = tmp_path.joinpath('bin') + bin_dir.mkdir() + bin_dir.joinpath('main.js').write_text( + '#!/usr/bin/env node\n' + 'console.log("Hello World");\n', + ) + + +def test_node_hook_system(tmp_path): + _make_hello_world(tmp_path) + ret = run_language(tmp_path, node, 'node-hello') + assert ret == (0, b'Hello World\n') + + +def test_node_with_user_config_set(tmp_path): + cfg = tmp_path.joinpath('cfg') + cfg.write_text('cache=/dne\n') + with envcontext.envcontext((('NPM_CONFIG_USERCONFIG', str(cfg)),)): + test_node_hook_system(tmp_path) + + +@pytest.mark.parametrize('version', (C.DEFAULT, '18.13.0')) +def test_node_hook_versions(tmp_path, version): + _make_hello_world(tmp_path) + ret = run_language(tmp_path, node, 'node-hello', version=version) + assert ret == (0, b'Hello World\n') + + +def test_node_additional_deps(tmp_path): + _make_local_repo(str(tmp_path)) + ret, out = run_language(tmp_path, node, 'npm ls -g', deps=('lodash',)) + assert b' lodash@' in out diff --git a/tests/repository_test.py b/tests/repository_test.py index 2cd4c0fa..b43b344c 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -17,7 +17,6 @@ from pre_commit.envcontext import envcontext from pre_commit.hook import Hook from pre_commit.languages import golang from pre_commit.languages import helpers -from pre_commit.languages import node from pre_commit.languages import python from pre_commit.languages.all import languages from pre_commit.prefix import Prefix @@ -193,38 +192,6 @@ def test_run_a_docker_image_hook(tempdir_factory, store, hook_id): ) -def test_run_a_node_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'node_hooks_repo', - 'foo', [os.devnull], b'Hello World\n', - ) - - -def test_run_a_node_hook_default_version(tempdir_factory, store): - # make sure that this continues to work for platforms where node is not - # installed at the system - with mock.patch.object( - node, - 'get_default_version', - return_value=C.DEFAULT, - ): - test_run_a_node_hook(tempdir_factory, store) - - -def test_run_versioned_node_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'node_versioned_hooks_repo', - 'versioned-node-hook', [os.devnull], b'v9.3.0\nHello World\n', - ) - - -def test_node_hook_with_npm_userconfig_set(tempdir_factory, store, tmpdir): - cfg = tmpdir.join('cfg') - cfg.write('cache=/dne\n') - with mock.patch.dict(os.environ, NPM_CONFIG_USERCONFIG=str(cfg)): - test_run_a_node_hook(tempdir_factory, store) - - def test_system_hook_with_spaces(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'system_hook_with_spaces_repo', @@ -482,17 +449,6 @@ def test_repository_state_compatibility(tempdir_factory, store, v): assert _hook_installed(hook) is True -def test_additional_node_dependencies_installed(tempdir_factory, store): - path = make_repo(tempdir_factory, 'node_hooks_repo') - config = make_config_from_repo(path) - # Careful to choose a small package that's not depped by npm - config['hooks'][0]['additional_dependencies'] = ['lodash'] - hook = _get_hook(config, store, 'foo') - with node.in_env(hook.prefix, hook.language_version): - output = cmd_output('npm', 'ls', '-g')[1] - assert 'lodash' in output - - def test_additional_golang_dependencies_installed( tempdir_factory, store, ): From d216cdd5c1eccab623a71aa8b58813e4850f167d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 1 Feb 2023 18:16:09 -0500 Subject: [PATCH 196/416] fix golang version regex in test --- tests/languages/golang_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 0219261f..7c04255b 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -1,9 +1,9 @@ from __future__ import annotations -import re from unittest import mock import pytest +import re_assert import pre_commit.constants as C from pre_commit.languages import golang @@ -40,4 +40,4 @@ def test_golang_infer_go_version_default(): version = ACTUAL_INFER_GO_VERSION(C.DEFAULT) assert version != C.DEFAULT - assert re.match(r'^\d+\.\d+\.\d+$', version) + re_assert.Matches(r'^\d+\.\d+(?:\.\d+)?$').assert_matches(version) From 7260d24d0fb0577f2111626b25d4f7bba56bfa5d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 1 Feb 2023 17:52:53 -0500 Subject: [PATCH 197/416] Revert "also ignore Gemfile in project" This reverts commit f4bd44996c888f48bc3a37d5ab19514325cb3f01. --- pre_commit/languages/ruby.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index b4d4b45a..4416f728 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -39,7 +39,6 @@ def get_env_patch( ('GEM_HOME', os.path.join(venv, 'gems')), ('GEM_PATH', UNSET), ('BUNDLE_IGNORE_CONFIG', '1'), - ('BUNDLE_GEMFILE', os.devnull), ) if language_version == 'system': patches += ( From 1129e7d222fea31c9c536da0ae41610349854128 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 1 Feb 2023 17:58:08 -0500 Subject: [PATCH 198/416] fixup Gemfile in ruby tests --- tests/languages/ruby_test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index b312c7fd..9cfaad5d 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -123,8 +123,9 @@ def test_ruby_hook_language_version(tmp_path): def test_ruby_with_bundle_disable_shared_gems(tmp_path): workdir = tmp_path.joinpath('workdir') workdir.mkdir() - # this Gemfile is missing `source` - workdir.joinpath('Gemfile').write_text('gem "lol_hai"\n') + # this needs a `source` or there's a deprecation warning + # silencing this with `BUNDLE_GEMFILE` breaks some tools (#2739) + workdir.joinpath('Gemfile').write_text('source ""\ngem "lol_hai"\n') # this bundle config causes things to be written elsewhere bundle = workdir.joinpath('.bundle') bundle.mkdir() @@ -134,5 +135,5 @@ def test_ruby_with_bundle_disable_shared_gems(tmp_path): ) with cwd(workdir): - # `3.2.0` has new enough `gem` requiring `source` and reading `.bundle` + # `3.2.0` has new enough `gem` reading `.bundle` test_ruby_hook_language_version(tmp_path) From e846829992a84ce8066e6513a72a357709eec56c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 1 Feb 2023 18:21:18 -0500 Subject: [PATCH 199/416] v3.0.3 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0657e63..adf1e4b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.0.3 - 2023-02-01 +================== + +### Fixes +- Revert "Prevent local `Gemfile` from interfering with hook execution.". + - #2739 issue by @Roguelazer. + - #2740 PR by @asottile. + 3.0.2 - 2023-01-29 ================== diff --git a/setup.cfg b/setup.cfg index 37511c09..8eb9de7a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.0.2 +version = 3.0.3 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 7783a3e63a18ea3fb073eef5412b985153abdee8 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Thu, 2 Feb 2023 11:02:58 +0000 Subject: [PATCH 200/416] Add `--no-textconv` to `git diff` calls --- pre_commit/commands/run.py | 6 +++--- tests/commands/run_test.py | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index e44e7036..a7eb4f45 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -272,7 +272,8 @@ def _all_filenames(args: argparse.Namespace) -> Collection[str]: def _get_diff() -> bytes: _, out, _ = cmd_output_b( - 'git', 'diff', '--no-ext-diff', '--ignore-submodules', check=False, + 'git', 'diff', '--no-ext-diff', '--no-textconv', '--ignore-submodules', + check=False, ) return out @@ -326,8 +327,7 @@ def _has_unmerged_paths() -> bool: def _has_unstaged_config(config_file: str) -> bool: retcode, _, _ = cmd_output_b( - 'git', 'diff', '--no-ext-diff', '--exit-code', config_file, - check=False, + 'git', 'diff', '--quiet', '--no-ext-diff', config_file, check=False, ) # be explicit, other git errors don't mean it has an unstaged config. return retcode == 1 diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 03d741e0..f1085d9b 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -766,6 +766,47 @@ def test_lots_of_files(store, tempdir_factory): ) +def test_no_textconv(cap_out, store, repo_with_passing_hook): + # git textconv filters can hide changes from hooks + with open('.gitattributes', 'w') as fp: + fp.write('*.jpeg diff=empty\n') + + with open('.git/config', 'a') as fp: + fp.write('[diff "empty"]\n') + fp.write('textconv = "true"\n') + + config = { + 'repo': 'local', + 'hooks': [ + { + 'id': 'extend-jpeg', + 'name': 'extend-jpeg', + 'language': 'system', + 'entry': ( + f'{shlex.quote(sys.executable)} -c "import sys; ' + 'open(sys.argv[1], \'ab\').write(b\'\\x00\')"' + ), + 'types': ['jpeg'], + }, + ], + } + add_config_to_repo(repo_with_passing_hook, config) + + stage_a_file('example.jpeg') + + _test_run( + cap_out, + store, + repo_with_passing_hook, + {}, + ( + b'Failed', + ), + expected_ret=1, + stage=False, + ) + + def test_stages(cap_out, store, repo_with_passing_hook): config = { 'repo': 'local', From 0359fae2da2aadb2fbd3afae1777edd3aa856cc9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 3 Feb 2023 12:07:23 -0500 Subject: [PATCH 201/416] v3.0.4 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adf1e4b3..0998da98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.0.4 - 2023-02-03 +================== + +### Fixes +- Fix hook diff detection for files affected by `--textconv`. + - #2743 PR by @adamchainz. + - #2743 issue by @adamchainz. + 3.0.3 - 2023-02-01 ================== diff --git a/setup.cfg b/setup.cfg index 8eb9de7a..56b856ca 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.0.3 +version = 3.0.4 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 0c1267b214cee6da7337f7bcd42b89fd13015e26 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 4 Feb 2023 14:26:09 -0500 Subject: [PATCH 202/416] deprecate python_venv language --- pre_commit/commands/migrate_config.py | 9 +++++ pre_commit/repository.py | 9 +++++ .../.pre-commit-hooks.yaml | 5 --- .../resources/python_venv_hooks_repo/foo.py | 9 ----- .../resources/python_venv_hooks_repo/setup.py | 10 ------ tests/commands/migrate_config_test.py | 33 +++++++++++++++++++ tests/languages/all_test.py | 7 ++++ tests/repository_test.py | 20 ++++++++--- 8 files changed, 73 insertions(+), 29 deletions(-) delete mode 100644 testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/python_venv_hooks_repo/foo.py delete mode 100644 testing/resources/python_venv_hooks_repo/setup.py create mode 100644 tests/languages/all_test.py diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index 6f7af4eb..842fb3a7 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -42,6 +42,14 @@ def _migrate_sha_to_rev(contents: str) -> str: return re.sub(r'(\n\s+)sha:', r'\1rev:', contents) +def _migrate_python_venv(contents: str) -> str: + return re.sub( + r'(\n\s+)language: python_venv\b', + r'\1language: python', + contents, + ) + + def migrate_config(config_file: str, quiet: bool = False) -> int: with open(config_file) as f: orig_contents = contents = f.read() @@ -55,6 +63,7 @@ def migrate_config(config_file: str, quiet: bool = False) -> int: contents = _migrate_map(contents) contents = _migrate_sha_to_rev(contents) + contents = _migrate_python_venv(contents) if contents != orig_contents: with open(config_file, 'w') as f: diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 616faf54..308e80c7 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -3,6 +3,7 @@ from __future__ import annotations import json import logging import os +import shlex from typing import Any from typing import Sequence @@ -68,6 +69,14 @@ def _hook_install(hook: Hook) -> None: logger.info('Once installed this environment will be reused.') logger.info('This may take a few minutes...') + if hook.language == 'python_venv': + logger.warning( + f'`repo: {hook.src}` uses deprecated `language: python_venv`. ' + f'This is an alias for `language: python`. ' + f'Often `pre-commit autoupdate --repo {shlex.quote(hook.src)}` ' + f'will fix this.', + ) + lang = languages[hook.language] assert lang.ENVIRONMENT_DIR is not None diff --git a/testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index a666ed87..00000000 --- a/testing/resources/python_venv_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: foo - name: Foo - entry: foo - language: python_venv - files: \.py$ diff --git a/testing/resources/python_venv_hooks_repo/foo.py b/testing/resources/python_venv_hooks_repo/foo.py deleted file mode 100644 index 40efde39..00000000 --- a/testing/resources/python_venv_hooks_repo/foo.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import annotations - -import sys - - -def main(): - print(repr(sys.argv[1:])) - print('Hello World') - return 0 diff --git a/testing/resources/python_venv_hooks_repo/setup.py b/testing/resources/python_venv_hooks_repo/setup.py deleted file mode 100644 index cff6cadf..00000000 --- a/testing/resources/python_venv_hooks_repo/setup.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import annotations - -from setuptools import setup - -setup( - name='foo', - version='0.0.0', - py_modules=['foo'], - entry_points={'console_scripts': ['foo = foo:main']}, -) diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py index fca1ad92..ba184636 100644 --- a/tests/commands/migrate_config_test.py +++ b/tests/commands/migrate_config_test.py @@ -134,6 +134,39 @@ def test_migrate_config_sha_to_rev(tmpdir): ) +def test_migrate_config_language_python_venv(tmp_path): + src = '''\ +repos: +- repo: local + hooks: + - id: example + name: example + entry: example + language: python_venv + - id: example + name: example + entry: example + language: system +''' + expected = '''\ +repos: +- repo: local + hooks: + - id: example + name: example + entry: example + language: python + - id: example + name: example + entry: example + language: system +''' + cfg = tmp_path.joinpath('cfg.yaml') + cfg.write_text(src) + assert migrate_config(str(cfg)) == 0 + assert cfg.read_text() == expected + + def test_migrate_config_invalid_yaml(tmpdir): contents = '[' cfg = tmpdir.join(C.CONFIG_FILE) diff --git a/tests/languages/all_test.py b/tests/languages/all_test.py new file mode 100644 index 00000000..33b8925f --- /dev/null +++ b/tests/languages/all_test.py @@ -0,0 +1,7 @@ +from __future__ import annotations + +from pre_commit.languages.all import languages + + +def test_python_venv_is_an_alias_to_python(): + assert languages['python_venv'] is languages['python'] diff --git a/tests/repository_test.py b/tests/repository_test.py index b43b344c..9ec2d549 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -129,11 +129,21 @@ def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store): ) -def test_python_venv(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'python_venv_hooks_repo', - 'foo', [os.devnull], - f'[{os.devnull!r}]\nHello World\n'.encode(), +def test_python_venv_deprecation(store, caplog): + config = { + 'repo': 'local', + 'hooks': [{ + 'id': 'example', + 'name': 'example', + 'language': 'python_venv', + 'entry': 'echo hi', + }], + } + _get_hook(config, store, 'example') + assert caplog.messages[-1] == ( + '`repo: local` uses deprecated `language: python_venv`. ' + 'This is an alias for `language: python`. ' + 'Often `pre-commit autoupdate --repo local` will fix this.' ) From 0afb95ccca2f590bf45f45bcafb8ca792ce66423 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 4 Feb 2023 16:50:40 -0500 Subject: [PATCH 203/416] test docker and docker_image directly --- pre_commit/languages/docker.py | 3 +- testing/language_helpers.py | 7 ++-- .../docker_hooks_repo/.pre-commit-hooks.yaml | 17 -------- .../resources/docker_hooks_repo/Dockerfile | 3 -- .../.pre-commit-hooks.yaml | 8 ---- testing/util.py | 15 ------- tests/languages/docker_image_test.py | 27 +++++++++++++ tests/languages/docker_test.py | 14 +++++++ tests/repository_test.py | 40 ------------------- 9 files changed, 46 insertions(+), 88 deletions(-) delete mode 100644 testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/docker_hooks_repo/Dockerfile delete mode 100644 testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml create mode 100644 tests/languages/docker_image_test.py diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index e80c9597..2212c5cc 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -138,9 +138,8 @@ def run_hook( entry_exe, *cmd_rest = helpers.hook_cmd(entry, args) entry_tag = ('--entrypoint', entry_exe, docker_tag(prefix)) - cmd = (*docker_cmd(), *entry_tag, *cmd_rest) return helpers.run_xargs( - cmd, + (*docker_cmd(), *entry_tag, *cmd_rest), file_args, require_serial=require_serial, color=color, diff --git a/testing/language_helpers.py b/testing/language_helpers.py index b9c53840..0964fbb4 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -20,9 +20,10 @@ def run_language( prefix = Prefix(str(path)) version = version or language.get_default_version() - language.install_environment(prefix, version, deps) - health_error = language.health_check(prefix, version) - assert health_error is None, health_error + if language.ENVIRONMENT_DIR is not None: + language.install_environment(prefix, version, deps) + health_error = language.health_check(prefix, version) + assert health_error is None, health_error with language.in_env(prefix, version): ret, out = language.run_hook( prefix, diff --git a/testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 52957396..00000000 --- a/testing/resources/docker_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,17 +0,0 @@ -- id: docker-hook - name: Docker test hook - entry: echo - language: docker - files: \.txt$ - -- id: docker-hook-arg - name: Docker test hook - entry: echo -n - language: docker - files: \.txt$ - -- id: docker-hook-failing - name: Docker test hook with nonzero exit code - entry: bork - language: docker - files: \.txt$ diff --git a/testing/resources/docker_hooks_repo/Dockerfile b/testing/resources/docker_hooks_repo/Dockerfile deleted file mode 100644 index 0bd1de0c..00000000 --- a/testing/resources/docker_hooks_repo/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM ubuntu:focal - -CMD ["echo", "This is overwritten by the .pre-commit-hooks.yaml 'entry'"] diff --git a/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index e9fb2456..00000000 --- a/testing/resources/docker_image_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,8 +0,0 @@ -- id: echo-entrypoint - name: echo (via --entrypoint) - language: docker_image - entry: --entrypoint echo ubuntu:focal -- id: echo-cmd - name: echo (via cmd) - language: docker_image - entry: ubuntu:focal echo diff --git a/testing/util.py b/testing/util.py index b6c3804e..7c68d0ee 100644 --- a/testing/util.py +++ b/testing/util.py @@ -6,24 +6,13 @@ import subprocess import pytest -from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output -from pre_commit.util import cmd_output_b from testing.auto_namedtuple import auto_namedtuple TESTING_DIR = os.path.abspath(os.path.dirname(__file__)) -def docker_is_running() -> bool: # pragma: win32 no cover - try: - cmd_output_b('docker', 'ps') - except CalledProcessError: # pragma: no cover - return False - else: - return True - - def get_resource_path(path): return os.path.join(TESTING_DIR, 'resources', path) @@ -41,10 +30,6 @@ def cmd_output_mocked_pre_commit_home( return ret, out.replace('\r\n', '\n'), None -skipif_cant_run_docker = pytest.mark.skipif( - os.name == 'nt' or not docker_is_running(), - reason="Docker isn't running or can't be accessed", -) xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows') diff --git a/tests/languages/docker_image_test.py b/tests/languages/docker_image_test.py new file mode 100644 index 00000000..7993c11a --- /dev/null +++ b/tests/languages/docker_image_test.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from pre_commit.languages import docker_image +from testing.language_helpers import run_language +from testing.util import xfailif_windows + + +@xfailif_windows # pragma: win32 no cover +def test_docker_image_hook_via_entrypoint(tmp_path): + ret = run_language( + tmp_path, + docker_image, + '--entrypoint echo ubuntu:22.04', + args=('hello hello world',), + ) + assert ret == (0, b'hello hello world\n') + + +@xfailif_windows # pragma: win32 no cover +def test_docker_image_hook_via_args(tmp_path): + ret = run_language( + tmp_path, + docker_image, + 'ubuntu:22.04 echo', + args=('hello hello world',), + ) + assert ret == (0, b'hello hello world\n') diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index 5f7c85e7..836382a8 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -11,6 +11,8 @@ import pytest from pre_commit.languages import docker from pre_commit.util import CalledProcessError +from testing.language_helpers import run_language +from testing.util import xfailif_windows DOCKER_CGROUP_EXAMPLE = b'''\ 12:hugetlb:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 @@ -181,3 +183,15 @@ def test_get_docker_path_in_docker_docker_in_docker(in_docker): err = CalledProcessError(1, (), b'', b'') with mock.patch.object(docker, 'cmd_output_b', side_effect=err): assert docker._get_docker_path('/project') == '/project' + + +@xfailif_windows # pragma: win32 no cover +def test_docker_hook(tmp_path): + dockerfile = '''\ +FROM ubuntu:22.04 +CMD ["echo", "This is overwritten by the entry"'] +''' + tmp_path.joinpath('Dockerfile').write_text(dockerfile) + + ret = run_language(tmp_path, docker, 'echo hello hello world') + assert ret == (0, b'hello hello world\n') diff --git a/tests/repository_test.py b/tests/repository_test.py index 9ec2d549..a4dcda5b 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -30,7 +30,6 @@ from testing.fixtures import make_repo from testing.fixtures import modify_manifest from testing.util import cwd from testing.util import get_resource_path -from testing.util import skipif_cant_run_docker def _norm_out(b): @@ -163,45 +162,6 @@ def test_language_versioned_python_hook(tempdir_factory, store): ) -@skipif_cant_run_docker # pragma: win32 no cover -def test_run_a_docker_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'docker_hooks_repo', - 'docker-hook', - ['Hello World from docker'], b'Hello World from docker\n', - ) - - -@skipif_cant_run_docker # pragma: win32 no cover -def test_run_a_docker_hook_with_entry_args(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'docker_hooks_repo', - 'docker-hook-arg', - ['Hello World from docker'], b'Hello World from docker', - ) - - -@skipif_cant_run_docker # pragma: win32 no cover -def test_run_a_failing_docker_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'docker_hooks_repo', - 'docker-hook-failing', - ['Hello World from docker'], - mock.ANY, # an error message about `bork` not existing - expected_return_code=127, - ) - - -@skipif_cant_run_docker # pragma: win32 no cover -@pytest.mark.parametrize('hook_id', ('echo-entrypoint', 'echo-cmd')) -def test_run_a_docker_image_hook(tempdir_factory, store, hook_id): - _test_hook_repo( - tempdir_factory, store, 'docker_image_hooks_repo', - hook_id, - ['Hello World from docker'], b'Hello World from docker\n', - ) - - def test_system_hook_with_spaces(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'system_hook_with_spaces_repo', From 6804100701a40c7defdbd5027e459385ceeba8f2 Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:24:30 -0600 Subject: [PATCH 204/416] test golang directly --- .../golang_hooks_repo/.pre-commit-hooks.yaml | 5 - testing/resources/golang_hooks_repo/go.mod | 5 - testing/resources/golang_hooks_repo/go.sum | 2 - .../golang-hello-world/main.go | 23 ---- tests/languages/golang_test.py | 93 +++++++++++++ tests/repository_test.py | 126 ------------------ tests/store_test.py | 24 ++++ 7 files changed, 117 insertions(+), 161 deletions(-) delete mode 100644 testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/golang_hooks_repo/go.mod delete mode 100644 testing/resources/golang_hooks_repo/go.sum delete mode 100644 testing/resources/golang_hooks_repo/golang-hello-world/main.go diff --git a/testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 206733bb..00000000 --- a/testing/resources/golang_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: golang-hook - name: golang example hook - entry: golang-hello-world - language: golang - files: '' diff --git a/testing/resources/golang_hooks_repo/go.mod b/testing/resources/golang_hooks_repo/go.mod deleted file mode 100644 index f37d4b67..00000000 --- a/testing/resources/golang_hooks_repo/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module golang-hello-world - -go 1.18 - -require github.com/BurntSushi/toml v1.1.0 diff --git a/testing/resources/golang_hooks_repo/go.sum b/testing/resources/golang_hooks_repo/go.sum deleted file mode 100644 index ec0c385a..00000000 --- a/testing/resources/golang_hooks_repo/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= diff --git a/testing/resources/golang_hooks_repo/golang-hello-world/main.go b/testing/resources/golang_hooks_repo/golang-hello-world/main.go deleted file mode 100644 index 16857438..00000000 --- a/testing/resources/golang_hooks_repo/golang-hello-world/main.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - - -import ( - "fmt" - "runtime" - "github.com/BurntSushi/toml" - "os" -) - -type Config struct { - What string -} - -func main() { - message := runtime.Version() - if len(os.Args) > 1 { - message = os.Args[1] - } - var conf Config - toml.Decode("What = 'world'\n", &conf) - fmt.Printf("hello %v from %s\n", conf.What, message) -} diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 7c04255b..f5f9985b 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -6,8 +6,11 @@ import pytest import re_assert import pre_commit.constants as C +from pre_commit.envcontext import envcontext from pre_commit.languages import golang from pre_commit.languages import helpers +from pre_commit.store import _make_local_repo +from testing.language_helpers import run_language ACTUAL_GET_DEFAULT_VERSION = golang.get_default_version.__wrapped__ @@ -41,3 +44,93 @@ def test_golang_infer_go_version_default(): assert version != C.DEFAULT re_assert.Matches(r'^\d+\.\d+(?:\.\d+)?$').assert_matches(version) + + +def _make_hello_world(tmp_path): + go_mod = '''\ +module golang-hello-world + +go 1.18 + +require github.com/BurntSushi/toml v1.1.0 +''' + go_sum = '''\ +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +''' # noqa: E501 + hello_world_go = '''\ +package main + + +import ( + "fmt" + "github.com/BurntSushi/toml" +) + +type Config struct { + What string +} + +func main() { + var conf Config + toml.Decode("What = 'world'\\n", &conf) + fmt.Printf("hello %v\\n", conf.What) +} +''' + tmp_path.joinpath('go.mod').write_text(go_mod) + tmp_path.joinpath('go.sum').write_text(go_sum) + mod_dir = tmp_path.joinpath('golang-hello-world') + mod_dir.mkdir() + main_file = mod_dir.joinpath('main.go') + main_file.write_text(hello_world_go) + + +def test_golang_system(tmp_path): + _make_hello_world(tmp_path) + + ret = run_language(tmp_path, golang, 'golang-hello-world') + assert ret == (0, b'hello world\n') + + +def test_golang_default_version(tmp_path): + _make_hello_world(tmp_path) + + ret = run_language( + tmp_path, + golang, + 'golang-hello-world', + version=C.DEFAULT, + ) + assert ret == (0, b'hello world\n') + + +def test_golang_versioned(tmp_path): + _make_local_repo(str(tmp_path)) + + ret, out = run_language( + tmp_path, + golang, + 'go version', + version='1.18.4', + ) + + assert ret == 0 + assert out.startswith(b'go version go1.18.4') + + +def test_local_golang_additional_deps(tmp_path): + _make_local_repo(str(tmp_path)) + + ret = run_language( + tmp_path, + golang, + 'hello', + deps=('golang.org/x/example/hello@latest',), + ) + + assert ret == (0, b'Hello, Go examples!\n') + + +def test_golang_hook_still_works_when_gobin_is_set(tmp_path): + with envcontext((('GOBIN', str(tmp_path.joinpath('gobin'))),)): + test_golang_system(tmp_path) diff --git a/tests/repository_test.py b/tests/repository_test.py index a4dcda5b..0c9bba74 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -10,12 +10,9 @@ import pytest import re_assert import pre_commit.constants as C -from pre_commit import git from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import load_manifest -from pre_commit.envcontext import envcontext from pre_commit.hook import Hook -from pre_commit.languages import golang from pre_commit.languages import helpers from pre_commit.languages import python from pre_commit.languages.all import languages @@ -169,92 +166,6 @@ def test_system_hook_with_spaces(tempdir_factory, store): ) -def test_golang_system_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'golang_hooks_repo', - 'golang-hook', ['system'], b'hello world from system\n', - config_kwargs={ - 'hooks': [{ - 'id': 'golang-hook', - 'language_version': 'system', - }], - }, - ) - - -def test_golang_versioned_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'golang_hooks_repo', - 'golang-hook', [], b'hello world from go1.18.4\n', - config_kwargs={ - 'hooks': [{ - 'id': 'golang-hook', - 'language_version': '1.18.4', - }], - }, - ) - - -def test_golang_hook_still_works_when_gobin_is_set(tempdir_factory, store): - gobin_dir = tempdir_factory.get() - with envcontext((('GOBIN', gobin_dir),)): - test_golang_system_hook(tempdir_factory, store) - assert os.listdir(gobin_dir) == [] - - -def test_golang_with_recursive_submodule(tmpdir, tempdir_factory, store): - sub_go = '''\ -package sub - -import "fmt" - -func Func() { - fmt.Println("hello hello world") -} -''' - sub = tmpdir.join('sub').ensure_dir() - sub.join('sub.go').write(sub_go) - cmd_output('git', '-C', str(sub), 'init', '.') - cmd_output('git', '-C', str(sub), 'add', '.') - git.commit(str(sub)) - - pre_commit_hooks = '''\ -- id: example - name: example - entry: example - language: golang - verbose: true -''' - go_mod = '''\ -module github.com/asottile/example - -go 1.14 -''' - main_go = '''\ -package main - -import "github.com/asottile/example/sub" - -func main() { - sub.Func() -} -''' - repo = tmpdir.join('repo').ensure_dir() - repo.join('.pre-commit-hooks.yaml').write(pre_commit_hooks) - repo.join('go.mod').write(go_mod) - repo.join('main.go').write(main_go) - cmd_output('git', '-C', str(repo), 'init', '.') - cmd_output('git', '-C', str(repo), 'add', '.') - cmd_output('git', '-C', str(repo), 'submodule', 'add', str(sub), 'sub') - git.commit(str(repo)) - - config = make_config_from_repo(str(repo)) - hook = _get_hook(config, store, 'example') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - assert _norm_out(out) == b'hello hello world\n' - - def test_missing_executable(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'not_found_exe', @@ -419,43 +330,6 @@ def test_repository_state_compatibility(tempdir_factory, store, v): assert _hook_installed(hook) is True -def test_additional_golang_dependencies_installed( - tempdir_factory, store, -): - path = make_repo(tempdir_factory, 'golang_hooks_repo') - config = make_config_from_repo(path) - # A small go package - deps = ['golang.org/x/example/hello@latest'] - config['hooks'][0]['additional_dependencies'] = deps - hook = _get_hook(config, store, 'golang-hook') - envdir = helpers.environment_dir( - hook.prefix, - golang.ENVIRONMENT_DIR, - golang.get_default_version(), - ) - binaries = os.listdir(os.path.join(envdir, 'bin')) - # normalize for windows - binaries = [os.path.splitext(binary)[0] for binary in binaries] - assert 'hello' in binaries - - -def test_local_golang_additional_dependencies(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'hello', - 'name': 'hello', - 'entry': 'hello', - 'language': 'golang', - 'additional_dependencies': ['golang.org/x/example/hello@latest'], - }], - } - hook = _get_hook(config, store, 'hello') - ret, out = _hook_run(hook, (), color=False) - assert ret == 0 - assert _norm_out(out) == b'Hello, Go examples!\n' - - def test_fail_hooks(store): config = { 'repo': 'local', diff --git a/tests/store_test.py b/tests/store_test.py index c42ce653..146eac41 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -246,3 +246,27 @@ def test_mark_config_as_used_readonly(tmpdir): # should be skipped due to readonly store.mark_config_used(str(cfg)) assert store.select_all_configs() == [] + + +def test_clone_with_recursive_submodules(store, tmp_path): + sub = tmp_path.joinpath('sub') + sub.mkdir() + sub.joinpath('submodule').write_text('i am a submodule') + cmd_output('git', '-C', str(sub), 'init', '.') + cmd_output('git', '-C', str(sub), 'add', '.') + git.commit(str(sub)) + + repo = tmp_path.joinpath('repo') + repo.mkdir() + repo.joinpath('repository').write_text('i am a repo') + cmd_output('git', '-C', str(repo), 'init', '.') + cmd_output('git', '-C', str(repo), 'add', '.') + cmd_output('git', '-C', str(repo), 'submodule', 'add', str(sub), 'sub') + git.commit(str(repo)) + + rev = git.head_rev(str(repo)) + ret = store.clone(str(repo), rev) + + assert os.path.exists(ret) + assert os.path.exists(os.path.join(ret, str(repo), 'repository')) + assert os.path.exists(os.path.join(ret, str(sub), 'submodule')) From 915b930a5d0c894a4b0d2a6957f833179255cd42 Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Tue, 7 Feb 2023 21:22:26 -0600 Subject: [PATCH 205/416] test dotnet directly --- pre_commit/languages/dotnet.py | 4 - .../.pre-commit-hooks.yaml | 12 -- .../dotnet_hooks_combo_repo.sln | 28 ---- .../dotnet_hooks_combo_repo/proj1/Program.cs | 12 -- .../proj1/proj1.csproj | 12 -- .../dotnet_hooks_combo_repo/proj2/Program.cs | 12 -- .../proj2/proj2.csproj | 12 -- .../.gitignore | 3 - .../.pre-commit-hooks.yaml | 5 - .../Program.cs | 12 -- .../dotnet_hooks_csproj_prefix_repo.csproj | 9 - .../dotnet_hooks_csproj_repo/.gitignore | 3 - .../.pre-commit-hooks.yaml | 5 - .../dotnet_hooks_csproj_repo/Program.cs | 12 -- .../dotnet_hooks_csproj_repo.csproj | 9 - .../dotnet_hooks_sln_repo/.gitignore | 3 - .../.pre-commit-hooks.yaml | 5 - .../dotnet_hooks_sln_repo/Program.cs | 12 -- .../dotnet_hooks_sln_repo.csproj | 9 - .../dotnet_hooks_sln_repo.sln | 34 ---- tests/languages/dotnet_test.py | 154 ++++++++++++++++++ tests/repository_test.py | 16 -- 22 files changed, 154 insertions(+), 229 deletions(-) delete mode 100644 testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln delete mode 100644 testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs delete mode 100644 testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj delete mode 100644 testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs delete mode 100644 testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj delete mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore delete mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs delete mode 100644 testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj delete mode 100644 testing/resources/dotnet_hooks_csproj_repo/.gitignore delete mode 100644 testing/resources/dotnet_hooks_csproj_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/dotnet_hooks_csproj_repo/Program.cs delete mode 100644 testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj delete mode 100644 testing/resources/dotnet_hooks_sln_repo/.gitignore delete mode 100644 testing/resources/dotnet_hooks_sln_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/dotnet_hooks_sln_repo/Program.cs delete mode 100644 testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj delete mode 100644 testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.sln diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 4c3955e8..05d4ce32 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -109,7 +109,3 @@ def install_environment( tool_id, ), ) - - # Clean the git dir, ignoring the environment dir - clean_cmd = ('git', 'clean', '-ffxd', '-e', f'{ENVIRONMENT_DIR}-*') - helpers.run_setup_cmd(prefix, clean_cmd) diff --git a/testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml b/testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml deleted file mode 100644 index f221854a..00000000 --- a/testing/resources/dotnet_hooks_combo_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,12 +0,0 @@ -- id: dotnet-example-hook - name: Test Project 1 - description: Test Project 1 - entry: proj1 - language: dotnet - stages: [commit] -- id: proj2 - name: Test Project 2 - description: Test Project 2 - entry: proj2 - language: dotnet - stages: [commit] diff --git a/testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln b/testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln deleted file mode 100644 index edb0fcbc..00000000 --- a/testing/resources/dotnet_hooks_combo_repo/dotnet_hooks_combo_repo.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30114.105 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proj1", "proj1\proj1.csproj", "{38A939C3-DEA4-47D7-9B75-0418C4249662}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proj2", "proj2\proj2.csproj", "{4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {38A939C3-DEA4-47D7-9B75-0418C4249662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {38A939C3-DEA4-47D7-9B75-0418C4249662}.Debug|Any CPU.Build.0 = Debug|Any CPU - {38A939C3-DEA4-47D7-9B75-0418C4249662}.Release|Any CPU.ActiveCfg = Release|Any CPU - {38A939C3-DEA4-47D7-9B75-0418C4249662}.Release|Any CPU.Build.0 = Release|Any CPU - {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs b/testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs deleted file mode 100644 index 03876f5c..00000000 --- a/testing/resources/dotnet_hooks_combo_repo/proj1/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace proj1 -{ - class Program - { - static void Main(string[] args) - { - Console.Write("Hello from dotnet!\n"); - } - } -} diff --git a/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj b/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj deleted file mode 100644 index 861ced6d..00000000 --- a/testing/resources/dotnet_hooks_combo_repo/proj1/proj1.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - net6 - - true - proj1 - ./nupkg - - - diff --git a/testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs b/testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs deleted file mode 100644 index 47a99a35..00000000 --- a/testing/resources/dotnet_hooks_combo_repo/proj2/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace proj2 -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Hello World!"); - } - } -} diff --git a/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj b/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj deleted file mode 100644 index dfce2cad..00000000 --- a/testing/resources/dotnet_hooks_combo_repo/proj2/proj2.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - net6 - - true - proj2 - ./nupkg - - - diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore b/testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore deleted file mode 100644 index edcd28f4..00000000 --- a/testing/resources/dotnet_hooks_csproj_prefix_repo/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -bin/ -obj/ -nupkg/ diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml b/testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 6626627d..00000000 --- a/testing/resources/dotnet_hooks_csproj_prefix_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: dotnet-example-hook - name: dotnet example hook - entry: testeroni.tool - language: dotnet - files: '' diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs b/testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs deleted file mode 100644 index 1456e8ef..00000000 --- a/testing/resources/dotnet_hooks_csproj_prefix_repo/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace dotnet_hooks_repo -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Hello from dotnet!"); - } - } -} diff --git a/testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj b/testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj deleted file mode 100644 index 754b7600..00000000 --- a/testing/resources/dotnet_hooks_csproj_prefix_repo/dotnet_hooks_csproj_prefix_repo.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Exe - net7.0 - true - testeroni.tool - ./nupkg - - diff --git a/testing/resources/dotnet_hooks_csproj_repo/.gitignore b/testing/resources/dotnet_hooks_csproj_repo/.gitignore deleted file mode 100644 index edcd28f4..00000000 --- a/testing/resources/dotnet_hooks_csproj_repo/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -bin/ -obj/ -nupkg/ diff --git a/testing/resources/dotnet_hooks_csproj_repo/.pre-commit-hooks.yaml b/testing/resources/dotnet_hooks_csproj_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 0f514c11..00000000 --- a/testing/resources/dotnet_hooks_csproj_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: dotnet-example-hook - name: dotnet example hook - entry: testeroni - language: dotnet - files: '' diff --git a/testing/resources/dotnet_hooks_csproj_repo/Program.cs b/testing/resources/dotnet_hooks_csproj_repo/Program.cs deleted file mode 100644 index 1456e8ef..00000000 --- a/testing/resources/dotnet_hooks_csproj_repo/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace dotnet_hooks_repo -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Hello from dotnet!"); - } - } -} diff --git a/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj b/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj deleted file mode 100644 index fa9879b0..00000000 --- a/testing/resources/dotnet_hooks_csproj_repo/dotnet_hooks_csproj_repo.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Exe - net6 - true - testeroni - ./nupkg - - diff --git a/testing/resources/dotnet_hooks_sln_repo/.gitignore b/testing/resources/dotnet_hooks_sln_repo/.gitignore deleted file mode 100644 index edcd28f4..00000000 --- a/testing/resources/dotnet_hooks_sln_repo/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -bin/ -obj/ -nupkg/ diff --git a/testing/resources/dotnet_hooks_sln_repo/.pre-commit-hooks.yaml b/testing/resources/dotnet_hooks_sln_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 0f514c11..00000000 --- a/testing/resources/dotnet_hooks_sln_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: dotnet-example-hook - name: dotnet example hook - entry: testeroni - language: dotnet - files: '' diff --git a/testing/resources/dotnet_hooks_sln_repo/Program.cs b/testing/resources/dotnet_hooks_sln_repo/Program.cs deleted file mode 100644 index 04ad4e0c..00000000 --- a/testing/resources/dotnet_hooks_sln_repo/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace dotnet_hooks_sln_repo -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Hello from dotnet!"); - } - } -} diff --git a/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj b/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj deleted file mode 100644 index a4e2d005..00000000 --- a/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Exe - net6 - true - testeroni - ./nupkg - - diff --git a/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.sln b/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.sln deleted file mode 100644 index 87d2afba..00000000 --- a/testing/resources/dotnet_hooks_sln_repo/dotnet_hooks_sln_repo.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 -MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet_hooks_sln_repo", "dotnet_hooks_sln_repo.csproj", "{6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x64.ActiveCfg = Debug|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x64.Build.0 = Debug|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x86.ActiveCfg = Debug|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x86.Build.0 = Debug|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|Any CPU.Build.0 = Release|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x64.ActiveCfg = Release|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x64.Build.0 = Release|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x86.ActiveCfg = Release|Any CPU - {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/tests/languages/dotnet_test.py b/tests/languages/dotnet_test.py index e69de29b..470c03b2 100644 --- a/tests/languages/dotnet_test.py +++ b/tests/languages/dotnet_test.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from pre_commit.languages import dotnet +from testing.language_helpers import run_language + + +def _write_program_cs(tmp_path): + program_cs = '''\ +using System; + +namespace dotnet_tests +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello from dotnet!"); + } + } +} +''' + tmp_path.joinpath('Program.cs').write_text(program_cs) + + +def _csproj(tool_name): + return f'''\ + + + Exe + net6 + true + {tool_name} + ./nupkg + + +''' + + +def test_dotnet_csproj(tmp_path): + csproj = _csproj('testeroni') + _write_program_cs(tmp_path) + tmp_path.joinpath('dotnet_csproj.csproj').write_text(csproj) + ret = run_language(tmp_path, dotnet, 'testeroni') + assert ret == (0, b'Hello from dotnet!\n') + + +def test_dotnet_csproj_prefix(tmp_path): + csproj = _csproj('testeroni.tool') + _write_program_cs(tmp_path) + tmp_path.joinpath('dotnet_hooks_csproj_prefix.csproj').write_text(csproj) + ret = run_language(tmp_path, dotnet, 'testeroni.tool') + assert ret == (0, b'Hello from dotnet!\n') + + +def test_dotnet_sln(tmp_path): + csproj = _csproj('testeroni') + sln = '''\ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet_hooks_sln_repo", "dotnet_hooks_sln_repo.csproj", "{6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x64.ActiveCfg = Debug|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x64.Build.0 = Debug|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x86.ActiveCfg = Debug|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Debug|x86.Build.0 = Debug|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|Any CPU.Build.0 = Release|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x64.ActiveCfg = Release|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x64.Build.0 = Release|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x86.ActiveCfg = Release|Any CPU + {6568CFDB-6F6F-45A9-932C-8C7DAABC8E56}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal +''' # noqa: E501 + _write_program_cs(tmp_path) + tmp_path.joinpath('dotnet_hooks_sln_repo.csproj').write_text(csproj) + tmp_path.joinpath('dotnet_hooks_sln_repo.sln').write_text(sln) + + ret = run_language(tmp_path, dotnet, 'testeroni') + assert ret == (0, b'Hello from dotnet!\n') + + +def _setup_dotnet_combo(tmp_path): + sln = '''\ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proj1", "proj1\\proj1.csproj", "{38A939C3-DEA4-47D7-9B75-0418C4249662}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proj2", "proj2\\proj2.csproj", "{4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38A939C3-DEA4-47D7-9B75-0418C4249662}.Release|Any CPU.Build.0 = Release|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C9916CB-165C-4EF5-8A57-4CB6794C1EBF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal +''' # noqa: E501 + tmp_path.joinpath('dotnet_hooks_combo_repo.sln').write_text(sln) + + csproj1 = _csproj('proj1') + proj1 = tmp_path.joinpath('proj1') + proj1.mkdir() + proj1.joinpath('proj1.csproj').write_text(csproj1) + _write_program_cs(proj1) + + csproj2 = _csproj('proj2') + proj2 = tmp_path.joinpath('proj2') + proj2.mkdir() + proj2.joinpath('proj2.csproj').write_text(csproj2) + _write_program_cs(proj2) + + +def test_dotnet_combo_proj1(tmp_path): + _setup_dotnet_combo(tmp_path) + ret = run_language(tmp_path, dotnet, 'proj1') + assert ret == (0, b'Hello from dotnet!\n') + + +def test_dotnet_combo_proj2(tmp_path): + _setup_dotnet_combo(tmp_path) + ret = run_language(tmp_path, dotnet, 'proj2') + assert ret == (0, b'Hello from dotnet!\n') diff --git a/tests/repository_test.py b/tests/repository_test.py index 0c9bba74..9e2f1e51 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -625,22 +625,6 @@ def test_manifest_hooks(tempdir_factory, store): ) -@pytest.mark.parametrize( - 'repo', - ( - 'dotnet_hooks_csproj_repo', - 'dotnet_hooks_sln_repo', - 'dotnet_hooks_combo_repo', - 'dotnet_hooks_csproj_prefix_repo', - ), -) -def test_dotnet_hook(tempdir_factory, store, repo): - _test_hook_repo( - tempdir_factory, store, repo, - 'dotnet-example-hook', [], b'Hello from dotnet!\n', - ) - - def test_non_installable_hook_error_for_language_version(store, caplog): config = { 'repo': 'local', From abbfb2e9b9195f6ae03441a0d69e4d2f8575d416 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 8 Feb 2023 06:43:04 +0000 Subject: [PATCH 206/416] List golang as first-class language --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9bcb79e..ab3a9298 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,10 +64,10 @@ to implement. The current implemented languages are at varying levels: - 0th class - pre-commit does not require any dependencies for these languages as they're not actually languages (current examples: fail, pygrep) - 1st class - pre-commit will bootstrap a full interpreter requiring nothing to - be installed globally (current examples: node, ruby, rust) + be installed globally (current examples: go, node, ruby, rust) - 2nd class - pre-commit requires the user to install the language globally but - will install tools in an isolated fashion (current examples: python, go, - swift, docker). + will install tools in an isolated fashion (current examples: python, swift, + docker). - 3rd class - pre-commit requires the user to install both the tool and the language globally (current examples: script, system) From 563507937324d8214a82f3cfd6199ea4ace875d0 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 8 Feb 2023 11:20:30 -0500 Subject: [PATCH 207/416] force the issue template more --- .../ISSUE_TEMPLATE/{bug.yaml => 00_bug.yaml} | 6 +++ .github/ISSUE_TEMPLATE/01_feature.yaml | 38 +++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yaml | 6 +++ 3 files changed, 50 insertions(+) rename .github/ISSUE_TEMPLATE/{bug.yaml => 00_bug.yaml} (87%) create mode 100644 .github/ISSUE_TEMPLATE/01_feature.yaml create mode 100644 .github/ISSUE_TEMPLATE/config.yaml diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/00_bug.yaml similarity index 87% rename from .github/ISSUE_TEMPLATE/bug.yaml rename to .github/ISSUE_TEMPLATE/00_bug.yaml index 96cd6c75..980f7afe 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/00_bug.yaml @@ -16,6 +16,12 @@ body: placeholder: ... validations: required: true + - type: markdown + attributes: + value: | + 95% of issues created are duplicates. + please try extra hard to find them first. + it's very unlikely your problem is unique. - type: textarea id: freeform attributes: diff --git a/.github/ISSUE_TEMPLATE/01_feature.yaml b/.github/ISSUE_TEMPLATE/01_feature.yaml new file mode 100644 index 00000000..c7ddc84c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01_feature.yaml @@ -0,0 +1,38 @@ +name: feature request +description: something new +body: + - type: markdown + attributes: + value: | + this is for issues for `pre-commit` (the framework). + if you are reporting an issue for [pre-commit.ci] please report it at [pre-commit-ci/issues] + + [pre-commit.ci]: https://pre-commit.ci + [pre-commit-ci/issues]: https://github.com/pre-commit-ci/issues + - type: input + id: search + attributes: + label: search you tried in the issue tracker + placeholder: ... + validations: + required: true + - type: markdown + attributes: + value: | + 95% of issues created are duplicates. + please try extra hard to find them first. + it's very unlikely your feature idea is a new one. + - type: textarea + id: freeform + attributes: + label: describe your actual problem + placeholder: 'I want to do ... I tried ... It does not work because ...' + validations: + required: true + - type: input + id: version + attributes: + label: pre-commit --version + placeholder: pre-commit x.x.x + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 00000000..a2d14826 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1,6 @@ +blank_issues_enabled: false +contact_links: +- name: documentation + url: https://pre-commit.com +- name: pre-commit.ci issues + url: https://github.com/pre-commit-ci/issues From 16869444cae5ebea1917a2442e37eff381c44c76 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 8 Feb 2023 11:21:50 -0500 Subject: [PATCH 208/416] git mv .github/ISSUE_TEMPLATE/config.{yaml,yml} --- .github/ISSUE_TEMPLATE/{config.yaml => config.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{config.yaml => config.yml} (100%) diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/config.yaml rename to .github/ISSUE_TEMPLATE/config.yml From 4bd1677cda652a92c38a6051e7b8a1d76e36364b Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 8 Feb 2023 11:23:43 -0500 Subject: [PATCH 209/416] do template links need about? --- .github/ISSUE_TEMPLATE/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index a2d14826..4179f47f 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,5 +2,7 @@ blank_issues_enabled: false contact_links: - name: documentation url: https://pre-commit.com + about: please check the docs first - name: pre-commit.ci issues url: https://github.com/pre-commit-ci/issues + about: please report issues about pre-commit.ci here From 4fdfb25a5245e63dd424f72ef7f66dfe49b2b53b Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Fri, 10 Feb 2023 16:18:43 -0600 Subject: [PATCH 210/416] test fail language inline --- tests/languages/fail_test.py | 14 ++++++++++++++ tests/repository_test.py | 24 ------------------------ 2 files changed, 14 insertions(+), 24 deletions(-) create mode 100644 tests/languages/fail_test.py diff --git a/tests/languages/fail_test.py b/tests/languages/fail_test.py new file mode 100644 index 00000000..7c74886f --- /dev/null +++ b/tests/languages/fail_test.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from pre_commit.languages import fail +from testing.language_helpers import run_language + + +def test_fail_hooks(tmp_path): + ret = run_language( + tmp_path, + fail, + 'watch out for', + file_args=('bunnies',), + ) + assert ret == (1, b'watch out for\n\nbunnies\n') diff --git a/tests/repository_test.py b/tests/repository_test.py index 9e2f1e51..1a16e691 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -330,30 +330,6 @@ def test_repository_state_compatibility(tempdir_factory, store, v): assert _hook_installed(hook) is True -def test_fail_hooks(store): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'fail', - 'name': 'fail', - 'language': 'fail', - 'entry': 'make sure to name changelogs as .rst!', - 'files': r'changelog/.*(? Date: Tue, 14 Feb 2023 02:25:01 +0000 Subject: [PATCH 211/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.991 → v1.0.0](https://github.com/pre-commit/mirrors-mypy/compare/v0.991...v1.0.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b7d7f1f0..023f4f68 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.991 + rev: v1.0.0 hooks: - id: mypy additional_dependencies: [types-all] From 8db5aaf4f32f9ac3d4407f70478d0aa15c0d4680 Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Fri, 17 Feb 2023 21:30:46 -0600 Subject: [PATCH 212/416] future-proof dotnet build command see https://github.com/dotnet/sdk/issues/30624#issuecomment-1435457318 --- pre_commit/languages/dotnet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 05d4ce32..3db2679d 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -61,7 +61,7 @@ def install_environment( helpers.assert_no_additional_deps('dotnet', additional_dependencies) envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) - build_dir = 'pre-commit-build' + build_dir = prefix.path('pre-commit-build') # Build & pack nupkg file helpers.run_setup_cmd( @@ -69,7 +69,7 @@ def install_environment( ( 'dotnet', 'pack', '--configuration', 'Release', - '--output', build_dir, + '--property', f'PackageOutputPath={build_dir}', ), ) From a2373d0a8198425785951cbd5f037d9815abb2ab Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Wed, 15 Feb 2023 20:50:19 -0600 Subject: [PATCH 213/416] test pygrep inline --- tests/languages/pygrep_test.py | 17 +++++++++++++ tests/repository_test.py | 46 ---------------------------------- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/tests/languages/pygrep_test.py b/tests/languages/pygrep_test.py index 8420046c..c6271c80 100644 --- a/tests/languages/pygrep_test.py +++ b/tests/languages/pygrep_test.py @@ -3,6 +3,7 @@ from __future__ import annotations import pytest from pre_commit.languages import pygrep +from testing.language_helpers import run_language @pytest.fixture @@ -13,6 +14,9 @@ def some_files(tmpdir): tmpdir.join('f4').write_binary(b'foo\npattern\nbar\n') tmpdir.join('f5').write_binary(b'[INFO] hi\npattern\nbar') tmpdir.join('f6').write_binary(b"pattern\nbarwith'foo\n") + tmpdir.join('f7').write_binary(b"hello'hi\nworld\n") + tmpdir.join('f8').write_binary(b'foo\nbar\nbaz\n') + tmpdir.join('f9').write_binary(b'[WARN] hi\n') with tmpdir.as_cwd(): yield @@ -125,3 +129,16 @@ def test_multiline_multiline_flag_is_enabled(cap_out): out = cap_out.get() assert ret == 1 assert out == 'f1:1:foo\nbar\n' + + +def test_grep_hook_matching(some_files, tmp_path): + ret = run_language( + tmp_path, pygrep, 'ello', file_args=('f7', 'f8', 'f9'), + ) + assert ret == (1, b"f7:1:hello'hi\n") + + +@pytest.mark.parametrize('regex', ('nope', "foo'bar", r'^\[INFO\]')) +def test_grep_hook_not_matching(regex, some_files, tmp_path): + ret = run_language(tmp_path, pygrep, regex, file_args=('f7', 'f8', 'f9')) + assert ret == (0, b'') diff --git a/tests/repository_test.py b/tests/repository_test.py index 1a16e691..332816d2 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -226,52 +226,6 @@ def test_output_isatty(tempdir_factory, store): ) -def _make_grep_repo(entry, store, args=()): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'grep-hook', - 'name': 'grep-hook', - 'language': 'pygrep', - 'entry': entry, - 'args': args, - 'types': ['text'], - }], - } - return _get_hook(config, store, 'grep-hook') - - -@pytest.fixture -def greppable_files(tmpdir): - with tmpdir.as_cwd(): - cmd_output_b('git', 'init', '.') - tmpdir.join('f1').write_binary(b"hello'hi\nworld\n") - tmpdir.join('f2').write_binary(b'foo\nbar\nbaz\n') - tmpdir.join('f3').write_binary(b'[WARN] hi\n') - yield tmpdir - - -def test_grep_hook_matching(greppable_files, store): - hook = _make_grep_repo('ello', store) - ret, out = _hook_run(hook, ('f1', 'f2', 'f3'), color=False) - assert ret == 1 - assert _norm_out(out) == b"f1:1:hello'hi\n" - - -def test_grep_hook_case_insensitive(greppable_files, store): - hook = _make_grep_repo('ELLO', store, args=['-i']) - ret, out = _hook_run(hook, ('f1', 'f2', 'f3'), color=False) - assert ret == 1 - assert _norm_out(out) == b"f1:1:hello'hi\n" - - -@pytest.mark.parametrize('regex', ('nope', "foo'bar", r'^\[INFO\]')) -def test_grep_hook_not_matching(regex, greppable_files, store): - hook = _make_grep_repo(regex, store) - ret, out = _hook_run(hook, ('f1', 'f2', 'f3'), color=False) - assert (ret, out) == (0, b'') - - def _norm_pwd(path): # Under windows bash's temp and windows temp is different. # This normalizes to the bash /tmp From d3883ce7f77f6cb88b622326de23c09cf8552cf6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Feb 2023 17:59:15 -0500 Subject: [PATCH 214/416] move languages.all and languages.helpers out of languages --- pre_commit/all_languages.py | 48 +++++++++ pre_commit/clientlib.py | 8 +- pre_commit/commands/run.py | 2 +- .../{languages/helpers.py => lang_base.py} | 45 ++++++++- pre_commit/languages/all.py | 99 ------------------- pre_commit/languages/conda.py | 14 +-- pre_commit/languages/coursier.py | 18 ++-- pre_commit/languages/dart.py | 20 ++-- pre_commit/languages/docker.py | 20 ++-- pre_commit/languages/docker_image.py | 14 +-- pre_commit/languages/dotnet.py | 20 ++-- pre_commit/languages/fail.py | 10 +- pre_commit/languages/golang.py | 16 +-- pre_commit/languages/lua.py | 18 ++-- pre_commit/languages/node.py | 18 ++-- pre_commit/languages/perl.py | 14 +-- pre_commit/languages/pygrep.py | 10 +- pre_commit/languages/python.py | 14 +-- pre_commit/languages/r.py | 12 +-- pre_commit/languages/ruby.py | 24 ++--- pre_commit/languages/rust.py | 12 +-- pre_commit/languages/script.py | 14 +-- pre_commit/languages/swift.py | 16 +-- pre_commit/languages/system.py | 12 +-- pre_commit/repository.py | 4 +- testing/language_helpers.py | 2 +- .../all_test.py => all_languages_test.py} | 2 +- .../helpers_test.py => lang_base_test.py} | 34 +++---- tests/languages/golang_test.py | 4 +- tests/repository_test.py | 12 +-- 30 files changed, 274 insertions(+), 282 deletions(-) create mode 100644 pre_commit/all_languages.py rename pre_commit/{languages/helpers.py => lang_base.py} (75%) delete mode 100644 pre_commit/languages/all.py rename tests/{languages/all_test.py => all_languages_test.py} (75%) rename tests/{languages/helpers_test.py => lang_base_test.py} (78%) diff --git a/pre_commit/all_languages.py b/pre_commit/all_languages.py new file mode 100644 index 00000000..2bed7067 --- /dev/null +++ b/pre_commit/all_languages.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +from pre_commit.lang_base import Language +from pre_commit.languages import conda +from pre_commit.languages import coursier +from pre_commit.languages import dart +from pre_commit.languages import docker +from pre_commit.languages import docker_image +from pre_commit.languages import dotnet +from pre_commit.languages import fail +from pre_commit.languages import golang +from pre_commit.languages import lua +from pre_commit.languages import node +from pre_commit.languages import perl +from pre_commit.languages import pygrep +from pre_commit.languages import python +from pre_commit.languages import r +from pre_commit.languages import ruby +from pre_commit.languages import rust +from pre_commit.languages import script +from pre_commit.languages import swift +from pre_commit.languages import system + + +languages: dict[str, Language] = { + 'conda': conda, + 'coursier': coursier, + 'dart': dart, + 'docker': docker, + 'docker_image': docker_image, + 'dotnet': dotnet, + 'fail': fail, + 'golang': golang, + 'lua': lua, + 'node': node, + 'perl': perl, + 'pygrep': pygrep, + 'python': python, + 'r': r, + 'ruby': ruby, + 'rust': rust, + 'script': script, + 'swift': swift, + 'system': system, + # TODO: fully deprecate `python_venv` + 'python_venv': python, +} +language_names = sorted(languages) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index e191d3a0..9ff38c6a 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -12,8 +12,8 @@ import cfgv from identify.identify import ALL_TAGS import pre_commit.constants as C +from pre_commit.all_languages import language_names from pre_commit.errors import FatalError -from pre_commit.languages.all import all_languages from pre_commit.yaml import yaml_load logger = logging.getLogger('pre_commit') @@ -49,7 +49,7 @@ MANIFEST_HOOK_DICT = cfgv.Map( cfgv.Required('id', cfgv.check_string), cfgv.Required('name', cfgv.check_string), cfgv.Required('entry', cfgv.check_string), - cfgv.Required('language', cfgv.check_one_of(all_languages)), + cfgv.Required('language', cfgv.check_one_of(language_names)), cfgv.Optional('alias', cfgv.check_string, ''), cfgv.Optional('files', check_string_regex, ''), @@ -281,8 +281,8 @@ CONFIG_REPO_DICT = cfgv.Map( ) DEFAULT_LANGUAGE_VERSION = cfgv.Map( 'DefaultLanguageVersion', None, - cfgv.NoAdditionalKeys(all_languages), - *(cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages), + cfgv.NoAdditionalKeys(language_names), + *(cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in language_names), ) CONFIG_SCHEMA = cfgv.Map( 'Config', None, diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index a7eb4f45..c9bc55b4 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -19,9 +19,9 @@ from identify.identify import tags_from_path from pre_commit import color from pre_commit import git from pre_commit import output +from pre_commit.all_languages import languages from pre_commit.clientlib import load_config from pre_commit.hook import Hook -from pre_commit.languages.all import languages from pre_commit.repository import all_hooks from pre_commit.repository import install_hook_envs from pre_commit.staged_files_only import staged_files_only diff --git a/pre_commit/languages/helpers.py b/pre_commit/lang_base.py similarity index 75% rename from pre_commit/languages/helpers.py rename to pre_commit/lang_base.py index d1be409c..6ba412f0 100644 --- a/pre_commit/languages/helpers.py +++ b/pre_commit/lang_base.py @@ -7,8 +7,10 @@ import random import re import shlex from typing import Any +from typing import ContextManager from typing import Generator from typing import NoReturn +from typing import Protocol from typing import Sequence import pre_commit.constants as C @@ -22,6 +24,47 @@ FIXED_RANDOM_SEED = 1542676187 SHIMS_RE = re.compile(r'[/\\]shims[/\\]') +class Language(Protocol): + # Use `None` for no installation / environment + @property + def ENVIRONMENT_DIR(self) -> str | None: ... + # return a value to replace `'default` for `language_version` + def get_default_version(self) -> str: ... + # return whether the environment is healthy (or should be rebuilt) + def health_check(self, prefix: Prefix, version: str) -> str | None: ... + + # install a repository for the given language and language_version + def install_environment( + self, + prefix: Prefix, + version: str, + additional_dependencies: Sequence[str], + ) -> None: + ... + + # modify the environment for hook execution + def in_env( + self, + prefix: Prefix, + version: str, + ) -> ContextManager[None]: + ... + + # execute a hook and return the exit code and output + def run_hook( + self, + prefix: Prefix, + entry: str, + args: Sequence[str], + file_args: Sequence[str], + *, + is_local: bool, + require_serial: bool, + color: bool, + ) -> tuple[int, bytes]: + ... + + def exe_exists(exe: str) -> bool: found = parse_shebang.find_executable(exe) if found is None: # exe exists @@ -45,7 +88,7 @@ def exe_exists(exe: str) -> bool: ) -def run_setup_cmd(prefix: Prefix, cmd: tuple[str, ...], **kwargs: Any) -> None: +def setup_cmd(prefix: Prefix, cmd: tuple[str, ...], **kwargs: Any) -> None: cmd_output_b(*cmd, cwd=prefix.prefix_dir, **kwargs) diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py deleted file mode 100644 index d952ae1a..00000000 --- a/pre_commit/languages/all.py +++ /dev/null @@ -1,99 +0,0 @@ -from __future__ import annotations - -from typing import ContextManager -from typing import Protocol -from typing import Sequence - -from pre_commit.languages import conda -from pre_commit.languages import coursier -from pre_commit.languages import dart -from pre_commit.languages import docker -from pre_commit.languages import docker_image -from pre_commit.languages import dotnet -from pre_commit.languages import fail -from pre_commit.languages import golang -from pre_commit.languages import lua -from pre_commit.languages import node -from pre_commit.languages import perl -from pre_commit.languages import pygrep -from pre_commit.languages import python -from pre_commit.languages import r -from pre_commit.languages import ruby -from pre_commit.languages import rust -from pre_commit.languages import script -from pre_commit.languages import swift -from pre_commit.languages import system -from pre_commit.prefix import Prefix - - -class Language(Protocol): - # Use `None` for no installation / environment - @property - def ENVIRONMENT_DIR(self) -> str | None: ... - # return a value to replace `'default` for `language_version` - def get_default_version(self) -> str: ... - - # return whether the environment is healthy (or should be rebuilt) - def health_check( - self, - prefix: Prefix, - language_version: str, - ) -> str | None: - ... - - # install a repository for the given language and language_version - def install_environment( - self, - prefix: Prefix, - version: str, - additional_dependencies: Sequence[str], - ) -> None: - ... - - # modify the environment for hook execution - def in_env( - self, - prefix: Prefix, - version: str, - ) -> ContextManager[None]: - ... - - # execute a hook and return the exit code and output - def run_hook( - self, - prefix: Prefix, - entry: str, - args: Sequence[str], - file_args: Sequence[str], - *, - is_local: bool, - require_serial: bool, - color: bool, - ) -> tuple[int, bytes]: - ... - - -languages: dict[str, Language] = { - 'conda': conda, - 'coursier': coursier, - 'dart': dart, - 'docker': docker, - 'docker_image': docker_image, - 'dotnet': dotnet, - 'fail': fail, - 'golang': golang, - 'lua': lua, - 'node': node, - 'perl': perl, - 'pygrep': pygrep, - 'python': python, - 'r': r, - 'ruby': ruby, - 'rust': rust, - 'script': script, - 'swift': swift, - 'system': system, - # TODO: fully deprecate `python_venv` - 'python_venv': python, -} -all_languages = sorted(languages) diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index e2fb0196..05f1d291 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -5,19 +5,19 @@ import os from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import SubstitutionT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'conda' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def get_env_patch(env: str) -> PatchesT: @@ -41,7 +41,7 @@ def get_env_patch(env: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -60,11 +60,11 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('conda', version) + lang_base.assert_version_default('conda', version) conda_exe = _conda_exe() - env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + env_dir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) cmd_output_b( conda_exe, 'env', 'create', '-p', env_dir, '--file', 'environment.yml', cwd=prefix.prefix_dir, diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 60757588..9c5fbfe2 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -5,19 +5,19 @@ import os.path from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var from pre_commit.errors import FatalError -from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix ENVIRONMENT_DIR = 'coursier' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def install_environment( @@ -25,7 +25,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('coursier', version) + lang_base.assert_version_default('coursier', version) # Support both possible executable names (either "cs" or "coursier") cs = find_executable('cs') or find_executable('coursier') @@ -35,12 +35,12 @@ def install_environment( 'executables in the application search path', ) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) def _install(*opts: str) -> None: assert cs is not None - helpers.run_setup_cmd(prefix, (cs, 'fetch', *opts)) - helpers.run_setup_cmd(prefix, (cs, 'install', '--dir', envdir, *opts)) + lang_base.setup_cmd(prefix, (cs, 'fetch', *opts)) + lang_base.setup_cmd(prefix, (cs, 'install', '--dir', envdir, *opts)) with in_env(prefix, version): channel = prefix.path('.pre-commit-channel') @@ -71,6 +71,6 @@ def get_env_patch(target_dir: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index e3c1c585..e8539caa 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -7,19 +7,19 @@ import tempfile from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import win_exe from pre_commit.yaml import yaml_load ENVIRONMENT_DIR = 'dartenv' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def get_env_patch(venv: str) -> PatchesT: @@ -30,7 +30,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -40,9 +40,9 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('dart', version) + lang_base.assert_version_default('dart', version) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) bin_dir = os.path.join(envdir, 'bin') def _install_dir(prefix_p: Prefix, pub_cache: str) -> None: @@ -51,10 +51,10 @@ def install_environment( with open(prefix_p.path('pubspec.yaml')) as f: pubspec_contents = yaml_load(f) - helpers.run_setup_cmd(prefix_p, ('dart', 'pub', 'get'), env=dart_env) + lang_base.setup_cmd(prefix_p, ('dart', 'pub', 'get'), env=dart_env) for executable in pubspec_contents['executables']: - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix_p, ( 'dart', 'compile', 'exe', @@ -77,7 +77,7 @@ def install_environment( else: dep_cmd = (dep,) - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix, ('dart', 'pub', 'cache', 'add', *dep_cmd), env={**os.environ, 'PUB_CACHE': dep_tmp}, diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 2212c5cc..8e53ca9e 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -5,16 +5,16 @@ import json import os from typing import Sequence -from pre_commit.languages import helpers +from pre_commit import lang_base from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output_b ENVIRONMENT_DIR = 'docker' PRE_COMMIT_LABEL = 'PRE_COMMIT' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -in_env = helpers.no_env # no special environment for docker +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +in_env = lang_base.no_env # no special environment for docker def _is_in_docker() -> bool: @@ -84,16 +84,16 @@ def build_docker_image( cmd += ('--pull',) # This must come last for old versions of docker. See #477 cmd += ('.',) - helpers.run_setup_cmd(prefix, cmd) + lang_base.setup_cmd(prefix, cmd) def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: # pragma: win32 no cover - helpers.assert_version_default('docker', version) - helpers.assert_no_additional_deps('docker', additional_dependencies) + lang_base.assert_version_default('docker', version) + lang_base.assert_no_additional_deps('docker', additional_dependencies) - directory = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + directory = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) # Docker doesn't really have relevant disk environment, but pre-commit # still needs to cleanup its state files on failure @@ -135,10 +135,10 @@ def run_hook( # automated cleanup of docker images. build_docker_image(prefix, pull=False) - entry_exe, *cmd_rest = helpers.hook_cmd(entry, args) + entry_exe, *cmd_rest = lang_base.hook_cmd(entry, args) entry_tag = ('--entrypoint', entry_exe, docker_tag(prefix)) - return helpers.run_xargs( + return lang_base.run_xargs( (*docker_cmd(), *entry_tag, *cmd_rest), file_args, require_serial=require_serial, diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index 8e5f2c04..26f006e4 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -2,15 +2,15 @@ from __future__ import annotations from typing import Sequence -from pre_commit.languages import helpers +from pre_commit import lang_base from pre_commit.languages.docker import docker_cmd from pre_commit.prefix import Prefix ENVIRONMENT_DIR = None -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -install_environment = helpers.no_install -in_env = helpers.no_env +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +install_environment = lang_base.no_install +in_env = lang_base.no_env def run_hook( @@ -23,8 +23,8 @@ def run_hook( require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover - cmd = docker_cmd() + helpers.hook_cmd(entry, args) - return helpers.run_xargs( + cmd = docker_cmd() + lang_base.hook_cmd(entry, args) + return lang_base.run_xargs( cmd, file_args, require_serial=require_serial, diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index 3db2679d..e9568f22 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -9,18 +9,18 @@ import zipfile from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix ENVIRONMENT_DIR = 'dotnetenv' BIN_DIR = 'bin' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def get_env_patch(venv: str) -> PatchesT: @@ -31,7 +31,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -57,14 +57,14 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('dotnet', version) - helpers.assert_no_additional_deps('dotnet', additional_dependencies) + lang_base.assert_version_default('dotnet', version) + lang_base.assert_no_additional_deps('dotnet', additional_dependencies) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) build_dir = prefix.path('pre-commit-build') # Build & pack nupkg file - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix, ( 'dotnet', 'pack', @@ -99,7 +99,7 @@ def install_environment( # Install to bin dir with _nuget_config_no_sources() as nuget_config: - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix, ( 'dotnet', 'tool', 'install', diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index 33df067e..a8ec6a53 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -2,14 +2,14 @@ from __future__ import annotations from typing import Sequence -from pre_commit.languages import helpers +from pre_commit import lang_base from pre_commit.prefix import Prefix ENVIRONMENT_DIR = None -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -install_environment = helpers.no_install -in_env = helpers.no_env +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +install_environment = lang_base.no_install +in_env = lang_base.no_env def run_hook( diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 3c4b652f..bea91e9b 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -19,17 +19,17 @@ from typing import Protocol from typing import Sequence import pre_commit.constants as C +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output from pre_commit.util import rmtree ENVIRONMENT_DIR = 'golangenv' -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook _ARCH_ALIASES = { 'x86_64': 'amd64', @@ -60,7 +60,7 @@ else: # pragma: win32 no cover @functools.lru_cache(maxsize=1) def get_default_version() -> str: - if helpers.exe_exists('go'): + if lang_base.exe_exists('go'): return 'system' else: return C.DEFAULT @@ -121,7 +121,7 @@ def _install_go(version: str, dest: str) -> None: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir, version)): yield @@ -131,7 +131,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + env_dir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) if version != 'system': _install_go(version, env_dir) @@ -149,9 +149,9 @@ def install_environment( os.path.join(env_dir, '.go', 'bin'), os.environ['PATH'], )) - helpers.run_setup_cmd(prefix, ('go', 'install', './...'), env=env) + lang_base.setup_cmd(prefix, ('go', 'install', './...'), env=env) for dependency in additional_dependencies: - helpers.run_setup_cmd(prefix, ('go', 'install', dependency), env=env) + lang_base.setup_cmd(prefix, ('go', 'install', dependency), env=env) # save some disk space -- we don't need this after installation pkgdir = os.path.join(env_dir, 'pkg') diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index ffc40b50..12d06614 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -6,17 +6,17 @@ import sys from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output ENVIRONMENT_DIR = 'lua_env' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def _get_lua_version() -> str: # pragma: win32 no cover @@ -45,7 +45,7 @@ def get_env_patch(d: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -55,9 +55,9 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: # pragma: win32 no cover - helpers.assert_version_default('lua', version) + lang_base.assert_version_default('lua', version) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with in_env(prefix, version): # luarocks doesn't bootstrap a tree prior to installing # so ensure the directory exists. @@ -66,10 +66,10 @@ def install_environment( # Older luarocks (e.g., 2.4.2) expect the rockspec as an arg for rockspec in prefix.star('.rockspec'): make_cmd = ('luarocks', '--tree', envdir, 'make', rockspec) - helpers.run_setup_cmd(prefix, make_cmd) + lang_base.setup_cmd(prefix, make_cmd) # luarocks can't install multiple packages at once # so install them individually. for dependency in additional_dependencies: cmd = ('luarocks', '--tree', envdir, 'install', dependency) - helpers.run_setup_cmd(prefix, cmd) + lang_base.setup_cmd(prefix, cmd) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 9688da35..66d61363 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -8,11 +8,11 @@ from typing import Generator from typing import Sequence import pre_commit.constants as C +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.languages.python import bin_dir from pre_commit.prefix import Prefix from pre_commit.util import cmd_output @@ -20,7 +20,7 @@ from pre_commit.util import cmd_output_b from pre_commit.util import rmtree ENVIRONMENT_DIR = 'node_env' -run_hook = helpers.basic_run_hook +run_hook = lang_base.basic_run_hook @functools.lru_cache(maxsize=1) @@ -30,7 +30,7 @@ def get_default_version() -> str: return C.DEFAULT # if node is already installed, we can save a bunch of setup time by # using the installed version - elif all(helpers.exe_exists(exe) for exe in ('node', 'npm')): + elif all(lang_base.exe_exists(exe) for exe in ('node', 'npm')): return 'system' else: return C.DEFAULT @@ -60,13 +60,13 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield -def health_check(prefix: Prefix, language_version: str) -> str | None: - with in_env(prefix, language_version): +def health_check(prefix: Prefix, version: str) -> str | None: + with in_env(prefix, version): retcode, _, _ = cmd_output_b('node', '--version', check=False) if retcode != 0: # pragma: win32 no cover return f'`node --version` returned {retcode}' @@ -78,7 +78,7 @@ def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: assert prefix.exists('package.json') - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) # https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath if sys.platform == 'win32': # pragma: no cover @@ -96,13 +96,13 @@ def install_environment( 'npm', 'install', '--dev', '--prod', '--ignore-prepublish', '--no-progress', '--no-save', ) - helpers.run_setup_cmd(prefix, local_install_cmd) + lang_base.setup_cmd(prefix, local_install_cmd) _, pkg, _ = cmd_output('npm', 'pack', cwd=prefix.prefix_dir) pkg = prefix.path(pkg.strip()) install = ('npm', 'install', '-g', pkg, *additional_dependencies) - helpers.run_setup_cmd(prefix, install) + lang_base.setup_cmd(prefix, install) # clean these up after installation if prefix.exists('node_modules'): # pragma: win32 no cover diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 2530c0ee..2a7f1629 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -6,16 +6,16 @@ import shlex from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix ENVIRONMENT_DIR = 'perl_env' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def get_env_patch(venv: str) -> PatchesT: @@ -34,7 +34,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -42,9 +42,9 @@ def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: - helpers.assert_version_default('perl', version) + lang_base.assert_version_default('perl', version) with in_env(prefix, version): - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix, ('cpan', '-T', '.', *additional_dependencies), ) diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index f0eb9a95..ec55560b 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -7,16 +7,16 @@ from typing import NamedTuple from typing import Pattern from typing import Sequence +from pre_commit import lang_base from pre_commit import output -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.xargs import xargs ENVIRONMENT_DIR = None -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -install_environment = helpers.no_install -in_env = helpers.no_env +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +install_environment = lang_base.no_install +in_env = lang_base.no_env def _process_filename_by_line(pattern: Pattern[bytes], filename: str) -> int: diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index c373646b..976674e2 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -8,11 +8,11 @@ from typing import Generator from typing import Sequence import pre_commit.constants as C +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError @@ -21,7 +21,7 @@ from pre_commit.util import cmd_output_b from pre_commit.util import win_exe ENVIRONMENT_DIR = 'py_env' -run_hook = helpers.basic_run_hook +run_hook = lang_base.basic_run_hook @functools.lru_cache(maxsize=None) @@ -153,13 +153,13 @@ def norm_version(version: str) -> str | None: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield -def health_check(prefix: Prefix, language_version: str) -> str | None: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, language_version) +def health_check(prefix: Prefix, version: str) -> str | None: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) pyvenv_cfg = os.path.join(envdir, 'pyvenv.cfg') # created with "old" virtualenv @@ -202,7 +202,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) venv_cmd = [sys.executable, '-mvirtualenv', envdir] python = norm_version(version) if python is not None: @@ -211,4 +211,4 @@ def install_environment( cmd_output_b(*venv_cmd, cwd='/') with in_env(prefix, version): - helpers.run_setup_cmd(prefix, install_cmd) + lang_base.setup_cmd(prefix, install_cmd) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index e2383658..138a26e1 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -7,18 +7,18 @@ import shutil from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b from pre_commit.util import win_exe ENVIRONMENT_DIR = 'renv' RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ') -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check def get_env_patch(venv: str) -> PatchesT: @@ -30,7 +30,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -93,7 +93,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - env_dir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + env_dir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) shutil.copytree(prefix.path('renv'), os.path.join(env_dir, 'renv')) @@ -166,7 +166,7 @@ def run_hook( color: bool, ) -> tuple[int, bytes]: cmd = _cmd_from_hook(prefix, entry, args, is_local=is_local) - return helpers.run_xargs( + return lang_base.run_xargs( cmd, file_args, require_serial=require_serial, diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 4416f728..0ee0a857 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -9,23 +9,23 @@ from typing import Generator from typing import Sequence import pre_commit.constants as C +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError from pre_commit.util import resource_bytesio ENVIRONMENT_DIR = 'rbenv' -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook @functools.lru_cache(maxsize=1) def get_default_version() -> str: - if all(helpers.exe_exists(exe) for exe in ('ruby', 'gem')): + if all(lang_base.exe_exists(exe) for exe in ('ruby', 'gem')): return 'system' else: return C.DEFAULT @@ -68,7 +68,7 @@ def get_env_patch( @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir, version)): yield @@ -83,7 +83,7 @@ def _install_rbenv( prefix: Prefix, version: str, ) -> None: # pragma: win32 no cover - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) _extract_resource('rbenv.tar.gz', prefix.path('.')) shutil.move(prefix.path('rbenv'), envdir) @@ -100,10 +100,10 @@ def _install_ruby( version: str, ) -> None: # pragma: win32 no cover try: - helpers.run_setup_cmd(prefix, ('rbenv', 'download', version)) + lang_base.setup_cmd(prefix, ('rbenv', 'download', version)) except CalledProcessError: # pragma: no cover (usually find with download) # Failed to download from mirror for some reason, build it instead - helpers.run_setup_cmd(prefix, ('rbenv', 'install', version)) + lang_base.setup_cmd(prefix, ('rbenv', 'install', version)) def install_environment( @@ -114,17 +114,17 @@ def install_environment( with in_env(prefix, version): # Need to call this before installing so rbenv's directories # are set up - helpers.run_setup_cmd(prefix, ('rbenv', 'init', '-')) + lang_base.setup_cmd(prefix, ('rbenv', 'init', '-')) if version != C.DEFAULT: _install_ruby(prefix, version) # Need to call this after installing to set up the shims - helpers.run_setup_cmd(prefix, ('rbenv', 'rehash')) + lang_base.setup_cmd(prefix, ('rbenv', 'rehash')) with in_env(prefix, version): - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix, ('gem', 'build', *prefix.star('.gemspec')), ) - helpers.run_setup_cmd( + lang_base.setup_cmd( prefix, ( 'gem', 'install', diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 391fd865..e98e0d02 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -11,19 +11,19 @@ from typing import Generator from typing import Sequence import pre_commit.constants as C +from pre_commit import lang_base from pre_commit import parse_shebang from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b from pre_commit.util import make_executable from pre_commit.util import win_exe ENVIRONMENT_DIR = 'rustenv' -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook @functools.lru_cache(maxsize=1) @@ -63,7 +63,7 @@ def get_env_patch(target_dir: str, version: str) -> PatchesT: @contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir, version)): yield @@ -78,7 +78,7 @@ def _add_dependencies( crate = f'{name}@{spec or "*"}' crates.append(crate) - helpers.run_setup_cmd(prefix, ('cargo', 'add', *crates)) + lang_base.setup_cmd(prefix, ('cargo', 'add', *crates)) def install_rust_with_toolchain(toolchain: str) -> None: @@ -116,7 +116,7 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) # There are two cases where we might want to specify more dependencies: # as dependencies for the library being built, and as binary packages diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index 08325f46..89a3ab2d 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -2,14 +2,14 @@ from __future__ import annotations from typing import Sequence -from pre_commit.languages import helpers +from pre_commit import lang_base from pre_commit.prefix import Prefix ENVIRONMENT_DIR = None -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -install_environment = helpers.no_install -in_env = helpers.no_env +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +install_environment = lang_base.no_install +in_env = lang_base.no_env def run_hook( @@ -22,9 +22,9 @@ def run_hook( require_serial: bool, color: bool, ) -> tuple[int, bytes]: - cmd = helpers.hook_cmd(entry, args) + cmd = lang_base.hook_cmd(entry, args) cmd = (prefix.path(cmd[0]), *cmd[1:]) - return helpers.run_xargs( + return lang_base.run_xargs( cmd, file_args, require_serial=require_serial, diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index c66ad5fb..8250ab70 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -5,10 +5,10 @@ import os from typing import Generator from typing import Sequence +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b @@ -16,9 +16,9 @@ BUILD_DIR = '.build' BUILD_CONFIG = 'release' ENVIRONMENT_DIR = 'swift_env' -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover @@ -28,7 +28,7 @@ def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @@ -36,9 +36,9 @@ def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: # pragma: win32 no cover - helpers.assert_version_default('swift', version) - helpers.assert_no_additional_deps('swift', additional_dependencies) - envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) + lang_base.assert_version_default('swift', version) + lang_base.assert_no_additional_deps('swift', additional_dependencies) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) # Build the swift package os.mkdir(envdir) diff --git a/pre_commit/languages/system.py b/pre_commit/languages/system.py index 204cad72..f6ad688f 100644 --- a/pre_commit/languages/system.py +++ b/pre_commit/languages/system.py @@ -1,10 +1,10 @@ from __future__ import annotations -from pre_commit.languages import helpers +from pre_commit import lang_base ENVIRONMENT_DIR = None -get_default_version = helpers.basic_get_default_version -health_check = helpers.basic_health_check -install_environment = helpers.no_install -in_env = helpers.no_env -run_hook = helpers.basic_run_hook +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +install_environment = lang_base.no_install +in_env = lang_base.no_env +run_hook = lang_base.basic_run_hook diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 308e80c7..5183df47 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -8,13 +8,13 @@ from typing import Any from typing import Sequence import pre_commit.constants as C +from pre_commit.all_languages import languages from pre_commit.clientlib import load_manifest from pre_commit.clientlib import LOCAL from pre_commit.clientlib import META from pre_commit.clientlib import parse_version from pre_commit.hook import Hook -from pre_commit.languages.all import languages -from pre_commit.languages.helpers import environment_dir +from pre_commit.lang_base import environment_dir from pre_commit.prefix import Prefix from pre_commit.store import Store from pre_commit.util import clean_path_on_failure diff --git a/testing/language_helpers.py b/testing/language_helpers.py index 0964fbb4..5ab2af2a 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -3,7 +3,7 @@ from __future__ import annotations import os from typing import Sequence -from pre_commit.languages.all import Language +from pre_commit.lang_base import Language from pre_commit.prefix import Prefix diff --git a/tests/languages/all_test.py b/tests/all_languages_test.py similarity index 75% rename from tests/languages/all_test.py rename to tests/all_languages_test.py index 33b8925f..98c91215 100644 --- a/tests/languages/all_test.py +++ b/tests/all_languages_test.py @@ -1,6 +1,6 @@ from __future__ import annotations -from pre_commit.languages.all import languages +from pre_commit.all_languages import languages def test_python_venv_is_an_alias_to_python(): diff --git a/tests/languages/helpers_test.py b/tests/lang_base_test.py similarity index 78% rename from tests/languages/helpers_test.py rename to tests/lang_base_test.py index c209e7e6..89a64a1f 100644 --- a/tests/languages/helpers_test.py +++ b/tests/lang_base_test.py @@ -8,8 +8,8 @@ from unittest import mock import pytest import pre_commit.constants as C +from pre_commit import lang_base from pre_commit import parse_shebang -from pre_commit.languages import helpers from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError @@ -32,42 +32,42 @@ def homedir_mck(): def test_exe_exists_does_not_exist(find_exe_mck, homedir_mck): find_exe_mck.return_value = None - assert helpers.exe_exists('ruby') is False + assert lang_base.exe_exists('ruby') is False def test_exe_exists_exists(find_exe_mck, homedir_mck): find_exe_mck.return_value = os.path.normpath('/usr/bin/ruby') - assert helpers.exe_exists('ruby') is True + assert lang_base.exe_exists('ruby') is True def test_exe_exists_false_if_shim(find_exe_mck, homedir_mck): find_exe_mck.return_value = os.path.normpath('/foo/shims/ruby') - assert helpers.exe_exists('ruby') is False + assert lang_base.exe_exists('ruby') is False def test_exe_exists_false_if_homedir(find_exe_mck, homedir_mck): find_exe_mck.return_value = os.path.normpath('/home/me/somedir/ruby') - assert helpers.exe_exists('ruby') is False + assert lang_base.exe_exists('ruby') is False def test_exe_exists_commonpath_raises_ValueError(find_exe_mck, homedir_mck): find_exe_mck.return_value = os.path.normpath('/usr/bin/ruby') with mock.patch.object(os.path, 'commonpath', side_effect=ValueError): - assert helpers.exe_exists('ruby') is True + assert lang_base.exe_exists('ruby') is True def test_exe_exists_true_when_homedir_is_slash(find_exe_mck): find_exe_mck.return_value = os.path.normpath('/usr/bin/ruby') with mock.patch.object(os.path, 'expanduser', return_value=os.sep): - assert helpers.exe_exists('ruby') is True + assert lang_base.exe_exists('ruby') is True def test_basic_get_default_version(): - assert helpers.basic_get_default_version() == C.DEFAULT + assert lang_base.basic_get_default_version() == C.DEFAULT def test_basic_health_check(): - assert helpers.basic_health_check(Prefix('.'), 'default') is None + assert lang_base.basic_health_check(Prefix('.'), 'default') is None def test_failed_setup_command_does_not_unicode_error(): @@ -79,12 +79,12 @@ def test_failed_setup_command_does_not_unicode_error(): # an assertion that this does not raise `UnicodeError` with pytest.raises(CalledProcessError): - helpers.run_setup_cmd(Prefix('.'), (sys.executable, '-c', script)) + lang_base.setup_cmd(Prefix('.'), (sys.executable, '-c', script)) def test_assert_no_additional_deps(): with pytest.raises(AssertionError) as excinfo: - helpers.assert_no_additional_deps('lang', ['hmmm']) + lang_base.assert_no_additional_deps('lang', ['hmmm']) msg, = excinfo.value.args assert msg == ( 'for now, pre-commit does not support additional_dependencies for ' @@ -96,19 +96,19 @@ def test_assert_no_additional_deps(): def test_target_concurrency_normal(): with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency() == 123 + assert lang_base.target_concurrency() == 123 def test_target_concurrency_testing_env_var(): with mock.patch.dict( os.environ, {'PRE_COMMIT_NO_CONCURRENCY': '1'}, clear=True, ): - assert helpers.target_concurrency() == 1 + assert lang_base.target_concurrency() == 1 def test_target_concurrency_on_travis(): with mock.patch.dict(os.environ, {'TRAVIS': '1'}, clear=True): - assert helpers.target_concurrency() == 2 + assert lang_base.target_concurrency() == 2 def test_target_concurrency_cpu_count_not_implemented(): @@ -116,17 +116,17 @@ def test_target_concurrency_cpu_count_not_implemented(): multiprocessing, 'cpu_count', side_effect=NotImplementedError, ): with mock.patch.dict(os.environ, {}, clear=True): - assert helpers.target_concurrency() == 1 + assert lang_base.target_concurrency() == 1 def test_shuffled_is_deterministic(): seq = [str(i) for i in range(10)] expected = ['4', '0', '5', '1', '8', '6', '2', '3', '7', '9'] - assert helpers._shuffled(seq) == expected + assert lang_base._shuffled(seq) == expected def test_xargs_require_serial_is_not_shuffled(): - ret, out = helpers.run_xargs( + ret, out = lang_base.run_xargs( ('echo',), [str(i) for i in range(10)], require_serial=True, color=False, diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index f5f9985b..ec5a8787 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -6,9 +6,9 @@ import pytest import re_assert import pre_commit.constants as C +from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.languages import golang -from pre_commit.languages import helpers from pre_commit.store import _make_local_repo from testing.language_helpers import run_language @@ -18,7 +18,7 @@ ACTUAL_GET_DEFAULT_VERSION = golang.get_default_version.__wrapped__ @pytest.fixture def exe_exists_mck(): - with mock.patch.object(helpers, 'exe_exists') as mck: + with mock.patch.object(lang_base, 'exe_exists') as mck: yield mck diff --git a/tests/repository_test.py b/tests/repository_test.py index 332816d2..c04eb379 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -10,12 +10,12 @@ import pytest import re_assert import pre_commit.constants as C +from pre_commit import lang_base +from pre_commit.all_languages import languages from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import load_manifest from pre_commit.hook import Hook -from pre_commit.languages import helpers from pre_commit.languages import python -from pre_commit.languages.all import languages from pre_commit.prefix import Prefix from pre_commit.repository import _hook_installed from pre_commit.repository import all_hooks @@ -275,7 +275,7 @@ def test_repository_state_compatibility(tempdir_factory, store, v): config = make_config_from_repo(path) hook = _get_hook(config, store, 'foo') - envdir = helpers.environment_dir( + envdir = lang_base.environment_dir( hook.prefix, python.ENVIRONMENT_DIR, hook.language_version, @@ -327,7 +327,7 @@ def test_control_c_control_c_on_install(tempdir_factory, store): # raise as well. with pytest.raises(MyKeyboardInterrupt): with mock.patch.object( - helpers, 'run_setup_cmd', side_effect=MyKeyboardInterrupt, + lang_base, 'setup_cmd', side_effect=MyKeyboardInterrupt, ): with mock.patch.object( shutil, 'rmtree', side_effect=MyKeyboardInterrupt, @@ -336,7 +336,7 @@ def test_control_c_control_c_on_install(tempdir_factory, store): # Should have made an environment, however this environment is broken! hook, = hooks - envdir = helpers.environment_dir( + envdir = lang_base.environment_dir( hook.prefix, python.ENVIRONMENT_DIR, hook.language_version, @@ -359,7 +359,7 @@ def test_invalidated_virtualenv(tempdir_factory, store): hook = _get_hook(config, store, 'foo') # Simulate breaking of the virtualenv - envdir = helpers.environment_dir( + envdir = lang_base.environment_dir( hook.prefix, python.ENVIRONMENT_DIR, hook.language_version, From c3613b954a7155e6143b52cb3f3defcab82ba3ae Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Feb 2023 18:18:08 -0500 Subject: [PATCH 215/416] test things more directly to improve coverage --- tests/languages/python_test.py | 23 +++++++++++++++++++++++ tests/languages/script_test.py | 14 ++++++++++++++ tests/languages/system_test.py | 9 +++++++++ tests/repository_test.py | 16 ---------------- 4 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 tests/languages/script_test.py create mode 100644 tests/languages/system_test.py diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index 54fb98fe..8bb284eb 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -12,6 +12,7 @@ from pre_commit.languages import python from pre_commit.prefix import Prefix from pre_commit.util import make_executable from pre_commit.util import win_exe +from testing.language_helpers import run_language def test_read_pyvenv_cfg(tmpdir): @@ -210,3 +211,25 @@ def test_unhealthy_then_replaced(python_dir): os.replace(f'{py_exe}.tmp', py_exe) assert python.health_check(prefix, C.DEFAULT) is None + + +def test_language_versioned_python_hook(tmp_path): + setup_py = '''\ +from setuptools import setup +setup( + name='example', + py_modules=['mod'], + entry_points={'console_scripts': ['myexe=mod:main']}, +) +''' + tmp_path.joinpath('setup.py').write_text(setup_py) + tmp_path.joinpath('mod.py').write_text('def main(): print("ohai")') + + # we patch this to force virtualenv executing with `-p` since we can't + # reliably have multiple pythons available in CI + with mock.patch.object( + python, + '_sys_executable_matches', + return_value=False, + ): + assert run_language(tmp_path, python, 'myexe') == (0, b'ohai\n') diff --git a/tests/languages/script_test.py b/tests/languages/script_test.py new file mode 100644 index 00000000..a02f615a --- /dev/null +++ b/tests/languages/script_test.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from pre_commit.languages import script +from pre_commit.util import make_executable +from testing.language_helpers import run_language + + +def test_script_language(tmp_path): + exe = tmp_path.joinpath('main') + exe.write_text('#!/usr/bin/env bash\necho hello hello world\n') + make_executable(exe) + + expected = (0, b'hello hello world\n') + assert run_language(tmp_path, script, 'main') == expected diff --git a/tests/languages/system_test.py b/tests/languages/system_test.py new file mode 100644 index 00000000..dcd9cf1e --- /dev/null +++ b/tests/languages/system_test.py @@ -0,0 +1,9 @@ +from __future__ import annotations + +from pre_commit.languages import system +from testing.language_helpers import run_language + + +def test_system_language(tmp_path): + expected = (0, b'hello hello world\n') + assert run_language(tmp_path, system, 'echo hello hello world') == expected diff --git a/tests/repository_test.py b/tests/repository_test.py index 332816d2..e8b54070 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -143,22 +143,6 @@ def test_python_venv_deprecation(store, caplog): ) -def test_language_versioned_python_hook(tempdir_factory, store): - # we patch this force virtualenv executing with `-p` since we can't - # reliably have multiple pythons available in CI - with mock.patch.object( - python, - '_sys_executable_matches', - return_value=False, - ): - _test_hook_repo( - tempdir_factory, store, 'python3_hooks_repo', - 'python3-hook', - [os.devnull], - f'3\n[{os.devnull!r}]\nHello World\n'.encode(), - ) - - def test_system_hook_with_spaces(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'system_hook_with_spaces_repo', From 0cc2856883adc8910c522f4c8eb4ba2b397ebff0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 02:06:17 +0000 Subject: [PATCH 216/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.0.0 → v1.0.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.0...v1.0.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 023f4f68..ad8ffba7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.0.0 + rev: v1.0.1 hooks: - id: mypy additional_dependencies: [types-all] From 25b8ad752831dbbe9c5469760baffef16f4630f6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Feb 2023 21:32:32 -0500 Subject: [PATCH 217/416] improve unit test coverage of lang_base --- tests/lang_base_test.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/lang_base_test.py b/tests/lang_base_test.py index 89a64a1f..a532b6a5 100644 --- a/tests/lang_base_test.py +++ b/tests/lang_base_test.py @@ -82,6 +82,21 @@ def test_failed_setup_command_does_not_unicode_error(): lang_base.setup_cmd(Prefix('.'), (sys.executable, '-c', script)) +def test_environment_dir(tmp_path): + ret = lang_base.environment_dir(Prefix(tmp_path), 'langenv', 'default') + assert ret == f'{tmp_path}{os.sep}langenv-default' + + +def test_assert_version_default(): + with pytest.raises(AssertionError) as excinfo: + lang_base.assert_version_default('lang', '1.2.3') + msg, = excinfo.value.args + assert msg == ( + 'for now, pre-commit requires system-installed lang -- ' + 'you selected `language_version: 1.2.3`' + ) + + def test_assert_no_additional_deps(): with pytest.raises(AssertionError) as excinfo: lang_base.assert_no_additional_deps('lang', ['hmmm']) @@ -93,6 +108,14 @@ def test_assert_no_additional_deps(): ) +def test_no_env_noop(tmp_path): + before = os.environ.copy() + with lang_base.no_env(Prefix(tmp_path), '1.2.3'): + inside = os.environ.copy() + after = os.environ.copy() + assert before == inside == after + + def test_target_concurrency_normal(): with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): with mock.patch.dict(os.environ, {}, clear=True): @@ -133,3 +156,18 @@ def test_xargs_require_serial_is_not_shuffled(): ) assert ret == 0 assert out.strip() == b'0 1 2 3 4 5 6 7 8 9' + + +def test_basic_run_hook(tmp_path): + ret, out = lang_base.basic_run_hook( + Prefix(tmp_path), + 'echo hi', + ['hello'], + ['file', 'file', 'file'], + is_local=False, + require_serial=False, + color=False, + ) + assert ret == 0 + out = out.replace(b'\r\n', b'\n') + assert out == b'hi hello file file file\n' From 8d84a7a2702b074a8b46f5e38af28bd576291251 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Feb 2023 21:45:04 -0500 Subject: [PATCH 218/416] resources_bytesio is only used by ruby --- pre_commit/languages/ruby.py | 9 +++++++-- pre_commit/util.py | 5 ----- tests/languages/ruby_test.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 0ee0a857..76631f25 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -2,10 +2,12 @@ from __future__ import annotations import contextlib import functools +import importlib.resources import os.path import shutil import tarfile from typing import Generator +from typing import IO from typing import Sequence import pre_commit.constants as C @@ -16,13 +18,16 @@ from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError -from pre_commit.util import resource_bytesio ENVIRONMENT_DIR = 'rbenv' health_check = lang_base.basic_health_check run_hook = lang_base.basic_run_hook +def _resource_bytesio(filename: str) -> IO[bytes]: + return importlib.resources.open_binary('pre_commit.resources', filename) + + @functools.lru_cache(maxsize=1) def get_default_version() -> str: if all(lang_base.exe_exists(exe) for exe in ('ruby', 'gem')): @@ -74,7 +79,7 @@ def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: def _extract_resource(filename: str, dest: str) -> None: - with resource_bytesio(filename) as bio: + with _resource_bytesio(filename) as bio: with tarfile.open(fileobj=bio) as tf: tf.extractall(dest) diff --git a/pre_commit/util.py b/pre_commit/util.py index 8ea48446..3d448e31 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -12,7 +12,6 @@ from types import TracebackType from typing import Any from typing import Callable from typing import Generator -from typing import IO from pre_commit import parse_shebang @@ -36,10 +35,6 @@ def clean_path_on_failure(path: str) -> Generator[None, None, None]: raise -def resource_bytesio(filename: str) -> IO[bytes]: - return importlib.resources.open_binary('pre_commit.resources', filename) - - def resource_text(filename: str) -> str: return importlib.resources.read_text('pre_commit.resources', filename) diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 9cfaad5d..6397a434 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -9,8 +9,8 @@ import pre_commit.constants as C from pre_commit import parse_shebang from pre_commit.envcontext import envcontext from pre_commit.languages import ruby +from pre_commit.languages.ruby import _resource_bytesio from pre_commit.store import _make_local_repo -from pre_commit.util import resource_bytesio from testing.language_helpers import run_language from testing.util import cwd from testing.util import xfailif_windows @@ -40,7 +40,7 @@ def test_uses_system_if_both_gem_and_ruby_are_available(find_exe_mck): ('rbenv.tar.gz', 'ruby-build.tar.gz', 'ruby-download.tar.gz'), ) def test_archive_root_stat(filename): - with resource_bytesio(filename) as f: + with _resource_bytesio(filename) as f: with tarfile.open(fileobj=f) as tarf: root, _, _ = filename.partition('.') assert oct(tarf.getmember(root).mode) == '0o755' From d23990cc8b3b6040c0e5a7455ab7104cd60a5df4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Feb 2023 22:21:31 -0500 Subject: [PATCH 219/416] use run_language for repository_test --- testing/language_helpers.py | 6 ++++-- tests/repository_test.py | 31 +++++++++++++++---------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/testing/language_helpers.py b/testing/language_helpers.py index 5ab2af2a..ead8dae2 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -16,6 +16,8 @@ def run_language( version: str | None = None, deps: Sequence[str] = (), is_local: bool = False, + require_serial: bool = True, + color: bool = False, ) -> tuple[int, bytes]: prefix = Prefix(str(path)) version = version or language.get_default_version() @@ -31,8 +33,8 @@ def run_language( args, file_args, is_local=is_local, - require_serial=True, - color=False, + require_serial=require_serial, + color=color, ) out = out.replace(b'\r\n', b'\n') return ret, out diff --git a/tests/repository_test.py b/tests/repository_test.py index 1af73e3a..9e5d9d62 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -25,25 +25,24 @@ from pre_commit.util import cmd_output_b from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo from testing.fixtures import modify_manifest +from testing.language_helpers import run_language from testing.util import cwd from testing.util import get_resource_path -def _norm_out(b): - return b.replace(b'\r\n', b'\n') - - def _hook_run(hook, filenames, color): - with languages[hook.language].in_env(hook.prefix, hook.language_version): - return languages[hook.language].run_hook( - hook.prefix, - hook.entry, - hook.args, - filenames, - is_local=hook.src == 'local', - require_serial=hook.require_serial, - color=color, - ) + return run_language( + path=hook.prefix.prefix_dir, + language=languages[hook.language], + exe=hook.entry, + args=hook.args, + file_args=filenames, + version=hook.language_version, + deps=hook.additional_dependencies, + is_local=hook.src == 'local', + require_serial=hook.require_serial, + color=color, + ) def _get_hook_no_install(repo_config, store, hook_id): @@ -77,7 +76,7 @@ def _test_hook_repo( hook = _get_hook(config, store, hook_id) ret, out = _hook_run(hook, args, color=color) assert ret == expected_return_code - assert _norm_out(out) == expected + assert out == expected def test_python_hook(tempdir_factory, store): @@ -425,7 +424,7 @@ def test_local_python_repo(store, local_python_config): assert hook.language_version != C.DEFAULT ret, out = _hook_run(hook, ('filename',), color=False) assert ret == 0 - assert _norm_out(out) == b"['filename']\nHello World\n" + assert out == b"['filename']\nHello World\n" def test_default_language_version(store, local_python_config): From 9655158d938d0f49df0a0eedc5c0d166a45d591a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Feb 2023 17:00:05 -0500 Subject: [PATCH 220/416] test languages only when they are changed --- .github/actions/pre-test/action.yml | 31 ----------- .github/workflows/languages.yaml | 82 +++++++++++++++++++++++++++++ testing/languages | 79 +++++++++++++++++++++++++++ tox.ini | 4 +- 4 files changed, 163 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/languages.yaml create mode 100755 testing/languages diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index 42bbf00b..9d1eb2de 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -5,36 +5,5 @@ inputs: runs: using: composite steps: - - name: setup (windows) - shell: bash - if: runner.os == 'Windows' - run: | - set -x - - echo 'TEMP=C:\TEMP' >> "$GITHUB_ENV" - - echo "$CONDA\Scripts" >> "$GITHUB_PATH" - - echo 'C:\Strawberry\perl\bin' >> "$GITHUB_PATH" - echo 'C:\Strawberry\perl\site\bin' >> "$GITHUB_PATH" - echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" - - testing/get-coursier.sh - testing/get-dart.sh - - name: setup (linux) - shell: bash - if: runner.os == 'Linux' - run: | - set -x - - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - lua5.3 \ - liblua5.3-dev \ - luarocks - - testing/get-coursier.sh - testing/get-dart.sh - testing/get-swift.sh - uses: asottile/workflows/.github/actions/latest-git@v1.4.0 if: inputs.env == 'py38' && runner.os == 'Linux' diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml new file mode 100644 index 00000000..8bc8e712 --- /dev/null +++ b/.github/workflows/languages.yaml @@ -0,0 +1,82 @@ +name: languages + +on: + push: + branches: [main, test-me-*] + tags: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + vars: + runs-on: ubuntu-latest + outputs: + languages: ${{ steps.vars.outputs.languages }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: install deps + run: python -mpip install -e . -r requirements-dev.txt + - name: vars + run: testing/languages ${{ github.event_name == 'push' && '--all' || '' }} + id: vars + language: + needs: [vars] + runs-on: ${{ matrix.os }} + if: needs.vars.outputs.languages != '[]' + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(needs.vars.outputs.languages) }} + steps: + - uses: asottile/workflows/.github/actions/fast-checkout@v1.4.0 + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - run: echo "$CONDA\Scripts" >> "$GITHUB_PATH" + shell: bash + if: matrix.os == 'windows-latest' && matrix.language == 'conda' + - run: testing/get-coursier.sh + shell: bash + if: matrix.language == 'coursier' + - run: testing/get-dart.sh + shell: bash + if: matrix.language == 'dart' + - run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + lua5.3 \ + liblua5.3-dev \ + luarocks + if: matrix.os == 'ubuntu-latest' && matrix.language == 'lua' + - run: | + echo 'C:\Strawberry\perl\bin' >> "$GITHUB_PATH" + echo 'C:\Strawberry\perl\site\bin' >> "$GITHUB_PATH" + echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" + shell: bash + if: matrix.os == 'windows-latest' && matrix.language == 'perl' + - run: testing/get-swift.sh + if: matrix.os == 'ubuntu-latest' && matrix.language == 'swift' + + - name: install deps + run: python -mpip install -e . -r requirements-dev.txt + - name: run tests + run: coverage run -m pytest tests/languages/${{ matrix.language }}_test.py + - name: check coverage + run: coverage report --include pre_commit/languages/${{ matrix.language }}.py,tests/languages/${{ matrix.language }}_test.py + collector: + needs: [language] + if: always() + runs-on: ubuntu-latest + steps: + - name: check for failures + if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: echo job failed && exit 1 diff --git a/testing/languages b/testing/languages new file mode 100755 index 00000000..5e8fc9e4 --- /dev/null +++ b/testing/languages @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import concurrent.futures +import json +import os.path +import subprocess +import sys + +EXCLUDED = frozenset(( + ('windows-latest', 'docker'), + ('windows-latest', 'docker_image'), + ('windows-latest', 'lua'), + ('windows-latest', 'swift'), +)) + + +def _lang_files(lang: str) -> frozenset[str]: + prog = f'''\ +import json +import os.path +import sys + +import pre_commit.languages.{lang} +import tests.languages.{lang}_test + +modules = sorted( + os.path.relpath(v.__file__) + for k, v in sys.modules.items() + if k.startswith(('pre_commit.', 'tests.', 'testing.')) +) +print(json.dumps(modules)) +''' + out = json.loads(subprocess.check_output((sys.executable, '-c', prog))) + return frozenset(out) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('--all', action='store_true') + args = parser.parse_args() + + langs = [ + os.path.splitext(fname)[0] + for fname in sorted(os.listdir('pre_commit/languages')) + if fname.endswith('.py') and fname != '__init__.py' + ] + + if not args.all: + with concurrent.futures.ThreadPoolExecutor(os.cpu_count()) as exe: + by_lang = { + lang: files + for lang, files in zip(langs, exe.map(_lang_files, langs)) + } + + diff_cmd = ('git', 'diff', '--name-only', 'origin/main...HEAD') + files = set(subprocess.check_output(diff_cmd).decode().splitlines()) + + langs = [ + lang + for lang, lang_files in by_lang.items() + if lang_files & files + ] + + matched = [ + {'os': os, 'language': lang} + for os in ('windows-latest', 'ubuntu-latest') + for lang in langs + if (os, lang) not in EXCLUDED + ] + + with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + f.write(f'languages={json.dumps(matched)}\n') + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/tox.ini b/tox.ini index a44f93d4..602679a6 100644 --- a/tox.ini +++ b/tox.ini @@ -6,8 +6,8 @@ deps = -rrequirements-dev.txt passenv = * commands = coverage erase - coverage run -m pytest {posargs:tests} - coverage report + coverage run -m pytest {posargs:tests} --ignore=tests/languages + coverage report --omit=pre_commit/languages/*,tests/languages/* [testenv:pre-commit] skip_install = true From 08fa5ffc4353f0d9255281e4914cff2acc1c0859 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 21 Feb 2023 11:06:24 -0500 Subject: [PATCH 221/416] make a change to trigger the language tests --- pre_commit/lang_base.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pre_commit/lang_base.py b/pre_commit/lang_base.py index 6ba412f0..9480c559 100644 --- a/pre_commit/lang_base.py +++ b/pre_commit/lang_base.py @@ -43,12 +43,7 @@ class Language(Protocol): ... # modify the environment for hook execution - def in_env( - self, - prefix: Prefix, - version: str, - ) -> ContextManager[None]: - ... + def in_env(self, prefix: Prefix, version: str) -> ContextManager[None]: ... # execute a hook and return the exit code and output def run_hook( From cddc9cff0f05a8d9e3ca126df03962574efe98e9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 21 Feb 2023 12:09:26 -0500 Subject: [PATCH 222/416] only treat exit code 1 as a successful diff --- pre_commit/staged_files_only.py | 23 ++++++++++----- tests/staged_files_only_test.py | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index 172fb20b..88123565 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -7,6 +7,7 @@ import time from typing import Generator from pre_commit import git +from pre_commit.errors import FatalError from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b @@ -49,12 +50,16 @@ def _intent_to_add_cleared() -> Generator[None, None, None]: @contextlib.contextmanager def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: tree = cmd_output('git', 'write-tree')[1].strip() - retcode, diff_stdout_binary, _ = cmd_output_b( + diff_cmd = ( 'git', 'diff-index', '--ignore-submodules', '--binary', '--exit-code', '--no-color', '--no-ext-diff', tree, '--', - check=False, ) - if retcode and diff_stdout_binary.strip(): + retcode, diff_stdout, diff_stderr = cmd_output_b(*diff_cmd, check=False) + if retcode == 0: + # There weren't any staged files so we don't need to do anything + # special + yield + elif retcode == 1 and diff_stdout.strip(): patch_filename = f'patch{int(time.time())}-{os.getpid()}' patch_filename = os.path.join(patch_dir, patch_filename) logger.warning('Unstaged files detected.') @@ -62,7 +67,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: # Save the current unstaged changes as a patch os.makedirs(patch_dir, exist_ok=True) with open(patch_filename, 'wb') as patch_file: - patch_file.write(diff_stdout_binary) + patch_file.write(diff_stdout) # prevent recursive post-checkout hooks (#1418) no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1') @@ -86,10 +91,12 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: _git_apply(patch_filename) logger.info(f'Restored changes from {patch_filename}.') - else: - # There weren't any staged files so we don't need to do anything - # special - yield + else: # pragma: win32 no cover + # some error occurred while requesting the diff + e = CalledProcessError(retcode, diff_cmd, b'', diff_stderr) + raise FatalError( + f'pre-commit failed to diff -- perhaps due to permissions?\n\n{e}', + ) @contextlib.contextmanager diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index a91f3151..50f146be 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -1,12 +1,15 @@ from __future__ import annotations +import contextlib import itertools import os.path import shutil import pytest +import re_assert from pre_commit import git +from pre_commit.errors import FatalError from pre_commit.staged_files_only import staged_files_only from pre_commit.util import cmd_output from testing.auto_namedtuple import auto_namedtuple @@ -14,6 +17,7 @@ from testing.fixtures import git_dir from testing.util import cwd from testing.util import get_resource_path from testing.util import git_commit +from testing.util import xfailif_windows FOO_CONTENTS = '\n'.join(('1', '2', '3', '4', '5', '6', '7', '8', '')) @@ -382,3 +386,51 @@ def test_intent_to_add(in_git_dir, patch_dir): with staged_files_only(patch_dir): assert_no_diff() assert git.intent_to_add_files() == ['foo'] + + +@contextlib.contextmanager +def _unreadable(f): + orig = os.stat(f).st_mode + os.chmod(f, 0o000) + try: + yield + finally: + os.chmod(f, orig) + + +@xfailif_windows # pragma: win32 no cover +def test_failed_diff_does_not_discard_changes(in_git_dir, patch_dir): + # stage 3 files + for i in range(3): + with open(str(i), 'w') as f: + f.write(str(i)) + cmd_output('git', 'add', '0', '1', '2') + + # modify all of their contents + for i in range(3): + with open(str(i), 'w') as f: + f.write('new contents') + + with _unreadable('1'): + with pytest.raises(FatalError) as excinfo: + with staged_files_only(patch_dir): + raise AssertionError('should have errored on enter') + + # the diff command failed to produce a diff of `1` + msg, = excinfo.value.args + re_assert.Matches( + r'^pre-commit failed to diff -- perhaps due to permissions\?\n\n' + r'command: .*\n' + r'return code: 128\n' + r'stdout: \(none\)\n' + r'stderr:\n' + r' error: open\("1"\): Permission denied\n' + r' fatal: cannot hash 1\n' + # TODO: not sure why there's weird whitespace here + r' $', + ).assert_matches(msg) + + # even though it errored, the unstaged changes should still be present + for i in range(3): + with open(str(i)) as f: + assert f.read() == 'new contents' From 4ded56efac790028557e8ad446937d00dff7f05d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 21 Feb 2023 12:42:09 -0500 Subject: [PATCH 223/416] fix trailing whitespace in CalledProcessError output --- pre_commit/util.py | 2 +- tests/staged_files_only_test.py | 4 +--- tests/util_test.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pre_commit/util.py b/pre_commit/util.py index 3d448e31..ea0d4f52 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -62,7 +62,7 @@ class CalledProcessError(RuntimeError): def __bytes__(self) -> bytes: def _indent_or_none(part: bytes | None) -> bytes: if part: - return b'\n ' + part.replace(b'\n', b'\n ') + return b'\n ' + part.replace(b'\n', b'\n ').rstrip() else: return b' (none)' diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index 50f146be..58dbe5ac 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -425,9 +425,7 @@ def test_failed_diff_does_not_discard_changes(in_git_dir, patch_dir): r'stdout: \(none\)\n' r'stderr:\n' r' error: open\("1"\): Permission denied\n' - r' fatal: cannot hash 1\n' - # TODO: not sure why there's weird whitespace here - r' $', + r' fatal: cannot hash 1$', ).assert_matches(msg) # even though it errored, the unstaged changes should still be present diff --git a/tests/util_test.py b/tests/util_test.py index 310f8f58..5b262113 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -16,7 +16,7 @@ from pre_commit.util import rmtree def test_CalledProcessError_str(): - error = CalledProcessError(1, ('exe',), b'output', b'errors') + error = CalledProcessError(1, ('exe',), b'output\n', b'errors\n') assert str(error) == ( "command: ('exe',)\n" 'return code: 1\n' From a631abdabf0fcc2bb31f85ae33dfdefb958fe03a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 22 Feb 2023 20:31:14 -0500 Subject: [PATCH 224/416] remove sorting for repo key for additional_deps in other languages this order can matter (such as ruby) --- pre_commit/repository.py | 2 +- pre_commit/store.py | 2 +- tests/store_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 5183df47..040f238f 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -33,7 +33,7 @@ def _state_filename_v2(venv: str) -> str: def _state(additional_deps: Sequence[str]) -> object: - return {'additional_dependencies': sorted(additional_deps)} + return {'additional_dependencies': additional_deps} def _read_state(venv: str) -> object | None: diff --git a/pre_commit/store.py b/pre_commit/store.py index 6ddc7c48..487e3e79 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -125,7 +125,7 @@ class Store: @classmethod def db_repo_name(cls, repo: str, deps: Sequence[str]) -> str: if deps: - return f'{repo}:{",".join(sorted(deps))}' + return f'{repo}:{",".join(deps)}' else: return repo diff --git a/tests/store_test.py b/tests/store_test.py index 146eac41..eaab9400 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -180,7 +180,7 @@ def test_create_when_store_already_exists(store): def test_db_repo_name(store): assert store.db_repo_name('repo', ()) == 'repo' - assert store.db_repo_name('repo', ('b', 'a', 'c')) == 'repo:a,b,c' + assert store.db_repo_name('repo', ('b', 'a', 'c')) == 'repo:b,a,c' def test_local_resources_reflects_reality(): From 294590fd124484a786ba90423fa5d89536a6de98 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 22 Feb 2023 20:53:02 -0500 Subject: [PATCH 225/416] v3.1.0 --- CHANGELOG.md | 18 ++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0998da98..8a427812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +3.1.0 - 2023-02-22 +================== + +### Fixes +- Fix `dotnet` for `.sln`-based hooks for dotnet>=7.0.200. + - #2763 PR by @m-rsha. +- Prevent stashing when `diff` fails to execute. + - #2774 PR by @asottile. + - #2773 issue by @strubbly. +- Dependencies are no longer sorted in repository key. + - #2776 PR by @asottile. + +### Updating +- Deprecate `language: python_venv`. Use `language: python` instead. + - #2746 PR by @asottile. + - #2734 issue by @asottile. + + 3.0.4 - 2023-02-03 ================== diff --git a/setup.cfg b/setup.cfg index 56b856ca..d1f649fe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.0.4 +version = 3.1.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 2700a7d62241d7bea52d5305b5bca88ad7072919 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 27 Feb 2023 20:49:22 -0500 Subject: [PATCH 226/416] set RUSTUP_HOME when using a non-system rust --- pre_commit/languages/rust.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index e98e0d02..af5f483d 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -142,10 +142,15 @@ def install_environment( else: packages_to_install.add((package,)) - with in_env(prefix, version): + with contextlib.ExitStack() as ctx: + ctx.enter_context(in_env(prefix, version)) + if version != 'system': install_rust_with_toolchain(_rust_toolchain(version)) + tmpdir = ctx.enter_context(tempfile.TemporaryDirectory()) + ctx.enter_context(envcontext((('RUSTUP_HOME', tmpdir),))) + if len(lib_deps) > 0: _add_dependencies(prefix, lib_deps) From 2822de9aa6284f2de1c5ff8d0884b38bc553afa5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 27 Feb 2023 21:07:23 -0500 Subject: [PATCH 227/416] v3.1.1 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a427812..cfcef453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.1.1 - 2023-02-27 +================== + +### Fixes +- Fix `rust` with `language_version` and a non-writable host `RUSTUP_HOME`. + - pre-commit-ci/issues#173 by @Swiftb0y. + - #2788 by @asottile. + 3.1.0 - 2023-02-22 ================== diff --git a/setup.cfg b/setup.cfg index d1f649fe..507c0ad1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.1.0 +version = 3.1.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 5ce4a549d3e0ee441698a13e431cf207bc3b611f Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Fri, 3 Mar 2023 20:16:09 -0600 Subject: [PATCH 228/416] prefer `sys.platform` over `os.name` when checking for windows OS --- pre_commit/languages/conda.py | 3 ++- pre_commit/languages/python.py | 4 ++-- pre_commit/util.py | 2 +- testing/util.py | 3 ++- tests/languages/python_test.py | 4 ++-- tests/parse_shebang_test.py | 2 +- tests/repository_test.py | 3 ++- tests/xargs_test.py | 2 +- 8 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 05f1d291..41c355e7 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -2,6 +2,7 @@ from __future__ import annotations import contextlib import os +import sys from typing import Generator from typing import Sequence @@ -26,7 +27,7 @@ def get_env_patch(env: str) -> PatchesT: # $CONDA_PREFIX/Scripts and $CONDA_PREFIX. Whereas the latter only # seems to be used for python.exe. path: SubstitutionT = (os.path.join(env, 'bin'), os.pathsep, Var('PATH')) - if os.name == 'nt': # pragma: no cover (platform specific) + if sys.platform == 'win32': # pragma: win32 cover path = (env, os.pathsep, *path) path = (os.path.join(env, 'Scripts'), os.pathsep, *path) path = (os.path.join(env, 'Library', 'bin'), os.pathsep, *path) diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 976674e2..3ef34360 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -48,7 +48,7 @@ def _read_pyvenv_cfg(filename: str) -> dict[str, str]: def bin_dir(venv: str) -> str: """On windows there's a different directory for the virtualenv""" - bin_part = 'Scripts' if os.name == 'nt' else 'bin' + bin_part = 'Scripts' if sys.platform == 'win32' else 'bin' return os.path.join(venv, bin_part) @@ -137,7 +137,7 @@ def norm_version(version: str) -> str | None: elif _sys_executable_matches(version): # virtualenv defaults to our exe return None - if os.name == 'nt': # pragma: no cover (windows) + if sys.platform == 'win32': # pragma: no cover (windows) version_exec = _find_by_py_launcher(version) if version_exec: return version_exec diff --git a/pre_commit/util.py b/pre_commit/util.py index ea0d4f52..4f8e8357 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -119,7 +119,7 @@ def cmd_output(*cmd: str, **kwargs: Any) -> tuple[int, str, str | None]: return returncode, stdout, stderr -if os.name != 'nt': # pragma: win32 no cover +if sys.platform != 'win32': # pragma: win32 no cover from os import openpty import termios diff --git a/testing/util.py b/testing/util.py index 7c68d0ee..0fee2826 100644 --- a/testing/util.py +++ b/testing/util.py @@ -3,6 +3,7 @@ from __future__ import annotations import contextlib import os.path import subprocess +import sys import pytest @@ -30,7 +31,7 @@ def cmd_output_mocked_pre_commit_home( return ret, out.replace('\r\n', '\n'), None -xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows') +xfailif_windows = pytest.mark.xfail(sys.platform == 'win32', reason='windows') def run_opts( diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index 8bb284eb..a4000b41 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -36,10 +36,10 @@ def test_read_pyvenv_cfg_non_utf8(tmpdir): def test_norm_version_expanduser(): home = os.path.expanduser('~') - if os.name == 'nt': # pragma: nt cover + if sys.platform == 'win32': # pragma: win32 cover path = r'~\python343' expected_path = fr'{home}\python343' - else: # pragma: nt no cover + else: # pragma: win32 no cover path = '~/.pyenv/versions/3.4.3/bin/python' expected_path = f'{home}/.pyenv/versions/3.4.3/bin/python' result = python.norm_version(path) diff --git a/tests/parse_shebang_test.py b/tests/parse_shebang_test.py index 2fcb29ee..dd97ca5d 100644 --- a/tests/parse_shebang_test.py +++ b/tests/parse_shebang_test.py @@ -94,7 +94,7 @@ def test_normexe_does_not_exist_sep(): assert excinfo.value.args == ('Executable `./i-dont-exist-lol` not found',) -@pytest.mark.xfail(os.name == 'nt', reason='posix only') +@pytest.mark.xfail(sys.platform == 'win32', reason='posix only') def test_normexe_not_executable(tmpdir): # pragma: win32 no cover tmpdir.join('exe').ensure() with tmpdir.as_cwd(), pytest.raises(OSError) as excinfo: diff --git a/tests/repository_test.py b/tests/repository_test.py index 9e5d9d62..8fe6e02b 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -2,6 +2,7 @@ from __future__ import annotations import os.path import shutil +import sys from typing import Any from unittest import mock @@ -198,7 +199,7 @@ def test_intermixed_stdout_stderr(tempdir_factory, store): ) -@pytest.mark.xfail(os.name == 'nt', reason='ptys are posix-only') +@pytest.mark.xfail(sys.platform == 'win32', reason='ptys are posix-only') def test_output_isatty(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'stdout_stderr_repo', diff --git a/tests/xargs_test.py b/tests/xargs_test.py index 0530e50d..7c41f98c 100644 --- a/tests/xargs_test.py +++ b/tests/xargs_test.py @@ -187,7 +187,7 @@ def test_xargs_propagate_kwargs_to_cmd(): assert b'Pre commit is awesome' in stdout -@pytest.mark.xfail(os.name == 'nt', reason='posix only') +@pytest.mark.xfail(sys.platform == 'win32', reason='posix only') def test_xargs_color_true_makes_tty(): retcode, out = xargs.xargs( (sys.executable, '-c', 'import sys; print(sys.stdout.isatty())'), From 0616c0abf75d45d2bd793ced4b3bddc42b478662 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Mar 2023 02:52:32 +0000 Subject: [PATCH 229/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-autopep8: v2.0.1 → v2.0.2](https://github.com/pre-commit/mirrors-autopep8/compare/v2.0.1...v2.0.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ad8ffba7..0aa2e9ea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: - id: pyupgrade args: [--py38-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v2.0.1 + rev: v2.0.2 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From 63a180a935dc0096d23a65aa48b84498b57b8760 Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Sun, 5 Mar 2023 05:16:00 -0600 Subject: [PATCH 230/416] rewrite `args with spaces` test to not require python --- tests/repository_test.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/tests/repository_test.py b/tests/repository_test.py index 8fe6e02b..a6c58bc7 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1,6 +1,7 @@ from __future__ import annotations import os.path +import shlex import shutil import sys from typing import Any @@ -17,6 +18,7 @@ from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import load_manifest from pre_commit.hook import Hook from pre_commit.languages import python +from pre_commit.languages import system from pre_commit.prefix import Prefix from pre_commit.repository import _hook_installed from pre_commit.repository import all_hooks @@ -99,22 +101,6 @@ def test_python_hook_default_version(tempdir_factory, store): test_python_hook(tempdir_factory, store) -def test_python_hook_args_with_spaces(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'python_hooks_repo', - 'foo', - [], - b"['i have spaces', 'and\"\\'quotes', '$and !this']\n" - b'Hello World\n', - config_kwargs={ - 'hooks': [{ - 'id': 'foo', - 'args': ['i have spaces', 'and"\'quotes', '$and !this'], - }], - }, - ) - - def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store): in_git_dir.join('setup.cfg').write('[install]\ninstall_scripts=/usr/sbin') @@ -583,3 +569,14 @@ def test_non_installable_hook_error_for_additional_dependencies(store, caplog): 'using language `system` which does not install an environment. ' 'Perhaps you meant to use a specific language?' ) + + +def test_args_with_spaces_and_quotes(tmp_path): + ret = run_language( + tmp_path, system, + f"{shlex.quote(sys.executable)} -c 'import sys; print(sys.argv[1:])'", + ('i have spaces', 'and"\'quotes', '$and !this'), + ) + + expected = b"['i have spaces', 'and\"\\'quotes', '$and !this']\n" + assert ret == (0, expected) From 8ab9747b339df5bfbf0b7ebb7ebd1885ad6baabd Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 9 Mar 2023 11:00:31 -0500 Subject: [PATCH 231/416] show 20 slowest durations in CI --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 602679a6..609c2fe1 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ deps = -rrequirements-dev.txt passenv = * commands = coverage erase - coverage run -m pytest {posargs:tests} --ignore=tests/languages + coverage run -m pytest {posargs:tests} --ignore=tests/languages --durations=20 coverage report --omit=pre_commit/languages/*,tests/languages/* [testenv:pre-commit] From e3e17a1617b90c081e043db32cb046ed010f2310 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 11 Mar 2023 14:15:49 -0500 Subject: [PATCH 232/416] make --hook-type and stages match --- pre_commit/clientlib.py | 67 ++++++++++++++++++++++++++++---- pre_commit/commands/hook_impl.py | 2 +- pre_commit/constants.py | 13 ------- pre_commit/main.py | 8 +++- testing/util.py | 2 +- tests/clientlib_test.py | 48 +++++++++++++++++++++++ tests/commands/hook_impl_test.py | 4 +- tests/commands/run_test.py | 14 +++---- tests/main_test.py | 6 +++ tests/repository_test.py | 25 +++++++----- 10 files changed, 147 insertions(+), 42 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 9ff38c6a..cb7778bb 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -6,6 +6,7 @@ import re import shlex import sys from typing import Any +from typing import NamedTuple from typing import Sequence import cfgv @@ -20,6 +21,20 @@ logger = logging.getLogger('pre_commit') check_string_regex = cfgv.check_and(cfgv.check_string, cfgv.check_regex) +HOOK_TYPES = ( + 'commit-msg', + 'post-checkout', + 'post-commit', + 'post-merge', + 'post-rewrite', + 'pre-commit', + 'pre-merge-commit', + 'pre-push', + 'prepare-commit-msg', +) +# `manual` is not invoked by any installed git hook. See #719 +STAGES = (*HOOK_TYPES, 'manual') + def check_type_tag(tag: str) -> None: if tag not in ALL_TAGS: @@ -43,6 +58,46 @@ def check_min_version(version: str) -> None: ) +_STAGES = { + 'commit': 'pre-commit', + 'merge-commit': 'pre-merge-commit', + 'push': 'pre-push', +} + + +def transform_stage(stage: str) -> str: + return _STAGES.get(stage, stage) + + +class StagesMigrationNoDefault(NamedTuple): + key: str + default: Sequence[str] + + def check(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + return + + val = dct[self.key] + cfgv.check_array(cfgv.check_any)(val) + + val = [transform_stage(v) for v in val] + cfgv.check_array(cfgv.check_one_of(STAGES))(val) + + def apply_default(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + return + dct[self.key] = [transform_stage(v) for v in dct[self.key]] + + def remove_default(self, dct: dict[str, Any]) -> None: + raise NotImplementedError + + +class StagesMigration(StagesMigrationNoDefault): + def apply_default(self, dct: dict[str, Any]) -> None: + dct.setdefault(self.key, self.default) + super().apply_default(dct) + + MANIFEST_HOOK_DICT = cfgv.Map( 'Hook', 'id', @@ -70,7 +125,7 @@ MANIFEST_HOOK_DICT = cfgv.Map( cfgv.Optional('log_file', cfgv.check_string, ''), cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'), cfgv.Optional('require_serial', cfgv.check_bool, False), - cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []), + StagesMigration('stages', []), cfgv.Optional('verbose', cfgv.check_bool, False), ) MANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT) @@ -241,7 +296,9 @@ CONFIG_HOOK_DICT = cfgv.Map( cfgv.OptionalNoDefault(item.key, item.check_fn) for item in MANIFEST_HOOK_DICT.items if item.key != 'id' + if item.key != 'stages' ), + StagesMigrationNoDefault('stages', []), OptionalSensibleRegexAtHook('files', cfgv.check_string), OptionalSensibleRegexAtHook('exclude', cfgv.check_string), ) @@ -290,17 +347,13 @@ CONFIG_SCHEMA = cfgv.Map( cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)), cfgv.Optional( 'default_install_hook_types', - cfgv.check_array(cfgv.check_one_of(C.HOOK_TYPES)), + cfgv.check_array(cfgv.check_one_of(HOOK_TYPES)), ['pre-commit'], ), cfgv.OptionalRecurse( 'default_language_version', DEFAULT_LANGUAGE_VERSION, {}, ), - cfgv.Optional( - 'default_stages', - cfgv.check_array(cfgv.check_one_of(C.STAGES)), - C.STAGES, - ), + StagesMigration('default_stages', STAGES), cfgv.Optional('files', check_string_regex, ''), cfgv.Optional('exclude', check_string_regex, '^$'), cfgv.Optional('fail_fast', cfgv.check_bool, False), diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index f5995e9a..25d99c29 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -84,7 +84,7 @@ def _ns( ) -> argparse.Namespace: return argparse.Namespace( color=color, - hook_stage=hook_type.replace('pre-', ''), + hook_stage=hook_type, remote_branch=remote_branch, local_branch=local_branch, from_ref=from_ref, diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 3f03ceed..79a9bb69 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -10,17 +10,4 @@ LOCAL_REPO_VERSION = '1' VERSION = importlib.metadata.version('pre_commit') -# `manual` is not invoked by any installed git hook. See #719 -STAGES = ( - 'commit', 'merge-commit', 'prepare-commit-msg', 'commit-msg', - 'post-commit', 'manual', 'post-checkout', 'push', 'post-merge', - 'post-rewrite', -) - -HOOK_TYPES = ( - 'pre-commit', 'pre-merge-commit', 'pre-push', 'prepare-commit-msg', - 'commit-msg', 'post-commit', 'post-checkout', 'post-merge', - 'post-rewrite', -) - DEFAULT = 'default' diff --git a/pre_commit/main.py b/pre_commit/main.py index 3915993f..62d171e6 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -7,6 +7,7 @@ import sys from typing import Sequence import pre_commit.constants as C +from pre_commit import clientlib from pre_commit import git from pre_commit.color import add_color_option from pre_commit.commands.autoupdate import autoupdate @@ -52,7 +53,7 @@ def _add_config_option(parser: argparse.ArgumentParser) -> None: def _add_hook_type_option(parser: argparse.ArgumentParser) -> None: parser.add_argument( '-t', '--hook-type', - choices=C.HOOK_TYPES, action='append', dest='hook_types', + choices=clientlib.HOOK_TYPES, action='append', dest='hook_types', ) @@ -73,7 +74,10 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None: help='When hooks fail, run `git diff` directly afterward.', ) parser.add_argument( - '--hook-stage', choices=C.STAGES, default='commit', + '--hook-stage', + choices=clientlib.STAGES, + type=clientlib.transform_stage, + default='pre-commit', help='The stage during which the hook is fired. One of %(choices)s', ) parser.add_argument( diff --git a/testing/util.py b/testing/util.py index 0fee2826..8e3934cf 100644 --- a/testing/util.py +++ b/testing/util.py @@ -46,7 +46,7 @@ def run_opts( to_ref='', remote_name='', remote_url='', - hook_stage='commit', + hook_stage='pre-commit', show_diff_on_failure=False, commit_msg_filename='', prepare_commit_message_source='', diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index efb2aa84..568b2e97 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -12,6 +12,7 @@ from pre_commit.clientlib import CONFIG_HOOK_DICT from pre_commit.clientlib import CONFIG_REPO_DICT from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION +from pre_commit.clientlib import MANIFEST_HOOK_DICT from pre_commit.clientlib import MANIFEST_SCHEMA from pre_commit.clientlib import META_HOOK_DICT from pre_commit.clientlib import OptionalSensibleRegexAtHook @@ -416,3 +417,50 @@ def test_warn_additional(schema): x for x in schema.items if isinstance(x, cfgv.WarnAdditionalKeys) ) assert allowed_keys == set(warn_additional.keys) + + +def test_stages_migration_for_default_stages(): + cfg = { + 'default_stages': ['commit-msg', 'push', 'commit', 'merge-commit'], + 'repos': [], + } + cfgv.validate(cfg, CONFIG_SCHEMA) + cfg = cfgv.apply_defaults(cfg, CONFIG_SCHEMA) + assert cfg['default_stages'] == [ + 'commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit', + ] + + +def test_manifest_stages_defaulting(): + dct = { + 'id': 'fake-hook', + 'name': 'fake-hook', + 'entry': 'fake-hook', + 'language': 'system', + 'stages': ['commit-msg', 'push', 'commit', 'merge-commit'], + } + cfgv.validate(dct, MANIFEST_HOOK_DICT) + dct = cfgv.apply_defaults(dct, MANIFEST_HOOK_DICT) + assert dct['stages'] == [ + 'commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit', + ] + + +def test_config_hook_stages_defaulting_missing(): + dct = {'id': 'fake-hook'} + cfgv.validate(dct, CONFIG_HOOK_DICT) + dct = cfgv.apply_defaults(dct, CONFIG_HOOK_DICT) + assert dct == {'id': 'fake-hook'} + + +def test_config_hook_stages_defaulting(): + dct = { + 'id': 'fake-hook', + 'stages': ['commit-msg', 'push', 'commit', 'merge-commit'], + } + cfgv.validate(dct, CONFIG_HOOK_DICT) + dct = cfgv.apply_defaults(dct, CONFIG_HOOK_DICT) + assert dct == { + 'id': 'fake-hook', + 'stages': ['commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit'], + } diff --git a/tests/commands/hook_impl_test.py b/tests/commands/hook_impl_test.py index aa321dab..169e1414 100644 --- a/tests/commands/hook_impl_test.py +++ b/tests/commands/hook_impl_test.py @@ -142,7 +142,7 @@ def test_check_args_length_prepare_commit_msg_error(): def test_run_ns_pre_commit(): ns = hook_impl._run_ns('pre-commit', True, (), b'') assert ns is not None - assert ns.hook_stage == 'commit' + assert ns.hook_stage == 'pre-commit' assert ns.color is True @@ -245,7 +245,7 @@ def test_run_ns_pre_push_updating_branch(push_example): ns = hook_impl._run_ns('pre-push', False, args, stdin) assert ns is not None - assert ns.hook_stage == 'push' + assert ns.hook_stage == 'pre-push' assert ns.color is False assert ns.remote_name == 'origin' assert ns.remote_url == src diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index f1085d9b..885b78d6 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -354,13 +354,13 @@ def test_show_diff_on_failure( ({'hook': 'bash_hook'}, (b'Bash hook', b'Passed'), 0, True), ( {'hook': 'nope'}, - (b'No hook with id `nope` in stage `commit`',), + (b'No hook with id `nope` in stage `pre-commit`',), 1, True, ), ( - {'hook': 'nope', 'hook_stage': 'push'}, - (b'No hook with id `nope` in stage `push`',), + {'hook': 'nope', 'hook_stage': 'pre-push'}, + (b'No hook with id `nope` in stage `pre-push`',), 1, True, ), @@ -818,7 +818,7 @@ def test_stages(cap_out, store, repo_with_passing_hook): 'language': 'pygrep', 'stages': [stage], } - for i, stage in enumerate(('commit', 'push', 'manual'), 1) + for i, stage in enumerate(('pre-commit', 'pre-push', 'manual'), 1) ], } add_config_to_repo(repo_with_passing_hook, config) @@ -833,8 +833,8 @@ def test_stages(cap_out, store, repo_with_passing_hook): assert printed.count(b'hook ') == 1 return printed - assert _run_for_stage('commit').startswith(b'hook 1...') - assert _run_for_stage('push').startswith(b'hook 2...') + assert _run_for_stage('pre-commit').startswith(b'hook 1...') + assert _run_for_stage('pre-push').startswith(b'hook 2...') assert _run_for_stage('manual').startswith(b'hook 3...') @@ -1173,7 +1173,7 @@ def test_args_hook_only(cap_out, store, repo_with_passing_hook): ), 'language': 'system', 'files': r'\.py$', - 'stages': ['commit'], + 'stages': ['pre-commit'], }, { 'id': 'do_not_commit', diff --git a/tests/main_test.py b/tests/main_test.py index 51159262..945349fa 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -216,3 +216,9 @@ def test_expected_fatal_error_no_git_repo(in_tmpdir, cap_out, mock_store_dir): 'Is it installed, and are you in a Git repository directory?' ) assert cap_out_lines[-1] == f'Check the log at {log_file}' + + +def test_hook_stage_migration(mock_store_dir): + with mock.patch.object(main, 'run') as mck: + main.main(('run', '--hook-stage', 'commit')) + assert mck.call_args[0][2].hook_stage == 'pre-commit' diff --git a/tests/repository_test.py b/tests/repository_test.py index a6c58bc7..903574ce 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -417,7 +417,7 @@ def test_local_python_repo(store, local_python_config): def test_default_language_version(store, local_python_config): config: dict[str, Any] = { 'default_language_version': {'python': 'fake'}, - 'default_stages': ['commit'], + 'default_stages': ['pre-commit'], 'repos': [local_python_config], } @@ -434,18 +434,18 @@ def test_default_language_version(store, local_python_config): def test_default_stages(store, local_python_config): config: dict[str, Any] = { 'default_language_version': {'python': C.DEFAULT}, - 'default_stages': ['commit'], + 'default_stages': ['pre-commit'], 'repos': [local_python_config], } # `stages` was not set, should default hook, = all_hooks(config, store) - assert hook.stages == ['commit'] + assert hook.stages == ['pre-commit'] # `stages` is set, should not default - config['repos'][0]['hooks'][0]['stages'] = ['push'] + config['repos'][0]['hooks'][0]['stages'] = ['pre-push'] hook, = all_hooks(config, store) - assert hook.stages == ['push'] + assert hook.stages == ['pre-push'] def test_hook_id_not_present(tempdir_factory, store, caplog): @@ -513,11 +513,18 @@ def test_manifest_hooks(tempdir_factory, store): name='Bash hook', pass_filenames=True, require_serial=False, - stages=( - 'commit', 'merge-commit', 'prepare-commit-msg', 'commit-msg', - 'post-commit', 'manual', 'post-checkout', 'push', 'post-merge', + stages=[ + 'commit-msg', + 'post-checkout', + 'post-commit', + 'post-merge', 'post-rewrite', - ), + 'pre-commit', + 'pre-merge-commit', + 'pre-push', + 'prepare-commit-msg', + 'manual', + ], types=['file'], types_or=[], verbose=False, From f39154f69f864457595b21f00e81f0e989d05ddf Mon Sep 17 00:00:00 2001 From: Marcelo Galigniana Date: Fri, 27 Jan 2023 16:18:06 -0300 Subject: [PATCH 233/416] Add pre-rebase hook support --- pre_commit/clientlib.py | 1 + pre_commit/commands/hook_impl.py | 17 ++++++++++ pre_commit/commands/run.py | 5 +++ pre_commit/main.py | 11 +++++++ testing/util.py | 4 +++ tests/commands/hook_impl_test.py | 25 +++++++++++++++ tests/commands/install_uninstall_test.py | 40 ++++++++++++++++++++++++ tests/commands/run_test.py | 10 ++++++ tests/repository_test.py | 1 + 9 files changed, 114 insertions(+) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index cb7778bb..d0651cae 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -30,6 +30,7 @@ HOOK_TYPES = ( 'pre-commit', 'pre-merge-commit', 'pre-push', + 'pre-rebase', 'prepare-commit-msg', ) # `manual` is not invoked by any installed git hook. See #719 diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index 25d99c29..dab2135d 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -73,6 +73,8 @@ def _ns( local_branch: str | None = None, from_ref: str | None = None, to_ref: str | None = None, + pre_rebase_upstream: str | None = None, + pre_rebase_branch: str | None = None, remote_name: str | None = None, remote_url: str | None = None, commit_msg_filename: str | None = None, @@ -89,6 +91,8 @@ def _ns( local_branch=local_branch, from_ref=from_ref, to_ref=to_ref, + pre_rebase_upstream=pre_rebase_upstream, + pre_rebase_branch=pre_rebase_branch, remote_name=remote_name, remote_url=remote_url, commit_msg_filename=commit_msg_filename, @@ -185,6 +189,12 @@ def _check_args_length(hook_type: str, args: Sequence[str]) -> None: f'hook-impl for {hook_type} expected 1, 2, or 3 arguments ' f'but got {len(args)}: {args}', ) + elif hook_type == 'pre-rebase': + if len(args) < 1 or len(args) > 2: + raise SystemExit( + f'hook-impl for {hook_type} expected 1 or 2 arguments ' + f'but got {len(args)}: {args}', + ) elif hook_type in _EXPECTED_ARG_LENGTH_BY_HOOK: expected = _EXPECTED_ARG_LENGTH_BY_HOOK[hook_type] if len(args) != expected: @@ -231,6 +241,13 @@ def _run_ns( return _ns(hook_type, color, is_squash_merge=args[0]) elif hook_type == 'post-rewrite': return _ns(hook_type, color, rewrite_command=args[0]) + elif hook_type == 'pre-rebase' and len(args) == 1: + return _ns(hook_type, color, pre_rebase_upstream=args[0]) + elif hook_type == 'pre-rebase' and len(args) == 2: + return _ns( + hook_type, color, pre_rebase_upstream=args[0], + pre_rebase_branch=args[1], + ) else: raise AssertionError(f'unexpected hook type: {hook_type}') diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index c9bc55b4..c867799e 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -254,6 +254,7 @@ def _all_filenames(args: argparse.Namespace) -> Collection[str]: # these hooks do not operate on files if args.hook_stage in { 'post-checkout', 'post-commit', 'post-merge', 'post-rewrite', + 'pre-rebase', }: return () elif args.hook_stage in {'prepare-commit-msg', 'commit-msg'}: @@ -389,6 +390,10 @@ def run( environ['PRE_COMMIT_FROM_REF'] = args.from_ref environ['PRE_COMMIT_TO_REF'] = args.to_ref + if args.pre_rebase_upstream and args.pre_rebase_branch: + environ['PRE_COMMIT_PRE_REBASE_UPSTREAM'] = args.pre_rebase_upstream + environ['PRE_COMMIT_PRE_REBASE_BRANCH'] = args.pre_rebase_branch + if ( args.remote_name and args.remote_url and args.remote_branch and args.local_branch diff --git a/pre_commit/main.py b/pre_commit/main.py index 62d171e6..9615c5e1 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -107,6 +107,17 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None: 'now checked out.' ), ) + parser.add_argument( + '--pre-rebase-upstream', help=( + 'The upstream from which the series was forked.' + ), + ) + parser.add_argument( + '--pre-rebase-branch', help=( + 'The branch being rebased, and is not set when ' + 'rebasing the current branch.' + ), + ) parser.add_argument( '--commit-msg-filename', help='Filename to check when running during `commit-msg`', diff --git a/testing/util.py b/testing/util.py index 8e3934cf..08d52cbc 100644 --- a/testing/util.py +++ b/testing/util.py @@ -44,6 +44,8 @@ def run_opts( local_branch='', from_ref='', to_ref='', + pre_rebase_upstream='', + pre_rebase_branch='', remote_name='', remote_url='', hook_stage='pre-commit', @@ -67,6 +69,8 @@ def run_opts( local_branch=local_branch, from_ref=from_ref, to_ref=to_ref, + pre_rebase_upstream=pre_rebase_upstream, + pre_rebase_branch=pre_rebase_branch, remote_name=remote_name, remote_url=remote_url, hook_stage=hook_stage, diff --git a/tests/commands/hook_impl_test.py b/tests/commands/hook_impl_test.py index 169e1414..d757e85c 100644 --- a/tests/commands/hook_impl_test.py +++ b/tests/commands/hook_impl_test.py @@ -100,6 +100,8 @@ def test_run_legacy_recursive(tmpdir): ('commit-msg', ['.git/COMMIT_EDITMSG']), ('post-commit', []), ('post-merge', ['1']), + ('pre-rebase', ['main', 'topic']), + ('pre-rebase', ['main']), ('post-checkout', ['old_head', 'new_head', '1']), ('post-rewrite', ['amend']), # multiple choices for commit-editmsg @@ -139,6 +141,13 @@ def test_check_args_length_prepare_commit_msg_error(): ) +def test_check_args_length_pre_rebase_error(): + with pytest.raises(SystemExit) as excinfo: + hook_impl._check_args_length('pre-rebase', []) + msg, = excinfo.value.args + assert msg == 'hook-impl for pre-rebase expected 1 or 2 arguments but got 0: []' # noqa: E501 + + def test_run_ns_pre_commit(): ns = hook_impl._run_ns('pre-commit', True, (), b'') assert ns is not None @@ -146,6 +155,22 @@ def test_run_ns_pre_commit(): assert ns.color is True +def test_run_ns_pre_rebase(): + ns = hook_impl._run_ns('pre-rebase', True, ('main', 'topic'), b'') + assert ns is not None + assert ns.hook_stage == 'pre-rebase' + assert ns.color is True + assert ns.pre_rebase_upstream == 'main' + assert ns.pre_rebase_branch == 'topic' + + ns = hook_impl._run_ns('pre-rebase', True, ('main',), b'') + assert ns is not None + assert ns.hook_stage == 'pre-rebase' + assert ns.color is True + assert ns.pre_rebase_upstream == 'main' + assert ns.pre_rebase_branch is None + + def test_run_ns_commit_msg(): ns = hook_impl._run_ns('commit-msg', False, ('.git/COMMIT_MSG',), b'') assert ns is not None diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index a1ecda86..8b0d3ece 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -810,6 +810,46 @@ def test_post_merge_integration(tempdir_factory, store): assert os.path.exists('post-merge.tmp') +def test_pre_rebase_integration(tempdir_factory, store): + path = git_dir(tempdir_factory) + config = { + 'repos': [ + { + 'repo': 'local', + 'hooks': [{ + 'id': 'pre-rebase', + 'name': 'Pre rebase', + 'entry': 'touch pre-rebase.tmp', + 'language': 'system', + 'always_run': True, + 'verbose': True, + 'stages': ['pre-rebase'], + }], + }, + ], + } + write_config(path, config) + with cwd(path): + install(C.CONFIG_FILE, store, hook_types=['pre-rebase']) + open('foo', 'a').close() + cmd_output('git', 'add', '.') + git_commit() + + cmd_output('git', 'checkout', '-b', 'branch') + open('bar', 'a').close() + cmd_output('git', 'add', '.') + git_commit() + + cmd_output('git', 'checkout', 'master') + open('baz', 'a').close() + cmd_output('git', 'add', '.') + git_commit() + + cmd_output('git', 'checkout', 'branch') + cmd_output('git', 'rebase', 'master', 'branch') + assert os.path.exists('pre-rebase.tmp') + + def test_post_rewrite_integration(tempdir_factory, store): path = git_dir(tempdir_factory) config = { diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 885b78d6..dd15b94c 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -563,6 +563,16 @@ def test_merge_conflict_resolved(cap_out, store, in_merge_conflict): assert msg in printed +def test_rebase(cap_out, store, repo_with_passing_hook): + args = run_opts(pre_rebase_upstream='master', pre_rebase_branch='topic') + environ: MutableMapping[str, str] = {} + ret, printed = _do_run( + cap_out, store, repo_with_passing_hook, args, environ, + ) + assert environ['PRE_COMMIT_PRE_REBASE_UPSTREAM'] == 'master' + assert environ['PRE_COMMIT_PRE_REBASE_BRANCH'] == 'topic' + + @pytest.mark.parametrize( ('hooks', 'expected'), ( diff --git a/tests/repository_test.py b/tests/repository_test.py index 903574ce..04565668 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -522,6 +522,7 @@ def test_manifest_hooks(tempdir_factory, store): 'pre-commit', 'pre-merge-commit', 'pre-push', + 'pre-rebase', 'prepare-commit-msg', 'manual', ], From d3c0a66d23b5cebc060f48278ddb43bcc3384dfc Mon Sep 17 00:00:00 2001 From: marsha <46257533+m-rsha@users.noreply.github.com> Date: Sun, 12 Mar 2023 08:24:38 -0500 Subject: [PATCH 234/416] move slowest python-specific tests out of repository_test --- tests/languages/python_test.py | 51 ++++++++++++++++++++++++++++++++++ tests/repository_test.py | 29 ------------------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index a4000b41..ab26e14e 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -233,3 +233,54 @@ setup( return_value=False, ): assert run_language(tmp_path, python, 'myexe') == (0, b'ohai\n') + + +def _make_hello_hello(tmp_path): + setup_py = '''\ +from setuptools import setup + +setup( + name='socks', + version='0.0.0', + py_modules=['socks'], + entry_points={'console_scripts': ['socks = socks:main']}, +) +''' + + main_py = '''\ +import sys + +def main(): + print(repr(sys.argv[1:])) + print('hello hello') + return 0 +''' + tmp_path.joinpath('setup.py').write_text(setup_py) + tmp_path.joinpath('socks.py').write_text(main_py) + + +def test_simple_python_hook(tmp_path): + _make_hello_hello(tmp_path) + + ret = run_language(tmp_path, python, 'socks', [os.devnull]) + assert ret == (0, f'[{os.devnull!r}]\nhello hello\n'.encode()) + + +def test_simple_python_hook_default_version(tmp_path): + # make sure that this continues to work for platforms where default + # language detection does not work + with mock.patch.object( + python, + 'get_default_version', + return_value=C.DEFAULT, + ): + test_simple_python_hook(tmp_path) + + +def test_python_hook_weird_setup_cfg(tmp_path): + _make_hello_hello(tmp_path) + setup_cfg = '[install]\ninstall_scripts=/usr/sbin' + tmp_path.joinpath('setup.cfg').write_text(setup_cfg) + + ret = run_language(tmp_path, python, 'socks', [os.devnull]) + assert ret == (0, f'[{os.devnull!r}]\nhello hello\n'.encode()) diff --git a/tests/repository_test.py b/tests/repository_test.py index 04565668..b8dde99b 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -82,35 +82,6 @@ def _test_hook_repo( assert out == expected -def test_python_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'python_hooks_repo', - 'foo', [os.devnull], - f'[{os.devnull!r}]\nHello World\n'.encode(), - ) - - -def test_python_hook_default_version(tempdir_factory, store): - # make sure that this continues to work for platforms where default - # language detection does not work - with mock.patch.object( - python, - 'get_default_version', - return_value=C.DEFAULT, - ): - test_python_hook(tempdir_factory, store) - - -def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store): - in_git_dir.join('setup.cfg').write('[install]\ninstall_scripts=/usr/sbin') - - _test_hook_repo( - tempdir_factory, store, 'python_hooks_repo', - 'foo', [os.devnull], - f'[{os.devnull!r}]\nHello World\n'.encode(), - ) - - def test_python_venv_deprecation(store, caplog): config = { 'repo': 'local', From 7a7772fcdae8694107b9ab19cc93ff5fdc690755 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 03:19:10 +0000 Subject: [PATCH 235/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.0.1 → v1.1.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.1...v1.1.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0aa2e9ea..cc96a703 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.0.1 + rev: v1.1.1 hooks: - id: mypy additional_dependencies: [types-all] From a412e5492da8cdac6642b50cc3907db06edec109 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 17 Mar 2023 12:55:34 -0400 Subject: [PATCH 236/416] don't set CARGO_HOME in rust this adds a 270 MB registry cache in the output --- pre_commit/languages/rust.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index af5f483d..a1f4dbe1 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -50,7 +50,6 @@ def _rust_toolchain(language_version: str) -> str: def get_env_patch(target_dir: str, version: str) -> PatchesT: return ( - ('CARGO_HOME', target_dir), ('PATH', (os.path.join(target_dir, 'bin'), os.pathsep, Var('PATH'))), # Only set RUSTUP_TOOLCHAIN if we don't want use the system's default # toolchain From df2cada973da6ee689cbc8e323caccf5c00df92c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 17 Mar 2023 14:26:34 -0400 Subject: [PATCH 237/416] v3.2.0 --- CHANGELOG.md | 15 +++++++++++++++ setup.cfg | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfcef453..f2466e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +3.2.0 - 2023-03-17 +================== + +### Features +- Allow `pre-commit`, `pre-push`, and `pre-merge-commit` as `stages`. + - #2732 issue by @asottile. + - #2808 PR by @asottile. +- Add `pre-rebase` hook support. + - #2582 issue by @BrutalSimplicity. + - #2725 PR by @mgaligniana. + +### Fixes +- Remove bulky cargo cache from `language: rust` installs. + - #2820 PR by @asottile. + 3.1.1 - 2023-02-27 ================== diff --git a/setup.cfg b/setup.cfg index 507c0ad1..5b3d1560 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.1.1 +version = 3.2.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From ee71a9345ce96a78e011c9635a61abc332e38961 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 25 Mar 2023 13:06:22 -0400 Subject: [PATCH 238/416] set CARGO_HOME while executing rustup --- pre_commit/languages/rust.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index a1f4dbe1..7eec0e7d 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -80,9 +80,9 @@ def _add_dependencies( lang_base.setup_cmd(prefix, ('cargo', 'add', *crates)) -def install_rust_with_toolchain(toolchain: str) -> None: +def install_rust_with_toolchain(toolchain: str, envdir: str) -> None: with tempfile.TemporaryDirectory() as rustup_dir: - with envcontext((('RUSTUP_HOME', rustup_dir),)): + with envcontext((('CARGO_HOME', envdir), ('RUSTUP_HOME', rustup_dir))): # acquire `rustup` if not present if parse_shebang.find_executable('rustup') is None: # We did not detect rustup and need to download it first. @@ -145,7 +145,7 @@ def install_environment( ctx.enter_context(in_env(prefix, version)) if version != 'system': - install_rust_with_toolchain(_rust_toolchain(version)) + install_rust_with_toolchain(_rust_toolchain(version), envdir) tmpdir = ctx.enter_context(tempfile.TemporaryDirectory()) ctx.enter_context(envcontext((('RUSTUP_HOME', tmpdir),))) From bb49560dc99a65608c8f9161dd71467af163c0d1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 25 Mar 2023 14:02:57 -0400 Subject: [PATCH 239/416] v3.2.1 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2466e20..dfb8f804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.2.1 - 2023-03-25 +================== + +### Fixes +- Fix `language_version` for `language: rust` without global `rustup`. + - #2823 issue by @daschuer. + - #2827 PR by @asottile. + 3.2.0 - 2023-03-17 ================== diff --git a/setup.cfg b/setup.cfg index 5b3d1560..350fe237 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.2.0 +version = 3.2.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 84f040f58a5710c2a9d6530f9d1e033657665f20 Mon Sep 17 00:00:00 2001 From: Eric DeLabar Date: Mon, 3 Apr 2023 15:50:55 -0400 Subject: [PATCH 240/416] fix #2235 --- pre_commit/languages/swift.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index 8250ab70..f16bb045 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -44,7 +44,7 @@ def install_environment( os.mkdir(envdir) cmd_output_b( 'swift', 'build', - '-C', prefix.prefix_dir, + '--package-path', prefix.prefix_dir, '-c', BUILD_CONFIG, '--build-path', os.path.join(envdir, BUILD_DIR), ) From 5027592625f8df286dea831e84e7bf83021b7c1b Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 3 Apr 2023 16:31:09 -0400 Subject: [PATCH 241/416] v3.2.2 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfb8f804..efd96c79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.2.2 - 2023-04-03 +================== + +### Fixes +- Fix support for swift >= 5.8. + - #2836 PR by @edelabar. + - #2835 issue by @kgrobelny-intive. + 3.2.1 - 2023-03-25 ================== diff --git a/setup.cfg b/setup.cfg index 350fe237..89e8e4ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.2.1 +version = 3.2.2 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From f5a716f1b1e2805444c199da7fbe24380100930c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 02:57:43 +0000 Subject: [PATCH 242/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.1.1 → v1.2.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.1.1...v1.2.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cc96a703..47d2630a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.1.1 + rev: v1.2.0 hooks: - id: mypy additional_dependencies: [types-all] From cfcb88364e29a8855998502fed425c33d18c1252 Mon Sep 17 00:00:00 2001 From: Jamie Alessio Date: Tue, 18 Apr 2023 10:58:57 -0700 Subject: [PATCH 243/416] Upgrade to ruby-build v20230330 --- pre_commit/resources/ruby-build.tar.gz | Bin 76466 -> 75808 bytes testing/make-archives | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index b6eacf59ba31c87032e76c2d1f39a87bb2b52489..19d467fdd2867742cdefe402a78489481ce9abba 100644 GIT binary patch literal 75808 zcmb2|=HOspU|?YSUsRe@shd=qnUkVdl32v>X7Am)+isgIEVi@zUu=7F(VeAk@-L4m zojMn{{hO%zU&V5!jHh!WgNBk4XPbhm_NH@h@BMrKJ!yWz{iOLR^AqF~UoYN$k-^ck zOvbvn&qBDHW!LJ}yH~GTy=wJp_sQRSFVAbS-Tz~|{p;YS^I3cS>K{)2YyEd`OkT+9 zdf~78Ya7q2$n93ns1tF0{QH#cmw)%a7<)b2Um)1Gdve)FeS`m3KfSvAr+)3v`?gk9 z*K=ge@9(*L+bU0N|FJ*USARWr`OkmTXZvk;YJB-?Z}q=7D)-r+_0z(PKi^+rda7P{ z>GGfdFWdJ$j$qy{pTqI{|L^_(zW>*Z^U*t^A>p=oWA4tk8AkU6+P?(vVA61mVeai{ z$>4gFY9jQlyL@-G^`ocP-o+Ik7uzV#b0<*ZsJ0Rx(?!0ji(5_kj@xFWCLVmX^MlGg zhk|L+#~&V5;7F=URy4bI=gu4pDfYt=J<3N?MScqF3q00qdbKM&(d3cS+3$xBNVD(T z(Zzk}>oMW&(=|7W#~zvX^{(-8!Th@wXB-v;A3hmT;uaWx$7S+F3HHTx76sL;AGe9` zC{$=_yxyIpXM3b---ks9EhKtY{(tDuo?3j-Tln{GAE(W{m>8Ci7R%D- zdahTm66BdD-TgYyg3aTGd3ed8xD8Aj+RZ}(%!Il*8h0jFomXW)xV1v`m;o0&n?yO9&8dl_EDuH z`oOlgaS!qtD*c(bR|@V})p|uNKf=kPNwxLl+Yb>Oni|`7H=8b8k0rud>WBi< z9>W?zSpgB9$c}xDKkf=R#CJF=I4UkZd2z{I_CsphcpCP)D}G2)5NqG-*`p((-?^cA zed}{RHo+o}56w){?SD5s@0*Y;;1r|qMs4xEwikWJ4_7RXNRiU72;6Ux#ooMn(Lsi~ zrmYumE2pJSU<~1EIUH)y#a5dTviWoS!B7sHuD$&1hCB*it)5-~Vlj`mgRR|4)^Yw_ zLq6{s=G5QvH(OtSFxq0L|DU~i9d~gAla`Cp+fjC#f)w5TpzH+ z9pM%%(7fFK_|vIv4%(CD`x0vV-ONAiJJFxCUiyddgPLEe36?CZzfZM_<~+3G(5p7* z_V4)@{_OwjjFOv-lXd^a%sb%!;eW`grRx9BhtIFq|D&UQfcew@p2>43{=XXa)bn3` zC;#iZ;|nfDis><{ANITxD|py*{q;$^?$1o+z36;snxI$d)8#i9zFzpM`}+C{-}8xI zB{pASXXdyzsatw0+k&;vOJXW`CuiiV8L~Tt19DDyhT%|SJrQGjQ zjk-j2Ec+Mv3JotImi`NRH%ju>tKWKOG3_a1FE68w@}4*oj+Vosu9oKmx&>F~8FVam z6m(Qrzx08;ADc;y=7aq0eewCXSXTw+v^V!w)->^L3$&0C-&n(S!aqU3Jg-GQmcMG^ z>+bUQ>ZV^Z{=c{iZYVAh-1vY?ZDVWb(Pzsd44&5ugW|vl`uh#IZN!pOQYF(Gjzpn<;jRVTF3o4Lc=DLqn`EW`}Vnh22C@$ z?#>e~Z;tC<@iJMwwf#xGreEj85{l_&KKg1vo~t&L=!miK;f`m^@c zw|rV2F&zCV@n(B=xd{im__5uEC6Xsn&G_~NGQ7UF`tIZF@8h=g@z>?Nd))O~#qq!N z>H4_$|2Ob{nDFQL*?DLF`7aHupY%W8?|;3saPC>LGeKulHgemG^ltfMAh%25(he63 z3BO}eP1~CNOt|=({gm?mG=zEPeS6#e>~!Accfa+YO=hck+V|+t zwe#*LKZnRxY}~r{u8mdJ-y46HZrwe3<&>)FYb&nYvCEN@PQA4H-0ZuD4>upawtIUu zd$jeY0WdHyd);2e(R0}GzViQZ>FZe#feeoek&seoL|%wKP`*p0ba~2|LoXc|%IKrC@xUv!M*@q-&3F&f1;R zx;rJOcomc8!ZkJW$Im*4O}osb`}xyr&J{fW+r^n9cTT!${S*G@ONSi~ zyfLrm;F}wL2TTgslYcy7msrZK|F_fpSVmN#fn;LCntH~t>+c-gb~RddJah=yBD^rS zEM=yIabRq)kZ8UT*>#~`-E9e)f?W&DKTtd zJHAl7X=mrd7DW>#4qo?*>l@t@H;Vmpt1dF)IBtGOG`9T7F+;N#C2o!hY$8c}WUcn) zEpptzBz30M`ct*znTeg^A6CfzG!K*c#}|L_Na^iF{)BZM33p@}_=_aeqpHNf2ewPT?Dh!z0`yc7RTfd$?`Fa`{o`wy0pGIuEH^a;i5%F z|H89r-eD~Q$63}cNPnKevwng4##Gb$yK5yJUrp%hd^RJ=_5~wrM6=zYk8SG|?9(em zmpI8BZoEGG$HBH#-R^QjF`s23yM5j#uen;xE-w6qLBCs^abMfQ0}OA^wX`+XPW~ao ztlA#f(Ri-t!jm6I0=|m!F}V3S+uQQ5$y~!|ae9JR20KsclI9)!OXJ<{wM<~@+Hve& zt6_=xvj#7|mD9d3wD#}1Xd0L#pRuBvdGG#X2ZaPhOf;9vPlz|Q?U>BCxLI)1$&PLL zLYt2Ko3Xf*=WO$}uBnx5jk9WOy(~5+%J1u$QKH5yciq8vdw1d^msb~06#dl>=ezJx z<5l9FH(bYN`c+xjxhfoaaVS;Zw1oNVC())=o;*>~ZniQOY;UWkbG&)GM-qt5HBZEjMp?j5z6E^&eqKLirSq=HZ+LwKZ%)eqfwKWaf7&TmBf?RN#VB~Byzc?_BSfJF$O7oIIqEU zL_)uD8LQ0;19c|7LW5(8muiYQS~|aWu6C9PeZ5vhc^N~I=AXc6Z#JI!P^I^-_EAHC z$ND6TNz$|IbbRG4*g4b#+(jE6AA6Uo;4@`oz;WJ>&dG~%w#S+{9O0f2DXL;pAQ>y$!E-CP)#{1XZ`CDyT#n; zic{OvW!%n9Sw6#yOPXty+Rx_0jT3Jl;1_4MREkZweP)vLB>rUY*gF#M`4=vvO_;UHnCMJ)CEIe#Sf&@>jVDvK1lB-zA zzo>)t%|!O@S*fzmA9QWL$!ygWntUhJ-Q~(D5&qaYI@6{mL<=AO==^$@_i2?q9}cg+ zpsp!@dFFHlw`bE+mN_gu!JxQUHPlf;=#*Dz@ma6VjLDxoH(WTEn)nUlL!%s{G9`dSK~%%Js&LR2d18FOBmPo*UKnbKYW5k?eG8 z@Q%M}-Z?vOmxO{@zU~6&#J+-tnYPY68}}QY%9eXDGiT9@Nr5M> ztvl(LSAA&m`Jf4&PC{2oIc#R^=kn$M65)lE{a~c?$fhj7-yBJunj~@XQ0uJuU z;d++Kc$D;5HcIvF@r>{DXq;xy`q`qOu{=qeiRsxgPt(VJ99F7NKA%$-lA159yw~gC zw8O@W8r^1nU*UAHYGt~R!`BR@fWn5(FAky?i(R>AwC5aq?7M_B;|Qb9!G?hMX>AX7 zzjHg(@A0A};cd^l%)+DtEs@jaF0>a9d=jlNWuf?usN+W$1@YXyP_?o};G4F@%g1_p zd}i}ClD!ljZCv6vQL%+}#=irtsXW(iC<-rsbzt@q<`q6N2Or44lu-J3x7^L;BER^F zO*=CG|NS2Dh4<$Ph65T*sbBy9v|nJb`z%*&-IG);6ZeOzS3d2^yU;zC`GD}l#hc1z zYIVNI?cHiKUy=La#Mir>=SW&5wcoWpX>4@P??SUVi|C6S*Ao^gfqGZMbiQ**sfsZh z7B+3vh@u{qTlZMOU?nP^&bi}jM)ju7dnW}oha?e9Kfobc$B?NBXy6EfuGym?} z+uf=C_^zV-|JCQl|KuP3Umfx)^7sBPCI6mt-~4~z(!TRj%<~MF9lO!u|yEd7(8 zj#f|EXfb{E)IHuWb>>gbd-dDWAY#SEZ|Y`620U!;?$tb&%xtx6g?Fs$x&HmO`m=xg z?z?yFv+Dkt$vyb*wQ`#6|M<)+^M3sAuGzNuA@A+x?t7C~9JpZp!QXUoenZ^S-jbLH zA0JqL_;K`v>)krn3DvwUEGq<*zs&Otp1PM`DQmIPVWYNlyP7vTsm05b9=o2wKgmpL zvS(vevwWk_s;TuhEb`s1A`agsu1VAnRIY0fyL{kK`KzgA1`CplM5^8_OgP+rC;U^X zK8x|R=nHO!RY%r%>YRVFzN79*^H%K_Y zYY#uZ`?h=UTIY}7?moQTyjaa-KXbzO^6&9-PTFV9&;EVPw1w-u%V+f;ihXhUZ{H>c zU%O^~;Ge)p;oI!_^_F*Pzy6BYV|U|r=Apylz6Ww%AB~$lyU8#2eeTWX8esqA#94+_>)7=XZg{t~s*rFc-IJgn_eOVU`n9=tDi_vH_CzxK+Lj(Y8zEa~6p9HApqbhdZ#isSpP zSiIq{ev#gNQ~K^})jX?+Z@z!$*D@5EIL34TsWIoc&%EQb!?W!U)9>h6^9n7VZzfbV zxqHIqwmAW_x;IZYu4!I<#?m$*cfPjC&A%N}Z|eIW-_*94&eoo*I#g^ z^IsD5{$#MF;n0r6fdx_lM$D1Hn~>5O`frdFGr;|ko{T088yAP z&z}1Cr0(T$uQ=y_{Margi%q?yon>;9zqzpHi(1z8$V_Lx%G{tf=llNh9>wx$+#j|S zeB8}yb?o%r`aCi9k1K9;7d&1SU~*dYDT_G6gg3J*+@Hs+n67`v;>#80JU*VRqT1QT z8E3miPI4W0+`j%q-Ln(YGK&wTerQfn4cate`?3Y0TvMGqpEyirO-l3BV~cuRFUoDx z!nH|t{nn{-nS7o$hz}6oK8#{I=a$c4>Wwm$lDOrb$r=vaW z+(ccRKedqmVT6gccWE3|*tIkkxg z=PRaSLoNiXa>#%;Oo(g_*A2Bq`Ackr*i zKH-c`lA)Df_m>4`0->23x>oe3%;&Y?d)Z)kPf=;oLk_Ejx2py6ZeA=)ymdVJjx*E8 zTm3UkcJSTIk(OC_Xm_>tjMu&2Dvl}NTC(&{eoLbXw2=%`ok*y2u~% zqI%k_ozL5v`Mygw$32g}YxL|G(;hd^f0h|hx)c12^j6+|DREfRq?SAC+r#I*x8I+9 zn||H>D%0bvJxtzLbo)v^@M>~%D`#XL2+_}AC>P>n2}@hDbiwM*(2EZu+*%aQGbg%= zGjknmFh5zdW<^d?(fOBdX@8~5EkDjX?t6OYW#8f~yE_-&KD;K78?a0w&7uACg5Wu# zytaJm0e6qu?$R+xsQt|Tsdj;R8T%sX*va(?EsvC%nesE!+B2d*wXgn`$#hd~0_Qu1 zRk9{$-CyuaxK8fQJGMCCna1v>NSB3u=UVw6ssHpo^P@&UUp2eK{`F_Z3kC1~cd&c^ zdC0%8ub|KLwD<=5Os+2-v)4}Erntm<*JJO^7jE3URd;tzBipH% z>#vs;1ne>s-rjh8=e4L6=PbLn6cmWYDm}`aTA3-;d;R$F{OH@&yU+f8{F$Yf`QB{{ z_o#Ih&$S=jncY+MJjG*9d^}5Xl(<0$_tA}troKn4R_woI=BYlbU}Hy6yD$4Lbwh;&uhcC2h9f3Y_WQHs z>P@6rkeIkwzWlyd4o_TV;o;y5bFGe@V9crb zGjYp*5%$*-4FxPdqHziHVqNU?Y&woTJb3Wq&nYr@=WUeBUO8owWTCjroWu*NMXxSi z-o(uI=$~FyVE?(|PLWbprLz_eN2hrdXSK4g*`~ZNfjt{qp#|);VdZZgNs>6BiWzw8?%md#(KJ=ihz1R053*woKNPZ2!z%wK3$!b6#ST7j_gKLACFav!g?SaXn&q@3XOuc>nDaTR*E&8@Uc4t( za?LWPU6zv%x;?sF9BLoa`0hsBfwxaBzDe{KCGHIm`257ce%(3)A0wBh!$9?u9qc1+7|WH&0wb>q(;7Ge^ebD!1OBX6VnBv^L&*wR=Ca)a|_)kM^@P%f>#KF};%Euw9r{1c&a1V&^_zc`>caZw1v> zNH5V3J;m!Sz8*dGeXg3!;_Xk8 zlbpSN?TDEFM1$3oN36040J)>u35R4u7r^tMt@`-M|i z!_||DG9Q|5$VT@_tN;J3XUV5rIA4-^){)&=zT$JQ)=XI3ye@dNK^)sb#giE(UhRth zZ?`Au?Xjq!7(-<1H>Wuz?00*cS$R6zKDr1rca(n$iq1>v z{JzKY{M6|wD}LR7)X1H_t&$<&$y!E-*ZWkyV&+|lqf;YleiRbkHY;)Nv|K(%Hb<6eg zJB}G2Bli|54OB)PcHT2Og!^Y!foIw!m>K5RL!u7ZS(C8$0JqT%^%WruwdH)t9p*1owwb0)Y5mmEts2sCpmuu7gZ;%T zUVb(Fopb8pza6_xCq#73VO%}qtG0rR)b9Qr%a~WGNZ0kRH(&leflLY`~NB*d;K}t1@iO%?+wznz5D-%>9hGN&9~0|HToRCZvC}QKli_SdMfze zdVS&l-+P?q7rYBx$@o>s$IjqapW1>e57x@f$tb3OsxR9Hbw&#gJH`j!ZhUzC@>I+o=A%C^to*g&ps$ljNwblrhtB(O zFD0FnCH&1jj4Ejc#ZBK8=U=uvRFfvp-PIs@YC#E8-inF4bT-YJ*&`Aq<26}TS1RPq z&%@$p|IY8ZJKN@Vvflmp9U5nqor0L01iaMalU%m^_Yc40we$ZHVSb&@YmWE7ju-9Z zx>d1TxxQ}F{$C6F@)OFs4@SIOyx|hxihlJydyT&tem6cCxMWHR!{qK6j2e>H4rCks ztTARixnz#J+m)#&lMP>fxfY`pp=x>j(Iqw^)fp$bFDX=&{*7065o0*|Lgeo0pBiTa zo_(3O`9PkSU&36DbcGyCd+W2}@8fPh^7-@kebc@D%PpMl&%al$Jx@AJ+*fF0kk+}- zTVFSYGjy6?yAf-=b)j3|-Z+=r|0gFNWID{vW2-L4yg@>*D)6?_e#OSTKnwpF34K$h z9@(Jhzw-0_M}g9cpUN4{-~PP)$Glwn^LDrH@@-Gun-6f^o6K&#zt5>=l0x1^%@5jl z)E_fWy2mm}<-jfV3;mmP&061DoVv(x`GYRseTEBsd-7D2eJ<}0@Kg2o5K*-cPEx7t z$(jEr>HgM#nvt4c8&q^`D&#ASmEG6+b?m+4e4o8{um0g9c_j|9IjrFdj)w1UurM8+ zmUCKZQ%sD|_Gwc-`HAz~QBnBzdy#yMXraqR6`^zQZBo)79cDk!bbdL{&UIGAuhP>(f1xH*TJr5Fnn(HtXM}{j@4JS)+YdYxkpNT<61t9lW0kJ*sQE zk~D4W(amRhlr=W8a#$S<`DmQg*ICo03~yZ*fB5b&rFCz8!JRuBOcfbc zPqderd~<`hVb5i*mY(CsKOYMEvc5nm<#tQVTCUlZ4aeQj{J&yj!?Z8+ZT{ZORo@C+ zLPaf`j;NiJ2$)=RaM51nH(BFdg7cP7KVO$)cK_7+3;p8k?yEk$ zUaMU4BWM4%HHvGlIC|$EzWLeyhRVqwjNBVPdq+XO34X%{$5HYPBK3~?Fa==-|vFOZXr-uoGvMQ15I2GoJ#GmM%r@nSIN7N0bwdZ#H^UIDC zx-nOy{(t#7?(R4FCH4O0@(-W#HEQlCQYhhI@(d20`yyfT3|md{;GI)uggy=4GHGqO z=hpzf)sKoq_nmzeT^@8Ob$`A@51BTNDKzM^ z{uJ3|4?fwfD7w7bX;ab(t<#!by4T~9v)j*1_qf%$h}f^azgMji<1n{!@BZ2J(6tGENg-1Yo=|#Wc@!yUFG~1z6Ir# zi?gq=NBX~Mx}^TTZU2Egp2}9+oo2FrDdDeyz5gd2ow~zJ-#*4!&wkUc zxVkBd8RtJsS9REQ^|kQa-}o(m!f7tnPp>R$ODC}YnA%_Hc{x?dT+R4$Te>}07hCWy z#^8lNIc6$kmgnW|H5@px*dAk~mMt|;43yzqNez)xZbf^Bfm?l|$E=h?$ z(eab~QU~7AaIodm&YayfV4L3$9KDDCk({KLRA9>_kSkEb9vr18P z+Tmxn_r@>Tr*!13k&f>E140KL%?o1=yK(vzr!M1)HHG`xzLzs`7#wL?f4y;sj7yFE zZ;j#&o?kt!-NH)l9rKX=IO#yeVYzhW>JOpT2_i28CPkagyl+|b>9a{DoknPz^CQ703gX7P5u zwMbp9wtM32%BjmOT_()p?qWEh@Q&eB!yRSD$aH?!Z|gO_PyHqlAiy zmvzgxm0#2S_PkBJ-f)#|@v7MB-inXBdEeFbg_Dqbr+ zvfoxb;Vboa-@U%j}});1^-u`teo3?xdnKx|1f$UrK%C!LsbIO6wCLX)X=Xl`$5Jc6%gV@IK#ty8KnG z(k`JLnTqq1+vJw_ZOrUn74rV*%bkrUnyl2k!mF38Js&b#p2eDRg^T)@Al>519;rEn zEVIOpT>fkmT;@1yWoE*S=XbZL$Gaa%(dF~go^WrnVH^JsCb!64b$K6u-}$5TR5^e> z!}nXvuG4+%KXv8I;qzmEDR?OQP|;_p6MA2Hcv+?QE$()+Tg5oD+2Pu97iO*<`@A9; zHCDVbu`ge;V1vW8AhqP&C)_jF#MSoq9Nb;KRLPcWSKb}l>1l1+XJBJ-~U;aRsXk#t+##q|DWo&`un_-K3}!c z&e!sOa^>85HTip|Q$MS2{d{_NgP(hXUF4a?6PCz57qDC_s(EnvrfnOKF8TKP%26N9 z*PfOcC9!kAHkhAVa#L67vmA+Q_ly44YO0HUagv(7tc^u%d9U}b!+giL>=w-N-DGTk zN`A@lZ=b7LaMeLzRN#)lJ>vHe8;l6@{-rxuYGiU(y_K?li`#XiI)!>q+Uod znJ}kKezk(_(TIQ6NB_T^AFuUqbBtzq`0`Kn*R__a|9zkRs@`j%w+;X0j}`a3-`^-R zN&b|UJLlQ-6E06uAD<~xnz_6E$O_3kGv!S=S`KgeTia`+3LaYN>($Xj0r$Py zW%>aR?{5DPbZ>)_|Ba%vY}a${gm0c0Z9IFru5ibUxt%L-9G`RI_@CV0e|~JQUVLBY zaOJAG%~OMxMy(3-E(=pmEZvzou`c@WyZ54o$0N_Wg&#X;C6RyO>c_f{KK)e-g1;Qv zcBMavQRLH10i%?p;)&(czoxCIQrMpEF7COcResO&wOp6JJ>=D`v0u@_eRyXPcfPro z^i%6=Nt@60mhAjw`_yEf`hsIC*Pl)=UvV(->8ZJMV=QJ@*#G!c>QJ#c$7bidMa9#9 zFJ?FsZ0K_E1zY`+>AtNKCWPH(oBGTsG|Q}MQ_?CEWz+pTPQ0xPj*Bw7H@RuS+Z`89 zy$s)!J@?kz>Ap_=A=R69u~eo4o^70>jjzoo{!j{#~fK z_Wtf~7elS~d^>4*ir?_s1Ybt)vpeT_)i~EqHGVr$oNxZ5=Bo-dIhn!xCVN>_UX}Q= z=%y+|#2o%-#vGv7;{cM7y_(EfU~xc%Xby#2vEv$!^DEfzFmV`KhWd-|t;S6^{p z*xhis$LrthsQ9G6f>G4_T-8BK?QLD+_q%r7$kKfr{=2xXHM4z$KAUF9j}nNDX* z_4Bqb5fSa&nj0`L@<8Wd!7p!YCzPy_IrzjT^unXpVqQ0DJSGK*hbpF9bbYXzS36^+ zs^Q;1>eH@zZ`(N4O6X|98_~r#0xf37D23nm5!_t(Oefdk?YjszedC#~Ta+6t**VUw z73Vn?xW|a=&pPY4mn?NAMd23DAJ0A3)b-2Jx`bVK>#-$flTH3Fneol6%Y4qyqnx=~ z79TTSp5u7d9bJ31x;6Ga*8-}-$}LSel#fZ=G~idb@qJ1Mh;gZ5IS9nK|Cb?pf4SmR9KJ zx>W8`X|~}!ue}e1Pkr9LYSBiw?2kz~*&0v2#{_I^VEB-rz3gC*`6Qu=Acm*Bd&~s9 z^h>MS7iVSqvz&PtGCk-@Oa9Ug`s&^sX7?9a|CwOF-ZnsBVQlENd0We~^UkR%Tw1N| z(<;w=REo7kLfOY`@3Ib)hcP`9*ZZtY+#qNCF5yysF9bY?ry!Qc17b}*22fVnHzRrZ)Iede=%CNrNTr~MrLVZOhZQ(o9xE_-##Slt}H1j zsJLQvjw?k{XVwNZLl0{9{z1>-lfKBxBODwid4P7TaMb~oi;gO*2TdSYxXL>$leNz>O`PKNcoF+02JfWbn$66&6ffG|72^0{#F6Jbb-L90Ce^vG z64kRaH$2PH$x|)f9Ja64Z1JXd!j`iq$Dg{oW@?e>MU@(p4Gc( zRpy64Mc=Ag_rvpixVL6_wv>d;`gz;L>xQ4n7tRfF=QCbTs5bRfw$LxvIh}f^UGdyg zqZ84m9OkF3-kFlw6?t!`!LB)KtnW&!{v3S~xXM6mNov)xYQz0&zO%@&Ep2a`lG?R7 z=V0X`>z2BY(+ng{d}vOrvI{6i(SDk z^~Qo*$;W)ee%mm!Ex8*MIVsA>JN8ysxW20IvhWolU$x7(WF~7||MvRXw|@8c_qO!i z+gn>*P{G4w!2Rsph20uXZzIL7n1Awm;v>=@;@WAvDKub%-X(zv>>rqCy`Ne3cFMz( zVn^+#E%97>T%BJ&O!>zp*1wPLEv#~g4&A;oJ7G3gb-{quaLMd950=Ocoz zGT!toXlz;+>~oTV@us-sp2NEzJ9^36dF#&YyjN*$-g^$jkKVZFayJNimvAetzZ)+NS&RafT zZ>jQjlQWYdWL%^^UE(V7)!BD*rGDVDw{E^VNk(SuEKyudHoJ~?Cm(8RJGSbXDA(~P zXBPh8S}dIRo+)Qrq4@fB$0VoqbQ#_YemwX1#hpD9W>)(~7Mi&unXZ>c ze3+-l&zPM>%cR8a&otR#;``$Hw6aHj2haX868iq)ipeR1gEj(f7AF@f-F;gp5xmb* zMXuFg0?+-K3pQUnyJ%WwPuLMx7PmhpZv4XDO6!k5PV{>5rMb}jQqWJA%J0i+>~h2} zbUam`a$bhR{N959ocYY(kLl*@d-~PMMlXzU^4z_FuWV}b-pB$V)Hk1RvAtk^e-rwjiae{lfej``K(#EW)nJF%Uy@WNGL`KOHDiyMmd8Xtr+Jv!nn@IiUS zDt-PP{Qa5&&8tg7pC35jweW!0vXWGrj9W|ZJLF$p$9C>*$NA+~WSti-ygkuj)6a(| z1kSPri0;m{(VBNIHN?hQ-iZ60?)jI0WrV#qpZWZ}`1C2`Sr%W5Hpiy@WsHc?TKrN* zJo^2&zEs;Nle7O4%BTH2;-fg%s4Q|$>UP)3hG$OPVp+NSQB7HBfZ(sazkemC{GIcu zc*fd$@y3D~G91S)bBP?;C;$8J`?;AxhEr~DVRyQBHNk$C(7f&S>r*@$V_s#wUh%iu zVogW&(=Vp+^R_9TesyNc{iK{+ADi?iD=lr8Cn+?kifxOlc)H^Lb-GPw`j)G+HBi9k(SoIX4w`nRY?>D@3%@-(?~~MtDz&!m8F8U{f`m`r>)$+@xC3n3-ixsgV|{j|x^8W@c!Aox=ZHS9P|+U+p0OUZt`=c5k7% zoq{KoY&5SL*>*=xF?g|Y^7W&8ELi4FNv!&<8d;w9)pMQViloE|J0kq7b25KeRi@8+ z@iRGO`Le7lCpIsswD4CwmA>fCQN8;d=GSI*nQY(}Oe-=9jGegb()LqJKCHUzsF!%@ z=dPah50oQr7o;2eYOHBn{6MQmtz0{7e}y;*bdx{-RS;K#O_Q+G}t zT{S8BSCsLWog%jWx_$For`_~*2(l?RNDG)TrF_0qN2jnte!vPeyQp(%K_F|SV{PY} zwbSppINVp8`fgeHg=opZG%=&Hl^Yk=^f#YMoVZ2xO@76c1QEmhdB0{|F`ssA&R2__ zth4!TAI_g>-LP#3Z$s+xS*J@>nWNd|)i%$yUUl@&xmUg>!QzH&hD-0Jw-*MsKb_gS zW{=~S=7&49PZ{x;nYO&-Qc3@?N9NWU{UGNe*&_jjOf2-TLxNkpiiA zHIe2|7OX$Q$ztID^NfvLNtu2O&zV!!4T~R7x2p;clZyQ05UJ@ecj|YCS#GK81Y6m= z(?n*)`(1f;rOep7eaqJL4vv$5e}(M7(*A;JzSyjjx_l|;vksoBSC>6H!_`4?aj37g zsl|@XOU$MeP00$t^tht4_r`MP2wS+b?}A_TjY8mwosC-TqqwD;>p4F8bOWn?2pN!TeB(i~buHmmgD} zKAANs{KVVtrp$@&`aXt3QkZTs;dyTW-qy`m=MfP)R}QQ=ZGYGyci3e%7nBjlImV_P)AW|Fge8oDezX+W7wQoQwQb)1Rk@q-r$rtV}<(+oLnJ z_=T4Tw_S+Bf`25z% zZmWvtbNg0i{#D+vWcScbC5s9}pRMg% z(A@5_+O_g=f7gDkL-noirffBIpYE_SV4=!&rn#@Gxi{&H-40xTJp8Mw;0;aQw#oZn zzP5Mu>wm+taZf|`wC&whq6u8>od>d3qNW}4ze^Ep35jx4dbI&qoh z0p3T4)}GM}niKd~FZsN*823tPO#N^`9|S->-J>7U8^ie-+=!8N&JtPMF>^ z-Yxs};3DqZiTtGzr&capw;(jKApMJLQq6p=)4X<4YfB9Gn254A$Vt{TM80N|eb~a! zW8ro4xCG~^)0=kZC%-#(a)UvZJ&V-^!Al1<$^`^2Uc2$SS6}$s#N&)YyCBD<<38UJ5k*?!-?tt8{VAj|XB3-sS>F8F-v$mN<~ z*YeL?Z%$@}JZYc*DDi6Yu?a@=UP>yYtlp52bo`j+@&(JZ9#4O)#>KfxbE92}+{-6c z-zP%@k;gY?s@q?f`Nk!6*)xF&ZPo2p zzO58kI%x)b=)O~TchsgRTO?JwpL{9ZXUAi?z{n{q@zpf`+(ZqpW%H&a376RWn`S>h z#d+_rpV6}E{7KRpy!{p)LO&UNz?Gow0tnU;>$sgIiHi0xI( z_}s43++CqsS{NDsaAvT~%;mz|S$fJ{A#Afs4z8RRU|I1ipucUQcu!q zjD5XZeD4FT@~@v4J>>QFIDdjGPcG$>(_V+2s;+*Hrxf#k+~0Qa)H2(@KbHAhG6Yy9 zPM>zU*fqn_gyqM1XMqLFcQO>j99pBc;BEzvz~(%?g32p1-IDjQvFu+NeBh(Rcb$}F z;&v%J8ZvYjxR)?WMVz=;eeB|ezqQ{^JmY_(-Y33wshgJV{V%JY_U*~*__$laEX3w% zkMO!zXMRm`QS7>Jp0#by6BQYsdxvKWe_l~Nzkk>M`0OnU7VLS}{`%Vn8@nSR4JRjO z9W^^I_+hrA3fn{1@;kd9J~UbAkxhrO!OQVKZ@7+oETwYE2py z9F`OAR>i*#m;AEA@T8kis-Qt~N6Hnixay-%-y~jewLAQ*)5~+7`~-D&nRuN!)5K=* z7-*&>#vT?nQAAH| zR>Ja$SEa1JO3v;7w9e$$KFj?puGwC>EN)SKEwOs`l?A=LVO4%Pa^k;p5<7F}nXmZi zu-lU@cR|T6orJ)9Jo$Il2|LbrWBMB@-19fy=+X3h|Mmnw(Nhr3+Hz&{%`FQU?!2-p zerbAZT6m7gvbMuH&xJiWrmYi5d6io5{*c|_zR8E4Ia)?)h?H7;*+{LQwA6h4o_}Vs zoc|vlIF#9$)perh-4Vwb7MiD9AJi)B|5@?cx;A@v@-H_gR#7pV)m8G&OO5`fNUNBy zRQ*z$=GgZu^}sBx{(IMs%1OM5KD1`L$=skT5sI@V^!7DIe(cp*^k~NHg(0UZ9^GNs z-V`}!Pu`>*67P44>=jUFDBtXC9~xa0u<1q-Tg_sYw{uV3y)7Z4bSv-bzv4YB^iTHp zyf5K-$))PLthwu$@s-r3#PeTY$OS#t2-Y7L_y=U)4-cMrNLZ&s=9q^ldg!@qpqwc)JOAc7H+oyzwsD z7Sq{Uf7Uko#0$3t|9zXUROLMD^_#Q&W!Sf4UVnlWX53D5pUiOLh-<-lljZ5XJweLv zAKwqQ6j{=46UrF1HTabCo#G3nee+x-8vp-_3*lPIYWK+Old^vu_h*OI*}+d)E!M_6 zT6!$hi%&UsBiV3j5cl`!58DeSi6qtQOAGS6x)i+6t8db;2RXU{sy~YyYrfwt|F(zo zy5A(11LpG{c<9VY@Y=Qca=zG^>u&$#U$*#|Yt_!!Y~VQk`ucxQpS!nRY8A~fo*J}g z=L|WN{YfO!& zoBp(!SpS%#sRyBM22JWvC6{Y7p z-@O#{mi4|Va6Gmv;_)7%+C9(L$ewtzV?pqRvLmbC=E_+sKVL8ITlFs?aSmHMd-{uA zQzjIjpEr-WZ29v~Lhe;Zw%_kzNoUvT*#6QYFhiTyNYr4~uHb7HS|+Jdsk`@Gwz+rf zuJx&9dAAoFIn*dvrarg1rZD5m%a*toLSb1xZZ>NFk8o>kesD)(@ja2)t6Wo?4pamt zTorAaZY)!gKlhv7#&d~IHn#5@8D9i!72Wmnq<{Ph#7hyyC%6t+)rfe*m&;N z=ayN_l| z{@W~Y`HI#(l}(4acf8GsjcH1mqkDh1ZEKeAjh41YMiQ6gvs%B-wCvcdaW;*u?D(PI z7AKB+%RZmq8__3ND9OWiaECS5p^xv6YSi_sJa{2{W|5Uma*s<|G?igGc|!o4CH^W`?*2dLt;zj& zvVWR9=cnqNR7(rIx+`bXnN)GdKl;b34B9X!x6@N5eKtZ`JJBBG!D$>E*WIh1F?x*}?q=)<#!LYdroRdG>fl z@!Zc17osHui{hX3I^Q{Jo3cSU;M;@TgG!zpdq3Lv@vfVgsui!Pb^E)vL-3N>n|LhVN{1HBxnpyr&1>$K zMWqL;qnkc`+OvM)smVVnEQpv z@;k3Q_ZFs^zI_A29Qvqyn*j~k23-~O26 zW3ctwbG0`64&VH2_-x+|+vCQ|{PvxSmN1)Kw0P;2vxl~CI`a8>>r?Bp(^F4h)?Cy! zeaG`FoduVD=imGpcg86H=Z1E@ACl)PmYkD%D)VVUai!WcgG-I_eey0rQ-3F0urbH@ z$a21Uyh}~n_R|lqY05?-MfTAzB!BMNGjZMv|AYx&-q>|{8{AK?7KvqJzET}+v?$~w zr}p8>%D9jhD-*?E+>k7_da3xkA-N>DV1hXRgNqk0&SMbXz9H>@^2|-ko=&;VomjCz zVXa3=D&Nm}Q8O2Vd|K#Q>#3Ql zv0al))vqj_HT61+?gLXt)%3q>BKAah%=^1~ON@@5PrBlb{w4DMDa$|I>aFZgay`JU zVjIfzJ>-L)Sec(z|JkIz<}SUfCV7!MaqZI|&e?O<`omAfj;7TGBD}v2ChVDV^P2ut zuUU1^O_(Gi!t@UOU!u40#DXpNGNyV@Wxv{W_GbF;p57^&&P=pEYrOLAG|k;J*WEa= z&~J&zo*NFlAIg*VIa;Ro)~mdwtWW>S?cps? zF-r+JqXoa(vn-pC~dpIpzIZpSXWrbPX=9p8fES`6H#mL@MJ zR~~05J>&VYj)(t4QswK(X?E>mV4kDm*|;2@ur(nC$y^^XgE80 z)9loD2e*B3+gUN6t$;^s^P9~-W%vIyPdJ|NX~I3;xSCSQAC|_eR~(oV^HaxktwV-c zW2s8Sf#Z!%p;y2C$!&UY%>0kg=harz7nl9*6THW1^=^r|-=^9LS`YtdX%#hJD`s!u z6kfS!o7nf#I|ozQkK8@W72D)|Ku^Q*ltA#(AB>;$1kA4;%&rhnD=%<8BIu{%bnL{A zz!&T$x4-wWnl%bMG1%|D?SAyf(oa*}G?v|$$Pp@?)N2&5PVex-eWl_lUE-(pn4TZq z`(l^F0@0t1Hox6=*g8zTwl7CoJ7B?-7SB_>F$->NwBE(BLi<$d+35{wFV$yfs@CRI zUiRCSe%``$^|>2aEB`Uf$q|=p%Fc7)Nt}6f!bXv=qJeQ@53a7scyFmVxtVLv;aNwu z*XxzIwN1Ty`oXc+yA);fToanszt{e7wO{Kv-zhbA#+JDPvF#Nl7bUwM$;rCy)%>Ti z@W@f+d)(I(47d3%%(v&$Xr96OTfl1b+$&wZ+cx#C?6Ll&b@E|qgv|FO+k#(u0cS*C z?JqlCbR*4W)hgkJlj4#qqE=3QUHnD%@BRgQtiN9R6}2*O<@)8xUyUZaU!S#%yjN|F_i5ZSlVufjjrlw{%`ol&<}7 z`fgV9^p*!R-Yf~{&$+mvpuf)2DsNw=>WxdgS1zA@ve&~an(eFUTZ``oyXWsu(C1hl z9C^xO_i}}_?@KaLtSVK7E0xl^BzY4Jq+N2(&zZL8P5o^N@nf3ZhGIUt49|Sdp83Td zl_K)m_{E$*0qdCW9`U+fB@_8+%hZSy8Apr0Tdb9tZOQdPfqTAeDZ5@Elik?=_)h(N}Jq54W{;;jnj=xYn^-|!}&G`n;bL7}o{ai4;o1yAf>FYOT z%QvlJ)Y#z&srJIaV>rjzGw5*{v+%aE7onzVHaOGarW$9 z*(-NSe!adin_2KlOevxo)^A@ybc-?;YJMdrzOSx-`8j&?kxM~ ztABL-4(hmQ^E>Wd-;7+Zd9MxptvR;)a(-&DSKPar---XLOmFKw!z&A3L`*!y?yoHN05*?SkXS%R``~3$~gU(!d_O!wK3 zDquEQ@Mli7^_(Z2=gy@Z2{`}$%N_1rjCQpG%iJIZB+9TNaqq?G`KC=0E-G<=da;Y%X6O|FSkk@}5$ET!U=doW_gl zf>-W(Ztko2w9LKRS2ekv%jDZ18SU~Wb4SgO9uk+Qab7>SYl{5N`-i5cS9nhHG2+bg z{3KENnepepP`1tWY1{TqdA*V&bl==qy0`Ex8A$^W|rki>yV1MYj$S( zUl-!M^X96C)siQMeZ3h*Wyhx9+^ceC`2?#Hc9Ad*waiGKn$$8ep5$jd;*pOvdlt{L zem2KPSNCzAL(qhmFJDL~{X6^IFaB-&)HV9^_T%~YKHb!A=X#O7 zeTs;T^me;i|Hdw!qh_1GJlHusk^kyk-!O(B4rlX|9>(`Q=GeYN;mj%xp&qTLEcOCj zpHE89<+;ll{MC4RVX?vED|&M3xA$=+--~veEGnjWrTA*_wzr1q-yQXbF1~D&YP5F|C_ga*Jbk=Y2O)LcD-mzR#M;Y zZ26)@NWEQK)1B$XZtkP?XGQ1#{gxY}Gw0s4aINL#M;~qfaQ%PT4hM0|X-^C{+@Hyu z!Kv!%a@Wc1_`{$Rk*B`rKAbGJbRv)E`b#TwFGTKTe!OLWbo)DSawdn7&nj{M{hqCAkC$n2bWh_;|Ie^0>BsDg>{j(Xi#YZjuc>nt=eze#-)4SGqLWT;S{|6t18mw?6I-gSia3>|AGBa7c7x?V*bp1vvR^s&S;x!&w9?x zS}1Ay<(R;=!xNXR6`VS00^gFyeN*_m@240nbB@y}FqmzAZ`rF!CNqT>f2&>|6%l`& z=Ubz7m#CmeaFdPNg@z}yTiht-47?{4tk*w!XziO1Cu@HC z>5Q{_H!<*-w{Km|^+9ZnLE(0Xi?Yw2NH#swH%PeS>sGt((2J?uVpKidI!j{#s%l^zQ|i_M{z&(>d!smTj0b?@&qBtl!J@WnB!z z_dLFESCV1VL-CB8slu{~^ElNK3{uNDADmnkEAzd5o9fx(DyMCtBDHZ-44xe^`+1vD zZ2!W=Crg%F$zE_(hC|F^7ozf^2!gFe)0R<|Csdp#n-uCoTQmM`G;cmt|~yh90k;Il2a2Qs#VIoj>2=Ph;D%oRw=-BJWI! zRn*J!`}CLNbdT%JnZn)9XP8}in6@c@d*Jq^(fin|2mfDMnwM7XGr6n0K*C0$<>tDN z=d!Q-SwGq4xVDE!Nz;VAU#;eCN(fjz@vegC=6UC4=&aw;JGp?l=xR8Zs!iUO-pIob zj{oLeWl`cNUs@;U!gtqst7Q4biS`9jrs*=4SG$aseZ3erXRqRo%Zj;^&KJJk5nd&G z!KC=qKheC;vyzsdFmy6>-N*Ao!Crsf$9^^OyG<60BDAN@ulG|8Ir91a`_73Bu|~@b zoJE$I7xAsK2oSo{#r2}&u3v-X{0X-%u=buUNN6qbX@AUmZJ*|@j(eva^h503d!|b) z7S`odnfOqo;`zaEZI3H=^z9Xo6O#4cc;Guv;=jbQZ=bZDtCqa56Zq_wX)U;eGqYgY zw-yzHU@NV?wIu$`+mEMVDYJaM79;@zWLlpgPV zQ6Qan++elG8L_0kbqn|SCasIfUE^tRT;yG`W6;+2+nMGiTLp8KeA+%r$bCKeuWIZ6 zzQhG{B$KtZk^-D|xxKow=fF*YCpUR(S@t>v+DctHv6Q8HN~^-%*9lu6d|lLeU(&U?Fi{}DY3j`D z>kofY_-(SdRdV|(`{zr-H$OZ#Z~bEV^82q&-}k&+>&AHO71xz%XWZR|N{yEJF7R5! zl-h20(DRP_d!O5#0LRBhaW#fKU?rO)#W)goLpCgW@|M&U&`TI8Zo2Gj--m>;MQN34{^eDRZe({k<=RREb-sBs4Hoqfn-nMC3_ZQYJcevG*{L+%c zXwvtf$E#j+&vM*->6(e)v6|*JA*u&HOi_KtlC}5l-J5gj+m^cNy;w9|qwx7v>1dg^ z`)=K}KW2aY>|ygoKhNJyzB==cqII5}?E827PZ|65DX-Kn+$0+y6|NCe>G*K@#l>f? ztvO|JYf2icrY@~6iPb#_!=UYXx`=1KLG*2}-UXG&E~{}?9fG|R_A;>FD$Tetr{ zv?=36#rjaUUK4(PUFVJF&rSQ(YRYr2^=-bQTP1n@(A*eB4`sR31%a3OwtnBfyuVOH z)06A}%-b3V)3?Sg-~Zv{Ki#X@zhv#%-!2dPJzJx;lW|7Ev5E}20}|Jhdl-0Lx%K_ZIzM}+U^%I~S%T>VBS@9qAqI{wzH z_sUioxChy9GVnQQagDoe&&1i2?>(EndeMTjf;)dn9Go$&^>#{0$)7+&$ut+XxIIm` zAN0)N^ZcTwJmJUwqwaI>?v1=wC%D*x=lU8hHq*1WLsa&~sZ;uXzL+63?I7ks36L5(%mOu5CUzNl!Yrvv8nx08Q*?wFrbzj~JJvuYsZO#-u@qd!B zyfK$_mT&G_UFWrb_Akq)B@g$`<7F@Z=@7ln>f_l1+Dn{NTa&U_m&_<}7CSLfT5_A& zZ@Z~N+Jy%sGW-kQ?^ZMuTx6d_3w8JRQ_vKf!_Q_@XUu4o)+57V}^kiK6 zKFwKjYvbcrZW}G?cYjTLZO{KL+C6l_tK0Tw{r?N6AK`uOap-uk%(|S(GY+}`FX?*R z_^b1R>-s%nnKz1@REzA4C(oa`pnrC-iqXyBUG^U5*6fmMj}Md)*85U9z1mLU%$E-f zY`iER{Z`a@jp$ePa7_5s_)$RZNB_YOl1Lu9{-L^4Jztapm+$^Ulp#=FZKS z@c5`}?@9CfI=WAb?W|9$Tz<{!<@$N`mu6P$nJri5R({^q`N*cXdz!h*^1b`^I2@d0 z=<%U}X~L3M-yK($+T1l{J*2Ym<)%G6uK&M9pML4&dEBwIrz>mk86%~%1$T;m|NVY_(tpn`h4b^3TVr+_+?)Q8>nR@Eq%uUx`*eK6XQjTC|^%7er{`L2YuFFSxMd}(Jim~+E<5w>< z?+9(KUw*w}lISU=J>d_3d|h&O!iR5X8T364d~ffuJ60o+>h~chT;Biq97oGK#cdY5 zW^Q{S$+73MWyL+YOIZtUg&tnS8-6A8=agliXIsq{=sm%xzRFB}yg7urk2 zKImjK5ckN8{P8gC?YsNB3%JgP=UmJ+csRrAtwqg}!-dC7*pg26d<_&`wzziNhYqbh zHy<<$yTvdvusS>L*cdTme<;H{u_C961iQ$75C1i}3yqSW99^86?3m}Fw;*?&{?wTz zFE%OOel)rJ#>ySivCY4(Jv^%&lOgkbyJyE??l9Ip9o-fyj;{V0y?E|!l~@_(tJ=le z)*iA+TXJg3JncK3`7V(icW&L?iFKTOLf&#nau`xlsO@8{>M-+0-|^;H++&VSoVo_XH$OfW4z zb$D@jLCoIJWqrPJb0?RVaGyB(e%saZ`d+uSbrucvlg})jqZcv#n&;FbPK=wiIzM@( zo>U5-&2`{QOu&8Ph5HYC&Ng74Q#9*fvpARifvMk146?Oq9ly)mOPuktsxU5eBkvLx z<*hC6B<&6zn78BozHB*}$n$;tWqk8E_t=LmxA8K{`s{ks>-fa);SK-V4JBJj8#i2Q zpJilzyz9-0MON+m*6rT;Gx{BujnU_69U)o#3oqYV8mtr9@pH1sKkifiaF(8F2-N#>cXfgT)7*WbT|cHO zhzeI6+ckOG>vtz!w}tQ6STx^YyM^_+JvzGIpRY5VJ*7Co?)lznf37--SG_qkVV8AT zZq%0lza(z@waz>8^}obVeeoCiivLevUGw+8M(8U4Pye+~)F%~XKWW?XSG}C^S>AK+ z@}&JgH-Gxnx%hhYHm`?`FZC^bA3a;PV#dD9q9vZESY}RJ*?8D^aYUogH{GUFdrN|} zL{6p8sT8P>zUIgAX_xp`aq(r%IpWhaT2;Ju@lWZ`Zm51Wqx!R|jn)G1YQcEDhlK^D z){R0{vk%#Y-ZY(S8C>|>G|+K;jZwr=bmzV zijV`Xorudm#D#b0#IED5fk0S{KMnp80%DSU$?-%BaRcwf0nr!om+lPvReJ;#rRE@n_iT}O+ETz z(cS`sO8xa8V;8ZV@jN2q^5fpy-xcdU^5i9(x~E;-tFYq$kAihc>4sy@9eb=hixR%a z>UX_&^>-?B|Lf0Kqkl={MOvK7mpp~@q3rwA{_rLr$ki6TuqJ8sJf7Xlzt&&-^**L2 zW_$V7|Cg`*U-N%`(5h?mzSYmW_W$_W|MxvU{b8SbILw$C?-mY%Sn zi_PQQqtE$EM4t4%U_RyO9ab46^yzw0{3?d|@!kOw=3i-9eqKKMzvr=koVhiBe!f4I zwe?@gzu&9R?Em=S_1XHpE&t{(|M`E{=Xkv}qOZ-(7g+yDIkKkHBY?~;G( zGyk!-t>1Mp>cYCUzusQ;N-te|Ij%JPy0v3v?$&EBS>{HajMZIx-D>s0D9(x#+2z-+ zXTPgj8n*K4pRelw{&W3_|IhX3|CIl4*B|@;)&KebUC;h!?Y(^Y*ic2n)b!m!UHSP9PuYkC<=6gyfh`hZtEBxJ+zirQ}uYTRC{_p>zKk+N4&A;~l z|HnW4As<%$;SV+azkPLT`PuyGF#;@CP1iI1c|UD$>4T!}TcozUF5SK>ZvEP_8gZSL zN#U!mT03xOe=SMgYr{&eJT{H*`d^H2V-*8d+KzWiMMwE3Uv|F!7w+8@zVe!OcIbAlsQI_^)~_{NrMhB6l-~B$bGI&d^?S8{&Ht-EjL2& zaymcacHYbUkv;cVRPNc;SGC`k=I;&CS|574SN;F}>ks~~PyBEH@_)VQKmB^E|LWiV zN8Qa{b6slnfiqXPewr1nzc%!C-0^&qI}3JgyZ6ySI_J7KZ@uil9d&Cju3Tr9^*TFs zeT-)5t+(I^{%`v2|GYmSv)0#I{a628Z+cz(=h9PIJEK-smPXupJ+)}%=3P$jM#>#*?u`oe$fL-x1*`~T$s|Ll+U0SA|V zvJbiX=e|a0c;ZR@sn&5@AFpSdyD2<6cYAi;(r4?}ty^C`)h*y4Z4QH9 zSdZ4Tam-)|eStdqIxul>o|8T9p<*VE-M z=C42eKimKHf8qb;*X&{$)~E_PD1e%}An{=Y$y8UMfJU;Ony_cP6} zHSWBfop+M|)zqq;GHb3%HNGxA^)zd3ROWT#HjYptJ~M? z>;9y8_K0XsJTo~-&ZuQUkC)q#lPpT-Kku@B@UB3%HdB1D;O6yw+G^92Cf}Cm*?jBS zf2M!>AO62S_y6aOANKG6Z~vz8pFQ=8o2dANO<%V0Okv;T6YXuI6Wj2Gxz8!_)ut0+ zNopdwOKxunXV81FKmOqVcmF?5{CNNT=ll78zF+Gu?z#4RRqdw&@7eZTy@_{9!?>oq z=vK9Jgsg0tdL^6x&E7L-|Fiyy7ySSJ&;0)0|DQkB??3uK;LfSTllD87GUr|0^=;R! zSI-*FmX}Lx&i>rGDWUXRR8?k9OwRlN`)&TSgg^QJ_Q(InkL=$!ZT|Co>G~hfXPi9w z!my@5cH54Awx(NA75w>Xd)(|;ebdrs{QRaU#IQN~W%lR)oBq6(|6uHQ_5Zs+`};fo z7q7J6zGi-k)Edqu{qmiYciu|8AMX3Vev8@EiB2n*sYJwPXKacKjNuM_@^4P4{ZFQO zPPO~~HvS4xpKvQ{Q@`aJgA?f)6?5-g@RU{%){BpoT4Tgom3_r~eVi?y{ZqSF^3;rz?({@l2h9S~i- z*pNMXVbCGdv=b3a7vFkS-1XGosLN&D%#~BtGKhch7yq#T`hR<~e=lwRf64eOzk8cv zaY%XXi$8n0&UuxFHL9+DmGkI?mv^e%>+Fl^AD=CDuDtf||Fi!x{|h|-pP&2xci~6= z0Rae@DIQ8 z|INSo@{<3r_;EAb{ZwDTWTx&fzJKfD$M$lue{)3gE`*zAMOe4W<<$!)=xh;s5clfD zfrQ)twSVka_@Dm$|Bn|x-ar4j|LOlN7yFj(eR}KpBsGPgMfz7gGQtG?m)~Eoc2VxO z8J`Q7Bd#nd(mMF)?EllB_kaFx_WyWn!L0x8KkNC={=Kw8JnHKTR-0dc*O{_jHD#__ z8OCBH!C>Xb`hvT{H+fCL7mlYl&Hn43t9OgjKllIL|L+?=_Aj0H)LwsYD$`j@>ylQU zPoa%n#!HxPY?{(AQ}6$kt32M`AI=_gkhv;ZE&DV>VnaB?x(D)l59;6luh02&xbk1V zcEgFxmwQ9Y9dg+Y8{hjLdDQsEbxUQfrT_bF-_|}o#avQ#P8s{Bs$;y6Mx|UyZ^g?p5Ohz=70aEdav^NEK*B0YGmqj z@^SWb@@-Vua{b9NJ_e@^2U*4Vr@y$e_Z`;)?jP5S82{h?|Nq2~>z`lO|9bI9|A`$} zl&w@oh@j53RMo)M+BZc~^gK;QZ!NzywUO#f)^}RKrQF8< z+rNXd)cN=SZCCx574eALut-lf+r;;=Ut-CX-$L6o-*vC(VVN)fZA#MuPsX3A7Y~5+ zeQtkh|Gs_izyE?C|6gBUUo*G1&c$!vpM3jX{Xe_+{}ulJc)k9olQpNeJlwnBN@V-B zsalTST}M{@yl<3nKK|RR_30mfmET|2`}z2(|HX&@-~Inu?#=(7AN~h^dB5-qm&U~x z#Xm!2ix;IxOgMA)(9wuAc@3e-&TIQwiy6f;vV-nk{IB{a{?h;C-~Z($|1ZB>|7F_W zmTla z8~&Vr{c(TTy|4B1;{WaMv!=T~cz!y+wn5(P`|4i1j;$4vyOa(yvmZ5Dye9L>6Ca*A&-?%W@1Iy-A@|?hKS9i+h~Ze&o3|W{Jvn>{Ik$dZ zV7B99-hQj*O4{kU*9vt6rrx@oc;h#N{#pBd2B732@$>lekM+0Nw z8=Q|V?#q--JHBLvUjyel%-SFj)CSRw-onYfV8(%hTd;7op!~Ojl^X=y!D*w3t z)cX1VOP8?Z{9FI*zx|v1`!#XNKbXt6QNw#dsocD=;Bfc?D?&>+r$;B zr{8xwBfrmT-{1FLR}QcJ_3zb{{WUdrb!}HZ=Ra?t(kvkFToS@9WpgaXCuo{j!>PSf z)w-LaLgJ2f-)d6(wE9bn|6`v+<)7o%KdgWLKkwiCQ}wnd|K~;;>6ZPASg_@uXTQaQd0YGfD^G6NS@q;HyJ>3AecsGj;@-w)maY9+?yY?+T%Q$4-=>n+ zFP}^|?UOs=)_!$9XW;sWKTTguoMX|VG9}kb>yXN{nlh`OA9gtZ`zZyA%V+;r{`u_r z@8`974lBa4Zr!*wL-M<^#hQEG9~vH&`Y4=Q!7xR8dRJ^wQLTyBnY8ys<$tc9{~u>( z^MC#G|C=6t`)~f=|MCAFq5hl)3Lok+bv*Vl;+8IsU|r(G_w#>H@t(c2)6d+$RcN>K zduu@D7Ojg7X>rs3|2rb`!1l-b4~gghpM3aG`se>mzw2}V%|BD$S{KIn=~DE}O948o z6{0IReV%dq9^gD)c{DAyFSs-5%Bjmrp^fPr%AXgp=sDP1>L=L$ThssjLcPKshyUCE zZ~yxLTyuGw# zoo-$G|96M-U-zlgum7+8cmLY|<*)5m&AIx2&zC^41W_(U-UEhLwidjVS*lU((fFw1 zMr%RT+1a5R_Oypjd8{FPu`T-l_s8?T?2ldWzxsdq>;Ig8^PhkHe{D(JisdUF1+Crt zrS8p}DVKI_E%`fF$=AUlH*}f_hx^x%+h&}(e3O2#Y(DTU`St(zuk2$t{#$STzy9_A z$zSK6TmS#^;;;WT7Eivmvdf3*t;M_zVwv52y)PvuuszHOwhPbHz7ev_Y~Ehkzh1|r zKo02p@}GJB|39~1|BwE^{hxj8|BoeX9JW?VcKMdAFI~1@e#xe`g1OGoZY)#pTo#+c zSFmM`dTf@R?W|)VFZca=Q~kHz{+-wV*Q~$xU;n@T-~0>ztK$C4hcbpMf8=4T5p$Q` z%O8GWg^EqCf{@~wrP(q|o1UHa{=9{E>oEhpS=?FyYW<{}D7VY22Q+VxNkflz{=|I*#NkxI~ zTg)g4{ulq^KY#guw7EdRD%)O$4c(gS7cTZ*s>h$XaErsjc9(nW zBX*Q7H|>(y>+?J$_MsX<~$%58tkBuihVzeQ6)F;Qyw- z|JVNazg};#_J2R0=I4X1S*$V3Lb=O%*GhPcGG|$R&lF#kvFm@D*n^rm;b$IxwODPi z?fQQC?~DI`c=&t&pSFLSug(3x`Ro78U;OF6_aAutPk-WJ+oFHTX8w$CUp`vQ`}opl zH`TS00&4;dW&dUdX65p}ZrRhiwtBYzdxpFF7;3uy$iJ_@@LyrI-s2xvAQ0$_1vyE7GHXUUKn#_ z+zsUkn_K)MNjsD087L#k|2=R0l<9x{e3YCR|FVA7vl9Xg*E`ad`c8j0;q!?=^XV51 zZ)fdlE4yr2+T~?$#^Kc3Fz?>~+}Ho>YWDo<-wMi4f5F+oKL6_GU-PHiS_ z>D)hy&qtT`-kW;uqR65?siuahuCGp&uZz2)n7(weNyRTs15l1ozE-~@>2Lb=|9OAw zcl|q@`QKiD@7Ma^t5;iUC9iBt~wl z6!<93s?{wtP0FZ0E#Y|7k!{Ss3*~?H>#z9_${+PX|36m#s<&p}Fxgc=_>k1q6V5Vw zcVAj#r8w=f*VDNR)|Q{;Sm^WY0S~X&S5_TRuui`IfBK96n||-l|NEc$%m1AJ;y*(F zi=P+VmUL{%gIqDAwM;pu6Q(SE!+P2!(M+dFJK#k4F;?b_+FRd#eSf_6rG3o8|JMJL zU;n@SRo?IQ|F!?SOHNF5d0%?P=}JOXd@7U3`Z5!?$#Fb}U+cDi@2bZtRjvDn2$#-f`qNtBp`HC{V*VT!t|U-J1& z>Ct=FTvOe@CNsb8-@g8@|DP}4rxm+z6|3FTnyKt-?&-%q{qbq_uh9Qo_h(J`bnwUj z4}a%7{OtYbzvJ`%b>IJQ6WcT8eOG#Q_`}EdLi2JZSh;ndU%lN>@;5@7^F595KmYIg|6e-)j^E$^``_{N|Gvim@6Q#`GvhdUH*)fX>G$|HZ}zHn6t!>kmFa2=r6f0xpw4@nkDesb|+3)>#nDy8G-}O0v|8IV6Kj(V=j+ga) z$94!OdLB)A9Z=2li6h6BeUIBet%lQD_n5R?v$VS>?mm{(HuuP<<=6lF$yfa6zi;#3 zvHaitxc__WJKvW?J+i**x8_8@&YI<6%klO_Ltl?3z9O z&kya88H?B6zq9eqr5#`Y&o7rU+3D~fT)J0Z|L^j8&A;bM*MFJ6@ai9)*tHP>(oWpB za;Dtd_vHEBHK#T#ww?Ml$}vK6%TnjF*#$E$fb!q|_5V4l8vnij^M39B^7a2auYqd$ z_?Q3RtetEiu*NQHYg)#&8lM7RX#<1*frk>8{*I4|;=F$F>akT$nfkXtCgfkNZ{+?` zzy5#z-~IJ}#VywUFFGCZ-mug4b>QNtYYp?}C$4w7wkmTX=j79cOQtE#_K~~y`Eq)G zNXgfG6`)#a`-}bWzW!hPKl;CY%fHtzzy9CzW$M4|R=+Jvt}m=*w2@)=z2&e%qMdFy!68|Cy3r!v+)=jIOn-*_!yLm#W{e;<>)8?QmW-@hI_ zHuUE2eQ@}(EdN~p>C)_flPg~ytNHQofueA`=%Oy+41=wYJ3Hf8F57M4;ZiG=*W!wq z{pQd4wg2<4{;zBN_Zei;_x1n(?)mrq_P_Tzwyd%zE}!oYJ1uaoKdvt|L^s!j>2P4% z&aC&^hnZ!QB-O6GOo-YB@_zTf;N5WV*JmyNIzR7u=~!|Wdm-)bzs?8S?gnbyebsCd} zkNfh)5@*6=f9`ZXFX2#Oz_G-#!|wVM!wu(+wjRFs|L(8|3B~V{_4N} zTh6_zkNf5Izfmywn)qpvh^6waOvpWG7$l{e6*60~Cn=L-)lHC(^RNEb zepSEy|NgK4{TG1RNBLj(Z``qU#tyM$&Dsgq+g|Wy2Xj9#VSNH|NpQ3|9$=cnq9B!!N2R?{Z5LZKE?68YasB-A zR)xvOqB(hA16bY|pYh22UVr1)|FFO7#b5k?_kRP}@~?aT-S=A~d(<+3ne+9NvMnxt zEjun8IL9)v`HE+k@v9{>FMCxR)-3$Yb5#lyVE_01tC#=(uk_F2I*Y%@&CmV6>}CD` ze`?+T-+$Kk9})Z0b2GB~!{?{l=PWpN{F$Dws&bt6inCi-uU1;Fy=q|p>CXp~w=BAk z&lyD7_dVJo>OJlKw*S%p<=?G&|99rQ|GWRzAFBO#{n~%~?f=x%)R)??-xJDIu=QG& zrthW0+l2x?HLt0f!x$XRqA^YLa&;RI-#kU;^o$3m3)h(NRI6sZ{{NQKqvtgDod3R` z+Wv*#1C7d6`k&n|yY}y^zS=_}`wKlP|| zU5B`;)&C_M6Er0IH~Pl|DW^S>DTt)WM97i|IeA=?#R@Ck9oLe-MyxixuGYl zo73`J;glbfb-Gs_*&tW-Z&_(Xj78436#f7Ae(nGI|NGbZb`}4==fC{F?*E-%_1}N_ zzn}mA@2-EB7yrqZ)0V9dU&-X_HvjN$hxHG3>}Y*auw{;i;PyDTOx~oWxe8WUEn@k9 z@BjKQ_BUTX?0@%^`zQY2{u{sU;{V+fua(6`-S&;@=JN5jzM8u2((4)Ag$W5)7cYrR z>21C2Jzrbux&4ZkAd`}VH<|3pGHdz&MLvD{^ZwWR+5gi&&M$u(`S0_k@IU79#cQ6f zt?G$XH<(tERH-|A-R1TW13lII20miz&z+l)w9#il!G89C*17-8|Ie5DKiBW`{rt72 z&ALpr3%A_c@F{CmRIhUc|Fh)YIbAo5^5z&DZLVp&ve)IkTlvBI-3|Y1{~dq!zw*!a z&wuVmt?ur7yvOF`Mnkt&#S@2LeXvx!nsM$d?A7UjHvdzr+-*%&;eeYJ?Rlbs~UZ%ck@%n8g zUwF9P)`z`os^8b}fA9azKkMcG*UbCxzIN(z|M

E%sJ2wWVrZ2Mm`!Jln4vwrf`M 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%0A>TXe<9KCS;j?4SKU z|NL))CPeLf{ukfazo@pACA0bQ9Dk)Zx1PydYrDviBP>+KJgcv9bwlUY0NtzJM<(2Q z9{cluf#`qh|M{QmC)HaV{lEH+{L0=9VF#{Fe!uVpORhnm;uGz+zb1;AMCIObW6oj} zSktko;mzf!zt!gdE8rS!z#91$-{Y~A{TI1Y)7dhr_N*j}vk}7uInkCy&koFfWXOK4 z=6&Ih^8Nb%UTXa-|Fi$6{Ym?|kN$^#>woxU$-d~Br`_g8tz5U$XoCHr+PTSFAIMk- zKFusWV^OxDbd&WizMabd9`5?PAKX3p$nSsif3tpm_+O)6GY?-E6J7eGKzi9}du5yE z>Z^0yHMx18dT<(amTOx=c|H%9s2*)-}-+WGz)w3cYQ(9fBtX(?nnRJpYb0& z;0Frw-}Ru1_uKy^lY8`v<}esl>ahzqUW_tXQOYuH<2A4Q^#`23I+QnR`XxP$(D;+` z{r`j3U;huh`@i|;|HnVupMU(H<-Q=*X2UWm2U%Y(IqARLH(uxP%spv+_EzB+PSNPi zb{v{n$M}!GT)6ih^Zy@*{=5hEUW!4ZGXJyO4{%?N)O@@5$&b@6t5eesy!Ym1XKUQ@ z($_@BtKz+BNt%GSQpk#z>SzCZfBCPq`~UT4|M{Q%_q@BmuJzyIckvc(;hJ%0UtfH; z-0NI-)cdtxRNrmBBD97zddAZ^S>`!A)RudE_~WvRVNdt})1Ur-`*k1Gr+$8;{%Gw{ z&0Ci_JUb6Oo^yWUV*fSVVK&U%WZ(-k_sD0npUHh+p`v2{p_Ot&_ z{xhHZcmCeGqme%|J_P$txy2)Qum7C=#lnjTnT72H zwZCBg{r|TA`+wFy`gi~Sn|ArfzrWx9^ZV)E`bTT`mw(E?|NqC<|F_Hk+s<3b`2N9u zrTvBf*iSzD?<$vPe)7$^mO7_%TtU0sqd;Mw7oA>|!^PTj?;MV;)rw`}Y{eCn5^ZtSZ z_WzmgmGAlg+rItP{o2oWzsLVS|6>hk@!ju>JC`4Sv;UvrpX2lQ_5c6%WBcdn?Wgzk z*F3y^{?*&xNBN)q|8v%^=K1~K`&Mqbf4e`v{`d9sbwB#2eA@r_`tkCQANR`FKK~QP zfB&of+vCAs{{OH3v8!%j{FQXikGucaU%37?eo5Zn{m1@S|M9L@(X)Rb{>}XN{QI@p z|9?DmOp?3z{Q>7cB~|;HpXXQC?aM!Q{r^b2a1vxv+cQbMLtpZYK`We z4@XRU(j8n~3VT(Z-(;-QimA5?wcPjn+2(fnjg@tV|6Y54=C}U;xai+&&3~_7|JffE zF}G>UG;j87K^vVNN*yI)nzcc5Z&iHdI$d*>hpEagcU6<=;iHYS|DXQRF8;j!d40?| z`#F!~9Jfs{h|y>|9$@S&t=VjFH8T$i-vVGpWX7+{hG>`P;Pd{k}ucJCKz$w z49xJg;gTxtc;+&V&#A=y?#KV7e?E7A-v4>O-t+nXAJ4D<{Qp%%>$Q_r4=b+(tXZ~} zeS#zZx?4F%Yi|7MWh{+YFOnN__!RT&DW>Y{&;C#Sa~i5O-tVLS`p^2?w+M7TU9xb( z{-SA9C)P*WaV@{AFQoXACB-B_;&6p&m(k?9ykwu1*}wmbfBJuvea-)4P3u3e-~Iov z`+@)B&&wD-?J_rga8=JCx$kEG5q9?=qpOhcAEm}NX$UXk)tHsOMZd}@R zhHW{^7QW+#T(j=&Kc=G=a?ItmU)h$xn@{48)K?e&EB|-@>7VVvf3{!$nZN#ryjq9B z#t?C-b4)LeKZ={WifLm;uiXYm#wU~d8iKDRKkvUT!Cn5RUiSarr9Y3){ad9A|cZ4r>JiRR2ST9>(t5aOC7V@-pi!ay^Zo~awf|7{mw(Ty|BA0|uVlZylB2Yd|NWYa*K=OJ zT3-{$cI91E8?VT`xZj_|B-vU%p8LOd!vE>_{x6pOAAkP;&cFK~gCpu+{2|+ABEIVP zCsrQlF=5!(FpWi*)hehieB;(-*4G}MS`&KLUH{0o&<9Na;`jZ_zy3ew+<(ho_Y?k$ z{;Xy7jtJf28k5|3z^L0osbSK*`g>e=GWd$w+14ysJyq^+#*SCH@BhRf|9|@W|F^&9 zpZ;mTo#DeVt^>Kx=VwMKYWN;kxx8$hhQhs9MmD!rRA15Zo!Bq;+N%HBtL#?uxSTDz z|4aYuulaj_-T$3){s(`p|4{W;{=wRR@moUV4y~063XQGH`5-zW%{?k0_oDaP&lyYK z7{_ZUN2NY9%Gs3nPyg}%r?3B){d@oP&-_*Yo3FqA{~+}5{Rgg_H@?))HmD|@s zm1==Wyo(=AUfDgv)bH{9XZu~+FK%Euw(bA*kN-b?t*`$7zUZI-)&B=yf35$p>fibW zjWgW+SKF1W47^p}V|0Cu>ocwyyH@NhDwHYR6{IM5@WH{X-T%H@fdlIK|G0DiSN^iE z*!zz^?&|-oniJb>YyUlD-0J=$fA+DBf?FPobzw}!~c=*{;&MAzxLnjr+?-b{g40tFW&OM?J*tRny;*}yLNf0{C~;B z^H$iKjj7f|H!8RH8iO%QhB9l?$E4P~e?EKt1Fcm1{XhJ3{i(n8cYoJE{S$7en11k9 zxX%&`t3N+i#fWD_)oM;L{Krvv^yYHqC$sN1CyMaj`nf;+(|Y~$|L^_ZKkI++yZ^86 z{nviJUtD%V$99&xhG{-pizjlX)vVV`aSm4cw7&7GxX`Ux#bN__@-#-0$ z|M&mupZ1~ueph|X->v)aa+Jl7hXwhoH@5~ITy`um&{}V^o_G4iOSc4A=Ni;FzBb^W zd*e_1iTe7=f8YQ8|9}48ZWH%1mFl{v@5?o^&nCS);oK626dO&E$f>{G~@5F7l)ai*nCdSNm+TK|jyJkjA(F*B{+q7ui=o zZ$kZ=xA*?l-~ajl^Phi@|Ns8?b@z|U^_%6_{C}7q(cHiNK>k*C`TcMETz~vHah~_! z%;?9K29Fu_uN-J!>6hfT;b1M-RkMn#YQbwnRwlRg<#n}rZOlFN`Q!hm+utv;6Z{`z zKmY%!9k2iE_x30=)peN5pZNblvZl1=*Tdg-_Z&Wd{r!I5uHVY< zZ2q0>xAQsTzl?FIpYz4QUBT8x3~>|X-KPX>UD*Hf(xVr$e94bi?Uni3`s$vS`@M&U zf+Fn$ zX9Xg2Q+{1obL`pwl7IJqI`cFB*ZTjZ^3VN^Z-4zi{n$Rg(f!eU`-jtCoNs@B$o@v6 z&O8%_q!~L*BLWxBIICvRvOuPtSxdt4b=2A|svDJlp102BZk^v&U*Y$!{NI0}pY86S z`S+jsuYRsxv26C^8!}h;o=rSyzxLkp6sHE8Inx3ky<4^L(LLK_=3+f=QNgms3pW2; ze}4b}?XUmqcmMyj;qU&c{Qv9YzWu+D>v5wcbjgu``Kz}*ji{-(>eqKx!}EMfg3^_f zZOJ}wXJ|4y-)BBJue-jc?qB)e_o*NI`5()_|JX17ulbZA*PIL2XG}I;x7?XwLVstN zF=?IDCBs~Y?WY2#Bwj0bGc`(V zH*DRSS!n7Q*=r@P<-u8hh;Oz2ccTrvMNHT3i(22kd~L1Ti^?DCuU`O7FQ|TumtXdO z<@Yc4U)TLhm%VGJawuwUYRjW3m&CWv_{pI({envDWi_3sy~kcjOg8NM*dVF%rcvSi ziT~opbrnkg7JfVb{eS1S|Mi7`>OaQ+>;M1r|1bUjumAu2Ut_|O$^Pf-bn#F3_ixO< z|NrUR^7s3H9lKXA{{CI_|IhwEG8oMcY(My4^xOaMKj%+BT3LPbd#O*|9&rqx~cUms{bAD ze*V9a(_!y?#w*sE4M`Q!XHK7b;`7OQddQm9=Ck9Bo|rcZ9!@?PK*%}U(Dwa9%phvw*TgWnW8)^ z?M^5!`tEj1>26))!fQ!W*b3%w^<}NGX04F>_wnY>`@jF|_te)Y{I8h*-&#n)mW|28 zif!MF!%cCz8ODhZduQBe7$mR(?c=wD&ar3@C=N~u3OUfBd zF>-riYE-(y^ndoArw#tc?d`4qTmP$1{PX$okLU3Z=G#A=zsBe2p-WXhEqRaJ@7C*X zJT~ute!!HTDg6^0t`tmLcfsPl*n(xdWlvoGcz@p9|FZx08~nTd_(%T!1NFbB{6BpA zu){Tn4axt$cU=uhuqxGYOxD|Ocy+bci;FLs756U!P&+PkJ&!)9+WP53#q>!# zd*s5?e)vqDW)-?klKYtmQ|<+~EwO*<_5Q6d_*eeAK3?qqAA^5C!Frombhkt#3uKm; z^(_{(2>ACeRY7cBtE}^Dsk>t3^0hP8 zEOp*j^7+5dpVOZ|?*|oy^_3F;i~8$#3jd$JI5WRA^tIgu@y9(kPwe57T*N3C z|NqWz`QY})$$#|gI@aH>`|Z2u=R5bx2iL#-+x`F3-s(N|`}h6-RsXZ#_08Sy`F%yHs{nY0dz<&lQl3^t1Y&%gb@{onVeAO9!) zslWU0f922mTmR}yzyIIO_)mTZW5E0O3^kV+Hmv$~shTyv>0H5|$9AuHzA0X;H0)b< zw6b8k*6N2FZPz@EHFmgh$DaNF*PTD_|NS2)^Z#q(pX+|Ojt5M#Q$$}xE**Sv@J zySGJ6tnv@Oa4gD9w&jqqrpDT$1nK7Xv!!1c?)?Gjp850s&;O?%@3))qziR&fU!Qp< zM0H$Y-SM@{-Fv-7)bGldy#X6aUa!u`U43=m3Z27Vi@RlVou@9(|2Mz6zM>2?7?Szt zF!NvgJKz78pJPye*l9LFc$$@U!U3J^iPNJhX1cX#h##L?>D1d&-{R5Sq&jPQEK`jb zxM2MHfBG?dy9xDs&i|ileBkBrqm8SsvP~@S^ybfe;&JHQ@rC;(oe$iaRa8+g-%}LA zu&gxtI77qP|Cc}epFam`gP8n#+4$#j?Z5YP7~MMhm}k7!GVL(6X$f2$z4`b5yZ@gr{diyQME!2C zyK@+8Lob#5kEkm%b3==zt0bOx5}1n+S~v0oB#iN^XL6P zP+9)Z;oontyWj1-(%DnHVCyBLHTgOB)U2nT_?_Ul`LU?nVKtNHthKDO&em{>+yF(? zr#FA{|DN}L94~ib|DEUY@8lShlCQ@ZJ-e-nF=zyDnSoTngmuFH*tM@C|?c1aCQ3-vxZ67udieJ zQ1RxS;DL2^{mK7w_6Ee7bW~->%@SKD{Ay07(uKv#Hf}JA5;k7SBjR>=*0+S)P0Jts z&jiiNMnCvp$lmZ!+>haKx_d)98}pt&&iDTt{(jO``pTk@Rd?3a1`(}gjSCbFk`wtG zg97{aH8|&d{_pbV@#pXVZ+_h`e(XQ<)B5jM>&uVS2g|0tJ(F9ps#ogW@L${y$I?8r!;MXWz-0jBgIxpFdV#n+Iwn9{m_Ef2@A*@&D)B|Hp(Z z2-Dbnc~xzu=N8$OJHH!hm&{zvsJC7_iu3TnIGvO0Z=8Cv_vd$?Kc7GU{(tsA_v8PK zpYH#Db>I5Y{n9gEL^YWnUYi&_*PAu`bD+=0^qL9trKHS~thOAOsh-funXIRB_m4gQ z|F=7T-v3-5Cj)Zxz3~6{1pj|aDox!Mzk4Om=C(wxb)~*jwq_Yfi{u@g{Ck6wt1U01 z-vy1v;?MtW{(OJ_yng=w`our>0spGw|5m&Iv0htk`t3qcR@=A3*OojCo4`0_(TT2C zQu8ABTV5B4IB2W3{H(*R_WJpq^_6x1zW@9W4&?pcukJ5DvVXC)_h}Y~Lc^K<7jFvs z99#6|z1Yz?F^w*1(KdZQA9Oforzl)Fe(wML&iY!A-uuXU<%F+G1hMO0xVmQji-4*v zdX7^wwRUTty>QfZ`s}rb_I7UFxaHc}|HU8r{cS;KH`Raq^Emx;eckLo?C*ORf35iU z^TUPMkNiICy(2a*^^K_5@<%7w`-4)T(p4VO8@~*7URbctDdz}2aOz3Im4~~M8`You z=lX14_UHehAM5)c?Z5Z@zwt-;ncwu{`v2{Jz`DTQ){h}v@_~$KN`kKQUc>8xUCDl~ zC;MCdO5d~EsQ!O?^XvZT|KBhDsE=U?s8?iKF~60e?!){$;+sntxp%nV&}e@oUMS(0 zJM9|dYeR(+@IGled>X)s~pKhoQ}P-UNoHKizry)?$-Srt>Q6xZ5O9m` zWgw{dd>Q=Dcuo4E&I`U(sq-EMWrVsl&(!>PO5e-&Sxbn#f%=Z5cGpW>{o8)ld;Pop z`Sbp-`}KSNf7AGPyY}Dh<$uawZJVVVdiq7a<3v~0}Gve@eZo_xbsrwafnVO~{L1vi(Iy@yzXl zaxcFh-+0^n^F%f7j^*B0ucd!n%Ua>|@99rSQ*yseSN+cO`)f|sTh%U(+~{$5*BOh& zwF@eFSPx5>3YEHM3D&ZOyjRsqZ2PzQs$=dukj?w;?Emln_y5q3>+T=dfB$*?{I~x* z-DU@;&E3Eva^Pt7^qZ~KR|H=-|G3Xv^VM#TMv?N0%{_#0Ezp=vCuW{+f3^ER|K)#+uId2EyPC`lvs1UO%Jw@ud-+sRiPcJiUoVBb{m;}s z_Q@@1@fovQ&;Gys(H{H%fBSQJxuf=Xp8q%g+kaT&t;EmSCv8?KJe+if{m`tALlP+_ z9G#1Ida$wH;yY^a?Vh0Q^?U!TmHwsw`EX+Y;K)||Nmca zt?>GN761L$$L;@lxW4Z1v)}*!`PWx`eU%^4yuanF^|A-&*YE#*`upR(BpQzi-=nCEi2+>MZ+r{n?|xPyYV?pYML__g!T8a#7`v%a_&R|Noq? z|Kb1b-TL+SWx~Jy{r%%|{JlEi$FYCD`seTOHGhA<{_h#_-@QL?e~+95|5EE;t+xMn-TeLj|KDzJf4{H$r3r z|Kop-m4CeZ{r$Z?tL*=+smTA=zWT%e-oHOz*CfAEzWhJ_sr(PS|65-FKmVz)f7buI z|NhLc|FyLK$uo<0vpx3A`}lPJ)#{J@7yyCs8y>Fg2jQ=YOyLzF({NR)1bz@%!s)`Tx`2-dTU> z|HPHHN<2SI|7q8qt5?7Ab$|L(`@fG?+t>Z${-3)4r}9hr_kH@GJMHD}&t!Xe_u1F) zC+ur(ti1c@|KSh+KkL_g{@;K0fBSiP*?<3K|J=X*Kl#Sj{jZPwFRy#Kzvq9uc+H>7 z_kPC5{TGP8+xzSPk5{wz@_*m`Xn$Pu|JeV#_5Od|{xRPC|NiKI4?BOdANl>~{ZISr zPvz^R{}@80c< zm4SaAoBp`}`~UT)^7YdH%iDfkeY94veKTL&qu@{1*I#tp&HLP|`J|Z9RK5Ui9=Tc5 z7%nb&5wYcGed3?XqCbw;{(Hac&*l8b|IY>37Z|NEI?p3;^ zX7{NlQHI5gs+wVjTh5ejd2{B?{#kyuO)NPVj<`gs%4-IATzmHa=*Rzm{?)(#A3OK| zuiHQV-~7K`!@6}C>bUo4DjqPkb#el)SO;Ze>Fx9x|G7Gwz*6^h7&*nVcb z{b#?$zlT4+|Nr*y|JI-F_mA2Cu{n`mrMZ=TTcqU@Kk+cPXy!G7eP?*8p8CyA=`&JI zdt&=wL{{r?JZl+69Jf1|Gt0XdsiJ<$T%w^+~e1`pp9F~a^6qg zx^L0XoTXn^J~$9I`M1)o&YCToe%43+v9J9i_=h|5qQr_CNOI|N39v|5KemT+Y^;|L2k00j9WZtD68VLx@T8@yX0jW(B-6?RwKal|I6p?nLFA3zdu%QZ`LH=`*8iY z|Es@0`X5#H@4wCd|NVdM_y7CVo*(ycdd+_37svUk<)fGmd@tuY6#xI%b$xrgp9@)E z{N8?l|K}gCE?@tj!hIDMmm@k+iR!Y&}WSo}!eoRtSJUWuMIP4(8N z%eVghc=h;v?boB?>#wgi7ySI!|Lp&NAzS{g6x&h%w$gZi-REDwzsu)6-hJ1*zUt5N zwEFlze>`q&*T4UG`nTS{uWy@wyZ+sNE7zVsbNIcb{&W3*Y&d^|art4*7{iPji(et$ zOBpU4o)cJMID7B9O|Pte%{+a;nN`&HrQhx;E^qnur~a?v{rCDDXsyksc>hQH|DE|? zc*yd`Qc20}X|5@W;qf~qOjqyR@HE)%7Sp^;^;cP?I!?iAlDG1k{~vc}*njK)@4El| z3)cSM&-VYnne+V0i~iLw>nbkJ^{>lX{JZ%79r?OHjPbSKnCp*m_7^jrWjnHA)nZ@q zR~~D(8onx=pz(h4%$-S#XX*P?JFeq+;ybZw`X`}+U$V#kfAIKv{{H3vpyS(iJ^#PQ z6a_1FK$DgFQA@$Y5uznAI%e(U6#%@JMZ_9H4ZdfEA& zQxi4nzxBg$>`RB9p&*%O>pU?lf{PCCk zj&m&4dcO^L3JjuN|K(us(#z)ybT78HVvERlo$E5Yb;tR$|Ajx@Uw82Twg3BF{@qso znLq#2{kmuIIZd~>9GbRopSY#jCF|{%uIuO>xW&MpRyV=(KgX(ruH4SKB8$cD{IQq) z|5pk$(Bl1Mzx|~D|1|&qP5-x;>0*Xz+V!N2j%(Rz|8?$8JbU@<^_R?C2Lx0dpJ*+4 zYT<73H$!UA&w4FTqp5w<>;L)_>nm0Mf71N_$@u?eN8=mk<7-no?i*h@9(j!=Z_ShL zQ#M_%nL}Lnid+@dKFA+`pmZnL%X``WNB{pV^z*v=r}gtct)KpPf8eUGEjvAOZLRp) z{xmmPMy<}RRAahjX{0MqG%HgfiSrx}lTq=FpZ_O+{D0%!fBv5T=KrrhnE&7R-~VSm z4f`km|MPFX-QPm{&+AXU$mn*SEfg$x?S#IiaEJG%l&^YxBk=pXyTdknlu0XUijHPW^UrnnPx1Co|1Vlyj|NQ^ckLT{c>i=E&|M~8Z`cR`+ zu0|XYTQ{#=xFu>!&=RM$F|Dzazn@rt*~}y(Au*PVwXz44&gw<~@Bdn_Kk@%BkAJV1 z|B3%ouemuj!@kOS25Y4fgGg`RSrJWM24!*UKBg>=uU3IQGkuJhGg6QL_doGJ^xXfP zzxTbL$jhCyuQ~Pq=^uaDrRB%?9422|<-MnorC)HVuTBG_nbfXpZYm}?f>e|KaZ7v9{2ybf6o8FXp`tA_5JhuVx{C;_nDcrMG1aT zR2tuLe9wlynSX;@r8$9c}sl=1=;sJ?H<;U;C$@w6~vB|8L6w(?8`;bo7UM+&vIo^=-ve0KieT9mm2ew>}DLppBrr((HXnWd+^LEizwJTbmC(3?#AsF`S+J75GQ04#)ioi0* z^w0K2K8uR0er6Oe6nLDqcx_w-4Ie-a?D|)q?bm*) z{a60?f9r?;)-V5`oIfYF%7r;#Uv<_>-c_cXMK?DcU-p#g9Y4; zE3_xMuV3Wn6yY`{NL(sQ@6r|-=L;u3duPvlzNSL4t2O@l{`mI)Z~vSBPyclP{KNl~ zHf{-Bxa+saliX=q5e>(hN`B|@?&3P5#aZ`qUT0Ui+G;1;Rc&V@^V|MwDg3;D`C~oL z@4q$w!tZ|lfA;^%KlOWh{f(IA>u>pAdyuwWzHV-P<(K;(75?x4x_|b6f`xF8Nb5Y@VLB_}V8~(>AVkU-!rCM}5ur z{`QajpwOuNQ-5pclY@Wmzm3?G_UO)%+gXgOR(#ztxtsA?XyDFcZ+LyVJGi~Y_4aI7 zR8a1;J^JDPxc2{ZL2Cz}?4Nh||I;H%j~3cU2&rUU3S(nb44oc4-EC=+q14vpm-DA_ z_s5j4ul3DVK6_-!?1%rgKG%Q$bN=lAoqy(wFx-)h$e1(pf1y|5vUu_3UJr!Bznd9J z9|-*Qpy`t2#sco_+OlmuoMKUI%;tvwzef~Q7X7RI{=Z7{&-eR=|CdWPSjT!-2u|v6 z5|Movk@Eau>I$Q&2UBv2&wlylyzJ}AFtx($@2BU3=BTW>K0Ja=>75cg9t=zSUbN+zyIg_JO6b4d5}w4SdIQJ-(-?y=~5@eZG6rDn(I`K)1P|2 z8rJ^vk`^er(UdABu=K@&+Yk2J+W+7E|NOK6Isa}){)s=wAaYM_ZsY#>NB=+NQP?{31^)>VhXUEF{}}I7 zzup^>_W!KK-g?K?PbOc}+0(J;o1k4)>c!a){$FG|!2Yt{?Em!#|I63>w_N?FeC0pK z6A@E4Dg}1-FmQ$O&CAfJ)e#JTrq$~8(qi|TCHK6d7`mtG<=yG{$G+~+|7)NlB%c0X z^XdN5U*>%K`pu3S7_a%h;MJvEJtqy1=B>vjbj57>@Pz*&qr9zS)H7Du*!-6IJzW2z zLE9gv{@;A6e)_BV2Mrf2xW;1h_-{~lvErPAT(3+o>|VG^sBa~A!pB*RGHdl;xA^9@ z)bB#o7Jt=g#+7ysYuU{nS!w@Pe|4GbaY`brdhW8x27BxD4!3GfW>{(>av`s!ejlpF z`6m6(I#l=mTjh3I>x$fs+zUD%6Q`+p_$g9bBIsU)Z0u3TR`ycY} zyw?BNRrOaVK66OmI_NaZ+hM)x=eqS*!xAHJyzZE=NvXL0nu+*US+0j$L|OA&{@02A z+x{>8bG_F8^r`>#uI}ISz%1tTx3jmaC;FUw?ds6Zw^!uE^X2`I_PJ=e1s}e)M^vV^ zVsiA&|C6&n@IwNo-m>$*H@ibRTk@6C9<7OsKd%@4Ah_znj~|CFE-RX1!8W7(YMa}O z-US`($9g}k4}Vw>+W5Zw(|Yxf>&yNAw@qT$zVXwi$jS-q$&OK}zf`y-`0ku#_i@VZ z=zUhiIj?!weYXGodjIX${J#!bWuE@2KIrHFpuhaQXKzP2dcQowV&hobb1Zer!M4hq zTOV#(W-wb(%X@`HOG{|p_Dlb{*IoXf4H|e|`Dgx>f9!g9>+gj9`g7DhJ^!G^GzZDg z;oEM8SN&NO%D`;c%=m8My-WYAv-z@Wb$1B9yZwH;jp!Hw<<^KnZ{s*t#oR*WnZ-UW|=eHJ>tZvSglDk`f{fSiFjD~ft*DkUK zc+FjG;r|ZJ%Krry|9?Lr5HG^gc=`J21``h7#aGU-C*9Clu~(QWL#oNBi{(m$> zGUZ?PJNo{WgU(@E{;7V_Kk;`j>bd3I>x?&@e_|J&x@cd@kEHHomW+jJ5+O!nD`a0S z;gl^@{GvB0@o?{ldQnKoo`;0&%YVY|+y5tBp5A*e`Nc-No)1>D`ZHc|bXI3auywXr zEjVDb#jO3_iJ$Qh8_oYiY}EU8f1S_ND3@gnBCP$7?RlnbH!ih&!m!im^|E5l^N(Nn z^B?kIXnG~m6n*i3to#4num8{fAN5d2^K20rQPCx^AGuSdu7L} zUoD9;Q@YH!KKtpes$wU%*LQX@mV95fby|$tch|>8UJO^v0@D>ORN+@QeTR{@#D~ zKjxqRrT>py|KE<%(>$~6mc~Y*x{#*D+5zjbuZ1Q|i~Fp4VD;36n|GcmEn$3NWOe_< zPgJLh>;Jmn^RD%#m%G)je`l_-Yj07B*4lXHkAePA)h(7`v-`4=gpC6&teCDroEi(N zmqAXApJM&lp4;n);Ja#;exsd}tphjTJl?cY=vw#jKL*SNSJjT1+;3ABao98QGdNV& zfi^3H6MEd2{j1mV{7jS)u6@3s@7-@$U6O97fldn=UAGcG9`# zvOA?Dz{v8z)PwuaEcWd9X1L(ai9hzckYjYZ-mm*5KPpQbRHaHc3)$RKWL%Osq0({P z;>pUoGR{$UvmQEl^oDYtTzQY{|8;20!0hxsZ9MsSRF-b4X^6huhR>HO?&U zOJ*S-!Xi36R-J`J3p52qN;gcGb-1o!r10v^k=UcB93(bY*|#y4=4>_pddb*W;*{uy z?@UX#N(r!3C_k@%sRd1Xr~iBYir@93{${R~+}u4^ZU_FB?{+O_EU~dlHJiBdv;$wR zgSMow&-vxIX5_X(eE1HuGXdg5*}v~292iWGu`FNw**rl{dDX*Bm(;EXnS5G2Wn+z> z=PT8>EgC*CkKN9pdGX5oGyh+DEO;cze&LM$nOCPu>a&u~-d@cJ-SF^u#R5yNkF(zJ zE;f5O`{jS<>lgpO1D$FDvC#E@^y(=a(q`oC<(t2X&n6(V_fTBc!l>hmI-6CTT(uVS zX|{+p-|l_!|D_e^(4qT(=7SULCF{@ojV7?i8!q<)`|tg$p7F2zIH-yBef59a%-`=f{SGe_>1Ud}RbO+So!vxr5BB>T zJ2}{X9||hqX@0om4*NQ*PbXt8pZ)UxDN36A z_MShd3zZh=JU4p&gzMp=0|I5*|4>ST_bPtxR4^bj#I^8@vy;a_#KVYuvPB zg8zp_iH%$Gmi`xycZJmJ#h?=XwD@2B30)J#qY|?t+9OXIAGE(!+Y!Po6|A;v_RA9r z2ag*4G?zEKY_X&a*6V#?QeBoJ$Jf3=twv6Z|6PB$;MpY3{k~^*N3=w^cs=S@S#&(^zD|<& zqTmBIuNWgz6OZ0YxO3uX{628iZVstvr@#O5U-adkR{`=?Rt!vf$}4JLIlU6N<9qnl zj8b0pE!UC*;)6_?8#^Ew5>Za>yZqnWEjilO`IlV#uIp`E)~WJca$Qxe#xCm`zA`yd zcNyPi#}zlX?3nnozTfY^{IdUdKmIrU@&E6udVjC~`Zw)AB&==UVXnXZ+O5gI_vAUf zd$n(mR#oY#3-x^&i6$G)n+RSmPJNqN^8e@VAN%|MmH+<#_CGj`@^`%p` z=e64`4A+}wuVY%$J$**Vbk)6jT|uZtY#K|Le<;+lC;G#s`*v4h z-@Sd)ERBuRHV8^;zTi0bq&{&oQ-Si|{kKEEK-zfIL2bOZi~if5`{ra-Kevas%Xi_; z)uu9xZM6pHOv6pupBjoTiHNsYkQK!+&wSDUT$J*4o3-!(1BGi>qO5q^UY44z4dl$| zGgL5oSHAQToAz_%E0WI7bCzD&^H2KX|81a*32PkI-*)|{#wNJ45?dqIen`x6*<#NV0uhfBnJ!|8+m@S2I+sWO%lfxooxZ|5ORj zN=fCag(ghSQ;&bR)Oe!G`X^HM zd#SN^`ySY_dus9v@ht0QO$QB)7Vz(!`s;q_m;Jl{?f+>HZUckDC#s5RmO;63WLwjn zjSFX7GK$`DC34r-#}gE`yj$zCk2`kPg-2!D;4B7j;@#H!6+gqSx%NwY$EgeTTNux5H~Rnh;=})kzwEdEx1a6*{`kM|Js;NZFaA~j zvt*r-P^#Cu=$WhnTzxb0L_hyeS?zcw!pQ0Rp}Ywj?H3+69q|8eEZEw=|Gz=9%J%p# z`zJm)9F-e7*EYC*p4Y{l3tZLpCAlU16uxRGwtl+b!yES9FtIgsFIx8^fB%d6YWdSL zsjd-`wbvwep0T^6x1~mDXS}0{cV~iY#|an3>zll$D?JVSRsUr*w5_lAU;SnMZ`c2~ zpU+zBo%UmL$VzuX=NElgpO3p)L7<)8UW z{=Y3L|L5Nje1Re7YI@C!Kamrz7br)o`;csVn*4E&cNUeN>&| zf8Sp`zn^bBVDj`WX4ovxw|~bn*MN`f0zbOF`u`VPiQR@& zV)yGV{=c^80%yUNAFE3jI!!kBUT))bY!>rZZzv0?Mj_Tk&4Mdf)uFzxCJN=l|}<|Fb{* z|9$oUyeI$k@5N6pSd$wvd$sW<;pVbc$&X%Kj5?W+a3(P8SMBo*<4?0rZ_=<@a&7j@ z|JtA;;s5@>|H1JxwfkRq&8)B!A^!z_ACzd!6q;r6^;&Kezrckp!hZL>i}MUVyx`lj zrShuu$^TDLnm{{W)PLr>zR7EjpzWc88Kts^>sO`q*r!y^{#g^bBdqv>qsXco{5KtD zOp#vs|0GJCTXgZi(JhHX0ijFJ^ev6fpD?lh%1PJSGOKTY+w^B$`7(pm%3Hnn-sP+* z(la5h1vTBlt(jAE|Lt#>%&{;?{4>wz+K%E|46`qL&+I<4rKLOSw9bO1zuTvNkk7U{ z;)K>m-CyMX|F&^oyu-${)1@hG^;;Mxc$M`0TJ57y>*x7r>-LyA!RN0(yUxXIB((!A z;ZE)Tx4p}-U&B~R&iC)HpsZ~iw#%05Hr!k6c<3{q>HOD@t^Ojm+IXR6#eCIS`lpVTy*!<_^k2Q` zUwuR)@s#WT+f6FhTMtBR-0hdzdFK6P4jsOA6WkU&pOo(3Zoi!O{Z`$X9f`Hyq)+~r z??o;7e#F0+e~_)gXsb-DoksG%ix(u^;-6-4hNYAVpHiP#^<@tr~g&{t_O8BUAD+&M{@g258HChP1Nfi^Yq>{5l4rmMFHG}y++3a@|T{G ze))eTD9OST!7JDQtCc@Vo$NFI|9QqI&+crGmv<&8SB3Iu*{rekhFXb=! zxBNPCx8#-Uf9)9E@XJe_<4ba)&Te6F)5>Q3_ORH|B>&~NwI%P5GfZGx{Zu@l>#oOt z{=LXOp>X|Q_cyZWh_k4yo)XpGDYb3IX5B}fepa1`YT;zfL zxZCAr?MtK8Q01{Aq*Pd{pI^xqxB#udhzrLR2f zq}N_dV?Ck$P1O0=qO@X(-#jx)IihEEo!ha%bmiBuSM?~J=~uFU*E6I!*nfVsy5o^Y zb3qS7fmRfEWu1;JYHLdBU|Esd{T&+~0^ zU%U0A%-Xq<4ZKY)2Hf0oSQM}^**8JiBm#2>h{}A~59yE)s{%QX9kCH#0_wQW% zFMVdv%3VczE2lCY(g>(bRZ#F1nc*#Q{$2CZEy)oMibgMTOV?~)_(U?hfBt{= z-{;?J%Rli~>hBtRv1YbkntphT%<2q-C0DMVT&e7%G2?uRtl?)@CneJ>&y1Y*Nd8-Y z`G56s$Ow=o!;0w~3~B3Uy|lkpHs@#g$~S9gynHZgrK4u(((`;3C7kcwd^wjVbeLRY zdusORf0gLp`n$jGp9K}Nq6~LB88(DZnGjjRIjcBfK{HRdLf?|wlM$wF`&KQT`oVPK zHAR-VH_5lagIq9ehduw?fBAoJ)X4|&*9|W&-@56>l@p=WmmRwm7kE75&~cdfbN_U+ zhQ4JFrX6(HFZyr&qW|l`b2C%xZ94yV|C>K|@^9ru`5{J|^v@Z*>JXC@mAT!#fyKZs zhpX&eUVEH|c=;K|r#?b?E&o@)`2YIa|Gax z`y-}!ZAbqk{ueXk+n9JKI%^wnd7ZXd*tkXd;eV}P|84&lf3Da2|5oLn{;ztwbKlm^ z`flbwfAwn}<_!nlT%5f&bfvNXyUWRCu3L}TiB<3?bv*)==)e9$d(uxq`r;RvFifcU zZnr>ZvYWDO?Xka2?vvv~5>-z>iC^Zlr7>(`d)C~Ct=GY!`u-hgJbrq;ZRdaMzxBc| z+9a?>^gu z=gL-s<_>sm+5UN*F#Mq`+<0xxnlJCny1q5CO!9maly7YR^~7wO`E85;zHi{+d$#t) z{|8pT_Jbz!z(bGx?_T`BG?#nJVs3@$nwtybFTQ?o?bZ_>#xEIvCLe3KeeutJH-7hd z7Yg)bAGQKSKg({FjC7S5x8C+f_X+%G-taEqRDBeY>gxHgGq5yh zN}Oze&BF}$0_lJA*B$=v?(Vz4~jGQ*tAPmj%6U*&+JxH{8DO#Xt5N|CL@Ow(OqmOR-JPU$4(?pPm?4 z>>BE3f2GlP@sFq{nXZzqD*NY1=P2NjNR~*?nZ&T4-ZTX#||JIxQF9)5Kmj0=J(x2yx{z*PEHLi4d z{N>f<-OqgIEo7Lvy@t(-u`qh3f`@b91*-zl`R@eNj%`0^AHVwl{b%)`>*fB}`2Dxv zclrN$(=9H?zHDflGEZAm>y-OzEx+^r+BGU4MW;%d9RAmKQ2tk4+K2sNI~o5ef7-4Q z|4o0vl|QAAfc9Us&wj|~|9*e*W2dte`kk(oLs9J_e{pm;zH8IWtZnN_cdFX&MF zR4wO?e0V; zAODxkJ$LoT{~JB(GlM2a_$mKiahzjc-p~C;&7Nm3g_gIbtY-GIW1MR2|3088;9{jz z&cFKB`X8IFJbzOE`hT3k|Kn#1YX9}G{?S>l&*^u)^vm7YbxtoTwL5=Gi3u1yJM`sy z^Nc;~PxvgEak)@yd1mji+5h98|6lpX{^H(0`?s(CUwQM-;qC|WdcV25*Z3CYo(z(= z5bHHt6eQAUd3M(ofh{+$Uu@t0`^c>lS=C))U$+1K|Nq19e?PYW`2X(i_w1+D6Z-%7 z*Vm-)KX9ojdu*KXf4^*5O_pT9Ncn>W*C!@8Rhzvh@k zE}#CGXPrl?u?C05iuIDG7JLqPbW}e6Zseu;cK?p<{8az%x&0sY>hIUD=l5-Y`1||E z<@@*iRXeu($7}!UKK&PWXUgk+5x*}dvujy}$E~Bc4y^Lfi+AzwW7F*IJ*G;v0(2XsqkI=;Hq6sb4$C z>z8l;2k*C@fBV06e*e{@6F8TqIK9kfQY_4#8PryGfKSr+d3Ae~>E@K6%O_pML^L&I zYIA68-)Ep{ad- zfkW}Op14HQZ002lRk6nnbv|u#Gd}OX{7c}p{$*QT6JPKao(bZefA63D-`$^A{{8>t z?a2dj%M$dPJNF!!bt9>C(b1|stOm1#qW+%gc02aFyYSJAgPSzwAG`6b{`UX>`}c0| zo~Uy2T8mo~yN61|1OfhVj`uI-oLlv-)91JO_c!PE1z!%ejWxE7-5Ywj;B>8{xEhFPd1_U>+vZifTRkHVWB zx~H*DOMdoF@SULC&v3!OnOEiRp6V(vH#fI_extl^rmS_k-@Nb*|IR=Axc}?_y_P@v zr?(gIYTuDKuhsC1tK99trRQga7H`~ei=}#g$C>uCrL36KX(+o;A6z^+^;D7XWc{g7k&#Csf4A^ zJS?T=8)JEC9mCci_S)yX4t#;B@Eho9r5>lc?))tGE=*+m^K8_q-sskSP1rTA%_;V}!bI<@422&06M z+&9hxZqFX(w14nfWL#jdyp2mv@A_n!%G1v{A7y6k6kd5mu1Y>ASZS&85C3+ZQl}`1 z)-#q0!bOUidyj_%EaW&dC#ZPcqctavYri@_^>Sudeb|X7tcKSNmI)l4l(dwiL0E8- z!O@+UHH?jR2nkFVEGq859(k4|NiWu zee6AlW#R|_pYpN@jc8B)Ay>$t?-R6i%Ed@6UY?|08P8x%#+SiQSzXzZn>TD1Np{L{ z+Z)CDZ+*8+@SpVpEXk+#6q=}p6fV+TAn`p&YvNKjji;JSD#cCO-kWuv=qtx0viC=% zJL+CAef0m-OOx*ZqDGBV7wr9VsE~h`;hW_RY#xrX5pR18_!fBGc2JwD^jKEp;=M`% zleIhjSt}oZn1AG}>!y%D>cy|^7oGk8>)6A3Ma$EYr(9E?zie1^kq*6h?lsdjma5HAt^71eDaH1pQVO@ym#WMb?FaUG*XyJH z>=*i{pQ|`0CS`s@$n}GaZ&*E5n{MvBVl~;I_<0k{bcy!X=N{IwN}sjaip!24co*K$ z7)@{v%mF^J%?Q0b@id}YG zvF41rl+wbuz_Rmt$4~9$mv!!ipGcW;a?SY}fj(IqWGcK={7bbGqgo^;PRVF(sJh4T z%Fst}g}A1lVAIV>zy05I{XgeZ-XHgG{m+;CH~A@VN|E57^=lq4(_Gjjb-+Nz z$w2UE5U+4`c5ts{_^be#kftxw*sc2#wOVr`2K?g*6=5hX=(6|#2l@2>XW79?&@fnc1I)O`)ZHAIhHSguToI{`ZK1zh7oN8eWKD_z$I`!Ls|9399xb?;VZ-0)@ zUjF~(Cxxy!m;d3{KI$rSgv?32QkXhZSn@Q_45o8ZZz{yhYFi3SblxeS-s;=ws&?6c zagt)n8EZ;Bw);RU39T&SbjH zkmzl5{gm~Y>nr|;`z??B8?QLo&-Cn?0Fe~s;;?{eQbJ{1wv!~(Y7Gp}OgMjO!j0RF zX2ncrRF3a8oy0ly)z_E*w+60^oMR*?w5UPgU`vF@w7{GdA6uG^&X7uz-73>O$1+bf zX~EybFx{P8iL-l*?rs0|pY3J+9yZVgO8Yy1$?Nkk`r!KIzlxpAbHz~ZhYTnC*yi)M zu2q`pHFM*YRGX_>_S#Z&9{6yXZ#i@;E73SN(Q3QY-~Dn$A&k{d0=%y}f1O$4BH6i# zN0V_I|HT`x9ax^FoLca{t8msOAHzw%OiCp;v-}Rp+#L3If0EVN*Y!5G31XYdBHwLH z91eql4ASBY|9=0^xupLD9`vH>hRO%5Brw+2kVancK^@*8T0c` zzN^x#2U!d@svG>{u_oAm2PHB2MS81N- z)TJ!xeGyq4(*nAra`%=_yK&1P=1}2%)1b#5GY_ut<2`%u*0gipdL4ewM}j9sD$DwO zm?Ac#=(y%m8P@o4l~%#F>f^py6SvJcV`09vy*m2$f1W?bvk(3M_UF3q!TLQaM-Fqd ztmFLO>A}nE*EJ<+^~{TYmh+6BiWEyOb>eQ_5OhOYnPXd6qEn}-md@MAqd#7KsDFAT z<3Ro7Ss@kbQ>VB|YHymr?QNjka@|b%UUGlX%w>Iw(-=3-V6b)6oqX_Rr^dxc_1*u) zkJfKe`;-58|6P$k>fTN^n;ag@`fz`_kN110CH|U5jzJBjxkgDF&KS)sd^W?oG|RNK zDO2U}Nxc@qk3Lmmli#o7`XBDs%l2ov5x1p}(M+Q$%Ul8)XC$<2GC87tKr5B+c+e!=3Ob_)3OI7?+Onhn#s2Ge{m=3JasOBSeUU%u z-cB~#z+O%5F>K;>J^1=cbaQT+fYGdA-ec=7`Q4iET1(kQ&}W9YRq?D;t*5uLABMO8 z*Iw>6`R{p$kAdrUY~eGWm3iD^TZoe4mI*7FgBV^#znSZ-=Th@nPVsev&b-@aw*9#O z=zr_S`Rh6VNB_S+yXk+8XUB1Iju_#8(y5#`w%yWl)YzmL(L2G8xyJZVrAp5^owS+4 zcByi&r<{DSYt@paS61jmEB;$QM~e5y{4B*8UMmaOmTEjHa@1Lp?|Jaj_9Fp~Q@kaa zY7?9d+?w+(c&2LvPaX6;oALKOS;I{h7hC=xx+L)+{`3^> zwZSulmikC)8nw(Z{@^cl?smF`%+b>^91kZPDmf`NJE*G!9IFEV*Khb+ZTHXEs{4P> zmf!o$S^iJo^6=)K`!{#|^xm>1avCSwvo+T%#7_3mQ&O270p+AED$vF2uq;n zmeV}`p==xGPbz!5{OJGF5A9>c|7}OLHQVyC+{X}((}5ii&Rq8KoL<#sbZR0)_58^_ z7QUHXo31>1@k4*f@+&O`-?b0_7oEJQ@~OJ(ohrvU1rq6+8*fOuSPIU3bR*!9tH(sn z&&;Vo?Gsg37DZTze`Au!`?&w;fA5F(@#6oszy1&Q>4Up_?%mz<u%@98fA#v{`&Qq3(c0`aEr33(hVD=d{!x`;&r99_)9GNn3e-%Tf-J zc?F8!rwD1ZcJ?)J@*nb=eI_D%%?GB$3)7oEIEXOcQp$b{O2_U0lYD>p-~Revy6L}n z)Q7yd_jxgY!dsG;Z9Kne!tCz!YfGJ4L-f1~n`drvGM=;R!GC4PKnum*vnC(IlAi|c z+jV%qwwkN(Kjw4QY}4$Y#icT-*(Gj!EUNlJ-dK%AQOqmY-AFs=vCQQtBZ*$M$y~zM zKn2D0L-jlL{v6l+cc16a^wW&CH+AxSf2@!7(shrMXyhrE>ZxnVNps#-e#~iB)ZD;l zxoJEb&v7?0atc1zoYur_wT|b1xK9_`pKyz_DQ?CAg=bbKygZy?#1x#qvdD_nh*Kq~ zPs7|#dy$F6-z!$LT2(Ao_5Qi==>O9X;8^`wpU3fU`DwK$Np$$z!N|+0l$E=O~pMSO}nmI z)~^HEDt~SJhE~HT6I$nGz7kx1ZpM|5Jprk{H$)dEHnC(KXqn6)GiAv}$?Z}vr)&q6 z6-PhVb0<}7EuYik?6ODc(NQZYmbIMUoF}lqY+dZMuwYJT(45MZ zIy1gSdfd~i_0kBIbYl~C+SE`Qx40*%S9jyhPl@$QMKTN;i*ek8q1D&%@Q$uEIBDo*jFUTp|eNnQD*hI)qnRe z{hPe?QT^-xm483Z*J1p7!sge+v_I$9EIs7yQp&Y$?X$3o^~S5_Ub(}3AYJ8jN4TVD zQ|0P4+jXX%Ql2cyRk1_pPrM@Qtgz}mM}$fmE|@LmTV^TQ#yO#+Elsg^+J!`Bm13h5 z&C+`Y%*Be+mQG0t5bL=5sQ!1Q>Yw|^v=7#wO8+Q-y6o?Nw+H{t;@JM>K6XpYzQknm z^;CvK*~Fl>Ips~uV$z~Kj>#nBQT0g@?}CLUi)o); z_JF4kyQlV@3O({CMw4~cr<#d9%S94b%WgUnnW+0G zaiK9TKtJV}WtQRozk7uKbTFNIZGObA_-HSVQL)1jE2whpJlE&*(q`O(v*rGdo z7nogbyWL~lds!z~^2@ZW+z_uV+g*&)JuJk0)&?xO$hqw*tM0$~o&SGiz27nE@BMlI zcX9scpWaZl!|{Stah;*t8vY2k1hog7MXGbwu<97|rLkIwUX#`}N)*_r^i*cT1tz{C zgW1OIU$Z9Er;21m{a@Zu)VcE0jZFsb(=4_gihNe%w#KdDt(2PewV78cr_bt%mg{q` zRt;XeG23we-x$IFoKfrltLMG_pWXL=r^_CxUr$R-IHDH+PxsPX*79(Qx98U7D|z3| z>&b4L_;h8HWy7Rt3k04YvuHhhN}#53XG8hCMN1$5&(gfG<=Oj?Q-&+-)OdU+Zeg>| zoO@2>lGHNGhA%yAe-|{rR=>z0ypqT3@T3XH*WLY}YrnqXfA-h^N7nv-{`GkM9+oeM zKfl<1;D2zV?CX?eTlgN{Ghmp@lP%j(wN_?_PqtO&7kaC{h(_Co7J zeXB^ufqK0}HkUPqja<{X9?cZAIy$XcuHXz;N~l}Khu%{e(<)o0Uf|I5-l%rwhuD8m z?yX<@Z~l(2|M&d+;XkdRE=BII*pK?Am+v_~$|yV3XRb(?d9;ODNK40PiQ)Enp34LT z6OTGuB<@_QsK02+j147_?CbiQu{wTK{CHeU{;J3nLR}59JF&daX@; zOQ!|sY`xH<{cvyY$Nhg}WdC1(_1`(_|NPhe|4TSuxIe#`-}t|OLt<=vQkIB!WS7zF zC8|#8D^((H3*2s$>RqwqUbEPOh^0Q3jFYBwWjhy~d;0i4m*#~j&t(_H8mT4xQrG$zkAA_qG>TwB8DSS*=x-0rD^++huF^(O&dw=@2~eSYdk|Mflp?yvhFQ~u|; zcf{XgpI6_nxcJL{Y24;19*HhqD~?E>l{x0au*Fid!{v%(mT{+qm-7jKzu+gG=cX*b zq_Df@|M{yy3mE@La?SE7l0Wx`KauZc}7`zM{MIJuK~MtYcZ%Aw4RS%pmx7ag0X zBzEmU)SrC&@Z4PiGxg>R_ z7>oVl{CoL^?^yI$J3^;GeyO+5+TBG+Y#eHeK)y&?(mT8*0Wv8|V zN-bS|m36hM$K{2Y;!JEo%?Gp!ysWjRvK`odt#EaZs#ru{%&`Iv+1ATvEV$hqkHu=u zcz$BvO{s@MKm4y}{onq4|2>&M%e@U4U+&@Dkud*;(X7go8%j?xA6VJLou+bWlGkKT zoz`Psjb$HQQ& z$);39Fek`S_j*vF2vY->H1qPR7juQhIud)%UeZyOd**T_yW&VnOXt*=O{M}%Gy~X9 z_k_*#U3>9{^r8f_2Ybb43FS@kl@*@(MKf8F*;(Z96HS#Mg@^Y3E7I2fjSrC6{uYbnF!O%)~7dV}vG3GW}0kAengS z!Gh0C>jXZBdvvjF5pP+N_)VFE&ojl>Lg~edXY+!*MO^)=pU8w+EG_U=e7%$Xop&G0 z89txv|N6)NhrazUq!Y3G-)FVQ_K{316Dm0(w)}rB`1MZ4%*I&t182%DM2(gl7S&?C zJpZN7>;*h?_}DW7rOaws9hP4?v~*=G+rRbuj+g%N=au*rb!&=e?%wGujTZ2k1lh54 z7`RolmaPlCku_VYe}|Xu3x?@hM~n|&5`FZa%k$!v|K5ddJ6QHCWJ{fY{he;M`FKJ)8;>BawF3N7eA z=X}5E?|gxueHl)gJ}gTOBPLx*WB8Qtq&mIVsU>liSGJ?7Rlba>%3}*RK}E%?D@I@b zzpAz|{_lK;X$AAG;+LHlSps6KnWO~N8YJ?5@T58^ERj6ZE->+gglfVs;mNN8H#_~^ z?-XS6_8a#h4Gn|&oUelC@A5gkhVP8rhIbl%a}x}teO88Mx<$6FOu7~Q*i=+8D#Kz4JYZVb+Pc$-+f6WT?Z0?QO{p*To|;ZP)`y*3Se`j?C0zJFr*H$yj#C^F zj1fw2RQMd5CY-QP6e`YYO>{|FedYh^WzMlGI}UUtP2pl~J`i*|=<&{^BTEgqf+kxD zpHW$J$V{Dw#YL5E_05d;#_GApqW<20^?&7($nRfHy|=jk-~G(X`jb(A|EIn9@4P(6 z_=D?;*@By5zT7F`YWxsqF6BS5VB5QQEA4FM<{#T|QuW8)OAO8PS z?!%&X-?O6ofA;hJQgU;KYoAKIsH`uacW^z*md%lzCA%iguV zS9sii@_{eCy$wB{0_}gDuiFhn8xp7Da?&7DWA?pwd>t!{ptV&bu2*~%QpoqDHK@124@??czu zTa{eqZod5S*Q75BmaMtcHXGp_b)vn!Ls?k&jPXk>jnSq&Tq<`ZS&_5`~L0!oAuw-SC#)?Y%O0~ zl>h&;b-z8M4bzJohNon9`9*$GFR!b~fA3NIc9r-y`I>(}F2*hYeY(YmtM1Fid4^B> z-xdDr>X)ne_VKTL-A9A^q~v6lX`fH7y)Ee7zi->##7nk}CwBe6x%haw-QSY`51ZNh znPYm7Ew{4VWb<*AebH0aVyide;S5{vnxC7~H}&1_Mf+spYS+JCpu8iv{&07}-`&>l z_wiism2!{az5eL^;l+)<_kO1pajxnQ+3;H-NGhRZ-^pGPo~d)^^zpqt#B{RV+Q9Or zrQO?h$)G^%DgWwfN(z!zvo4VQ`u%w6Nk<9VN0 zqIm1$TIMlTm*3ak_r~_7&c3}qc7F^`HmZ%Li~M&=)p%CB{Qh>7bo zq%Pd6UtV-=@0%kAp$?l4uC$!9pZoip2RCw`xcHt~|98omly}$vuGk~Sy6}bjld=ix z|0+EF-Fi=lL+B!LMH|$q2mp(_iKN9^s`$RgCZQ zt{yvj?#aEdoT7yXA78EA5w*oaf_>q#b4~5mn@{aeVzdo+|GUIoOZ}Yzqh9WUJHJ-; zckZb%e_|mxw{7>&U1dCLb_Px;s(;}(hs*eNO=#9?YpqP-@X~G1PPMAGN^xD;aiwDI zrcV#5?;r5lo3*&NtZ(k-#d#UOrU)$#PQH^NB4=ycXVd?7_CKDpGyZiISkzV>YD(JR zb8^${lHKag6+g|ZP0Mmxq$V-U|G9nB%iu||-%ftGr>T7Pr04(2l$ZuK3H@7)>alup z3G?o$l!-MPygwcmS^v-YLE5L;DJ-Vt?^WksJU98R{{B0me;;37e0Tl6s{G>g-_Py; z|MaU}k=uH$dEV~o|B359SQS5FTGD^jyqmW`a>1X){$@Gns~y(rXDs@)xA}2y@W0&` z-%#G9*SJSKgOm*&0w-nXCcSdIkae39QFXNByQ zFBdwmzJJ+3Q&a8uQ?u}tKWAh%2mK0lcUk_%Y)kC%JQ4of(EFRNMy4qG6Y2fhivyMFMv zoT#)}dhBR~P06WaPk)6!ERHl3`{eVqg)CXNSzKtcccew(%iLXR(eVa%Z)d&w)@Lc(%kCb1 z->ObrcE7~zgHJB!&ETo|bn$t-3fr2yfe#j0y=^u$lT&%ZwP()dhdb4MRvvLKs5O2U z-*Nly_xHiYyQv$tu6V^%b5u9}{9|pq;;CnQlhr1!Sg*A3loiuKrY);FP|M1A%9~%SF0J)w zT={Rs%~JM<&!)0&HeMd+#J^bBWzCLAug8ClUw#OY{r;==s;*4Gc-L9ST0_0*i@5Bs z7JhM9eO~m@i=Nkewc_{f4)~sJ{cq>x2tB>Kx4zX^oKE>~U+*1r=(Vb~`}y)uuDdsU zkd!rQD7<|2w_kz4jgIs2LTp|4a*kU6{JvvTbo{oxXG*g26UC?ZOQ|of@@z2tDVkZp zRyXJ9^wgOz(h5G=Jh1!l{z0XXc!B%L2P>uRq`w_|mu0Z&0J{dyp93>4-Aw)#$H^7^ zeD1r=#@(?(OQn8_*l3@taKFTO^v3qNJJTJ#V)om6blnye>E3Ou>RQYswpG;Id!vi_ zk-M{H*SqeVtNh}y0aM)FKz5VLOQk#apPTGErT=K<@=0q~CZ9OgBED1j;X{QthF|*3 zi`1^@zuVK{`}pv2maB4vjOyKm^UaDDc}-$24=In}?$KPgr)kacbMw_- zx-LB3bTj0@xdWR#7jiCrG&Rj3nj`SGaHQ_v1IxJn_vkg=TR*MDS5-eofaT+zqRmF( z#x`xgW-q93&i=l!wb6p_bj#t*JbW)czsy*qU-zP~i2rc+37^8H6`}8fwq1S8^r(-? zTmACQPhpiyD-z<8=f%6LFY>w9vGVh+?p^t}es8^Q^U|e!+xN-SpZ{1B>v-{6XE;|z zAybaE{)SqsTPwxqc4!v7zLR?TMyIh!_QlgXm}_=?zao44V8QZ=RsU|ade2-Mol-90 z!ewEnl|5JaThFQ1T@KfpF1(D(dA}lLbLi!@f=}Yk38bp;F_+ghEfvftDdJl8Ic&$i z&;wtz_bT*liu!91E~6eTUl$Qpf6qdb{p+za5;NpApL>4^=}~8}Sqs!|x!KY0{z=S1=GDzTrge3Xm`eG&Ouw(6 zd~*7Im4`dhE*;(eJU(pG-h&@*-nz$EzRfHxt=yMa@5rasv$$U`O5(O+Kjwc~c;WKR zN_7*(e778($;-8L-GzC-Cd}abDR0Z;miY9<#n!e*`rM+r+c*E{i+`q7c&jHtWZ#*y z2P^Wk1lZ)R+H6_>!)rqGOYUrU!K9PDkLMKz-aX13w3yW+V5Mn0qrF6qbM>QgUgslD zEC2jn-~9gcQud6utWRI`h%eq7ET=9f`nNg!X{-9<&(phe=O2wySzh^~meYN|&YLxt zlNAnZuoBX@T(t1go?o{n*oE&<-hEE=UBIiLLwjdj->mdc`D=)(k>#siH|}tuVx?4$ zg}JZiJ!ATKdREep)D@{oN%K`XoxiWXeDA{BcJ(JpJ7?@$CBl38_B=25xD(&p9($ft zP)t90Y^VD>tM77lH6IGhmmhDhc9^ti>9=YI=EqNdJ}8-SUnlgAvFWY1CYLv}8-KdI zk=I*iz01XOYwYg+O5MupZ&eYUv$(cte#y2;{Pz{-=1YGSpTA&@V3yPJbJrFz7F1o5 z<=@qqy8g(iw>dw1%W>z{u4Q+$3b#0|%u@ek+x}uR`Chc_%0Rt31zA zKjHG^C+_8SRq6jfHnSI=e)zBXyqs%fef`A_kH$k^cJ+63UzFHqYf*UIe%J5Es>0?j z>_3a<{IbcOtrw#*TQ8PXi598eEL|ubr@L2*EhXaRVFNkg zCXRPXcaGi^<(LsC&U9+4aDZQic;D_jCbw+QIjgvG&Er|Hs_0aag+$F<;rt4bu%Kt> zbK^4}Metq`;WzqHy=%`7;kbyrXK&lZ^ZNNtXQnRse)#g^#|sudi`tgpWchpBoXuAa z0;bP(Ja_%Z&qoiJf4vZtuHSoJav`^MsOjf^_TzUqTopSxdw#g*6gi%52jy+sn9VKE z2Xz`4ZLXapKJ#XThJKitir8_DncOa$7GyLpx$^dNQn;zzj_7TBGrVV9Zn?YWMWay0 z0wvSxMy`iF)%Rvt&D1K|!R1u@*-b!eU&z<${bh@vT;45TU-i7bU+BeV{isQw}JF;OaMr_P;8>=!fxmrLAS?7}#!_e$`LOy-2Cr`K8DD_OSD zJn77IzwhCmr@avT`#vdPc2>Rk-g3p@ zJPF51%NMN95%zU!*QyX}`pepTV*9et6O%f(rnM-)mbo;Ow{i1Yl_TkH2EJR2?k(wv zUekKni>WMA`qQz9tcvGfC;VQtC2qqK`;RWavTn|qxoeJl(EQ^o?-kAsPi)-Be@uJ| zXY=0`<}!S3omPC^If)O8Lu9|DD_=3$5E%G9?)lZ3dm|=v%`54eKU?_a?1Rh8-?MXY z@%ttHKa&{7QT%)N`*%LCG7ha#tMhq~os=HeHq+euo!a^5?l0?0Uux-@dFdT4w+K|qh zaK9}lX6@hjf{K~J4V&NA_k5W1_k5?o+Q0wXZu~C}tNC>Fu>bkZVe1!vt+QLBYv!B2 z``@iMm$nL)rH0r#zdaXNd2LyZ@XMGl8$0g>ySJ^}^>y`ngPuPFc9q<+cVeLP>zqrUFK&ISG3O3X z|6Jn@-Kood8HIj*^wp#(u6vI8+Bv@7b2fThIrViyt2<`?szCqeh?K z8x(W`PyXv&q|Z>8?xMBpM?_XfX!Yl_HzR+q-^8`uMEHZue}ByvIsfb#)e^G*$IAbH zzgfSI>DPHJH}C_BgUZtv!g3#HF>MG1d>tzNw9chJ{;=dT)9I`3_(sAPY0 zKX;Q@-kIsE_W%B5qrBNhTW3YW(KY6)Y20w3)kX*goW=p81;q=tsGA(NbcE0kr>Rz+?_>rtt$q%)ae?PqSqhw0) zyfgYL*U$HcO30SY`Sak*jccNzrfMc1%-VkQJ$LNB`7pzE)`FO>d)257I zo?U$(kd_s<;AQq|ap$E|?@xVy^>yUesz?o)8*BI2{kfB|CHPhN=7P#^LTlrz-Y2XG z`TsI-`huI6u134gxj5mo=nt7~+UDMEK0#mOoWk?%&a%gzIbEHZYFk;lT#SFceVL(y z>ym#DO17|VD0C5hBuJN855I|CoMkzs|p>AJ=!(r~a9JY`^56rynEb z=A#j!8~1cPb=A>NsuVok9kEX<`{7Newr#7+53S$wjXQ;X*~Ns%wr7`SFYfswX;o%o z>mT{kZm*o%xq$l1OBD{~eCqYz*Ll+1QhQ#dYx?P&!pzxc;*W$+eJgdy=cc0ci3+yL zSFzKlXT;y^c*U{0>zbBZ1Z|%6#b+D2S2n3iofFrR ze7OHkx%Sld~;K;{aQ0+M@88Oj<&dxnH3iw#Fsx!c>mnJ`?tZ) zHLp+1oF~3ef4Aqw>#q!7Je#%3QEyr5@n*;UZD&gFukx3(|5x*WvH$z~zjfN&Us{*$ zkx!O9%wov2uUSl1c4e~lE&j{(1py5?>El zo_$r9p}(g5+u>R97hbC?yi}ClD7PxvfWJ@VOkKP9%LipER^%A^+)}%^RQtN#n`L6s zp|u~J__7vq&fRoUn0-t4yHI9MrmcEE=5Z}w71OfK?6X0@6B$0IwO19T&Na5LQuo{J zt78-2`sT`u_{6G*64FPP9Qt)|Lpej(k7`!Q^uB`Qj3Ry8Smz&=pR(oL{F^K7FMawI z6SrNj>h;$D#b*s}{XAFn_P_C;|IhX(A7lCJcPRSz|F0kSXGyJ@``^jy;-~+&KK#F7 zY5mGB-2HFpng4=~2jd>wI|gm}w?F&m8QCh1n0IZi?uMpDe)HN_Z}nkUJQBNOhq12x z*^aBc?US0$ylLNk+Hc`at+%E9|Ffh{iT2d@r2pB^v24lL|5dh+_sh64E&Fcqoy|7;mwx!nnxa3!J(1S`@}K?Cf07cvp|*HM+o_(r z1@%SeBSzwOue`LfBNQ!`i$)#|L48iwVB|GWABbNRnZ^M5qk|KQ&Kzy1Cu`#*>6 z|5yL$|9>UkxBl1rKOf)!-@O0-_J33VKe}H3C;Z1-?{&YQgx7xh zv%UWB`hUI8|KETA-~Ru#{Vx0dEWZCwxc+VaKlA!mfA|01{{O-Gzs+m^zk2_#y8hex zzwh^de(?T(Z~Xs@|MuVhyZ`^?`<36O|9}4f&-?$s{~!DR`)d8q^?$e5zwZC{`Yiw3 z`FH-F|Mz3A{D0&6XZm0Le!u_wa{oX1ys+IL_rI-sUjFZR|Jm}qt;)Zy9;^3|H;Y>T zUw>i7w?F2>Gqyagm!04J^S@cuhkp<5rQ7Sy{ZVW_Z(*C2*113PZ7M!I-j$rMZyB<9 z#^Sthb6zjWd7I(5V#Bmsd6N=y=FC4j+s3R=iRs~7wf~pT@wct>;f-iHcS8T2n!lNS zeZ~97zwPhe3b4}&y5fB_d*Ow}$IIpFKW3~h@atOVS-Cr@TJ883wUx5VV{fk7zVhFf z3yhk4-7C6(@~5Yt5^>kqwePyVb9dfx!RR|3d?~@+wNB5JuHKsBch$IAzUG7D$4j>^ zc2+bjbbEg*Sz5eM=CxnuzS%kZW^|o6J@=D|$GvU6FL#@BIUU~G#9`cd|Fhd%x%dDc zHP+cIiBYF-E;5MLi@SU8mW15YW`&ryJpGd-+*zY0Sv#v2sPeD@44rh&b#bR-rSU;Ca-#Tq5X27lV9c>N%fglRW)Jrt}j)ep6y-vYyX6f zrECl~{{M{)v;P-gd-i`v*suL{O0^-jFRxk4@lTSmsqt@GU0@bPY)LS1mj{Ee>~l@vdmWw~G8yt}euv)c1d?>_Qe@_(7 zXh^ykcK3!}-obu#pZ^v4g2KKJlbh$1O3sY2YhEcGx{E0?e(s{@CvsN&OL*a@mYiEJ z^!)ppw0RR}{Qgq$;+J7n%m$^;JhPS`-}pRLg%BzNd%xASUSii92F3(PxJ8k8q zEjxB4v!`wG3fh$=Eyi;sEBaHT>^*tcTVi)L?>(w3UFCG?(K~a)Iyb$YyK|=RtNF|% zasJhRo70bq#2L;z!;(VOOr#4qW@@uJ@oRziz<)0ycr#;V|HR1gR zbG=TMSEUwOXEr@mpRN1)%>AwWyz@Fc4P}G%%e6Su#hYS*WU1Ph^79EprNvCUD&cG z(h9DMEmvP$*>bgD^|Sxes*`g4qywv%a?i5-n=3Md<^B7fdHu)Utq`7j^qF>tUVG&- zT?xM5g%($S1$C~IPg2f)aiZqk>Z+_&fzh4`(LY`^xy(e#7(^u=a zS#2|u`uioRti8?m(y7ZEPb9hP?6|q|L0oSCo;_wypT9Xer}658|I69gA99-{?pOvSyU!q{7X9J=vul&pk4L9}TXy?MYir_>&pHyu zH+77*6(;Un{Y+ZZJ;~Ya{ERglc8Oc)*MDzHm3*`5$=q_MIp+$Uwq0}BYBS|m<-}(0 zrlV$gIW}#Luh|v3@)_1ndhaP1Yf<^BJK|*+#{v1{JFJR!2Rv@M;JI|8v~>TRZpm}c zR5jzJYCd(>1YG~QXY1aLh4+vDI$ij$ra)?OX6woef%zhbgzEV-KG;~=T1q@CEZ5GA zVzPAFap9f&Nv7+wo;)eh`<`gKJ#n!|jgdvs#QQ(9KkIZI4mMuL-xs51m6~^KW&h`z z$I1UReU6;=sWz^Bto18D z=-uj8o2Ut?4=1&G*%n@yxI5smc;z1P*0Mhd1#w*+$DVJIGP5&ZKB0?cEBB|^rv_WA z`Fu=+QyL5MV)h)A7GHj{=XUCqI`gJ~y|*5V{w%Ca-7U6E#5X+j*4v_U|uy$MVlIFu8b#;OFSq z2T$bs7{#t{f3J9cmbKg*IT^LAih?SZXE!vSF|L}p=%UfwneB&d>guHGwym_kI_0aT zLP%)lqY8ndKzaN4XlCWKN0CqVL?pYnH>Z2nTKWb({-N5^j90V zv7PeC(+@o`?dpnD?yHw>m4-U5l9|4zNyB&Ez8wa>ayPU3AK!iO^}j;6H}Ajyb5|d! zUp{HF*}vbfAJ_lbZT7F&>-qP37wP{`zrOk3!*@8&?^0=^yGjcCy~8efb9mUv3oH=-&t-=#gRAf{+Gwz7ExBvgm zyVdsd^#%2(r`lC-SP)W}{Apcv|Gpnz3J<@2^mWsfz31PZ6L0K(`giyDx(`SBpL-uU zec|Igf38n^DpnUgSDo1hWGhBv-pra5$W0kE2mq}*6(85^M{q!Y9oL+`?zu{vG{>#qVSD|jiaqaSN`HUUt=39n zj>Sg)vp$fX@ag*0>CBfGCcfVjtX`lPQot@1b7j)-$!vh>=Q44;6Kq}%R2AL zv!s8Q7F~%`zsZyT@=%bks$dhUE*C(gC+ z_om<}GxlTzJ$PH5?EA4!LcUVmE_ma^Z{WxLA=Dj}#TkPt1_M@nQ94#~h#*>M*j4pMY6YV{<-V-^kCl42RsLS7OE_o&$j26)wGhoF}*q(G1)hn z794#l&{@yqIGO*M$Vs=!`%We1|C+RYa=+86^H0902qPnUa(2`dmt5LE^VqpBE1jBt1Sm@~8A@C2 zobY$SglE=wZ6&6M{CqWuj`{SuUqt`j z?ByAg_MAz!JKGg-u&Ku7plC*(_5S^D{;YrWRg^hkt>V9amlC~y{Zrol{J*t^>%5)8 zM@ROvySE(O8F~2QKYh8ns1&Pt`y)Mz_FU)G+v025vi;8gH|>V23l|1kneKmZNN!Gk zkmSN`X7;CEueaM@{%rH*^i}H)R2OzdwaLBo2@0Pc{N(N*f1U>6{jK}w1|2W4le7BX z>|So|nek)oW*1H zJk)Zxb#n4M)@kV<>^4p2o`3guT~19 zpSUgFkEENv-dZ_h?a$MW3)Cym^zW0~y?CJLHnrHid@77;{$LVJ)9`%{g``d=+$EAZSdFFJU51(GDHt)#h)!YZKyws_)(D|uTW46vm zr^aN>**9m|e0#o%9JVy5eIkBDZPvO8WvkAI-V#_l(T3+zuFk8eQp1rkl){PZ2C);d&)(~-gM#4_F zpGIMy%D$&A{9brv7HdWOqUu70o=Gu!Tm_yVj+MNdA1=KmPt!Jae{*oVmX+V3-Xx~z zoxx{TyiQ#$JF9A;&&mngSLAJflhY0E$2?_bQD5kc0cd%akldG=Z%DYWlCu*CX z`)+;tYUA`)zjr-l#fGoeTMOG16&q(v4kJlM4)Ic`To}Bel6qeetR#3H#!9NKbow!schz`m@m? z(zjCgPQE&QdwRg+|;C~{Nay^o4*QbqOaHY`ISxk+o%1b-r&x! z`aNd<^5q+1%L{BIc9qWg->Y~a{rdkEIiKs-JpG*4{aN>4__6wj_x4@kV0eD?zkAWO z|J})Yw?F=m`m=x5Oo>*RO861mqi|2oZUS}5;(Xa2qFA20qjpFgle zcl8^ev-gb3_S}7yb99c1f$oeQrvA(CR$l%5Jm~Sx<9}kJo}XKM-oCcrd)$^2_w{Y& zZ+n*h;qqsh^mzsMY69Q;#mv#2v*F>=(D$!jIxjRmn|p@eFt0WB=SFVryGJ``*f^b2 zStBK4Yjf4G$m`3-br;N6yf~TY@w$nC4-54?jA+ gOLajb+gq89f49v4cDXL^-ShwKH#E8h85(#P0P8{AyZ`_I literal 76466 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

rzYC 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 z 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 H6+8?82(pr0 diff --git a/testing/make-archives b/testing/make-archives index cec9a9ff..8ec05e2d 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -17,7 +17,7 @@ from typing import Sequence REPOS = ( ('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'), - ('ruby-build', 'https://github.com/rbenv/ruby-build', '9d92a69'), + ('ruby-build', 'https://github.com/rbenv/ruby-build', '855b963'), ( 'ruby-download', 'https://github.com/garnieretienne/rvm-download', From 6f941298a44b55e2dbc88f711c8916251636acc2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 03:20:55 +0000 Subject: [PATCH 244/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.3.1 → v3.3.2](https://github.com/asottile/pyupgrade/compare/v3.3.1...v3.3.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47d2630a..ffd30587 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.3.2 hooks: - id: pyupgrade args: [--py38-plus] From 4727922b9316703d97fb12319f9f459c47f88cc5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 29 Apr 2023 13:29:00 -0400 Subject: [PATCH 245/416] use blobless clone for faster autoupdate --- pre_commit/commands/autoupdate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 7ed6e776..a43d7dd9 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -50,7 +50,12 @@ class RevInfo(NamedTuple): with tempfile.TemporaryDirectory() as tmp: git.init_repo(tmp, self.repo) cmd_output_b( - *git_cmd, 'fetch', 'origin', 'HEAD', '--tags', + *git_cmd, 'config', 'extensions.partialClone', 'true', + cwd=tmp, + ) + cmd_output_b( + *git_cmd, 'fetch', 'origin', 'HEAD', + '--quiet', '--filter=blob:none', '--tags', cwd=tmp, ) From e885f2e76ed09c178a7e16a235b76ee4f6e765f6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 29 Apr 2023 15:11:14 -0400 Subject: [PATCH 246/416] use -C for git commands in autoupdate --- pre_commit/commands/autoupdate.py | 37 +++++++++++-------------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index a43d7dd9..347599f6 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -34,44 +34,33 @@ class RevInfo(NamedTuple): return cls(config['repo'], config['rev'], None) def update(self, tags_only: bool, freeze: bool) -> RevInfo: - git_cmd = ('git', *git.NO_FS_MONITOR) - - if tags_only: - tag_cmd = ( - *git_cmd, 'describe', - 'FETCH_HEAD', '--tags', '--abbrev=0', - ) - else: - tag_cmd = ( - *git_cmd, 'describe', - 'FETCH_HEAD', '--tags', '--exact', - ) - with tempfile.TemporaryDirectory() as tmp: + _git = ('git', *git.NO_FS_MONITOR, '-C', tmp) + + if tags_only: + tag_opt = '--abbrev=0' + else: + tag_opt = '--exact' + tag_cmd = (*_git, 'describe', 'FETCH_HEAD', '--tags', tag_opt) + git.init_repo(tmp, self.repo) + cmd_output_b(*_git, 'config', 'extensions.partialClone', 'true') cmd_output_b( - *git_cmd, 'config', 'extensions.partialClone', 'true', - cwd=tmp, - ) - cmd_output_b( - *git_cmd, 'fetch', 'origin', 'HEAD', + *_git, 'fetch', 'origin', 'HEAD', '--quiet', '--filter=blob:none', '--tags', - cwd=tmp, ) try: - rev = cmd_output(*tag_cmd, cwd=tmp)[1].strip() + rev = cmd_output(*tag_cmd)[1].strip() except CalledProcessError: - cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD') - rev = cmd_output(*cmd, cwd=tmp)[1].strip() + rev = cmd_output(*_git, 'rev-parse', 'FETCH_HEAD')[1].strip() else: if tags_only: rev = git.get_best_candidate_tag(rev, tmp) frozen = None if freeze: - exact_rev_cmd = (*git_cmd, 'rev-parse', rev) - exact = cmd_output(*exact_rev_cmd, cwd=tmp)[1].strip() + exact = cmd_output(*_git, 'rev-parse', rev)[1].strip() if exact != rev: rev, frozen = exact, rev return self._replace(rev=rev, frozen=frozen) From 4f045cbc21fd3113c50fc9592666908692b1d24e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 29 Apr 2023 15:19:20 -0400 Subject: [PATCH 247/416] perform autoupdate without Store contention --- pre_commit/commands/autoupdate.py | 34 ++++++----- pre_commit/main.py | 2 +- tests/commands/autoupdate_test.py | 96 +++++++++++++++---------------- tests/commands/gc_test.py | 5 +- 4 files changed, 71 insertions(+), 66 deletions(-) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 347599f6..71e5c99b 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -16,7 +16,6 @@ from pre_commit.clientlib import load_manifest from pre_commit.clientlib import LOCAL from pre_commit.clientlib import META from pre_commit.commands.migrate_config import migrate_config -from pre_commit.store import Store from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b @@ -27,11 +26,12 @@ from pre_commit.yaml import yaml_load class RevInfo(NamedTuple): repo: str rev: str - frozen: str | None + frozen: str | None = None + hook_ids: frozenset[str] = frozenset() @classmethod def from_config(cls, config: dict[str, Any]) -> RevInfo: - return cls(config['repo'], config['rev'], None) + return cls(config['repo'], config['rev']) def update(self, tags_only: bool, freeze: bool) -> RevInfo: with tempfile.TemporaryDirectory() as tmp: @@ -63,7 +63,19 @@ class RevInfo(NamedTuple): exact = cmd_output(*_git, 'rev-parse', rev)[1].strip() if exact != rev: rev, frozen = exact, rev - return self._replace(rev=rev, frozen=frozen) + + try: + cmd_output(*_git, 'checkout', rev, '--', C.MANIFEST_FILE) + except CalledProcessError: + pass # this will be caught by manifest validating code + try: + manifest = load_manifest(os.path.join(tmp, C.MANIFEST_FILE)) + except InvalidManifestError as e: + raise RepositoryCannotBeUpdatedError(str(e)) + else: + hook_ids = frozenset(hook['id'] for hook in manifest) + + return self._replace(rev=rev, frozen=frozen, hook_ids=hook_ids) class RepositoryCannotBeUpdatedError(RuntimeError): @@ -73,17 +85,10 @@ class RepositoryCannotBeUpdatedError(RuntimeError): def _check_hooks_still_exist_at_rev( repo_config: dict[str, Any], info: RevInfo, - store: Store, ) -> None: - try: - path = store.clone(repo_config['repo'], info.rev) - manifest = load_manifest(os.path.join(path, C.MANIFEST_FILE)) - except InvalidManifestError as e: - raise RepositoryCannotBeUpdatedError(str(e)) - # See if any of our hooks were deleted with the new commits hooks = {hook['id'] for hook in repo_config['hooks']} - hooks_missing = hooks - {hook['id'] for hook in manifest} + hooks_missing = hooks - info.hook_ids if hooks_missing: raise RepositoryCannotBeUpdatedError( f'Cannot update because the update target is missing these ' @@ -139,7 +144,6 @@ def _write_new_config(path: str, rev_infos: list[RevInfo | None]) -> None: def autoupdate( config_file: str, - store: Store, tags_only: bool, freeze: bool, repos: Sequence[str] = (), @@ -161,9 +165,9 @@ def autoupdate( continue output.write(f'Updating {info.repo} ... ') - new_info = info.update(tags_only=tags_only, freeze=freeze) try: - _check_hooks_still_exist_at_rev(repo_config, new_info, store) + new_info = info.update(tags_only=tags_only, freeze=freeze) + _check_hooks_still_exist_at_rev(repo_config, new_info) except RepositoryCannotBeUpdatedError as error: output.write_line(error.args[0]) rev_infos.append(None) diff --git a/pre_commit/main.py b/pre_commit/main.py index 9615c5e1..402bc2e5 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -368,7 +368,7 @@ def main(argv: Sequence[str] | None = None) -> int: if args.command == 'autoupdate': return autoupdate( - args.config, store, + args.config, tags_only=not args.bleeding_edge, freeze=args.freeze, repos=args.repos, diff --git a/tests/commands/autoupdate_test.py b/tests/commands/autoupdate_test.py index 4bcb5d82..71bd0444 100644 --- a/tests/commands/autoupdate_test.py +++ b/tests/commands/autoupdate_test.py @@ -67,7 +67,7 @@ def test_rev_info_from_config(): def test_rev_info_update_up_to_date_repo(up_to_date): config = make_config_from_repo(up_to_date) - info = RevInfo.from_config(config) + info = RevInfo.from_config(config)._replace(hook_ids=frozenset(('foo',))) new_info = info.update(tags_only=False, freeze=False) assert info == new_info @@ -139,7 +139,7 @@ def test_rev_info_update_does_not_freeze_if_already_sha(out_of_date): assert new_info.frozen is None -def test_autoupdate_up_to_date_repo(up_to_date, tmpdir, store): +def test_autoupdate_up_to_date_repo(up_to_date, tmpdir): contents = ( f'repos:\n' f'- repo: {up_to_date}\n' @@ -150,11 +150,11 @@ def test_autoupdate_up_to_date_repo(up_to_date, tmpdir, store): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(contents) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 assert cfg.read() == contents -def test_autoupdate_old_revision_broken(tempdir_factory, in_tmpdir, store): +def test_autoupdate_old_revision_broken(tempdir_factory, in_tmpdir): """In $FUTURE_VERSION, hooks.yaml will no longer be supported. This asserts that when that day comes, pre-commit will be able to autoupdate despite not being able to read hooks.yaml in that repository. @@ -174,14 +174,14 @@ def test_autoupdate_old_revision_broken(tempdir_factory, in_tmpdir, store): write_config('.', config) with open(C.CONFIG_FILE) as f: before = f.read() - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) == 0 with open(C.CONFIG_FILE) as f: after = f.read() assert before != after assert update_rev in after -def test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store): +def test_autoupdate_out_of_date_repo(out_of_date, tmpdir): fmt = ( 'repos:\n' '- repo: {}\n' @@ -192,24 +192,24 @@ def test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(fmt.format(out_of_date.path, out_of_date.original_rev)) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 assert cfg.read() == fmt.format(out_of_date.path, out_of_date.head_rev) -def test_autoupdate_with_core_useBuiltinFSMonitor(out_of_date, tmpdir, store): +def test_autoupdate_with_core_useBuiltinFSMonitor(out_of_date, tmpdir): # force the setting on "globally" for git home = tmpdir.join('fakehome').ensure_dir() home.join('.gitconfig').write('[core]\nuseBuiltinFSMonitor = true\n') with envcontext.envcontext((('HOME', str(home)),)): - test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store) + test_autoupdate_out_of_date_repo(out_of_date, tmpdir) -def test_autoupdate_pure_yaml(out_of_date, tmpdir, store): +def test_autoupdate_pure_yaml(out_of_date, tmpdir): with mock.patch.object(yaml, 'Dumper', yaml.yaml.SafeDumper): - test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store) + test_autoupdate_out_of_date_repo(out_of_date, tmpdir) -def test_autoupdate_only_one_to_update(up_to_date, out_of_date, tmpdir, store): +def test_autoupdate_only_one_to_update(up_to_date, out_of_date, tmpdir): fmt = ( 'repos:\n' '- repo: {}\n' @@ -228,7 +228,7 @@ def test_autoupdate_only_one_to_update(up_to_date, out_of_date, tmpdir, store): ) cfg.write(before) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 assert cfg.read() == fmt.format( up_to_date, git.head_rev(up_to_date), out_of_date.path, out_of_date.head_rev, @@ -236,7 +236,7 @@ def test_autoupdate_only_one_to_update(up_to_date, out_of_date, tmpdir, store): def test_autoupdate_out_of_date_repo_with_correct_repo_name( - out_of_date, in_tmpdir, store, + out_of_date, in_tmpdir, ): stale_config = make_config_from_repo( out_of_date.path, rev=out_of_date.original_rev, check=False, @@ -249,7 +249,7 @@ def test_autoupdate_out_of_date_repo_with_correct_repo_name( before = f.read() repo_name = f'file://{out_of_date.path}' ret = autoupdate( - C.CONFIG_FILE, store, freeze=False, tags_only=False, + C.CONFIG_FILE, freeze=False, tags_only=False, repos=(repo_name,), ) with open(C.CONFIG_FILE) as f: @@ -261,7 +261,7 @@ def test_autoupdate_out_of_date_repo_with_correct_repo_name( def test_autoupdate_out_of_date_repo_with_wrong_repo_name( - out_of_date, in_tmpdir, store, + out_of_date, in_tmpdir, ): config = make_config_from_repo( out_of_date.path, rev=out_of_date.original_rev, check=False, @@ -272,7 +272,7 @@ def test_autoupdate_out_of_date_repo_with_wrong_repo_name( before = f.read() # It will not update it, because the name doesn't match ret = autoupdate( - C.CONFIG_FILE, store, freeze=False, tags_only=False, + C.CONFIG_FILE, freeze=False, tags_only=False, repos=('dne',), ) with open(C.CONFIG_FILE) as f: @@ -281,7 +281,7 @@ def test_autoupdate_out_of_date_repo_with_wrong_repo_name( assert before == after -def test_does_not_reformat(tmpdir, out_of_date, store): +def test_does_not_reformat(tmpdir, out_of_date): fmt = ( 'repos:\n' '- repo: {}\n' @@ -294,12 +294,12 @@ def test_does_not_reformat(tmpdir, out_of_date, store): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(fmt.format(out_of_date.path, out_of_date.original_rev)) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 expected = fmt.format(out_of_date.path, out_of_date.head_rev) assert cfg.read() == expected -def test_does_not_change_mixed_endlines_read(up_to_date, tmpdir, store): +def test_does_not_change_mixed_endlines_read(up_to_date, tmpdir): fmt = ( 'repos:\n' '- repo: {}\n' @@ -314,11 +314,11 @@ def test_does_not_change_mixed_endlines_read(up_to_date, tmpdir, store): expected = fmt.format(up_to_date, git.head_rev(up_to_date)).encode() cfg.write_binary(expected) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 assert cfg.read_binary() == expected -def test_does_not_change_mixed_endlines_write(tmpdir, out_of_date, store): +def test_does_not_change_mixed_endlines_write(tmpdir, out_of_date): fmt = ( 'repos:\n' '- repo: {}\n' @@ -333,12 +333,12 @@ def test_does_not_change_mixed_endlines_write(tmpdir, out_of_date, store): fmt.format(out_of_date.path, out_of_date.original_rev).encode(), ) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 expected = fmt.format(out_of_date.path, out_of_date.head_rev).encode() assert cfg.read_binary() == expected -def test_loses_formatting_when_not_detectable(out_of_date, store, tmpdir): +def test_loses_formatting_when_not_detectable(out_of_date, tmpdir): """A best-effort attempt is made at updating rev without rewriting formatting. When the original formatting cannot be detected, this is abandoned. @@ -359,7 +359,7 @@ def test_loses_formatting_when_not_detectable(out_of_date, store, tmpdir): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(config) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 expected = ( f'repos:\n' f'- repo: {out_of_date.path}\n' @@ -370,43 +370,43 @@ def test_loses_formatting_when_not_detectable(out_of_date, store, tmpdir): assert cfg.read() == expected -def test_autoupdate_tagged_repo(tagged, in_tmpdir, store): +def test_autoupdate_tagged_repo(tagged, in_tmpdir): config = make_config_from_repo(tagged.path, rev=tagged.original_rev) write_config('.', config) - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) == 0 with open(C.CONFIG_FILE) as f: assert 'v1.2.3' in f.read() -def test_autoupdate_freeze(tagged, in_tmpdir, store): +def test_autoupdate_freeze(tagged, in_tmpdir): config = make_config_from_repo(tagged.path, rev=tagged.original_rev) write_config('.', config) - assert autoupdate(C.CONFIG_FILE, store, freeze=True, tags_only=False) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=True, tags_only=False) == 0 with open(C.CONFIG_FILE) as f: expected = f'rev: {tagged.head_rev} # frozen: v1.2.3' assert expected in f.read() # if we un-freeze it should remove the frozen comment - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) == 0 with open(C.CONFIG_FILE) as f: assert 'rev: v1.2.3\n' in f.read() -def test_autoupdate_tags_only(tagged, in_tmpdir, store): +def test_autoupdate_tags_only(tagged, in_tmpdir): # add some commits after the tag git_commit(cwd=tagged.path) config = make_config_from_repo(tagged.path, rev=tagged.original_rev) write_config('.', config) - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=True) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=True) == 0 with open(C.CONFIG_FILE) as f: assert 'v1.2.3' in f.read() -def test_autoupdate_latest_no_config(out_of_date, in_tmpdir, store): +def test_autoupdate_latest_no_config(out_of_date, in_tmpdir): config = make_config_from_repo( out_of_date.path, rev=out_of_date.original_rev, ) @@ -415,12 +415,12 @@ def test_autoupdate_latest_no_config(out_of_date, in_tmpdir, store): cmd_output('git', 'rm', '-r', ':/', cwd=out_of_date.path) git_commit(cwd=out_of_date.path) - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 1 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) == 1 with open(C.CONFIG_FILE) as f: assert out_of_date.original_rev in f.read() -def test_hook_disppearing_repo_raises(hook_disappearing, store): +def test_hook_disppearing_repo_raises(hook_disappearing): config = make_config_from_repo( hook_disappearing.path, rev=hook_disappearing.original_rev, @@ -428,10 +428,10 @@ def test_hook_disppearing_repo_raises(hook_disappearing, store): ) info = RevInfo.from_config(config).update(tags_only=False, freeze=False) with pytest.raises(RepositoryCannotBeUpdatedError): - _check_hooks_still_exist_at_rev(config, info, store) + _check_hooks_still_exist_at_rev(config, info) -def test_autoupdate_hook_disappearing_repo(hook_disappearing, tmpdir, store): +def test_autoupdate_hook_disappearing_repo(hook_disappearing, tmpdir): contents = ( f'repos:\n' f'- repo: {hook_disappearing.path}\n' @@ -442,21 +442,21 @@ def test_autoupdate_hook_disappearing_repo(hook_disappearing, tmpdir, store): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(contents) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 1 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 1 assert cfg.read() == contents -def test_autoupdate_local_hooks(in_git_dir, store): +def test_autoupdate_local_hooks(in_git_dir): config = sample_local_config() add_config_to_repo('.', config) - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) == 0 new_config_written = read_config('.') assert len(new_config_written['repos']) == 1 assert new_config_written['repos'][0] == config def test_autoupdate_local_hooks_with_out_of_date_repo( - out_of_date, in_tmpdir, store, + out_of_date, in_tmpdir, ): stale_config = make_config_from_repo( out_of_date.path, rev=out_of_date.original_rev, check=False, @@ -464,13 +464,13 @@ def test_autoupdate_local_hooks_with_out_of_date_repo( local_config = sample_local_config() config = {'repos': [local_config, stale_config]} write_config('.', config) - assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0 + assert autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) == 0 new_config_written = read_config('.') assert len(new_config_written['repos']) == 2 assert new_config_written['repos'][0] == local_config -def test_autoupdate_meta_hooks(tmpdir, store): +def test_autoupdate_meta_hooks(tmpdir): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write( 'repos:\n' @@ -478,7 +478,7 @@ def test_autoupdate_meta_hooks(tmpdir, store): ' hooks:\n' ' - id: check-useless-excludes\n', ) - assert autoupdate(str(cfg), store, freeze=False, tags_only=True) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=True) == 0 assert cfg.read() == ( 'repos:\n' '- repo: meta\n' @@ -487,7 +487,7 @@ def test_autoupdate_meta_hooks(tmpdir, store): ) -def test_updates_old_format_to_new_format(tmpdir, capsys, store): +def test_updates_old_format_to_new_format(tmpdir, capsys): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write( '- repo: local\n' @@ -497,7 +497,7 @@ def test_updates_old_format_to_new_format(tmpdir, capsys, store): ' entry: ./bin/foo.sh\n' ' language: script\n', ) - assert autoupdate(str(cfg), store, freeze=False, tags_only=True) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=True) == 0 contents = cfg.read() assert contents == ( 'repos:\n' @@ -512,7 +512,7 @@ def test_updates_old_format_to_new_format(tmpdir, capsys, store): assert out == 'Configuration has been migrated.\n' -def test_maintains_rev_quoting_style(tmpdir, out_of_date, store): +def test_maintains_rev_quoting_style(tmpdir, out_of_date): fmt = ( 'repos:\n' '- repo: {path}\n' @@ -527,6 +527,6 @@ def test_maintains_rev_quoting_style(tmpdir, out_of_date, store): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(fmt.format(path=out_of_date.path, rev=out_of_date.original_rev)) - assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0 + assert autoupdate(str(cfg), freeze=False, tags_only=False) == 0 expected = fmt.format(path=out_of_date.path, rev=out_of_date.head_rev) assert cfg.read() == expected diff --git a/tests/commands/gc_test.py b/tests/commands/gc_test.py index c128e939..95113ed5 100644 --- a/tests/commands/gc_test.py +++ b/tests/commands/gc_test.py @@ -43,8 +43,9 @@ def test_gc(tempdir_factory, store, in_git_dir, cap_out): store.mark_config_used(C.CONFIG_FILE) # update will clone both the old and new repo, making the old one gc-able - install_hooks(C.CONFIG_FILE, store) - assert not autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) + assert not install_hooks(C.CONFIG_FILE, store) + assert not autoupdate(C.CONFIG_FILE, freeze=False, tags_only=False) + assert not install_hooks(C.CONFIG_FILE, store) assert _config_count(store) == 1 assert _repo_count(store) == 2 From ddbee32ad0722a0bc216bc29ee29a1885454bd78 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 29 Apr 2023 15:05:17 -0400 Subject: [PATCH 248/416] add --jobs option to autoupdate --- pre_commit/commands/autoupdate.py | 90 +++++++++++++++++++------------ pre_commit/lang_base.py | 10 ++-- pre_commit/main.py | 7 ++- pre_commit/xargs.py | 8 +++ 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 71e5c99b..17864810 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -1,5 +1,6 @@ from __future__ import annotations +import concurrent.futures import os.path import re import tempfile @@ -10,6 +11,7 @@ from typing import Sequence import pre_commit.constants as C from pre_commit import git from pre_commit import output +from pre_commit import xargs from pre_commit.clientlib import InvalidManifestError from pre_commit.clientlib import load_config from pre_commit.clientlib import load_manifest @@ -71,7 +73,7 @@ class RevInfo(NamedTuple): try: manifest = load_manifest(os.path.join(tmp, C.MANIFEST_FILE)) except InvalidManifestError as e: - raise RepositoryCannotBeUpdatedError(str(e)) + raise RepositoryCannotBeUpdatedError(f'[{self.repo}] {e}') else: hook_ids = frozenset(hook['id'] for hook in manifest) @@ -91,11 +93,24 @@ def _check_hooks_still_exist_at_rev( hooks_missing = hooks - info.hook_ids if hooks_missing: raise RepositoryCannotBeUpdatedError( - f'Cannot update because the update target is missing these ' - f'hooks:\n{", ".join(sorted(hooks_missing))}', + f'[{info.repo}] Cannot update because the update target is ' + f'missing these hooks: {", ".join(sorted(hooks_missing))}', ) +def _update_one( + i: int, + repo: dict[str, Any], + *, + tags_only: bool, + freeze: bool, +) -> tuple[int, RevInfo, RevInfo]: + old = RevInfo.from_config(repo) + new = old.update(tags_only=tags_only, freeze=freeze) + _check_hooks_still_exist_at_rev(repo, new) + return i, old, new + + REV_LINE_RE = re.compile(r'^(\s+)rev:(\s*)([\'"]?)([^\s#]+)(.*)(\r?\n)$') @@ -147,45 +162,50 @@ def autoupdate( tags_only: bool, freeze: bool, repos: Sequence[str] = (), + jobs: int = 1, ) -> int: """Auto-update the pre-commit config to the latest versions of repos.""" migrate_config(config_file, quiet=True) - retv = 0 - rev_infos: list[RevInfo | None] = [] changed = False + retv = 0 - config = load_config(config_file) - for repo_config in config['repos']: - if repo_config['repo'] in {LOCAL, META}: - continue + config_repos = [ + repo for repo in load_config(config_file)['repos'] + if repo['repo'] not in {LOCAL, META} + ] - info = RevInfo.from_config(repo_config) - if repos and info.repo not in repos: - rev_infos.append(None) - continue - - output.write(f'Updating {info.repo} ... ') - try: - new_info = info.update(tags_only=tags_only, freeze=freeze) - _check_hooks_still_exist_at_rev(repo_config, new_info) - except RepositoryCannotBeUpdatedError as error: - output.write_line(error.args[0]) - rev_infos.append(None) - retv = 1 - continue - - if new_info.rev != info.rev: - changed = True - if new_info.frozen: - updated_to = f'{new_info.frozen} (frozen)' + rev_infos: list[RevInfo | None] = [None] * len(config_repos) + jobs = jobs or xargs.cpu_count() # 0 => number of cpus + jobs = min(jobs, len(repos) or len(config_repos)) # max 1-per-thread + jobs = max(jobs, 1) # at least one thread + with concurrent.futures.ThreadPoolExecutor(jobs) as exe: + futures = [ + exe.submit( + _update_one, + i, repo, tags_only=tags_only, freeze=freeze, + ) + for i, repo in enumerate(config_repos) + if not repos or repo['repo'] in repos + ] + for future in concurrent.futures.as_completed(futures): + try: + i, old, new = future.result() + except RepositoryCannotBeUpdatedError as e: + output.write_line(str(e)) + retv = 1 else: - updated_to = new_info.rev - msg = f'updating {info.rev} -> {updated_to}.' - output.write_line(msg) - rev_infos.append(new_info) - else: - output.write_line('already up to date.') - rev_infos.append(None) + if new.rev != old.rev: + changed = True + if new.frozen: + new_s = f'{new.frozen} (frozen)' + else: + new_s = new.rev + msg = f'updating {old.rev} -> {new_s}' + rev_infos[i] = new + else: + msg = 'already up to date!' + + output.write_line(f'[{old.repo}] {msg}') if changed: _write_new_config(config_file, rev_infos) diff --git a/pre_commit/lang_base.py b/pre_commit/lang_base.py index 9480c559..4a993eaa 100644 --- a/pre_commit/lang_base.py +++ b/pre_commit/lang_base.py @@ -1,7 +1,6 @@ from __future__ import annotations import contextlib -import multiprocessing import os import random import re @@ -15,9 +14,9 @@ from typing import Sequence import pre_commit.constants as C from pre_commit import parse_shebang +from pre_commit import xargs from pre_commit.prefix import Prefix from pre_commit.util import cmd_output_b -from pre_commit.xargs import xargs FIXED_RANDOM_SEED = 1542676187 @@ -140,10 +139,7 @@ def target_concurrency() -> int: if 'TRAVIS' in os.environ: return 2 else: - try: - return multiprocessing.cpu_count() - except NotImplementedError: - return 1 + return xargs.cpu_count() def _shuffled(seq: Sequence[str]) -> list[str]: @@ -171,7 +167,7 @@ def run_xargs( # ordering. file_args = _shuffled(file_args) jobs = target_concurrency() - return xargs(cmd, file_args, target_concurrency=jobs, color=color) + return xargs.xargs(cmd, file_args, target_concurrency=jobs, color=color) def hook_cmd(entry: str, args: Sequence[str]) -> tuple[str, ...]: diff --git a/pre_commit/main.py b/pre_commit/main.py index 402bc2e5..9dfce2c2 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -226,9 +226,13 @@ def main(argv: Sequence[str] | None = None) -> int: help='Store "frozen" hashes in `rev` instead of tag names', ) autoupdate_parser.add_argument( - '--repo', dest='repos', action='append', metavar='REPO', + '--repo', dest='repos', action='append', metavar='REPO', default=[], help='Only update this repository -- may be specified multiple times.', ) + autoupdate_parser.add_argument( + '-j', '--jobs', type=int, default=1, + help='Number of threads to use. (default %(default)s).', + ) _add_cmd('clean', help='Clean out pre-commit files.') @@ -372,6 +376,7 @@ def main(argv: Sequence[str] | None = None) -> int: tags_only=not args.bleeding_edge, freeze=args.freeze, repos=args.repos, + jobs=args.jobs, ) elif args.command == 'clean': return clean(store) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index e3af90ef..31be6f32 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -3,6 +3,7 @@ from __future__ import annotations import concurrent.futures import contextlib import math +import multiprocessing import os import subprocess import sys @@ -22,6 +23,13 @@ TArg = TypeVar('TArg') TRet = TypeVar('TRet') +def cpu_count() -> int: + try: + return multiprocessing.cpu_count() + except NotImplementedError: + return 1 + + def _environ_size(_env: MutableMapping[str, str] | None = None) -> int: environ = _env if _env is not None else getattr(os, 'environb', os.environ) size = 8 * len(environ) # number of pointers in `envp` From 4c0623963f9cd0735829fec265575fdd003a7659 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 1 May 2023 18:22:26 -0400 Subject: [PATCH 249/416] v3.3.0 --- CHANGELOG.md | 12 ++++++++++++ setup.cfg | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efd96c79..57e58ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +3.3.0 - 2023-05-01 +================== + +### Features +- Upgrade ruby-build. + - #2846 PR by @jalessio. +- Use blobless clone for faster autoupdate. + - #2859 PR by @asottile. +- Add `-j` / `--jobs` argument to `autoupdate` for parallel execution. + - #2863 PR by @asottile. + - issue by @gaborbernat. + 3.2.2 - 2023-04-03 ================== diff --git a/setup.cfg b/setup.cfg index 89e8e4ad..8dffb6b7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.2.2 +version = 3.3.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 420a15f87e6f0ec8f9fba0ff284b7e1bd34b9d82 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 2 May 2023 09:54:25 -0400 Subject: [PATCH 250/416] add partial clone hack to fix autoupdate for windows --- pre_commit/commands/autoupdate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 17864810..e7725fdc 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -67,6 +67,8 @@ class RevInfo(NamedTuple): rev, frozen = exact, rev try: + # workaround for windows -- see #2865 + cmd_output_b(*_git, 'show', f'{rev}:{C.MANIFEST_FILE}') cmd_output(*_git, 'checkout', rev, '--', C.MANIFEST_FILE) except CalledProcessError: pass # this will be caught by manifest validating code From 51104fa94a6c3cdf603de2e187284289ea5abcf5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 2 May 2023 10:07:25 -0400 Subject: [PATCH 251/416] v3.3.1 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e58ff2..970b8be1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.3.1 - 2023-05-02 +================== + +### Fixes +- Work around `git` partial clone bug for `autoupdate` on windows. + - #2866 PR by @asottile. + - #2865 issue by @adehad. + 3.3.0 - 2023-05-01 ================== diff --git a/setup.cfg b/setup.cfg index 8dffb6b7..cdd6ec3b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.3.0 +version = 3.3.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 1dd85c904eb76543c80e6506cdfd662fcb889e3b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 04:04:18 +0000 Subject: [PATCH 252/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - https://github.com/asottile/reorder_python_imports → https://github.com/asottile/reorder-python-imports - [github.com/asottile/pyupgrade: v3.3.2 → v3.4.0](https://github.com/asottile/pyupgrade/compare/v3.3.2...v3.4.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ffd30587..d275d244 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: rev: v2.2.0 hooks: - id: setup-cfg-fmt -- repo: https://github.com/asottile/reorder_python_imports +- repo: https://github.com/asottile/reorder-python-imports rev: v3.9.0 hooks: - id: reorder-python-imports @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.3.2 + rev: v3.4.0 hooks: - id: pyupgrade args: [--py38-plus] From 8923fa368a5cb37ed7219a7ce0eafbe2351258b5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 13 May 2023 15:46:34 -0400 Subject: [PATCH 253/416] r does not support language_version currently --- pre_commit/languages/r.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 138a26e1..083329c0 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -93,6 +93,8 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: + lang_base.assert_version_default('r', version) + env_dir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) From 926071b6a7e9f797cab6a089e32cd59065741b1e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 13 May 2023 16:03:14 -0400 Subject: [PATCH 254/416] make some files trigger all languages --- testing/languages | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/testing/languages b/testing/languages index 5e8fc9e4..9abc185f 100755 --- a/testing/languages +++ b/testing/languages @@ -16,6 +16,15 @@ EXCLUDED = frozenset(( )) +def _always_run() -> frozenset[str]: + ret = ['.github/workflows/languages.yml', 'testing/languages'] + ret.extend( + os.path.join('pre_commit/resources', fname) + for fname in os.listdir('pre_commit/resources') + ) + return frozenset(ret) + + def _lang_files(lang: str) -> frozenset[str]: prog = f'''\ import json @@ -47,10 +56,12 @@ def main() -> int: if fname.endswith('.py') and fname != '__init__.py' ] + triggers_all = _always_run() + if not args.all: with concurrent.futures.ThreadPoolExecutor(os.cpu_count()) as exe: by_lang = { - lang: files + lang: files | triggers_all for lang, files in zip(langs, exe.map(_lang_files, langs)) } From 9c2a01186b0b7e3395dfa2744e94a1b860ef716f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 13 May 2023 16:27:14 -0400 Subject: [PATCH 255/416] fix typo in testing/languages --- testing/languages | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testing/languages b/testing/languages index 9abc185f..f4804c7e 100755 --- a/testing/languages +++ b/testing/languages @@ -17,7 +17,7 @@ EXCLUDED = frozenset(( def _always_run() -> frozenset[str]: - ret = ['.github/workflows/languages.yml', 'testing/languages'] + ret = ['.github/workflows/languages.yaml', 'testing/languages'] ret.extend( os.path.join('pre_commit/resources', fname) for fname in os.listdir('pre_commit/resources') @@ -57,6 +57,8 @@ def main() -> int: ] triggers_all = _always_run() + for fname in triggers_all: + assert os.path.exists(fname), fname if not args.all: with concurrent.futures.ThreadPoolExecutor(os.cpu_count()) as exe: From 08b670ff9e32e6c0fca2c5d22180b8b686b3d985 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 13 May 2023 16:24:29 -0400 Subject: [PATCH 256/416] swift is included in github actions --- .github/workflows/languages.yaml | 2 -- testing/get-swift.sh | 29 ----------------------------- 2 files changed, 31 deletions(-) delete mode 100755 testing/get-swift.sh diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 8bc8e712..57a1c0c7 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -63,8 +63,6 @@ jobs: echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" shell: bash if: matrix.os == 'windows-latest' && matrix.language == 'perl' - - run: testing/get-swift.sh - if: matrix.os == 'ubuntu-latest' && matrix.language == 'swift' - name: install deps run: python -mpip install -e . -r requirements-dev.txt diff --git a/testing/get-swift.sh b/testing/get-swift.sh deleted file mode 100755 index dfe09391..00000000 --- a/testing/get-swift.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -# This is a script used in CI to install swift -set -euo pipefail - -. /etc/lsb-release -if [ "$DISTRIB_CODENAME" = "jammy" ]; then - SWIFT_URL='https://download.swift.org/swift-5.7.1-release/ubuntu2204/swift-5.7.1-RELEASE/swift-5.7.1-RELEASE-ubuntu22.04.tar.gz' - SWIFT_HASH='7f60291f5088d3e77b0c2364beaabd29616ee7b37260b7b06bdbeb891a7fe161' -else - echo "unknown dist: ${DISTRIB_CODENAME}" 1>&2 - exit 1 -fi - -check() { - echo "$SWIFT_HASH $TGZ" | sha256sum --check -} - -TGZ="$HOME/.swift/swift.tar.gz" -mkdir -p "$(dirname "$TGZ")" -if ! check >& /dev/null; then - rm -f "$TGZ" - curl --location --silent --output "$TGZ" "$SWIFT_URL" - check -fi - -mkdir -p /tmp/swift -tar -xf "$TGZ" --strip 1 --directory /tmp/swift - -echo '/tmp/swift/usr/bin' >> "$GITHUB_PATH" From 64985bd63d62126dc4efd58af63967ae80121ca2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 03:20:34 +0000 Subject: [PATCH 257/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.2.0 → v1.3.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.2.0...v1.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d275d244..cb03c759 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.2.0 + rev: v1.3.0 hooks: - id: mypy additional_dependencies: [types-all] From cd09c3525e35676af9fa614c04faebe5a88fc9de Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Mon, 15 May 2023 09:26:55 +0200 Subject: [PATCH 258/416] avoid quoting and escaping while installing R hooks by writing code to tempfile instead of execute R code inline --- pre_commit/languages/r.py | 51 +++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 083329c0..6feb0652 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -4,6 +4,8 @@ import contextlib import os import shlex import shutil +import tempfile +import textwrap from typing import Generator from typing import Sequence @@ -21,6 +23,19 @@ get_default_version = lang_base.basic_get_default_version health_check = lang_base.basic_health_check +@contextlib.contextmanager +def _r_code_in_tempfile(code: str) -> Generator[str, None, None]: + """ + To avoid quoting and escaping issues, avoid `Rscript [options] -e {expr}` + but use `Rscript [options] path/to/file_with_expr.R` + """ + with tempfile.TemporaryDirectory() as tmpdir: + fname = os.path.join(tmpdir, 'script.R') + with open(fname, 'w') as f: + f.write(_inline_r_setup(textwrap.dedent(code))) + yield fname + + def get_env_patch(venv: str) -> PatchesT: return ( ('R_PROFILE_USER', os.path.join(venv, 'activate.R')), @@ -129,20 +144,19 @@ def install_environment( }} """ - cmd_output_b( - _rscript_exec(), '--vanilla', '-e', - _inline_r_setup(r_code_inst_environment), - cwd=env_dir, - ) + with _r_code_in_tempfile(r_code_inst_environment) as f: + cmd_output_b(_rscript_exec(), '--vanilla', f, cwd=env_dir) + if additional_dependencies: r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' with in_env(prefix, version): - cmd_output_b( - _rscript_exec(), *RSCRIPT_OPTS, '-e', - _inline_r_setup(r_code_inst_add), - *additional_dependencies, - cwd=env_dir, - ) + with _r_code_in_tempfile(r_code_inst_add) as f: + cmd_output_b( + _rscript_exec(), *RSCRIPT_OPTS, + f, + *additional_dependencies, + cwd=env_dir, + ) def _inline_r_setup(code: str) -> str: @@ -150,11 +164,16 @@ def _inline_r_setup(code: str) -> str: Some behaviour of R cannot be configured via env variables, but can only be configured via R options once R has started. These are set here. """ - with_option = f"""\ - options(install.packages.compile.from.source = "never", pkgType = "binary") - {code} - """ - return with_option + with_option = [ + textwrap.dedent("""\ + options( + install.packages.compile.from.source = "never", + pkgType = "binary" + ) + """), + code, + ] + return '\n'.join(with_option) def run_hook( From a0a734750e1af5a0ec0b2579d3b05f427f53c8b6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 17 May 2023 18:36:52 -0400 Subject: [PATCH 259/416] v3.3.2 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 970b8be1..4256c6aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.3.2 - 2023-05-17 +================== + +### Fixes +- Work around `r` on windows sometimes double-un-quoting arguments. + - #2885 PR by @lorenzwalthert. + - #2870 issue by @lorenzwalthert. + 3.3.1 - 2023-05-02 ================== diff --git a/setup.cfg b/setup.cfg index cdd6ec3b..b2c268ba 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.3.1 +version = 3.3.2 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 18348f5d0dbbfe10b139dbd8f220fe608810fc83 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 17 May 2023 18:55:11 -0400 Subject: [PATCH 260/416] use distlib inside the zipapp docker image --- testing/zipapp/Dockerfile | 4 ++-- testing/zipapp/make | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/testing/zipapp/Dockerfile b/testing/zipapp/Dockerfile index 7c74c1b2..ea967e38 100644 --- a/testing/zipapp/Dockerfile +++ b/testing/zipapp/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:focal +FROM ubuntu:jammy RUN : \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ @@ -11,4 +11,4 @@ RUN : \ ENV LANG=C.UTF-8 PATH=/venv/bin:$PATH RUN : \ && python3 -mvenv /venv \ - && pip install --no-cache-dir pip setuptools wheel no-manylinux --upgrade + && pip install --no-cache-dir pip distlib no-manylinux --upgrade diff --git a/testing/zipapp/make b/testing/zipapp/make index 37b5c355..165046f6 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -4,7 +4,6 @@ from __future__ import annotations import argparse import base64 import hashlib -import importlib.resources import io import os.path import shutil @@ -42,10 +41,17 @@ def _add_shim(dest: str) -> None: with zipfile.ZipFile(bio, 'w') as zipf: zipf.write(shim, arcname='__main__.py') - with open(os.path.join(dest, 'python.exe'), 'wb') as f: - f.write(importlib.resources.read_binary('distlib', 't32.exe')) - f.write(b'#!py.exe -3\n') - f.write(bio.getvalue()) + with tempfile.TemporaryDirectory() as tmpdir: + _exit_if_retv( + 'podman', 'run', '--rm', '--volume', f'{tmpdir}:/out:rw', IMG, + 'cp', '/venv/lib/python3.10/site-packages/distlib/t32.exe', '/out', + ) + + with open(os.path.join(dest, 'python.exe'), 'wb') as f: + with open(os.path.join(tmpdir, 't32.exe'), 'rb') as t32: + f.write(t32.read()) + f.write(b'#!py.exe -3\n') + f.write(bio.getvalue()) def _write_cache_key(version: str, wheeldir: str, dest: str) -> None: From f4a2d52bb46f9d030aad76790035b5a3c12cb1cb Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 1 Jun 2023 19:12:46 -0400 Subject: [PATCH 261/416] fix tags trigger for github actions the old syntax worked for azure pipelines but not GHA Committed via https://github.com/asottile/all-repos --- .github/workflows/languages.yaml | 2 +- .github/workflows/main.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 57a1c0c7..7e97158c 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -3,7 +3,7 @@ name: languages on: push: branches: [main, test-me-*] - tags: + tags: '*' pull_request: concurrency: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f281dcf2..903d2478 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,7 +3,7 @@ name: main on: push: branches: [main, test-me-*] - tags: + tags: '*' pull_request: concurrency: From f88cc6125681378d4d2704a7b08dd595e3744180 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 03:14:12 +0000 Subject: [PATCH 262/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.2.0 → v2.3.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.2.0...v2.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cb03c759..80ee23d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.2.0 + rev: v2.3.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports From 5d273951e00e8331b6b3b07ef6e0280080566cca Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 03:14:26 +0000 Subject: [PATCH 263/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index b2c268ba..efbf2141 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,7 +8,7 @@ url = https://github.com/pre-commit/pre-commit author = Anthony Sottile author_email = asottile@umich.edu license = MIT -license_file = LICENSE +license_files = LICENSE classifiers = License :: OSI Approved :: MIT License Programming Language :: Python :: 3 From 1fc28903ab82e4ef7f8e9c37b052e4f9a53c9967 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 03:58:21 +0000 Subject: [PATCH 264/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/add-trailing-comma: v2.4.0 → v2.5.1](https://github.com/asottile/add-trailing-comma/compare/v2.4.0...v2.5.1) - [github.com/asottile/pyupgrade: v3.4.0 → v3.6.0](https://github.com/asottile/pyupgrade/compare/v3.4.0...v3.6.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 80ee23d0..7810d229 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,12 +20,12 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.4.0 + rev: v2.5.1 hooks: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.4.0 + rev: v3.6.0 hooks: - id: pyupgrade args: [--py38-plus] From 9a7ed8be09b6de99bae5d1e03defc350a132b1e5 Mon Sep 17 00:00:00 2001 From: Jay Soffian Date: Tue, 13 Jun 2023 17:47:49 -0400 Subject: [PATCH 265/416] Force gem installation into envdir RubyGems allows OS packagers to specify defaults for `--install-dir` and `--bindir` and these take precedence over `GEM_HOME`. The only way to override the defaults is to explicitly specify the options ourselves when running `gem install`. Examples of OSes where this is the case are RedHat 9.2 and Gentoo. Fixes #2799. --- pre_commit/languages/ruby.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 76631f25..a411925a 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -114,6 +114,8 @@ def _install_ruby( def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + if version != 'system': # pragma: win32 no cover _install_rbenv(prefix, version) with in_env(prefix, version): @@ -135,6 +137,8 @@ def install_environment( 'gem', 'install', '--no-document', '--no-format-executable', '--no-user-install', + '--install-dir', os.path.join(envdir, 'gems'), + '--bindir', os.path.join(envdir, 'gems', 'bin'), *prefix.star('.gem'), *additional_dependencies, ), ) From 50b1511a5b81e5c95bcf496acc22dc9799a429b3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 22:04:03 +0000 Subject: [PATCH 266/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pre_commit/languages/ruby.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index a411925a..c88269f2 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -138,7 +138,7 @@ def install_environment( '--no-document', '--no-format-executable', '--no-user-install', '--install-dir', os.path.join(envdir, 'gems'), - '--bindir', os.path.join(envdir, 'gems', 'bin'), + '--bindir', os.path.join(envdir, 'gems', 'bin'), *prefix.star('.gem'), *additional_dependencies, ), ) From 5da4258b17dea7bd4601358de200e185699f9997 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 13 Jun 2023 19:11:02 -0400 Subject: [PATCH 267/416] v3.3.3 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4256c6aa..722e8ffa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.3.3 - 2023-06-13 +================== + +### Fixes +- Work around OS packagers setting `--install-dir` / `--bin-dir` in gem settings. + - #2905 PR by @jaysoffian. + - #2799 issue by @lmilbaum. + 3.3.2 - 2023-05-17 ================== diff --git a/setup.cfg b/setup.cfg index efbf2141..88302e75 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.3.2 +version = 3.3.3 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From f94744a699e7d125bcd7cabc070c3129a9079cc1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 04:33:31 +0000 Subject: [PATCH 268/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder-python-imports: v3.9.0 → v3.10.0](https://github.com/asottile/reorder-python-imports/compare/v3.9.0...v3.10.0) - [github.com/asottile/pyupgrade: v3.6.0 → v3.7.0](https://github.com/asottile/pyupgrade/compare/v3.6.0...v3.7.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7810d229..6896fb75 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.9.0 + rev: v3.10.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -25,7 +25,7 @@ repos: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.6.0 + rev: v3.7.0 hooks: - id: pyupgrade args: [--py38-plus] From 854f6985314079889586d1eee43fc185fe0fee62 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 03:51:58 +0000 Subject: [PATCH 269/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.3.0 → v1.4.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.3.0...v1.4.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6896fb75..bb989bb3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.3.0 + rev: v1.4.1 hooks: - id: mypy additional_dependencies: [types-all] From e72699b9ef824d1dc2a1834ba7acbced9853235a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 1 Jul 2023 16:47:06 -0400 Subject: [PATCH 270/416] updates for add-trailing-comma 3.x Committed via https://github.com/asottile/all-repos --- .pre-commit-config.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bb989bb3..2bd6cca9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.3.0 + rev: v2.4.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports @@ -20,12 +20,11 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.5.1 + rev: v3.0.0 hooks: - id: add-trailing-comma - args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.7.0 + rev: v3.8.0 hooks: - id: pyupgrade args: [--py38-plus] From 1c439b5a79d1c6ff9e36327f852e58e79452124c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 1 Jul 2023 17:22:42 -0400 Subject: [PATCH 271/416] shlex.join is always available in 3.8+ --- pre_commit/commands/install_uninstall.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index 5ff6cba6..d19e0d47 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -103,8 +103,7 @@ def _install_hook_script( hook_file.write(before + TEMPLATE_START) hook_file.write(f'INSTALL_PYTHON={shlex.quote(sys.executable)}\n') - # TODO: python3.8+: shlex.join - args_s = ' '.join(shlex.quote(part) for part in args) + args_s = shlex.join(args) hook_file.write(f'ARGS=({args_s})\n') hook_file.write(TEMPLATE_END + after) make_executable(hook_path) From 9bf6856db35f51be1fd131094aba142f71af3543 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 05:21:22 +0000 Subject: [PATCH 272/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.8.0 → v3.9.0](https://github.com/asottile/pyupgrade/compare/v3.8.0...v3.9.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2bd6cca9..2e7ff8cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.8.0 + rev: v3.9.0 hooks: - id: pyupgrade args: [--py38-plus] From 5e4af63e8546f9b0e3f9b4a454b09c8607d02fe8 Mon Sep 17 00:00:00 2001 From: Max R Date: Sun, 16 Jul 2023 15:00:55 -0400 Subject: [PATCH 273/416] Fix link to `language` API --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ab3a9298..182e7bc1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,7 +92,7 @@ language, for example: here are the apis that should be implemented for a language -Note that these are also documented in [`pre_commit/languages/all.py`](https://github.com/pre-commit/pre-commit/blob/main/pre_commit/languages/all.py) +Note that these are also documented in [`pre_commit/lang_base.py`](https://github.com/pre-commit/pre-commit/blob/main/pre_commit/lang_base.py) #### `ENVIRONMENT_DIR` From d537c09032e1c1ca945aec2d0abb8fe80835eb88 Mon Sep 17 00:00:00 2001 From: Max R Date: Mon, 17 Jul 2023 09:36:47 -0400 Subject: [PATCH 274/416] `s/helpers/lang_base/g` --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ab3a9298..dc7a70c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -111,7 +111,7 @@ one cannot be determined, return `'default'`. You generally don't need to implement this on a first pass and can just use: ```python -get_default_version = helpers.basic_default_version +get_default_version = lang_base.basic_default_version ``` `python` is currently the only language which implements this api @@ -125,7 +125,7 @@ healthy. You generally don't need to implement this on a first pass and can just use: ```python -health_check = helpers.basic_healthy_check +health_check = lang_base.basic_healthy_check ``` `python` is currently the only language which implements this api, for python @@ -137,7 +137,7 @@ this is the trickiest one to implement and where all the smart parts happen. this api should do the following things -- (0th / 3rd class): `install_environment = helpers.no_install` +- (0th / 3rd class): `install_environment = lang_base.no_install` - (1st class): install a language runtime into the hook's directory - (2nd class): install the package at `.` into the `ENVIRONMENT_DIR` - (2nd class, optional): install packages listed in `additional_dependencies` From 60273ca81ea974bd429e7ebfbcee6b8598f30040 Mon Sep 17 00:00:00 2001 From: Alex Brandt Date: Wed, 19 Jul 2023 19:26:28 +0100 Subject: [PATCH 275/416] Add haskell language support to pre-commit. --- .github/workflows/languages.yaml | 2 ++ pre_commit/all_languages.py | 2 ++ pre_commit/languages/haskell.py | 56 ++++++++++++++++++++++++++++++++ tests/languages/haskell_test.py | 50 ++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 pre_commit/languages/haskell.py create mode 100644 tests/languages/haskell_test.py diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 7e97158c..5a6ae9cd 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -63,6 +63,8 @@ jobs: echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" shell: bash if: matrix.os == 'windows-latest' && matrix.language == 'perl' + - uses: haskell/actions/setup@v2 + if: matrix.language == 'haskell' - name: install deps run: python -mpip install -e . -r requirements-dev.txt diff --git a/pre_commit/all_languages.py b/pre_commit/all_languages.py index 2bed7067..476bad9d 100644 --- a/pre_commit/all_languages.py +++ b/pre_commit/all_languages.py @@ -9,6 +9,7 @@ from pre_commit.languages import docker_image from pre_commit.languages import dotnet from pre_commit.languages import fail from pre_commit.languages import golang +from pre_commit.languages import haskell from pre_commit.languages import lua from pre_commit.languages import node from pre_commit.languages import perl @@ -31,6 +32,7 @@ languages: dict[str, Language] = { 'dotnet': dotnet, 'fail': fail, 'golang': golang, + 'haskell': haskell, 'lua': lua, 'node': node, 'perl': perl, diff --git a/pre_commit/languages/haskell.py b/pre_commit/languages/haskell.py new file mode 100644 index 00000000..76442eb0 --- /dev/null +++ b/pre_commit/languages/haskell.py @@ -0,0 +1,56 @@ +from __future__ import annotations + +import contextlib +import os.path +from typing import Generator +from typing import Sequence + +from pre_commit import lang_base +from pre_commit.envcontext import envcontext +from pre_commit.envcontext import PatchesT +from pre_commit.envcontext import Var +from pre_commit.errors import FatalError +from pre_commit.prefix import Prefix + +ENVIRONMENT_DIR = 'hs_env' +get_default_version = lang_base.basic_get_default_version +health_check = lang_base.basic_health_check +run_hook = lang_base.basic_run_hook + + +def get_env_patch(target_dir: str) -> PatchesT: + bin_path = os.path.join(target_dir, 'bin') + return (('PATH', (bin_path, os.pathsep, Var('PATH'))),) + + +@contextlib.contextmanager +def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + with envcontext(get_env_patch(envdir)): + yield + + +def install_environment( + prefix: Prefix, + version: str, + additional_dependencies: Sequence[str], +) -> None: + lang_base.assert_version_default('haskell', version) + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + + pkgs = [*prefix.star('.cabal'), *additional_dependencies] + if not pkgs: + raise FatalError('Expected .cabal files or additional_dependencies') + + bindir = os.path.join(envdir, 'bin') + os.makedirs(bindir, exist_ok=True) + lang_base.setup_cmd(prefix, ('cabal', 'update')) + lang_base.setup_cmd( + prefix, + ( + 'cabal', 'install', + '--install-method', 'copy', + '--installdir', bindir, + *pkgs, + ), + ) diff --git a/tests/languages/haskell_test.py b/tests/languages/haskell_test.py new file mode 100644 index 00000000..f888109b --- /dev/null +++ b/tests/languages/haskell_test.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import pytest + +from pre_commit.errors import FatalError +from pre_commit.languages import haskell +from pre_commit.util import win_exe +from testing.language_helpers import run_language + + +def test_run_example_executable(tmp_path): + example_cabal = '''\ +cabal-version: 2.4 +name: example +version: 0.1.0.0 + +executable example + main-is: Main.hs + + build-depends: base >=4 + default-language: Haskell2010 +''' + main_hs = '''\ +module Main where + +main :: IO () +main = putStrLn "Hello, Haskell!" +''' + tmp_path.joinpath('example.cabal').write_text(example_cabal) + tmp_path.joinpath('Main.hs').write_text(main_hs) + + result = run_language(tmp_path, haskell, 'example') + assert result == (0, b'Hello, Haskell!\n') + + # should not symlink things into environments + exe = tmp_path.joinpath(win_exe('hs_env-default/bin/example')) + assert exe.is_file() + assert not exe.is_symlink() + + +def test_run_dep(tmp_path): + result = run_language(tmp_path, haskell, 'hello', deps=['hello']) + assert result == (0, b'Hello, World!\n') + + +def test_run_empty(tmp_path): + with pytest.raises(FatalError) as excinfo: + run_language(tmp_path, haskell, 'example') + msg, = excinfo.value.args + assert msg == 'Expected .cabal files or additional_dependencies' From 3557077bbc9a5c7fe8f373f785ec2d2d79b6a999 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 07:08:53 +0000 Subject: [PATCH 276/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/add-trailing-comma: v3.0.0 → v3.0.1](https://github.com/asottile/add-trailing-comma/compare/v3.0.0...v3.0.1) - [github.com/asottile/pyupgrade: v3.9.0 → v3.10.1](https://github.com/asottile/pyupgrade/compare/v3.9.0...v3.10.1) - [github.com/PyCQA/flake8: 6.0.0 → 6.1.0](https://github.com/PyCQA/flake8/compare/6.0.0...6.1.0) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e7ff8cc..4ab4feb3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,11 +20,11 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v3.0.0 + rev: v3.0.1 hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.9.0 + rev: v3.10.1 hooks: - id: pyupgrade args: [--py38-plus] @@ -33,7 +33,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From 8c75a26f2df489b89e808d26f0cdd83ced19d1e0 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 1 Aug 2023 12:08:52 -0400 Subject: [PATCH 277/416] update hello world go test --- tests/languages/golang_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index ec5a8787..64062671 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -128,7 +128,7 @@ def test_local_golang_additional_deps(tmp_path): deps=('golang.org/x/example/hello@latest',), ) - assert ret == (0, b'Hello, Go examples!\n') + assert ret == (0, b'Hello, world!\n') def test_golang_hook_still_works_when_gobin_is_set(tmp_path): From 1803db979f86ab3e1df8194f40f0177413f0fbb3 Mon Sep 17 00:00:00 2001 From: Fufu Fang Date: Mon, 14 Aug 2023 11:00:17 +0100 Subject: [PATCH 278/416] fix typo in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9965c6ca..da7f9432 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -125,7 +125,7 @@ healthy. You generally don't need to implement this on a first pass and can just use: ```python -health_check = lang_base.basic_healthy_check +health_check = lang_base.basic_health_check ``` `python` is currently the only language which implements this api, for python From 93b1a144023891c0083e2a18cd8d320e47e0d656 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 06:03:09 +0000 Subject: [PATCH 279/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.4.1 → v1.5.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.4.1...v1.5.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4ab4feb3..b53a90e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.4.1 + rev: v1.5.0 hooks: - id: mypy additional_dependencies: [types-all] From 5a4b5b1f8ea29a9df154df504f844db186e877b0 Mon Sep 17 00:00:00 2001 From: Chris Kuehl Date: Mon, 21 Aug 2023 20:02:27 -0500 Subject: [PATCH 280/416] Fix exit code for commands terminated by signals Fixes https://github.com/pre-commit/pre-commit/issues/2970 --- pre_commit/xargs.py | 3 ++- tests/xargs_test.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index 31be6f32..eff57ce7 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -170,7 +170,8 @@ def xargs( results = thread_map(run_cmd_partition, partitions) for proc_retcode, proc_out, _ in results: - retcode = max(retcode, proc_retcode) + if abs(proc_retcode) > abs(retcode): + retcode = proc_retcode stdout += proc_out return retcode, stdout diff --git a/tests/xargs_test.py b/tests/xargs_test.py index 7c41f98c..b0a8e0d6 100644 --- a/tests/xargs_test.py +++ b/tests/xargs_test.py @@ -147,6 +147,15 @@ def test_xargs_retcode_normal(): assert ret == 5 +@pytest.mark.xfail(sys.platform == 'win32', reason='posix only') +def test_xargs_retcode_killed_by_signal(): + ret, _ = xargs.xargs( + parse_shebang.normalize_cmd(('bash', '-c', 'kill -9 $$', '--')), + ('foo', 'bar'), + ) + assert ret == -9 + + def test_xargs_concurrency(): bash_cmd = parse_shebang.normalize_cmd(('bash', '-c')) print_pid = ('sleep 0.5 && echo $$',) From a4ae868633ca56f37fb4264c528c2ae52f50305f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 06:16:21 +0000 Subject: [PATCH 281/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.5.0 → v1.5.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.5.0...v1.5.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b53a90e2..54a56ef3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.5.0 + rev: v1.5.1 hooks: - id: mypy additional_dependencies: [types-all] From 3dd1875df85ea258c790af93ed9d4311fc87a5d8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 05:38:11 +0000 Subject: [PATCH 282/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-autopep8: v2.0.2 → v2.0.4](https://github.com/pre-commit/mirrors-autopep8/compare/v2.0.2...v2.0.4) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 54a56ef3..5c6f62b4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ repos: - id: pyupgrade args: [--py38-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v2.0.2 + rev: v2.0.4 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From ea8244b229fa3b7e0c1c26e5e824fb64dfbb4b1d Mon Sep 17 00:00:00 2001 From: Joe Bateson Date: Mon, 28 Aug 2023 19:20:23 -0700 Subject: [PATCH 283/416] Use os.sched_getaffinity for cpu counts when available --- pre_commit/xargs.py | 8 ++++++++ tests/lang_base_test.py | 27 +++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index eff57ce7..a7493c01 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -24,6 +24,14 @@ TRet = TypeVar('TRet') def cpu_count() -> int: + try: + # On systems that support it, this will return a more accurate count of + # usable CPUs for the current process, which will take into account + # cgroup limits + return len(os.sched_getaffinity(0)) + except AttributeError: + pass + try: return multiprocessing.cpu_count() except NotImplementedError: diff --git a/tests/lang_base_test.py b/tests/lang_base_test.py index a532b6a5..1cffa0e5 100644 --- a/tests/lang_base_test.py +++ b/tests/lang_base_test.py @@ -30,6 +30,19 @@ def homedir_mck(): yield +@pytest.fixture +def no_sched_getaffinity(): + # Simulates an OS without os.sched_getaffinity available (mac/windows) + # https://docs.python.org/3/library/os.html#interface-to-the-scheduler + with mock.patch.object( + os, + 'sched_getaffinity', + create=True, + side_effect=AttributeError, + ): + yield + + def test_exe_exists_does_not_exist(find_exe_mck, homedir_mck): find_exe_mck.return_value = None assert lang_base.exe_exists('ruby') is False @@ -116,7 +129,17 @@ def test_no_env_noop(tmp_path): assert before == inside == after -def test_target_concurrency_normal(): +def test_target_concurrency_sched_getaffinity(no_sched_getaffinity): + with mock.patch.object( + os, + 'sched_getaffinity', + return_value=set(range(345)), + ): + with mock.patch.dict(os.environ, clear=True): + assert lang_base.target_concurrency() == 345 + + +def test_target_concurrency_without_sched_getaffinity(no_sched_getaffinity): with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): with mock.patch.dict(os.environ, {}, clear=True): assert lang_base.target_concurrency() == 123 @@ -134,7 +157,7 @@ def test_target_concurrency_on_travis(): assert lang_base.target_concurrency() == 2 -def test_target_concurrency_cpu_count_not_implemented(): +def test_target_concurrency_cpu_count_not_implemented(no_sched_getaffinity): with mock.patch.object( multiprocessing, 'cpu_count', side_effect=NotImplementedError, ): From fe9ba6b53fd5ae112ef5a3d2ac883e2d0e5a10db Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 2 Sep 2023 13:09:13 -0400 Subject: [PATCH 284/416] v3.4.0 --- CHANGELOG.md | 15 +++++++++++++++ setup.cfg | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 722e8ffa..9e2ef0de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +3.4.0 - 2023-09-02 +================== + +### Features +- Add `language: haskell`. + - #2932 by @alunduil. +- Improve cpu count detection when run under cgroups. + - #2979 PR by @jdb8. + - #2978 issue by @jdb8. + +### Fixes +- Handle negative exit codes from hooks receiving posix signals. + - #2971 PR by @chriskuehl. + - #2970 issue by @chriskuehl. + 3.3.3 - 2023-06-13 ================== diff --git a/setup.cfg b/setup.cfg index 88302e75..cfaa61bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.3.3 +version = 3.4.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 818240e42575620ba8d8d5f36c1d7b5765699c68 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 06:46:49 +0000 Subject: [PATCH 285/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/add-trailing-comma: v3.0.1 → v3.1.0](https://github.com/asottile/add-trailing-comma/compare/v3.0.1...v3.1.0) - https://github.com/pre-commit/mirrors-autopep8 → https://github.com/hhatto/autopep8 --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5c6f62b4..3b98f96b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v3.0.1 + rev: v3.1.0 hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade @@ -28,7 +28,7 @@ repos: hooks: - id: pyupgrade args: [--py38-plus] -- repo: https://github.com/pre-commit/mirrors-autopep8 +- repo: https://github.com/hhatto/autopep8 rev: v2.0.4 hooks: - id: autopep8 From 493c20ce91818493068e499216e64709b96f1230 Mon Sep 17 00:00:00 2001 From: Roel Adriaans Date: Fri, 8 Sep 2023 15:12:45 +0200 Subject: [PATCH 286/416] Use the --include command, hides warning messages Fixes #1983 --- pre_commit/languages/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 66d61363..3e22dc78 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -93,7 +93,7 @@ def install_environment( # install as if we installed from git local_install_cmd = ( - 'npm', 'install', '--dev', '--prod', + 'npm', 'install', '--include=dev', '--include=prod', '--ignore-prepublish', '--no-progress', '--no-save', ) lang_base.setup_cmd(prefix, local_install_cmd) From 9ac229dad886ed5b133a946a524f36ce4220cbf9 Mon Sep 17 00:00:00 2001 From: Max R Date: Sat, 9 Sep 2023 21:54:47 -0400 Subject: [PATCH 287/416] Refactor `target_concurrency` tests --- tests/lang_base_test.py | 62 +++++++++++------------------------------ tests/xargs_test.py | 35 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/tests/lang_base_test.py b/tests/lang_base_test.py index 1cffa0e5..da289aef 100644 --- a/tests/lang_base_test.py +++ b/tests/lang_base_test.py @@ -1,6 +1,5 @@ from __future__ import annotations -import multiprocessing import os.path import sys from unittest import mock @@ -10,6 +9,7 @@ import pytest import pre_commit.constants as C from pre_commit import lang_base from pre_commit import parse_shebang +from pre_commit import xargs from pre_commit.prefix import Prefix from pre_commit.util import CalledProcessError @@ -30,19 +30,6 @@ def homedir_mck(): yield -@pytest.fixture -def no_sched_getaffinity(): - # Simulates an OS without os.sched_getaffinity available (mac/windows) - # https://docs.python.org/3/library/os.html#interface-to-the-scheduler - with mock.patch.object( - os, - 'sched_getaffinity', - create=True, - side_effect=AttributeError, - ): - yield - - def test_exe_exists_does_not_exist(find_exe_mck, homedir_mck): find_exe_mck.return_value = None assert lang_base.exe_exists('ruby') is False @@ -129,40 +116,23 @@ def test_no_env_noop(tmp_path): assert before == inside == after -def test_target_concurrency_sched_getaffinity(no_sched_getaffinity): - with mock.patch.object( - os, - 'sched_getaffinity', - return_value=set(range(345)), - ): - with mock.patch.dict(os.environ, clear=True): - assert lang_base.target_concurrency() == 345 +@pytest.fixture +def cpu_count_mck(): + with mock.patch.object(xargs, 'cpu_count', return_value=4): + yield -def test_target_concurrency_without_sched_getaffinity(no_sched_getaffinity): - with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): - with mock.patch.dict(os.environ, {}, clear=True): - assert lang_base.target_concurrency() == 123 - - -def test_target_concurrency_testing_env_var(): - with mock.patch.dict( - os.environ, {'PRE_COMMIT_NO_CONCURRENCY': '1'}, clear=True, - ): - assert lang_base.target_concurrency() == 1 - - -def test_target_concurrency_on_travis(): - with mock.patch.dict(os.environ, {'TRAVIS': '1'}, clear=True): - assert lang_base.target_concurrency() == 2 - - -def test_target_concurrency_cpu_count_not_implemented(no_sched_getaffinity): - with mock.patch.object( - multiprocessing, 'cpu_count', side_effect=NotImplementedError, - ): - with mock.patch.dict(os.environ, {}, clear=True): - assert lang_base.target_concurrency() == 1 +@pytest.mark.parametrize( + ('var', 'expected'), + ( + ('PRE_COMMIT_NO_CONCURRENCY', 1), + ('TRAVIS', 2), + (None, 4), + ), +) +def test_target_concurrency(cpu_count_mck, var, expected): + with mock.patch.dict(os.environ, {var: '1'} if var else {}, clear=True): + assert lang_base.target_concurrency() == expected def test_shuffled_is_deterministic(): diff --git a/tests/xargs_test.py b/tests/xargs_test.py index b0a8e0d6..e8000b25 100644 --- a/tests/xargs_test.py +++ b/tests/xargs_test.py @@ -1,6 +1,7 @@ from __future__ import annotations import concurrent.futures +import multiprocessing import os import sys import time @@ -12,6 +13,40 @@ from pre_commit import parse_shebang from pre_commit import xargs +def test_cpu_count_sched_getaffinity_exists(): + with mock.patch.object( + os, 'sched_getaffinity', create=True, return_value=set(range(345)), + ): + assert xargs.cpu_count() == 345 + + +@pytest.fixture +def no_sched_getaffinity(): + # Simulates an OS without os.sched_getaffinity available (mac/windows) + # https://docs.python.org/3/library/os.html#interface-to-the-scheduler + with mock.patch.object( + os, + 'sched_getaffinity', + create=True, + side_effect=AttributeError, + ): + yield + + +def test_cpu_count_multiprocessing_cpu_count_implemented(no_sched_getaffinity): + with mock.patch.object(multiprocessing, 'cpu_count', return_value=123): + assert xargs.cpu_count() == 123 + + +def test_cpu_count_multiprocessing_cpu_count_not_implemented( + no_sched_getaffinity, +): + with mock.patch.object( + multiprocessing, 'cpu_count', side_effect=NotImplementedError, + ): + assert xargs.cpu_count() == 1 + + @pytest.mark.parametrize( ('env', 'expected'), ( From 5d692d7e06606ec34ef3a6acf4a0fa7fef158983 Mon Sep 17 00:00:00 2001 From: Max R Date: Sat, 9 Sep 2023 21:51:59 -0400 Subject: [PATCH 288/416] Short-circuit hooks --- pre_commit/commands/run.py | 48 +++++++++---------- pre_commit/meta_hooks/check_hooks_apply.py | 2 +- .../meta_hooks/check_useless_excludes.py | 14 +++--- tests/commands/run_test.py | 16 +++---- 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index c867799e..38d80db3 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -10,7 +10,8 @@ import subprocess import time import unicodedata from typing import Any -from typing import Collection +from typing import Generator +from typing import Iterable from typing import MutableMapping from typing import Sequence @@ -57,20 +58,20 @@ def _full_msg( def filter_by_include_exclude( - names: Collection[str], + names: Iterable[str], include: str, exclude: str, -) -> list[str]: +) -> Generator[str, None, None]: include_re, exclude_re = re.compile(include), re.compile(exclude) - return [ + return ( filename for filename in names if include_re.search(filename) if not exclude_re.search(filename) - ] + ) class Classifier: - def __init__(self, filenames: Collection[str]) -> None: + def __init__(self, filenames: Iterable[str]) -> None: self.filenames = [f for f in filenames if os.path.lexists(f)] @functools.lru_cache(maxsize=None) @@ -79,15 +80,14 @@ class Classifier: def by_types( self, - names: Sequence[str], - types: Collection[str], - types_or: Collection[str], - exclude_types: Collection[str], - ) -> list[str]: + names: Iterable[str], + types: Iterable[str], + types_or: Iterable[str], + exclude_types: Iterable[str], + ) -> Generator[str, None, None]: types = frozenset(types) types_or = frozenset(types_or) exclude_types = frozenset(exclude_types) - ret = [] for filename in names: tags = self._types_for_file(filename) if ( @@ -95,24 +95,24 @@ class Classifier: (not types_or or tags & types_or) and not tags & exclude_types ): - ret.append(filename) - return ret + yield filename - def filenames_for_hook(self, hook: Hook) -> tuple[str, ...]: - names = self.filenames - names = filter_by_include_exclude(names, hook.files, hook.exclude) - names = self.by_types( - names, + def filenames_for_hook(self, hook: Hook) -> Generator[str, None, None]: + return self.by_types( + filter_by_include_exclude( + self.filenames, + hook.files, + hook.exclude, + ), hook.types, hook.types_or, hook.exclude_types, ) - return tuple(names) @classmethod def from_config( cls, - filenames: Collection[str], + filenames: Iterable[str], include: str, exclude: str, ) -> Classifier: @@ -121,7 +121,7 @@ class Classifier: # this also makes improperly quoted shell-based hooks work better # see #1173 if os.altsep == '/' and os.sep == '\\': - filenames = [f.replace(os.sep, os.altsep) for f in filenames] + filenames = (f.replace(os.sep, os.altsep) for f in filenames) filenames = filter_by_include_exclude(filenames, include, exclude) return Classifier(filenames) @@ -148,7 +148,7 @@ def _run_single_hook( verbose: bool, use_color: bool, ) -> tuple[bool, bytes]: - filenames = classifier.filenames_for_hook(hook) + filenames = tuple(classifier.filenames_for_hook(hook)) if hook.id in skips or hook.alias in skips: output.write( @@ -250,7 +250,7 @@ def _compute_cols(hooks: Sequence[Hook]) -> int: return max(cols, 80) -def _all_filenames(args: argparse.Namespace) -> Collection[str]: +def _all_filenames(args: argparse.Namespace) -> Iterable[str]: # these hooks do not operate on files if args.hook_stage in { 'post-checkout', 'post-commit', 'post-merge', 'post-rewrite', diff --git a/pre_commit/meta_hooks/check_hooks_apply.py b/pre_commit/meta_hooks/check_hooks_apply.py index b05a7050..7f491a20 100644 --- a/pre_commit/meta_hooks/check_hooks_apply.py +++ b/pre_commit/meta_hooks/check_hooks_apply.py @@ -21,7 +21,7 @@ def check_all_hooks_match_files(config_file: str) -> int: for hook in all_hooks(config, Store()): if hook.always_run or hook.language == 'fail': continue - elif not classifier.filenames_for_hook(hook): + elif not any(classifier.filenames_for_hook(hook)): print(f'{hook.id} does not apply to this repository') retv = 1 diff --git a/pre_commit/meta_hooks/check_useless_excludes.py b/pre_commit/meta_hooks/check_useless_excludes.py index 0a8249b8..8b0c106a 100644 --- a/pre_commit/meta_hooks/check_useless_excludes.py +++ b/pre_commit/meta_hooks/check_useless_excludes.py @@ -2,6 +2,7 @@ from __future__ import annotations import argparse import re +from typing import Iterable from typing import Sequence from cfgv import apply_defaults @@ -14,7 +15,7 @@ from pre_commit.commands.run import Classifier def exclude_matches_any( - filenames: Sequence[str], + filenames: Iterable[str], include: str, exclude: str, ) -> bool: @@ -50,11 +51,12 @@ def check_useless_excludes(config_file: str) -> int: # Not actually a manifest dict, but this more accurately reflects # the defaults applied during runtime hook = apply_defaults(hook, MANIFEST_HOOK_DICT) - names = classifier.filenames - types = hook['types'] - types_or = hook['types_or'] - exclude_types = hook['exclude_types'] - names = classifier.by_types(names, types, types_or, exclude_types) + names = classifier.by_types( + classifier.filenames, + hook['types'], + hook['types_or'], + hook['exclude_types'], + ) include, exclude = hook['files'], hook['exclude'] if not exclude_matches_any(names, include, exclude): print( diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index dd15b94c..8d89815b 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -1127,8 +1127,8 @@ def test_classifier_empty_types_or(tmpdir): types_or=[], exclude_types=[], ) - assert for_symlink == ['foo'] - assert for_file == ['bar'] + assert tuple(for_symlink) == ('foo',) + assert tuple(for_file) == ('bar',) @pytest.fixture @@ -1142,33 +1142,33 @@ def some_filenames(): def test_include_exclude_base_case(some_filenames): ret = filter_by_include_exclude(some_filenames, '', '^$') - assert ret == [ + assert tuple(ret) == ( '.pre-commit-hooks.yaml', 'pre_commit/git.py', 'pre_commit/main.py', - ] + ) def test_matches_broken_symlink(tmpdir): with tmpdir.as_cwd(): os.symlink('does-not-exist', 'link') ret = filter_by_include_exclude({'link'}, '', '^$') - assert ret == ['link'] + assert tuple(ret) == ('link',) def test_include_exclude_total_match(some_filenames): ret = filter_by_include_exclude(some_filenames, r'^.*\.py$', '^$') - assert ret == ['pre_commit/git.py', 'pre_commit/main.py'] + assert tuple(ret) == ('pre_commit/git.py', 'pre_commit/main.py') def test_include_exclude_does_search_instead_of_match(some_filenames): ret = filter_by_include_exclude(some_filenames, r'\.yaml$', '^$') - assert ret == ['.pre-commit-hooks.yaml'] + assert tuple(ret) == ('.pre-commit-hooks.yaml',) def test_include_exclude_exclude_removes_files(some_filenames): ret = filter_by_include_exclude(some_filenames, '', r'\.py$') - assert ret == ['.pre-commit-hooks.yaml'] + assert tuple(ret) == ('.pre-commit-hooks.yaml',) def test_args_hook_only(cap_out, store, repo_with_passing_hook): From d33801e78176d91023a441ca869ecb0288f4f461 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 07:06:08 +0000 Subject: [PATCH 289/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder-python-imports: v3.10.0 → v3.11.0](https://github.com/asottile/reorder-python-imports/compare/v3.10.0...v3.11.0) - [github.com/asottile/pyupgrade: v3.10.1 → v3.11.0](https://github.com/asottile/pyupgrade/compare/v3.10.1...v3.11.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3b98f96b..fb969280 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.10.0 + rev: v3.11.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.11.0 hooks: - id: pyupgrade args: [--py38-plus] From 5e05b012157763a46f5f0364ce575d7b99cf5c21 Mon Sep 17 00:00:00 2001 From: Eric Long Date: Mon, 25 Sep 2023 17:00:29 +0800 Subject: [PATCH 290/416] Bump Node.js version to 18.14.0 and Go to 1.21.1 On riscv64, nodeenv will pull binary from unofficial-builds [1], and unfortunately 18.13.0 seems to be the only version above 18 that is missing riscv64 builds. Shifting the version slightly to make test work. Go's binary now ships with linux/riscv64 binary since 1.21. --- tests/languages/golang_test.py | 4 ++-- tests/languages/node_test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 64062671..19e9f62f 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -111,11 +111,11 @@ def test_golang_versioned(tmp_path): tmp_path, golang, 'go version', - version='1.18.4', + version='1.21.1', ) assert ret == 0 - assert out.startswith(b'go version go1.18.4') + assert out.startswith(b'go version go1.21.1') def test_local_golang_additional_deps(tmp_path): diff --git a/tests/languages/node_test.py b/tests/languages/node_test.py index cba0228b..055cb1e9 100644 --- a/tests/languages/node_test.py +++ b/tests/languages/node_test.py @@ -139,7 +139,7 @@ def test_node_with_user_config_set(tmp_path): test_node_hook_system(tmp_path) -@pytest.mark.parametrize('version', (C.DEFAULT, '18.13.0')) +@pytest.mark.parametrize('version', (C.DEFAULT, '18.14.0')) def test_node_hook_versions(tmp_path, version): _make_hello_world(tmp_path) ret = run_language(tmp_path, node, 'node-hello', version=version) From c68c6b944aafed8d7b7d75c0d6a0f4109d7dde50 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 07:23:52 +0000 Subject: [PATCH 291/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.11.0 → v3.13.0](https://github.com/asottile/pyupgrade/compare/v3.11.0...v3.13.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb969280..309e9de5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.11.0 + rev: v3.13.0 hooks: - id: pyupgrade args: [--py38-plus] From a4ab977cc36e06fff8a8c69cca652162407b55cf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 08:58:04 +0000 Subject: [PATCH 292/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.4.0 → v2.5.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.4.0...v2.5.0) - [github.com/asottile/reorder-python-imports: v3.11.0 → v3.12.0](https://github.com/asottile/reorder-python-imports/compare/v3.11.0...v3.12.0) - [github.com/asottile/pyupgrade: v3.13.0 → v3.14.0](https://github.com/asottile/pyupgrade/compare/v3.13.0...v3.14.0) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 309e9de5..cccecb8e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,11 +10,11 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.4.0 + rev: v2.5.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.11.0 + rev: v3.12.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.13.0 + rev: v3.14.0 hooks: - id: pyupgrade args: [--py38-plus] From 997ea0ad52074c3e6474f3d99f76f7965e2d05f0 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 9 Oct 2023 16:49:30 -0400 Subject: [PATCH 293/416] use sys.executable instead of echo.exe in parse_shebang the GHA runners now have echo.exe in a path with spaces --- tests/parse_shebang_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/parse_shebang_test.py b/tests/parse_shebang_test.py index dd97ca5d..bd4384df 100644 --- a/tests/parse_shebang_test.py +++ b/tests/parse_shebang_test.py @@ -133,17 +133,17 @@ def test_normalize_cmd_PATH(): def test_normalize_cmd_shebang(in_tmpdir): - echo = _echo_exe().replace(os.sep, '/') - path = write_executable(echo) - assert parse_shebang.normalize_cmd((path,)) == (echo, path) + us = sys.executable.replace(os.sep, '/') + path = write_executable(us) + assert parse_shebang.normalize_cmd((path,)) == (us, path) def test_normalize_cmd_PATH_shebang_full_path(in_tmpdir): - echo = _echo_exe().replace(os.sep, '/') - path = write_executable(echo) + us = sys.executable.replace(os.sep, '/') + path = write_executable(us) with bin_on_path(): ret = parse_shebang.normalize_cmd(('run',)) - assert ret == (echo, os.path.abspath(path)) + assert ret == (us, os.path.abspath(path)) def test_normalize_cmd_PATH_shebang_PATH(in_tmpdir): From 155c52134848b05b0092a446cdd2c336a03a85c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:33:33 +0000 Subject: [PATCH 294/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) - [github.com/asottile/pyupgrade: v3.14.0 → v3.15.0](https://github.com/asottile/pyupgrade/compare/v3.14.0...v3.15.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cccecb8e..5381cd61 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.14.0 + rev: v3.15.0 hooks: - id: pyupgrade args: [--py38-plus] From d988767b414495bdab9ea24532ad337e8ee3fd1f Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Fri, 13 Oct 2023 16:01:59 +0100 Subject: [PATCH 295/416] Improve hook duration timing --- pre_commit/commands/run.py | 4 ++-- tests/commands/run_test.py | 2 +- tests/commands/try_repo_test.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index c867799e..241f6fe1 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -187,7 +187,7 @@ def _run_single_hook( if not hook.pass_filenames: filenames = () - time_before = time.time() + time_before = time.monotonic() language = languages[hook.language] with language.in_env(hook.prefix, hook.language_version): retcode, out = language.run_hook( @@ -199,7 +199,7 @@ def _run_single_hook( require_serial=hook.require_serial, color=use_color, ) - duration = round(time.time() - time_before, 2) or 0 + duration = round(time.monotonic() - time_before, 2) or 0 diff_after = _get_diff() # if the hook makes changes, fail the commit diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index dd15b94c..4be8f3b9 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -293,7 +293,7 @@ def test_verbose_duration(cap_out, store, in_git_dir, t1, t2, expected): write_config('.', {'repo': 'meta', 'hooks': [{'id': 'identity'}]}) cmd_output('git', 'add', '.') opts = run_opts(verbose=True) - with mock.patch.object(time, 'time', side_effect=(t1, t2)): + with mock.patch.object(time, 'monotonic', side_effect=(t1, t2)): ret, printed = _do_run(cap_out, store, str(in_git_dir), opts) assert ret == 0 assert expected in printed diff --git a/tests/commands/try_repo_test.py b/tests/commands/try_repo_test.py index 0b2db7e5..c5f891ea 100644 --- a/tests/commands/try_repo_test.py +++ b/tests/commands/try_repo_test.py @@ -43,7 +43,7 @@ def _run_try_repo(tempdir_factory, **kwargs): def test_try_repo_repo_only(cap_out, tempdir_factory): - with mock.patch.object(time, 'time', return_value=0.0): + with mock.patch.object(time, 'monotonic', return_value=0.0): _run_try_repo(tempdir_factory, verbose=True) start, config, rest = _get_out(cap_out) assert start == '' From 61cc55a59cc63c7405dd3cd7c96b169fdb750333 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 13 Oct 2023 11:57:20 -0400 Subject: [PATCH 296/416] v3.5.0 --- CHANGELOG.md | 17 +++++++++++++++++ setup.cfg | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e2ef0de..7a1b61a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +3.5.0 - 2023-10-13 +================== + +### Features +- Improve performance of `check-hooks-apply` and `check-useless-excludes`. + - #2998 PR by @mxr. + - #2935 issue by @mxr. + +### Fixes +- Use `time.monotonic()` for more accurate hook timing. + - #3024 PR by @adamchainz. + +### Migrating +- Require npm 6.x+ for `language: node` hooks. + - #2996 PR by @RoelAdriaans. + - #1983 issue by @henryiii. + 3.4.0 - 2023-09-02 ================== diff --git a/setup.cfg b/setup.cfg index cfaa61bb..7543835d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.4.0 +version = 3.5.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 44b625ebd3c3f239737ee1ea0603daffbd61c4e2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 20:03:36 +0000 Subject: [PATCH 297/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.5.1 → v1.6.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.5.1...v1.6.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5381cd61..0ef18ba3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.5.1 + rev: v1.6.0 hooks: - id: mypy additional_dependencies: [types-all] From c69e32e925dc4ef160aa9ecde13bea73f2175803 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:28:04 +0000 Subject: [PATCH 298/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.6.0 → v1.6.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.6.0...v1.6.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ef18ba3..46dce481 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.0 + rev: v1.6.1 hooks: - id: mypy additional_dependencies: [types-all] From 7f15dc75eea8ad1017c9870e1468d6a9e5339ac3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Oct 2023 14:20:37 -0400 Subject: [PATCH 299/416] python3.9+ --- .github/actions/pre-test/action.yml | 2 +- .github/workflows/languages.yaml | 4 ++-- .github/workflows/main.yml | 8 ++++---- .pre-commit-config.yaml | 4 ++-- pre_commit/clientlib.py | 2 +- pre_commit/commands/autoupdate.py | 2 +- pre_commit/commands/hook_impl.py | 2 +- pre_commit/commands/run.py | 10 +++++----- pre_commit/commands/validate_config.py | 2 +- pre_commit/commands/validate_manifest.py | 2 +- pre_commit/envcontext.py | 9 ++++----- pre_commit/error_handler.py | 2 +- pre_commit/file_lock.py | 2 +- pre_commit/git.py | 2 +- pre_commit/hook.py | 2 +- pre_commit/lang_base.py | 4 ++-- pre_commit/languages/conda.py | 4 ++-- pre_commit/languages/coursier.py | 4 ++-- pre_commit/languages/dart.py | 4 ++-- pre_commit/languages/docker.py | 2 +- pre_commit/languages/docker_image.py | 2 +- pre_commit/languages/dotnet.py | 4 ++-- pre_commit/languages/fail.py | 2 +- pre_commit/languages/golang.py | 4 ++-- pre_commit/languages/haskell.py | 4 ++-- pre_commit/languages/lua.py | 4 ++-- pre_commit/languages/node.py | 4 ++-- pre_commit/languages/perl.py | 4 ++-- pre_commit/languages/pygrep.py | 4 ++-- pre_commit/languages/python.py | 6 +++--- pre_commit/languages/r.py | 4 ++-- pre_commit/languages/ruby.py | 4 ++-- pre_commit/languages/rust.py | 4 ++-- pre_commit/languages/script.py | 2 +- pre_commit/languages/swift.py | 4 ++-- pre_commit/logging_handler.py | 2 +- pre_commit/main.py | 2 +- pre_commit/meta_hooks/check_hooks_apply.py | 2 +- pre_commit/meta_hooks/check_useless_excludes.py | 4 ++-- pre_commit/meta_hooks/identity.py | 2 +- pre_commit/parse_shebang.py | 2 +- pre_commit/repository.py | 2 +- pre_commit/staged_files_only.py | 2 +- pre_commit/store.py | 4 ++-- pre_commit/util.py | 2 +- pre_commit/xargs.py | 8 ++++---- setup.cfg | 2 +- testing/language_helpers.py | 2 +- testing/make-archives | 2 +- tests/commands/run_test.py | 2 +- 50 files changed, 84 insertions(+), 85 deletions(-) diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index 9d1eb2de..b70c942f 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -6,4 +6,4 @@ runs: using: composite steps: - uses: asottile/workflows/.github/actions/latest-git@v1.4.0 - if: inputs.env == 'py38' && runner.os == 'Linux' + if: inputs.env == 'py39' && runner.os == 'Linux' diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 5a6ae9cd..7d50535f 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -21,7 +21,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - name: install deps run: python -mpip install -e . -r requirements-dev.txt - name: vars @@ -39,7 +39,7 @@ jobs: - uses: asottile/workflows/.github/actions/fast-checkout@v1.4.0 - uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.9 - run: echo "$CONDA\Scripts" >> "$GITHUB_PATH" shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 903d2478..6e32f6c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,12 +12,12 @@ concurrency: jobs: main-windows: - uses: asottile/workflows/.github/workflows/tox.yml@v1.4.0 + uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 with: - env: '["py38"]' + env: '["py39"]' os: windows-latest main-linux: - uses: asottile/workflows/.github/workflows/tox.yml@v1.4.0 + uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 with: - env: '["py38", "py39", "py310"]' + env: '["py39", "py310", "py311"]' os: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5381cd61..ca2dc42b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) - args: [--py38-plus, --add-import, 'from __future__ import annotations'] + args: [--py39-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v3.1.0 hooks: @@ -27,7 +27,7 @@ repos: rev: v3.15.0 hooks: - id: pyupgrade - args: [--py38-plus] + args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 rev: v2.0.4 hooks: diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index d0651cae..9f41bf4b 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -5,9 +5,9 @@ import logging import re import shlex import sys +from collections.abc import Sequence from typing import Any from typing import NamedTuple -from typing import Sequence import cfgv from identify.identify import ALL_TAGS diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index e7725fdc..aa0c5e25 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -4,9 +4,9 @@ import concurrent.futures import os.path import re import tempfile +from collections.abc import Sequence from typing import Any from typing import NamedTuple -from typing import Sequence import pre_commit.constants as C from pre_commit import git diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index dab2135d..49a80b7b 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -4,7 +4,7 @@ import argparse import os.path import subprocess import sys -from typing import Sequence +from collections.abc import Sequence from pre_commit.commands.run import run from pre_commit.envcontext import envcontext diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 41ba4ecf..076f16d8 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -9,11 +9,11 @@ import re import subprocess import time import unicodedata +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import MutableMapping +from collections.abc import Sequence from typing import Any -from typing import Generator -from typing import Iterable -from typing import MutableMapping -from typing import Sequence from identify.identify import tags_from_path @@ -74,7 +74,7 @@ class Classifier: def __init__(self, filenames: Iterable[str]) -> None: self.filenames = [f for f in filenames if os.path.lexists(f)] - @functools.lru_cache(maxsize=None) + @functools.cache def _types_for_file(self, filename: str) -> set[str]: return tags_from_path(filename) diff --git a/pre_commit/commands/validate_config.py b/pre_commit/commands/validate_config.py index 24bd3135..b3de635b 100644 --- a/pre_commit/commands/validate_config.py +++ b/pre_commit/commands/validate_config.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from pre_commit import clientlib diff --git a/pre_commit/commands/validate_manifest.py b/pre_commit/commands/validate_manifest.py index 419031a9..8493c6e1 100644 --- a/pre_commit/commands/validate_manifest.py +++ b/pre_commit/commands/validate_manifest.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from pre_commit import clientlib diff --git a/pre_commit/envcontext.py b/pre_commit/envcontext.py index 4f595601..1f816cea 100644 --- a/pre_commit/envcontext.py +++ b/pre_commit/envcontext.py @@ -3,10 +3,9 @@ from __future__ import annotations import contextlib import enum import os -from typing import Generator -from typing import MutableMapping +from collections.abc import Generator +from collections.abc import MutableMapping from typing import NamedTuple -from typing import Tuple from typing import Union _Unset = enum.Enum('_Unset', 'UNSET') @@ -18,9 +17,9 @@ class Var(NamedTuple): default: str = '' -SubstitutionT = Tuple[Union[str, Var], ...] +SubstitutionT = tuple[Union[str, Var], ...] ValueT = Union[str, _Unset, SubstitutionT] -PatchesT = Tuple[Tuple[str, ValueT], ...] +PatchesT = tuple[tuple[str, ValueT], ...] def format_env(parts: SubstitutionT, env: MutableMapping[str, str]) -> str: diff --git a/pre_commit/error_handler.py b/pre_commit/error_handler.py index d740ee3e..73e608b7 100644 --- a/pre_commit/error_handler.py +++ b/pre_commit/error_handler.py @@ -5,7 +5,7 @@ import functools import os.path import sys import traceback -from typing import Generator +from collections.abc import Generator from typing import IO import pre_commit.constants as C diff --git a/pre_commit/file_lock.py b/pre_commit/file_lock.py index f67a5864..d3dafb4d 100644 --- a/pre_commit/file_lock.py +++ b/pre_commit/file_lock.py @@ -3,8 +3,8 @@ from __future__ import annotations import contextlib import errno import sys +from collections.abc import Generator from typing import Callable -from typing import Generator if sys.platform == 'win32': # pragma: no cover (windows) diff --git a/pre_commit/git.py b/pre_commit/git.py index 333dc7ba..19aac387 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging import os.path import sys -from typing import Mapping +from collections.abc import Mapping from pre_commit.errors import FatalError from pre_commit.util import CalledProcessError diff --git a/pre_commit/hook.py b/pre_commit/hook.py index 6d436ca3..309cd5be 100644 --- a/pre_commit/hook.py +++ b/pre_commit/hook.py @@ -1,9 +1,9 @@ from __future__ import annotations import logging +from collections.abc import Sequence from typing import Any from typing import NamedTuple -from typing import Sequence from pre_commit.prefix import Prefix diff --git a/pre_commit/lang_base.py b/pre_commit/lang_base.py index 4a993eaa..5303948b 100644 --- a/pre_commit/lang_base.py +++ b/pre_commit/lang_base.py @@ -5,12 +5,12 @@ import os import random import re import shlex +from collections.abc import Generator +from collections.abc import Sequence from typing import Any from typing import ContextManager -from typing import Generator from typing import NoReturn from typing import Protocol -from typing import Sequence import pre_commit.constants as C from pre_commit import parse_shebang diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 41c355e7..80b3e150 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -3,8 +3,8 @@ from __future__ import annotations import contextlib import os import sys -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 9c5fbfe2..6558bf6b 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -2,8 +2,8 @@ from __future__ import annotations import contextlib import os.path -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index e8539caa..129ac591 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -4,8 +4,8 @@ import contextlib import os.path import shutil import tempfile -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 8e53ca9e..26328515 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -3,7 +3,7 @@ from __future__ import annotations import hashlib import json import os -from typing import Sequence +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.prefix import Prefix diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index 26f006e4..a1a2c169 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.languages.docker import docker_cmd diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index e9568f22..e1202c4f 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -6,8 +6,8 @@ import re import tempfile import xml.etree.ElementTree import zipfile -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/fail.py b/pre_commit/languages/fail.py index a8ec6a53..6ac4d767 100644 --- a/pre_commit/languages/fail.py +++ b/pre_commit/languages/fail.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.prefix import Prefix diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index bea91e9b..4c13d8f9 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -12,11 +12,11 @@ import tempfile import urllib.error import urllib.request import zipfile +from collections.abc import Generator +from collections.abc import Sequence from typing import ContextManager -from typing import Generator from typing import IO from typing import Protocol -from typing import Sequence import pre_commit.constants as C from pre_commit import lang_base diff --git a/pre_commit/languages/haskell.py b/pre_commit/languages/haskell.py index 76442eb0..c6945c82 100644 --- a/pre_commit/languages/haskell.py +++ b/pre_commit/languages/haskell.py @@ -2,8 +2,8 @@ from __future__ import annotations import contextlib import os.path -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index 12d06614..a475ec99 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -3,8 +3,8 @@ from __future__ import annotations import contextlib import os import sys -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 3e22dc78..d49c0e32 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -4,8 +4,8 @@ import contextlib import functools import os import sys -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence import pre_commit.constants as C from pre_commit import lang_base diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 2a7f1629..61b1d114 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -3,8 +3,8 @@ from __future__ import annotations import contextlib import os import shlex -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/pygrep.py b/pre_commit/languages/pygrep.py index ec55560b..72a9345f 100644 --- a/pre_commit/languages/pygrep.py +++ b/pre_commit/languages/pygrep.py @@ -3,9 +3,9 @@ from __future__ import annotations import argparse import re import sys +from collections.abc import Sequence +from re import Pattern from typing import NamedTuple -from typing import Pattern -from typing import Sequence from pre_commit import lang_base from pre_commit import output diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 3ef34360..e5bac9fa 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -4,8 +4,8 @@ import contextlib import functools import os import sys -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence import pre_commit.constants as C from pre_commit import lang_base @@ -24,7 +24,7 @@ ENVIRONMENT_DIR = 'py_env' run_hook = lang_base.basic_run_hook -@functools.lru_cache(maxsize=None) +@functools.cache def _version_info(exe: str) -> str: prog = 'import sys;print(".".join(str(p) for p in sys.version_info))' try: diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 6feb0652..93b62bd5 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -6,8 +6,8 @@ import shlex import shutil import tempfile import textwrap -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index c88269f2..3ed15cfc 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -6,9 +6,9 @@ import importlib.resources import os.path import shutil import tarfile -from typing import Generator +from collections.abc import Generator +from collections.abc import Sequence from typing import IO -from typing import Sequence import pre_commit.constants as C from pre_commit import lang_base diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 7eec0e7d..241146c5 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -7,8 +7,8 @@ import shutil import sys import tempfile import urllib.request -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence import pre_commit.constants as C from pre_commit import lang_base diff --git a/pre_commit/languages/script.py b/pre_commit/languages/script.py index 89a3ab2d..1eaa1e27 100644 --- a/pre_commit/languages/script.py +++ b/pre_commit/languages/script.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.prefix import Prefix diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index f16bb045..f7bfe84c 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -2,8 +2,8 @@ from __future__ import annotations import contextlib import os -from typing import Generator -from typing import Sequence +from collections.abc import Generator +from collections.abc import Sequence from pre_commit import lang_base from pre_commit.envcontext import envcontext diff --git a/pre_commit/logging_handler.py b/pre_commit/logging_handler.py index 1b68fc7d..cd33953d 100644 --- a/pre_commit/logging_handler.py +++ b/pre_commit/logging_handler.py @@ -2,7 +2,7 @@ from __future__ import annotations import contextlib import logging -from typing import Generator +from collections.abc import Generator from pre_commit import color from pre_commit import output diff --git a/pre_commit/main.py b/pre_commit/main.py index 9dfce2c2..18c978a8 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -4,7 +4,7 @@ import argparse import logging import os import sys -from typing import Sequence +from collections.abc import Sequence import pre_commit.constants as C from pre_commit import clientlib diff --git a/pre_commit/meta_hooks/check_hooks_apply.py b/pre_commit/meta_hooks/check_hooks_apply.py index 7f491a20..84c142b4 100644 --- a/pre_commit/meta_hooks/check_hooks_apply.py +++ b/pre_commit/meta_hooks/check_hooks_apply.py @@ -1,7 +1,7 @@ from __future__ import annotations import argparse -from typing import Sequence +from collections.abc import Sequence import pre_commit.constants as C from pre_commit import git diff --git a/pre_commit/meta_hooks/check_useless_excludes.py b/pre_commit/meta_hooks/check_useless_excludes.py index 8b0c106a..664251a4 100644 --- a/pre_commit/meta_hooks/check_useless_excludes.py +++ b/pre_commit/meta_hooks/check_useless_excludes.py @@ -2,8 +2,8 @@ from __future__ import annotations import argparse import re -from typing import Iterable -from typing import Sequence +from collections.abc import Iterable +from collections.abc import Sequence from cfgv import apply_defaults diff --git a/pre_commit/meta_hooks/identity.py b/pre_commit/meta_hooks/identity.py index 72ee440b..3e20bbc6 100644 --- a/pre_commit/meta_hooks/identity.py +++ b/pre_commit/meta_hooks/identity.py @@ -1,7 +1,7 @@ from __future__ import annotations import sys -from typing import Sequence +from collections.abc import Sequence from pre_commit import output diff --git a/pre_commit/parse_shebang.py b/pre_commit/parse_shebang.py index 3ee04e8d..043a9b5d 100644 --- a/pre_commit/parse_shebang.py +++ b/pre_commit/parse_shebang.py @@ -1,7 +1,7 @@ from __future__ import annotations import os.path -from typing import Mapping +from collections.abc import Mapping from typing import NoReturn from identify.identify import parse_shebang_from_file diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 040f238f..439a09b4 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -4,8 +4,8 @@ import json import logging import os import shlex +from collections.abc import Sequence from typing import Any -from typing import Sequence import pre_commit.constants as C from pre_commit.all_languages import languages diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index 88123565..fd28e1c2 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -4,7 +4,7 @@ import contextlib import logging import os.path import time -from typing import Generator +from collections.abc import Generator from pre_commit import git from pre_commit.errors import FatalError diff --git a/pre_commit/store.py b/pre_commit/store.py index 487e3e79..84bc09a4 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -5,9 +5,9 @@ import logging import os.path import sqlite3 import tempfile +from collections.abc import Generator +from collections.abc import Sequence from typing import Callable -from typing import Generator -from typing import Sequence import pre_commit.constants as C from pre_commit import file_lock diff --git a/pre_commit/util.py b/pre_commit/util.py index 4f8e8357..1e311269 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -8,10 +8,10 @@ import shutil import stat import subprocess import sys +from collections.abc import Generator from types import TracebackType from typing import Any from typing import Callable -from typing import Generator from pre_commit import parse_shebang diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index a7493c01..22580f59 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -7,12 +7,12 @@ import multiprocessing import os import subprocess import sys +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import MutableMapping +from collections.abc import Sequence from typing import Any from typing import Callable -from typing import Generator -from typing import Iterable -from typing import MutableMapping -from typing import Sequence from typing import TypeVar from pre_commit import parse_shebang diff --git a/setup.cfg b/setup.cfg index 7543835d..3110881f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,7 +24,7 @@ install_requires = nodeenv>=0.11.1 pyyaml>=5.1 virtualenv>=20.10.0 -python_requires = >=3.8 +python_requires = >=3.9 [options.packages.find] exclude = diff --git a/testing/language_helpers.py b/testing/language_helpers.py index ead8dae2..05c94ebc 100644 --- a/testing/language_helpers.py +++ b/testing/language_helpers.py @@ -1,7 +1,7 @@ from __future__ import annotations import os -from typing import Sequence +from collections.abc import Sequence from pre_commit.lang_base import Language from pre_commit.prefix import Prefix diff --git a/testing/make-archives b/testing/make-archives index 8ec05e2d..3c7ab9dd 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -8,7 +8,7 @@ import shutil import subprocess import tarfile import tempfile -from typing import Sequence +from collections.abc import Sequence # This is a script for generating the tarred resources for git repo diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 6a0cd855..e36a3ca9 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -4,7 +4,7 @@ import os.path import shlex import sys import time -from typing import MutableMapping +from collections.abc import MutableMapping from unittest import mock import pytest From 75f2710bd4ffdce232fd1a37e9accbcac3ade14a Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Oct 2023 14:39:49 -0400 Subject: [PATCH 300/416] 3.13 removed the simpler importlib.resources api --- pre_commit/languages/ruby.py | 3 ++- pre_commit/util.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 3ed15cfc..0438ae09 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -25,7 +25,8 @@ run_hook = lang_base.basic_run_hook def _resource_bytesio(filename: str) -> IO[bytes]: - return importlib.resources.open_binary('pre_commit.resources', filename) + files = importlib.resources.files('pre_commit.resources') + return files.joinpath(filename).open('rb') @functools.lru_cache(maxsize=1) diff --git a/pre_commit/util.py b/pre_commit/util.py index 1e311269..8f595841 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -36,7 +36,8 @@ def clean_path_on_failure(path: str) -> Generator[None, None, None]: def resource_text(filename: str) -> str: - return importlib.resources.read_text('pre_commit.resources', filename) + files = importlib.resources.files('pre_commit.resources') + return files.joinpath(filename).read_text() def make_executable(filename: str) -> None: From 1d474994e0d4276c98f5ab22f7f84e5570318f8d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:35:35 +0000 Subject: [PATCH 301/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.6.1 → v1.7.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.6.1...v1.7.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 858be1ba..5547ec1f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + rev: v1.7.0 hooks: - id: mypy additional_dependencies: [types-all] From e36cefc8bd43aaee1686d16e31ecb98f576fe121 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:01:19 +0000 Subject: [PATCH 302/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.7.0 → v1.7.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.7.0...v1.7.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5547ec1f..4433e4e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.7.0 + rev: v1.7.1 hooks: - id: mypy additional_dependencies: [types-all] From cffabe54be63f0fd05b42ae73842387d07110feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= Date: Fri, 1 Dec 2023 17:02:12 -0600 Subject: [PATCH 303/416] Address deprecation warning in `shutil.rmtree(onerror=...)` --- .github/workflows/main.yml | 2 +- pre_commit/util.py | 46 ++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6e32f6c6..2355b662 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,5 +19,5 @@ jobs: main-linux: uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 with: - env: '["py39", "py310", "py311"]' + env: '["py39", "py310", "py311", "py312"]' os: ubuntu-latest diff --git a/pre_commit/util.py b/pre_commit/util.py index 8f595841..b3682d4f 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -202,24 +202,36 @@ else: # pragma: no cover cmd_output_p = cmd_output_b -def rmtree(path: str) -> None: - """On windows, rmtree fails for readonly dirs.""" - def handle_remove_readonly( - func: Callable[..., Any], - path: str, - exc: tuple[type[OSError], OSError, TracebackType], +def _handle_readonly( + func: Callable[[str], object], + path: str, + exc: OSError, +) -> None: + if ( + func in (os.rmdir, os.remove, os.unlink) and + exc.errno in {errno.EACCES, errno.EPERM} + ): + for p in (path, os.path.dirname(path)): + os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR) + func(path) + else: + raise + + +if sys.version_info < (3, 12): # pragma: <3.12 cover + def _handle_readonly_old( + func: Callable[[str], object], + path: str, + excinfo: tuple[type[OSError], OSError, TracebackType], ) -> None: - excvalue = exc[1] - if ( - func in (os.rmdir, os.remove, os.unlink) and - excvalue.errno in {errno.EACCES, errno.EPERM} - ): - for p in (path, os.path.dirname(path)): - os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR) - func(path) - else: - raise - shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly) + return _handle_readonly(func, path, excinfo[1]) + + def rmtree(path: str) -> None: + shutil.rmtree(path, ignore_errors=False, onerror=_handle_readonly_old) +else: # pragma: >=3.12 cover + def rmtree(path: str) -> None: + """On windows, rmtree fails for readonly dirs.""" + shutil.rmtree(path, ignore_errors=False, onexc=_handle_readonly) def win_exe(s: str) -> str: From 047439abffb164edd5b49e50439fd63a625be3da Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 9 Dec 2023 15:34:16 -0500 Subject: [PATCH 304/416] attempt minimum_pre_commit_version first when parsing configs --- pre_commit/clientlib.py | 20 ++-- pre_commit/repository.py | 10 -- tests/clientlib_test.py | 195 +++++++++++++++++++++------------------ tests/repository_test.py | 28 ------ 4 files changed, 119 insertions(+), 134 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 9f41bf4b..a49465e8 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -102,6 +102,13 @@ class StagesMigration(StagesMigrationNoDefault): MANIFEST_HOOK_DICT = cfgv.Map( 'Hook', 'id', + # check first in case it uses some newer, incompatible feature + cfgv.Optional( + 'minimum_pre_commit_version', + cfgv.check_and(cfgv.check_string, check_min_version), + '0', + ), + cfgv.Required('id', cfgv.check_string), cfgv.Required('name', cfgv.check_string), cfgv.Required('entry', cfgv.check_string), @@ -124,7 +131,6 @@ MANIFEST_HOOK_DICT = cfgv.Map( cfgv.Optional('description', cfgv.check_string, ''), cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT), cfgv.Optional('log_file', cfgv.check_string, ''), - cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'), cfgv.Optional('require_serial', cfgv.check_bool, False), StagesMigration('stages', []), cfgv.Optional('verbose', cfgv.check_bool, False), @@ -345,6 +351,13 @@ DEFAULT_LANGUAGE_VERSION = cfgv.Map( CONFIG_SCHEMA = cfgv.Map( 'Config', None, + # check first in case it uses some newer, incompatible feature + cfgv.Optional( + 'minimum_pre_commit_version', + cfgv.check_and(cfgv.check_string, check_min_version), + '0', + ), + cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)), cfgv.Optional( 'default_install_hook_types', @@ -358,11 +371,6 @@ CONFIG_SCHEMA = cfgv.Map( cfgv.Optional('files', check_string_regex, ''), cfgv.Optional('exclude', check_string_regex, '^$'), cfgv.Optional('fail_fast', cfgv.check_bool, False), - cfgv.Optional( - 'minimum_pre_commit_version', - cfgv.check_and(cfgv.check_string, check_min_version), - '0', - ), cfgv.WarnAdditionalKeys( ( 'repos', diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 439a09b4..aa841856 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -12,7 +12,6 @@ from pre_commit.all_languages import languages from pre_commit.clientlib import load_manifest from pre_commit.clientlib import LOCAL from pre_commit.clientlib import META -from pre_commit.clientlib import parse_version from pre_commit.hook import Hook from pre_commit.lang_base import environment_dir from pre_commit.prefix import Prefix @@ -124,15 +123,6 @@ def _hook( for dct in rest: ret.update(dct) - version = ret['minimum_pre_commit_version'] - if parse_version(version) > parse_version(C.VERSION): - logger.error( - f'The hook `{ret["id"]}` requires pre-commit version {version} ' - f'but version {C.VERSION} is installed. ' - f'Perhaps run `pip install --upgrade pre-commit`.', - ) - exit(1) - lang = ret['language'] if ret['language_version'] == C.DEFAULT: ret['language_version'] = root_config['default_language_version'][lang] diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 568b2e97..eaa8a044 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -40,56 +40,51 @@ def test_check_type_tag_success(): @pytest.mark.parametrize( - ('config_obj', 'expected'), ( - ( - { - 'repos': [{ - 'repo': 'git@github.com:pre-commit/pre-commit-hooks', - 'rev': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37', - 'hooks': [{'id': 'pyflakes', 'files': '\\.py$'}], - }], - }, - True, - ), - ( - { - 'repos': [{ - 'repo': 'git@github.com:pre-commit/pre-commit-hooks', - 'rev': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37', - 'hooks': [ - { - 'id': 'pyflakes', - 'files': '\\.py$', - 'args': ['foo', 'bar', 'baz'], - }, - ], - }], - }, - True, - ), - ( - { - 'repos': [{ - 'repo': 'git@github.com:pre-commit/pre-commit-hooks', - 'rev': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37', - 'hooks': [ - { - 'id': 'pyflakes', - 'files': '\\.py$', - # Exclude pattern must be a string - 'exclude': 0, - 'args': ['foo', 'bar', 'baz'], - }, - ], - }], - }, - False, - ), + 'cfg', + ( + { + 'repos': [{ + 'repo': 'git@github.com:pre-commit/pre-commit-hooks', + 'rev': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37', + 'hooks': [{'id': 'pyflakes', 'files': '\\.py$'}], + }], + }, + { + 'repos': [{ + 'repo': 'git@github.com:pre-commit/pre-commit-hooks', + 'rev': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37', + 'hooks': [ + { + 'id': 'pyflakes', + 'files': '\\.py$', + 'args': ['foo', 'bar', 'baz'], + }, + ], + }], + }, ), ) -def test_config_valid(config_obj, expected): - ret = is_valid_according_to_schema(config_obj, CONFIG_SCHEMA) - assert ret is expected +def test_config_valid(cfg): + assert is_valid_according_to_schema(cfg, CONFIG_SCHEMA) + + +def test_invalid_config_wrong_type(): + cfg = { + 'repos': [{ + 'repo': 'git@github.com:pre-commit/pre-commit-hooks', + 'rev': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37', + 'hooks': [ + { + 'id': 'pyflakes', + 'files': '\\.py$', + # Exclude pattern must be a string + 'exclude': 0, + 'args': ['foo', 'bar', 'baz'], + }, + ], + }], + } + assert not is_valid_according_to_schema(cfg, CONFIG_SCHEMA) def test_local_hooks_with_rev_fails(): @@ -198,14 +193,13 @@ def test_warn_mutable_rev_conditional(): ), ) def test_sensible_regex_validators_dont_pass_none(validator_cls): - key = 'files' + validator = validator_cls('files', cfgv.check_string) with pytest.raises(cfgv.ValidationError) as excinfo: - validator = validator_cls(key, cfgv.check_string) - validator.check({key: None}) + validator.check({'files': None}) assert str(excinfo.value) == ( '\n' - f'==> At key: {key}' + '==> At key: files' '\n' '=====> Expected string got NoneType' ) @@ -298,46 +292,36 @@ def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning): @pytest.mark.parametrize( - ('manifest_obj', 'expected'), + 'manifest_obj', ( - ( - [{ - 'id': 'a', - 'name': 'b', - 'entry': 'c', - 'language': 'python', - 'files': r'\.py$', - }], - True, - ), - ( - [{ - 'id': 'a', - 'name': 'b', - 'entry': 'c', - 'language': 'python', - 'language_version': 'python3.4', - 'files': r'\.py$', - }], - True, - ), - ( - # A regression in 0.13.5: always_run and files are permissible - [{ - 'id': 'a', - 'name': 'b', - 'entry': 'c', - 'language': 'python', - 'files': '', - 'always_run': True, - }], - True, - ), + [{ + 'id': 'a', + 'name': 'b', + 'entry': 'c', + 'language': 'python', + 'files': r'\.py$', + }], + [{ + 'id': 'a', + 'name': 'b', + 'entry': 'c', + 'language': 'python', + 'language_version': 'python3.4', + 'files': r'\.py$', + }], + # A regression in 0.13.5: always_run and files are permissible + [{ + 'id': 'a', + 'name': 'b', + 'entry': 'c', + 'language': 'python', + 'files': '', + 'always_run': True, + }], ), ) -def test_valid_manifests(manifest_obj, expected): - ret = is_valid_according_to_schema(manifest_obj, MANIFEST_SCHEMA) - assert ret is expected +def test_valid_manifests(manifest_obj): + assert is_valid_according_to_schema(manifest_obj, MANIFEST_SCHEMA) @pytest.mark.parametrize( @@ -393,8 +377,39 @@ def test_parse_version(): def test_minimum_pre_commit_version_failing(): + cfg = {'repos': [], 'minimum_pre_commit_version': '999'} + with pytest.raises(cfgv.ValidationError) as excinfo: + cfgv.validate(cfg, CONFIG_SCHEMA) + assert str(excinfo.value) == ( + f'\n' + f'==> At Config()\n' + f'==> At key: minimum_pre_commit_version\n' + f'=====> pre-commit version 999 is required but version {C.VERSION} ' + f'is installed. Perhaps run `pip install --upgrade pre-commit`.' + ) + + +def test_minimum_pre_commit_version_failing_in_config(): + cfg = {'repos': [sample_local_config()]} + cfg['repos'][0]['hooks'][0]['minimum_pre_commit_version'] = '999' + with pytest.raises(cfgv.ValidationError) as excinfo: + cfgv.validate(cfg, CONFIG_SCHEMA) + assert str(excinfo.value) == ( + f'\n' + f'==> At Config()\n' + f'==> At key: repos\n' + f"==> At Repository(repo='local')\n" + f'==> At key: hooks\n' + f"==> At Hook(id='do_not_commit')\n" + f'==> At key: minimum_pre_commit_version\n' + f'=====> pre-commit version 999 is required but version {C.VERSION} ' + f'is installed. Perhaps run `pip install --upgrade pre-commit`.' + ) + + +def test_minimum_pre_commit_version_failing_before_other_error(): + cfg = {'repos': 5, 'minimum_pre_commit_version': '999'} with pytest.raises(cfgv.ValidationError) as excinfo: - cfg = {'repos': [], 'minimum_pre_commit_version': '999'} cfgv.validate(cfg, CONFIG_SCHEMA) assert str(excinfo.value) == ( f'\n' diff --git a/tests/repository_test.py b/tests/repository_test.py index b8dde99b..ac065ec4 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -9,7 +9,6 @@ from unittest import mock import cfgv import pytest -import re_assert import pre_commit.constants as C from pre_commit import lang_base @@ -27,7 +26,6 @@ from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b from testing.fixtures import make_config_from_repo from testing.fixtures import make_repo -from testing.fixtures import modify_manifest from testing.language_helpers import run_language from testing.util import cwd from testing.util import get_resource_path @@ -433,32 +431,6 @@ def test_hook_id_not_present(tempdir_factory, store, caplog): ) -def test_too_new_version(tempdir_factory, store, caplog): - path = make_repo(tempdir_factory, 'script_hooks_repo') - with modify_manifest(path) as manifest: - manifest[0]['minimum_pre_commit_version'] = '999.0.0' - config = make_config_from_repo(path) - with pytest.raises(SystemExit): - _get_hook(config, store, 'bash_hook') - _, msg = caplog.messages - pattern = re_assert.Matches( - r'^The hook `bash_hook` requires pre-commit version 999\.0\.0 but ' - r'version \d+\.\d+\.\d+ is installed. ' - r'Perhaps run `pip install --upgrade pre-commit`\.$', - ) - pattern.assert_matches(msg) - - -@pytest.mark.parametrize('version', ('0.1.0', C.VERSION)) -def test_versions_ok(tempdir_factory, store, version): - path = make_repo(tempdir_factory, 'script_hooks_repo') - with modify_manifest(path) as manifest: - manifest[0]['minimum_pre_commit_version'] = version - config = make_config_from_repo(path) - # Should succeed - _get_hook(config, store, 'bash_hook') - - def test_manifest_hooks(tempdir_factory, store): path = make_repo(tempdir_factory, 'script_hooks_repo') config = make_config_from_repo(path) From 08478ec176b705d17e3f7b0608d155e9dadff9bf Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 9 Dec 2023 16:04:25 -0500 Subject: [PATCH 305/416] python 3.9+: use removeprefix --- pre_commit/languages/python.py | 4 ++-- pre_commit/languages/rust.py | 2 +- tests/commands/install_uninstall_test.py | 10 ++++++---- tests/store_test.py | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index e5bac9fa..9f4bf69a 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -65,7 +65,7 @@ def _find_by_py_launcher( version: str, ) -> str | None: # pragma: no cover (windows only) if version.startswith('python'): - num = version[len('python'):] + num = version.removeprefix('python') cmd = ('py', f'-{num}', '-c', 'import sys; print(sys.executable)') env = dict(os.environ, PYTHONIOENCODING='UTF-8') try: @@ -124,7 +124,7 @@ def _sys_executable_matches(version: str) -> bool: return False try: - info = tuple(int(p) for p in version[len('python'):].split('.')) + info = tuple(int(p) for p in version.removeprefix('python').split('.')) except ValueError: return False diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 241146c5..7b04d6c2 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -134,7 +134,7 @@ def install_environment( packages_to_install: set[tuple[str, ...]] = {('--path', '.')} for cli_dep in cli_deps: - cli_dep = cli_dep[len('cli:'):] + cli_dep = cli_dep.removeprefix('cli:') package, _, crate_version = cli_dep.partition(':') if crate_version != '': packages_to_install.add((package, '--version', crate_version)) diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py index 8b0d3ece..9eb0e741 100644 --- a/tests/commands/install_uninstall_test.py +++ b/tests/commands/install_uninstall_test.py @@ -349,8 +349,9 @@ def test_install_existing_hooks_no_overwrite(tempdir_factory, store): # We should run both the legacy and pre-commit hooks ret, output = _get_commit_output(tempdir_factory) assert ret == 0 - assert output.startswith('legacy hook\n') - NORMAL_PRE_COMMIT_RUN.assert_matches(output[len('legacy hook\n'):]) + legacy = 'legacy hook\n' + assert output.startswith(legacy) + NORMAL_PRE_COMMIT_RUN.assert_matches(output.removeprefix(legacy)) def test_legacy_overwriting_legacy_hook(tempdir_factory, store): @@ -375,8 +376,9 @@ def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory, store): # We should run both the legacy and pre-commit hooks ret, output = _get_commit_output(tempdir_factory) assert ret == 0 - assert output.startswith('legacy hook\n') - NORMAL_PRE_COMMIT_RUN.assert_matches(output[len('legacy hook\n'):]) + legacy = 'legacy hook\n' + assert output.startswith(legacy) + NORMAL_PRE_COMMIT_RUN.assert_matches(output.removeprefix(legacy)) def test_install_with_existing_non_utf8_script(tmpdir, store): diff --git a/tests/store_test.py b/tests/store_test.py index eaab9400..45ec7327 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -185,7 +185,7 @@ def test_db_repo_name(store): def test_local_resources_reflects_reality(): on_disk = { - res[len('empty_template_'):] + res.removeprefix('empty_template_') for res in os.listdir('pre_commit/resources') if res.startswith('empty_template_') } From 9c9983dba00bf67d1b2625f1f0e9112afc063849 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 9 Dec 2023 16:24:52 -0500 Subject: [PATCH 306/416] v3.6.0 --- CHANGELOG.md | 18 ++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a1b61a4..340ac476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +3.6.0 - 2023-12-09 +================== + +### Features +- Check `minimum_pre_commit_version` first when parsing configs. + - #3092 PR by @asottile. + +### Fixes +- Fix deprecation warnings for `importlib.resources`. + - #3043 PR by @asottile. +- Fix deprecation warnings for rmtree. + - #3079 PR by @edgarrmondragon. + +### Updating +- Drop support for python<3.9. + - #3042 PR by @asottile. + - #3093 PR by @asottile. + 3.5.0 - 2023-10-13 ================== diff --git a/setup.cfg b/setup.cfg index 3110881f..24b94e2e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.5.0 +version = 3.6.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 9cce2834221364d4287a38469632c835142dbd62 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 20:20:03 +0000 Subject: [PATCH 307/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.7.1 → v1.8.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.7.1...v1.8.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4433e4e2..2245fea1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.7.1 + rev: v1.8.0 hooks: - id: mypy additional_dependencies: [types-all] From 9682f93e317639846cdae13b828b3d07d35e3eed Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 20:21:06 +0000 Subject: [PATCH 308/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 6.1.0 → 7.0.0](https://github.com/PyCQA/flake8/compare/6.1.0...7.0.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2245fea1..9cbda101 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From 3388e2dbdf8f95d280b837db8cb9e4f7e7680bd0 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Fri, 12 Jan 2024 17:30:01 +0100 Subject: [PATCH 309/416] Pop PYTHONEXECUTABLE --- pre_commit/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pre_commit/main.py b/pre_commit/main.py index 18c978a8..50a2e519 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -37,6 +37,9 @@ logger = logging.getLogger('pre_commit') # pyvenv os.environ.pop('__PYVENV_LAUNCHER__', None) +# https://github.com/getsentry/snuba/pull/5388 +os.environ.pop("PYTHONEXECUTABLE", None) + COMMANDS_NO_GIT = { 'clean', 'gc', 'init-templatedir', 'sample-config', 'validate-config', 'validate-manifest', From 96e0712f432ebf118a8f2963570586590d832e85 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:32:43 +0000 Subject: [PATCH 310/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pre_commit/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit/main.py b/pre_commit/main.py index 50a2e519..559c927c 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -38,7 +38,7 @@ logger = logging.getLogger('pre_commit') os.environ.pop('__PYVENV_LAUNCHER__', None) # https://github.com/getsentry/snuba/pull/5388 -os.environ.pop("PYTHONEXECUTABLE", None) +os.environ.pop('PYTHONEXECUTABLE', None) COMMANDS_NO_GIT = { 'clean', 'gc', 'init-templatedir', 'sample-config', From 032d8e2704c9e77c04083cbcca92623a2f1e084f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 10 Feb 2024 14:01:09 -0500 Subject: [PATCH 311/416] staged_files_only can handle a crlf-only diff --- pre_commit/staged_files_only.py | 5 +++++ tests/staged_files_only_test.py | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index fd28e1c2..e1f81ba9 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -59,6 +59,11 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: # There weren't any staged files so we don't need to do anything # special yield + elif retcode == 1 and not diff_stdout.strip(): + # due to behaviour (probably a bug?) in git with crlf endings and + # autocrlf set to either `true` or `input` sometimes git will refuse + # to show a crlf-only diff to us :( + yield elif retcode == 1 and diff_stdout.strip(): patch_filename = f'patch{int(time.time())}-{os.getpid()}' patch_filename = os.path.join(patch_dir, patch_filename) diff --git a/tests/staged_files_only_test.py b/tests/staged_files_only_test.py index 58dbe5ac..cd2f6387 100644 --- a/tests/staged_files_only_test.py +++ b/tests/staged_files_only_test.py @@ -358,6 +358,21 @@ def test_crlf(in_git_dir, patch_dir, crlf_before, crlf_after, autocrlf): assert_no_diff() +@pytest.mark.parametrize('autocrlf', ('true', 'input')) +def test_crlf_diff_only(in_git_dir, patch_dir, autocrlf): + # due to a quirk (?) in git -- a diff only in crlf does not show but + # still results in an exit code of `1` + # we treat this as "no diff" -- though ideally it would discard the diff + # while committing + cmd_output('git', 'config', '--local', 'core.autocrlf', autocrlf) + + _write(b'1\r\n2\r\n3\r\n') + cmd_output('git', 'add', 'foo') + _write(b'1\n2\n3\n') + with staged_files_only(patch_dir): + pass + + def test_whitespace_errors(in_git_dir, patch_dir): cmd_output('git', 'config', '--local', 'apply.whitespace', 'error') test_crlf(in_git_dir, patch_dir, True, True, 'true') From 15bd0c7993587dc7d739ac6b1ab939eb9639bc1e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 10 Feb 2024 14:45:43 -0500 Subject: [PATCH 312/416] v3.6.1 --- CHANGELOG.md | 10 ++++++++++ setup.cfg | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 340ac476..be2fee60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +3.6.1 - 2024-02-10 +================== + +### Fixes +- Remove `PYTHONEXECUTABLE` from environment when running. + - #3110 PR by @untitaker. +- Handle staged-files-only with only a crlf diff. + - #3126 PR by @asottile. + - issue by @tyyrok. + 3.6.0 - 2023-12-09 ================== diff --git a/setup.cfg b/setup.cfg index 24b94e2e..2002a681 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.6.0 +version = 3.6.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 61d9c95cc17cb391855d17cf382feb079372644e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 18 Feb 2024 13:03:44 -0500 Subject: [PATCH 313/416] fix building golang hooks during `commit --all` --- pre_commit/languages/golang.py | 3 ++- tests/languages/golang_test.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 4c13d8f9..66e07cf7 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -23,6 +23,7 @@ from pre_commit import lang_base from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var +from pre_commit.git import no_git_env from pre_commit.prefix import Prefix from pre_commit.util import cmd_output from pre_commit.util import rmtree @@ -141,7 +142,7 @@ def install_environment( else: gopath = env_dir - env = dict(os.environ, GOPATH=gopath) + env = no_git_env(dict(os.environ, GOPATH=gopath)) env.pop('GOBIN', None) if version != 'system': env['GOROOT'] = os.path.join(env_dir, '.go') diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 19e9f62f..02e35d71 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -7,10 +7,16 @@ import re_assert import pre_commit.constants as C from pre_commit import lang_base +from pre_commit.commands.install_uninstall import install from pre_commit.envcontext import envcontext from pre_commit.languages import golang from pre_commit.store import _make_local_repo +from pre_commit.util import cmd_output +from testing.fixtures import add_config_to_repo +from testing.fixtures import make_config_from_repo from testing.language_helpers import run_language +from testing.util import cmd_output_mocked_pre_commit_home +from testing.util import git_commit ACTUAL_GET_DEFAULT_VERSION = golang.get_default_version.__wrapped__ @@ -134,3 +140,28 @@ def test_local_golang_additional_deps(tmp_path): def test_golang_hook_still_works_when_gobin_is_set(tmp_path): with envcontext((('GOBIN', str(tmp_path.joinpath('gobin'))),)): test_golang_system(tmp_path) + + +def test_during_commit_all(tmp_path, tempdir_factory, store, in_git_dir): + hook_dir = tmp_path.joinpath('hook') + hook_dir.mkdir() + _make_hello_world(hook_dir) + hook_dir.joinpath('.pre-commit-hooks.yaml').write_text( + '- id: hello-world\n' + ' name: hello world\n' + ' entry: golang-hello-world\n' + ' language: golang\n' + ' always_run: true\n', + ) + cmd_output('git', 'init', hook_dir) + cmd_output('git', 'add', '.', cwd=hook_dir) + git_commit(cwd=hook_dir) + + add_config_to_repo(in_git_dir, make_config_from_repo(hook_dir)) + + assert not install(C.CONFIG_FILE, store, hook_types=['pre-commit']) + + git_commit( + fn=cmd_output_mocked_pre_commit_home, + tempdir_factory=tempdir_factory, + ) From e5257268558a1e83731232b1ec4276a24ba870dc Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 18 Feb 2024 13:19:11 -0500 Subject: [PATCH 314/416] v3.6.2 --- CHANGELOG.md | 8 ++++++++ setup.cfg | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be2fee60..6c2ee949 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +3.6.2 - 2024-02-18 +================== + +### Fixes +- Fix building golang hooks during `git commit --all`. + - #3130 PR by @asottile. + - #2722 issue by @pestanko and @matthewhughes934. + 3.6.1 - 2024-02-10 ================== diff --git a/setup.cfg b/setup.cfg index 2002a681..a447bbb9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.6.1 +version = 3.6.2 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From a768c038e3ac1a6bdf04f7f2c38e7e87bf6a57ee Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 00:02:29 +0000 Subject: [PATCH 315/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.15.0 → v3.15.1](https://github.com/asottile/pyupgrade/compare/v3.15.0...v3.15.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9cbda101..c428788e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 + rev: v3.15.1 hooks: - id: pyupgrade args: [--py39-plus] From e58009684cfc4842028e99d34837e2722af39b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Lehmann?= Date: Wed, 7 Feb 2024 11:18:24 +0100 Subject: [PATCH 316/416] give docker a tty output when expecting color this makes the behavior more consistent with the system language and would help the executable run in a docker container to produce a colored output. --- pre_commit/languages/docker.py | 9 +++++++-- pre_commit/languages/docker_image.py | 2 +- tests/languages/docker_image_test.py | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 26328515..4de1d582 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -108,10 +108,15 @@ def get_docker_user() -> tuple[str, ...]: # pragma: win32 no cover return () -def docker_cmd() -> tuple[str, ...]: # pragma: win32 no cover +def get_docker_tty(*, color: bool) -> tuple[str, ...]: # pragma: win32 no cover # noqa: E501 + return (('--tty',) if color else ()) + + +def docker_cmd(*, color: bool) -> tuple[str, ...]: # pragma: win32 no cover return ( 'docker', 'run', '--rm', + *get_docker_tty(color=color), *get_docker_user(), # https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from # The `Z` option tells Docker to label the content with a private @@ -139,7 +144,7 @@ def run_hook( entry_tag = ('--entrypoint', entry_exe, docker_tag(prefix)) return lang_base.run_xargs( - (*docker_cmd(), *entry_tag, *cmd_rest), + (*docker_cmd(color=color), *entry_tag, *cmd_rest), file_args, require_serial=require_serial, color=color, diff --git a/pre_commit/languages/docker_image.py b/pre_commit/languages/docker_image.py index a1a2c169..60caa101 100644 --- a/pre_commit/languages/docker_image.py +++ b/pre_commit/languages/docker_image.py @@ -23,7 +23,7 @@ def run_hook( require_serial: bool, color: bool, ) -> tuple[int, bytes]: # pragma: win32 no cover - cmd = docker_cmd() + lang_base.hook_cmd(entry, args) + cmd = docker_cmd(color=color) + lang_base.hook_cmd(entry, args) return lang_base.run_xargs( cmd, file_args, diff --git a/tests/languages/docker_image_test.py b/tests/languages/docker_image_test.py index 7993c11a..4e3a8789 100644 --- a/tests/languages/docker_image_test.py +++ b/tests/languages/docker_image_test.py @@ -25,3 +25,27 @@ def test_docker_image_hook_via_args(tmp_path): args=('hello hello world',), ) assert ret == (0, b'hello hello world\n') + + +@xfailif_windows # pragma: win32 no cover +def test_docker_image_color_tty(tmp_path): + ret = run_language( + tmp_path, + docker_image, + 'ubuntu:22.04', + args=('grep', '--color', 'root', '/etc/group'), + color=True, + ) + assert ret == (0, b'\x1b[01;31m\x1b[Kroot\x1b[m\x1b[K:x:0:\n') + + +@xfailif_windows # pragma: win32 no cover +def test_docker_image_no_color_no_tty(tmp_path): + ret = run_language( + tmp_path, + docker_image, + 'ubuntu:22.04', + args=('grep', '--color', 'root', '/etc/group'), + color=False, + ) + assert ret == (0, b'root:x:0:\n') From 75b3e52e57b5d6fc7bef10c131204edf196ae17a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 00:16:12 +0000 Subject: [PATCH 317/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.8.0 → v1.9.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.8.0...v1.9.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c428788e..229c0a8a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.9.0 hooks: - id: mypy additional_dependencies: [types-all] From 0939c11b4f0488ae3bff9b67aed67ea744189412 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:47:27 +0000 Subject: [PATCH 318/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/hhatto/autopep8: v2.0.4 → v2.1.0](https://github.com/hhatto/autopep8/compare/v2.0.4...v2.1.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 229c0a8a..8a0ad8d7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 - rev: v2.0.4 + rev: v2.1.0 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From fc622159a6c5cd31919ed2a22fa1c11d8ca56dbf Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 24 Mar 2024 13:17:00 -0400 Subject: [PATCH 319/416] fix per-hook fail_fast to not fail on previous failures --- pre_commit/commands/run.py | 2 +- tests/commands/run_test.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 076f16d8..2a08dff0 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -298,7 +298,7 @@ def _run_hooks( verbose=args.verbose, use_color=args.color, ) retval |= current_retval - if retval and (config['fail_fast'] or hook.fail_fast): + if current_retval and (config['fail_fast'] or hook.fail_fast): break if retval and args.show_diff_on_failure and prior_diff: if args.all_files: diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index e36a3ca9..50a20f37 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -1088,6 +1088,22 @@ def test_fail_fast_per_hook(cap_out, store, repo_with_failing_hook): assert printed.count(b'Failing hook') == 1 +def test_fail_fast_not_prev_failures(cap_out, store, repo_with_failing_hook): + with modify_config() as config: + config['repos'].append({ + 'repo': 'meta', + 'hooks': [ + {'id': 'identity', 'fail_fast': True}, + {'id': 'identity', 'name': 'run me!'}, + ], + }) + stage_a_file() + + ret, printed = _do_run(cap_out, store, repo_with_failing_hook, run_opts()) + # should still run the last hook since the `fail_fast` one didn't fail + assert printed.count(b'run me!') == 1 + + def test_classifier_removes_dne(): classifier = Classifier(('this_file_does_not_exist',)) assert classifier.filenames == [] From 7b4667e9e6e05e31707c404c95115b151745866c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 24 Mar 2024 13:37:19 -0400 Subject: [PATCH 320/416] v3.7.0 --- CHANGELOG.md | 17 +++++++++++++++++ setup.cfg | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c2ee949..076e1631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +3.7.0 - 2024-03-24 +================== + +### Features +- Use a tty for `docker` and `docker_image` hooks when `--color` is specified. + - #3122 PR by @glehmann. + +### Fixes +- Fix `fail_fast` for individual hooks stopping when previous hooks had failed. + - #3167 issue by @tp832944. + - #3168 PR by @asottile. + +### Updating +- The per-hook behaviour of `fail_fast` was fixed. If you want the pre-3.7.0 + behaviour, add `fail_fast: true` to all hooks before the last `fail_fast` + hook. + 3.6.2 - 2024-02-18 ================== diff --git a/setup.cfg b/setup.cfg index a447bbb9..0e155601 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.6.2 +version = 3.7.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 4e121ef25c21a8caaca8304cc683e382cacd48f4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:31:39 +0000 Subject: [PATCH 321/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.15.1 → v3.15.2](https://github.com/asottile/pyupgrade/compare/v3.15.1...v3.15.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a0ad8d7..9cd3b47b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 + rev: v3.15.2 hooks: - id: pyupgrade args: [--py39-plus] From 74d05b444de75367eaf630e099f15aa51e060dc1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 22:08:29 +0000 Subject: [PATCH 322/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v4.6.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9cd3b47b..93f70f87 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 0d4c6da36e96443f05ae2d1f6c4e63d1a5d2b652 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 29 Apr 2024 21:05:41 -0400 Subject: [PATCH 323/416] adjust _handle_readonly for typeshed updates --- pre_commit/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pre_commit/util.py b/pre_commit/util.py index b3682d4f..b75c84a2 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -205,10 +205,11 @@ else: # pragma: no cover def _handle_readonly( func: Callable[[str], object], path: str, - exc: OSError, + exc: Exception, ) -> None: if ( func in (os.rmdir, os.remove, os.unlink) and + isinstance(exc, OSError) and exc.errno in {errno.EACCES, errno.EPERM} ): for p in (path, os.path.dirname(path)): @@ -222,7 +223,7 @@ if sys.version_info < (3, 12): # pragma: <3.12 cover def _handle_readonly_old( func: Callable[[str], object], path: str, - excinfo: tuple[type[OSError], OSError, TracebackType], + excinfo: tuple[type[Exception], Exception, TracebackType], ) -> None: return _handle_readonly(func, path, excinfo[1]) From 5c3d006443d616f5b9a717a43a6f3bce60381ddf Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 29 Apr 2024 21:28:16 -0400 Subject: [PATCH 324/416] use a simpler gem for testing additional_dependencies tins required building bigdecimal, whereas jmespath is self-contained --- tests/languages/ruby_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/languages/ruby_test.py b/tests/languages/ruby_test.py index 6397a434..5d767b25 100644 --- a/tests/languages/ruby_test.py +++ b/tests/languages/ruby_test.py @@ -91,8 +91,8 @@ def test_ruby_additional_deps(tmp_path): tmp_path, ruby, 'ruby -e', - args=('require "tins"',), - deps=('tins',), + args=('require "jmespath"',), + deps=('jmespath',), ) assert ret == (0, b'') From 0142f453224801138448584a8517927194865330 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:03:55 +0000 Subject: [PATCH 325/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.9.0 → v1.10.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.9.0...v1.10.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93f70f87..6caee40d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 + rev: v1.10.0 hooks: - id: mypy additional_dependencies: [types-all] From 296f59266ec656fe46bf0d1b2bce6aac89476476 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 10 May 2024 17:06:29 -0400 Subject: [PATCH 326/416] determine rust default language version independent of rust-toolchain.toml --- pre_commit/languages/rust.py | 2 +- tests/languages/rust_test.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 7b04d6c2..5f9db8fb 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -34,7 +34,7 @@ def get_default_version() -> str: # Just detecting the executable does not suffice, because if rustup is # installed but no toolchain is available, then `cargo` exists but # cannot be used without installing a toolchain first. - if cmd_output_b('cargo', '--version', check=False)[0] == 0: + if cmd_output_b('cargo', '--version', check=False, cwd='/')[0] == 0: return 'system' else: return C.DEFAULT diff --git a/tests/languages/rust_test.py b/tests/languages/rust_test.py index 5c17f5b6..52e35613 100644 --- a/tests/languages/rust_test.py +++ b/tests/languages/rust_test.py @@ -9,6 +9,7 @@ from pre_commit import parse_shebang from pre_commit.languages import rust from pre_commit.store import _make_local_repo from testing.language_helpers import run_language +from testing.util import cwd ACTUAL_GET_DEFAULT_VERSION = rust.get_default_version.__wrapped__ @@ -29,6 +30,14 @@ def test_uses_default_when_rust_is_not_available(cmd_output_b_mck): assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT +def test_selects_system_even_if_rust_toolchain_toml(tmp_path): + toolchain_toml = '[toolchain]\nchannel = "wtf"\n' + tmp_path.joinpath('rust-toolchain.toml').write_text(toolchain_toml) + + with cwd(tmp_path): + assert ACTUAL_GET_DEFAULT_VERSION() == 'system' + + def _make_hello_world(tmp_path): src_dir = tmp_path.joinpath('src') src_dir.mkdir() From 9ee076835365c0b3aa700de8f574def623826385 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 10 May 2024 21:24:51 -0400 Subject: [PATCH 327/416] v3.7.1 --- CHANGELOG.md | 9 +++++++++ setup.cfg | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 076e1631..81d5b33e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +3.7.1 - 2024-05-10 +================== + +### Fixes +- Fix `language: rust` default language version check when `rust-toolchain.toml` + is present. + - issue by @gaborbernat. + - #3201 PR by @asottile. + 3.7.0 - 2024-03-24 ================== diff --git a/setup.cfg b/setup.cfg index 0e155601..83c09acd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.7.0 +version = 3.7.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 5526bb21377dc3e4a59451a55d0d729644eac462 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 21:34:15 +0000 Subject: [PATCH 328/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/hhatto/autopep8: v2.1.0 → v2.1.1](https://github.com/hhatto/autopep8/compare/v2.1.0...v2.1.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6caee40d..eebeea99 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 - rev: v2.1.0 + rev: v2.1.1 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From 1f128556e4ac2fae84133b9a4f085a8044a44382 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:47:18 +0000 Subject: [PATCH 329/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder-python-imports: v3.12.0 → v3.13.0](https://github.com/asottile/reorder-python-imports/compare/v3.12.0...v3.13.0) - [github.com/hhatto/autopep8: v2.1.1 → v2.2.0](https://github.com/hhatto/autopep8/compare/v2.1.1...v2.2.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eebeea99..0467fa39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.12.0 + rev: v3.13.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -29,7 +29,7 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 - rev: v2.1.1 + rev: v2.2.0 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From 9dd247898c86405b68705595d8a3c8911be39d57 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:56:51 +0000 Subject: [PATCH 330/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.15.2 → v3.16.0](https://github.com/asottile/pyupgrade/compare/v3.15.2...v3.16.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0467fa39..6282056f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.15.2 + rev: v3.16.0 hooks: - id: pyupgrade args: [--py39-plus] From 49a9664cd0e393fb3bc5e1023bee801cc3e6fc6a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:57:20 +0000 Subject: [PATCH 331/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/hhatto/autopep8: v2.2.0 → v2.3.0](https://github.com/hhatto/autopep8/compare/v2.2.0...v2.3.0) - [github.com/PyCQA/flake8: 7.0.0 → 7.1.0](https://github.com/PyCQA/flake8/compare/7.0.0...7.1.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6282056f..b11a1dce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,11 +29,11 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 - rev: v2.2.0 + rev: v2.3.0 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 7.0.0 + rev: 7.1.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From 69b5dce12ab0674cd7a622ca8b55f1afa720211b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 21:49:02 +0000 Subject: [PATCH 332/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/hhatto/autopep8: v2.3.0 → v2.3.1](https://github.com/hhatto/autopep8/compare/v2.3.0...v2.3.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b11a1dce..1f734f8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 - rev: v2.3.0 + rev: v2.3.1 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From f632459bc67834a200aac26f1129fc16f82fb625 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 23:34:14 +0000 Subject: [PATCH 333/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.10.0 → v1.10.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.0...v1.10.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1f734f8c..f987dfe8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.10.1 hooks: - id: mypy additional_dependencies: [types-all] From 88317ddb34ac8c60b4be7e22198fb550dcae995e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:04:19 +0000 Subject: [PATCH 334/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.10.1 → v1.11.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.1...v1.11.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f987dfe8..a628f4f4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.1 + rev: v1.11.0 hooks: - id: mypy additional_dependencies: [types-all] From a68a19d217d0d1067828622fde9044d9502693b3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 28 Jul 2024 14:50:24 -0400 Subject: [PATCH 335/416] fixes for mypy 1.11 --- .pre-commit-config.yaml | 2 +- pre_commit/util.py | 4 ++-- tests/conftest.py | 25 +++++++------------------ 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a628f4f4..1a9a8fef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,5 +40,5 @@ repos: rev: v1.11.0 hooks: - id: mypy - additional_dependencies: [types-all] + additional_dependencies: [types-pyyaml] exclude: ^testing/resources/ diff --git a/pre_commit/util.py b/pre_commit/util.py index b75c84a2..12aa3c0e 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -205,7 +205,7 @@ else: # pragma: no cover def _handle_readonly( func: Callable[[str], object], path: str, - exc: Exception, + exc: BaseException, ) -> None: if ( func in (os.rmdir, os.remove, os.unlink) and @@ -223,7 +223,7 @@ if sys.version_info < (3, 12): # pragma: <3.12 cover def _handle_readonly_old( func: Callable[[str], object], path: str, - excinfo: tuple[type[Exception], Exception, TracebackType], + excinfo: tuple[type[BaseException], BaseException, TracebackType], ) -> None: return _handle_readonly(func, path, excinfo[1]) diff --git a/tests/conftest.py b/tests/conftest.py index 30761715..bd4af9a5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -209,36 +209,25 @@ def log_info_mock(): yield mck -class FakeStream: - def __init__(self): - self.data = io.BytesIO() - - def write(self, s): - self.data.write(s) - - def flush(self): - pass - - class Fixture: - def __init__(self, stream): + def __init__(self, stream: io.BytesIO) -> None: self._stream = stream - def get_bytes(self): + def get_bytes(self) -> bytes: """Get the output as-if no encoding occurred""" - data = self._stream.data.getvalue() - self._stream.data.seek(0) - self._stream.data.truncate() + data = self._stream.getvalue() + self._stream.seek(0) + self._stream.truncate() return data.replace(b'\r\n', b'\n') - def get(self): + def get(self) -> str: """Get the output assuming it was written as UTF-8 bytes""" return self.get_bytes().decode() @pytest.fixture def cap_out(): - stream = FakeStream() + stream = io.BytesIO() write = functools.partial(output.write, stream=stream) write_line_b = functools.partial(output.write_line_b, stream=stream) with mock.patch.multiple(output, write=write, write_line_b=write_line_b): From da0c1d0cfa19f6dc0d6ed97820c7cc93fe7e7c58 Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Mon, 22 Jul 2024 20:52:43 +0200 Subject: [PATCH 336/416] implement health check for language:r --- pre_commit/languages/r.py | 77 +++++++++++++++++++++++++---- tests/languages/r_test.py | 100 +++++++++++++++++++++++++++++++++----- 2 files changed, 155 insertions(+), 22 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 93b62bd5..5d18bf1c 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -14,13 +14,74 @@ from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.prefix import Prefix +from pre_commit.util import cmd_output from pre_commit.util import cmd_output_b from pre_commit.util import win_exe ENVIRONMENT_DIR = 'renv' RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ') get_default_version = lang_base.basic_get_default_version -health_check = lang_base.basic_health_check + + +def _execute_vanilla_r_code_as_script( + code: str, *, + prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str, +) -> str: + with in_env(prefix, version), _r_code_in_tempfile(code) as f: + _, out, _ = cmd_output( + _rscript_exec(), *RSCRIPT_OPTS, f, *args, cwd=cwd, + ) + return out.rstrip('\n') + + +def _read_installed_version(envdir: str, prefix: Prefix, version: str) -> str: + return _execute_vanilla_r_code_as_script( + 'cat(renv::settings$r.version())', + prefix=prefix, version=version, + cwd=envdir, + ) + + +def _read_executable_version(envdir: str, prefix: Prefix, version: str) -> str: + return _execute_vanilla_r_code_as_script( + 'cat(as.character(getRversion()))', + prefix=prefix, version=version, + cwd=envdir, + ) + + +def _write_current_r_version( + envdir: str, prefix: Prefix, version: str, +) -> None: + _execute_vanilla_r_code_as_script( + 'renv::settings$r.version(as.character(getRversion()))', + prefix=prefix, version=version, + cwd=envdir, + ) + + +def health_check(prefix: Prefix, version: str) -> str | None: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + + r_version_installation = _read_installed_version( + envdir=envdir, prefix=prefix, version=version, + ) + r_version_current_executable = _read_executable_version( + envdir=envdir, prefix=prefix, version=version, + ) + if r_version_installation in {'NULL', ''}: + return ( + f'Hooks were installed with an unknown R version. R version for ' + f'hook repo now set to {r_version_current_executable}' + ) + elif r_version_installation != r_version_current_executable: + return ( + f'Hooks were installed for R version {r_version_installation}, ' + f'but current R executable has version ' + f'{r_version_current_executable}' + ) + + return None @contextlib.contextmanager @@ -147,16 +208,14 @@ def install_environment( with _r_code_in_tempfile(r_code_inst_environment) as f: cmd_output_b(_rscript_exec(), '--vanilla', f, cwd=env_dir) + _write_current_r_version(envdir=env_dir, prefix=prefix, version=version) if additional_dependencies: r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' - with in_env(prefix, version): - with _r_code_in_tempfile(r_code_inst_add) as f: - cmd_output_b( - _rscript_exec(), *RSCRIPT_OPTS, - f, - *additional_dependencies, - cwd=env_dir, - ) + _execute_vanilla_r_code_as_script( + code=r_code_inst_add, prefix=prefix, version=version, + args=additional_dependencies, + cwd=env_dir, + ) def _inline_r_setup(code: str) -> str: diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index 02c559cb..10919e4a 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -1,14 +1,17 @@ from __future__ import annotations import os.path -import shutil +from unittest import mock import pytest +import pre_commit.constants as C from pre_commit import envcontext +from pre_commit import lang_base from pre_commit.languages import r from pre_commit.prefix import Prefix from pre_commit.store import _make_local_repo +from pre_commit.util import resource_text from pre_commit.util import win_exe from testing.language_helpers import run_language @@ -127,7 +130,8 @@ def test_path_rscript_exec_no_r_home_set(): assert r._rscript_exec() == 'Rscript' -def test_r_hook(tmp_path): +@pytest.fixture +def renv_lock_file(tmp_path): renv_lock = '''\ { "R": { @@ -157,6 +161,12 @@ def test_r_hook(tmp_path): } } ''' + tmp_path.joinpath('renv.lock').write_text(renv_lock) + yield + + +@pytest.fixture +def description_file(tmp_path): description = '''\ Package: gli.clu Title: What the Package Does (One Line, Title Case) @@ -178,27 +188,39 @@ RoxygenNote: 7.1.1 Imports: rprojroot ''' - hello_world_r = '''\ + tmp_path.joinpath('DESCRIPTION').write_text(description) + yield + + +@pytest.fixture +def hello_world_file(tmp_path): + hello_world = '''\ stopifnot( packageVersion('rprojroot') == '1.0', packageVersion('gli.clu') == '0.0.0.9000' ) cat("Hello, World, from R!\n") ''' + tmp_path.joinpath('hello-world.R').write_text(hello_world) + yield - tmp_path.joinpath('renv.lock').write_text(renv_lock) - tmp_path.joinpath('DESCRIPTION').write_text(description) - tmp_path.joinpath('hello-world.R').write_text(hello_world_r) + +@pytest.fixture +def renv_folder(tmp_path): renv_dir = tmp_path.joinpath('renv') renv_dir.mkdir() - shutil.copy( - os.path.join( - os.path.dirname(__file__), - '../../pre_commit/resources/empty_template_activate.R', - ), - renv_dir.joinpath('activate.R'), - ) + activate_r = resource_text('empty_template_activate.R') + renv_dir.joinpath('activate.R').write_text(activate_r) + yield + +def test_r_hook( + tmp_path, + renv_lock_file, + description_file, + hello_world_file, + renv_folder, +): expected = (0, b'Hello, World, from R!\n') assert run_language(tmp_path, r, 'Rscript hello-world.R') == expected @@ -221,3 +243,55 @@ Rscript -e ' args=('hi', 'hello'), ) assert ret == (0, b'hi, hello, from R!\n') + + +@pytest.fixture +def prefix(tmpdir): + yield Prefix(str(tmpdir)) + + +@pytest.fixture +def installed_environment( + renv_lock_file, + hello_world_file, + renv_folder, + prefix, +): + env_dir = lang_base.environment_dir( + prefix, r.ENVIRONMENT_DIR, r.get_default_version(), + ) + r.install_environment(prefix, C.DEFAULT, ()) + yield prefix, env_dir + + +def test_health_check_healthy(installed_environment): + # should be healthy right after creation + prefix, _ = installed_environment + assert r.health_check(prefix, C.DEFAULT) is None + + +def test_health_check_after_downgrade(installed_environment): + prefix, _ = installed_environment + + # pretend the saved installed version is old + with mock.patch.object(r, '_read_installed_version', return_value='1.0.0'): + output = r.health_check(prefix, C.DEFAULT) + + assert output is not None + assert output.startswith('Hooks were installed for R version') + + +@pytest.mark.parametrize('version', ('NULL', 'NA', "''")) +def test_health_check_without_version(prefix, installed_environment, version): + prefix, env_dir = installed_environment + + # simulate old pre-commit install by unsetting the installed version + r._execute_vanilla_r_code_as_script( + f'renv::settings$r.version({version})', + prefix=prefix, version=C.DEFAULT, cwd=env_dir, + ) + + # no R version specified fails as unhealty + msg = 'Hooks were installed with an unknown R version' + check_output = r.health_check(prefix, C.DEFAULT) + assert check_output is not None and check_output.startswith(msg) From d46423ffe14a37a06a0bcb6fe1b8294a27b6c289 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 28 Jul 2024 15:58:29 -0400 Subject: [PATCH 337/416] v3.8.0 --- CHANGELOG.md | 9 +++++++++ setup.cfg | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81d5b33e..49094bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +3.8.0 - 2024-07-28 +================== + +### Features +- Implement health checks for `language: r` so environments are recreated if + the system version of R changes. + - #3206 issue by @lorenzwalthert. + - #3265 PR by @lorenzwalthert. + 3.7.1 - 2024-05-10 ================== diff --git a/setup.cfg b/setup.cfg index 83c09acd..52b7681e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.7.1 +version = 3.8.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 9d4ab670d18f3c32ee204dbb50af74884d832ce4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:59:01 +0000 Subject: [PATCH 338/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.16.0 → v3.17.0](https://github.com/asottile/pyupgrade/compare/v3.16.0...v3.17.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1a9a8fef..16cec4cd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.16.0 + rev: v3.17.0 hooks: - id: pyupgrade args: [--py39-plus] From 917e2102be90a6384cf514ddc0edefbc563b49fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:59:19 +0000 Subject: [PATCH 339/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pre_commit/commands/run.py | 6 +++--- pre_commit/envcontext.py | 2 +- pre_commit/error_handler.py | 2 +- pre_commit/file_lock.py | 6 +++--- pre_commit/lang_base.py | 2 +- pre_commit/languages/conda.py | 2 +- pre_commit/languages/coursier.py | 2 +- pre_commit/languages/dart.py | 2 +- pre_commit/languages/dotnet.py | 4 ++-- pre_commit/languages/golang.py | 2 +- pre_commit/languages/haskell.py | 2 +- pre_commit/languages/lua.py | 2 +- pre_commit/languages/node.py | 2 +- pre_commit/languages/perl.py | 2 +- pre_commit/languages/python.py | 2 +- pre_commit/languages/r.py | 4 ++-- pre_commit/languages/ruby.py | 2 +- pre_commit/languages/rust.py | 2 +- pre_commit/languages/swift.py | 2 +- pre_commit/logging_handler.py | 2 +- pre_commit/staged_files_only.py | 6 +++--- pre_commit/store.py | 4 ++-- pre_commit/util.py | 2 +- pre_commit/xargs.py | 1 - 24 files changed, 32 insertions(+), 33 deletions(-) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 2a08dff0..793adbdb 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -61,7 +61,7 @@ def filter_by_include_exclude( names: Iterable[str], include: str, exclude: str, -) -> Generator[str, None, None]: +) -> Generator[str]: include_re, exclude_re = re.compile(include), re.compile(exclude) return ( filename for filename in names @@ -84,7 +84,7 @@ class Classifier: types: Iterable[str], types_or: Iterable[str], exclude_types: Iterable[str], - ) -> Generator[str, None, None]: + ) -> Generator[str]: types = frozenset(types) types_or = frozenset(types_or) exclude_types = frozenset(exclude_types) @@ -97,7 +97,7 @@ class Classifier: ): yield filename - def filenames_for_hook(self, hook: Hook) -> Generator[str, None, None]: + def filenames_for_hook(self, hook: Hook) -> Generator[str]: return self.by_types( filter_by_include_exclude( self.filenames, diff --git a/pre_commit/envcontext.py b/pre_commit/envcontext.py index 1f816cea..d4d24118 100644 --- a/pre_commit/envcontext.py +++ b/pre_commit/envcontext.py @@ -33,7 +33,7 @@ def format_env(parts: SubstitutionT, env: MutableMapping[str, str]) -> str: def envcontext( patch: PatchesT, _env: MutableMapping[str, str] | None = None, -) -> Generator[None, None, None]: +) -> Generator[None]: """In this context, `os.environ` is modified according to `patch`. `patch` is an iterable of 2-tuples (key, value): diff --git a/pre_commit/error_handler.py b/pre_commit/error_handler.py index 73e608b7..4f0e0573 100644 --- a/pre_commit/error_handler.py +++ b/pre_commit/error_handler.py @@ -68,7 +68,7 @@ def _log_and_exit( @contextlib.contextmanager -def error_handler() -> Generator[None, None, None]: +def error_handler() -> Generator[None]: try: yield except (Exception, KeyboardInterrupt) as e: diff --git a/pre_commit/file_lock.py b/pre_commit/file_lock.py index d3dafb4d..c840ad8b 100644 --- a/pre_commit/file_lock.py +++ b/pre_commit/file_lock.py @@ -20,7 +20,7 @@ if sys.platform == 'win32': # pragma: no cover (windows) def _locked( fileno: int, blocked_cb: Callable[[], None], - ) -> Generator[None, None, None]: + ) -> Generator[None]: try: msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region) except OSError: @@ -53,7 +53,7 @@ else: # pragma: win32 no cover def _locked( fileno: int, blocked_cb: Callable[[], None], - ) -> Generator[None, None, None]: + ) -> Generator[None]: try: fcntl.flock(fileno, fcntl.LOCK_EX | fcntl.LOCK_NB) except OSError: # pragma: no cover (tests are single-threaded) @@ -69,7 +69,7 @@ else: # pragma: win32 no cover def lock( path: str, blocked_cb: Callable[[], None], -) -> Generator[None, None, None]: +) -> Generator[None]: with open(path, 'a+') as f: with _locked(f.fileno(), blocked_cb): yield diff --git a/pre_commit/lang_base.py b/pre_commit/lang_base.py index 5303948b..95be7b9b 100644 --- a/pre_commit/lang_base.py +++ b/pre_commit/lang_base.py @@ -127,7 +127,7 @@ def no_install( @contextlib.contextmanager -def no_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def no_env(prefix: Prefix, version: str) -> Generator[None]: yield diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index 80b3e150..d397ebeb 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -41,7 +41,7 @@ def get_env_patch(env: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index 6558bf6b..08f9a958 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -70,7 +70,7 @@ def get_env_patch(target_dir: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/dart.py b/pre_commit/languages/dart.py index 129ac591..52a229ee 100644 --- a/pre_commit/languages/dart.py +++ b/pre_commit/languages/dart.py @@ -29,7 +29,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/dotnet.py b/pre_commit/languages/dotnet.py index e1202c4f..ffc65d1e 100644 --- a/pre_commit/languages/dotnet.py +++ b/pre_commit/languages/dotnet.py @@ -30,14 +30,14 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield @contextlib.contextmanager -def _nuget_config_no_sources() -> Generator[str, None, None]: +def _nuget_config_no_sources() -> Generator[str]: with tempfile.TemporaryDirectory() as tmpdir: nuget_config = os.path.join(tmpdir, 'nuget.config') with open(nuget_config, 'w') as f: diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 66e07cf7..60908796 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -121,7 +121,7 @@ def _install_go(version: str, dest: str) -> None: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir, version)): yield diff --git a/pre_commit/languages/haskell.py b/pre_commit/languages/haskell.py index c6945c82..28bca08c 100644 --- a/pre_commit/languages/haskell.py +++ b/pre_commit/languages/haskell.py @@ -24,7 +24,7 @@ def get_env_patch(target_dir: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/lua.py b/pre_commit/languages/lua.py index a475ec99..15ac1a2e 100644 --- a/pre_commit/languages/lua.py +++ b/pre_commit/languages/lua.py @@ -44,7 +44,7 @@ def get_env_patch(d: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index d49c0e32..af7dc6f8 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -59,7 +59,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/perl.py b/pre_commit/languages/perl.py index 61b1d114..a07d442a 100644 --- a/pre_commit/languages/perl.py +++ b/pre_commit/languages/perl.py @@ -33,7 +33,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 9f4bf69a..0c4bb62d 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -152,7 +152,7 @@ def norm_version(version: str) -> str | None: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 5d18bf1c..c75a3089 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -85,7 +85,7 @@ def health_check(prefix: Prefix, version: str) -> str | None: @contextlib.contextmanager -def _r_code_in_tempfile(code: str) -> Generator[str, None, None]: +def _r_code_in_tempfile(code: str) -> Generator[str]: """ To avoid quoting and escaping issues, avoid `Rscript [options] -e {expr}` but use `Rscript [options] path/to/file_with_expr.R` @@ -105,7 +105,7 @@ def get_env_patch(venv: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 0438ae09..f32fea3f 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -73,7 +73,7 @@ def get_env_patch( @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir, version)): yield diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 5f9db8fb..fd77a9d2 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -61,7 +61,7 @@ def get_env_patch(target_dir: str, version: str) -> PatchesT: @contextlib.contextmanager -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir, version)): yield diff --git a/pre_commit/languages/swift.py b/pre_commit/languages/swift.py index f7bfe84c..08a9c39a 100644 --- a/pre_commit/languages/swift.py +++ b/pre_commit/languages/swift.py @@ -27,7 +27,7 @@ def get_env_patch(venv: str) -> PatchesT: # pragma: win32 no cover @contextlib.contextmanager # pragma: win32 no cover -def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: +def in_env(prefix: Prefix, version: str) -> Generator[None]: envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): yield diff --git a/pre_commit/logging_handler.py b/pre_commit/logging_handler.py index cd33953d..74772bee 100644 --- a/pre_commit/logging_handler.py +++ b/pre_commit/logging_handler.py @@ -32,7 +32,7 @@ class LoggingHandler(logging.Handler): @contextlib.contextmanager -def logging_handler(use_color: bool) -> Generator[None, None, None]: +def logging_handler(use_color: bool) -> Generator[None]: handler = LoggingHandler(use_color) logger.addHandler(handler) logger.setLevel(logging.INFO) diff --git a/pre_commit/staged_files_only.py b/pre_commit/staged_files_only.py index e1f81ba9..99ea0979 100644 --- a/pre_commit/staged_files_only.py +++ b/pre_commit/staged_files_only.py @@ -33,7 +33,7 @@ def _git_apply(patch: str) -> None: @contextlib.contextmanager -def _intent_to_add_cleared() -> Generator[None, None, None]: +def _intent_to_add_cleared() -> Generator[None]: intent_to_add = git.intent_to_add_files() if intent_to_add: logger.warning('Unstaged intent-to-add files detected.') @@ -48,7 +48,7 @@ def _intent_to_add_cleared() -> Generator[None, None, None]: @contextlib.contextmanager -def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: +def _unstaged_changes_cleared(patch_dir: str) -> Generator[None]: tree = cmd_output('git', 'write-tree')[1].strip() diff_cmd = ( 'git', 'diff-index', '--ignore-submodules', '--binary', @@ -105,7 +105,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]: @contextlib.contextmanager -def staged_files_only(patch_dir: str) -> Generator[None, None, None]: +def staged_files_only(patch_dir: str) -> Generator[None]: """Clear any unstaged changes from the git working directory inside this context. """ diff --git a/pre_commit/store.py b/pre_commit/store.py index 84bc09a4..36cc4945 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -101,7 +101,7 @@ class Store: os.replace(tmpfile, self.db_path) @contextlib.contextmanager - def exclusive_lock(self) -> Generator[None, None, None]: + def exclusive_lock(self) -> Generator[None]: def blocked_cb() -> None: # pragma: no cover (tests are in-process) logger.info('Locking pre-commit directory') @@ -112,7 +112,7 @@ class Store: def connect( self, db_path: str | None = None, - ) -> Generator[sqlite3.Connection, None, None]: + ) -> Generator[sqlite3.Connection]: db_path = db_path or self.db_path # sqlite doesn't close its fd with its contextmanager >.< # contextlib.closing fixes this. diff --git a/pre_commit/util.py b/pre_commit/util.py index 12aa3c0e..e199d080 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -25,7 +25,7 @@ def force_bytes(exc: Any) -> bytes: @contextlib.contextmanager -def clean_path_on_failure(path: str) -> Generator[None, None, None]: +def clean_path_on_failure(path: str) -> Generator[None]: """Cleans up the directory on an exceptional failure.""" try: yield diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index 22580f59..a1345b58 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -120,7 +120,6 @@ def partition( @contextlib.contextmanager def _thread_mapper(maxsize: int) -> Generator[ Callable[[Callable[[TArg], TRet], Iterable[TArg]], Iterable[TRet]], - None, None, ]: if maxsize == 1: yield map From d5c21926ab78fd3d89f4891b29bd426f6ee80c9c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 22:39:33 +0000 Subject: [PATCH 340/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 7.1.0 → 7.1.1](https://github.com/PyCQA/flake8/compare/7.1.0...7.1.1) - [github.com/pre-commit/mirrors-mypy: v1.11.0 → v1.11.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.0...v1.11.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 16cec4cd..a6c853ca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,11 +33,11 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 7.1.0 + rev: 7.1.1 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.0 + rev: v1.11.1 hooks: - id: mypy additional_dependencies: [types-pyyaml] From c2c68d985ceac41afe63635c15789207c441614e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:18:35 +0000 Subject: [PATCH 341/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.11.1 → v1.11.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.1...v1.11.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a6c853ca..87b8551d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.11.2 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 364e6d77f051b40d22ac9071ef64bc12f3e6a1fe Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 16 Sep 2024 20:05:29 -0400 Subject: [PATCH 342/416] change migrate-config to use yaml parse tree instead --- pre_commit/commands/migrate_config.py | 58 ++++++++++++++++++++++----- pre_commit/yaml.py | 1 + pre_commit/yaml_rewrite.py | 52 ++++++++++++++++++++++++ tests/commands/migrate_config_test.py | 46 +++++++++++++++++++++ tests/yaml_rewrite_test.py | 47 ++++++++++++++++++++++ 5 files changed, 194 insertions(+), 10 deletions(-) create mode 100644 pre_commit/yaml_rewrite.py create mode 100644 tests/yaml_rewrite_test.py diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index 842fb3a7..cdce83f5 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -1,13 +1,20 @@ from __future__ import annotations -import re +import functools import textwrap +from typing import Callable import cfgv import yaml +from yaml.nodes import ScalarNode from pre_commit.clientlib import InvalidConfigError +from pre_commit.yaml import yaml_compose from pre_commit.yaml import yaml_load +from pre_commit.yaml_rewrite import MappingKey +from pre_commit.yaml_rewrite import MappingValue +from pre_commit.yaml_rewrite import match +from pre_commit.yaml_rewrite import SequenceItem def _is_header_line(line: str) -> bool: @@ -38,16 +45,48 @@ def _migrate_map(contents: str) -> str: return contents -def _migrate_sha_to_rev(contents: str) -> str: - return re.sub(r'(\n\s+)sha:', r'\1rev:', contents) +def _preserve_style(n: ScalarNode, *, s: str) -> str: + return f'{n.style}{s}{n.style}' -def _migrate_python_venv(contents: str) -> str: - return re.sub( - r'(\n\s+)language: python_venv\b', - r'\1language: python', - contents, +def _migrate_composed(contents: str) -> str: + tree = yaml_compose(contents) + rewrites: list[tuple[ScalarNode, Callable[[ScalarNode], str]]] = [] + + # sha -> rev + sha_to_rev_replace = functools.partial(_preserve_style, s='rev') + sha_to_rev_matcher = ( + MappingValue('repos'), + SequenceItem(), + MappingKey('sha'), ) + for node in match(tree, sha_to_rev_matcher): + rewrites.append((node, sha_to_rev_replace)) + + # python_venv -> python + language_matcher = ( + MappingValue('repos'), + SequenceItem(), + MappingValue('hooks'), + SequenceItem(), + MappingValue('language'), + ) + python_venv_replace = functools.partial(_preserve_style, s='python') + for node in match(tree, language_matcher): + if node.value == 'python_venv': + rewrites.append((node, python_venv_replace)) + + rewrites.sort(reverse=True, key=lambda nf: nf[0].start_mark.index) + + src_parts = [] + end: int | None = None + for node, func in rewrites: + src_parts.append(contents[node.end_mark.index:end]) + src_parts.append(func(node)) + end = node.start_mark.index + src_parts.append(contents[:end]) + src_parts.reverse() + return ''.join(src_parts) def migrate_config(config_file: str, quiet: bool = False) -> int: @@ -62,8 +101,7 @@ def migrate_config(config_file: str, quiet: bool = False) -> int: raise cfgv.ValidationError(str(e)) contents = _migrate_map(contents) - contents = _migrate_sha_to_rev(contents) - contents = _migrate_python_venv(contents) + contents = _migrate_composed(contents) if contents != orig_contents: with open(config_file, 'w') as f: diff --git a/pre_commit/yaml.py b/pre_commit/yaml.py index bdf4ec47..a5bbbc99 100644 --- a/pre_commit/yaml.py +++ b/pre_commit/yaml.py @@ -6,6 +6,7 @@ from typing import Any import yaml Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) +yaml_compose = functools.partial(yaml.compose, Loader=Loader) yaml_load = functools.partial(yaml.load, Loader=Loader) Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) diff --git a/pre_commit/yaml_rewrite.py b/pre_commit/yaml_rewrite.py new file mode 100644 index 00000000..8d0e8fdb --- /dev/null +++ b/pre_commit/yaml_rewrite.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +from collections.abc import Generator +from collections.abc import Iterable +from typing import NamedTuple +from typing import Protocol + +from yaml.nodes import MappingNode +from yaml.nodes import Node +from yaml.nodes import ScalarNode +from yaml.nodes import SequenceNode + + +class _Matcher(Protocol): + def match(self, n: Node) -> Generator[Node]: ... + + +class MappingKey(NamedTuple): + k: str + + def match(self, n: Node) -> Generator[Node]: + if isinstance(n, MappingNode): + for k, _ in n.value: + if k.value == self.k: + yield k + + +class MappingValue(NamedTuple): + k: str + + def match(self, n: Node) -> Generator[Node]: + if isinstance(n, MappingNode): + for k, v in n.value: + if k.value == self.k: + yield v + + +class SequenceItem(NamedTuple): + def match(self, n: Node) -> Generator[Node]: + if isinstance(n, SequenceNode): + yield from n.value + + +def _match(gen: Iterable[Node], m: _Matcher) -> Iterable[Node]: + return (n for src in gen for n in m.match(src)) + + +def match(n: Node, matcher: tuple[_Matcher, ...]) -> Generator[ScalarNode]: + gen: Iterable[Node] = (n,) + for m in matcher: + gen = _match(gen, m) + return (n for n in gen if isinstance(n, ScalarNode)) diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py index ba184636..c563866d 100644 --- a/tests/commands/migrate_config_test.py +++ b/tests/commands/migrate_config_test.py @@ -134,6 +134,27 @@ def test_migrate_config_sha_to_rev(tmpdir): ) +def test_migrate_config_sha_to_rev_json(tmp_path): + contents = """\ +{"repos": [{ + "repo": "https://github.com/pre-commit/pre-commit-hooks", + "sha": "v1.2.0", + "hooks": [] +}]} +""" + expected = """\ +{"repos": [{ + "repo": "https://github.com/pre-commit/pre-commit-hooks", + "rev": "v1.2.0", + "hooks": [] +}]} +""" + cfg = tmp_path.joinpath('cfg.yaml') + cfg.write_text(contents) + assert not migrate_config(str(cfg)) + assert cfg.read_text() == expected + + def test_migrate_config_language_python_venv(tmp_path): src = '''\ repos: @@ -167,6 +188,31 @@ repos: assert cfg.read_text() == expected +def test_migrate_config_quoted_python_venv(tmp_path): + src = '''\ +repos: +- repo: local + hooks: + - id: example + name: example + entry: example + language: "python_venv" +''' + expected = '''\ +repos: +- repo: local + hooks: + - id: example + name: example + entry: example + language: "python" +''' + cfg = tmp_path.joinpath('cfg.yaml') + cfg.write_text(src) + assert migrate_config(str(cfg)) == 0 + assert cfg.read_text() == expected + + def test_migrate_config_invalid_yaml(tmpdir): contents = '[' cfg = tmpdir.join(C.CONFIG_FILE) diff --git a/tests/yaml_rewrite_test.py b/tests/yaml_rewrite_test.py new file mode 100644 index 00000000..d0f6841c --- /dev/null +++ b/tests/yaml_rewrite_test.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +import pytest + +from pre_commit.yaml import yaml_compose +from pre_commit.yaml_rewrite import MappingKey +from pre_commit.yaml_rewrite import MappingValue +from pre_commit.yaml_rewrite import match +from pre_commit.yaml_rewrite import SequenceItem + + +def test_match_produces_scalar_values_only(): + src = '''\ +- name: foo +- name: [not, foo] # not a scalar: should be skipped! +- name: bar +''' + matcher = (SequenceItem(), MappingValue('name')) + ret = [n.value for n in match(yaml_compose(src), matcher)] + assert ret == ['foo', 'bar'] + + +@pytest.mark.parametrize('cls', (MappingKey, MappingValue)) +def test_mapping_not_a_map(cls): + m = cls('s') + assert list(m.match(yaml_compose('[foo]'))) == [] + + +def test_sequence_item_not_a_sequence(): + assert list(SequenceItem().match(yaml_compose('s: val'))) == [] + + +def test_mapping_key(): + m = MappingKey('s') + ret = [n.value for n in m.match(yaml_compose('s: val\nt: val2'))] + assert ret == ['s'] + + +def test_mapping_value(): + m = MappingValue('s') + ret = [n.value for n in m.match(yaml_compose('s: val\nt: val2'))] + assert ret == ['val'] + + +def test_sequence_item(): + ret = [n.value for n in SequenceItem().match(yaml_compose('[a, b, c]'))] + assert ret == ['a', 'b', 'c'] From 5679399d905a30b37c8132e8a854353f3025dcc3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 16 Sep 2024 20:36:33 -0400 Subject: [PATCH 343/416] migrate-config rewrites deprecated stages --- pre_commit/commands/migrate_config.py | 21 ++++++++++++++ tests/commands/migrate_config_test.py | 42 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index cdce83f5..ada094fa 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -1,6 +1,7 @@ from __future__ import annotations import functools +import itertools import textwrap from typing import Callable @@ -49,6 +50,10 @@ def _preserve_style(n: ScalarNode, *, s: str) -> str: return f'{n.style}{s}{n.style}' +def _fix_stage(n: ScalarNode) -> str: + return _preserve_style(n, s=f'pre-{n.value}') + + def _migrate_composed(contents: str) -> str: tree = yaml_compose(contents) rewrites: list[tuple[ScalarNode, Callable[[ScalarNode], str]]] = [] @@ -76,6 +81,22 @@ def _migrate_composed(contents: str) -> str: if node.value == 'python_venv': rewrites.append((node, python_venv_replace)) + # stages rewrites + default_stages_matcher = (MappingValue('default_stages'), SequenceItem()) + default_stages_match = match(tree, default_stages_matcher) + hook_stages_matcher = ( + MappingValue('repos'), + SequenceItem(), + MappingValue('hooks'), + SequenceItem(), + MappingValue('stages'), + SequenceItem(), + ) + hook_stages_match = match(tree, hook_stages_matcher) + for node in itertools.chain(default_stages_match, hook_stages_match): + if node.value in {'commit', 'push', 'merge-commit'}: + rewrites.append((node, _fix_stage)) + rewrites.sort(reverse=True, key=lambda nf: nf[0].start_mark.index) src_parts = [] diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py index c563866d..9ffae6ee 100644 --- a/tests/commands/migrate_config_test.py +++ b/tests/commands/migrate_config_test.py @@ -213,6 +213,48 @@ repos: assert cfg.read_text() == expected +def test_migrate_config_default_stages(tmp_path): + src = '''\ +default_stages: [commit, push, merge-commit, commit-msg] +repos: [] +''' + expected = '''\ +default_stages: [pre-commit, pre-push, pre-merge-commit, commit-msg] +repos: [] +''' + cfg = tmp_path.joinpath('cfg.yaml') + cfg.write_text(src) + assert migrate_config(str(cfg)) == 0 + assert cfg.read_text() == expected + + +def test_migrate_config_hook_stages(tmp_path): + src = '''\ +repos: +- repo: local + hooks: + - id: example + name: example + entry: example + language: system + stages: ["commit", "push", "merge-commit", "commit-msg"] +''' + expected = '''\ +repos: +- repo: local + hooks: + - id: example + name: example + entry: example + language: system + stages: ["pre-commit", "pre-push", "pre-merge-commit", "commit-msg"] +''' + cfg = tmp_path.joinpath('cfg.yaml') + cfg.write_text(src) + assert migrate_config(str(cfg)) == 0 + assert cfg.read_text() == expected + + def test_migrate_config_invalid_yaml(tmpdir): contents = '[' cfg = tmpdir.join(C.CONFIG_FILE) From a4e4cef335c62dc314fecbbd57e6fc57460c95d3 Mon Sep 17 00:00:00 2001 From: Travis Johnson Date: Thu, 9 May 2024 12:49:09 -0400 Subject: [PATCH 344/416] Upgrade to ruby-build v20240917 --- testing/make-archives | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/make-archives b/testing/make-archives index 3c7ab9dd..251be4a5 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -17,7 +17,7 @@ from collections.abc import Sequence REPOS = ( ('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'), - ('ruby-build', 'https://github.com/rbenv/ruby-build', '855b963'), + ('ruby-build', 'https://github.com/rbenv/ruby-build', 'ed384c8'), ( 'ruby-download', 'https://github.com/garnieretienne/rvm-download', From e687548842aab3c3ccc7677492960c740c2ced11 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Sep 2024 13:06:21 -0400 Subject: [PATCH 345/416] regenerate archives with python3.12 --- pre_commit/resources/rbenv.tar.gz | Bin 32551 -> 32545 bytes pre_commit/resources/ruby-download.tar.gz | Bin 5271 -> 5269 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pre_commit/resources/rbenv.tar.gz b/pre_commit/resources/rbenv.tar.gz index da2514e71145e91debbad4bb1e11ca6d95ed3f63..111546e3dd9796511942c278495c21fe1ef947ae 100644 GIT binary patch delta 31950 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 diff --git a/pre_commit/resources/ruby-download.tar.gz b/pre_commit/resources/ruby-download.tar.gz index 92502a77e79abba062c5a4fc38e5d885a9982d29..f7cb0b42157696814f31d477b609b1e247c6c0e6 100644 GIT binary patch delta 4977 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 JGE^`y0026K%)tNv delta 4959 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 From c9454e2ec3245b792eb7626e9bea799bf5e96bbf Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Sep 2024 13:07:55 -0400 Subject: [PATCH 346/416] regenerate ruby-build archive --- pre_commit/resources/ruby-build.tar.gz | Bin 75808 -> 88488 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index 19d467fdd2867742cdefe402a78489481ce9abba..a4f7eb24fd0a7e4d59cf120014d8b054555b8b0f 100644 GIT binary patch literal 88488 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

E%sJ2wWVrZ2Mm`!Jln4vwrf`M zgq4%D*v)#c6{H+#xcI)QzP9pT`Tyf*{~P}VjR*#5UksFHS=Jt}YF{`24augm(N_h0^wxBs90udDv|M{4b6 zr>|A#&EFn$zkj|dxl?W@=Vqp=DM?Ek&MggXJK5qkSLSm5!?<6UCS=(>TgUqUv+cd; z{|{Tg*8i@*{^I|+|Fw?lU(>hDTmHY`HLK9i!fK_It&dh6ZTCw{EqQ9!FE{IF=IUs9 z$rE}{pKjHE>}qn!q~=fe)!&7U|Mt85_rLkIKKlRvnqU80=FMO4`Ty~}`R?^kEOpZj zI+SXbzVQ}5P?e%HO-_+JVa=tjt20CLc-`i&?vc9qD(o+)KB(W}@IQ6^{~S@Me2tpUjArkBqy+P%j*Bz{{5f# zPhG$M!1;>uzu#Z~uAg%v_wW5*^~ZnBcdo2|yFUKjx?M}v{9;ljPro7;C%M3RqN38N zp9`yZ?0SA&pX=T=iQb)|D`oI3%{~OQO z-}?1m{bGH^ynpw@nzl|geXiAbk0(oi&E&1F&LU@b+@G^pSbW*Va3!;XCufp_v<+4t z2iIgT{+s@kul}F^`v2Y6|0jR4uT%Zo|Jgog>z5yU*9df1yzrTt9J7_j%CF|B-j*3^ z*Kb95ALrrtqT#o?ed!G0?XU9x{*V2;zW%^@i>?2+gBq3l^Z(i}|J#4=m)PdS<1h76 z1YW*6pZs#U0mt+SPcL8QP|(ZXJN4$}tJ9|yufAB=sek`>{qK)?fA!^K{&!!we!YIi zx1aZ`|G$^KRHe6l(Y;C9KAuw|FE_}htIuLSe&LisQX->Di>AV^S)W$yJ^I3Ksjy_f z>*_kKN5Ay`J+$A;@Za^`gZ*!Q)PJs@^}kqq)%MmaEIWIdB=vsBEMCfzaP&&^mn}Xj z@BQ8_b+KCAP#lmMqNTaaKxg`krFB;8uI~PEeD#m}zyHtvfBDa2&42Q;E7at;R!?LN zeIcp0(?dZl^s>yVzM$wCeWA}S&V?jTaY}x=cTdQ&JN*AkL_r;>Kl7i>_xo7?`q#dI z@U_=s`uWxeRQ8B8a;a>*bY1_T)KstdrJ5|iz3LeZ)9MUwvFw)r_fzX%`QPKu{+s-- z>G~gi{W?>~<@NDbMOXK)x>fD=E!AY1X^?c38`I_sUn1gWFRc#9(G;6x+V%DK!}xWN z>fis*`RD&xfBBF7bAK&qW-MgcH1VZW@Cs%&$2E@wQe_R*4A0x8e)U{>rIFcp(Tvm= z1@3=dhyHp0Io|C5@}Jj(|J>hY*UwZZ^XW;j@wwxw%&TR7eijM-5g{pHaH{cf68C|~ z30_il3VH5DfB$~CzwS}}{Qnz%+MlhrKKg&{YvY2MsRgg?)~vog=iZT`3zo7Ezx+|x zG%mB6<+Qpd@#4mBm!$cREc<@Aet*~h*#Emh`s|O^@822{9T0eQ%{2{M^^3BN#UC~& z@@EE0>^<{^cY*IpzY9E!o{m+Hoz)NJ;}-oto&T|a*U$TZ=0B02cPWZ>-=5gg?6r?r zv$Y)F*P7bg`75ZA6s28U>%l6)#j-TNYooG*~JK=Ii!p z-3|-mFFs^SIei2v6Q_`mmcz1jbIga6NO z)R!#r+OR^zRY5Y#c)<&fp0G8^C$C?+b3Mr7?v=Q;YrZfUnQ$m&d+rgx~t zAaSY)+uK7G?%)1z`gK3{|Ms8uXYJ=b`XBcHwbz@)+Zp#Z`Ps_+u?p)?YI^x{`F#Cu zwP{y4OQKAcEp%qFV!v8y|0h1||L(v4LH4~A`M>>F{F;D(T{mR1{k#v~o5GWp5c?{} zRF*|v=|T`|)-Hxpwkv@eu{`u|->rv9w?FaPU)hSw5ylcqC?r0$rxbwXQd zhMl`v+SrTE;^?}z`Ve%-(OU;gL%S@pI@|F8YGT{P>_o$9M5 zKYMdq-Feo`F<<>~OY-jZrPkBf7cC15@jiNCJmpdzmhq*0&! zSJ83B*bT0taa`KAf4c&vPc7k?cEF;j_P2uu%dus#TCKaL?SA>cJsdo>4+_wanqT+- zc=~o#^q=>qZXIrOoDj^Yz4rV=Ns%vNd$KN_cfDPBFG)Lf3C9HKX`PFU~S=;ZTF?`}+ZndA3{^R6y zFja>4zoByor{r1P|FfgQ543na+E|A%EW1@ycm;m3E#bu7xtNzzqomytwkg{~+{5zEnmR|q6FYcNDAxQ$ zv_VquWvP}W=JLWvRJZ&re4=mSvs@uG(PZYts(@veH(Gjd%x!yavSaf7z<>O4;r};( z2B)Uw;M7#}Ev%@ehc{yx4^N)*nP*4hj<7#?;mbMuc%jpRKE_+@3}5;rh1WnV-1`sY zPW${#pM|FCqn0-u=V6AkM{5WCw~9d54C+&3b}P6Ss(oVtv~hu z{-6AR_b2~9{_}r{(*OBo|Nck+*st-we*OR4|Noc#_h0_$KPXK<`yZaFySm3M;O1IJ zgEdimx{gg0d82xC^}^}1-k(^>KOsnW)$PIriLd^~|EI4z{r~>!dT50pFIURKQuK^* z^UDN(%?#lS9$DQzzqwz?#Qja&->{}&O{6>@Q*?LD)t@In_v@dwfBSX++5ew^f+l27 za~wIu#vJ2Nt^cuLhk99z&|)jWCk)Rwc^&_@|M#3)K_ylfO}1knUVf^-__H2V6#VD; zH^1cH{q+~>YyQdioqBm{`qk%J#aur+By=O3Rn};pX{k2Qmo^T|wXD+aflM1@w)^)ci>+gr6Q!jGf1_w5jf8-Cp`5#g({NI_n|8`b<=EQZi zp85MTJ0mw{u^9!Ok~*yR{hTKMwokgDEz<36)sG|lUhOw}f8yWc&_DUVK^X+9(NNdo zy40!_?s@*#7yrJ_v4Cy$6NmnD@#{=CtZ-JGbWm5hCG?>9wBHZsuX_ZF+<*R`{lO{y z*^DB#HC|Ef_NV?xn>~+E5M!3;y)4;qZRxhS8NC_1wmjBjKNR}Dy?$TU|GED+gX*vO zkN#i$S+6xuk%8^{g2bd$*VWl20x!Enj!QMPn?^3RD*UqVfax^8^OcYOe$Ws9xc_rK zsO<%*O{!mNAO0&7&i3E(nrUrie9sBJ#IP+%Z*%#KK6V{uYg}U%b#CWVmG|xc#aI4k zz4Isk-+zaHUq$}^I{l*7OD9}o-m-WG6I~mg;{wNGVFci)bx z=s2*v`M>qgeDRzAcY#_3%YWvB{m3>=dExr-9HT?gORuSOXfaplhw2_Pm~=II%fY7> z(reDo39p;z|NZyI|9`dqmH#^rDn0&+{Qn#HU*F=>PoW$y{{<8Jl%*F`_wjnIUK|{6 znDr_D>B3L@r-|)dn|1tJ!hY$0KX?85fA;^g|0@6gO!-y+?^D@T?SJXs>*ctwEG@kx z)N%NFyWWK}yE{3)*M#;jZ`#@Q;-Q{Eng;iqI`=>Eq5t=TT6`=1KNtS`f6wdx_YeJd z1;e`U}brG5@c#=rI4bIQOF^@kYQBi3dkAvQ}SP z{9=El@RnQ2oToNQGu)Xzx$5Qos=xB_;s3WoN^JY%|9XFKs&I;2D!04tTFb^z?K2B! zD9>LUI_Z=)Q~#R%ZCe}pbKRKPr`@-I`}uPBfBn_}Z~g@LBMxi+lb`!P-NNRMd`2I` z+UB$$JbnAb+(M_=RX&}Q)@&xY>iWIDq=tQ`V!$l`dq@kQ-sY&i-K%d`eP;7b{`0>f zNiR_S_NmAfK2tIbmrju}zbwKsPx5K_@k^grr$Q0^1jCvc;@XYq;fBj%cMOLr!zo@JJXX=;ItTRe_ zU94T_xt7iFSN%SP>A-|{_3widO+Iw;8J*p*?5DeAe&+A*C!hZR%zgF$n?L{0{+Bs7Unl>FTwBWTcVLrR^Ww*aH=avrn>HSp^(=>r;gJ?3 zNUI@@sya|5c)r7s>GG}Z_uhW^z$+Fqr}6m8`B7HIeETAgUagSuf6sHHHS)FqEP!SDD z(3NjE_C)@_d`!gs=uVYIQ~W|4ySF;7_Hw)%|LMWa zaBp^fMIt0;{`_g# ze^<|Y$34DyxBcF-Li?t~r1)&NzuB1<8dn(?#PA&6S@R3j-rxVa9@PA{Pya2y_FH4Q z)`f>Jeq6Qs+RGMqv#vR^N9~P*pZlZv4>YWfWKT9tf7&A^q2geiv7`TU{nK6lJ`z7=GoLGEt%e7S<3<0KxQVpZl*Vupizv-X+ z?SJ6rXWq^K+iuw}Pmu0jP+(tGeKqn#*vvCkbN-lWIyV_@xqhhO>dCz~3S%PLIH!so z`TLBEN#St4PLcb+|EYiN%l?9!lT}^+qyP8IbbeHk?UIu?=)U>< zRcpT4!R-NtC*IFq=$P!vGSiu5Vd3LdQKuoEgpL4!Mh^ZT-y(A^@Ye2I8xE?S4&C}S zdB=oz4vw*B7k`-ek6AUgwS;v8ms|Wcr+4lDPyeca^Jo6q|C#@OYyQjsYrlr$o6^zF z?DW0o!%hO-}ZvvJWO2ryUh&&$al~4^*9?o7 zT#V;^H9_v;t%5%#KkFO+$>-1czxg$&oAvm==U@A})_;%x$zQ$6#dGjT)y{=hp_!#J zt_??LM(4IQOuc+dUX|gVnE1PvcFIN5ae=NW5K|QD|o&J%3`Op28e{)N@E+^h< zcWL{0Ap1h0$%l&~9A2y4O9T9P)3_LR`Wnm?xYbg-^~aZ=^%MWe?|A*+?0>z=|K~aX z7hkorjjA;h=Iy=7u#9D9%U1=aXR2$Zm#aLnmPosru{k04%ICcS59+@Cf1vem`(H?& ze7pZ?cVI-Gzb0DeGKsrIM^I^&79=W{O*+D`}X=h9gw!< zc}SB`-cA3Ydwl*Z?fq-+Zd}nj>0Z4pAM5J}sZ+RgQ+SLg+C}wyrlfjEe?M#=d-VT0 za6JPW$y@#3{@mLPv3tuC+h<(6z3N<0_p-gyFIX*nb>{Y!rLT%OeQw)t)#vi9e^~e9 z`RX6{f7XLW4#9&A|AW~sUc7tTqD$xehx=i%?xpKP_4zJ)aGw|4q9FUv;?=(;eYYx} z&Up=K7J>o>I>_)pl`Ubu*S?gfmzyg>SBD17HWgHj+0$iM;r=XBp;1_=c*{A&fzw4|2 zmv4fnHToa#pZjS4U!z}#_scig?a|$Eh)43L`RtHt9bubqtm>jmE!)=blX0^>$E_}Z zDF2TF2H%{taKR>(+PX zOtymFtfa}}R|K!l;gs!MV;F*v%LDna*grc(f{37 z{{Ol5>wX`&t8ah&pZ2@Js^;YC_22d#Q3{*tsM@*9~C!Mv4Np1;b`+7q0w2Z=XL4)ez z7y}u1owMPuWIy(Ye}q<)$AkYo*8Y87SGUSGszPVlI@Ve1Hl=x=F@1hzVL>+6PnVff zBTqZbiR#Im2QZMHB7_{;%Qv9|9d&sOhS&+j=YiG;8!mrmQWCqW(=k(*ApbW2}3* znSRsN{yFv2uD16{Tv@U5li5PNya?1zPj%h{!gcX;CVZ_P;&;-|xr&KYR=Sxp`V* zLDJo5wsS}Ldq4hqvoWdR5zqF=Pjo)K{3$-`^_4A)MT1!R9(%oCAiwWWP~G%@zoxvo z|Lf`7RkvTw7u93_lc|M~yU-}*0nbAP{V zV|@C5IXT9uuC*5puSs03cqNr;!nVPwxJ=TIZNn}P!;=vX3%0A>TXe<9KCS;j?4SKU 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 From fa08d1d6372e389e0a34425001543429732410e1 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Sep 2024 18:09:04 -0400 Subject: [PATCH 347/416] also apply sensible regex warning for `repo: meta` --- pre_commit/clientlib.py | 2 ++ tests/clientlib_test.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index a49465e8..0127c4d0 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -289,6 +289,8 @@ META_HOOK_DICT = cfgv.Map( item for item in MANIFEST_HOOK_DICT.items ), + OptionalSensibleRegexAtHook('files', cfgv.check_string), + OptionalSensibleRegexAtHook('exclude', cfgv.check_string), ) CONFIG_HOOK_DICT = cfgv.Map( 'Hook', 'id', diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index eaa8a044..9d31d339 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -256,6 +256,24 @@ def test_validate_optional_sensible_regex_at_local_hook(caplog): ] +def test_validate_optional_sensible_regex_at_meta_hook(caplog): + config_obj = { + 'repo': 'meta', + 'hooks': [{'id': 'identity', 'files': 'dir/*.py'}], + } + + cfgv.validate(config_obj, CONFIG_REPO_DICT) + + assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + "The 'files' field in hook 'identity' is a regex, not a glob " + "-- matching '/*' probably isn't what you want here", + ), + ] + + @pytest.mark.parametrize( ('regex', 'warning'), ( From 7441a62eb1db5820d52a2c28afa3025773e4f015 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Sep 2024 18:41:13 -0400 Subject: [PATCH 348/416] add warning for deprecated stages names --- pre_commit/clientlib.py | 42 ++++++++++++++++++++++++++++++++++------- tests/clientlib_test.py | 26 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 0127c4d0..4e0425c3 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -99,6 +99,32 @@ class StagesMigration(StagesMigrationNoDefault): super().apply_default(dct) +class DeprecatedStagesWarning(NamedTuple): + key: str + + def check(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + return + + val = dct[self.key] + cfgv.check_array(cfgv.check_any)(val) + + legacy_stages = [stage for stage in val if stage in _STAGES] + if legacy_stages: + logger.warning( + f'hook id `{dct["id"]}` uses deprecated stage names ' + f'({", ".join(legacy_stages)}) which will be removed in a ' + f'future version. ' + f'run: `pre-commit migrate-config` to automatically fix this.', + ) + + def apply_default(self, dct: dict[str, Any]) -> None: + pass + + def remove_default(self, dct: dict[str, Any]) -> None: + raise NotImplementedError + + MANIFEST_HOOK_DICT = cfgv.Map( 'Hook', 'id', @@ -267,6 +293,12 @@ class NotAllowed(cfgv.OptionalNoDefault): raise cfgv.ValidationError(f'{self.key!r} cannot be overridden') +_COMMON_HOOK_WARNINGS = ( + OptionalSensibleRegexAtHook('files', cfgv.check_string), + OptionalSensibleRegexAtHook('exclude', cfgv.check_string), + DeprecatedStagesWarning('stages'), +) + META_HOOK_DICT = cfgv.Map( 'Hook', 'id', cfgv.Required('id', cfgv.check_string), @@ -289,8 +321,7 @@ META_HOOK_DICT = cfgv.Map( item for item in MANIFEST_HOOK_DICT.items ), - OptionalSensibleRegexAtHook('files', cfgv.check_string), - OptionalSensibleRegexAtHook('exclude', cfgv.check_string), + *_COMMON_HOOK_WARNINGS, ) CONFIG_HOOK_DICT = cfgv.Map( 'Hook', 'id', @@ -308,16 +339,13 @@ CONFIG_HOOK_DICT = cfgv.Map( if item.key != 'stages' ), StagesMigrationNoDefault('stages', []), - OptionalSensibleRegexAtHook('files', cfgv.check_string), - OptionalSensibleRegexAtHook('exclude', cfgv.check_string), + *_COMMON_HOOK_WARNINGS, ) LOCAL_HOOK_DICT = cfgv.Map( 'Hook', 'id', *MANIFEST_HOOK_DICT.items, - - OptionalSensibleRegexAtHook('files', cfgv.check_string), - OptionalSensibleRegexAtHook('exclude', cfgv.check_string), + *_COMMON_HOOK_WARNINGS, ) CONFIG_REPO_DICT = cfgv.Map( 'Repository', 'repo', diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 9d31d339..1335e086 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -309,6 +309,32 @@ def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning): assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)] +def test_warning_for_deprecated_stages(caplog): + config_obj = sample_local_config() + config_obj['hooks'][0]['stages'] = ['commit', 'push'] + + cfgv.validate(config_obj, CONFIG_REPO_DICT) + + assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + 'hook id `do_not_commit` uses deprecated stage names ' + '(commit, push) which will be removed in a future version. ' + 'run: `pre-commit migrate-config` to automatically fix this.', + ), + ] + + +def test_no_warning_for_non_deprecated_stages(caplog): + config_obj = sample_local_config() + config_obj['hooks'][0]['stages'] = ['pre-commit', 'pre-push'] + + cfgv.validate(config_obj, CONFIG_REPO_DICT) + + assert caplog.record_tuples == [] + + @pytest.mark.parametrize( 'manifest_obj', ( From 33e020f315a0f8654500ffbbb103ef7b39fd7ff9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Sep 2024 19:22:14 -0400 Subject: [PATCH 349/416] add warning for deprecated stages values in `default_stages` --- pre_commit/clientlib.py | 27 +++++++++++++++++++++++++++ tests/clientlib_test.py | 24 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 4e0425c3..f7885071 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -125,6 +125,32 @@ class DeprecatedStagesWarning(NamedTuple): raise NotImplementedError +class DeprecatedDefaultStagesWarning(NamedTuple): + key: str + + def check(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + return + + val = dct[self.key] + cfgv.check_array(cfgv.check_any)(val) + + legacy_stages = [stage for stage in val if stage in _STAGES] + if legacy_stages: + logger.warning( + f'top-level `default_stages` uses deprecated stage names ' + f'({", ".join(legacy_stages)}) which will be removed in a ' + f'future version. ' + f'run: `pre-commit migrate-config` to automatically fix this.', + ) + + def apply_default(self, dct: dict[str, Any]) -> None: + pass + + def remove_default(self, dct: dict[str, Any]) -> None: + raise NotImplementedError + + MANIFEST_HOOK_DICT = cfgv.Map( 'Hook', 'id', @@ -398,6 +424,7 @@ CONFIG_SCHEMA = cfgv.Map( 'default_language_version', DEFAULT_LANGUAGE_VERSION, {}, ), StagesMigration('default_stages', STAGES), + DeprecatedDefaultStagesWarning('default_stages'), cfgv.Optional('files', check_string_regex, ''), cfgv.Optional('exclude', check_string_regex, '^$'), cfgv.Optional('fail_fast', cfgv.check_bool, False), diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 1335e086..7aa84af0 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -335,6 +335,30 @@ def test_no_warning_for_non_deprecated_stages(caplog): assert caplog.record_tuples == [] +def test_warning_for_deprecated_default_stages(caplog): + cfg = {'default_stages': ['commit', 'push'], 'repos': []} + + cfgv.validate(cfg, CONFIG_SCHEMA) + + assert caplog.record_tuples == [ + ( + 'pre_commit', + logging.WARNING, + 'top-level `default_stages` uses deprecated stage names ' + '(commit, push) which will be removed in a future version. ' + 'run: `pre-commit migrate-config` to automatically fix this.', + ), + ] + + +def test_no_warning_for_non_deprecated_default_stages(caplog): + cfg = {'default_stages': ['pre-commit', 'pre-push'], 'repos': []} + + cfgv.validate(cfg, CONFIG_SCHEMA) + + assert caplog.record_tuples == [] + + @pytest.mark.parametrize( 'manifest_obj', ( From 1d2f1c0ccea63906c8bcc9265bb9940383341c0c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Sep 2024 19:58:16 -0400 Subject: [PATCH 350/416] replace log_info_mock with pytest's caplog --- tests/conftest.py | 7 ------- tests/repository_test.py | 8 ++++---- tests/store_test.py | 8 ++++---- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index bd4af9a5..8c9cd14d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,6 @@ from __future__ import annotations import functools import io -import logging import os.path from unittest import mock @@ -203,12 +202,6 @@ def store(tempdir_factory): yield Store(os.path.join(tempdir_factory.get(), '.pre-commit')) -@pytest.fixture -def log_info_mock(): - with mock.patch.object(logging.getLogger('pre_commit'), 'info') as mck: - yield mck - - class Fixture: def __init__(self, stream: io.BytesIO) -> None: self._stream = stream diff --git a/tests/repository_test.py b/tests/repository_test.py index ac065ec4..32c361ef 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -240,16 +240,16 @@ def test_unknown_keys(store, caplog): assert msg == 'Unexpected key(s) present on local => too-much: foo, hello' -def test_reinstall(tempdir_factory, store, log_info_mock): +def test_reinstall(tempdir_factory, store, caplog): path = make_repo(tempdir_factory, 'python_hooks_repo') config = make_config_from_repo(path) _get_hook(config, store, 'foo') # We print some logging during clone (1) + install (3) - assert log_info_mock.call_count == 4 - log_info_mock.reset_mock() + assert len(caplog.record_tuples) == 4 + caplog.clear() # Reinstall on another run should not trigger another install _get_hook(config, store, 'foo') - assert log_info_mock.call_count == 0 + assert len(caplog.record_tuples) == 0 def test_control_c_control_c_on_install(tempdir_factory, store): diff --git a/tests/store_test.py b/tests/store_test.py index 45ec7327..b6b0a0b0 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -65,7 +65,7 @@ def test_store_init(store): assert text_line in readme_contents -def test_clone(store, tempdir_factory, log_info_mock): +def test_clone(store, tempdir_factory, caplog): path = git_dir(tempdir_factory) with cwd(path): git_commit() @@ -74,7 +74,7 @@ def test_clone(store, tempdir_factory, log_info_mock): ret = store.clone(path, rev) # Should have printed some stuff - assert log_info_mock.call_args_list[0][0][0].startswith( + assert caplog.record_tuples[0][-1].startswith( 'Initializing environment for ', ) @@ -118,7 +118,7 @@ def test_clone_when_repo_already_exists(store): def test_clone_shallow_failure_fallback_to_complete( store, tempdir_factory, - log_info_mock, + caplog, ): path = git_dir(tempdir_factory) with cwd(path): @@ -134,7 +134,7 @@ def test_clone_shallow_failure_fallback_to_complete( ret = store.clone(path, rev) # Should have printed some stuff - assert log_info_mock.call_args_list[0][0][0].startswith( + assert caplog.record_tuples[0][-1].startswith( 'Initializing environment for ', ) From d31722386e57a98d8d7d6d74228d255b9a9ffaf3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 30 Sep 2024 20:29:19 -0400 Subject: [PATCH 351/416] add warning for deprecates stages for remote repos on init --- pre_commit/clientlib.py | 38 +++++++++++++++++++++++ pre_commit/store.py | 5 +++ tests/store_test.py | 69 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index f7885071..c0f736d9 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -2,6 +2,7 @@ from __future__ import annotations import functools import logging +import os.path import re import shlex import sys @@ -70,6 +71,43 @@ def transform_stage(stage: str) -> str: return _STAGES.get(stage, stage) +MINIMAL_MANIFEST_SCHEMA = cfgv.Array( + cfgv.Map( + 'Hook', 'id', + cfgv.Required('id', cfgv.check_string), + cfgv.Optional('stages', cfgv.check_array(cfgv.check_string), []), + ), +) + + +def warn_for_stages_on_repo_init(repo: str, directory: str) -> None: + try: + manifest = cfgv.load_from_filename( + os.path.join(directory, C.MANIFEST_FILE), + schema=MINIMAL_MANIFEST_SCHEMA, + load_strategy=yaml_load, + exc_tp=InvalidManifestError, + ) + except InvalidManifestError: + return # they'll get a better error message when it actually loads! + + legacy_stages = {} # sorted set + for hook in manifest: + for stage in hook.get('stages', ()): + if stage in _STAGES: + legacy_stages[stage] = True + + if legacy_stages: + logger.warning( + f'repo `{repo}` uses deprecated stage names ' + f'({", ".join(legacy_stages)}) which will be removed in a ' + f'future version. ' + f'Hint: often `pre-commit autoupdate --repo {shlex.quote(repo)}` ' + f'will fix this. ' + f'if it does not -- consider reporting an issue to that repo.', + ) + + class StagesMigrationNoDefault(NamedTuple): key: str default: Sequence[str] diff --git a/pre_commit/store.py b/pre_commit/store.py index 36cc4945..1235942c 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -10,6 +10,7 @@ from collections.abc import Sequence from typing import Callable import pre_commit.constants as C +from pre_commit import clientlib from pre_commit import file_lock from pre_commit import git from pre_commit.util import CalledProcessError @@ -136,6 +137,7 @@ class Store: deps: Sequence[str], make_strategy: Callable[[str], None], ) -> str: + original_repo = repo repo = self.db_repo_name(repo, deps) def _get_result() -> str | None: @@ -168,6 +170,9 @@ class Store: 'INSERT INTO repos (repo, ref, path) VALUES (?, ?, ?)', [repo, ref, directory], ) + + clientlib.warn_for_stages_on_repo_init(original_repo, directory) + return directory def _complete_clone(self, ref: str, git_cmd: Callable[..., None]) -> None: diff --git a/tests/store_test.py b/tests/store_test.py index b6b0a0b0..7d4dffb0 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -1,12 +1,15 @@ from __future__ import annotations +import logging import os.path +import shlex import sqlite3 import stat from unittest import mock import pytest +import pre_commit.constants as C from pre_commit import git from pre_commit.store import _get_default_directory from pre_commit.store import _LOCAL_RESOURCES @@ -91,6 +94,72 @@ def test_clone(store, tempdir_factory, caplog): assert store.select_all_repos() == [(path, rev, ret)] +def test_warning_for_deprecated_stages_on_init(store, tempdir_factory, caplog): + manifest = '''\ +- id: hook1 + name: hook1 + language: system + entry: echo hook1 + stages: [commit, push] +- id: hook2 + name: hook2 + language: system + entry: echo hook2 + stages: [push, merge-commit] +''' + + path = git_dir(tempdir_factory) + with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f: + f.write(manifest) + cmd_output('git', 'add', '.', cwd=path) + git_commit(cwd=path) + rev = git.head_rev(path) + + store.clone(path, rev) + assert caplog.record_tuples[1] == ( + 'pre_commit', + logging.WARNING, + f'repo `{path}` uses deprecated stage names ' + f'(commit, push, merge-commit) which will be removed in a future ' + f'version. ' + f'Hint: often `pre-commit autoupdate --repo {shlex.quote(path)}` ' + f'will fix this. ' + f'if it does not -- consider reporting an issue to that repo.', + ) + + # should not re-warn + caplog.clear() + store.clone(path, rev) + assert caplog.record_tuples == [] + + +def test_no_warning_for_non_deprecated_stages_on_init( + store, tempdir_factory, caplog, +): + manifest = '''\ +- id: hook1 + name: hook1 + language: system + entry: echo hook1 + stages: [pre-commit, pre-push] +- id: hook2 + name: hook2 + language: system + entry: echo hook2 + stages: [pre-push, pre-merge-commit] +''' + + path = git_dir(tempdir_factory) + with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f: + f.write(manifest) + cmd_output('git', 'add', '.', cwd=path) + git_commit(cwd=path) + rev = git.head_rev(path) + + store.clone(path, rev) + assert logging.WARNING not in {tup[1] for tup in caplog.record_tuples} + + def test_clone_cleans_up_on_checkout_failure(store): with pytest.raises(Exception) as excinfo: # This raises an exception because you can't clone something that From 801b956304e2ad2738bdb76d9c65ed52e967bb57 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 5 Oct 2024 13:30:25 -0400 Subject: [PATCH 352/416] remove deprecated python_venv alias --- pre_commit/all_languages.py | 2 -- pre_commit/repository.py | 9 --------- tests/all_languages_test.py | 7 ------- tests/repository_test.py | 18 ------------------ 4 files changed, 36 deletions(-) delete mode 100644 tests/all_languages_test.py diff --git a/pre_commit/all_languages.py b/pre_commit/all_languages.py index 476bad9d..f2d11bb6 100644 --- a/pre_commit/all_languages.py +++ b/pre_commit/all_languages.py @@ -44,7 +44,5 @@ languages: dict[str, Language] = { 'script': script, 'swift': swift, 'system': system, - # TODO: fully deprecate `python_venv` - 'python_venv': python, } language_names = sorted(languages) diff --git a/pre_commit/repository.py b/pre_commit/repository.py index aa841856..a9461ab6 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -3,7 +3,6 @@ from __future__ import annotations import json import logging import os -import shlex from collections.abc import Sequence from typing import Any @@ -68,14 +67,6 @@ def _hook_install(hook: Hook) -> None: logger.info('Once installed this environment will be reused.') logger.info('This may take a few minutes...') - if hook.language == 'python_venv': - logger.warning( - f'`repo: {hook.src}` uses deprecated `language: python_venv`. ' - f'This is an alias for `language: python`. ' - f'Often `pre-commit autoupdate --repo {shlex.quote(hook.src)}` ' - f'will fix this.', - ) - lang = languages[hook.language] assert lang.ENVIRONMENT_DIR is not None diff --git a/tests/all_languages_test.py b/tests/all_languages_test.py deleted file mode 100644 index 98c91215..00000000 --- a/tests/all_languages_test.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import annotations - -from pre_commit.all_languages import languages - - -def test_python_venv_is_an_alias_to_python(): - assert languages['python_venv'] is languages['python'] diff --git a/tests/repository_test.py b/tests/repository_test.py index 32c361ef..b54c910d 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -80,24 +80,6 @@ def _test_hook_repo( assert out == expected -def test_python_venv_deprecation(store, caplog): - config = { - 'repo': 'local', - 'hooks': [{ - 'id': 'example', - 'name': 'example', - 'language': 'python_venv', - 'entry': 'echo hi', - }], - } - _get_hook(config, store, 'example') - assert caplog.messages[-1] == ( - '`repo: local` uses deprecated `language: python_venv`. ' - 'This is an alias for `language: python`. ' - 'Often `pre-commit autoupdate --repo local` will fix this.' - ) - - def test_system_hook_with_spaces(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'system_hook_with_spaces_repo', From dbccd57db0e9cf993ea909e929eea97f6e4389ea Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 5 Oct 2024 14:58:22 -0400 Subject: [PATCH 353/416] v4.0.0 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49094bbb..2e4dd3cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +4.0.0 - 2024-10-05 +================== + +### Features +- Improve `pre-commit migrate-config` to handle more yaml formats. + - #3301 PR by @asottile. +- Handle `stages` deprecation in `pre-commit migrate-config`. + - #3302 PR by @asottile. + - #2732 issue by @asottile. +- Upgrade `ruby-build`. + - #3199 PR by @ThisGuyCodes. +- Add "sensible regex" warnings to `repo: meta`. + - #3311 PR by @asottile. +- Add warnings for deprecated `stages` (`commit` -> `pre-commit`, `push` -> + `pre-push`, `merge-commit` -> `pre-merge-commit`). + - #3312 PR by @asottile. + - #3313 PR by @asottile. + - #3315 PR by @asottile. + - #2732 issue by @asottile. + +### Migrating +- `language: python_venv` has been removed -- use `language: python` instead. + - #3320 PR by @asottile. + - #2734 issue by @asottile. + 3.8.0 - 2024-07-28 ================== diff --git a/setup.cfg b/setup.cfg index 52b7681e..70289e1f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.8.0 +version = 4.0.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 4235a877f3ac4998b41e9cce8a709ac13de159b5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 00:02:26 +0000 Subject: [PATCH 354/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 87b8551d..7bd2611f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From 222c62bc5d2907efbd6052c5fb89c4c027400044 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 8 Oct 2024 11:46:48 -0400 Subject: [PATCH 355/416] fix migrate-config for purelib yaml --- pre_commit/commands/migrate_config.py | 3 ++- tests/commands/migrate_config_test.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index ada094fa..c5d47a08 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -47,7 +47,8 @@ def _migrate_map(contents: str) -> str: def _preserve_style(n: ScalarNode, *, s: str) -> str: - return f'{n.style}{s}{n.style}' + style = n.style or '' + return f'{style}{s}{style}' def _fix_stage(n: ScalarNode) -> str: diff --git a/tests/commands/migrate_config_test.py b/tests/commands/migrate_config_test.py index 9ffae6ee..a517d2f4 100644 --- a/tests/commands/migrate_config_test.py +++ b/tests/commands/migrate_config_test.py @@ -1,10 +1,26 @@ from __future__ import annotations +from unittest import mock + import pytest +import yaml import pre_commit.constants as C from pre_commit.clientlib import InvalidConfigError from pre_commit.commands.migrate_config import migrate_config +from pre_commit.yaml import yaml_compose + + +@pytest.fixture(autouse=True, params=['c', 'pure']) +def switch_pyyaml_impl(request): + if request.param == 'c': + yield + else: + with mock.patch.dict( + yaml_compose.keywords, + {'Loader': yaml.SafeLoader}, + ): + yield def test_migrate_config_normal_format(tmpdir, capsys): From cc4a52241565440ce200666799eef70626457488 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 8 Oct 2024 12:08:49 -0400 Subject: [PATCH 356/416] v4.0.1 --- CHANGELOG.md | 9 +++++++++ setup.cfg | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e4dd3cb..a9b4c8c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +4.0.1 - 2024-10-08 +================== + +### Fixes +- Fix `pre-commit migrate-config` for unquoted deprecated stages names with + purelib `pyyaml`. + - #3324 PR by @asottile. + - pre-commit-ci/issues#234 issue by @lorenzwalthert. + 4.0.0 - 2024-10-05 ================== diff --git a/setup.cfg b/setup.cfg index 70289e1f..6936a1f0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.0.0 +version = 4.0.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 46de4da34e362e8dfa34c08205b662da8ab47788 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:30:38 +0000 Subject: [PATCH 357/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.5.0 → v2.7.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.5.0...v2.7.0) - [github.com/asottile/reorder-python-imports: v3.13.0 → v3.14.0](https://github.com/asottile/reorder-python-imports/compare/v3.13.0...v3.14.0) - [github.com/asottile/pyupgrade: v3.17.0 → v3.18.0](https://github.com/asottile/pyupgrade/compare/v3.17.0...v3.18.0) - [github.com/pre-commit/mirrors-mypy: v1.11.2 → v1.12.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.2...v1.12.1) --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7bd2611f..33c905cd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,11 +10,11 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.5.0 + rev: v2.7.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.13.0 + rev: v3.14.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.17.0 + rev: v3.18.0 hooks: - id: pyupgrade args: [--py39-plus] @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 + rev: v1.12.1 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 0de4c8028a95c1a7dfd57e772ec11ce3a71834cc Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 21 Oct 2024 20:35:56 -0400 Subject: [PATCH 358/416] remove unused type ignore --- testing/make-archives | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/make-archives b/testing/make-archives index 251be4a5..eb3f3af8 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -57,8 +57,7 @@ def make_archive(name: str, repo: str, ref: str, destdir: str) -> str: arcs.sort() with gzip.GzipFile(output_path, 'wb', mtime=0) as gzipf: - # https://github.com/python/typeshed/issues/5491 - with tarfile.open(fileobj=gzipf, mode='w') as tf: # type: ignore + with tarfile.open(fileobj=gzipf, mode='w') as tf: for arcname, abspath in arcs: tf.add( abspath, From 708ca3b581f3fa033d918dd6d5b3794803d4dbb2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 22:56:52 +0000 Subject: [PATCH 359/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.18.0 → v3.19.0](https://github.com/asottile/pyupgrade/compare/v3.18.0...v3.19.0) - [github.com/pre-commit/mirrors-mypy: v1.12.1 → v1.13.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.12.1...v1.13.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33c905cd..614170ba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.18.0 + rev: v3.19.0 hooks: - id: pyupgrade args: [--py39-plus] @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.12.1 + rev: v1.13.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 85783bdc0ba86c3e772612a44b8825de1d24a6da Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 1 Nov 2024 15:24:51 +0100 Subject: [PATCH 360/416] Add support for julia hooks This patch adds 2nd class support for hooks using julia as the language. pre-commit will install any dependencies defined in the hooks repo `Project.toml` file, with support for `additional_dependencies` as well. Julia doesn't (yet) have a way to install binaries/scripts so for julia hooks the `entry` value is a (relative) path to a julia script within the hooks repository. When executing a julia hook the (globally installed) julia interpreter is prepended to the entry. Example `.pre-commit-hooks.yaml`: ```yaml - id: foo name: ... language: julia entry: bin/foo.jl --arg1 ``` Example hooks repo: https://github.com/fredrikekre/runic-pre-commit/tree/fe/julia Accompanying pre-commit.com PR: https://github.com/pre-commit/pre-commit.com/pull/998 Fixes #2689. --- pre_commit/all_languages.py | 2 + pre_commit/languages/julia.py | 132 ++++++++++++++++++++++++++++++++++ tests/languages/julia_test.py | 97 +++++++++++++++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 pre_commit/languages/julia.py create mode 100644 tests/languages/julia_test.py diff --git a/pre_commit/all_languages.py b/pre_commit/all_languages.py index f2d11bb6..ba569c37 100644 --- a/pre_commit/all_languages.py +++ b/pre_commit/all_languages.py @@ -10,6 +10,7 @@ from pre_commit.languages import dotnet from pre_commit.languages import fail from pre_commit.languages import golang from pre_commit.languages import haskell +from pre_commit.languages import julia from pre_commit.languages import lua from pre_commit.languages import node from pre_commit.languages import perl @@ -33,6 +34,7 @@ languages: dict[str, Language] = { 'fail': fail, 'golang': golang, 'haskell': haskell, + 'julia': julia, 'lua': lua, 'node': node, 'perl': perl, diff --git a/pre_commit/languages/julia.py b/pre_commit/languages/julia.py new file mode 100644 index 00000000..df91c069 --- /dev/null +++ b/pre_commit/languages/julia.py @@ -0,0 +1,132 @@ +from __future__ import annotations + +import contextlib +import os +import shutil +from collections.abc import Generator +from collections.abc import Sequence + +from pre_commit import lang_base +from pre_commit.envcontext import envcontext +from pre_commit.envcontext import PatchesT +from pre_commit.envcontext import UNSET +from pre_commit.prefix import Prefix +from pre_commit.util import cmd_output_b + +ENVIRONMENT_DIR = 'juliaenv' +health_check = lang_base.basic_health_check +get_default_version = lang_base.basic_get_default_version + + +def run_hook( + prefix: Prefix, + entry: str, + args: Sequence[str], + file_args: Sequence[str], + *, + is_local: bool, + require_serial: bool, + color: bool, +) -> tuple[int, bytes]: + # `entry` is a (hook-repo relative) file followed by (optional) args, e.g. + # `bin/id.jl` or `bin/hook.jl --arg1 --arg2` so we + # 1) shell parse it and join with args with hook_cmd + # 2) prepend the hooks prefix path to the first argument (the file), unless + # it is a local script + # 3) prepend `julia` as the interpreter + + cmd = lang_base.hook_cmd(entry, args) + script = cmd[0] if is_local else prefix.path(cmd[0]) + cmd = ('julia', script, *cmd[1:]) + return lang_base.run_xargs( + cmd, + file_args, + require_serial=require_serial, + color=color, + ) + + +def get_env_patch(target_dir: str, version: str) -> PatchesT: + return ( + ('JULIA_LOAD_PATH', target_dir), + # May be set, remove it to not interfer with LOAD_PATH + ('JULIA_PROJECT', UNSET), + ) + + +@contextlib.contextmanager +def in_env(prefix: Prefix, version: str) -> Generator[None]: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + with envcontext(get_env_patch(envdir, version)): + yield + + +def install_environment( + prefix: Prefix, + version: str, + additional_dependencies: Sequence[str], +) -> None: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + with in_env(prefix, version): + # TODO: Support language_version with juliaup similar to rust via + # rustup + # if version != 'system': + # ... + + # Copy Project.toml to hook env if it exist + os.makedirs(envdir, exist_ok=True) + project_names = ('JuliaProject.toml', 'Project.toml') + project_found = False + for project_name in project_names: + project_file = prefix.path(project_name) + if not os.path.isfile(project_file): + continue + shutil.copy(project_file, envdir) + project_found = True + break + + # If no project file was found we create an empty one so that the + # package manager doesn't error + if not project_found: + open(os.path.join(envdir, 'Project.toml'), 'a').close() + + # Copy Manifest.toml to hook env if it exists + manifest_names = ('JuliaManifest.toml', 'Manifest.toml') + for manifest_name in manifest_names: + manifest_file = prefix.path(manifest_name) + if not os.path.isfile(manifest_file): + continue + shutil.copy(manifest_file, envdir) + break + + # Julia code to instantiate the hook environment + julia_code = """ + @assert length(ARGS) > 0 + hook_env = ARGS[1] + deps = join(ARGS[2:end], " ") + + # We prepend @stdlib here so that we can load the package manager even + # though `get_env_patch` limits `JULIA_LOAD_PATH` to just the hook env. + pushfirst!(LOAD_PATH, "@stdlib") + using Pkg + popfirst!(LOAD_PATH) + + # Instantiate the environment shipped with the hook repo. If we have + # additional dependencies we disable precompilation in this step to + # avoid double work. + precompile = isempty(deps) ? "1" : "0" + withenv("JULIA_PKG_PRECOMPILE_AUTO" => precompile) do + Pkg.instantiate() + end + + # Add additional dependencies (with precompilation) + if !isempty(deps) + withenv("JULIA_PKG_PRECOMPILE_AUTO" => "1") do + Pkg.REPLMode.pkgstr("add " * deps) + end + end + """ + cmd_output_b( + 'julia', '-e', julia_code, '--', envdir, *additional_dependencies, + cwd=prefix.prefix_dir, + ) diff --git a/tests/languages/julia_test.py b/tests/languages/julia_test.py new file mode 100644 index 00000000..4ea3c25b --- /dev/null +++ b/tests/languages/julia_test.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +from pre_commit.languages import julia +from testing.language_helpers import run_language +from testing.util import cwd + + +def _make_hook(tmp_path, julia_code): + src_dir = tmp_path.joinpath('src') + src_dir.mkdir() + src_dir.joinpath('main.jl').write_text(julia_code) + tmp_path.joinpath('Project.toml').write_text( + '[deps]\n' + 'Example = "7876af07-990d-54b4-ab0e-23690620f79a"\n', + ) + + +def test_julia_hook(tmp_path): + code = """ + using Example + function main() + println("Hello, world!") + end + main() + """ + _make_hook(tmp_path, code) + expected = (0, b'Hello, world!\n') + assert run_language(tmp_path, julia, 'src/main.jl') == expected + + +def test_julia_hook_manifest(tmp_path): + code = """ + using Example + println(pkgversion(Example)) + """ + _make_hook(tmp_path, code) + + tmp_path.joinpath('Manifest.toml').write_text( + 'manifest_format = "2.0"\n\n' + '[[deps.Example]]\n' + 'git-tree-sha1 = "11820aa9c229fd3833d4bd69e5e75ef4e7273bf1"\n' + 'uuid = "7876af07-990d-54b4-ab0e-23690620f79a"\n' + 'version = "0.5.4"\n', + ) + expected = (0, b'0.5.4\n') + assert run_language(tmp_path, julia, 'src/main.jl') == expected + + +def test_julia_hook_args(tmp_path): + code = """ + function main(argv) + foreach(println, argv) + end + main(ARGS) + """ + _make_hook(tmp_path, code) + expected = (0, b'--arg1\n--arg2\n') + assert run_language( + tmp_path, julia, 'src/main.jl --arg1 --arg2', + ) == expected + + +def test_julia_hook_additional_deps(tmp_path): + code = """ + using TOML + function main() + project_file = Base.active_project() + dict = TOML.parsefile(project_file) + for (k, v) in dict["deps"] + println(k, " = ", v) + end + end + main() + """ + _make_hook(tmp_path, code) + deps = ('TOML=fa267f1f-6049-4f14-aa54-33bafae1ed76',) + ret, out = run_language(tmp_path, julia, 'src/main.jl', deps=deps) + assert ret == 0 + assert b'Example = 7876af07-990d-54b4-ab0e-23690620f79a' in out + assert b'TOML = fa267f1f-6049-4f14-aa54-33bafae1ed76' in out + + +def test_julia_repo_local(tmp_path): + env_dir = tmp_path.joinpath('envdir') + env_dir.mkdir() + local_dir = tmp_path.joinpath('local') + local_dir.mkdir() + local_dir.joinpath('local.jl').write_text( + 'using TOML; foreach(println, ARGS)', + ) + with cwd(local_dir): + deps = ('TOML=fa267f1f-6049-4f14-aa54-33bafae1ed76',) + expected = (0, b'--local-arg1\n--local-arg2\n') + assert run_language( + env_dir, julia, 'local.jl --local-arg1 --local-arg2', + deps=deps, is_local=True, + ) == expected From 109628c5058e6901cc69a1d0dfa3c2a0e0ea14d8 Mon Sep 17 00:00:00 2001 From: AleksaC Date: Thu, 19 Sep 2024 01:01:33 +0200 Subject: [PATCH 361/416] disable automatic toolchain switching for golang hooks --- pre_commit/languages/golang.py | 2 + tests/languages/golang_test.py | 69 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 60908796..678c04b1 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -75,6 +75,7 @@ def get_env_patch(venv: str, version: str) -> PatchesT: return ( ('GOROOT', os.path.join(venv, '.go')), + ('GOTOOLCHAIN', 'local'), ( 'PATH', ( os.path.join(venv, 'bin'), os.pathsep, @@ -145,6 +146,7 @@ def install_environment( env = no_git_env(dict(os.environ, GOPATH=gopath)) env.pop('GOBIN', None) if version != 'system': + env['GOTOOLCHAIN'] = 'local' env['GOROOT'] = os.path.join(env_dir, '.go') env['PATH'] = os.pathsep.join(( os.path.join(env_dir, '.go', 'bin'), os.environ['PATH'], diff --git a/tests/languages/golang_test.py b/tests/languages/golang_test.py index 02e35d71..7fb6ab18 100644 --- a/tests/languages/golang_test.py +++ b/tests/languages/golang_test.py @@ -11,11 +11,13 @@ from pre_commit.commands.install_uninstall import install from pre_commit.envcontext import envcontext from pre_commit.languages import golang from pre_commit.store import _make_local_repo +from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from testing.fixtures import add_config_to_repo from testing.fixtures import make_config_from_repo from testing.language_helpers import run_language from testing.util import cmd_output_mocked_pre_commit_home +from testing.util import cwd from testing.util import git_commit @@ -165,3 +167,70 @@ def test_during_commit_all(tmp_path, tempdir_factory, store, in_git_dir): fn=cmd_output_mocked_pre_commit_home, tempdir_factory=tempdir_factory, ) + + +def test_automatic_toolchain_switching(tmp_path): + go_mod = '''\ +module toolchain-version-test + +go 1.23.1 +''' + main_go = '''\ +package main + +func main() {} +''' + tmp_path.joinpath('go.mod').write_text(go_mod) + mod_dir = tmp_path.joinpath('toolchain-version-test') + mod_dir.mkdir() + main_file = mod_dir.joinpath('main.go') + main_file.write_text(main_go) + + with pytest.raises(CalledProcessError) as excinfo: + run_language( + path=tmp_path, + language=golang, + version='1.22.0', + exe='golang-version-test', + ) + + assert 'go.mod requires go >= 1.23.1' in excinfo.value.stderr.decode() + + +def test_automatic_toolchain_switching_go_fmt(tmp_path, monkeypatch): + go_mod_hook = '''\ +module toolchain-version-test + +go 1.22.0 +''' + go_mod = '''\ +module toolchain-version-test + +go 1.23.1 +''' + main_go = '''\ +package main + +func main() {} +''' + hook_dir = tmp_path.joinpath('hook') + hook_dir.mkdir() + hook_dir.joinpath('go.mod').write_text(go_mod_hook) + + test_dir = tmp_path.joinpath('test') + test_dir.mkdir() + test_dir.joinpath('go.mod').write_text(go_mod) + main_file = test_dir.joinpath('main.go') + main_file.write_text(main_go) + + with cwd(test_dir): + ret, out = run_language( + path=hook_dir, + language=golang, + version='1.22.0', + exe='go fmt', + file_args=(str(main_file),), + ) + + assert ret == 1 + assert 'go.mod requires go >= 1.23.1' in out.decode() From db85eeed2d114b1fb60cc6c969573fefa23c4fc8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:45:24 +0000 Subject: [PATCH 362/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.19.0 → v3.19.1](https://github.com/asottile/pyupgrade/compare/v3.19.0...v3.19.1) - [github.com/pre-commit/mirrors-mypy: v1.13.0 → v1.14.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.13.0...v1.14.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 614170ba..5743224e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.19.0 + rev: v3.19.1 hooks: - id: pyupgrade args: [--py39-plus] @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.13.0 + rev: v1.14.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] From aa85be934071e7c73fb49e9339e307285a784d16 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Dec 2024 15:43:55 -0500 Subject: [PATCH 363/416] fix docker_image test when ubuntu:22.04 image is not pre-pulled --- tests/languages/docker_image_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/languages/docker_image_test.py b/tests/languages/docker_image_test.py index 4e3a8789..4f720600 100644 --- a/tests/languages/docker_image_test.py +++ b/tests/languages/docker_image_test.py @@ -1,10 +1,18 @@ from __future__ import annotations +import pytest + from pre_commit.languages import docker_image +from pre_commit.util import cmd_output_b from testing.language_helpers import run_language from testing.util import xfailif_windows +@pytest.fixture(autouse=True, scope='module') +def _ensure_image_available(): + cmd_output_b('docker', 'run', '--rm', 'ubuntu:22.04', 'echo') + + @xfailif_windows # pragma: win32 no cover def test_docker_image_hook_via_entrypoint(tmp_path): ret = run_language( From 28c3d81bd27fe5e62eead459c1963a582e763bd7 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Dec 2024 15:50:58 -0500 Subject: [PATCH 364/416] update .net tests to use .net 8 .net 6 and 7 were removed from github actions runners --- tests/languages/dotnet_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/languages/dotnet_test.py b/tests/languages/dotnet_test.py index 470c03b2..ee408256 100644 --- a/tests/languages/dotnet_test.py +++ b/tests/languages/dotnet_test.py @@ -27,7 +27,7 @@ def _csproj(tool_name): Exe - net6 + net8 true {tool_name} ./nupkg From 77edad8455e88b403e055d2692c9545085cf3edb Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Dec 2024 16:06:00 -0500 Subject: [PATCH 365/416] install r on ubuntu runners this was removed in ubuntu-24.04 github actions runner --- .github/workflows/languages.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 7d50535f..61293a0d 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -65,6 +65,8 @@ jobs: if: matrix.os == 'windows-latest' && matrix.language == 'perl' - uses: haskell/actions/setup@v2 if: matrix.language == 'haskell' + - uses: r-lib/actions/setup-r@v2 + if: matrix.os == 'ubuntu-latest' && matrix.language == 'r' - name: install deps run: python -mpip install -e . -r requirements-dev.txt From 9b9f8e254d46da65c8544244c423596d54260e24 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 23:30:19 +0000 Subject: [PATCH 366/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.14.0 → v1.14.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.14.0...v1.14.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5743224e..4a23da2b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.14.0 + rev: v1.14.1 hooks: - id: mypy additional_dependencies: [types-pyyaml] From c2c061cf63e00a3ff8c88a9054c47e96a36f2daa Mon Sep 17 00:00:00 2001 From: Lorenz Walthert Date: Sun, 19 Jan 2025 19:43:24 +0100 Subject: [PATCH 367/416] fix: ensure env patch is applied for vanilla emulation otherwise, installing the hooks when RENV_USER env variable is set (e.g. in RStudio with renv project) will result in executing the installation script in the wrong renv --- pre_commit/languages/r.py | 48 +++++++++++++++++++++++++++++---------- tests/languages/r_test.py | 2 +- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index c75a3089..f70d2fdc 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -15,27 +15,50 @@ from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.prefix import Prefix from pre_commit.util import cmd_output -from pre_commit.util import cmd_output_b from pre_commit.util import win_exe ENVIRONMENT_DIR = 'renv' -RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ') get_default_version = lang_base.basic_get_default_version +_RENV_ACTIVATED_OPTS = ( + '--no-save', '--no-restore', '--no-site-file', '--no-environ', +) -def _execute_vanilla_r_code_as_script( + +def _execute_r( code: str, *, prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str, + cli_opts: Sequence[str], ) -> str: with in_env(prefix, version), _r_code_in_tempfile(code) as f: _, out, _ = cmd_output( - _rscript_exec(), *RSCRIPT_OPTS, f, *args, cwd=cwd, + _rscript_exec(), *cli_opts, f, *args, cwd=cwd, ) return out.rstrip('\n') +def _execute_r_in_renv( + code: str, *, + prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str, +) -> str: + return _execute_r( + code=code, prefix=prefix, version=version, args=args, cwd=cwd, + cli_opts=_RENV_ACTIVATED_OPTS, + ) + + +def _execute_vanilla_r( + code: str, *, + prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str, +) -> str: + return _execute_r( + code=code, prefix=prefix, version=version, args=args, cwd=cwd, + cli_opts=('--vanilla',), + ) + + def _read_installed_version(envdir: str, prefix: Prefix, version: str) -> str: - return _execute_vanilla_r_code_as_script( + return _execute_r_in_renv( 'cat(renv::settings$r.version())', prefix=prefix, version=version, cwd=envdir, @@ -43,7 +66,7 @@ def _read_installed_version(envdir: str, prefix: Prefix, version: str) -> str: def _read_executable_version(envdir: str, prefix: Prefix, version: str) -> str: - return _execute_vanilla_r_code_as_script( + return _execute_r_in_renv( 'cat(as.character(getRversion()))', prefix=prefix, version=version, cwd=envdir, @@ -53,7 +76,7 @@ def _read_executable_version(envdir: str, prefix: Prefix, version: str) -> str: def _write_current_r_version( envdir: str, prefix: Prefix, version: str, ) -> None: - _execute_vanilla_r_code_as_script( + _execute_r_in_renv( 'renv::settings$r.version(as.character(getRversion()))', prefix=prefix, version=version, cwd=envdir, @@ -161,7 +184,7 @@ def _cmd_from_hook( _entry_validate(cmd) cmd_part = _prefix_if_file_entry(cmd, prefix, is_local=is_local) - return (cmd[0], *RSCRIPT_OPTS, *cmd_part, *args) + return (cmd[0], *_RENV_ACTIVATED_OPTS, *cmd_part, *args) def install_environment( @@ -204,14 +227,15 @@ def install_environment( renv::install(prefix_dir) }} """ - - with _r_code_in_tempfile(r_code_inst_environment) as f: - cmd_output_b(_rscript_exec(), '--vanilla', f, cwd=env_dir) + _execute_vanilla_r( + r_code_inst_environment, + prefix=prefix, version=version, cwd=env_dir, + ) _write_current_r_version(envdir=env_dir, prefix=prefix, version=version) if additional_dependencies: r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' - _execute_vanilla_r_code_as_script( + _execute_r_in_renv( code=r_code_inst_add, prefix=prefix, version=version, args=additional_dependencies, cwd=env_dir, diff --git a/tests/languages/r_test.py b/tests/languages/r_test.py index 10919e4a..9e73129e 100644 --- a/tests/languages/r_test.py +++ b/tests/languages/r_test.py @@ -286,7 +286,7 @@ def test_health_check_without_version(prefix, installed_environment, version): prefix, env_dir = installed_environment # simulate old pre-commit install by unsetting the installed version - r._execute_vanilla_r_code_as_script( + r._execute_r_in_renv( f'renv::settings$r.version({version})', prefix=prefix, version=C.DEFAULT, cwd=env_dir, ) From b152e922ef11a97efe22ca7dc4f90011f0d1711c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 20 Jan 2025 13:35:33 -0500 Subject: [PATCH 368/416] v4.1.0 --- CHANGELOG.md | 18 ++++++++++++++++++ setup.cfg | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9b4c8c2..408afe68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +4.1.0 - 2025-01-20 +================== + +### Features +- Add `language: julia`. + - #3348 PR by @fredrikekre. + - #2689 issue @jmuchovej. + +### Fixes +- Disable automatic toolchain switching for `language: golang`. + - #3304 PR by @AleksaC. + - #3300 issue by @AleksaC. + - #3149 issue by @nijel. +- Fix `language: r` installation when initiated by RStudio. + - #3389 PR by @lorenzwalthert. + - #3385 issue by @lorenzwalthert. + + 4.0.1 - 2024-10-08 ================== diff --git a/setup.cfg b/setup.cfg index 6936a1f0..60d97641 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.0.1 +version = 4.1.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From edd0002e4312dc62fc8a236a3b4dc08d1012555d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 22:30:07 +0000 Subject: [PATCH 369/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/hhatto/autopep8: v2.3.1 → v2.3.2](https://github.com/hhatto/autopep8/compare/v2.3.1...v2.3.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4a23da2b..b7362292 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/hhatto/autopep8 - rev: v2.3.1 + rev: v2.3.2 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 From e2210c97e2128703e41cc19e66f24c23b9157f69 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 30 Jan 2025 14:58:50 -0500 Subject: [PATCH 370/416] upgrade asottile/workflows Committed via https://github.com/asottile/all-repos --- .github/workflows/languages.yaml | 2 +- .github/workflows/main.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 61293a0d..fccf2989 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -36,7 +36,7 @@ jobs: matrix: include: ${{ fromJSON(needs.vars.outputs.languages) }} steps: - - uses: asottile/workflows/.github/actions/fast-checkout@v1.4.0 + - uses: asottile/workflows/.github/actions/fast-checkout@v1.8.1 - uses: actions/setup-python@v4 with: python-version: 3.9 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2355b662..7fda646f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,12 +12,12 @@ concurrency: jobs: main-windows: - uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 + uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 with: env: '["py39"]' os: windows-latest main-linux: - uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0 + uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 with: env: '["py39", "py310", "py311", "py312"]' os: ubuntu-latest From 4f90a1e88a80dd460f36e21d774d06bf0e73921b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 22:44:01 +0000 Subject: [PATCH 371/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.14.1 → v1.15.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.14.1...v1.15.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b7362292..ead07d89 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.14.1 + rev: v1.15.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 94b97e28f7cc7d9bcb536d7a3cf7ef6311e076fd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 21:07:26 +0000 Subject: [PATCH 372/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 7.1.1 → 7.1.2](https://github.com/PyCQA/flake8/compare/7.1.1...7.1.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ead07d89..b216fbd6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 7.1.1 + rev: 7.1.2 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From b7eb412c798424a94ca83c72eed6f97271545dc4 Mon Sep 17 00:00:00 2001 From: Tushar Sadhwani Date: Thu, 13 Mar 2025 17:29:20 +0530 Subject: [PATCH 373/416] fix: crash on ambiguous ref 'HEAD' --- pre_commit/git.py | 2 +- tests/git_test.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index 19aac387..2f424f89 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -126,7 +126,7 @@ def get_conflicted_files() -> set[str]: merge_diff_filenames = zsplit( cmd_output( 'git', 'diff', '--name-only', '--no-ext-diff', '-z', - '-m', tree_hash, 'HEAD', 'MERGE_HEAD', + '-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--', )[1], ) return set(merge_conflict_filenames) | set(merge_diff_filenames) diff --git a/tests/git_test.py b/tests/git_test.py index 93f5a1c6..02b6ce3a 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -141,6 +141,15 @@ def test_get_conflicted_files_unstaged_files(in_merge_conflict): assert ret == {'conflict_file'} +def test_get_conflicted_files_with_file_named_head(in_merge_conflict): + resolve_conflict() + open('HEAD', 'w').close() + cmd_output('git', 'add', 'HEAD') + + ret = set(git.get_conflicted_files()) + assert ret == {'conflict_file', 'HEAD'} + + MERGE_MSG = b"Merge branch 'foo' into bar\n\nConflicts:\n\tconflict_file\n" OTHER_MERGE_MSG = MERGE_MSG + b'\tother_conflict_file\n' From 3e8d0f5e1c449381272b80241140e985631f9912 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 18 Mar 2025 14:55:24 -0400 Subject: [PATCH 374/416] adjust python default_language_version to prefer versioned exe --- pre_commit/languages/python.py | 34 ++++++++++++----- tests/languages/python_test.py | 67 ++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 10 deletions(-) diff --git a/pre_commit/languages/python.py b/pre_commit/languages/python.py index 0c4bb62d..88ececce 100644 --- a/pre_commit/languages/python.py +++ b/pre_commit/languages/python.py @@ -75,6 +75,13 @@ def _find_by_py_launcher( return None +def _impl_exe_name() -> str: + if sys.implementation.name == 'cpython': # pragma: cpython cover + return 'python' + else: # pragma: cpython no cover + return sys.implementation.name # pypy mostly + + def _find_by_sys_executable() -> str | None: def _norm(path: str) -> str | None: _, exe = os.path.split(path.lower()) @@ -100,18 +107,25 @@ def _find_by_sys_executable() -> str | None: @functools.lru_cache(maxsize=1) def get_default_version() -> str: # pragma: no cover (platform dependent) - # First attempt from `sys.executable` (or the realpath) - exe = _find_by_sys_executable() - if exe: - return exe + v_major = f'{sys.version_info[0]}' + v_minor = f'{sys.version_info[0]}.{sys.version_info[1]}' - # Next try the `pythonX.X` executable - exe = f'python{sys.version_info[0]}.{sys.version_info[1]}' - if find_executable(exe): - return exe + # attempt the likely implementation exe + for potential in (v_minor, v_major): + exe = f'{_impl_exe_name()}{potential}' + if find_executable(exe): + return exe - if _find_by_py_launcher(exe): - return exe + # next try `sys.executable` (or the realpath) + maybe_exe = _find_by_sys_executable() + if maybe_exe: + return maybe_exe + + # maybe on windows we can find it via py launcher? + if sys.platform == 'win32': # pragma: win32 cover + exe = f'python{v_minor}' + if _find_by_py_launcher(exe): + return exe # We tried! return C.DEFAULT diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index ab26e14e..565525a4 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -12,6 +12,7 @@ from pre_commit.languages import python from pre_commit.prefix import Prefix from pre_commit.util import make_executable from pre_commit.util import win_exe +from testing.auto_namedtuple import auto_namedtuple from testing.language_helpers import run_language @@ -34,6 +35,72 @@ def test_read_pyvenv_cfg_non_utf8(tmpdir): assert python._read_pyvenv_cfg(pyvenv_cfg) == expected +def _get_default_version( + *, + impl: str, + exe: str, + found: set[str], + version: tuple[int, int], +) -> str: + sys_exe = f'/fake/path/{exe}' + sys_impl = auto_namedtuple(name=impl) + sys_ver = auto_namedtuple(major=version[0], minor=version[1]) + + def find_exe(s): + if s in found: + return f'/fake/path/found/{exe}' + else: + return None + + with ( + mock.patch.object(sys, 'implementation', sys_impl), + mock.patch.object(sys, 'executable', sys_exe), + mock.patch.object(sys, 'version_info', sys_ver), + mock.patch.object(python, 'find_executable', find_exe), + ): + return python.get_default_version.__wrapped__() + + +def test_default_version_sys_executable_found(): + ret = _get_default_version( + impl='cpython', + exe='python3.12', + found={'python3.12'}, + version=(3, 12), + ) + assert ret == 'python3.12' + + +def test_default_version_picks_specific_when_found(): + ret = _get_default_version( + impl='cpython', + exe='python3', + found={'python3', 'python3.12'}, + version=(3, 12), + ) + assert ret == 'python3.12' + + +def test_default_version_picks_pypy_versioned_exe(): + ret = _get_default_version( + impl='pypy', + exe='python', + found={'pypy3.12', 'python3'}, + version=(3, 12), + ) + assert ret == 'pypy3.12' + + +def test_default_version_picks_pypy_unversioned_exe(): + ret = _get_default_version( + impl='pypy', + exe='python', + found={'pypy3', 'python3'}, + version=(3, 12), + ) + assert ret == 'pypy3' + + def test_norm_version_expanduser(): home = os.path.expanduser('~') if sys.platform == 'win32': # pragma: win32 cover From aa48766b888990e7b118d12cf757109d96e65a7e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 18 Mar 2025 17:34:49 -0400 Subject: [PATCH 375/416] v4.2.0 --- CHANGELOG.md | 13 +++++++++++++ setup.cfg | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 408afe68..b63f4431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +4.2.0 - 2025-03-18 +================== + +### Features +- For `language: python` first attempt a versioned python executable for + the default language version before consulting a potentially unversioned + `sys.executable`. + - #3430 PR by @asottile. + +### Fixes +- Handle error during conflict detection when a file is named "HEAD" + - #3425 PR by @tusharsadhwani. + 4.1.0 - 2025-01-20 ================== diff --git a/setup.cfg b/setup.cfg index 60d97641..af34452d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.1.0 +version = 4.2.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 6d47b8d52bd53320807886edd82b6fb4e1c67089 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 19:43:51 +0000 Subject: [PATCH 376/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.7.0 → v2.8.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.7.0...v2.8.0) - [github.com/PyCQA/flake8: 7.1.2 → 7.2.0](https://github.com/PyCQA/flake8/compare/7.1.2...7.2.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b216fbd6..a19b44bc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.7.0 + rev: v2.8.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports @@ -33,7 +33,7 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 7.1.2 + rev: 7.2.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy From 43592c2a29c587aab7f70046a02ef95893841e67 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 19:44:12 +0000 Subject: [PATCH 377/416] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index af34452d..90f49df9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,6 @@ author_email = asottile@umich.edu license = MIT license_files = LICENSE classifiers = - License :: OSI Approved :: MIT License Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: Implementation :: CPython From 466f6c4a3939375dc2dc7a2fc34f553c2715d738 Mon Sep 17 00:00:00 2001 From: Matthew Hughes Date: Sun, 13 Apr 2025 11:18:18 +0100 Subject: [PATCH 378/416] Fix permission errors for mounts in rootless docker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By running containers in a rootless docker context as root. This is because user and group IDs are remapped in the user namespaces uses by rootless docker, and it's unlikely that the current user ID will map to the same ID under this remap (see docs[1] for some more details). Specifically, it means ownership of mounted volumes will not be for the current user and trying to write can result in permission errors. This change borrows heavily from an existing PR[2]. The output format of `docker system info` I don't think is documented/guaranteed anywhere, but it should corresponding to the format of a `/info` API request to Docker[3] The added test _hopes_ to avoid regressions in this behaviour, but since tests aren't run in a rootless docker context on the PR checks (and I couldn't find an easy way to make it the case) there's still a risk of regressions sneaking in. Link: https://docs.docker.com/engine/security/rootless/ [1] Link: https://github.com/pre-commit/pre-commit/pull/1484/ [2] Link: https://docs.docker.com/reference/api/engine/version/v1.48/#tag/System/operation/SystemAuth [3] Co-authored-by: Kurt von Laven Co-authored-by: Fabrice Flore-Thébault --- pre_commit/languages/docker.py | 26 +++++++++++++++++++ tests/languages/docker_test.py | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 4de1d582..086e874d 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -1,5 +1,6 @@ from __future__ import annotations +import functools import hashlib import json import os @@ -101,7 +102,32 @@ def install_environment( os.mkdir(directory) +@functools.lru_cache(maxsize=1) +def _is_rootless() -> bool: # pragma: win32 no cover + retcode, out, _ = cmd_output_b( + 'docker', 'system', 'info', '--format', '{{ json . }}', + ) + if retcode != 0: + return False + + info = json.loads(out) + try: + return ( + # docker: + # https://docs.docker.com/reference/api/engine/version/v1.48/#tag/System/operation/SystemInfo + 'name=rootless' in info.get('SecurityOptions', ()) or + # podman: + # https://docs.podman.io/en/latest/_static/api.html?version=v5.4#tag/system/operation/SystemInfoLibpod + info['host']['security']['rootless'] + ) + except KeyError: + return False + + def get_docker_user() -> tuple[str, ...]: # pragma: win32 no cover + if _is_rootless(): + return () + try: return ('-u', f'{os.getuid()}:{os.getgid()}') except AttributeError: diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index 836382a8..03235c46 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -62,6 +62,42 @@ def test_docker_fallback_user(): assert docker.get_docker_user() == () +@pytest.fixture(autouse=True) +def _avoid_cache(): + with mock.patch.object( + docker, + '_is_rootless', + docker._is_rootless.__wrapped__, + ): + yield + + +@pytest.mark.parametrize( + 'info_ret', + ( + (0, b'{"SecurityOptions": ["name=rootless","name=cgroupns"]}', b''), + (0, b'{"host": {"security": {"rootless": true}}}', b''), + ), +) +def test_docker_user_rootless(info_ret): + with mock.patch.object(docker, 'cmd_output_b', return_value=info_ret): + assert docker.get_docker_user() == () + + +@pytest.mark.parametrize( + 'info_ret', + ( + (0, b'{"SecurityOptions": ["name=cgroupns"]}', b''), + (0, b'{"host": {"security": {"rootless": false}}}', b''), + (0, b'{"respone_from_some_other_container_engine": true}', b''), + (1, b'', b''), + ), +) +def test_docker_user_non_rootless(info_ret): + with mock.patch.object(docker, 'cmd_output_b', return_value=info_ret): + assert docker.get_docker_user() != () + + def test_in_docker_no_file(): with mock.patch.object(builtins, 'open', side_effect=FileNotFoundError): assert docker._is_in_docker() is False @@ -195,3 +231,14 @@ CMD ["echo", "This is overwritten by the entry"'] ret = run_language(tmp_path, docker, 'echo hello hello world') assert ret == (0, b'hello hello world\n') + + +@xfailif_windows # pragma: win32 no cover +def test_docker_hook_mount_permissions(tmp_path): + dockerfile = '''\ +FROM ubuntu:22.04 +''' + tmp_path.joinpath('Dockerfile').write_text(dockerfile) + + retcode, _ = run_language(tmp_path, docker, 'touch', ('README.md',)) + assert retcode == 0 From 43b426a501e621cc1c837f07b5633cb12525e79b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 19:45:48 +0000 Subject: [PATCH 379/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/reorder-python-imports: v3.14.0 → v3.15.0](https://github.com/asottile/reorder-python-imports/compare/v3.14.0...v3.15.0) - [github.com/asottile/add-trailing-comma: v3.1.0 → v3.2.0](https://github.com/asottile/add-trailing-comma/compare/v3.1.0...v3.2.0) - [github.com/asottile/pyupgrade: v3.19.1 → v3.20.0](https://github.com/asottile/pyupgrade/compare/v3.19.1...v3.20.0) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a19b44bc..97d1174d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,17 +14,17 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.14.0 + rev: v3.15.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py39-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v3.1.0 + rev: v3.2.0 hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.19.1 + rev: v3.20.0 hooks: - id: pyupgrade args: [--py39-plus] From d4f0c6e8a7db7c29177f16fe3e56ab5c9aad7d73 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 19:57:10 +0000 Subject: [PATCH 380/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.15.0 → v1.16.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.15.0...v1.16.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 97d1174d..4ddf3406 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.15.0 + rev: v1.16.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] From d1d5b3d5648d213f8dcb1648eae77b411a27ac05 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:55:22 +0000 Subject: [PATCH 381/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 7.2.0 → 7.3.0](https://github.com/PyCQA/flake8/compare/7.2.0...7.3.0) - [github.com/pre-commit/mirrors-mypy: v1.16.0 → v1.16.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.16.0...v1.16.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4ddf3406..2dc7f4c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,11 +33,11 @@ repos: hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 7.2.0 + rev: 7.3.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.16.0 + rev: v1.16.1 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 4fd4537bc69e6804998d99e4851a9dbe43e91757 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 20:02:20 +0000 Subject: [PATCH 382/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.16.1 → v1.17.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.16.1...v1.17.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2dc7f4c1..3ef94b45 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.16.1 + rev: v1.17.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 6f1f433a9cea94a70828ade95931a703c9a9c82b Mon Sep 17 00:00:00 2001 From: Eric Hanson <5846501+ericphanson@users.noreply.github.com> Date: Mon, 21 Jul 2025 18:05:54 +0200 Subject: [PATCH 383/416] Julia language: skip startup.jl file --- pre_commit/languages/julia.py | 5 +++-- tests/languages/julia_test.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/julia.py b/pre_commit/languages/julia.py index df91c069..7559b5ba 100644 --- a/pre_commit/languages/julia.py +++ b/pre_commit/languages/julia.py @@ -37,7 +37,7 @@ def run_hook( cmd = lang_base.hook_cmd(entry, args) script = cmd[0] if is_local else prefix.path(cmd[0]) - cmd = ('julia', script, *cmd[1:]) + cmd = ('julia', '--startup-file=no', script, *cmd[1:]) return lang_base.run_xargs( cmd, file_args, @@ -127,6 +127,7 @@ def install_environment( end """ cmd_output_b( - 'julia', '-e', julia_code, '--', envdir, *additional_dependencies, + 'julia', '--startup-file=no', '-e', julia_code, '--', envdir, + *additional_dependencies, cwd=prefix.prefix_dir, ) diff --git a/tests/languages/julia_test.py b/tests/languages/julia_test.py index 4ea3c25b..175622d6 100644 --- a/tests/languages/julia_test.py +++ b/tests/languages/julia_test.py @@ -1,5 +1,8 @@ from __future__ import annotations +import os +from unittest import mock + from pre_commit.languages import julia from testing.language_helpers import run_language from testing.util import cwd @@ -28,6 +31,17 @@ def test_julia_hook(tmp_path): assert run_language(tmp_path, julia, 'src/main.jl') == expected +def test_julia_hook_with_startup(tmp_path): + depot_path = tmp_path.joinpath('depot') + depot_path.joinpath('config').mkdir(parents=True) + startup = depot_path.joinpath('config', 'startup.jl') + startup.write_text('error("Startup file used!")\n') + + depo_path_var = f'{depot_path}{os.pathsep}' + with mock.patch.dict(os.environ, {'JULIA_DEPOT_PATH': depo_path_var}): + test_julia_hook(tmp_path) + + def test_julia_hook_manifest(tmp_path): code = """ using Example From c8925a457afb1d6850c8f105671846bae408aae0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 20:31:31 +0000 Subject: [PATCH 384/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.17.0 → v1.17.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.17.0...v1.17.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3ef94b45..da8e24ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.17.0 + rev: v1.17.1 hooks: - id: mypy additional_dependencies: [types-pyyaml] From f1cc7a445f1adbfc9ea4072e180fbe3054af669b Mon Sep 17 00:00:00 2001 From: Byoungchan Lee Date: Fri, 8 Aug 2025 17:02:53 +0900 Subject: [PATCH 385/416] Make Dart pre-commit hook compatible with the latest Dart SDKs Dart introduced sound null safety in version 2.12.0, and as of Dart 3, null safety is mandatory. Older Dart SDKs allowed both pre-null safety and null-safe packages, but modern Dart SDKs, where most source code is null-safe, now reject pre-null safety packages. The current `pubspec.yaml` template with `sdk: '>=2.10.0'` is incompatible with recent Dart SDKs, leading to the following error: An unexpected error has occurred: CalledProcessError: command: ('/path/to/dart-sdk/bin/dart', 'pub', 'get') return code: 65 stdout: Resolving dependencies... stderr: The lower bound of "sdk: '>=2.10.0'" must be 2.12.0' or higher to enable null safety. The current Dart SDK (3.8.3) only supports null safety. For details, see https://dart.dev/null-safety To ensure compatibility with the modern Dart ecosystem, this commit updates the minimum Dart SDK version to 2.12.0 or higher, which implicitly supports null safety. Additionally, `testing/get-dart.sh` has been updated to verify that the pre-commit hook functions correctly with the latest Dart versions. --- pre_commit/resources/empty_template_pubspec.yaml | 2 +- testing/get-dart.sh | 2 +- tests/languages/dart_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pre_commit/resources/empty_template_pubspec.yaml b/pre_commit/resources/empty_template_pubspec.yaml index 3be6ffe3..8306aeb6 100644 --- a/pre_commit/resources/empty_template_pubspec.yaml +++ b/pre_commit/resources/empty_template_pubspec.yaml @@ -1,4 +1,4 @@ name: pre_commit_empty_pubspec environment: - sdk: '>=2.10.0' + sdk: '>=2.12.0' executables: {} diff --git a/testing/get-dart.sh b/testing/get-dart.sh index 998b9d98..3402c421 100755 --- a/testing/get-dart.sh +++ b/testing/get-dart.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -VERSION=2.13.4 +VERSION=3.8.3 if [ "$OSTYPE" = msys ]; then URL="https://storage.googleapis.com/dart-archive/channels/stable/release/${VERSION}/sdk/dartsdk-windows-x64-release.zip" diff --git a/tests/languages/dart_test.py b/tests/languages/dart_test.py index 5bb5aa68..213d888e 100644 --- a/tests/languages/dart_test.py +++ b/tests/languages/dart_test.py @@ -10,7 +10,7 @@ from testing.language_helpers import run_language def test_dart(tmp_path): pubspec_yaml = '''\ environment: - sdk: '>=2.10.0 <3.0.0' + sdk: '>=2.12.0 <4.0.0' name: hello_world_dart From 2a0bcea7570620416a550362d9b2d2b24eb80dd8 Mon Sep 17 00:00:00 2001 From: Byoungchan Lee Date: Fri, 8 Aug 2025 17:40:30 +0900 Subject: [PATCH 386/416] Downgrade Dart SDK version installed in the CI --- testing/get-dart.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/get-dart.sh b/testing/get-dart.sh index 3402c421..b4545e71 100755 --- a/testing/get-dart.sh +++ b/testing/get-dart.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -VERSION=3.8.3 +VERSION=2.19.6 if [ "$OSTYPE" = msys ]; then URL="https://storage.googleapis.com/dart-archive/channels/stable/release/${VERSION}/sdk/dartsdk-windows-x64-release.zip" From b74a22d96cca546b8e0bb9f68f1d7d8565205b65 Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 9 Aug 2025 14:54:49 -0400 Subject: [PATCH 387/416] v4.3.0 --- CHANGELOG.md | 13 +++++++++++++ setup.cfg | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b63f4431..42a63f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +4.3.0 - 2025-08-09 +================== + +### Features +- `language: docker` / `language: docker_image`: detect rootless docker. + - #3446 PR by @matthewhughes934. + - #1243 issue by @dkolepp. +- `language: julia`: avoid `startup.jl` when executing hooks. + - #3496 PR by @ericphanson. +- `language: dart`: support latest dart versions which require a higher sdk + lower bound. + - #3507 PR by @bc-lee. + 4.2.0 - 2025-03-18 ================== diff --git a/setup.cfg b/setup.cfg index 90f49df9..9b0e02ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.2.0 +version = 4.3.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 87a681f8662554ee888a02e162d8772d64eee6cc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:46:13 +0000 Subject: [PATCH 388/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v5.0.0...v6.0.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index da8e24ad..464cfe60 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer From c78f248c60846fa48c9d38b488f3acc0fed96207 Mon Sep 17 00:00:00 2001 From: JulianMaurin Date: Mon, 25 Aug 2025 23:20:07 +0200 Subject: [PATCH 389/416] Add fail-fast argument for run command --- pre_commit/commands/hook_impl.py | 1 + pre_commit/commands/run.py | 3 ++- pre_commit/main.py | 4 ++++ testing/util.py | 2 ++ tests/commands/run_test.py | 13 +++++++++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pre_commit/commands/hook_impl.py b/pre_commit/commands/hook_impl.py index 49a80b7b..de5c8f34 100644 --- a/pre_commit/commands/hook_impl.py +++ b/pre_commit/commands/hook_impl.py @@ -106,6 +106,7 @@ def _ns( hook=None, verbose=False, show_diff_on_failure=False, + fail_fast=False, ) diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 793adbdb..8ab505ff 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -298,7 +298,8 @@ def _run_hooks( verbose=args.verbose, use_color=args.color, ) retval |= current_retval - if current_retval and (config['fail_fast'] or hook.fail_fast): + fail_fast = (config['fail_fast'] or hook.fail_fast or args.fail_fast) + if current_retval and fail_fast: break if retval and args.show_diff_on_failure and prior_diff: if args.all_files: diff --git a/pre_commit/main.py b/pre_commit/main.py index 559c927c..fc4531b8 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -76,6 +76,10 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None: '--show-diff-on-failure', action='store_true', help='When hooks fail, run `git diff` directly afterward.', ) + parser.add_argument( + '--fail-fast', action='store_true', + help='Stop after the first failing hook.', + ) parser.add_argument( '--hook-stage', choices=clientlib.STAGES, diff --git a/testing/util.py b/testing/util.py index 08d52cbc..1646ccd2 100644 --- a/testing/util.py +++ b/testing/util.py @@ -40,6 +40,7 @@ def run_opts( color=False, verbose=False, hook=None, + fail_fast=False, remote_branch='', local_branch='', from_ref='', @@ -65,6 +66,7 @@ def run_opts( color=color, verbose=verbose, hook=hook, + fail_fast=fail_fast, remote_branch=remote_branch, local_branch=local_branch, from_ref=from_ref, diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index 50a20f37..e4af1e16 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -1104,6 +1104,19 @@ def test_fail_fast_not_prev_failures(cap_out, store, repo_with_failing_hook): assert printed.count(b'run me!') == 1 +def test_fail_fast_run_arg(cap_out, store, repo_with_failing_hook): + with modify_config() as config: + # More than one hook to demonstrate early exit + config['repos'][0]['hooks'] *= 2 + stage_a_file() + + ret, printed = _do_run( + cap_out, store, repo_with_failing_hook, run_opts(fail_fast=True), + ) + # it should have only run one hook due to the CLI flag + assert printed.count(b'Failing hook') == 1 + + def test_classifier_removes_dne(): classifier = Classifier(('this_file_does_not_exist',)) assert classifier.filenames == [] From e67183040220cd8662b5b886b24841e2d04bac9c Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 6 Sep 2025 14:20:01 -0400 Subject: [PATCH 390/416] store_true does not need default=... --- pre_commit/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pre_commit/main.py b/pre_commit/main.py index 559c927c..b7ac3dc2 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -62,10 +62,10 @@ def _add_hook_type_option(parser: argparse.ArgumentParser) -> None: def _add_run_options(parser: argparse.ArgumentParser) -> None: parser.add_argument('hook', nargs='?', help='A single hook-id to run') - parser.add_argument('--verbose', '-v', action='store_true', default=False) + parser.add_argument('--verbose', '-v', action='store_true') mutex_group = parser.add_mutually_exclusive_group(required=False) mutex_group.add_argument( - '--all-files', '-a', action='store_true', default=False, + '--all-files', '-a', action='store_true', help='Run on all the files in the repo.', ) mutex_group.add_argument( @@ -275,7 +275,7 @@ def main(argv: Sequence[str] | None = None) -> int: ) _add_hook_type_option(install_parser) install_parser.add_argument( - '--allow-missing-config', action='store_true', default=False, + '--allow-missing-config', action='store_true', help=( 'Whether to allow a missing `pre-commit` configuration file ' 'or exit with a failure code.' From 2930ea0fcd481f4c2cbeae0245a8bb748bae905a Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 6 Sep 2025 14:40:20 -0400 Subject: [PATCH 391/416] handle `SecurityOptions: null` in docker response --- pre_commit/languages/docker.py | 2 +- tests/languages/docker_test.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 086e874d..d5ce1eb7 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -115,7 +115,7 @@ def _is_rootless() -> bool: # pragma: win32 no cover return ( # docker: # https://docs.docker.com/reference/api/engine/version/v1.48/#tag/System/operation/SystemInfo - 'name=rootless' in info.get('SecurityOptions', ()) or + 'name=rootless' in (info.get('SecurityOptions') or ()) or # podman: # https://docs.podman.io/en/latest/_static/api.html?version=v5.4#tag/system/operation/SystemInfoLibpod info['host']['security']['rootless'] diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index 03235c46..b830439a 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -89,7 +89,8 @@ def test_docker_user_rootless(info_ret): ( (0, b'{"SecurityOptions": ["name=cgroupns"]}', b''), (0, b'{"host": {"security": {"rootless": false}}}', b''), - (0, b'{"respone_from_some_other_container_engine": true}', b''), + (0, b'{"response_from_some_other_container_engine": true}', b''), + (0, b'{"SecurityOptions": null}', b''), (1, b'', b''), ), ) From ad0d4cd4271cab68ddbf5e5c3386f38320e0ccd2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:44:04 +0000 Subject: [PATCH 392/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.17.1 → v1.18.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.17.1...v1.18.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 464cfe60..0a24427f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.17.1 + rev: v1.18.2 hooks: - id: mypy additional_dependencies: [types-pyyaml] From f415f6c4d72224363ba794429b25cc3f52e04933 Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Thu, 9 Oct 2025 17:44:05 -0400 Subject: [PATCH 393/416] py310+ Committed via https://github.com/asottile/all-repos --- .github/workflows/languages.yaml | 4 ++-- .github/workflows/main.yml | 4 ++-- .pre-commit-config.yaml | 4 ++-- pre_commit/commands/migrate_config.py | 2 +- pre_commit/file_lock.py | 2 +- pre_commit/languages/golang.py | 3 +-- pre_commit/store.py | 2 +- pre_commit/util.py | 2 +- pre_commit/xargs.py | 2 +- setup.cfg | 2 +- 10 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index fccf2989..be8963ba 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -21,7 +21,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: '3.10' - name: install deps run: python -mpip install -e . -r requirements-dev.txt - name: vars @@ -39,7 +39,7 @@ jobs: - uses: asottile/workflows/.github/actions/fast-checkout@v1.8.1 - uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: '3.10' - run: echo "$CONDA\Scripts" >> "$GITHUB_PATH" shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7fda646f..02b11ae2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,10 +14,10 @@ jobs: main-windows: uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 with: - env: '["py39"]' + env: '["py310"]' os: windows-latest main-linux: uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1 with: - env: '["py39", "py310", "py311", "py312"]' + env: '["py310", "py311", "py312", "py313"]' os: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a24427f..58b96f76 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) - args: [--py39-plus, --add-import, 'from __future__ import annotations'] + args: [--py310-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v3.2.0 hooks: @@ -27,7 +27,7 @@ repos: rev: v3.20.0 hooks: - id: pyupgrade - args: [--py39-plus] + args: [--py310-plus] - repo: https://github.com/hhatto/autopep8 rev: v2.3.2 hooks: diff --git a/pre_commit/commands/migrate_config.py b/pre_commit/commands/migrate_config.py index c5d47a08..b04c53a5 100644 --- a/pre_commit/commands/migrate_config.py +++ b/pre_commit/commands/migrate_config.py @@ -3,7 +3,7 @@ from __future__ import annotations import functools import itertools import textwrap -from typing import Callable +from collections.abc import Callable import cfgv import yaml diff --git a/pre_commit/file_lock.py b/pre_commit/file_lock.py index c840ad8b..6223f869 100644 --- a/pre_commit/file_lock.py +++ b/pre_commit/file_lock.py @@ -3,8 +3,8 @@ from __future__ import annotations import contextlib import errno import sys +from collections.abc import Callable from collections.abc import Generator -from typing import Callable if sys.platform == 'win32': # pragma: no cover (windows) diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py index 678c04b1..bedbd114 100644 --- a/pre_commit/languages/golang.py +++ b/pre_commit/languages/golang.py @@ -90,8 +90,7 @@ def _infer_go_version(version: str) -> str: if version != C.DEFAULT: return version resp = urllib.request.urlopen('https://go.dev/dl/?mode=json') - # TODO: 3.9+ .removeprefix('go') - return json.load(resp)[0]['version'][2:] + return json.load(resp)[0]['version'].removeprefix('go') def _get_url(version: str) -> str: diff --git a/pre_commit/store.py b/pre_commit/store.py index 1235942c..9e3b4048 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -5,9 +5,9 @@ import logging import os.path import sqlite3 import tempfile +from collections.abc import Callable from collections.abc import Generator from collections.abc import Sequence -from typing import Callable import pre_commit.constants as C from pre_commit import clientlib diff --git a/pre_commit/util.py b/pre_commit/util.py index e199d080..19b1880b 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -8,10 +8,10 @@ import shutil import stat import subprocess import sys +from collections.abc import Callable from collections.abc import Generator from types import TracebackType from typing import Any -from typing import Callable from pre_commit import parse_shebang diff --git a/pre_commit/xargs.py b/pre_commit/xargs.py index a1345b58..7c98d167 100644 --- a/pre_commit/xargs.py +++ b/pre_commit/xargs.py @@ -7,12 +7,12 @@ import multiprocessing import os import subprocess import sys +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import MutableMapping from collections.abc import Sequence from typing import Any -from typing import Callable from typing import TypeVar from pre_commit import parse_shebang diff --git a/setup.cfg b/setup.cfg index 9b0e02ad..8fb6e6aa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,7 +23,7 @@ install_requires = nodeenv>=0.11.1 pyyaml>=5.1 virtualenv>=20.10.0 -python_requires = >=3.9 +python_requires = >=3.10 [options.packages.find] exclude = From 221637b0cbdfbfe8ca209ba5df0111b08f9d8cda Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:38:45 +0000 Subject: [PATCH 394/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v2.8.0 → v3.1.0](https://github.com/asottile/setup-cfg-fmt/compare/v2.8.0...v3.1.0) - [github.com/asottile/reorder-python-imports: v3.15.0 → v3.16.0](https://github.com/asottile/reorder-python-imports/compare/v3.15.0...v3.16.0) - [github.com/asottile/add-trailing-comma: v3.2.0 → v4.0.0](https://github.com/asottile/add-trailing-comma/compare/v3.2.0...v4.0.0) - [github.com/asottile/pyupgrade: v3.20.0 → v3.21.0](https://github.com/asottile/pyupgrade/compare/v3.20.0...v3.21.0) --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 58b96f76..b1623a64 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,21 +10,21 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.8.0 + rev: v3.1.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports - rev: v3.15.0 + rev: v3.16.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py310-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v3.2.0 + rev: v4.0.0 hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.20.0 + rev: v3.21.0 hooks: - id: pyupgrade args: [--py310-plus] From ddfcf4034bc72445497b5e6708205523a9da7ed7 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 16 Oct 2025 10:23:27 -0400 Subject: [PATCH 395/416] fix deprecated call --- pre_commit/git.py | 2 +- setup.cfg | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index 2f424f89..ec1928f3 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -219,7 +219,7 @@ def check_for_cygwin_mismatch() -> None: if is_cygwin_python ^ is_cygwin_git: exe_type = {True: '(cygwin)', False: '(windows)'} - logger.warn( + logger.warning( f'pre-commit has detected a mix of cygwin python / git\n' f'This combination is not supported, it is likely you will ' f'receive an error later in the program.\n' diff --git a/setup.cfg b/setup.cfg index 8fb6e6aa..17c3fe0e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -52,6 +52,7 @@ check_untyped_defs = true disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_defs = true +enable_error_code = deprecated warn_redundant_casts = true warn_unused_ignores = true From fc33a62f3c55c671cdef8306b6c3dc91d81e2b4a Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Fri, 24 Oct 2025 15:18:07 -0400 Subject: [PATCH 396/416] upgrade rbenv / ruby-build --- pre_commit/resources/rbenv.tar.gz | Bin 32545 -> 31297 bytes pre_commit/resources/ruby-build.tar.gz | Bin 88488 -> 93998 bytes testing/make-archives | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pre_commit/resources/rbenv.tar.gz b/pre_commit/resources/rbenv.tar.gz index 111546e3dd9796511942c278495c21fe1ef947ae..b5df08744c17c6fd950d89e8a5caf6186905dedc 100644 GIT binary patch literal 31297 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 diff --git a/pre_commit/resources/ruby-build.tar.gz b/pre_commit/resources/ruby-build.tar.gz index a4f7eb24fd0a7e4d59cf120014d8b054555b8b0f..5c82c90609384836116acd7df8bbe9f79a4c7a86 100644 GIT binary patch delta 93686 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

8nw4 z!YLMht)2IuEXtMl+j`ze>*Sk5IVF!}MT`FZ`LgYt>TPXH{}Zi`s+o2?o*S}^Y17~O z%|C=#?Egl;kO*emV#Qi{nZteE(%t18uVU467S1e~{%iG}jgu#3mYn=vbbM9Xtf!G| zVHdfLA6aDxyZO&_oGJ2krS&ZqoQpl-sTqO{e$pOqW~ocKxaysg3nz-;ZS%POZ9jtm~{sp2m?mQyLYr z%lzWlQsny#9xR(KaIiU0aZi)xqN!KB=2jQEL{188%yz!Hgk!0s*rUTA-fV5iVPebh zixZq)bWrrh0R-4%aS;w@@w*pm*8aqIOX@`Z*>eM4eVelLj_}==CtWv091`Scy(TE} z=Z;+yA zdWSs~@5w(pYxt%6q+X@Y%K2yCw7qxT)g!R3z$ofw$G^Khn)XWd0hV*i-sn#BdsvpW z?)V^y1l)g>HD5A?EcnY3n=L{p7(8S8iJ zsf8b&?s}?xO84!KyDjhO^C)hjUx=ugP>JE&N33wzC zY_(~}*OF+X+~OEJpAS16{Xb2Z?{-A`=*NGNn-~^xx}4UK(rGAqdF4ah{6*Kcon)H0 z**?GUy?kJt+M~}q4VSuc6s=@m8qw2dQt}tM}{a z>+71fiJ5CIsfwAia`P4)^JfBp6MQuCjZ8+y50c$>nfem~XLxmZ(Pc|TXw@xMP6kLtdE;U~!d z@nn;IoAy~Xk-Jhmb$%#+4m$s=xT*Z))SwM>_B!4^IziN#UFVJXHNBXw*>@)9dJCtz z-ifJy*!1B7Lz%|5Agl5@QAX2zQf|8&zUTNK`GuR?!Ty}ltT>r7y+2pWNC|wDO%t2R ty-P6$W_+)w?oav`J}oRv{@MTds-nA!6j67x`f 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 WV@Cva`~Bztj4D6Ov>9ITG5`ST$-fH# diff --git a/testing/make-archives b/testing/make-archives index eb3f3af8..10f40a3a 100755 --- a/testing/make-archives +++ b/testing/make-archives @@ -16,8 +16,8 @@ from collections.abc import Sequence REPOS = ( - ('rbenv', 'https://github.com/rbenv/rbenv', '38e1fbb'), - ('ruby-build', 'https://github.com/rbenv/ruby-build', 'ed384c8'), + ('rbenv', 'https://github.com/rbenv/rbenv', '10e96bfc'), + ('ruby-build', 'https://github.com/rbenv/ruby-build', '447468b1'), ( 'ruby-download', 'https://github.com/garnieretienne/rvm-download', From 8bbfcf1f82ed7d1970e21a9c0323030805fdba3f Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 8 Nov 2025 13:16:33 -0500 Subject: [PATCH 397/416] remove redundant system spaces test `test_args_with_spaces_and_quotes` also covers this behaviour --- .../system_hook_with_spaces_repo/.pre-commit-hooks.yaml | 5 ----- tests/repository_test.py | 7 ------- 2 files changed, 12 deletions(-) delete mode 100644 testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml diff --git a/testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml b/testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml deleted file mode 100644 index b2c347c1..00000000 --- a/testing/resources/system_hook_with_spaces_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: system-hook-with-spaces - name: System hook with spaces - entry: bash -c 'echo "Hello World"' - language: system - files: \.sh$ diff --git a/tests/repository_test.py b/tests/repository_test.py index b54c910d..f1559301 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -80,13 +80,6 @@ def _test_hook_repo( assert out == expected -def test_system_hook_with_spaces(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'system_hook_with_spaces_repo', - 'system-hook-with-spaces', [os.devnull], b'Hello World\n', - ) - - def test_missing_executable(tempdir_factory, store): _test_hook_repo( tempdir_factory, store, 'not_found_exe', From 95eec7500464500d2ca0cc13d0986000508830e5 Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 8 Nov 2025 13:33:50 -0500 Subject: [PATCH 398/416] rm python3_hooks_repo --- .pre-commit-config.yaml | 2 +- .../resources/python3_hooks_repo/.pre-commit-hooks.yaml | 6 ------ testing/resources/python3_hooks_repo/py3_hook.py | 8 -------- testing/resources/python3_hooks_repo/setup.py | 8 -------- 4 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml delete mode 100644 testing/resources/python3_hooks_repo/py3_hook.py delete mode 100644 testing/resources/python3_hooks_repo/setup.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b1623a64..fa077365 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: rev: v3.16.0 hooks: - id: reorder-python-imports - exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) + exclude: ^pre_commit/resources/ args: [--py310-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma rev: v4.0.0 diff --git a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index 2c237009..00000000 --- a/testing/resources/python3_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- id: python3-hook - name: Python 3 Hook - entry: python3-hook - language: python - language_version: python3 - files: \.py$ diff --git a/testing/resources/python3_hooks_repo/py3_hook.py b/testing/resources/python3_hooks_repo/py3_hook.py deleted file mode 100644 index 8c9cda4c..00000000 --- a/testing/resources/python3_hooks_repo/py3_hook.py +++ /dev/null @@ -1,8 +0,0 @@ -import sys - - -def main(): - print(sys.version_info[0]) - print(repr(sys.argv[1:])) - print('Hello World') - return 0 diff --git a/testing/resources/python3_hooks_repo/setup.py b/testing/resources/python3_hooks_repo/setup.py deleted file mode 100644 index 9125dc1d..00000000 --- a/testing/resources/python3_hooks_repo/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -from setuptools import setup - -setup( - name='python3_hook', - version='0.0.0', - py_modules=['py3_hook'], - entry_points={'console_scripts': ['python3-hook = py3_hook:main']}, -) From aa2961c122b4aa834c77e612232c154f9439c388 Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 8 Nov 2025 14:31:11 -0500 Subject: [PATCH 399/416] fix missing context in error for stages --- pre_commit/clientlib.py | 9 +++++---- tests/clientlib_test.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index c0f736d9..51514bd3 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -116,11 +116,12 @@ class StagesMigrationNoDefault(NamedTuple): if self.key not in dct: return - val = dct[self.key] - cfgv.check_array(cfgv.check_any)(val) + with cfgv.validate_context(f'At key: {self.key}'): + val = dct[self.key] + cfgv.check_array(cfgv.check_any)(val) - val = [transform_stage(v) for v in val] - cfgv.check_array(cfgv.check_one_of(STAGES))(val) + val = [transform_stage(v) for v in val] + cfgv.check_array(cfgv.check_one_of(STAGES))(val) def apply_default(self, dct: dict[str, Any]) -> None: if self.key not in dct: diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 7aa84af0..2251abc4 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -309,6 +309,27 @@ def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning): assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)] +def test_invalid_stages_error(): + cfg = {'repos': [sample_local_config()]} + cfg['repos'][0]['hooks'][0]['stages'] = ['invalid'] + + with pytest.raises(cfgv.ValidationError) as excinfo: + cfgv.validate(cfg, CONFIG_SCHEMA) + + assert str(excinfo.value) == ( + '\n' + '==> At Config()\n' + '==> At key: repos\n' + "==> At Repository(repo='local')\n" + '==> At key: hooks\n' + "==> At Hook(id='do_not_commit')\n" + # this line was missing due to the custom validator + '==> At key: stages\n' + '==> At index 0\n' + "=====> Expected one of commit-msg, manual, post-checkout, post-commit, post-merge, post-rewrite, pre-commit, pre-merge-commit, pre-push, pre-rebase, prepare-commit-msg but got: 'invalid'" # noqa: E501 + ) + + def test_warning_for_deprecated_stages(caplog): config_obj = sample_local_config() config_obj['hooks'][0]['stages'] = ['commit', 'push'] From 725acc969a28a6bc9a7e2260f035426bc932e8da Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 8 Nov 2025 13:13:18 -0500 Subject: [PATCH 400/416] rename system and script languages to unsupported / unsupported_script --- pre_commit/all_languages.py | 8 ++-- pre_commit/clientlib.py | 47 +++++++++++++++++-- .../languages/{system.py => unsupported.py} | 0 .../{script.py => unsupported_script.py} | 0 tests/clientlib_test.py | 20 ++++++++ tests/languages/system_test.py | 9 ---- ...ipt_test.py => unsupported_script_test.py} | 6 +-- tests/languages/unsupported_test.py | 10 ++++ tests/repository_test.py | 14 +++--- 9 files changed, 88 insertions(+), 26 deletions(-) rename pre_commit/languages/{system.py => unsupported.py} (100%) rename pre_commit/languages/{script.py => unsupported_script.py} (100%) delete mode 100644 tests/languages/system_test.py rename tests/languages/{script_test.py => unsupported_script_test.py} (63%) create mode 100644 tests/languages/unsupported_test.py diff --git a/pre_commit/all_languages.py b/pre_commit/all_languages.py index ba569c37..166bc167 100644 --- a/pre_commit/all_languages.py +++ b/pre_commit/all_languages.py @@ -19,9 +19,9 @@ from pre_commit.languages import python from pre_commit.languages import r from pre_commit.languages import ruby from pre_commit.languages import rust -from pre_commit.languages import script from pre_commit.languages import swift -from pre_commit.languages import system +from pre_commit.languages import unsupported +from pre_commit.languages import unsupported_script languages: dict[str, Language] = { @@ -43,8 +43,8 @@ languages: dict[str, Language] = { 'r': r, 'ruby': ruby, 'rust': rust, - 'script': script, 'swift': swift, - 'system': system, + 'unsupported': unsupported, + 'unsupported_script': unsupported_script, } language_names = sorted(languages) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 51514bd3..eb0fd4d6 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -6,6 +6,7 @@ import os.path import re import shlex import sys +from collections.abc import Callable from collections.abc import Sequence from typing import Any from typing import NamedTuple @@ -190,6 +191,42 @@ class DeprecatedDefaultStagesWarning(NamedTuple): raise NotImplementedError +def _translate_language(name: str) -> str: + return { + 'system': 'unsupported', + 'script': 'unsupported_script', + }.get(name, name) + + +class LanguageMigration(NamedTuple): # remove + key: str + check_fn: Callable[[object], None] + + def check(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + return + + with cfgv.validate_context(f'At key: {self.key}'): + self.check_fn(_translate_language(dct[self.key])) + + def apply_default(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + return + + dct[self.key] = _translate_language(dct[self.key]) + + def remove_default(self, dct: dict[str, Any]) -> None: + raise NotImplementedError + + +class LanguageMigrationRequired(LanguageMigration): # replace with Required + def check(self, dct: dict[str, Any]) -> None: + if self.key not in dct: + raise cfgv.ValidationError(f'Missing required key: {self.key}') + + super().check(dct) + + MANIFEST_HOOK_DICT = cfgv.Map( 'Hook', 'id', @@ -203,7 +240,7 @@ MANIFEST_HOOK_DICT = cfgv.Map( cfgv.Required('id', cfgv.check_string), cfgv.Required('name', cfgv.check_string), cfgv.Required('entry', cfgv.check_string), - cfgv.Required('language', cfgv.check_one_of(language_names)), + LanguageMigrationRequired('language', cfgv.check_one_of(language_names)), cfgv.Optional('alias', cfgv.check_string, ''), cfgv.Optional('files', check_string_regex, ''), @@ -368,8 +405,10 @@ META_HOOK_DICT = cfgv.Map( 'Hook', 'id', cfgv.Required('id', cfgv.check_string), cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))), - # language must be system - cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'), + # language must be `unsupported` + cfgv.Optional( + 'language', cfgv.check_one_of({'unsupported'}), 'unsupported', + ), # entry cannot be overridden NotAllowed('entry', cfgv.check_any), *( @@ -402,8 +441,10 @@ CONFIG_HOOK_DICT = cfgv.Map( for item in MANIFEST_HOOK_DICT.items if item.key != 'id' if item.key != 'stages' + if item.key != 'language' # remove ), StagesMigrationNoDefault('stages', []), + LanguageMigration('language', cfgv.check_one_of(language_names)), # remove *_COMMON_HOOK_WARNINGS, ) LOCAL_HOOK_DICT = cfgv.Map( diff --git a/pre_commit/languages/system.py b/pre_commit/languages/unsupported.py similarity index 100% rename from pre_commit/languages/system.py rename to pre_commit/languages/unsupported.py diff --git a/pre_commit/languages/script.py b/pre_commit/languages/unsupported_script.py similarity index 100% rename from pre_commit/languages/script.py rename to pre_commit/languages/unsupported_script.py diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 2251abc4..93c698f7 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -380,6 +380,26 @@ def test_no_warning_for_non_deprecated_default_stages(caplog): assert caplog.record_tuples == [] +def test_unsupported_language_migration(): + cfg = {'repos': [sample_local_config(), sample_local_config()]} + cfg['repos'][0]['hooks'][0]['language'] = 'system' + cfg['repos'][1]['hooks'][0]['language'] = 'script' + + cfgv.validate(cfg, CONFIG_SCHEMA) + ret = cfgv.apply_defaults(cfg, CONFIG_SCHEMA) + + assert ret['repos'][0]['hooks'][0]['language'] == 'unsupported' + assert ret['repos'][1]['hooks'][0]['language'] == 'unsupported_script' + + +def test_unsupported_language_migration_language_required(): + cfg = {'repos': [sample_local_config()]} + del cfg['repos'][0]['hooks'][0]['language'] + + with pytest.raises(cfgv.ValidationError): + cfgv.validate(cfg, CONFIG_SCHEMA) + + @pytest.mark.parametrize( 'manifest_obj', ( diff --git a/tests/languages/system_test.py b/tests/languages/system_test.py deleted file mode 100644 index dcd9cf1e..00000000 --- a/tests/languages/system_test.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import annotations - -from pre_commit.languages import system -from testing.language_helpers import run_language - - -def test_system_language(tmp_path): - expected = (0, b'hello hello world\n') - assert run_language(tmp_path, system, 'echo hello hello world') == expected diff --git a/tests/languages/script_test.py b/tests/languages/unsupported_script_test.py similarity index 63% rename from tests/languages/script_test.py rename to tests/languages/unsupported_script_test.py index a02f615a..b15b67e7 100644 --- a/tests/languages/script_test.py +++ b/tests/languages/unsupported_script_test.py @@ -1,14 +1,14 @@ from __future__ import annotations -from pre_commit.languages import script +from pre_commit.languages import unsupported_script from pre_commit.util import make_executable from testing.language_helpers import run_language -def test_script_language(tmp_path): +def test_unsupported_script_language(tmp_path): exe = tmp_path.joinpath('main') exe.write_text('#!/usr/bin/env bash\necho hello hello world\n') make_executable(exe) expected = (0, b'hello hello world\n') - assert run_language(tmp_path, script, 'main') == expected + assert run_language(tmp_path, unsupported_script, 'main') == expected diff --git a/tests/languages/unsupported_test.py b/tests/languages/unsupported_test.py new file mode 100644 index 00000000..7f8461e0 --- /dev/null +++ b/tests/languages/unsupported_test.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from pre_commit.languages import unsupported +from testing.language_helpers import run_language + + +def test_unsupported_language(tmp_path): + expected = (0, b'hello hello world\n') + ret = run_language(tmp_path, unsupported, 'echo hello hello world') + assert ret == expected diff --git a/tests/repository_test.py b/tests/repository_test.py index f1559301..b1c7a002 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -17,7 +17,7 @@ from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import load_manifest from pre_commit.hook import Hook from pre_commit.languages import python -from pre_commit.languages import system +from pre_commit.languages import unsupported from pre_commit.prefix import Prefix from pre_commit.repository import _hook_installed from pre_commit.repository import all_hooks @@ -424,7 +424,7 @@ def test_manifest_hooks(tempdir_factory, store): exclude_types=[], files='', id='bash_hook', - language='script', + language='unsupported_script', language_version='default', log_file='', minimum_pre_commit_version='0', @@ -457,7 +457,7 @@ def test_non_installable_hook_error_for_language_version(store, caplog): 'hooks': [{ 'id': 'system-hook', 'name': 'system-hook', - 'language': 'system', + 'language': 'unsupported', 'entry': 'python3 -c "import sys; print(sys.version)"', 'language_version': 'python3.10', }], @@ -469,7 +469,7 @@ def test_non_installable_hook_error_for_language_version(store, caplog): msg, = caplog.messages assert msg == ( 'The hook `system-hook` specifies `language_version` but is using ' - 'language `system` which does not install an environment. ' + 'language `unsupported` which does not install an environment. ' 'Perhaps you meant to use a specific language?' ) @@ -480,7 +480,7 @@ def test_non_installable_hook_error_for_additional_dependencies(store, caplog): 'hooks': [{ 'id': 'system-hook', 'name': 'system-hook', - 'language': 'system', + 'language': 'unsupported', 'entry': 'python3 -c "import sys; print(sys.version)"', 'additional_dependencies': ['astpretty'], }], @@ -492,14 +492,14 @@ def test_non_installable_hook_error_for_additional_dependencies(store, caplog): msg, = caplog.messages assert msg == ( 'The hook `system-hook` specifies `additional_dependencies` but is ' - 'using language `system` which does not install an environment. ' + 'using language `unsupported` which does not install an environment. ' 'Perhaps you meant to use a specific language?' ) def test_args_with_spaces_and_quotes(tmp_path): ret = run_language( - tmp_path, system, + tmp_path, unsupported, f"{shlex.quote(sys.executable)} -c 'import sys; print(sys.argv[1:])'", ('i have spaces', 'and"\'quotes', '$and !this'), ) From f80801d75a429d5eafa1d87e9f88f73b108d1890 Mon Sep 17 00:00:00 2001 From: Radek Hrbacek Date: Fri, 5 Sep 2025 15:01:10 +0200 Subject: [PATCH 401/416] Fix docker-in-docker detection for cgroups v2 --- pre_commit/languages/docker.py | 42 +++--- tests/languages/docker_test.py | 230 +++++++++++++++++++++++++-------- 2 files changed, 202 insertions(+), 70 deletions(-) diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index d5ce1eb7..7f45ac86 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -1,9 +1,11 @@ from __future__ import annotations +import contextlib import functools import hashlib import json import os +import re from collections.abc import Sequence from pre_commit import lang_base @@ -17,31 +19,33 @@ get_default_version = lang_base.basic_get_default_version health_check = lang_base.basic_health_check in_env = lang_base.no_env # no special environment for docker - -def _is_in_docker() -> bool: - try: - with open('/proc/1/cgroup', 'rb') as f: - return b'docker' in f.read() - except FileNotFoundError: - return False +_HOSTNAME_MOUNT_RE = re.compile( + rb""" + /containers + (?:/overlay-containers)? + /([a-z0-9]{64}) + (?:/userdata)? + /hostname + """, + re.VERBOSE, +) -def _get_container_id() -> str: - # It's assumed that we already check /proc/1/cgroup in _is_in_docker. The - # cpuset cgroup controller existed since cgroups were introduced so this - # way of getting the container ID is pretty reliable. - with open('/proc/1/cgroup', 'rb') as f: - for line in f.readlines(): - if line.split(b':')[1] == b'cpuset': - return os.path.basename(line.split(b':')[2]).strip().decode() - raise RuntimeError('Failed to find the container ID in /proc/1/cgroup.') +def _get_container_id() -> str | None: + with contextlib.suppress(FileNotFoundError): + with open('/proc/1/mountinfo', 'rb') as f: + for line in f: + m = _HOSTNAME_MOUNT_RE.search(line) + if m: + return m[1].decode() + + return None def _get_docker_path(path: str) -> str: - if not _is_in_docker(): - return path - container_id = _get_container_id() + if container_id is None: + return path try: _, out, _ = cmd_output_b('docker', 'inspect', container_id) diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index b830439a..e269976f 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -14,40 +14,173 @@ from pre_commit.util import CalledProcessError from testing.language_helpers import run_language from testing.util import xfailif_windows -DOCKER_CGROUP_EXAMPLE = b'''\ -12:hugetlb:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -11:blkio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -10:freezer:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -9:cpu,cpuacct:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -8:pids:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -7:rdma:/ -6:net_cls,net_prio:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -5:cpuset:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -4:devices:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -3:memory:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -2:perf_event:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -1:name=systemd:/docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 -0::/system.slice/containerd.service +DOCKER_CGROUPS_V1_MOUNTINFO_EXAMPLE = b'''\ +759 717 0:52 / / rw,relatime master:300 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/PCPE5P5IVGM7CFCPJR353N3ONK:/var/lib/docker/overlay2/l/EQFSDHFAJ333VEMEJD4ZTRIZCB,upperdir=/var/lib/docker/overlay2/0d9f6bf186030d796505b87d6daa92297355e47641e283d3c09d83a7f221e462/diff,workdir=/var/lib/docker/overlay2/0d9f6bf186030d796505b87d6daa92297355e47641e283d3c09d83a7f221e462/work +760 759 0:58 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +761 759 0:59 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +762 761 0:60 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +763 759 0:61 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +764 763 0:62 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755,inode64 +765 764 0:29 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/systemd ro,nosuid,nodev,noexec,relatime master:11 - cgroup cgroup rw,xattr,name=systemd +766 764 0:32 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/rdma ro,nosuid,nodev,noexec,relatime master:15 - cgroup cgroup rw,rdma +767 764 0:33 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:16 - cgroup cgroup rw,cpu,cpuacct +768 764 0:34 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/cpuset ro,nosuid,nodev,noexec,relatime master:17 - cgroup cgroup rw,cpuset +769 764 0:35 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/pids ro,nosuid,nodev,noexec,relatime master:18 - cgroup cgroup rw,pids +770 764 0:36 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime master:19 - cgroup cgroup rw,memory +771 764 0:37 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/perf_event ro,nosuid,nodev,noexec,relatime master:20 - cgroup cgroup rw,perf_event +772 764 0:38 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/net_cls,net_prio ro,nosuid,nodev,noexec,relatime master:21 - cgroup cgroup rw,net_cls,net_prio +773 764 0:39 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/blkio ro,nosuid,nodev,noexec,relatime master:22 - cgroup cgroup rw,blkio +774 764 0:40 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/misc ro,nosuid,nodev,noexec,relatime master:23 - cgroup cgroup rw,misc +775 764 0:41 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/hugetlb ro,nosuid,nodev,noexec,relatime master:24 - cgroup cgroup rw,hugetlb +776 764 0:42 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/devices ro,nosuid,nodev,noexec,relatime master:25 - cgroup cgroup rw,devices +777 764 0:43 /docker/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7 /sys/fs/cgroup/freezer ro,nosuid,nodev,noexec,relatime master:26 - cgroup cgroup rw,freezer +778 761 0:57 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +779 761 0:63 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k,inode64 +780 759 8:5 /var/lib/docker/containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/sda5 rw,errors=remount-ro +781 759 8:5 /var/lib/docker/containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/hostname /etc/hostname rw,relatime - ext4 /dev/sda5 rw,errors=remount-ro +782 759 8:5 /var/lib/docker/containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/hosts /etc/hosts rw,relatime - ext4 /dev/sda5 rw,errors=remount-ro +718 761 0:60 /0 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +719 760 0:58 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +720 760 0:58 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +721 760 0:58 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +722 760 0:58 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +723 760 0:58 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +724 760 0:64 / /proc/asound ro,relatime - tmpfs tmpfs ro,inode64 +725 760 0:65 / /proc/acpi ro,relatime - tmpfs tmpfs ro,inode64 +726 760 0:59 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +727 760 0:59 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +728 760 0:59 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +729 760 0:66 / /proc/scsi ro,relatime - tmpfs tmpfs ro,inode64 +730 763 0:67 / /sys/firmware ro,relatime - tmpfs tmpfs ro,inode64 +731 763 0:68 / /sys/devices/virtual/powercap ro,relatime - tmpfs tmpfs ro,inode64 +''' # noqa: E501 + +DOCKER_CGROUPS_V2_MOUNTINFO_EXAMPLE = b'''\ +721 386 0:45 / / rw,relatime master:218 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/QHZ7OM7P4AQD3XLG274ZPWAJCV:/var/lib/docker/overlay2/l/5RFG6SZWVGOG2NKEYXJDQCQYX5,upperdir=/var/lib/docker/overlay2/e4ad859fc5d4791932b9b976052f01fb0063e01de3cef916e40ae2121f6a166e/diff,workdir=/var/lib/docker/overlay2/e4ad859fc5d4791932b9b976052f01fb0063e01de3cef916e40ae2121f6a166e/work,nouserxattr +722 721 0:48 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +723 721 0:50 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +724 723 0:51 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +725 721 0:52 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +726 725 0:26 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw,nsdelegate,memory_recursiveprot +727 723 0:47 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +728 723 0:53 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k,inode64 +729 721 8:3 /var/lib/docker/containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/sda3 rw,errors=remount-ro +730 721 8:3 /var/lib/docker/containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/hostname /etc/hostname rw,relatime - ext4 /dev/sda3 rw,errors=remount-ro +731 721 8:3 /var/lib/docker/containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/hosts /etc/hosts rw,relatime - ext4 /dev/sda3 rw,errors=remount-ro +387 723 0:51 /0 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +388 722 0:48 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +389 722 0:48 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +525 722 0:48 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +526 722 0:48 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +571 722 0:48 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +572 722 0:57 / /proc/asound ro,relatime - tmpfs tmpfs ro,inode64 +575 722 0:58 / /proc/acpi ro,relatime - tmpfs tmpfs ro,inode64 +576 722 0:50 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +577 722 0:50 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +578 722 0:50 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +579 722 0:59 / /proc/scsi ro,relatime - tmpfs tmpfs ro,inode64 +580 725 0:60 / /sys/firmware ro,relatime - tmpfs tmpfs ro,inode64 +''' # noqa: E501 + +PODMAN_CGROUPS_V1_MOUNTINFO_EXAMPLE = b'''\ +1200 915 0:57 / / rw,relatime - overlay overlay rw,lowerdir=/home/asottile/.local/share/containers/storage/overlay/l/ZWAU3VY3ZHABQJRBUAFPBX7R5D,upperdir=/home/asottile/.local/share/containers/storage/overlay/72504ef163fda63838930450553b7306412ccad139a007626732b3dc43af5200/diff,workdir=/home/asottile/.local/share/containers/storage/overlay/72504ef163fda63838930450553b7306412ccad139a007626732b3dc43af5200/work,volatile,userxattr +1204 1200 0:62 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +1205 1200 0:63 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,uid=1000,gid=1000,inode64 +1206 1200 0:64 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs rw +1207 1205 0:65 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=100004,mode=620,ptmxmode=666 +1208 1205 0:61 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +1209 1200 0:53 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/.containerenv /run/.containerenv rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=814036k,mode=700,uid=1000,gid=1000,inode64 +1210 1200 0:53 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/resolv.conf /etc/resolv.conf rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=814036k,mode=700,uid=1000,gid=1000,inode64 +1211 1200 0:53 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/hosts /etc/hosts rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=814036k,mode=700,uid=1000,gid=1000,inode64 +1212 1205 0:56 / /dev/shm rw,relatime - tmpfs shm rw,size=64000k,uid=1000,gid=1000,inode64 +1213 1200 0:53 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/hostname /etc/hostname rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=814036k,mode=700,uid=1000,gid=1000,inode64 +1214 1206 0:66 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs cgroup rw,size=1024k,uid=1000,gid=1000,inode64 +1215 1214 0:43 / /sys/fs/cgroup/freezer ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer +1216 1214 0:42 /user.slice /sys/fs/cgroup/devices ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices +1217 1214 0:41 / /sys/fs/cgroup/hugetlb ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,hugetlb +1218 1214 0:40 / /sys/fs/cgroup/misc ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,misc +1219 1214 0:39 / /sys/fs/cgroup/blkio ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio +1220 1214 0:38 / /sys/fs/cgroup/net_cls,net_prio ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,net_cls,net_prio +1221 1214 0:37 / /sys/fs/cgroup/perf_event ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,perf_event +1222 1214 0:36 /user.slice/user-1000.slice/user@1000.service /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory +1223 1214 0:35 /user.slice/user-1000.slice/user@1000.service /sys/fs/cgroup/pids ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,pids +1224 1214 0:34 / /sys/fs/cgroup/cpuset ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset +1225 1214 0:33 / /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu,cpuacct +1226 1214 0:32 / /sys/fs/cgroup/rdma ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,rdma +1227 1214 0:29 /user.slice/user-1000.slice/user@1000.service/apps.slice/apps-org.gnome.Terminal.slice/vte-spawn-0c50448e-b395-4d76-8b92-379f16e5066f.scope /sys/fs/cgroup/systemd ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,xattr,name=systemd +1228 1205 0:5 /null /dev/null rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1229 1205 0:5 /zero /dev/zero rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1230 1205 0:5 /full /dev/full rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1231 1205 0:5 /tty /dev/tty rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1232 1205 0:5 /random /dev/random rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1233 1205 0:5 /urandom /dev/urandom rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1234 1204 0:67 / /proc/acpi ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +1235 1204 0:5 /null /proc/kcore rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1236 1204 0:5 /null /proc/keys rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1237 1204 0:5 /null /proc/timer_list rw,nosuid,noexec,relatime - devtmpfs udev rw,size=4031656k,nr_inodes=1007914,mode=755,inode64 +1238 1204 0:68 / /proc/scsi ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +1239 1206 0:69 / /sys/firmware ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +1240 1206 0:70 / /sys/dev/block ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +1241 1204 0:62 /asound /proc/asound ro,relatime - proc proc rw +1242 1204 0:62 /bus /proc/bus ro,relatime - proc proc rw +1243 1204 0:62 /fs /proc/fs ro,relatime - proc proc rw +1244 1204 0:62 /irq /proc/irq ro,relatime - proc proc rw +1245 1204 0:62 /sys /proc/sys ro,relatime - proc proc rw +1256 1204 0:62 /sysrq-trigger /proc/sysrq-trigger ro,relatime - proc proc rw +916 1205 0:65 /0 /dev/console rw,relatime - devpts devpts rw,gid=100004,mode=620,ptmxmode=666 +''' # noqa: E501 + +PODMAN_CGROUPS_V2_MOUNTINFO_EXAMPLE = b'''\ +685 690 0:63 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/resolv.conf /etc/resolv.conf rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=1637624k,nr_inodes=409406,mode=700,uid=1000,gid=1000,inode64 +686 690 0:63 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/hosts /etc/hosts rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=1637624k,nr_inodes=409406,mode=700,uid=1000,gid=1000,inode64 +687 692 0:50 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=64000k,uid=1000,gid=1000,inode64 +688 690 0:63 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/.containerenv /run/.containerenv rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=1637624k,nr_inodes=409406,mode=700,uid=1000,gid=1000,inode64 +689 690 0:63 /containers/overlay-containers/c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7/userdata/hostname /etc/hostname rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=1637624k,nr_inodes=409406,mode=700,uid=1000,gid=1000,inode64 +690 546 0:55 / / rw,relatime - overlay overlay rw,lowerdir=/home/asottile/.local/share/containers/storage/overlay/l/NPOHYOD3PI3YW6TQSGBOVOUSK6,upperdir=/home/asottile/.local/share/containers/storage/overlay/565c206fb79f876ffd5f069b8bd7a97fb5e47d5d07396b0c395a4ed6725d4a8e/diff,workdir=/home/asottile/.local/share/containers/storage/overlay/565c206fb79f876ffd5f069b8bd7a97fb5e47d5d07396b0c395a4ed6725d4a8e/work,redirect_dir=nofollow,uuid=on,volatile,userxattr +691 690 0:59 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +692 690 0:61 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,uid=1000,gid=1000,inode64 +693 690 0:62 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs rw +694 692 0:66 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=100004,mode=620,ptmxmode=666 +695 692 0:58 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +696 693 0:28 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup2 rw,nsdelegate,memory_recursiveprot +698 692 0:6 /null /dev/null rw,nosuid,noexec,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +699 692 0:6 /zero /dev/zero rw,nosuid,noexec,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +700 692 0:6 /full /dev/full rw,nosuid,noexec,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +701 692 0:6 /tty /dev/tty rw,nosuid,noexec,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +702 692 0:6 /random /dev/random rw,nosuid,noexec,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +703 692 0:6 /urandom /dev/urandom rw,nosuid,noexec,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +704 691 0:67 / /proc/acpi ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +705 691 0:6 /null /proc/kcore ro,nosuid,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +706 691 0:6 /null /proc/keys ro,nosuid,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +707 691 0:6 /null /proc/latency_stats ro,nosuid,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +708 691 0:6 /null /proc/timer_list ro,nosuid,relatime - devtmpfs udev rw,size=8147812k,nr_inodes=2036953,mode=755,inode64 +709 691 0:68 / /proc/scsi ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +710 693 0:69 / /sys/firmware ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +711 693 0:70 / /sys/dev/block ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +712 693 0:71 / /sys/devices/virtual/powercap ro,relatime - tmpfs tmpfs rw,size=0k,uid=1000,gid=1000,inode64 +713 691 0:59 /asound /proc/asound ro,nosuid,nodev,noexec,relatime - proc proc rw +714 691 0:59 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +715 691 0:59 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +716 691 0:59 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +717 691 0:59 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +718 691 0:59 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +547 692 0:66 /0 /dev/console rw,relatime - devpts devpts rw,gid=100004,mode=620,ptmxmode=666 ''' # noqa: E501 # The ID should match the above cgroup example. CONTAINER_ID = 'c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7' # noqa: E501 -NON_DOCKER_CGROUP_EXAMPLE = b'''\ -12:perf_event:/ -11:hugetlb:/ -10:devices:/ -9:blkio:/ -8:rdma:/ -7:cpuset:/ -6:cpu,cpuacct:/ -5:freezer:/ -4:memory:/ -3:pids:/ -2:net_cls,net_prio:/ -1:name=systemd:/init.scope -0::/init.scope -''' +NON_DOCKER_MOUNTINFO_EXAMPLE = b'''\ +21 27 0:19 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw +22 27 0:20 / /proc rw,nosuid,nodev,noexec,relatime shared:14 - proc proc rw +23 27 0:5 / /dev rw,nosuid,relatime shared:2 - devtmpfs udev rw,size=10219484k,nr_inodes=2554871,mode=755,inode64 +24 23 0:21 / /dev/pts rw,nosuid,noexec,relatime shared:3 - devpts devpts rw,gid=5,mode=620,ptmxmode=000 +25 27 0:22 / /run rw,nosuid,nodev,noexec,relatime shared:5 - tmpfs tmpfs rw,size=2047768k,mode=755,inode64 +27 1 8:2 / / rw,relatime shared:1 - ext4 /dev/sda2 rw,errors=remount-ro +28 21 0:6 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:8 - securityfs securityfs rw +29 23 0:24 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw,inode64 +30 25 0:25 / /run/lock rw,nosuid,nodev,noexec,relatime shared:6 - tmpfs tmpfs rw,size=5120k,inode64 +''' # noqa: E501 def test_docker_fallback_user(): @@ -99,9 +232,9 @@ def test_docker_user_non_rootless(info_ret): assert docker.get_docker_user() != () -def test_in_docker_no_file(): +def test_container_id_no_file(): with mock.patch.object(builtins, 'open', side_effect=FileNotFoundError): - assert docker._is_in_docker() is False + assert docker._get_container_id() is None def _mock_open(data): @@ -113,38 +246,33 @@ def _mock_open(data): ) -def test_in_docker_docker_in_file(): - with _mock_open(DOCKER_CGROUP_EXAMPLE): - assert docker._is_in_docker() is True - - -def test_in_docker_docker_not_in_file(): - with _mock_open(NON_DOCKER_CGROUP_EXAMPLE): - assert docker._is_in_docker() is False +def test_container_id_not_in_file(): + with _mock_open(NON_DOCKER_MOUNTINFO_EXAMPLE): + assert docker._get_container_id() is None def test_get_container_id(): - with _mock_open(DOCKER_CGROUP_EXAMPLE): + with _mock_open(DOCKER_CGROUPS_V1_MOUNTINFO_EXAMPLE): + assert docker._get_container_id() == CONTAINER_ID + with _mock_open(DOCKER_CGROUPS_V2_MOUNTINFO_EXAMPLE): + assert docker._get_container_id() == CONTAINER_ID + with _mock_open(PODMAN_CGROUPS_V1_MOUNTINFO_EXAMPLE): + assert docker._get_container_id() == CONTAINER_ID + with _mock_open(PODMAN_CGROUPS_V2_MOUNTINFO_EXAMPLE): assert docker._get_container_id() == CONTAINER_ID -def test_get_container_id_failure(): - with _mock_open(b''), pytest.raises(RuntimeError): - docker._get_container_id() - - def test_get_docker_path_not_in_docker_returns_same(): - with mock.patch.object(docker, '_is_in_docker', return_value=False): + with _mock_open(b''): assert docker._get_docker_path('abc') == 'abc' @pytest.fixture def in_docker(): - with mock.patch.object(docker, '_is_in_docker', return_value=True): - with mock.patch.object( - docker, '_get_container_id', return_value=CONTAINER_ID, - ): - yield + with mock.patch.object( + docker, '_get_container_id', return_value=CONTAINER_ID, + ): + yield def _linux_commonpath(): From 17cf8864737af2ce75c73839a0cdedc26ce50598 Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 8 Nov 2025 16:11:43 -0500 Subject: [PATCH 402/416] v4.4.0 --- CHANGELOG.md | 28 ++++++++++++++++++++++++++-- setup.cfg | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42a63f78..b27af5e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +4.4.0 - 2025-11-08 +================== + +### Features +- Add `--fail-fast` option to `pre-commit run`. + - #3528 PR by @JulianMaurin. +- Upgrade `ruby-build` / `rbenv`. + - #3566 PR by @asottile. + - #3565 issue by @MRigal. +- Add `language: unsupported` / `language: unsupported_script` as aliases + for `language: system` / `language: script` (which will eventually be + deprecated). + - #3577 PR by @asottile. +- Add support docker-in-docker detection for cgroups v2. + - #3535 PR by @br-rhrbacek. + - #3360 issue by @JasonAlt. + +### Fixes +- Handle when docker gives `SecurityOptions: null`. + - #3537 PR by @asottile. + - #3514 issue by @jenstroeger. +- Fix error context for invalid `stages` in `.pre-commit-config.yaml`. + - #3576 PR by @asottile. + 4.3.0 - 2025-08-09 ================== @@ -71,7 +95,7 @@ - #3315 PR by @asottile. - #2732 issue by @asottile. -### Migrating +### Updating - `language: python_venv` has been removed -- use `language: python` instead. - #3320 PR by @asottile. - #2734 issue by @asottile. @@ -159,7 +183,7 @@ - Use `time.monotonic()` for more accurate hook timing. - #3024 PR by @adamchainz. -### Migrating +### Updating - Require npm 6.x+ for `language: node` hooks. - #2996 PR by @RoelAdriaans. - #1983 issue by @henryiii. diff --git a/setup.cfg b/setup.cfg index 17c3fe0e..be031c3e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.3.0 +version = 4.4.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From d5c273a2ba0c712659640e9487adb38bd7da68f6 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 9 Nov 2025 16:57:40 -0500 Subject: [PATCH 403/416] refactor gc into store this will make refactoring this easier later and limits the api surface of Store --- pre_commit/commands/gc.py | 82 +-------------------------------- pre_commit/store.py | 96 +++++++++++++++++++++++++++++++-------- tests/commands/gc_test.py | 9 ++-- tests/store_test.py | 25 +++++++--- 4 files changed, 101 insertions(+), 111 deletions(-) diff --git a/pre_commit/commands/gc.py b/pre_commit/commands/gc.py index 6892e097..d1941e4b 100644 --- a/pre_commit/commands/gc.py +++ b/pre_commit/commands/gc.py @@ -1,89 +1,9 @@ from __future__ import annotations -import os.path -from typing import Any - -import pre_commit.constants as C from pre_commit import output -from pre_commit.clientlib import InvalidConfigError -from pre_commit.clientlib import InvalidManifestError -from pre_commit.clientlib import load_config -from pre_commit.clientlib import load_manifest -from pre_commit.clientlib import LOCAL -from pre_commit.clientlib import META from pre_commit.store import Store -def _mark_used_repos( - store: Store, - all_repos: dict[tuple[str, str], str], - unused_repos: set[tuple[str, str]], - repo: dict[str, Any], -) -> None: - if repo['repo'] == META: - return - elif repo['repo'] == LOCAL: - for hook in repo['hooks']: - deps = hook.get('additional_dependencies') - unused_repos.discard(( - store.db_repo_name(repo['repo'], deps), C.LOCAL_REPO_VERSION, - )) - else: - key = (repo['repo'], repo['rev']) - path = all_repos.get(key) - # can't inspect manifest if it isn't cloned - if path is None: - return - - try: - manifest = load_manifest(os.path.join(path, C.MANIFEST_FILE)) - except InvalidManifestError: - return - else: - unused_repos.discard(key) - by_id = {hook['id']: hook for hook in manifest} - - for hook in repo['hooks']: - if hook['id'] not in by_id: - continue - - deps = hook.get( - 'additional_dependencies', - by_id[hook['id']]['additional_dependencies'], - ) - unused_repos.discard(( - store.db_repo_name(repo['repo'], deps), repo['rev'], - )) - - -def _gc_repos(store: Store) -> int: - configs = store.select_all_configs() - repos = store.select_all_repos() - - # delete config paths which do not exist - dead_configs = [p for p in configs if not os.path.exists(p)] - live_configs = [p for p in configs if os.path.exists(p)] - - all_repos = {(repo, ref): path for repo, ref, path in repos} - unused_repos = set(all_repos) - for config_path in live_configs: - try: - config = load_config(config_path) - except InvalidConfigError: - dead_configs.append(config_path) - continue - else: - for repo in config['repos']: - _mark_used_repos(store, all_repos, unused_repos, repo) - - store.delete_configs(dead_configs) - for db_repo_name, ref in unused_repos: - store.delete_repo(db_repo_name, ref, all_repos[(db_repo_name, ref)]) - return len(unused_repos) - - def gc(store: Store) -> int: - with store.exclusive_lock(): - repos_removed = _gc_repos(store) - output.write_line(f'{repos_removed} repo(s) removed.') + output.write_line(f'{store.gc()} repo(s) removed.') return 0 diff --git a/pre_commit/store.py b/pre_commit/store.py index 9e3b4048..34c5f0d9 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -8,6 +8,7 @@ import tempfile from collections.abc import Callable from collections.abc import Generator from collections.abc import Sequence +from typing import Any import pre_commit.constants as C from pre_commit import clientlib @@ -96,7 +97,7 @@ class Store: ' PRIMARY KEY (repo, ref)' ');', ) - self._create_config_table(db) + self._create_configs_table(db) # Atomic file move os.replace(tmpfile, self.db_path) @@ -215,7 +216,7 @@ class Store: 'local', C.LOCAL_REPO_VERSION, deps, _make_local_repo, ) - def _create_config_table(self, db: sqlite3.Connection) -> None: + def _create_configs_table(self, db: sqlite3.Connection) -> None: db.executescript( 'CREATE TABLE IF NOT EXISTS configs (' ' path TEXT NOT NULL,' @@ -232,28 +233,83 @@ class Store: return with self.connect() as db: # TODO: eventually remove this and only create in _create - self._create_config_table(db) + self._create_configs_table(db) db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,)) - def select_all_configs(self) -> list[str]: - with self.connect() as db: - self._create_config_table(db) - rows = db.execute('SELECT path FROM configs').fetchall() - return [path for path, in rows] + def _mark_used_repos( + self, + all_repos: dict[tuple[str, str], str], + unused_repos: set[tuple[str, str]], + repo: dict[str, Any], + ) -> None: + if repo['repo'] == clientlib.META: + return + elif repo['repo'] == clientlib.LOCAL: + for hook in repo['hooks']: + deps = hook.get('additional_dependencies') + unused_repos.discard(( + self.db_repo_name(repo['repo'], deps), + C.LOCAL_REPO_VERSION, + )) + else: + key = (repo['repo'], repo['rev']) + path = all_repos.get(key) + # can't inspect manifest if it isn't cloned + if path is None: + return - def delete_configs(self, configs: list[str]) -> None: - with self.connect() as db: - rows = [(path,) for path in configs] - db.executemany('DELETE FROM configs WHERE path = ?', rows) + try: + manifest = clientlib.load_manifest( + os.path.join(path, C.MANIFEST_FILE), + ) + except clientlib.InvalidManifestError: + return + else: + unused_repos.discard(key) + by_id = {hook['id']: hook for hook in manifest} - def select_all_repos(self) -> list[tuple[str, str, str]]: - with self.connect() as db: - return db.execute('SELECT repo, ref, path from repos').fetchall() + for hook in repo['hooks']: + if hook['id'] not in by_id: + continue - def delete_repo(self, db_repo_name: str, ref: str, path: str) -> None: - with self.connect() as db: - db.execute( + deps = hook.get( + 'additional_dependencies', + by_id[hook['id']]['additional_dependencies'], + ) + unused_repos.discard(( + self.db_repo_name(repo['repo'], deps), repo['rev'], + )) + + def gc(self) -> int: + with self.exclusive_lock(), self.connect() as db: + self._create_configs_table(db) + + repos = db.execute('SELECT repo, ref, path FROM repos').fetchall() + all_repos = {(repo, ref): path for repo, ref, path in repos} + unused_repos = set(all_repos) + + configs_rows = db.execute('SELECT path FROM configs').fetchall() + configs = [path for path, in configs_rows] + + dead_configs = [] + for config_path in configs: + try: + config = clientlib.load_config(config_path) + except clientlib.InvalidConfigError: + dead_configs.append(config_path) + continue + else: + for repo in config['repos']: + self._mark_used_repos(all_repos, unused_repos, repo) + + paths = [(path,) for path in dead_configs] + db.executemany('DELETE FROM configs WHERE path = ?', paths) + + db.executemany( 'DELETE FROM repos WHERE repo = ? and ref = ?', - (db_repo_name, ref), + sorted(unused_repos), ) - rmtree(path) + for k in unused_repos: + rmtree(all_repos[k]) + + return len(unused_repos) diff --git a/tests/commands/gc_test.py b/tests/commands/gc_test.py index 95113ed5..85e66977 100644 --- a/tests/commands/gc_test.py +++ b/tests/commands/gc_test.py @@ -19,11 +19,13 @@ from testing.util import git_commit def _repo_count(store): - return len(store.select_all_repos()) + with store.connect() as db: + return db.execute('SELECT COUNT(1) FROM repos').fetchone()[0] def _config_count(store): - return len(store.select_all_configs()) + with store.connect() as db: + return db.execute('SELECT COUNT(1) FROM configs').fetchone()[0] def _remove_config_assert_cleared(store, cap_out): @@ -153,7 +155,8 @@ def test_invalid_manifest_gcd(tempdir_factory, store, in_git_dir, cap_out): install_hooks(C.CONFIG_FILE, store) # we'll "break" the manifest to simulate an old version clone - (_, _, path), = store.select_all_repos() + with store.connect() as db: + path, = db.execute('SELECT path FROM repos').fetchone() os.remove(os.path.join(path, C.MANIFEST_FILE)) assert _config_count(store) == 1 diff --git a/tests/store_test.py b/tests/store_test.py index 7d4dffb0..4b04a8e7 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -22,6 +22,17 @@ from testing.util import git_commit from testing.util import xfailif_windows +def _select_all_configs(store: Store) -> list[str]: + with store.connect() as db: + rows = db.execute('SELECT * FROM configs').fetchall() + return [path for path, in rows] + + +def _select_all_repos(store: Store) -> list[tuple[str, str, str]]: + with store.connect() as db: + return db.execute('SELECT repo, ref, path FROM repos').fetchall() + + def test_our_session_fixture_works(): """There's a session fixture which makes `Store` invariantly raise to prevent writing to the home directory. @@ -91,7 +102,7 @@ def test_clone(store, tempdir_factory, caplog): assert git.head_rev(ret) == rev # Assert there's an entry in the sqlite db for this - assert store.select_all_repos() == [(path, rev, ret)] + assert _select_all_repos(store) == [(path, rev, ret)] def test_warning_for_deprecated_stages_on_init(store, tempdir_factory, caplog): @@ -217,7 +228,7 @@ def test_clone_shallow_failure_fallback_to_complete( assert git.head_rev(ret) == rev # Assert there's an entry in the sqlite db for this - assert store.select_all_repos() == [(path, rev, ret)] + assert _select_all_repos(store) == [(path, rev, ret)] def test_clone_tag_not_on_mainline(store, tempdir_factory): @@ -265,7 +276,7 @@ def test_mark_config_as_used(store, tmpdir): with tmpdir.as_cwd(): f = tmpdir.join('f').ensure() store.mark_config_used('f') - assert store.select_all_configs() == [f.strpath] + assert _select_all_configs(store) == [f.strpath] def test_mark_config_as_used_idempotent(store, tmpdir): @@ -275,7 +286,7 @@ def test_mark_config_as_used_idempotent(store, tmpdir): def test_mark_config_as_used_does_not_exist(store): store.mark_config_used('f') - assert store.select_all_configs() == [] + assert _select_all_configs(store) == [] def _simulate_pre_1_14_0(store): @@ -283,9 +294,9 @@ def _simulate_pre_1_14_0(store): db.executescript('DROP TABLE configs') -def test_select_all_configs_roll_forward(store): +def test_gc_roll_forward(store): _simulate_pre_1_14_0(store) - assert store.select_all_configs() == [] + assert store.gc() == 0 def test_mark_config_as_used_roll_forward(store, tmpdir): @@ -314,7 +325,7 @@ def test_mark_config_as_used_readonly(tmpdir): assert store.readonly # should be skipped due to readonly store.mark_config_used(str(cfg)) - assert store.select_all_configs() == [] + assert _select_all_configs(store) == [] def test_clone_with_recursive_submodules(store, tmp_path): From 063229aee77ba2da3e9ed5c8217070b4128234fd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 20:59:54 +0000 Subject: [PATCH 404/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.21.0 → v3.21.1](https://github.com/asottile/pyupgrade/compare/v3.21.0...v3.21.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fa077365..e47d56ca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.21.0 + rev: v3.21.1 hooks: - id: pyupgrade args: [--py310-plus] From 66278a9a0b69a69fde820d2b85a7e198eae52981 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 19 Nov 2025 14:29:50 -0500 Subject: [PATCH 405/416] move logic for gc back to commands.gc --- pre_commit/commands/gc.py | 91 ++++++++++++++++++++++++++++++++++++++- pre_commit/store.py | 80 ---------------------------------- tests/commands/gc_test.py | 8 ++++ tests/store_test.py | 13 +----- 4 files changed, 100 insertions(+), 92 deletions(-) diff --git a/pre_commit/commands/gc.py b/pre_commit/commands/gc.py index d1941e4b..975d5e4c 100644 --- a/pre_commit/commands/gc.py +++ b/pre_commit/commands/gc.py @@ -1,9 +1,98 @@ from __future__ import annotations +import os.path +from typing import Any + +import pre_commit.constants as C from pre_commit import output +from pre_commit.clientlib import InvalidConfigError +from pre_commit.clientlib import InvalidManifestError +from pre_commit.clientlib import load_config +from pre_commit.clientlib import load_manifest +from pre_commit.clientlib import LOCAL +from pre_commit.clientlib import META from pre_commit.store import Store +from pre_commit.util import rmtree + + +def _mark_used_repos( + store: Store, + all_repos: dict[tuple[str, str], str], + unused_repos: set[tuple[str, str]], + repo: dict[str, Any], +) -> None: + if repo['repo'] == META: + return + elif repo['repo'] == LOCAL: + for hook in repo['hooks']: + deps = hook.get('additional_dependencies') + unused_repos.discard(( + store.db_repo_name(repo['repo'], deps), + C.LOCAL_REPO_VERSION, + )) + else: + key = (repo['repo'], repo['rev']) + path = all_repos.get(key) + # can't inspect manifest if it isn't cloned + if path is None: + return + + try: + manifest = load_manifest(os.path.join(path, C.MANIFEST_FILE)) + except InvalidManifestError: + return + else: + unused_repos.discard(key) + by_id = {hook['id']: hook for hook in manifest} + + for hook in repo['hooks']: + if hook['id'] not in by_id: + continue + + deps = hook.get( + 'additional_dependencies', + by_id[hook['id']]['additional_dependencies'], + ) + unused_repos.discard(( + store.db_repo_name(repo['repo'], deps), repo['rev'], + )) + + +def _gc(store: Store) -> int: + with store.exclusive_lock(), store.connect() as db: + store._create_configs_table(db) + + repos = db.execute('SELECT repo, ref, path FROM repos').fetchall() + all_repos = {(repo, ref): path for repo, ref, path in repos} + unused_repos = set(all_repos) + + configs_rows = db.execute('SELECT path FROM configs').fetchall() + configs = [path for path, in configs_rows] + + dead_configs = [] + for config_path in configs: + try: + config = load_config(config_path) + except InvalidConfigError: + dead_configs.append(config_path) + continue + else: + for repo in config['repos']: + _mark_used_repos(store, all_repos, unused_repos, repo) + + paths = [(path,) for path in dead_configs] + db.executemany('DELETE FROM configs WHERE path = ?', paths) + + db.executemany( + 'DELETE FROM repos WHERE repo = ? and ref = ?', + sorted(unused_repos), + ) + for k in unused_repos: + rmtree(all_repos[k]) + + return len(unused_repos) def gc(store: Store) -> int: - output.write_line(f'{store.gc()} repo(s) removed.') + output.write_line(f'{_gc(store)} repo(s) removed.') return 0 diff --git a/pre_commit/store.py b/pre_commit/store.py index 34c5f0d9..dc90c051 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -8,7 +8,6 @@ import tempfile from collections.abc import Callable from collections.abc import Generator from collections.abc import Sequence -from typing import Any import pre_commit.constants as C from pre_commit import clientlib @@ -18,7 +17,6 @@ from pre_commit.util import CalledProcessError from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output_b from pre_commit.util import resource_text -from pre_commit.util import rmtree logger = logging.getLogger('pre_commit') @@ -235,81 +233,3 @@ class Store: # TODO: eventually remove this and only create in _create self._create_configs_table(db) db.execute('INSERT OR IGNORE INTO configs VALUES (?)', (path,)) - - def _mark_used_repos( - self, - all_repos: dict[tuple[str, str], str], - unused_repos: set[tuple[str, str]], - repo: dict[str, Any], - ) -> None: - if repo['repo'] == clientlib.META: - return - elif repo['repo'] == clientlib.LOCAL: - for hook in repo['hooks']: - deps = hook.get('additional_dependencies') - unused_repos.discard(( - self.db_repo_name(repo['repo'], deps), - C.LOCAL_REPO_VERSION, - )) - else: - key = (repo['repo'], repo['rev']) - path = all_repos.get(key) - # can't inspect manifest if it isn't cloned - if path is None: - return - - try: - manifest = clientlib.load_manifest( - os.path.join(path, C.MANIFEST_FILE), - ) - except clientlib.InvalidManifestError: - return - else: - unused_repos.discard(key) - by_id = {hook['id']: hook for hook in manifest} - - for hook in repo['hooks']: - if hook['id'] not in by_id: - continue - - deps = hook.get( - 'additional_dependencies', - by_id[hook['id']]['additional_dependencies'], - ) - unused_repos.discard(( - self.db_repo_name(repo['repo'], deps), repo['rev'], - )) - - def gc(self) -> int: - with self.exclusive_lock(), self.connect() as db: - self._create_configs_table(db) - - repos = db.execute('SELECT repo, ref, path FROM repos').fetchall() - all_repos = {(repo, ref): path for repo, ref, path in repos} - unused_repos = set(all_repos) - - configs_rows = db.execute('SELECT path FROM configs').fetchall() - configs = [path for path, in configs_rows] - - dead_configs = [] - for config_path in configs: - try: - config = clientlib.load_config(config_path) - except clientlib.InvalidConfigError: - dead_configs.append(config_path) - continue - else: - for repo in config['repos']: - self._mark_used_repos(all_repos, unused_repos, repo) - - paths = [(path,) for path in dead_configs] - db.executemany('DELETE FROM configs WHERE path = ?', paths) - - db.executemany( - 'DELETE FROM repos WHERE repo = ? and ref = ?', - sorted(unused_repos), - ) - for k in unused_repos: - rmtree(all_repos[k]) - - return len(unused_repos) diff --git a/tests/commands/gc_test.py b/tests/commands/gc_test.py index 85e66977..992b02f3 100644 --- a/tests/commands/gc_test.py +++ b/tests/commands/gc_test.py @@ -165,3 +165,11 @@ def test_invalid_manifest_gcd(tempdir_factory, store, in_git_dir, cap_out): assert _config_count(store) == 1 assert _repo_count(store) == 0 assert cap_out.get().splitlines()[-1] == '1 repo(s) removed.' + + +def test_gc_pre_1_14_roll_forward(store, cap_out): + with store.connect() as db: # simulate pre-1.14.0 + db.executescript('DROP TABLE configs') + + assert not gc(store) + assert cap_out.get() == '0 repo(s) removed.\n' diff --git a/tests/store_test.py b/tests/store_test.py index 4b04a8e7..13f198ea 100644 --- a/tests/store_test.py +++ b/tests/store_test.py @@ -289,18 +289,9 @@ def test_mark_config_as_used_does_not_exist(store): assert _select_all_configs(store) == [] -def _simulate_pre_1_14_0(store): - with store.connect() as db: - db.executescript('DROP TABLE configs') - - -def test_gc_roll_forward(store): - _simulate_pre_1_14_0(store) - assert store.gc() == 0 - - def test_mark_config_as_used_roll_forward(store, tmpdir): - _simulate_pre_1_14_0(store) + with store.connect() as db: # simulate pre-1.14.0 + db.executescript('DROP TABLE configs') test_mark_config_as_used(store, tmpdir) From 844dacc168d68a32553ecf8a99178ab395fdb11e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 19 Nov 2025 14:57:01 -0500 Subject: [PATCH 406/416] add forward-compat error message --- pre_commit/clientlib.py | 11 ++++++++++- tests/clientlib_test.py | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index eb0fd4d6..51f14d26 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -270,10 +270,19 @@ class InvalidManifestError(FatalError): pass +def _load_manifest_forward_compat(contents: str) -> object: + obj = yaml_load(contents) + if isinstance(obj, dict): + check_min_version('5') + raise AssertionError('unreachable') + else: + return obj + + load_manifest = functools.partial( cfgv.load_from_filename, schema=MANIFEST_SCHEMA, - load_strategy=yaml_load, + load_strategy=_load_manifest_forward_compat, exc_tp=InvalidManifestError, ) diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 93c698f7..2c42b80c 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -12,6 +12,8 @@ from pre_commit.clientlib import CONFIG_HOOK_DICT from pre_commit.clientlib import CONFIG_REPO_DICT from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION +from pre_commit.clientlib import InvalidManifestError +from pre_commit.clientlib import load_manifest from pre_commit.clientlib import MANIFEST_HOOK_DICT from pre_commit.clientlib import MANIFEST_SCHEMA from pre_commit.clientlib import META_HOOK_DICT @@ -588,3 +590,18 @@ def test_config_hook_stages_defaulting(): 'id': 'fake-hook', 'stages': ['commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit'], } + + +def test_manifest_v5_forward_compat(tmp_path): + manifest = tmp_path.joinpath('.pre-commit-hooks.yaml') + manifest.write_text('hooks: {}') + + with pytest.raises(InvalidManifestError) as excinfo: + load_manifest(manifest) + assert str(excinfo.value) == ( + f'\n' + f'==> File {manifest}\n' + f'=====> \n' + f'=====> pre-commit version 5 is required but version {C.VERSION} ' + f'is installed. Perhaps run `pip install --upgrade pre-commit`.' + ) From 8d34f95308fc4c14dea3d3e90153acfdaf55e2de Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Fri, 21 Nov 2025 15:09:41 -0500 Subject: [PATCH 407/416] use ExitStack instead of start + stop --- tests/main_test.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/main_test.py b/tests/main_test.py index 945349fa..325792d8 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -1,6 +1,7 @@ from __future__ import annotations import argparse +import contextlib import os.path from unittest import mock @@ -97,11 +98,9 @@ CMDS = tuple(fn.replace('_', '-') for fn in FNS) @pytest.fixture def mock_commands(): - mcks = {fn: mock.patch.object(main, fn).start() for fn in FNS} - ret = auto_namedtuple(**mcks) - yield ret - for mck in ret: - mck.stop() + with contextlib.ExitStack() as ctx: + mcks = {f: ctx.enter_context(mock.patch.object(main, f)) for f in FNS} + yield auto_namedtuple(**mcks) @pytest.fixture From bdf68790b78158268bbc8482f76491a61d75809a Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Fri, 21 Nov 2025 16:38:55 -0500 Subject: [PATCH 408/416] add pre-commit hazmat --- pre_commit/commands/hazmat.py | 95 +++++++++++++++++++++++++++++++++ pre_commit/lang_base.py | 6 ++- pre_commit/main.py | 10 +++- tests/commands/hazmat_test.py | 99 +++++++++++++++++++++++++++++++++++ tests/lang_base_test.py | 12 +++++ tests/main_test.py | 12 +++++ tests/repository_test.py | 11 ++++ 7 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 pre_commit/commands/hazmat.py create mode 100644 tests/commands/hazmat_test.py diff --git a/pre_commit/commands/hazmat.py b/pre_commit/commands/hazmat.py new file mode 100644 index 00000000..01b27ce6 --- /dev/null +++ b/pre_commit/commands/hazmat.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +import argparse +import subprocess +from collections.abc import Sequence + +from pre_commit.parse_shebang import normalize_cmd + + +def add_parsers(parser: argparse.ArgumentParser) -> None: + subparsers = parser.add_subparsers(dest='tool') + + cd_parser = subparsers.add_parser( + 'cd', help='cd to a subdir and run the command', + ) + cd_parser.add_argument('subdir') + cd_parser.add_argument('cmd', nargs=argparse.REMAINDER) + + ignore_exit_code_parser = subparsers.add_parser( + 'ignore-exit-code', help='run the command but ignore the exit code', + ) + ignore_exit_code_parser.add_argument('cmd', nargs=argparse.REMAINDER) + + n1_parser = subparsers.add_parser( + 'n1', help='run the command once per filename', + ) + n1_parser.add_argument('cmd', nargs=argparse.REMAINDER) + + +def _cmd_filenames(cmd: tuple[str, ...]) -> tuple[ + tuple[str, ...], + tuple[str, ...], +]: + for idx, val in enumerate(reversed(cmd)): + if val == '--': + split = len(cmd) - idx + break + else: + raise SystemExit('hazmat entry must end with `--`') + + return cmd[:split - 1], cmd[split:] + + +def cd(subdir: str, cmd: tuple[str, ...]) -> int: + cmd, filenames = _cmd_filenames(cmd) + + prefix = f'{subdir}/' + new_filenames = [] + for filename in filenames: + if not filename.startswith(prefix): + raise SystemExit(f'unexpected file without {prefix=}: {filename}') + else: + new_filenames.append(filename.removeprefix(prefix)) + + cmd = normalize_cmd(cmd) + return subprocess.call((*cmd, *new_filenames), cwd=subdir) + + +def ignore_exit_code(cmd: tuple[str, ...]) -> int: + cmd = normalize_cmd(cmd) + subprocess.call(cmd) + return 0 + + +def n1(cmd: tuple[str, ...]) -> int: + cmd, filenames = _cmd_filenames(cmd) + cmd = normalize_cmd(cmd) + ret = 0 + for filename in filenames: + ret |= subprocess.call((*cmd, filename)) + return ret + + +def impl(args: argparse.Namespace) -> int: + args.cmd = tuple(args.cmd) + if args.tool == 'cd': + return cd(args.subdir, args.cmd) + elif args.tool == 'ignore-exit-code': + return ignore_exit_code(args.cmd) + elif args.tool == 'n1': + return n1(args.cmd) + else: + raise NotImplementedError(f'unexpected tool: {args.tool}') + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser() + add_parsers(parser) + args = parser.parse_args(argv) + + return impl(args) + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/pre_commit/lang_base.py b/pre_commit/lang_base.py index 95be7b9b..198e9365 100644 --- a/pre_commit/lang_base.py +++ b/pre_commit/lang_base.py @@ -5,6 +5,7 @@ import os import random import re import shlex +import sys from collections.abc import Generator from collections.abc import Sequence from typing import Any @@ -171,7 +172,10 @@ def run_xargs( def hook_cmd(entry: str, args: Sequence[str]) -> tuple[str, ...]: - return (*shlex.split(entry), *args) + cmd = shlex.split(entry) + if cmd[:2] == ['pre-commit', 'hazmat']: + cmd = [sys.executable, '-m', 'pre_commit.commands.hazmat', *cmd[2:]] + return (*cmd, *args) def basic_run_hook( diff --git a/pre_commit/main.py b/pre_commit/main.py index c33fbfda..0c3eefda 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -10,6 +10,7 @@ import pre_commit.constants as C from pre_commit import clientlib from pre_commit import git from pre_commit.color import add_color_option +from pre_commit.commands import hazmat from pre_commit.commands.autoupdate import autoupdate from pre_commit.commands.clean import clean from pre_commit.commands.gc import gc @@ -41,7 +42,7 @@ os.environ.pop('__PYVENV_LAUNCHER__', None) os.environ.pop('PYTHONEXECUTABLE', None) COMMANDS_NO_GIT = { - 'clean', 'gc', 'init-templatedir', 'sample-config', + 'clean', 'gc', 'hazmat', 'init-templatedir', 'sample-config', 'validate-config', 'validate-manifest', } @@ -245,6 +246,11 @@ def main(argv: Sequence[str] | None = None) -> int: _add_cmd('gc', help='Clean unused cached repos.') + hazmat_parser = _add_cmd( + 'hazmat', help='Composable tools for rare use in hook `entry`.', + ) + hazmat.add_parsers(hazmat_parser) + init_templatedir_parser = _add_cmd( 'init-templatedir', help=( @@ -389,6 +395,8 @@ def main(argv: Sequence[str] | None = None) -> int: return clean(store) elif args.command == 'gc': return gc(store) + elif args.command == 'hazmat': + return hazmat.impl(args) elif args.command == 'hook-impl': return hook_impl( store, diff --git a/tests/commands/hazmat_test.py b/tests/commands/hazmat_test.py new file mode 100644 index 00000000..df957e36 --- /dev/null +++ b/tests/commands/hazmat_test.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +import sys + +import pytest + +from pre_commit.commands.hazmat import _cmd_filenames +from pre_commit.commands.hazmat import main +from testing.util import cwd + + +def test_cmd_filenames_no_dash_dash(): + with pytest.raises(SystemExit) as excinfo: + _cmd_filenames(('no', 'dashdash', 'here')) + msg, = excinfo.value.args + assert msg == 'hazmat entry must end with `--`' + + +def test_cmd_filenames_no_filenames(): + cmd, filenames = _cmd_filenames(('hello', 'world', '--')) + assert cmd == ('hello', 'world') + assert filenames == () + + +def test_cmd_filenames_some_filenames(): + cmd, filenames = _cmd_filenames(('hello', 'world', '--', 'f1', 'f2')) + assert cmd == ('hello', 'world') + assert filenames == ('f1', 'f2') + + +def test_cmd_filenames_multiple_dashdash(): + cmd, filenames = _cmd_filenames(('hello', '--', 'arg', '--', 'f1', 'f2')) + assert cmd == ('hello', '--', 'arg') + assert filenames == ('f1', 'f2') + + +def test_cd_unexpected_filename(): + with pytest.raises(SystemExit) as excinfo: + main(('cd', 'subdir', 'cmd', '--', 'subdir/1', 'not-subdir/2')) + msg, = excinfo.value.args + assert msg == "unexpected file without prefix='subdir/': not-subdir/2" + + +def _norm(out): + return out.replace('\r\n', '\n') + + +def test_cd(tmp_path, capfd): + subdir = tmp_path.joinpath('subdir') + subdir.mkdir() + subdir.joinpath('a').write_text('a') + subdir.joinpath('b').write_text('b') + + with cwd(tmp_path): + ret = main(( + 'cd', 'subdir', + sys.executable, '-c', + 'import os; print(os.getcwd());' + 'import sys; [print(open(f).read()) for f in sys.argv[1:]]', + '--', + 'subdir/a', 'subdir/b', + )) + + assert ret == 0 + out, err = capfd.readouterr() + assert _norm(out) == f'{subdir}\na\nb\n' + assert err == '' + + +def test_ignore_exit_code(capfd): + ret = main(( + 'ignore-exit-code', sys.executable, '-c', 'raise SystemExit("bye")', + )) + assert ret == 0 + out, err = capfd.readouterr() + assert out == '' + assert _norm(err) == 'bye\n' + + +def test_n1(capfd): + ret = main(( + 'n1', sys.executable, '-c', 'import sys; print(sys.argv[1:])', + '--', + 'foo', 'bar', 'baz', + )) + assert ret == 0 + out, err = capfd.readouterr() + assert _norm(out) == "['foo']\n['bar']\n['baz']\n" + assert err == '' + + +def test_n1_some_error_code(): + ret = main(( + 'n1', sys.executable, '-c', + 'import sys; raise SystemExit(sys.argv[1] == "error")', + '--', + 'ok', 'error', 'ok', + )) + assert ret == 1 diff --git a/tests/lang_base_test.py b/tests/lang_base_test.py index da289aef..9fac83da 100644 --- a/tests/lang_base_test.py +++ b/tests/lang_base_test.py @@ -164,3 +164,15 @@ def test_basic_run_hook(tmp_path): assert ret == 0 out = out.replace(b'\r\n', b'\n') assert out == b'hi hello file file file\n' + + +def test_hook_cmd(): + assert lang_base.hook_cmd('echo hi', ()) == ('echo', 'hi') + + +def test_hook_cmd_hazmat(): + ret = lang_base.hook_cmd('pre-commit hazmat cd a echo -- b', ()) + assert ret == ( + sys.executable, '-m', 'pre_commit.commands.hazmat', + 'cd', 'a', 'echo', '--', 'b', + ) diff --git a/tests/main_test.py b/tests/main_test.py index 945349fa..eb9ea18d 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -8,6 +8,7 @@ import pytest import pre_commit.constants as C from pre_commit import main +from pre_commit.commands import hazmat from pre_commit.errors import FatalError from pre_commit.util import cmd_output from testing.auto_namedtuple import auto_namedtuple @@ -158,6 +159,17 @@ def test_all_cmds(command, mock_commands, mock_store_dir): assert_only_one_mock_called(mock_commands) +def test_hazmat(mock_store_dir): + with mock.patch.object(hazmat, 'impl') as mck: + main.main(('hazmat', 'cd', 'subdir', '--', 'cmd', '--', 'f1', 'f2')) + assert mck.call_count == 1 + (arg,), dct = mck.call_args + assert dct == {} + assert arg.tool == 'cd' + assert arg.subdir == 'subdir' + assert arg.cmd == ['cmd', '--', 'f1', 'f2'] + + def test_try_repo(mock_store_dir): with mock.patch.object(main, 'try_repo') as patch: main.main(('try-repo', '.')) diff --git a/tests/repository_test.py b/tests/repository_test.py index b1c7a002..5d71c3e4 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -506,3 +506,14 @@ def test_args_with_spaces_and_quotes(tmp_path): expected = b"['i have spaces', 'and\"\\'quotes', '$and !this']\n" assert ret == (0, expected) + + +def test_hazmat(tmp_path): + ret = run_language( + tmp_path, unsupported, + f'pre-commit hazmat ignore-exit-code {shlex.quote(sys.executable)} ' + f"-c 'import sys; raise SystemExit(sys.argv[1:])'", + ('f1', 'f2'), + ) + expected = b"['f1', 'f2']\n" + assert ret == (0, expected) From 1af6c8fa9502336c6977c2ff3e79185bd97a6e57 Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 22 Nov 2025 16:02:16 -0500 Subject: [PATCH 409/416] v4.5.0 --- CHANGELOG.md | 7 +++++++ setup.cfg | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b27af5e7..1434728d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +4.5.0 - 2025-11-22 +================== + +### Features +- Add `pre-commit hazmat`. + - #3585 PR by @asottile. + 4.4.0 - 2025-11-08 ================== diff --git a/setup.cfg b/setup.cfg index be031c3e..00c71759 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.4.0 +version = 4.5.0 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 8ea2b790d817088444b2328ff6cfe6742260070f Mon Sep 17 00:00:00 2001 From: anthony sottile Date: Sat, 22 Nov 2025 16:06:27 -0500 Subject: [PATCH 410/416] remove sha256 file from zipapp script github displays the checksum for us now! --- testing/zipapp/make | 3 --- 1 file changed, 3 deletions(-) diff --git a/testing/zipapp/make b/testing/zipapp/make index 165046f6..43bb4373 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -107,9 +107,6 @@ def main() -> int: shebang = '/usr/bin/env python3' zipapp.create_archive(tmpdir, filename, interpreter=shebang) - with open(f'{filename}.sha256sum', 'w') as f: - subprocess.check_call(('sha256sum', filename), stdout=f) - return 0 From 465192d7de58d569776eaaa818c94cb2b962d436 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:53:38 +0000 Subject: [PATCH 411/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.21.1 → v3.21.2](https://github.com/asottile/pyupgrade/compare/v3.21.1...v3.21.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e47d56ca..50893030 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: add-trailing-comma - repo: https://github.com/asottile/pyupgrade - rev: v3.21.1 + rev: v3.21.2 hooks: - id: pyupgrade args: [--py310-plus] From 48953556d06f8cdb4248002c1a0044e69e0916b3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 21:05:15 +0000 Subject: [PATCH 412/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.18.2 → v1.19.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.18.2...v1.19.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 50893030..cedeae5e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.18.2 + rev: v1.19.0 hooks: - id: mypy additional_dependencies: [types-pyyaml] From c251e6b6d011b3b262339dc8e109de29b0ff8db1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:48:45 +0000 Subject: [PATCH 413/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.19.0 → v1.19.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.19.0...v1.19.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cedeae5e..83ff03f3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.19.0 + rev: v1.19.1 hooks: - id: mypy additional_dependencies: [types-pyyaml] From 51592eececd13b99c40ec477ad8f810799147227 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 16 Dec 2025 15:45:01 -0500 Subject: [PATCH 414/416] fix python local template when artifact dirs are present --- pre_commit/resources/empty_template_setup.py | 2 +- tests/languages/python_test.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pre_commit/resources/empty_template_setup.py b/pre_commit/resources/empty_template_setup.py index ef05eef8..e8b1ff02 100644 --- a/pre_commit/resources/empty_template_setup.py +++ b/pre_commit/resources/empty_template_setup.py @@ -1,4 +1,4 @@ from setuptools import setup -setup(name='pre-commit-placeholder-package', version='0.0.0') +setup(name='pre-commit-placeholder-package', version='0.0.0', py_modules=[]) diff --git a/tests/languages/python_test.py b/tests/languages/python_test.py index 565525a4..593634b7 100644 --- a/tests/languages/python_test.py +++ b/tests/languages/python_test.py @@ -10,6 +10,8 @@ import pre_commit.constants as C from pre_commit.envcontext import envcontext from pre_commit.languages import python from pre_commit.prefix import Prefix +from pre_commit.store import _make_local_repo +from pre_commit.util import cmd_output_b from pre_commit.util import make_executable from pre_commit.util import win_exe from testing.auto_namedtuple import auto_namedtuple @@ -351,3 +353,15 @@ def test_python_hook_weird_setup_cfg(tmp_path): ret = run_language(tmp_path, python, 'socks', [os.devnull]) assert ret == (0, f'[{os.devnull!r}]\nhello hello\n'.encode()) + + +def test_local_repo_with_other_artifacts(tmp_path): + cmd_output_b('git', 'init', tmp_path) + _make_local_repo(str(tmp_path)) + # pretend a rust install also ran here + tmp_path.joinpath('target').mkdir() + + ret, out = run_language(tmp_path, python, 'python --version') + + assert ret == 0 + assert out.startswith(b'Python ') From 8a0630ca1aa7f6d5665effe674ebe2022af17919 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 16 Dec 2025 16:13:56 -0500 Subject: [PATCH 415/416] v4.5.1 --- CHANGELOG.md | 7 +++++++ setup.cfg | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1434728d..879ae073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +4.5.1 - 2025-12-16 +================== + +### Fixes +- Fix `language: python` with `repo: local` without `additional_dependencies`. + - #3597 PR by @asottile. + 4.5.0 - 2025-11-22 ================== diff --git a/setup.cfg b/setup.cfg index 00c71759..a95ee447 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 4.5.0 +version = 4.5.1 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown From 37a879e65ee00d8375d12f053ef76e0024a0ed55 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 20:26:26 +0000 Subject: [PATCH 416/416] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/setup-cfg-fmt: v3.1.0 → v3.2.0](https://github.com/asottile/setup-cfg-fmt/compare/v3.1.0...v3.2.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83ff03f3..3654066f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v3.1.0 + rev: v3.2.0 hooks: - id: setup-cfg-fmt - repo: https://github.com/asottile/reorder-python-imports

Ic>4rPYCPrkRQ0`qRDI8#|2${EyKj}()OD)= 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