From 825637ff2d39b459e3fe751b6077eaa9a32ae152 Mon Sep 17 00:00:00 2001 From: Jeremy Carbaugh Date: Fri, 8 Apr 2011 16:27:17 -0400 Subject: [PATCH] add Google Closure Compiler processor --- README.rst | 21 ++++++++++++---- mediasync/processors/closurecompiler.py | 26 ++++++++++++++++++++ mediasync/processors/yuicompressor.py | 5 ++-- mediasync/tests/tests.py | 32 ++++++++++++++++++++++++- 4 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 mediasync/processors/closurecompiler.py diff --git a/README.rst b/README.rst index 18ee38c..2e86b6a 100644 --- a/README.rst +++ b/README.rst @@ -366,8 +366,7 @@ File Processors File processors allow you to modify the content of a file as it is being synced or served statically. -Mediasync ships with two processor modules, each of which defines two -processors for minifying both CSS and Javascript files: +Mediasync ships with three processor modules: 1. ``slim`` is a minifier written in Python and requires the `slimmer` Python package. The Python package can be found here: @@ -379,6 +378,8 @@ processors for minifying both CSS and Javascript files: `yuicompressor` is new and should be considered experimental until the mediasync 2.1 release. +3. ``closurecompiler`` is a javascript compiler provided by Google. + Custom processors can be specified using the *PROCESSORS* entry in the mediasync settings dict. *PROCESSORS* should be a list of processor entries. Each processor entry can be a callable or a string path to a callable. If the @@ -411,10 +412,19 @@ if you plan on using them:: ... ), -Mediasync will attempt to use `slimmer` by default if you leave it out of -your settings. If it is on your Python path it will get used. +mediasync will attempt to use `slimmer` by default if you have the package +installed and do not use the PROCESSORS setting. -**EXPERIMENTAL** +Google Closure Compiler +----------------------- + +Google's JavaScript Closure Compiler provides an API that allows files to be +compressed without installing anything locally. To use the service:: + + 'PROCESSORS': ('mediasync.processors.closurecompiler.compile',) + +YUI Compressor +-------------- To configure YUI Compressor you need to define a `PROCESSORS` and `YUI_COMPRESSOR_PATH` as follows, assuming you placed the ".jar" file in @@ -630,6 +640,7 @@ Change Log * added pre_sync and post_sync signals * provide basic receiver for calling collectstatic before syncing * show media directory listing when serving locally in debug mode +* add processor for Google's Closure Compiler API for JavaScript 2.1.0 ===== diff --git a/mediasync/processors/closurecompiler.py b/mediasync/processors/closurecompiler.py new file mode 100644 index 0000000..9c17e13 --- /dev/null +++ b/mediasync/processors/closurecompiler.py @@ -0,0 +1,26 @@ +from mediasync import JS_MIMETYPES +from urllib import urlencode +import httplib + +HEADERS = {"content-type": "application/x-www-form-urlencoded"} + +def compile(filedata, content_type, remote_path, is_active): + + is_js = (content_type in JS_MIMETYPES or remote_path.lower().endswith('.js')) + + if is_js: + + params = urlencode({ + 'js_code': filedata, + 'compilation_level': 'SIMPLE_OPTIMIZATIONS', + 'output_info': 'compiled_code', + 'output_format': 'text', + }) + + conn = httplib.HTTPConnection('closure-compiler.appspot.com') + conn.request('POST', '/compile', params, HEADERS) + response = conn.getresponse() + data = response.read() + conn.close + + return data \ No newline at end of file diff --git a/mediasync/processors/yuicompressor.py b/mediasync/processors/yuicompressor.py index d4bb5c0..47ed368 100644 --- a/mediasync/processors/yuicompressor.py +++ b/mediasync/processors/yuicompressor.py @@ -1,4 +1,5 @@ from django.conf import settings +from mediasync import JS_MIMETYPES import os from subprocess import Popen, PIPE @@ -11,7 +12,7 @@ def _yui_path(settings): return path def css_minifier(filedata, content_type, remote_path, is_active): - is_css = (content_type == 'text/css' or remote_path.lower().endswith('.css')) + is_css = (content_type in JS_MIMETYPES or remote_path.lower().endswith('.css')) yui_path = _yui_path(settings) if is_css and yui_path and is_active: proc = Popen(['java', '-jar', yui_path, '--type', 'css'], stdout=PIPE, @@ -20,7 +21,7 @@ def css_minifier(filedata, content_type, remote_path, is_active): return str(stdout) def js_minifier(filedata, content_type, remote_path, is_active): - is_js = (content_type == 'text/javascript' or remote_path.lower().endswith('.js')) + is_js = (content_type in JS_MIMETYPES or remote_path.lower().endswith('.js')) yui_path = _yui_path(settings) if is_js and yui_path and is_active: proc = Popen(['java', '-jar', yui_path, '--type', 'js'], stdout=PIPE, diff --git a/mediasync/tests/tests.py b/mediasync/tests/tests.py index f87a59b..e8b0c44 100644 --- a/mediasync/tests/tests.py +++ b/mediasync/tests/tests.py @@ -9,7 +9,7 @@ import re import time import unittest -from mediasync import backends +from mediasync import backends, JS_MIMETYPES from mediasync.backends import BaseClient from mediasync.conf import msettings from mediasync.signals import pre_sync, post_sync @@ -308,6 +308,36 @@ class ProcessorTestCase(unittest.TestCase): procd = self.client.process('asdf', 'text/plain', 'asdf.txt') self.assertEqual(procd, "ASDF") +class ClosureCompilerTestCase(unittest.TestCase): + + def setUp(self): + msettings['SERVE_REMOTE'] = True + msettings['BACKEND'] = 'mediasync.tests.tests' + msettings['PROCESSORS'] = ( + 'mediasync.processors.closurecompiler.compile', + ) + self.client = backends.client() + + def testCompiler(self): + + content = """var foo = function() { + alert(1); + };""" + + for ct in JS_MIMETYPES: + procd = self.client.process(content, ct, 'test.js') + self.assertEqual(procd, 'var foo=function(){alert(1)};\n') + + def testNotJavascript(self): + + content = """html { + border: 1px solid #000000; + font-family: "Helvetica", "Arial", sans-serif; + }""" + + procd = self.client.process(content, 'text/css', 'test.css') + self.assertEqual(procd, content) + class SignalTestCase(unittest.TestCase): def setUp(self):