Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

normalize slashes even earlier on windows for filenames #1494

Merged
merged 1 commit into from Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 18 additions & 9 deletions pre_commit/commands/run.py
Expand Up @@ -72,13 +72,7 @@ def filter_by_include_exclude(


class Classifier:
def __init__(self, filenames: Sequence[str]) -> None:
# 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
# see #1173
if os.altsep == '/' and os.sep == '\\':
filenames = [f.replace(os.sep, os.altsep) for f in filenames]
def __init__(self, filenames: Collection[str]) -> None:
self.filenames = [f for f in filenames if os.path.lexists(f)]

@functools.lru_cache(maxsize=None)
Expand All @@ -105,6 +99,22 @@ def filenames_for_hook(self, hook: Hook) -> Tuple[str, ...]:
names = self.by_types(names, hook.types, hook.exclude_types)
return tuple(names)

@classmethod
def from_config(
cls,
filenames: Collection[str],
include: str,
exclude: str,
) -> '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
# see #1173
if os.altsep == '/' and os.sep == '\\':
filenames = [f.replace(os.sep, os.altsep) for f in filenames]
filenames = filter_by_include_exclude(filenames, include, exclude)
return Classifier(filenames)


def _get_skips(environ: EnvironT) -> Set[str]:
skips = environ.get('SKIP', '')
Expand Down Expand Up @@ -247,10 +257,9 @@ def _run_hooks(
"""Actually run the hooks."""
skips = _get_skips(environ)
cols = _compute_cols(hooks)
filenames = filter_by_include_exclude(
classifier = Classifier.from_config(
_all_filenames(args), config['files'], config['exclude'],
)
classifier = Classifier(filenames)
retval = 0
for hook in hooks:
retval |= _run_single_hook(
Expand Down
7 changes: 5 additions & 2 deletions pre_commit/meta_hooks/check_hooks_apply.py
Expand Up @@ -11,10 +11,13 @@


def check_all_hooks_match_files(config_file: str) -> int:
classifier = Classifier(git.get_all_files())
config = load_config(config_file)
classifier = Classifier.from_config(
git.get_all_files(), config['files'], config['exclude'],
)
retv = 0

for hook in all_hooks(load_config(config_file), Store()):
for hook in all_hooks(config, Store()):
if hook.always_run or hook.language == 'fail':
continue
elif not classifier.filenames_for_hook(hook):
Expand Down
7 changes: 5 additions & 2 deletions pre_commit/meta_hooks/check_useless_excludes.py
Expand Up @@ -28,11 +28,14 @@ def exclude_matches_any(

def check_useless_excludes(config_file: str) -> int:
config = load_config(config_file)
classifier = Classifier(git.get_all_files())
filenames = git.get_all_files()
classifier = Classifier.from_config(
filenames, config['files'], config['exclude'],
)
retv = 0

exclude = config['exclude']
if not exclude_matches_any(classifier.filenames, '', exclude):
if not exclude_matches_any(filenames, '', exclude):
print(
f'The global exclude pattern {exclude!r} does not match any files',
)
Expand Down
4 changes: 2 additions & 2 deletions tests/commands/run_test.py
Expand Up @@ -939,15 +939,15 @@ def test_classifier_normalizes_filenames_on_windows_to_forward_slashes(tmpdir):
tmpdir.join('a/b/c').ensure()
with mock.patch.object(os, 'altsep', '/'):
with mock.patch.object(os, 'sep', '\\'):
classifier = Classifier((r'a\b\c',))
classifier = Classifier.from_config((r'a\b\c',), '', '^$')
assert classifier.filenames == ['a/b/c']


def test_classifier_does_not_normalize_backslashes_non_windows(tmpdir):
with mock.patch.object(os.path, 'lexists', return_value=True):
with mock.patch.object(os, 'altsep', None):
with mock.patch.object(os, 'sep', '/'):
classifier = Classifier((r'a/b\c',))
classifier = Classifier.from_config((r'a/b\c',), '', '^$')
assert classifier.filenames == [r'a/b\c']


Expand Down