Hashes and creates files now.

This commit is contained in:
xian
2009-04-27 19:09:48 -05:00
parent 951430ae10
commit ae6f003e7a
8 changed files with 124 additions and 22 deletions

View File

@@ -5,6 +5,7 @@ from django.conf import settings
MEDIA_URL = getattr(settings, 'COMPRESS_URL', settings.MEDIA_URL)
MEDIA_ROOT = getattr(settings, 'COMPRESS_ROOT', settings.MEDIA_ROOT)
PREFIX = getattr(settings, 'COMPRESS_PREFIX', 'compressed')
OUTPUT_DIR = getattr(settings, 'COMPRESS_OUTPUT_DIR', 'COMPRESSOR_CACHE')
COMPRESS = getattr(settings, 'COMPRESS', not settings.DEBUG)
COMPRESS_CSS_FILTERS = getattr(settings, 'COMPRESS_CSS_FILTERS', [])

View File

@@ -1,5 +1,5 @@
class FilterBase:
def __init__(self, verbose):
def __init__(self, verbose=0):
self.verbose = verbose
def filter_css(self, css):
@@ -11,4 +11,33 @@ class FilterError(Exception):
"""
This exception is raised when a filter fails
"""
pass
pass
def get_class(class_string):
"""
Convert a string version of a function name to the callable object.
"""
if not hasattr(class_string, '__bases__'):
try:
class_string = class_string.encode('ascii')
mod_name, class_name = get_mod_func(class_string)
if class_name != '':
cls = getattr(__import__(mod_name, {}, {}, ['']), class_name)
except (ImportError, AttributeError):
raise FilterError('Failed to import filter %s' % class_string)
return cls
def get_mod_func(callback):
"""
Converts 'django.views.news.stories.story_detail' to
('django.views.news.stories', 'story_detail')
"""
try:
dot = callback.rindex('.')
except ValueError:
return callback, ''
return callback[:dot], callback[dot+1:]

View File

@@ -1,4 +1,4 @@
from compress.filters.jsmin.jsmin import jsmin
from compressor.filters.jsmin.jsmin import jsmin
from compressor.filters import FilterBase
class JSMinFilter(FilterBase):

View File

@@ -1 +1 @@
<link href="{{ url }}" rel="stylesheet" type="text/css"{% if media %} media="{{ media }}"{% endif %}{% if title %} title="{{ title|default:"all" }}"{% endif %}{% if charset %} charset="{{ charset }}"{% endif %} />
<link rel="stylesheet" href="{{ url }}" type="text/css"{% if media %} media="{{ media }}"{% endif %} charset="utf-8">

View File

@@ -1,8 +1,12 @@
import os
from hashlib import sha1 as hash
from BeautifulSoup import BeautifulSoup
from django import template
from django.template.loader import render_to_string
from compressor.conf import settings
from compressor import filters
register = template.Library()
@@ -12,7 +16,6 @@ class CompressedNode(template.Node):
def __init__(self, content, ouput_prefix="compressed"):
self.content = content
self.ouput_prefix = ouput_prefix
self.hunks = []
self.split_content = []
self.soup = BeautifulSoup(self.content)
@@ -33,30 +36,76 @@ class CompressedNode(template.Node):
return filename
def get_hunks(self):
if self.hunks:
return self.hunks
if getattr(self, '_hunks', ''):
return self._hunks
self._hunks = []
for k, v in self.split_contents():
if k == 'hunk':
self.hunks.append(v)
self._hunks.append(v)
if k == 'file':
fd = open(v, 'rb')
self.hunks.append(fd.read())
self._hunks.append(fd.read())
fd.close()
return self.hunks
return self._hunks
hunks = property(get_hunks)
def concat(self):
return "\n".join(self.get_hunks())
def get_output(self):
if getattr(self, '_output', ''):
return self._output
output = self.concat()
filter_method = getattr(self, 'filter_method', None)
if filter_method and self.filters:
for f in self.filters:
filter = getattr(filters.get_class(f)(), filter_method)
if callable(filter):
output = filter(output)
self._output = output
return self._output
output = property(get_output)
def get_hash(self):
return hash(self.output).hexdigest()[:12]
hash = property(get_hash)
def get_new_filepath(self):
filename = "".join([self.hash, self.extension])
filepath = "%s/%s/%s" % (settings.OUTPUT_DIR.strip('/'), self.ouput_prefix, filename)
return filepath
new_filepath = property(get_new_filepath)
def save_file(self):
filename = "%s/%s" % (settings.MEDIA_ROOT.rstrip('/'), self.new_filepath)
if os.path.exists(filename):
return False
dirname = os.path.dirname(filename)
if not os.path.exists(dirname):
os.makedirs(dirname)
fd = open(filename, 'wb+')
fd.write(self.output)
fd.close()
return True
def render(self):
if not settings.COMPRESS:
return self.content
return "fail"
url = "%s/%s" % (settings.MEDIA_URL.rstrip('/'), self.new_filepath)
self.save_file()
context = getattr(self, 'extra_context', {})
context['url'] = url
return render_to_string(self.template_name, context)
class CompressedCssNode(CompressedNode):
def __init__(self, content, ouput_prefix="css", media="all"):
self.media = media
self.extra_context = { 'media': media }
self.extension = ".css"
self.template_name = "compressor/css.html"
self.filters = settings.COMPRESS_CSS_FILTERS
self.filter_method = 'filter_css'
super(CompressedCssNode, self).__init__(content, ouput_prefix)
def split_contents(self):
@@ -74,6 +123,10 @@ class CompressedCssNode(CompressedNode):
class CompressedJsNode(CompressedNode):
def __init__(self, content, ouput_prefix="js"):
self.extension = ".js"
self.template_name = "compressor/js.html"
self.filters = settings.COMPRESS_JS_FILTERS
self.filter_method = 'filter_js'
super(CompressedJsNode, self).__init__(content, ouput_prefix)
def split_contents(self):

0
tests/__init__.py Normal file
View File

View File

@@ -14,14 +14,12 @@ class CompressedNodeTestCase(TestCase):
<style type="text/css" media="screen">p { border:5px solid green;}</style>
<link rel="stylesheet" href="/media/css/two.css" type="text/css" media="screen" charset="utf-8">
"""
self.css_output = '<link rel="stylesheet" href="/media/compressed/cssHASH.css" type="text/css" media="all" charset="utf-8">'
self.cssNode = CompressedCssNode(self.css)
self.js = """
<script src="/media/js/one.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">obj.value = "value";</script>
"""
self.js_output = '<script src="/media/compressed/jsHASH.js" charset="utf-8"></script>'
self.jsNode = CompressedJsNode(self.js)
def test_css_split(self):
@@ -34,18 +32,22 @@ class CompressedNodeTestCase(TestCase):
def test_css_hunks(self):
out = ['body { background:#990; }', u'p { border:5px solid green;}', 'body { color:#fff; }']
self.assertEqual(out, self.cssNode.get_hunks())
self.assertEqual(out, self.cssNode.hunks)
def test_css_concat(self):
def test_css_output(self):
out = u'body { background:#990; }\np { border:5px solid green;}\nbody { color:#fff; }'
self.assertEqual(out, self.cssNode.concat())
self.assertEqual(out, self.cssNode.output)
def test_css_return_if_off(self):
settings.COMPRESS = False
self.assertEqual(self.css, self.cssNode.render())
def test_css_hash(self):
self.assertEqual('f7c661b7a124', self.cssNode.hash)
def test_css_return_if_on(self):
self.assertEqual(self.css_output, self.cssNode.render())
output = u'<link rel="stylesheet" href="/media/COMPRESSOR_CACHE/css/f7c661b7a124.css" type="text/css" media="all" charset="utf-8">'
self.assertEqual(output, self.cssNode.render())
def test_js_split(self):
@@ -57,15 +59,33 @@ class CompressedNodeTestCase(TestCase):
def test_js_hunks(self):
out = ['obj = {};', u'obj.value = "value";']
self.assertEqual(out, self.jsNode.get_hunks())
self.assertEqual(out, self.jsNode.hunks)
def test_js_concat(self):
out = u'obj = {};\nobj.value = "value";'
self.assertEqual(out, self.jsNode.concat())
def test_js_output(self):
out = u'obj={};obj.value="value";'
self.assertEqual(out, self.jsNode.output)
def test_js_return_if_off(self):
settings.COMPRESS = False
self.assertEqual(self.js, self.jsNode.render())
def test_js_return_if_on(self):
self.assertEqual(self.js_output, self.jsNode.render())
output = u'<script type="text/javascript" src="/media/COMPRESSOR_CACHE/js/3f33b9146e12.js" charset="utf-8"></script>'
self.assertEqual(output, self.jsNode.render())
class CssAbsolutizingTestCase(TestCase):
def setUp(self):
settings.COMPRESS = True
self.css = """
<link rel="stylesheet" href="/media/css/backgrounded.css" type="text/css" media="screen" charset="utf-8">
"""
self.cssNode = CompressedCssNode(self.css)
def test_fail(self):
settings.COMPRESS = False
self.assertEqual(self.js, self.jsNode.render())

View File

@@ -3,7 +3,6 @@ from os.path import dirname, abspath, join
TEST_DIR = dirname(abspath(__file__))
DEBUG = True
XDADD = ""
ROOT_URLCONF = 'urls'
@@ -11,7 +10,7 @@ MEDIA_URL = '/media/'
MEDIA_ROOT = join(TEST_DIR, 'media')
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = 'django_inlines_tests.db'
DATABASE_NAME = 'django_compressor_tests.db'
INSTALLED_APPS = [
'core',