Commit 31b4db9f by andreas.pelme

Cleanup and some new/changed features.

* It is now possible to use several filters for CSS/JavaScript
* A management-command - synccompress - has been added. It can be used to update and force updates to the compressed files
* Heaps of other fixes


git-svn-id: https://django-compress.googlecode.com/svn/trunk@6 98d35234-f74b-0410-9e22-51d878bdf110
parent fc7aa6ab
from django.conf import settings
from compress.utils import needs_update, compress_css, compress_js
from compress.utils import needs_update, filter_css, filter_js
if settings.COMPRESS:
for css in settings.COMPRESS_CSS.values():
if needs_update(css['compressed_filename'], css['source_filenames']):
compress_css(css)
if needs_update(css['output_filename'], css['source_filenames']):
filter_css(css)
for js in settings.COMPRESS_JS.values():
if needs_update(js['compressed_filename'], css['source_filenames']):
compress_js(js)
\ No newline at end of file
if needs_update(js['output_filename'], js['source_filenames']):
filter_js(js)
\ No newline at end of file
import os
from django.conf import settings
from compress.utils import media_root
DEFAULT_ARGUMENTS = '--template=highest'
DEFAULT_BINARY = 'csstidy'
class CSSTidyCompressor:
def compress_css(self, css):
try:
binary = settings.COMPRESS_CSS_CSSTIDY_BINARY
except AttributeError:
binary = DEFAULT_BINARY
try:
arguments = settings.COMPRESS_CSS_CSSTIDY_ARGUMENTS
except AttributeError:
arguments = DEFAULT_ARGUMENTS
# try to create a temporary concatenated source
tmp_filename = os.tmpnam()
fd_source = open(tmp_filename, 'w+')
for source_filename in css['source_filenames']:
fd = open(media_root(source_filename), 'r')
fd_source.write(fd.read())
fd.close()
fd_source.close()
command = '%s %s %s %s' % (binary, tmp_filename, arguments, media_root(css['compressed_filename']))
print os.popen(command).readlines()
os.unlink(tmp_filename)
def compress_js(self, js):
raise NotImplementedError
\ No newline at end of file
from compress.utils import media_root
from compress.compressors.jsmin.jsmin import jsmin
class JSMinCompressor:
def compress_css(self, css):
raise NotImplementedError
def compress_js(self, js):
source = ''
for source_filename in js['source_filenames']:
fd = open(media_root(source_filename), 'r')
source += fd.read()
source += ';'
fd.close()
compressed = jsmin(source)
fd = open(media_root(js['compressed_filename']), 'w+')
fd.write(compressed)
fd.close()
\ No newline at end of file
class FilterBase:
def __init__(self, verbose):
self.verbose = verbose
def filter_css(self, css):
raise NotImplementedError
def filter_js(self, js):
raise NotImplementedError
\ No newline at end of file
import os
from django.conf import settings
from compress.utils import *
DEFAULT_ARGUMENTS = '--template=highest'
DEFAULT_BINARY = 'csstidy'
import warnings
warnings.simplefilter('ignore', RuntimeWarning)
from compress.filter_base import FilterBase
class CSSTidyFilter(FilterBase):
def filter_css(self, css):
try:
binary = settings.COMPRESS_CSS_CSSTIDY_BINARY
except AttributeError:
binary = DEFAULT_BINARY
try:
arguments = settings.COMPRESS_CSS_CSSTIDY_ARGUMENTS
except AttributeError:
arguments = DEFAULT_ARGUMENTS
tmp_filename = write_tmpfile(css)
try:
output_filename = os.tmpnam()
except RuntimeWarning:
pass
command = '%s %s %s %s' % (binary, tmp_filename, arguments, output_filename)
output = os.popen(command).read()
if self.verbose:
print output
os.unlink(tmp_filename)
return read_tmpfile(output_filename)
\ No newline at end of file
from compress.filters.jsmin.jsmin import jsmin
from compress.filter_base import FilterBase
class JSMinFilter(FilterBase):
def filter_js(self, js):
return jsmin(js)
\ No newline at end of file
from django.core.management.base import BaseCommand
from optparse import make_option
from django.conf import settings
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('--force', action='store_true', default=False, help='Force update of all files, even if the source files are older than the current compressed file.'),
make_option('--verbosity', action='store', dest='verbosity', default='1',
type='choice', choices=['0', '1', '2'],
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
)
help = 'Updates and compresses CSS and JavsScript on-demand, with no need to restart Django'
args = ''
def handle(self, **options):
force = options.get('force', False)
verbosity = int(options.get('verbosity', 1))
from compress.utils import needs_update, filter_css, filter_js
for name, css in settings.COMPRESS_CSS.items():
if force or needs_update(css['output_filename'], css['source_filenames']):
if verbosity >= 1:
print ("Updating CSS group %s..." % name),
filter_css(css, verbose=(verbosity >= 2))
if verbosity >= 1:
print "done."
for name, js in settings.COMPRESS_JS.items():
if force or needs_update(js['output_filename'], js['source_filenames']):
if verbosity >= 1:
print ("Updating JavaScript group %s..." % name),
filter_js(js, verbose=(verbosity >= 2))
if verbosity >= 1:
print "done."
\ No newline at end of file
<link href="{{ url }}" rel="stylesheet" type="text/css" media="{{ css.media }}" />
\ No newline at end of file
<link href="{{ url }}" rel="stylesheet" type="text/css" media="{{ media|default:"screen,projection" }}" />
\ No newline at end of file
# {% %}
import os
from django import template
from django.conf import settings
register = template.Library()
def render_common(template_name, obj, filename):
if 'extra_context' in obj:
context = obj['extra_context']
else:
context = {}
url = settings.MEDIA_URL + filename
if settings.COMPRESS and 'bump_filename' in obj and obj['bump_filename']:
url += '?%d' % os.stat(settings.MEDIA_ROOT + '/'+(filename)).st_mtime
context.update(url=url)
return template.loader.render_to_string(template_name, context)
def render_css(css, filename):
return template.loader.render_to_string('compress/css.html', {
'url': settings.MEDIA_URL + filename,
'css': css,
})
return render_common('compress/css.html', css, filename)
def render_js(js, filename):
return template.loader.render_to_string('compress/js.html', {
'url': settings.MEDIA_URL + filename,
'js': js,
})
return render_common('compress/js.html', js, filename)
class CompressedCSSNode(template.Node):
def __init__(self, name):
......@@ -23,8 +32,9 @@ class CompressedCSSNode(template.Node):
def render(self, context):
css_name = template.Variable(self.name).resolve(context)
css = settings.COMPRESS_CSS[css_name]
if settings.COMPRESS:
return render_css(css, css['compressed_filename'])
return render_css(css, css['output_filename'])
else:
# output source files
r = ''
......@@ -41,7 +51,7 @@ class CompressedJSNode(template.Node):
js_name = template.Variable(self.name).resolve(context)
js = settings.COMPRESS_JS[js_name]
if settings.COMPRESS:
return render_js(js, js['compressed_filename'])
return render_js(js, js['output_filename'])
else:
# output source files
r = ''
......@@ -49,7 +59,7 @@ class CompressedJSNode(template.Node):
r += render_js(js, source_file)
return r
# @register.tag
#@register.tag
def compressed_css(parser, token):
try:
tag_name, name = token.split_contents()
......@@ -59,7 +69,7 @@ def compressed_css(parser, token):
return CompressedCSSNode(name)
compressed_css = register.tag(compressed_css)
# @register.tag
#@register.tag
def compressed_js(parser, token):
try:
tag_name, name = token.split_contents()
......
......@@ -4,7 +4,7 @@ import os
from django.conf import settings
def get_compressor(compressor_class):
def get_filter(compressor_class):
"""
Convert a string version of a function name to the callable object.
......@@ -19,8 +19,6 @@ def get_compressor(compressor_class):
# Bail early for non-ASCII strings (they can't be functions).
compressor_class = compressor_class.encode('ascii')
mod_name, class_name = get_mod_func(compressor_class)
print mod_name
print class_name
if class_name != '':
compressor_class = getattr(__import__(mod_name, {}, {}, ['']), class_name)
except (ImportError, AttributeError):
......@@ -62,8 +60,55 @@ def media_root(filename):
def media_url(filename):
return settings.MEDIA_URL + filename
def compress_css(css):
get_compressor(settings.COMPRESS_CSS_COMPRESSOR)().compress_css(css)
def write_tmpfile(content):
try:
filename = os.tmpnam()
except RuntimeWarning:
pass
fd = open(filename, 'w+')
fd.write(content)
fd.close()
return filename
def read_tmpfile(filename, delete=True):
fd = open(filename, 'r')
r = fd.read()
fd.close()
if delete:
os.unlink(filename)
return r
def concat(filenames, separator=''):
r = ''
for filename in filenames:
fd = open(media_root(filename), 'r')
r += fd.read()
r += separator
fd.close()
return r
def save_file(filename, contents):
fd = open(media_root(filename), 'w+')
fd.write(contents)
fd.close()
def filter_css(css, verbose=False):
output = concat(css['source_filenames'])
for f in settings.COMPRESS_CSS_FILTERS:
output = get_filter(f)(verbose=verbose).filter_css(output)
save_file(css['output_filename'], output)
def filter_js(js, verbose=False):
output = concat(js['source_filenames'], ';') # add a ; between each files to make sure every file is properly "closed"
for f in settings.COMPRESS_JS_FILTERS:
output = get_filter(f)(verbose=verbose).filter_js(output)
def compress_js(js):
get_compressor(settings.COMPRESS_JS_COMPRESSOR)().compress_js(js)
\ No newline at end of file
save_file(js['output_filename'], output)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment