142 lines
3.3 KiB
Python
142 lines
3.3 KiB
Python
from minify import JavascriptMinify
|
|
|
|
class Bundle:
|
|
"""
|
|
Concatenate, compress and mix (if required) js+css files from build.json
|
|
"""
|
|
def concat(self, filelist, outfile=None, is_js=False):
|
|
"""
|
|
Concat css and js files into a bundle
|
|
"""
|
|
import os
|
|
from cStringIO import StringIO
|
|
from build import verbose
|
|
|
|
out_type = outfile and outfile.split('.')[-1] or 'js'
|
|
|
|
temp = StringIO()
|
|
for f in filelist:
|
|
if verbose:
|
|
print f + ' | ' + str(int(os.path.getsize(f)/1024)) + 'k'
|
|
|
|
fh = open(f)
|
|
|
|
# get file type
|
|
ftype = f.split('.')[-1]
|
|
|
|
# special concat (css inside js)
|
|
if is_js and ftype =='css':
|
|
css = fh.read()
|
|
data = "\nwn.assets.handler.css('%s');\n" % css.replace("'", "\\'").replace('\n', '\\\n')
|
|
|
|
# plain concat
|
|
else:
|
|
data = fh.read() + '\n'
|
|
|
|
fh.close()
|
|
temp.write(data)
|
|
|
|
if outfile:
|
|
f = open(outfile, 'w')
|
|
f.write(temp.getvalue())
|
|
f.close()
|
|
self.timestamps.update(outfile)
|
|
if verbose: print 'Wrote %s' % outfile
|
|
|
|
return temp
|
|
|
|
def changed(self, files):
|
|
"""
|
|
Returns true if the files are changed since last build
|
|
"""
|
|
import os
|
|
from build import force_rebuild
|
|
|
|
if force_rebuild:
|
|
return True
|
|
|
|
for f in files:
|
|
if f in self.timestamps.dirty:
|
|
return True
|
|
return False
|
|
|
|
def minify(self, in_files, outfile, concat=False):
|
|
"""
|
|
Compress in_files into outfile,
|
|
give some stats
|
|
"""
|
|
from build import verbose
|
|
import os
|
|
|
|
# concat everything into temp
|
|
outtype = outfile.split('.')[-1]
|
|
temp = self.concat(in_files, is_js=True)
|
|
|
|
out = open(outfile, 'w')
|
|
|
|
org_size = len(temp.getvalue())
|
|
temp.seek(0)
|
|
|
|
# minify
|
|
jsm = JavascriptMinify()
|
|
jsm.minify(temp, out)
|
|
|
|
out.close()
|
|
self.timestamps.update(outfile)
|
|
|
|
new_size = os.path.getsize(outfile)
|
|
|
|
if verbose:
|
|
print '=> %s' % outfile
|
|
print 'Original: %.2f kB' % (org_size / 1024.0)
|
|
print 'Compressed: %.2f kB' % (new_size / 1024.0)
|
|
print 'Reduction: %.1f%%' % (float(org_size - new_size) / org_size * 100)
|
|
|
|
def make(self, path):
|
|
"""
|
|
Build (stitch + compress) the file defined in build.json
|
|
"""
|
|
import os, sys, json
|
|
from build import no_minify
|
|
|
|
# open the build.json file and read
|
|
# the dict
|
|
bfile = open(os.path.join(path, 'build.json'), 'r')
|
|
bdata = json.loads(bfile.read())
|
|
bfile.close()
|
|
|
|
for outfile in bdata:
|
|
prefix, fname = False, outfile
|
|
|
|
# check if there is a prefix
|
|
if ':' in outfile:
|
|
prefix, fname = outfile.split(':')
|
|
|
|
# build the file list relative to the main folder
|
|
fl = [os.path.relpath(os.path.join(path, f), os.curdir) for f in bdata[outfile]]
|
|
|
|
self.timestamps.bundled += fl
|
|
|
|
if self.changed(fl):
|
|
# js files are minified by default unless explicitly
|
|
# mentioned in the prefix.
|
|
# some files may not work if minified (known jsmin bug)
|
|
|
|
if fname.split('.')[-1]=='js' and prefix!='concat' and not no_minify:
|
|
self.minify(fl, os.path.relpath(os.path.join(path, fname), os.curdir))
|
|
else:
|
|
self.concat(fl, os.path.relpath(os.path.join(path, fname), os.curdir))
|
|
|
|
def bundle(self, timestamps):
|
|
"""
|
|
Build js files from "build.json"
|
|
"""
|
|
import os
|
|
self.timestamps = timestamps
|
|
|
|
# walk the parent folder and build all files as defined in the build.json files
|
|
for wt in os.walk('.', followlinks=True):
|
|
if 'build.json' in wt[2]:
|
|
# found build file
|
|
self.make(os.path.abspath(wt[0]))
|
|
|