From 3047981517ffa0c75c97f05446bd0d41865e323b Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Sun, 8 Jul 2012 18:17:53 +0200 Subject: [PATCH] Fixed #18050 -- Fixed a rather glaring bug in the handling of @import statements when using the cached staticfiles storage. --- django/contrib/staticfiles/storage.py | 21 +++++++++++++------ .../project/documents/cached/import.css | 1 + .../staticfiles_tests/tests.py | 7 +++++++ 3 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 tests/regressiontests/staticfiles_tests/project/documents/cached/import.css diff --git a/django/contrib/staticfiles/storage.py b/django/contrib/staticfiles/storage.py index 16d33fff4b1..4a6650b193f 100644 --- a/django/contrib/staticfiles/storage.py +++ b/django/contrib/staticfiles/storage.py @@ -45,10 +45,11 @@ class StaticFilesStorage(FileSystemStorage): class CachedFilesMixin(object): + default_template = """url("%s")""" patterns = ( ("*.css", ( br"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""", - br"""(@import\s*["']\s*(.*?)["'])""", + (br"""(@import\s*["']\s*(.*?)["'])""", """@import url("%s")"""), )), ) @@ -62,8 +63,12 @@ class CachedFilesMixin(object): self._patterns = SortedDict() for extension, patterns in self.patterns: for pattern in patterns: + if isinstance(pattern, (tuple, list)): + pattern, template = pattern + else: + template = self.default_template compiled = re.compile(pattern) - self._patterns.setdefault(extension, []).append(compiled) + self._patterns.setdefault(extension, []).append((compiled, template)) def file_hash(self, name, content=None): """ @@ -140,10 +145,13 @@ class CachedFilesMixin(object): return unquote(final_url) - def url_converter(self, name): + def url_converter(self, name, template=None): """ Returns the custom URL converter for the given file name. """ + if template is None: + template = self.default_template + def converter(matchobj): """ Converts the matched URL depending on the parent level (`..`) @@ -178,7 +186,8 @@ class CachedFilesMixin(object): relative_url = '/'.join(url.split('/')[:-1] + file_name) # Return the hashed version to the file - return 'url("%s")' % unquote(relative_url) + return template % unquote(relative_url) + return converter def post_process(self, paths, dry_run=False, **options): @@ -229,9 +238,9 @@ class CachedFilesMixin(object): # ..to apply each replacement pattern to the content if name in adjustable_paths: content = original_file.read().decode(settings.FILE_CHARSET) - converter = self.url_converter(name) for patterns in self._patterns.values(): - for pattern in patterns: + for pattern, template in patterns: + converter = self.url_converter(name, template) content = pattern.sub(converter, content) if hashed_file_exists: self.delete(hashed_name) diff --git a/tests/regressiontests/staticfiles_tests/project/documents/cached/import.css b/tests/regressiontests/staticfiles_tests/project/documents/cached/import.css new file mode 100644 index 00000000000..6bc7ce04c48 --- /dev/null +++ b/tests/regressiontests/staticfiles_tests/project/documents/cached/import.css @@ -0,0 +1 @@ +@import 'styles.css'; diff --git a/tests/regressiontests/staticfiles_tests/tests.py b/tests/regressiontests/staticfiles_tests/tests.py index 91435a2c86e..9b14c78dc52 100644 --- a/tests/regressiontests/staticfiles_tests/tests.py +++ b/tests/regressiontests/staticfiles_tests/tests.py @@ -446,6 +446,13 @@ class TestCollectionCachedStorage(BaseCollectionTestCase, self.assertIn(b'url("img/relative.acae32e4532b.png")', content) self.assertIn(b"../cached/styles.93b1147e8552.css", content) + def test_import_replacement(self): + "See #18050" + 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.93b1147e8552.css")""", relfile.read()) + def test_template_tag_deep_relative(self): relpath = self.cached_file_path("cached/css/window.css") self.assertEqual(relpath, "cached/css/window.9db38d5169f3.css")