Browse Source

Fixed #19670 -- Applied CachedFilesMixin patterns to specific extensions

Thanks Simon Meers for the initial patch, and Tim Graham for the review.
Claude Paroz 9 years ago
parent
commit
edcecaf0de

+ 1 - 0
.gitattributes

@@ -1,6 +1,7 @@
 # Normalize line endings to avoid spurious failures in the core test suite on Windows.
 *html text eol=lf
 *css text eol=lf
+*js text eol=lf
 tests/staticfiles_tests/apps/test/static/test/*txt text eol=lf
 tests/staticfiles_tests/project/documents/test/*txt text eol=lf
 docs/releases/*.txt merge=union

+ 9 - 7
django/contrib/staticfiles/storage.py

@@ -17,6 +17,7 @@ from django.core.files.base import ContentFile
 from django.core.files.storage import FileSystemStorage, get_storage_class
 from django.utils.encoding import force_bytes, force_text
 from django.utils.functional import LazyObject
+from django.utils.six import iteritems
 from django.utils.six.moves.urllib.parse import (
     unquote, urldefrag, urlsplit, urlunsplit,
 )
@@ -248,13 +249,14 @@ class HashedFilesMixin(object):
                 # ..to apply each replacement pattern to the content
                 if name in adjustable_paths:
                     content = original_file.read().decode(settings.FILE_CHARSET)
-                    for patterns in self._patterns.values():
-                        for pattern, template in patterns:
-                            converter = self.url_converter(name, template)
-                            try:
-                                content = pattern.sub(converter, content)
-                            except ValueError as exc:
-                                yield name, None, exc
+                    for extension, patterns in iteritems(self._patterns):
+                        if matches_patterns(path, (extension,)):
+                            for pattern, template in patterns:
+                                converter = self.url_converter(name, template)
+                                try:
+                                    content = pattern.sub(converter, content)
+                                except ValueError as exc:
+                                    yield name, None, exc
                     if hashed_file_exists:
                         self.delete(hashed_name)
                     # then save the processed result

+ 1 - 0
tests/staticfiles_tests/project/documents/cached/test.js

@@ -0,0 +1 @@
+myVar = url("import.css");

+ 14 - 0
tests/staticfiles_tests/storage.py

@@ -63,3 +63,17 @@ class SimpleCachedStaticFilesStorage(CachedStaticFilesStorage):
 
     def file_hash(self, name, content=None):
         return 'deploy12345'
+
+
+class ExtraPatternsCachedStaticFilesStorage(CachedStaticFilesStorage):
+    """
+    A storage class to test pattern substitutions with more than one pattern
+    entry. The added pattern rewrites strings like "url(...)" to JS_URL("...").
+    """
+    patterns = tuple(CachedStaticFilesStorage.patterns) + (
+        (
+            "*.js", (
+                (r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""", 'JS_URL("%s")'),
+            ),
+        ),
+    )

+ 36 - 0
tests/staticfiles_tests/test_storage.py

@@ -237,6 +237,38 @@ class TestCollectionCachedStorage(TestHashedFiles, CollectionTestCase):
         self.assertEqual(cache_key, 'staticfiles:821ea71ef36f95b3922a77f7364670e7')
 
 
+@override_settings(
+    STATICFILES_STORAGE='staticfiles_tests.storage.ExtraPatternsCachedStaticFilesStorage',
+)
+class TestExtraPatternsCachedStorage(CollectionTestCase):
+
+    def setUp(self):
+        storage.staticfiles_storage.hashed_files.clear()  # avoid cache interference
+        super(TestExtraPatternsCachedStorage, self).setUp()
+
+    def cached_file_path(self, path):
+        fullpath = self.render_template(self.static_template_snippet(path))
+        return fullpath.replace(settings.STATIC_URL, '')
+
+    def test_multi_extension_patterns(self):
+        """
+        With storage classes having several file extension patterns, only the
+        files matching a specific file pattern should be affected by the
+        substitution (#19670).
+        """
+        # CSS files shouldn't be touched by JS patterns.
+        relpath = self.cached_file_path("cached/import.css")
+        self.assertEqual(relpath, "cached/import.2b1d40b0bbd4.css")
+        with storage.staticfiles_storage.open(relpath) as relfile:
+            self.assertIn(b'import url("styles.bb84a0240107.css")', relfile.read())
+
+        # Confirm JS patterns have been applied to JS files.
+        relpath = self.cached_file_path("cached/test.js")
+        self.assertEqual(relpath, "cached/test.62789ffcd280.js")
+        with storage.staticfiles_storage.open(relpath) as relfile:
+            self.assertIn(b'JS_URL("import.2b1d40b0bbd4.css")', relfile.read())
+
+
 @override_settings(
     STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage',
 )
@@ -320,6 +352,10 @@ class TestCollectionSimpleCachedStorage(CollectionTestCase):
     """
     hashed_file_path = hashed_file_path
 
+    def setUp(self):
+        storage.staticfiles_storage.hashed_files.clear()  # avoid cache interference
+        super(TestCollectionSimpleCachedStorage, self).setUp()
+
     def test_template_tag_return(self):
         """
         Test the CachedStaticFilesStorage backend.