Fix converting relative URLs in CSS files when DEBUG=True

This commit is contained in:
Mike Yumatov
2011-05-06 02:46:26 +04:00
parent 376e0f06e3
commit 88c6d67683
5 changed files with 52 additions and 33 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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

View File

@@ -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 = {