mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-04-15 18:11:48 +04:00
First pass at adding a hook selector for files that contain a given string
This commit is contained in:
parent
6872289f1a
commit
82e1768656
6 changed files with 38 additions and 0 deletions
|
|
@ -60,6 +60,7 @@ MANIFEST_HOOK_DICT = cfgv.Map(
|
||||||
cfgv.Optional('alias', cfgv.check_string, ''),
|
cfgv.Optional('alias', cfgv.check_string, ''),
|
||||||
|
|
||||||
cfgv.Optional('files', check_string_regex, ''),
|
cfgv.Optional('files', check_string_regex, ''),
|
||||||
|
cfgv.Optional('files_contain', cfgv.check_string, ''),
|
||||||
cfgv.Optional('exclude', check_string_regex, '^$'),
|
cfgv.Optional('exclude', check_string_regex, '^$'),
|
||||||
cfgv.Optional('types', cfgv.check_array(check_type_tag), ['file']),
|
cfgv.Optional('types', cfgv.check_array(check_type_tag), ['file']),
|
||||||
cfgv.Optional('types_or', cfgv.check_array(check_type_tag), []),
|
cfgv.Optional('types_or', cfgv.check_array(check_type_tag), []),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import argparse
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
|
import mmap
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
@ -100,6 +101,22 @@ class Classifier:
|
||||||
ret.append(filename)
|
ret.append(filename)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def files_contain(
|
||||||
|
self,
|
||||||
|
names: Sequence[str],
|
||||||
|
contains: str,
|
||||||
|
) -> List[str]:
|
||||||
|
if contains == '':
|
||||||
|
return list(names)
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
for filename in names:
|
||||||
|
with open(filename, 'r+') as f:
|
||||||
|
with mmap.mmap(f.fileno(), 0) as mm:
|
||||||
|
if mm.find(contains.encode()) >= 0:
|
||||||
|
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 = self.filenames
|
||||||
names = filter_by_include_exclude(names, hook.files, hook.exclude)
|
names = filter_by_include_exclude(names, hook.files, hook.exclude)
|
||||||
|
|
@ -109,6 +126,10 @@ class Classifier:
|
||||||
hook.types_or,
|
hook.types_or,
|
||||||
hook.exclude_types,
|
hook.exclude_types,
|
||||||
)
|
)
|
||||||
|
names = self.files_contain(
|
||||||
|
names,
|
||||||
|
hook.files_contain,
|
||||||
|
)
|
||||||
return tuple(names)
|
return tuple(names)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ class Hook(NamedTuple):
|
||||||
language: str
|
language: str
|
||||||
alias: str
|
alias: str
|
||||||
files: str
|
files: str
|
||||||
|
files_contain: str
|
||||||
exclude: str
|
exclude: str
|
||||||
types: Sequence[str]
|
types: Sequence[str]
|
||||||
types_or: Sequence[str]
|
types_or: Sequence[str]
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,9 @@ def check_useless_excludes(config_file: str) -> int:
|
||||||
types = hook['types']
|
types = hook['types']
|
||||||
types_or = hook['types_or']
|
types_or = hook['types_or']
|
||||||
exclude_types = hook['exclude_types']
|
exclude_types = hook['exclude_types']
|
||||||
|
files_contain = hook['files_contain']
|
||||||
names = classifier.by_types(names, types, types_or, exclude_types)
|
names = classifier.by_types(names, types, types_or, exclude_types)
|
||||||
|
names = classifier.files_contain(names, files_contain)
|
||||||
include, exclude = hook['files'], hook['exclude']
|
include, exclude = hook['files'], hook['exclude']
|
||||||
if not exclude_matches_any(names, include, exclude):
|
if not exclude_matches_any(names, include, exclude):
|
||||||
print(
|
print(
|
||||||
|
|
|
||||||
|
|
@ -1028,6 +1028,18 @@ def test_classifier_empty_types_or(tmpdir):
|
||||||
assert for_file == ['bar']
|
assert for_file == ['bar']
|
||||||
|
|
||||||
|
|
||||||
|
def test_classifier_files_contain(tmpdir):
|
||||||
|
tmpdir.join('ignored').ensure().write('We\nIgnore\nThis\nFile\n')
|
||||||
|
tmpdir.join('matched').ensure().write('We\nMatch\nThis\nFile\n')
|
||||||
|
with tmpdir.as_cwd():
|
||||||
|
classifier = Classifier(('ignored', 'matched'))
|
||||||
|
files_contain = classifier.files_contain(
|
||||||
|
classifier.filenames,
|
||||||
|
contains='Match',
|
||||||
|
)
|
||||||
|
assert files_contain == ['matched']
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def some_filenames():
|
def some_filenames():
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -986,6 +986,7 @@ def test_manifest_hooks(tempdir_factory, store):
|
||||||
exclude='^$',
|
exclude='^$',
|
||||||
exclude_types=[],
|
exclude_types=[],
|
||||||
files='',
|
files='',
|
||||||
|
files_contain='',
|
||||||
id='bash_hook',
|
id='bash_hook',
|
||||||
language='script',
|
language='script',
|
||||||
language_version='default',
|
language_version='default',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue