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 glob
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -12,7 +11,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.files.temp import NamedTemporaryFile
|
from django.core.files.temp import NamedTemporaryFile
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.core.management.utils import (
|
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.encoding import DEFAULT_LOCALE_ENCODING
|
||||||
from django.utils.functional import cached_property
|
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
|
Get all files in the given root. Also check that there is a matching
|
||||||
locale dir for each file.
|
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 = []
|
all_files = []
|
||||||
ignored_roots = []
|
ignored_roots = []
|
||||||
if self.settings_available:
|
if self.settings_available:
|
||||||
ignored_roots = [os.path.normpath(p) for p in (settings.MEDIA_ROOT, settings.STATIC_ROOT) if p]
|
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 dirpath, dirnames, filenames in os.walk(root, topdown=True, followlinks=self.symlinks):
|
||||||
for dirname in dirnames[:]:
|
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):
|
os.path.join(os.path.abspath(dirpath), dirname) in ignored_roots):
|
||||||
dirnames.remove(dirname)
|
dirnames.remove(dirname)
|
||||||
if self.verbosity > 1:
|
if self.verbosity > 1:
|
||||||
|
@ -493,7 +470,7 @@ class Command(BaseCommand):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
file_path = os.path.normpath(os.path.join(dirpath, filename))
|
file_path = os.path.normpath(os.path.join(dirpath, filename))
|
||||||
file_ext = os.path.splitext(filename)[1]
|
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:
|
if self.verbosity > 1:
|
||||||
self.stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
|
self.stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
import fnmatch
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from subprocess import PIPE, Popen
|
from subprocess import PIPE, Popen
|
||||||
|
|
||||||
from django.apps import apps as installed_apps
|
from django.apps import apps as installed_apps
|
||||||
|
@ -122,3 +124,31 @@ def get_command_line_option(argv, option):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return options.value
|
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 import management
|
||||||
from django.core.management import BaseCommand, CommandError, find_commands
|
from django.core.management import BaseCommand, CommandError, find_commands
|
||||||
from django.core.management.utils import (
|
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.db import connection
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
|
@ -268,3 +269,25 @@ class UtilsTests(SimpleTestCase):
|
||||||
self.assertEqual(len(key), 50)
|
self.assertEqual(len(key), 50)
|
||||||
for char in key:
|
for char in key:
|
||||||
self.assertIn(char, 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)')
|
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