summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsiemens <ryanjsiemens@gmail.com>2019-01-27 11:30:06 -0800
committerTim Graham <timograham@gmail.com>2019-01-28 18:23:41 -0500
commitbc9f0b32039325e96683e0e4a3ea84428a336c8d (patch)
treebc37951a5330572a3d32dc5eb05522d38b69870e
parent16454ac35f6a24a04b23a9340b0d62c33edbc1ea (diff)
Refs #29973 -- Extracted helper functions from makemessages.
-rw-r--r--django/core/management/commands/makemessages.py29
-rw-r--r--django/core/management/utils.py30
-rw-r--r--tests/user_commands/tests.py25
3 files changed, 57 insertions, 27 deletions
diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py
index 2d0227b493..6fc2028688 100644
--- a/django/core/management/commands/makemessages.py
+++ b/django/core/management/commands/makemessages.py
@@ -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:
diff --git a/django/core/management/utils.py b/django/core/management/utils.py
index d2b85c986f..c7580c1931 100644
--- a/django/core/management/utils.py
+++ b/django/core/management/utils.py
@@ -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))
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index 45fe0aaf46..25ab82baed 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -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)