Skip to content

Instantly share code, notes, and snippets.

@chrisgeo
Created September 25, 2010 22:44
Show Gist options
  • Save chrisgeo/597374 to your computer and use it in GitHub Desktop.
Save chrisgeo/597374 to your computer and use it in GitHub Desktop.
"""Combo Loader WSGI App
Variable location combo loader to import javascript and css files.
It will loader Javascript files into one JS and CSS into another much like YUI PHP Loader:
http://developer.yahoo.com/yui/phploader/
TODO:
Build in caching beaker, sessions, and/or memcache.
"""
import sys
import webob
import webob.exc as exc
import json
import re
from comboloader.utils import HttpRequest, FileRequest
from beaker.middleware import SessionMiddleware
from paste.deploy.converters import asbool
import logging
log = logging.getLogger(__name__)
REQUEST_TYPES = {
'server': HttpRequest,
'file': FileRequest
}
required_config_keys = ['base', 'request_type', 'js_path', 'css_path', 'combo_base']
def parse_json_confing(config_file):
"""Parse JSON for config
JSON will can look like this:
{
"request_type": "server",
"comboBase": "www.cdn.com"
"base": "/base/path", //build directory
"js_path": "js", //path relative to base
"css_path": "path/to/css", //path relative to base; note: combo loader will try and search/replace images in CSS files
"filter": DEBUG|MIN
}
Otherwise uses the *.ini file to load the server config
"""
f = open(config_file, 'r')
content = f.read()
f.close()
config = json.loads(content)
#parse through options to load files by file name
missing_keys = []
for key in required_config_keys:
if key not in config.keys():
missing_keys.append(key)
if len(missing_keys) > 0:
raise Exception("Required keys are missing in config :: required are: %s ::: config is missing: %s"
% (required_config_keys, missing_keys))
config['request_type'] = REQUEST_TYPES[config['request_type'].lower()]
return config
def parse_ini_config(config):
new_config = {}
new_config['request_type'] = REQUEST_TYPES['file']
new_config['js_path'] = config['base_js_dir']
new_config['css_path'] = config['base_css_dir']
new_config['img_path'] = config['base_img_dir']
new_config['filter'] = config.get('filter', 'min')
return new_config
def parse_config_file(config):
if asbool(config['use_config']):
new_config = parse_json_file(config['config_file'])
else:
new_config = parse_ini_config(config)
return new_config
class ComboLoaderApp(object):
"""ComboLoader WSGI App
Retrieves files from a filesystem or HTTP Request and concatenates them
into one file request
"""
def __init__(self, config):
self.config = parse_config_file(config)
self.js_regex = re.compile('^.+?\.js$', re.IGNORECASE)
self.css_regex = re.compile('^.+?\.css$', re.IGNORECASE)
def __call__(self, environ, start_response):
req = webob.Request(environ)
req.session = environ['beaker.session']
self.js_regex = re.compile('^.+?\.js$', re.IGNORECASE)
self.css_regex = re.compile('^.+?\.css$', re.IGNORECASE)
#get files and munge together
#command line arguments
if not req.query_string:
return exc.HTTPBadRequest("Cannot have empty parameter list")(environ, start_response)
else:
files = dict(js=list(), css=list())
#probably a more elegant way to do this.
for param in req.query_string.split('&'):
if(self.js_regex.match(param)):
files['js'].append(param)
elif(self.css_regex.match(param)):
files['css'].append(param)
return self.config['request_type'](request=req, config=self.config, files=files)(environ, start_response)
def make_app(config):
"""Construct WSGI App from JSON file"""
app = ComboLoaderApp(config)
app = SessionMiddleware(app, config)
return app
def make_loader_app(global_conf, **app_conf):
"""Construct a complete WSGI app ready to serve by Paste
Example INI file:
.. code-block:: ini
[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 80
[composite:main]
use = egg:Paste#urlmap
/ = YOURAPP
/loader = loader
[app:loader]
use = egg:comboloader
config_file = %(here)s/LOCATION_TO/CONFIG.json
beaker.session.data_dir = %(here)s/data/sdata
beaker.session.lock_dir = %(here)s/data/slock
beaker.session.key = comboloader
beaker.session.secret = somesecret
beaker.session.type = cookie
beaker.session.validate_key = STRONG_KEY_HERE
beaker.session.cookie_domain = .yourdomain.com
base_js_dir = %(here)s/js/
base_css_dir = %(here)/css/
use_config = False
[app:YOURAPP]
use = egg:YOURAPP
full_stack = true
static_files = true
"""
app = ComboLoaderApp(app_conf)
app = SessionMiddleware(app, app_conf)
return app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment