Fix converting relative URLs in CSS files when DEBUG=True
This commit is contained in:
@@ -36,7 +36,7 @@ class Compressor(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_filename(self, url):
|
||||
def get_basename(self, url):
|
||||
try:
|
||||
base_url = self.storage.base_url
|
||||
except AttributeError:
|
||||
@@ -48,6 +48,9 @@ class Compressor(object):
|
||||
basename = url.replace(base_url, "", 1)
|
||||
# drop the querystring, which is used for non-compressed cache-busting.
|
||||
basename = basename.split("?", 1)[0]
|
||||
return basename
|
||||
|
||||
def get_filename(self, basename):
|
||||
# first try to find it with staticfiles (in debug mode)
|
||||
filename = None
|
||||
if settings.DEBUG and self.finders:
|
||||
@@ -76,7 +79,8 @@ class Compressor(object):
|
||||
@cached_property
|
||||
def mtimes(self):
|
||||
return [str(get_mtime(value))
|
||||
for kind, value, _ in self.split_contents() if kind == 'file']
|
||||
for kind, value, _, _ in self.split_contents()
|
||||
if kind == 'file']
|
||||
|
||||
@cached_property
|
||||
def cachekey(self):
|
||||
@@ -86,10 +90,11 @@ class Compressor(object):
|
||||
|
||||
@cached_property
|
||||
def hunks(self):
|
||||
for kind, value, elem in self.split_contents():
|
||||
for kind, value, basename, elem in self.split_contents():
|
||||
if kind == "hunk":
|
||||
yield unicode(self.filter(
|
||||
value, method="input", elem=elem, kind=kind))
|
||||
value, basename=basename, method="input", elem=elem,
|
||||
kind=kind))
|
||||
elif kind == "file":
|
||||
content = ""
|
||||
fd = open(value, 'rb')
|
||||
@@ -101,7 +106,8 @@ class Compressor(object):
|
||||
finally:
|
||||
fd.close()
|
||||
content = self.filter(content,
|
||||
method="input", filename=value, elem=elem, kind=kind)
|
||||
method="input", filename=value, basename=basename,
|
||||
elem=elem, kind=kind)
|
||||
attribs = self.parser.elem_attribs(elem)
|
||||
charset = attribs.get("charset", self.charset)
|
||||
yield unicode(content, charset)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
from compressor.conf import settings
|
||||
from compressor.base import Compressor
|
||||
from compressor.exceptions import UncompressableFileError
|
||||
@@ -22,13 +24,14 @@ class CssCompressor(Compressor):
|
||||
elem_attribs = self.parser.elem_attribs(elem)
|
||||
if elem_name == 'link' and elem_attribs['rel'] == 'stylesheet':
|
||||
try:
|
||||
filename = self.get_filename(elem_attribs['href'])
|
||||
data = ('file', filename, elem)
|
||||
basename = self.get_basename(elem_attribs['href'])
|
||||
filename = self.get_filename(basename)
|
||||
data = ('file', filename, basename, elem)
|
||||
except UncompressableFileError:
|
||||
if settings.DEBUG:
|
||||
raise
|
||||
elif elem_name == 'style':
|
||||
data = ('hunk', self.parser.elem_content(elem), elem)
|
||||
data = ('hunk', self.parser.elem_content(elem), None, elem)
|
||||
if data:
|
||||
self.split_content.append(data)
|
||||
media = elem_attribs.get('media', None)
|
||||
|
||||
@@ -5,18 +5,20 @@ import posixpath
|
||||
from compressor.cache import get_hashed_mtime
|
||||
from compressor.conf import settings
|
||||
from compressor.filters import FilterBase
|
||||
from compressor.utils import staticfiles
|
||||
|
||||
URL_PATTERN = re.compile(r'url\(([^\)]+)\)')
|
||||
|
||||
|
||||
class CssAbsoluteFilter(FilterBase):
|
||||
def input(self, filename=None, **kwargs):
|
||||
def input(self, filename=None, basename=None, **kwargs):
|
||||
self.root = os.path.normcase(os.path.abspath(settings.COMPRESS_ROOT))
|
||||
if filename is not None:
|
||||
filename = os.path.normcase(os.path.abspath(filename))
|
||||
if not filename or not filename.startswith(self.root):
|
||||
if not (filename and filename.startswith(self.root)) and \
|
||||
not self.find(basename):
|
||||
return self.content
|
||||
self.path = filename[len(self.root):].replace(os.sep, '/')
|
||||
self.path = basename.replace(os.sep, '/')
|
||||
self.path = self.path.lstrip('/')
|
||||
self.url = settings.COMPRESS_URL.rstrip('/')
|
||||
self.url_path = self.url
|
||||
@@ -36,6 +38,10 @@ class CssAbsoluteFilter(FilterBase):
|
||||
output = URL_PATTERN.sub(self.url_converter, self.content)
|
||||
return output
|
||||
|
||||
def find(self, basename):
|
||||
if settings.DEBUG and basename and staticfiles.finders:
|
||||
return staticfiles.finders.find(basename)
|
||||
|
||||
def guess_filename(self, url):
|
||||
local_path = url
|
||||
if self.has_http:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
from compressor.conf import settings
|
||||
from compressor.base import Compressor
|
||||
from compressor.exceptions import UncompressableFileError
|
||||
@@ -19,12 +21,14 @@ class JsCompressor(Compressor):
|
||||
attribs = self.parser.elem_attribs(elem)
|
||||
if 'src' in attribs:
|
||||
try:
|
||||
basename = self.get_basename(attribs['src'])
|
||||
filename = self.get_filename(basename)
|
||||
self.split_content.append(
|
||||
('file', self.get_filename(attribs['src']), elem))
|
||||
('file', filename, basename, elem))
|
||||
except UncompressableFileError:
|
||||
if settings.DEBUG:
|
||||
raise
|
||||
else:
|
||||
content = self.parser.elem_content(elem)
|
||||
self.split_content.append(('hunk', content, elem))
|
||||
self.split_content.append(('hunk', content, None, elem))
|
||||
return self.split_content
|
||||
|
||||
@@ -55,12 +55,12 @@ class CompressorTestCase(TestCase):
|
||||
|
||||
def test_css_split(self):
|
||||
out = [
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/one.css'), u'<link rel="stylesheet" href="/media/css/one.css" type="text/css" charset="utf-8" />'),
|
||||
('hunk', u'p { border:5px solid green;}', u'<style type="text/css">p { border:5px solid green;}</style>'),
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/two.css'), u'<link rel="stylesheet" href="/media/css/two.css" type="text/css" charset="utf-8" />'),
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/one.css'), u'css/one.css', u'<link rel="stylesheet" href="/media/css/one.css" type="text/css" charset="utf-8" />'),
|
||||
('hunk', u'p { border:5px solid green;}', None, u'<style type="text/css">p { border:5px solid green;}</style>'),
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/two.css'), u'css/two.css', u'<link rel="stylesheet" href="/media/css/two.css" type="text/css" charset="utf-8" />'),
|
||||
]
|
||||
split = self.css_node.split_contents()
|
||||
split = [(x[0], x[1], self.css_node.parser.elem_str(x[2])) for x in split]
|
||||
split = [(x[0], x[1], x[2], self.css_node.parser.elem_str(x[3])) for x in split]
|
||||
self.assertEqual(out, split)
|
||||
|
||||
def test_css_hunks(self):
|
||||
@@ -93,11 +93,11 @@ class CompressorTestCase(TestCase):
|
||||
self.assertEqual(output, self.css_node.output().strip())
|
||||
|
||||
def test_js_split(self):
|
||||
out = [('file', os.path.join(settings.COMPRESS_ROOT, u'js/one.js'), '<script src="/media/js/one.js" type="text/javascript" charset="utf-8"></script>'),
|
||||
('hunk', u'obj.value = "value";', '<script type="text/javascript" charset="utf-8">obj.value = "value";</script>')
|
||||
out = [('file', os.path.join(settings.COMPRESS_ROOT, u'js/one.js'), u'js/one.js', '<script src="/media/js/one.js" type="text/javascript" charset="utf-8"></script>'),
|
||||
('hunk', u'obj.value = "value";', None, '<script type="text/javascript" charset="utf-8">obj.value = "value";</script>')
|
||||
]
|
||||
split = self.js_node.split_contents()
|
||||
split = [(x[0], x[1], self.js_node.parser.elem_str(x[2])) for x in split]
|
||||
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3])) for x in split]
|
||||
self.assertEqual(out, split)
|
||||
|
||||
def test_js_hunks(self):
|
||||
@@ -164,20 +164,20 @@ class Html5LibParserTests(ParserTestCase, CompressorTestCase):
|
||||
|
||||
def test_css_split(self):
|
||||
out = [
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/one.css'), u'<link charset="utf-8" href="/media/css/one.css" rel="stylesheet" type="text/css">'),
|
||||
('hunk', u'p { border:5px solid green;}', u'<style type="text/css">p { border:5px solid green;}</style>'),
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/two.css'), u'<link charset="utf-8" href="/media/css/two.css" rel="stylesheet" type="text/css">'),
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/one.css'), u'css/one.css', u'<link charset="utf-8" href="/media/css/one.css" rel="stylesheet" type="text/css">'),
|
||||
('hunk', u'p { border:5px solid green;}', None, u'<style type="text/css">p { border:5px solid green;}</style>'),
|
||||
('file', os.path.join(settings.COMPRESS_ROOT, u'css/two.css'), u'css/two.css', u'<link charset="utf-8" href="/media/css/two.css" rel="stylesheet" type="text/css">'),
|
||||
]
|
||||
split = self.css_node.split_contents()
|
||||
split = [(x[0], x[1], self.css_node.parser.elem_str(x[2])) for x in split]
|
||||
split = [(x[0], x[1], x[2], self.css_node.parser.elem_str(x[3])) for x in split]
|
||||
self.assertEqual(out, split)
|
||||
|
||||
def test_js_split(self):
|
||||
out = [('file', os.path.join(settings.COMPRESS_ROOT, u'js/one.js'), u'<script charset="utf-8" src="/media/js/one.js" type="text/javascript"></script>'),
|
||||
('hunk', u'obj.value = "value";', u'<script charset="utf-8" type="text/javascript">obj.value = "value";</script>')
|
||||
out = [('file', os.path.join(settings.COMPRESS_ROOT, u'js/one.js'), u'js/one.js', u'<script charset="utf-8" src="/media/js/one.js" type="text/javascript"></script>'),
|
||||
('hunk', u'obj.value = "value";', None, u'<script charset="utf-8" type="text/javascript">obj.value = "value";</script>')
|
||||
]
|
||||
split = self.js_node.split_contents()
|
||||
split = [(x[0], x[1], self.js_node.parser.elem_str(x[2])) for x in split]
|
||||
split = [(x[0], x[1], x[2], self.js_node.parser.elem_str(x[3])) for x in split]
|
||||
self.assertEqual(out, split)
|
||||
|
||||
Html5LibParserTests = skipIf(
|
||||
@@ -211,11 +211,11 @@ class CssAbsolutizingTestCase(TestCase):
|
||||
content = "p { background: url('../../images/image.gif') }"
|
||||
output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename))
|
||||
filter = CssAbsoluteFilter(content)
|
||||
self.assertEqual(output, filter.input(filename=filename))
|
||||
self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css'))
|
||||
settings.COMPRESS_URL = 'http://media.example.com/'
|
||||
filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css')
|
||||
output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename))
|
||||
self.assertEqual(output, filter.input(filename=filename))
|
||||
self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css'))
|
||||
|
||||
def test_css_absolute_filter_https(self):
|
||||
from compressor.filters.css_default import CssAbsoluteFilter
|
||||
@@ -223,11 +223,11 @@ class CssAbsolutizingTestCase(TestCase):
|
||||
content = "p { background: url('../../images/image.gif') }"
|
||||
output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename))
|
||||
filter = CssAbsoluteFilter(content)
|
||||
self.assertEqual(output, filter.input(filename=filename))
|
||||
self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css'))
|
||||
settings.COMPRESS_URL = 'https://media.example.com/'
|
||||
filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css')
|
||||
output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename))
|
||||
self.assertEqual(output, filter.input(filename=filename))
|
||||
self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css'))
|
||||
|
||||
def test_css_absolute_filter_relative_path(self):
|
||||
from compressor.filters.css_default import CssAbsoluteFilter
|
||||
@@ -235,10 +235,10 @@ class CssAbsolutizingTestCase(TestCase):
|
||||
content = "p { background: url('../../images/image.gif') }"
|
||||
output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename))
|
||||
filter = CssAbsoluteFilter(content)
|
||||
self.assertEqual(output, filter.input(filename=filename))
|
||||
self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css'))
|
||||
settings.COMPRESS_URL = 'https://media.example.com/'
|
||||
output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename))
|
||||
self.assertEqual(output, filter.input(filename=filename))
|
||||
self.assertEqual(output, filter.input(filename=filename, basename='css/url/test.css'))
|
||||
|
||||
def test_css_hunks(self):
|
||||
hash_dict = {
|
||||
|
||||
Reference in New Issue
Block a user