Refs #29973 -- Extracted helper functions from makemessages.

This commit is contained in:
rsiemens 2019-01-27 11:30:06 -08:00 committed by Tim Graham
parent 16454ac35f
commit bc9f0b3203
3 changed files with 57 additions and 27 deletions

View File

@ -1,4 +1,3 @@
import fnmatch
import glob
import os
import re
@ -12,7 +11,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.core.files.temp import NamedTemporaryFile
from django.core.management.base import BaseCommand, CommandError
from django.core.management.utils import (
find_command, handle_extensions, popen_wrapper,
find_command, handle_extensions, is_ignored_path, popen_wrapper,
)
from django.utils.encoding import DEFAULT_LOCALE_ENCODING
from django.utils.functional import cached_property
@ -454,35 +453,13 @@ class Command(BaseCommand):
Get all files in the given root. Also check that there is a matching
locale dir for each file.
"""
def is_ignored(path, ignore_patterns):
"""
Check if the given path should be ignored or not.
"""
filename = os.path.basename(path)
def ignore(pattern):
return fnmatch.fnmatchcase(filename, pattern) or fnmatch.fnmatchcase(path, pattern)
return any(ignore(pattern) for pattern in ignore_patterns)
ignore_patterns = [os.path.normcase(p) for p in self.ignore_patterns]
dir_suffixes = {'%s*' % path_sep for path_sep in {'/', os.sep}}
norm_patterns = []
for p in ignore_patterns:
for dir_suffix in dir_suffixes:
if p.endswith(dir_suffix):
norm_patterns.append(p[:-len(dir_suffix)])
break
else:
norm_patterns.append(p)
all_files = []
ignored_roots = []
if self.settings_available:
ignored_roots = [os.path.normpath(p) for p in (settings.MEDIA_ROOT, settings.STATIC_ROOT) if p]
for dirpath, dirnames, filenames in os.walk(root, topdown=True, followlinks=self.symlinks):
for dirname in dirnames[:]:
if (is_ignored(os.path.normpath(os.path.join(dirpath, dirname)), norm_patterns) or
if (is_ignored_path(os.path.normpath(os.path.join(dirpath, dirname)), self.ignore_patterns) or
os.path.join(os.path.abspath(dirpath), dirname) in ignored_roots):
dirnames.remove(dirname)
if self.verbosity > 1:
@ -493,7 +470,7 @@ class Command(BaseCommand):
for filename in filenames:
file_path = os.path.normpath(os.path.join(dirpath, filename))
file_ext = os.path.splitext(filename)[1]
if file_ext not in self.extensions or is_ignored(file_path, self.ignore_patterns):
if file_ext not in self.extensions or is_ignored_path(file_path, self.ignore_patterns):
if self.verbosity > 1:
self.stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
else:

View File

@ -1,4 +1,6 @@
import fnmatch
import os
from pathlib import Path
from subprocess import PIPE, Popen
from django.apps import apps as installed_apps
@ -122,3 +124,31 @@ def get_command_line_option(argv, option):
return None
else:
return options.value
def normalize_path_patterns(patterns):
"""Normalize an iterable of glob style patterns based on OS."""
patterns = [os.path.normcase(p) for p in patterns]
dir_suffixes = {'%s*' % path_sep for path_sep in {'/', os.sep}}
norm_patterns = []
for pattern in patterns:
for dir_suffix in dir_suffixes:
if pattern.endswith(dir_suffix):
norm_patterns.append(pattern[:-len(dir_suffix)])
break
else:
norm_patterns.append(pattern)
return norm_patterns
def is_ignored_path(path, ignore_patterns):
"""
Check if the given path should be ignored or not based on matching
one of the glob style `ignore_patterns`.
"""
path = Path(path)
def ignore(pattern):
return fnmatch.fnmatchcase(path.name, pattern) or fnmatch.fnmatchcase(str(path), pattern)
return any(ignore(pattern) for pattern in normalize_path_patterns(ignore_patterns))

View File

@ -8,7 +8,8 @@ from django.apps import apps
from django.core import management
from django.core.management import BaseCommand, CommandError, find_commands
from django.core.management.utils import (
find_command, get_random_secret_key, popen_wrapper,
find_command, get_random_secret_key, is_ignored_path,
normalize_path_patterns, popen_wrapper,
)
from django.db import connection
from django.test import SimpleTestCase, override_settings
@ -268,3 +269,25 @@ class UtilsTests(SimpleTestCase):
self.assertEqual(len(key), 50)
for char in key:
self.assertIn(char, 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)')
def test_is_ignored_path_true(self):
patterns = (
['foo/bar/baz'],
['baz'],
['foo/bar/baz'],
['*/baz'],
['*'],
['b?z'],
['[abc]az'],
['*/ba[!z]/baz'],
)
for ignore_patterns in patterns:
with self.subTest(ignore_patterns=ignore_patterns):
self.assertIs(is_ignored_path('foo/bar/baz', ignore_patterns=ignore_patterns), True)
def test_is_ignored_path_false(self):
self.assertIs(is_ignored_path('foo/bar/baz', ignore_patterns=['foo/bar/bat', 'bar', 'flub/blub']), False)
def test_normalize_path_patterns_truncates_wildcard_base(self):
expected = [os.path.normcase(p) for p in ['foo/bar', 'bar/*/']]
self.assertEqual(normalize_path_patterns(['foo/bar/*', 'bar/*/']), expected)