| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,36 +1,40 @@ | |||
| 1 | - import re | ||
| 2 | - import sys | ||
| 1 | + import argparse | ||
| 3 | 2 | ||
| 4 | 3 | import pre_commit.constants as C | |
| 5 | - from pre_commit.clientlib import load_config | ||
| 4 | + from pre_commit.commands.run import _filter_by_include_exclude | ||
| 5 | + from pre_commit.commands.run import _filter_by_types | ||
| 6 | 6 | from pre_commit.git import get_all_files | |
| 7 | + from pre_commit.runner import Runner | ||
| 7 | 8 | ||
| 8 | 9 | ||
| 9 | - def files_matches_any(filenames, include): | ||
| 10 | - include_re = re.compile(include) | ||
| 11 | - for filename in filenames: | ||
| 12 | - if include_re.search(filename): | ||
| 13 | - return True | ||
| 14 | - return False | ||
| 10 | + def check_all_hooks_match_files(config_file): | ||
| 11 | + runner = Runner.create(config_file) | ||
| 12 | + files = get_all_files() | ||
| 13 | + files_matched = True | ||
| 15 | 14 | ||
| 15 | + for repo in runner.repositories: | ||
| 16 | + for hook_id, hook in repo.hooks: | ||
| 17 | + include, exclude = hook['files'], hook['exclude'] | ||
| 18 | + filtered = _filter_by_include_exclude(files, include, exclude) | ||
| 19 | + types, exclude_types = hook['types'], hook['exclude_types'] | ||
| 20 | + filtered = _filter_by_types(filtered, types, exclude_types) | ||
| 21 | + if not filtered: | ||
| 22 | + print('{} does not apply to this repository'.format(hook_id)) | ||
| 23 | + files_matched = False | ||
| 24 | + | ||
| 25 | + return files_matched | ||
| 16 | 26 | ||
| 17 | - def check_files_matches_any(config_file=None): | ||
| 18 | - config = load_config(config_file or C.CONFIG_FILE) | ||
| 19 | - files = get_all_files() | ||
| 20 | - files_not_matched = False | ||
| 21 | 27 | ||
| 22 | - for repo in config['repos']: | ||
| 23 | - for hook in repo['hooks']: | ||
| 24 | - include = hook.get('files', '') | ||
| 25 | - if include and not files_matches_any(files, include): | ||
| 26 | - print( | ||
| 27 | - 'The files pattern for {} does not match any files' | ||
| 28 | - .format(hook['id']) | ||
| 29 | - ) | ||
| 30 | - files_not_matched = True | ||
| 28 | + def main(argv=None): | ||
| 29 | + parser = argparse.ArgumentParser() | ||
| 30 | + parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE]) | ||
| 31 | + args = parser.parse_args(argv) | ||
| 31 | 32 | ||
| 32 | - return files_not_matched | ||
| 33 | + retv = 0 | ||
| 34 | + for filename in args.filenames: | ||
| 35 | + retv |= not check_all_hooks_match_files(filename) | ||
| 36 | + return retv | ||
| 33 | 37 | ||
| 34 | 38 | ||
| 35 | 39 | if __name__ == '__main__': | |
| 36 | - sys.exit(check_files_matches_any()) | ||
| 40 | + exit(main()) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,7 @@ | |||
| 1 | + from __future__ import print_function | ||
| 2 | + | ||
| 3 | + import argparse | ||
| 1 | 4 | import re | |
| 2 | - import sys | ||
| 3 | 5 | ||
| 4 | 6 | import pre_commit.constants as C | |
| 5 | 7 | from pre_commit.clientlib import load_config | |
@@ -14,28 +16,42 @@ def exclude_matches_any(filenames, include, exclude): | |||
| 14 | 16 | return False | |
| 15 | 17 | ||
| 16 | 18 | ||
| 17 | - def check_useless_excludes(config_file=None): | ||
| 18 | - config = load_config(config_file or C.CONFIG_FILE) | ||
| 19 | + def check_useless_excludes(config_file): | ||
| 20 | + config = load_config(config_file) | ||
| 19 | 21 | files = get_all_files() | |
| 20 | 22 | useless_excludes = False | |
| 21 | 23 | ||
| 22 | 24 | exclude = config.get('exclude') | |
| 23 | 25 | if exclude != '^$' and not exclude_matches_any(files, '', exclude): | |
| 24 | - print('The global exclude pattern does not match any files') | ||
| 26 | + print( | ||
| 27 | + 'The global exclude pattern {!r} does not match any files' | ||
| 28 | + .format(exclude), | ||
| 29 | + ) | ||
| 25 | 30 | useless_excludes = True | |
| 26 | 31 | ||
| 27 | 32 | for repo in config['repos']: | |
| 28 | 33 | for hook in repo['hooks']: | |
| 29 | 34 | include, exclude = hook.get('files', ''), hook.get('exclude') | |
| 30 | 35 | if exclude and not exclude_matches_any(files, include, exclude): | |
| 31 | 36 | print( | |
| 32 | - 'The exclude pattern for {} does not match any files' | ||
| 33 | - .format(hook['id']) | ||
| 37 | + 'The exclude pattern {!r} for {} does not match any files' | ||
| 38 | + .format(exclude, hook['id']), | ||
| 34 | 39 | ) | |
| 35 | 40 | useless_excludes = True | |
| 36 | 41 | ||
| 37 | 42 | return useless_excludes | |
| 38 | 43 | ||
| 39 | 44 | ||
| 45 | + def main(argv=None): | ||
| 46 | + parser = argparse.ArgumentParser() | ||
| 47 | + parser.add_argument('filenames', nargs='*', default=[C.CONFIG_FILE]) | ||
| 48 | + args = parser.parse_args(argv) | ||
| 49 | + | ||
| 50 | + retv = 0 | ||
| 51 | + for filename in args.filenames: | ||
| 52 | + retv |= check_useless_excludes(filename) | ||
| 53 | + return retv | ||
| 54 | + | ||
| 55 | + | ||
| 40 | 56 | if __name__ == '__main__': | |
| 41 | - sys.exit(check_useless_excludes()) | ||
| 57 | + exit(main()) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -252,50 +252,56 @@ def _venvs(self): | |||
| 252 | 252 | ||
| 253 | 253 | ||
| 254 | 254 | class MetaRepository(LocalRepository): | |
| 255 | - # Note: the hook `entry` is passed through `shlex.split()` by the command | ||
| 256 | - # runner, so to prevent issues with spaces and backslashes (on Windows) it | ||
| 257 | - # must be quoted here. | ||
| 258 | - meta_hooks = { | ||
| 259 | - 'check-useless-excludes': { | ||
| 260 | - 'name': 'Check for useless excludes', | ||
| 261 | - 'files': '.pre-commit-config.yaml', | ||
| 262 | - 'language': 'system', | ||
| 263 | - 'entry': pipes.quote(sys.executable), | ||
| 264 | - 'args': ['-m', 'pre_commit.meta_hooks.check_useless_excludes'], | ||
| 265 | - }, | ||
| 266 | - 'check-files-matches-any': { | ||
| 267 | - 'name': 'Check hooks match any files', | ||
| 268 | - 'files': '.pre-commit-config.yaml', | ||
| 269 | - 'language': 'system', | ||
| 270 | - 'entry': pipes.quote(sys.executable), | ||
| 271 | - 'args': ['-m', 'pre_commit.meta_hooks.check_files_matches_any'], | ||
| 272 | - }, | ||
| 273 | - } | ||
| 255 | + @cached_property | ||
| 256 | + def manifest_hooks(self): | ||
| 257 | + # The hooks are imported here to prevent circular imports. | ||
| 258 | + from pre_commit.meta_hooks import check_files_matches_any | ||
| 259 | + from pre_commit.meta_hooks import check_useless_excludes | ||
| 260 | + | ||
| 261 | + # Note: the hook `entry` is passed through `shlex.split()` by the | ||
| 262 | + # command runner, so to prevent issues with spaces and backslashes | ||
| 263 | + # (on Windows) it must be quoted here. | ||
| 264 | + meta_hooks = [ | ||
| 265 | + { | ||
| 266 | + 'id': 'check-useless-excludes', | ||
| 267 | + 'name': 'Check for useless excludes', | ||
| 268 | + 'files': '.pre-commit-config.yaml', | ||
| 269 | + 'language': 'system', | ||
| 270 | + 'entry': pipes.quote(sys.executable), | ||
| 271 | + 'args': ['-m', check_useless_excludes.__name__], | ||
| 272 | + }, | ||
| 273 | + { | ||
| 274 | + 'id': 'check-files-matches-any', | ||
| 275 | + 'name': 'Check hooks match any files', | ||
| 276 | + 'files': '.pre-commit-config.yaml', | ||
| 277 | + 'language': 'system', | ||
| 278 | + 'entry': pipes.quote(sys.executable), | ||
| 279 | + 'args': ['-m', check_files_matches_any.__name__], | ||
| 280 | + }, | ||
| 281 | + ] | ||
| 282 | + | ||
| 283 | + return { | ||
| 284 | + hook['id']: apply_defaults( | ||
| 285 | + validate(hook, MANIFEST_HOOK_DICT), | ||
| 286 | + MANIFEST_HOOK_DICT, | ||
| 287 | + ) | ||
| 288 | + for hook in meta_hooks | ||
| 289 | + } | ||
| 274 | 290 | ||
| 275 | 291 | @cached_property | |
| 276 | 292 | def hooks(self): | |
| 277 | 293 | for hook in self.repo_config['hooks']: | |
| 278 | - if hook['id'] not in self.meta_hooks: | ||
| 294 | + if hook['id'] not in self.manifest_hooks: | ||
| 279 | 295 | logger.error( | |
| 280 | 296 | '`{}` is not a valid meta hook. ' | |
| 281 | 297 | 'Typo? Perhaps it is introduced in a newer version? ' | |
| 282 | - 'Often `pre-commit autoupdate` fixes this.'.format( | ||
| 283 | - hook['id'], | ||
| 284 | - ), | ||
| 298 | + 'Often `pip install --upgrade pre-commit` fixes this.' | ||
| 299 | + .format(hook['id']), | ||
| 285 | 300 | ) | |
| 286 | 301 | exit(1) | |
| 287 | 302 | ||
| 288 | 303 | return tuple( | |
| 289 | - ( | ||
| 290 | - hook['id'], | ||
| 291 | - apply_defaults( | ||
| 292 | - validate( | ||
| 293 | - dict(self.meta_hooks[hook['id']], **hook), | ||
| 294 | - MANIFEST_HOOK_DICT, | ||
| 295 | - ), | ||
| 296 | - MANIFEST_HOOK_DICT, | ||
| 297 | - ), | ||
| 298 | - ) | ||
| 304 | + (hook['id'], _hook(self.manifest_hooks[hook['id']], hook)) | ||
| 299 | 305 | for hook in self.repo_config['hooks'] | |
| 300 | 306 | ) | |
| 301 | 307 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -670,104 +670,6 @@ def test_meta_hook_passes( | |||
| 670 | 670 | ) | |
| 671 | 671 | ||
| 672 | 672 | ||
| 673 | - def test_useless_exclude_global( | ||
| 674 | - cap_out, repo_with_passing_hook, mock_out_store_directory, | ||
| 675 | - ): | ||
| 676 | - config = OrderedDict(( | ||
| 677 | - ('exclude', 'foo'), | ||
| 678 | - ( | ||
| 679 | - 'repos', [ | ||
| 680 | - OrderedDict(( | ||
| 681 | - ('repo', 'meta'), | ||
| 682 | - ( | ||
| 683 | - 'hooks', ( | ||
| 684 | - OrderedDict(( | ||
| 685 | - ('id', 'check-useless-excludes'), | ||
| 686 | - )), | ||
| 687 | - ), | ||
| 688 | - ), | ||
| 689 | - )), | ||
| 690 | - ], | ||
| 691 | - ), | ||
| 692 | - )) | ||
| 693 | - add_config_to_repo(repo_with_passing_hook, config) | ||
| 694 | - | ||
| 695 | - _test_run( | ||
| 696 | - cap_out, | ||
| 697 | - repo_with_passing_hook, | ||
| 698 | - opts={'all_files': True}, | ||
| 699 | - expected_outputs=[ | ||
| 700 | - b'Check for useless excludes', | ||
| 701 | - b'The global exclude pattern does not match any files', | ||
| 702 | - ], | ||
| 703 | - expected_ret=1, | ||
| 704 | - stage=False, | ||
| 705 | - ) | ||
| 706 | - | ||
| 707 | - | ||
| 708 | - def test_useless_exclude_for_hook( | ||
| 709 | - cap_out, repo_with_passing_hook, mock_out_store_directory, | ||
| 710 | - ): | ||
| 711 | - config = OrderedDict(( | ||
| 712 | - ('repo', 'meta'), | ||
| 713 | - ( | ||
| 714 | - 'hooks', ( | ||
| 715 | - OrderedDict(( | ||
| 716 | - ('id', 'check-useless-excludes'), | ||
| 717 | - ('exclude', 'foo'), | ||
| 718 | - )), | ||
| 719 | - ), | ||
| 720 | - ), | ||
| 721 | - )) | ||
| 722 | - add_config_to_repo(repo_with_passing_hook, config) | ||
| 723 | - | ||
| 724 | - _test_run( | ||
| 725 | - cap_out, | ||
| 726 | - repo_with_passing_hook, | ||
| 727 | - opts={'all_files': True}, | ||
| 728 | - expected_outputs=[ | ||
| 729 | - b'Check for useless excludes', | ||
| 730 | - b'The exclude pattern for check-useless-excludes ' | ||
| 731 | - b'does not match any files', | ||
| 732 | - ], | ||
| 733 | - expected_ret=1, | ||
| 734 | - stage=False, | ||
| 735 | - ) | ||
| 736 | - | ||
| 737 | - | ||
| 738 | - def test_files_match_any( | ||
| 739 | - cap_out, repo_with_passing_hook, mock_out_store_directory, | ||
| 740 | - ): | ||
| 741 | - config = OrderedDict(( | ||
| 742 | - ('repo', 'meta'), | ||
| 743 | - ( | ||
| 744 | - 'hooks', ( | ||
| 745 | - OrderedDict(( | ||
| 746 | - ('id', 'check-files-matches-any'), | ||
| 747 | - )), | ||
| 748 | - OrderedDict(( | ||
| 749 | - ('id', 'check-useless-excludes'), | ||
| 750 | - ('files', 'foo'), | ||
| 751 | - )), | ||
| 752 | - ), | ||
| 753 | - ), | ||
| 754 | - )) | ||
| 755 | - add_config_to_repo(repo_with_passing_hook, config) | ||
| 756 | - | ||
| 757 | - _test_run( | ||
| 758 | - cap_out, | ||
| 759 | - repo_with_passing_hook, | ||
| 760 | - opts={'all_files': True}, | ||
| 761 | - expected_outputs=[ | ||
| 762 | - b'Check hooks match any files', | ||
| 763 | - b'The files pattern for check-useless-excludes ' | ||
| 764 | - b'does not match any files', | ||
| 765 | - ], | ||
| 766 | - expected_ret=1, | ||
| 767 | - stage=False, | ||
| 768 | - ) | ||
| 769 | - | ||
| 770 | - | ||
| 771 | 673 | @pytest.yield_fixture | |
| 772 | 674 | def modified_config_repo(repo_with_passing_hook): | |
| 773 | 675 | with modify_config(repo_with_passing_hook, commit=False) as config: | |
| Back | FazBrowse Home | New Git URL |
0 commit comments