Refs #29973 -- Extracted helper functions from makemessages.
This commit is contained in:
parent
16454ac35f
commit
bc9f0b3203
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue