Permalink
Browse files

Merge branch 'release/0.6b7'

  • Loading branch information...
2 parents a057284 + 13a653b commit 0ab45f0ccbc809f94446f812c1649b50ac0559d4 @jezdez jezdez committed Apr 8, 2011
View
@@ -1,4 +1,4 @@
-VERSION = (0, 6, 0, "b", 6) # following PEP 386
+VERSION = (0, 6, 0, "b", 7) # following PEP 386
DEV_N = None
View
@@ -29,6 +29,7 @@ def __init__(self, content=None, output_prefix="compressed"):
self.storage = default_storage
self.split_content = []
self.extra_context = {}
+ self.all_mimetypes = dict(settings.COMPRESS_PRECOMPILERS)
def split_contents(self):
"""
@@ -105,12 +106,15 @@ def precompile(self, content, kind=None, elem=None, filename=None, **kwargs):
attrs = self.parser.elem_attribs(elem)
mimetype = attrs.get("type", None)
if mimetype is not None:
- for mimetypes, command in settings.COMPRESS_PRECOMPILERS:
- if not isinstance(mimetypes, (list, tuple)):
- mimetypes = (mimetypes,)
- if mimetype in mimetypes:
- content = CompilerFilter(content, filter_type=self.type,
- command=command).output(**kwargs)
+ command = self.all_mimetypes.get(mimetype)
+ if command is None:
+ if mimetype not in ("text/css", "text/javascript"):
+ raise CompressorError(
+ "Couldn't find any configured precompiler "
+ "for mimetype '%s'." % mimetype)
+ else:
+ content = CompilerFilter(content, filter_type=self.type,
+ command=command).output(**kwargs)
return content
def filter(self, content, method, **kwargs):
@@ -156,6 +160,9 @@ def output(self, mode='file', forced=False):
# or just doing nothing, when neither
# compression nor compilation is enabled
return self.content
+ # Shortcurcuit in case the content is empty.
+ if not content:
+ return ''
# Then check for the appropriate output method and call it
output_func = getattr(self, "output_%s" % mode, None)
if callable(output_func):
View
@@ -22,8 +22,8 @@ def split_contents(self):
elem_attribs = self.parser.elem_attribs(elem)
if elem_name == 'link' and elem_attribs['rel'] == 'stylesheet':
try:
- data = (
- 'file', self.get_filename(elem_attribs['href']), elem)
+ filename = self.get_filename(elem_attribs['href'])
+ data = ('file', filename, elem)
except UncompressableFileError:
if settings.DEBUG:
raise
@@ -43,13 +43,15 @@ def split_contents(self):
return self.split_content
def output(self, *args, **kwargs):
+ # Populate self.split_content
self.split_contents()
if not hasattr(self, 'media_nodes'):
return super(CssCompressor, self).output(*args, **kwargs)
- if settings.COMPRESS_ENABLED or kwargs.get('forced', False):
+ if (settings.COMPRESS_ENABLED or settings.COMPRESS_PRECOMPILERS or
+ kwargs.get('forced', False)):
ret = []
for media, subnode in self.media_nodes:
subnode.extra_context.update({'media': media})
ret.append(subnode.output(*args, **kwargs))
- return "".join(ret)
+ return ''.join(ret)
return self.content
@@ -38,25 +38,25 @@ def __init__(self, content, filter_type=None, verbose=0, command=None):
self.command = command
if self.command is None:
raise FilterError("Required command attribute not set")
+ self.options = {}
self.stdout = subprocess.PIPE
self.stdin = subprocess.PIPE
self.stderr = subprocess.PIPE
def output(self, **kwargs):
infile = None
outfile = None
- options = {}
try:
if "{infile}" in self.command:
infile = tempfile.NamedTemporaryFile(mode='w')
infile.write(self.content)
infile.flush()
- options["infile"] = infile.name
+ self.options["infile"] = infile.name
if "{outfile}" in self.command:
ext = ".%s" % self.type and self.type or ""
outfile = tempfile.NamedTemporaryFile(mode='w', suffix=ext)
- options["outfile"] = outfile.name
- cmd = FormattableString(self.command).format(**options)
+ self.options["outfile"] = outfile.name
+ cmd = FormattableString(self.command).format(**self.options)
proc = subprocess.Popen(cmd_split(cmd),
stdout=self.stdout, stdin=self.stdin, stderr=self.stderr)
if infile is not None:
@@ -3,7 +3,7 @@
class ClosureCompilerFilter(CompilerFilter):
- command = "%(binary)s %(args)s"
+ command = "{binary} {args}"
options = {
"binary": settings.COMPRESS_CLOSURE_COMPILER_ARGUMENTS,
"args": settings.COMPRESS_CLOSURE_COMPILER_ARGUMENTS,
@@ -3,7 +3,7 @@
class CSSTidyFilter(CompilerFilter):
- command = "%(binary)s %(infile)s %(args)s %(outfile)s"
+ command = "{binary} {infile} {args} {outfile}"
options = {
"binary": settings.COMPRESS_CSSTIDY_BINARY,
"args": settings.COMPRESS_CSSTIDY_ARGUMENTS,
@@ -3,7 +3,7 @@
class YUICompressorFilter(CompilerFilter):
- command = "%(binary)s %(args)s"
+ command = "{binary} {args}"
def __init__(self, *args, **kwargs):
super(YUICompressorFilter, self).__init__(*args, **kwargs)
@@ -55,9 +55,6 @@ def render(self, context, forced=False):
if content:
return content
content = self.nodelist.render(context)
- if (not settings.COMPRESS_ENABLED or
- not len(content.strip())) and not forced:
- return content
compressor = self.compressor_cls(content)
cachekey = self.cache_key(compressor)
output = self.cache_get(cachekey)
View
@@ -0,0 +1,47 @@
+Behind the scenes
+=================
+
+This document assumes you already have an up and running instance of
+Django Compressor, and that you understand how to use it in your templates.
+The goal is to explain what the main template tag, {% compress %}, does
+behind the scenes, to help you debug performance problems for instance.
+
+First step: Offline cache
+-------------------------
+
+The first thing {% compress %} tries to do is get the offline cache for its
+nodelist if offline cache is activated. It doesn't parse, doesn't check the
+modified times of the files, doesn't even know which files are concerned
+actually, since it doesn't look inside the nodelist of the template block
+enclosed by the ``compress`` template tag. The cache should return the HTML
+containing the element code for the combined file or piece of code (which,
+if the cache key exists, is supposed to already exist on disk/custom storage).
+
+Everything stops here if the cache entry exists.
+
+Second step: parsing and file list
+----------------------------------
+
+A compressor instance is created, which in turns instanciates the HTML parser.
+The parser is used to determine a file or code hunk list. Each file mtime is
+checked, first in cache and then on disk/storage, and this is used to
+determine an unique cache key.
+
+Third step: Checking the "main" cache
+-------------------------------------
+
+Compressor checks if it can get some info about the combined file/hunks
+corresponding to its instance, using the cache key obtained in the previous
+step. The cache content here will actually be the HTML containing the final
+element code, just like in the offline step before.
+
+Everything stops here if the cache entry exists.
+
+Fourth step: Generating the combined file if needed
+---------------------------------------------------
+
+The file is generated if necessary. All precompilers are called and all
+filters are executed, and a hash is determined from the contents. This in
+turns helps determine the file name, which is only saved if it didn't exist
+already. Then the HTML output is returned (and also saved in the cache).
+And that's it!
View
@@ -50,7 +50,7 @@
# The short X.Y version.
version = '0.6'
# The full version, including alpha/beta/rc tags.
-release = '0.6b6'
+release = '0.6b7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Oops, something went wrong.

0 comments on commit 0ab45f0

Please sign in to comment.