86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
from django.core.exceptions import ImproperlyConfigured
|
|
|
|
from jinja2 import nodes
|
|
from jinja2.ext import Extension
|
|
from jinja2.exceptions import TemplateSyntaxError
|
|
|
|
from compressor.conf import settings
|
|
from compressor.utils import get_class
|
|
from compressor.templatetags.compress import OUTPUT_FILE
|
|
from compressor.cache import (cache_get, cache_set,
|
|
get_templatetag_cachekey)
|
|
|
|
|
|
class CompressorExtension(Extension):
|
|
|
|
tags = set(['compress'])
|
|
|
|
@property
|
|
def compressors(self):
|
|
return {
|
|
'js': settings.COMPRESS_JS_COMPRESSOR,
|
|
'css': settings.COMPRESS_CSS_COMPRESSOR,
|
|
}
|
|
|
|
def parse(self, parser):
|
|
lineno = parser.stream.next().lineno
|
|
kindarg = parser.parse_expression()
|
|
# Allow kind to be defined as jinja2 name node
|
|
if isinstance(kindarg, nodes.Name):
|
|
kindarg = nodes.Const(kindarg.name)
|
|
args = [kindarg]
|
|
if args[0].value not in self.compressors:
|
|
raise TemplateSyntaxError('compress kind may be one of: %s' %
|
|
(', '.join(self.compressors.keys())),
|
|
lineno)
|
|
if parser.stream.skip_if('comma'):
|
|
modearg = parser.parse_expression()
|
|
# Allow mode to be defined as jinja2 name node
|
|
if isinstance(modearg, nodes.Name):
|
|
modearg = nodes.Const(modearg.name)
|
|
args.append(modearg)
|
|
else:
|
|
args.append(nodes.Const('file'))
|
|
body = parser.parse_statements(['name:endcompress'], drop_needle=True)
|
|
return nodes.CallBlock(self.call_method('_compress', args), [], [],
|
|
body).set_lineno(lineno)
|
|
|
|
def _compress(self, kind, mode, caller):
|
|
mode = mode or OUTPUT_FILE
|
|
Compressor = get_class(self.compressors.get(kind),
|
|
exception=ImproperlyConfigured)
|
|
original_content = caller()
|
|
compressor = Compressor(original_content)
|
|
# This extension assumes that we won't force compression
|
|
forced = False
|
|
|
|
# Prepare the actual compressor and check cache
|
|
cache_key, cache_content = self.render_cached(kind, mode, compressor,
|
|
forced)
|
|
if cache_content is not None:
|
|
return cache_content
|
|
|
|
# call compressor output method and handle exceptions
|
|
try:
|
|
rendered_output = compressor.output(mode, forced)
|
|
if cache_key:
|
|
cache_set(cache_key, rendered_output)
|
|
return rendered_output
|
|
except Exception, e:
|
|
if settings.DEBUG:
|
|
raise e
|
|
|
|
# Or don't do anything in production
|
|
return original_content
|
|
|
|
def render_cached(self, kind, mode, compressor, forced):
|
|
"""
|
|
If enabled checks the cache for the given compressor's cache key
|
|
and return a tuple of cache key and output
|
|
"""
|
|
if settings.COMPRESS_ENABLED and not forced:
|
|
cache_key = get_templatetag_cachekey(compressor, mode, kind)
|
|
cache_content = cache_get(cache_key)
|
|
return cache_key, cache_content
|
|
return None, None
|