Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update build process to use new wq.core api #39

Merged
merged 3 commits into from
Apr 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion build/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
from .builder import Builder
from .appcache import appcache # NOQA
from .builder import build # NOQA
from .collect import collectjson # NOQA
from .compilers import optimize, scss, mustache # NOQA
from .init import init # NOQA
from .setversion import setversion # NOQA
19 changes: 16 additions & 3 deletions build/appcache.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
from __future__ import print_function

from wq.core import wq
import click
import os
import re


def appcache(conf, indir, outdir, version):
@wq.command()
@click.argument('version')
@wq.pass_config
def appcache(config, version):
if 'appcache' not in config:
click.echo("appcache section not found in %s" % config.filename)
return
if 'optimize' not in config:
click.echo("optimize section not found in %s" % config.filename)
return

conf = config['appcache']
indir = config['optimize']['appDir']
outdir = config['optimize']['dir']

# Open output files
s_acpath = indir + '/' + conf['name']
Expand Down
136 changes: 44 additions & 92 deletions build/builder.py
Original file line number Diff line number Diff line change
@@ -1,99 +1,51 @@
import json
import yaml
import sys
from wq.core import wq
import click

from .collect import collectjson
from .setversion import setversion
from .appcache import appcache
from .compilers import optimize, scss, mustache
from .init import init


class Builder(object):
conf = None
indir = None
outdir = None
version = ""

COMMANDS = {
'init': init,
'collectjson': collectjson,
'scss': scss,
'mustache': mustache,
}

def __init__(self, version=None, config="wq.yml"):
# Load configuration file
try:
self.conf = yaml.load(open(config))
except (OSError, IOError):
try:
self.conf = json.load(open("app.build.json"))
except (OSError, IOError):
raise Exception("Could not find configuration file.")
else:
sys.stderr.write(
"Warning: Converted app.build.json to wq.yml\n"
)
yaml.dump(self.conf, open("wq.yml", 'w'))

if 'optimize' not in self.conf:
raise Exception("No optimize section in conf file!")

# Determine input and output directories
self.indir = self.conf['optimize']['appDir']
self.outdir = self.conf['optimize']['dir']
if version is not None:
self.version = version

def build(self):
self.run('init')

# Save version information
if 'setversion' in self.conf or self.version != "":
self.setversion()

for command in ('init', 'collectjson', 'scss', 'mustache'):
if command in self.conf:
self.run(command)

# Compile Javascript / CSS (using r.js)
self.optimize()

# Generate HTML5 Cache manifests
if 'appcache' in self.conf:
self.appcache()

def run(self, command, directory=None, conf=None):
if directory is None:
directory = self.indir
if conf is None:
conf = self.conf.get(command, {})

fn = self.COMMANDS[command]
if isinstance(conf, dict):
fn(conf, directory)
else:
for c in conf:
fn(c, directory)

def setversion(self, directory=None, conf=None):
if directory is None:
directory = self.indir
if conf is None:
conf = self.conf.get('setversion', {})
if self.version != '':
conf['version'] = self.version
self.version = setversion(conf, directory)

def optimize(self, conf=None):
"Combine and optimize Javascript and CSS files"
if conf is None:
conf = self.conf.get('optimize', {})

optimize(conf, self.indir, self.outdir)

def appcache(self, conf=None):
if conf is None:
conf = self.conf.get('appcache', {})
appcache(conf, self.indir, self.outdir, self.version)
COMMANDS = {
'collectjson': collectjson,
'init': init,
'mustache': mustache,
'scss': scss,
'setversion': setversion,
}


@wq.command()
@click.argument('version')
@wq.pass_config
@click.pass_context
def build(ctx, config, version):
if 'optimize' not in config:
click.echo("optimize section not found in %s" % config.filename)
return

def run(name, **kwargs):
confs = config.get(name, {})
command = COMMANDS[name]
if not isinstance(confs, list):
confs = [confs]
for conf in confs:
conf.update(kwargs)
ctx.invoke(command, **conf)

run('init')

# Save version information
run('setversion', version=version)

for name in ('collectjson', 'scss', 'mustache'):
if name in config:
run(name)

# Compile Javascript / CSS (using r.js)
ctx.invoke(optimize)

# Generate HTML5 Cache manifests
if 'appcache' in config:
ctx.invoke(appcache, version=version)
49 changes: 28 additions & 21 deletions build/collect.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
from __future__ import print_function

import os
import json
try:
import yaml
except:
yaml = None
import yaml
from wq.core import wq
import click

NEST = {
'json': json,
Expand Down Expand Up @@ -38,11 +35,11 @@ def readfiles(basedir, ftype=None, fext=None):

fpath = path + name
data = open(basedir + os.sep + fpath + ext)
if NEST.get(ftype, None):
if ftype in NEST:
try:
o[name] = NEST[ftype].load(data)
except ValueError:
print("Could not parse %s!" % name)
click.echo("Could not parse %s!" % name)
raise
else:
o[name] = data.read()
Expand All @@ -53,32 +50,42 @@ def readfiles(basedir, ftype=None, fext=None):
return obj


def collectjson(conf, directory):
"Collect files and dump the result into a JSON object"
obj = {}
cur = os.getcwd()
os.chdir(directory)
@wq.command()
@click.option(
'--type', default='json', help="Source file type (e.g. json, yaml)"
)
@click.option('--extension', help="Source file extension (e.g. json, yml)")
@click.option('--output', default='output.json', help="Destination JSON file")
@click.option('--indent', default=4, help="JSON Indentation")
@click.option('--jsonp', help="Wrap as JSONP")
@click.argument('paths', type=click.Path(exists=True), nargs=-1)
def collectjson(**conf):
"Collect directory contents into a JSON object"

if not conf['extension']:
conf['extension'] = conf['type']
if not conf['paths']:
conf['paths'] = ['.']

obj = {}
for d in conf['paths']:
obj.update(readfiles(d, conf['type'], conf.get('extension', None)))
obj.update(readfiles(d, conf['type'], conf['extension']))

outfile = open(conf['output'], 'w')

opts = dict([
(str(key), value)
for key, value in conf.get('json', {'indent': 4}).items()
])
opts = {}
if conf['indent']:
opts['indent'] = conf['indent']

if 'jsonp' in conf:
if conf['jsonp']:
txt = json.dumps(obj, **opts)
txt = '%s(%s);' % (conf['jsonp'], txt)
outfile.write(txt)
else:
json.dump(obj, outfile, **opts)

print('%s: %s objects collected from %s' % (
click.echo('%s: %s objects collected from %s' % (
conf['output'], len(obj), ', '.join(conf['paths'])
))

outfile.close()
os.chdir(cur)
88 changes: 61 additions & 27 deletions build/compilers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import print_function
from wq.core import wq
import click

import os
import subprocess
Expand All @@ -8,24 +9,48 @@
from .collect import readfiles


def optimize(conf, indir, outdir):
@wq.command()
@wq.pass_config
def optimize(config):
"""
Use r.js to optimize JS and CSS assets
"""
conf = config.get('optimize', None)
if not conf:
click.echo("optimize section not found in %s" % config.filename)
return
outdir = conf.get('dir', None)

bfile = "rjsconf%s" % (random.random() * 10000)
bjs = open(bfile, 'w')
json.dump(conf, bjs)
bjs.close()

# Defer to r.js for actual processing
print('#' * 20)
print("Optimizing with r.js")
click.echo('#' * 20)
click.echo("Optimizing with r.js")
rjs = os.path.dirname(__file__) + "/r.js"
subprocess.call(["node", rjs, "-o", bfile])
os.remove(bfile)
os.remove(outdir + '/' + bfile)
print("Optimization complete")
print('#' * 20)
if outdir:
os.remove(outdir + '/' + bfile)
click.echo("Optimization complete")
click.echo('#' * 20)


def scss(conf, indir=None):
@wq.command()
@click.option(
'--indir', type=click.Path(exists=True), default="scss",
help="Path to SCSS/SASS files"
)
@click.option(
'--outdir', type=click.Path(exists=True), default="css",
help="Path to CSS files"
)
def scss(**conf):
"""
Render all SCSS/SASS files into CSS
"""
import scss
import logging
compiler = scss.Scss(scss_opts={'compress': 0})
Expand All @@ -37,42 +62,51 @@ def compile(path, source):
outfile.write(css)
outfile.close()

if 'indir' in conf and 'outdir' in conf:
files = readfiles(conf['indir'], "scss")
scss.config.LOAD_PATHS = [
conf['indir'],
os.path.join(conf['indir'], 'lib'),
]
for name, source in files.items():
if isinstance(source, dict):
continue
path = "%s/%s.css" % (conf['outdir'], name)
compile(path, source)
print("%s compiled from %s/%s.scss" % (path, conf['indir'], name))
files = readfiles(conf['indir'], "scss")
scss.config.LOAD_PATHS = [
conf['indir'],
os.path.join(conf['indir'], 'lib'),
]
for name, source in files.items():
if isinstance(source, dict):
continue
path = "%s/%s.css" % (conf['outdir'], name)
compile(path, source)
click.echo("%s compiled from %s/%s.scss" % (path, conf['indir'], name))


def mustache(conf, indir=None):
@wq.command()
@click.option('--template', help="Path to template")
@click.option('--partials', help="Path to partials")
@click.option('--context', help="Path to context (JSON or YAML)")
@click.option(
'--output', type=click.Path(), default="output.html",
help="Output filename"
)
def mustache(**conf):
"""
Render a mustache template into static HTML
"""
import pystache
template = conf.get("template", None)
template = conf['template']
if template is None:
return
if os.sep in template or template.endswith(".html"):
template = open(template).read()

context = conf.get("context", {})
context = conf["context"] or {}
if not isinstance(context, dict):
path = context
context = readfiles(path, "yaml", "yml")
context.update(**readfiles(path, "json"))

partials = conf.get("partials", {})
partials = conf['partials'] or {}
if not isinstance(partials, dict):
partials = readfiles(partials, "html")

output = conf.get("output", "output.html")
print("Generating %s from %s" % (output, conf['template']))
click.echo("Generating %s from %s" % (conf['output'], conf['template']))
renderer = pystache.Renderer(partials=partials)
html = renderer.render(template, context)
f = open(output, 'w')
f = open(conf['output'], 'w')
f.write(html)
f.close()
Loading