diff --git a/compressor/contrib/__init__.py b/compressor/contrib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compressor/contrib/jinja2ext.py b/compressor/contrib/jinja2ext.py new file mode 100644 index 0000000..ffd3f53 --- /dev/null +++ b/compressor/contrib/jinja2ext.py @@ -0,0 +1,78 @@ +from jinja2 import nodes +from jinja2.ext import Extension +from jinja2.exceptions import TemplateSyntaxError +from django.core.exceptions import ImproperlyConfigured +from compressor.conf import settings +from compressor.utils import get_class +from compressor.templatetags.compress import COMPRESSORS, OUTPUT_FILE +from compressor.cache import (cache_get, cache_set, + get_templatetag_cachekey) + + +class CompressorExtension(Extension): + + tags = set(['compress']) + + 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 COMPRESSORS: + raise TemplateSyntaxError('compress kind may be "css" or "js"', + 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(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 + +