Skip to content

Commit edcecaf

Browse files
committed
Fixed #19670 -- Applied CachedFilesMixin patterns to specific extensions
Thanks Simon Meers for the initial patch, and Tim Graham for the review.
1 parent 940b7fd commit edcecaf

File tree

5 files changed

+61
-7
lines changed

5 files changed

+61
-7
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Normalize line endings to avoid spurious failures in the core test suite on Windows.
22
*html text eol=lf
33
*css text eol=lf
4+
*js text eol=lf
45
tests/staticfiles_tests/apps/test/static/test/*txt text eol=lf
56
tests/staticfiles_tests/project/documents/test/*txt text eol=lf
67
docs/releases/*.txt merge=union

django/contrib/staticfiles/storage.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from django.core.files.storage import FileSystemStorage, get_storage_class
1818
from django.utils.encoding import force_bytes, force_text
1919
from django.utils.functional import LazyObject
20+
from django.utils.six import iteritems
2021
from django.utils.six.moves.urllib.parse import (
2122
unquote, urldefrag, urlsplit, urlunsplit,
2223
)
@@ -248,13 +249,14 @@ def path_level(name):
248249
# ..to apply each replacement pattern to the content
249250
if name in adjustable_paths:
250251
content = original_file.read().decode(settings.FILE_CHARSET)
251-
for patterns in self._patterns.values():
252-
for pattern, template in patterns:
253-
converter = self.url_converter(name, template)
254-
try:
255-
content = pattern.sub(converter, content)
256-
except ValueError as exc:
257-
yield name, None, exc
252+
for extension, patterns in iteritems(self._patterns):
253+
if matches_patterns(path, (extension,)):
254+
for pattern, template in patterns:
255+
converter = self.url_converter(name, template)
256+
try:
257+
content = pattern.sub(converter, content)
258+
except ValueError as exc:
259+
yield name, None, exc
258260
if hashed_file_exists:
259261
self.delete(hashed_name)
260262
# then save the processed result
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
myVar = url("import.css");

tests/staticfiles_tests/storage.py

+14
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,17 @@ class SimpleCachedStaticFilesStorage(CachedStaticFilesStorage):
6363

6464
def file_hash(self, name, content=None):
6565
return 'deploy12345'
66+
67+
68+
class ExtraPatternsCachedStaticFilesStorage(CachedStaticFilesStorage):
69+
"""
70+
A storage class to test pattern substitutions with more than one pattern
71+
entry. The added pattern rewrites strings like "url(...)" to JS_URL("...").
72+
"""
73+
patterns = tuple(CachedStaticFilesStorage.patterns) + (
74+
(
75+
"*.js", (
76+
(r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""", 'JS_URL("%s")'),
77+
),
78+
),
79+
)

tests/staticfiles_tests/test_storage.py

+36
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,38 @@ def test_cache_key_memcache_validation(self):
237237
self.assertEqual(cache_key, 'staticfiles:821ea71ef36f95b3922a77f7364670e7')
238238

239239

240+
@override_settings(
241+
STATICFILES_STORAGE='staticfiles_tests.storage.ExtraPatternsCachedStaticFilesStorage',
242+
)
243+
class TestExtraPatternsCachedStorage(CollectionTestCase):
244+
245+
def setUp(self):
246+
storage.staticfiles_storage.hashed_files.clear() # avoid cache interference
247+
super(TestExtraPatternsCachedStorage, self).setUp()
248+
249+
def cached_file_path(self, path):
250+
fullpath = self.render_template(self.static_template_snippet(path))
251+
return fullpath.replace(settings.STATIC_URL, '')
252+
253+
def test_multi_extension_patterns(self):
254+
"""
255+
With storage classes having several file extension patterns, only the
256+
files matching a specific file pattern should be affected by the
257+
substitution (#19670).
258+
"""
259+
# CSS files shouldn't be touched by JS patterns.
260+
relpath = self.cached_file_path("cached/import.css")
261+
self.assertEqual(relpath, "cached/import.2b1d40b0bbd4.css")
262+
with storage.staticfiles_storage.open(relpath) as relfile:
263+
self.assertIn(b'import url("styles.bb84a0240107.css")', relfile.read())
264+
265+
# Confirm JS patterns have been applied to JS files.
266+
relpath = self.cached_file_path("cached/test.js")
267+
self.assertEqual(relpath, "cached/test.62789ffcd280.js")
268+
with storage.staticfiles_storage.open(relpath) as relfile:
269+
self.assertIn(b'JS_URL("import.2b1d40b0bbd4.css")', relfile.read())
270+
271+
240272
@override_settings(
241273
STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage',
242274
)
@@ -320,6 +352,10 @@ class TestCollectionSimpleCachedStorage(CollectionTestCase):
320352
"""
321353
hashed_file_path = hashed_file_path
322354

355+
def setUp(self):
356+
storage.staticfiles_storage.hashed_files.clear() # avoid cache interference
357+
super(TestCollectionSimpleCachedStorage, self).setUp()
358+
323359
def test_template_tag_return(self):
324360
"""
325361
Test the CachedStaticFilesStorage backend.

0 commit comments

Comments
 (0)