37
build.py
37
build.py
@@ -10,16 +10,15 @@ import time
|
|||||||
|
|
||||||
import pake
|
import pake
|
||||||
|
|
||||||
pake.variables['JSDOC'] = 'jsdoc'
|
pake.variables.BRANCH = pake.output('git', 'rev-parse', '--abbrev-ref', 'HEAD').strip()
|
||||||
pake.variables['PHANTOMJS'] = 'phantomjs'
|
pake.variables.JSDOC = 'jsdoc'
|
||||||
|
pake.variables.PHANTOMJS = 'phantomjs'
|
||||||
|
|
||||||
EXPORTS = [path
|
EXPORTS = [path
|
||||||
for path in pake.ifind('src')
|
for path in pake.ifind('src')
|
||||||
if path.endswith('.exports')
|
if path.endswith('.exports')
|
||||||
if path != 'src/objectliterals.exports']
|
if path != 'src/objectliterals.exports']
|
||||||
|
|
||||||
BRANCH = pake.output('git', 'rev-parse', '--abbrev-ref', 'HEAD').strip()
|
|
||||||
|
|
||||||
EXTERNAL_SRC = [
|
EXTERNAL_SRC = [
|
||||||
'build/src/external/externs/types.js',
|
'build/src/external/externs/types.js',
|
||||||
'build/src/external/src/exports.js',
|
'build/src/external/src/exports.js',
|
||||||
@@ -184,41 +183,37 @@ pake.virtual('plovr', PLOVR_JAR)
|
|||||||
|
|
||||||
@pake.target(PLOVR_JAR, clean=False)
|
@pake.target(PLOVR_JAR, clean=False)
|
||||||
def plovr_jar(t):
|
def plovr_jar(t):
|
||||||
import urllib2
|
t.download('https://plovr.googlecode.com/files/' + os.path.basename(PLOVR_JAR))
|
||||||
url = 'https://plovr.googlecode.com/files/' + os.path.basename(PLOVR_JAR)
|
|
||||||
content = urllib2.urlopen(url).read()
|
|
||||||
with open(t.name, 'w') as f:
|
|
||||||
f.write(content)
|
|
||||||
|
|
||||||
|
|
||||||
@pake.target('gh-pages', phony=True)
|
@pake.target('gh-pages', phony=True)
|
||||||
def gh_pages(t):
|
def gh_pages(t):
|
||||||
t.run('bin/git-update-ghpages', 'openlayers/ol3', '-i', 'build/gh-pages/%(BRANCH)s' % globals(), '-p', BRANCH)
|
t.run('bin/git-update-ghpages', 'openlayers/ol3', '-i', 'build/gh-pages/%(BRANCH)s', '-p', '%(BRANCH)s')
|
||||||
|
|
||||||
|
|
||||||
pake.virtual('doc', 'build/jsdoc-%(BRANCH)s-timestamp' % globals())
|
pake.virtual('doc', 'build/jsdoc-%(BRANCH)s-timestamp' % vars(pake.variables))
|
||||||
|
|
||||||
|
|
||||||
@pake.target('build/jsdoc-%(BRANCH)s-timestamp' % globals(), SRC, pake.ifind('doc/template'))
|
@pake.target('build/jsdoc-%(BRANCH)s-timestamp' % vars(pake.variables), SRC, pake.ifind('doc/template'))
|
||||||
def jsdoc_BRANCH_timestamp(t):
|
def jsdoc_BRANCH_timestamp(t):
|
||||||
t.run(pake.variables['JSDOC'], '-t', 'doc/template', '-r', 'src', '-d', 'build/gh-pages/%(BRANCH)s/apidoc' % globals())
|
t.run('%(JSDOC)s', '-t', 'doc/template', '-r', 'src', '-d', 'build/gh-pages/%(BRANCH)s/apidoc')
|
||||||
t.touch()
|
t.touch()
|
||||||
|
|
||||||
|
|
||||||
@pake.target('hostexamples', 'build', 'examples', phony=True)
|
@pake.target('hostexamples', 'build', 'examples', phony=True)
|
||||||
def hostexamples(t):
|
def hostexamples(t):
|
||||||
t.makedirs('build/gh-pages/%(BRANCH)s/examples' % globals())
|
t.makedirs('build/gh-pages/%(BRANCH)s/examples')
|
||||||
t.makedirs('build/gh-pages/%(BRANCH)s/build' % globals())
|
t.makedirs('build/gh-pages/%(BRANCH)s/build')
|
||||||
t.cp(EXAMPLES, (path.replace('.html', '.js') for path in EXAMPLES), 'examples/style.css', 'build/gh-pages/%(BRANCH)s/examples/' % globals())
|
t.cp(EXAMPLES, (path.replace('.html', '.js') for path in EXAMPLES), 'examples/style.css', 'build/gh-pages/%(BRANCH)s/examples/')
|
||||||
t.cp('build/loader_hosted_examples.js', 'build/gh-pages/%(BRANCH)s/examples/loader.js' % globals())
|
t.cp('build/loader_hosted_examples.js', 'build/gh-pages/%(BRANCH)s/examples/loader.js')
|
||||||
t.cp('build/ol.js', 'build/ol.css', 'build/gh-pages/%(BRANCH)s/build/' % globals())
|
t.cp('build/ol.js', 'build/ol.css', 'build/gh-pages/%(BRANCH)s/build/')
|
||||||
t.cp('examples/example-list.html', 'build/gh-pages/%(BRANCH)s/examples/index.html' % globals())
|
t.cp('examples/example-list.html', 'build/gh-pages/%(BRANCH)s/examples/index.html')
|
||||||
t.cp('examples/example-list.js', 'examples/example-list.xml', 'examples/Jugl.js', 'build/gh-pages/%(BRANCH)s/examples/' % globals())
|
t.cp('examples/example-list.js', 'examples/example-list.xml', 'examples/Jugl.js', 'build/gh-pages/%(BRANCH)s/examples/')
|
||||||
|
|
||||||
|
|
||||||
@pake.target('test', INTERNAL_SRC, phony=True)
|
@pake.target('test', INTERNAL_SRC, phony=True)
|
||||||
def test(t):
|
def test(t):
|
||||||
t.run(pake.variables['PHANTOMJS'], 'test/phantom-jasmine/run_jasmine_test.coffee', 'test/ol.html')
|
t.run('%(PHANTOMJS)s', 'test/phantom-jasmine/run_jasmine_test.coffee', 'test/ol.html')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
334
pake.py
Normal file
334
pake.py
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import contextlib
|
||||||
|
import logging
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PakeError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AmbiguousRuleError(PakeError):
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%r matches multiple rules' % (self.name,)
|
||||||
|
|
||||||
|
|
||||||
|
class BuildError(PakeError):
|
||||||
|
|
||||||
|
def __init__(self, target, message):
|
||||||
|
self.target = target
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s: %s' % (self.target.name, self.message)
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateTargetError(PakeError):
|
||||||
|
|
||||||
|
def __init__(self, target):
|
||||||
|
self.target = target
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'duplicate target %r' % (self.target.name,)
|
||||||
|
|
||||||
|
|
||||||
|
class Target(object):
|
||||||
|
|
||||||
|
def __init__(self, name, action=None, clean=True, dependencies=(),
|
||||||
|
makedirs=True, phony=False, precious=False):
|
||||||
|
self.name = name
|
||||||
|
self.action = action
|
||||||
|
self._clean = clean
|
||||||
|
self.dependencies = list(flatten(dependencies))
|
||||||
|
self._makedirs = makedirs
|
||||||
|
self.phony = phony
|
||||||
|
self.precious = precious
|
||||||
|
self.logger = logging.getLogger(self.name)
|
||||||
|
self.timestamp = None
|
||||||
|
|
||||||
|
def build(self, dry_run=False):
|
||||||
|
timestamp = 0
|
||||||
|
for dependency in self.dependencies:
|
||||||
|
target = targets.get(dependency)
|
||||||
|
timestamp = max(timestamp, target.build(dry_run=dry_run))
|
||||||
|
self.debug('build')
|
||||||
|
if self.timestamp is None:
|
||||||
|
if not self.phony and os.path.exists(self.name):
|
||||||
|
self.timestamp = os.stat(self.name).st_mtime
|
||||||
|
else:
|
||||||
|
self.timestamp = -1
|
||||||
|
if self.timestamp < timestamp:
|
||||||
|
self.debug('action')
|
||||||
|
if self._makedirs and not dry_run:
|
||||||
|
self.makedirs(os.path.dirname(self.name))
|
||||||
|
if self.action:
|
||||||
|
if self.action.__doc__:
|
||||||
|
self.info(self.action.__doc__)
|
||||||
|
if not dry_run:
|
||||||
|
self.action(self)
|
||||||
|
self.timestamp = timestamp or time.time()
|
||||||
|
return self.timestamp
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def chdir(self, dir):
|
||||||
|
cwd = os.getcwd()
|
||||||
|
dir = dir % vars(variables)
|
||||||
|
self.info('cd %s', dir)
|
||||||
|
os.chdir(dir)
|
||||||
|
try:
|
||||||
|
yield dir
|
||||||
|
finally:
|
||||||
|
self.info('cd %s', cwd)
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
def cp(self, *args):
|
||||||
|
args = flatten_expand_list(args)
|
||||||
|
dest = args.pop()
|
||||||
|
for arg in args:
|
||||||
|
self.info('cp %s %s', arg, dest)
|
||||||
|
shutil.copy(arg, dest)
|
||||||
|
|
||||||
|
def cp_r(self, *args):
|
||||||
|
args = flatten_expand_list(args)
|
||||||
|
dest = args.pop()
|
||||||
|
for arg in args:
|
||||||
|
self.info('cp -r %s %s', arg, dest)
|
||||||
|
shutil.copytree(arg, dest)
|
||||||
|
|
||||||
|
def clean(self, really=False, recurse=True):
|
||||||
|
if (self._clean or really) and not self.precious:
|
||||||
|
self.info('clean')
|
||||||
|
try:
|
||||||
|
os.remove(self.name)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
if recurse:
|
||||||
|
for dependency in self.dependencies:
|
||||||
|
targets.get(dependency).clean(really=really, recurse=recurse)
|
||||||
|
|
||||||
|
def debug(self, *args, **kwargs):
|
||||||
|
self.logger.debug(*args, **kwargs)
|
||||||
|
|
||||||
|
def download(self, url):
|
||||||
|
content = urllib2.urlopen(url).read()
|
||||||
|
with open(self.name, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
def error(self, message):
|
||||||
|
raise BuildError(self, message)
|
||||||
|
|
||||||
|
def graph(self, f, visited):
|
||||||
|
if self in visited:
|
||||||
|
return
|
||||||
|
visited.add(self)
|
||||||
|
for dependency in self.dependencies:
|
||||||
|
target = targets.get(dependency)
|
||||||
|
f.write('\t"%s" -> "%s";\n' % (self.name, target.name))
|
||||||
|
target.graph(f, visited)
|
||||||
|
|
||||||
|
def info(self, *args, **kwargs):
|
||||||
|
self.logger.info(*args, **kwargs)
|
||||||
|
|
||||||
|
def makedirs(self, path):
|
||||||
|
path = path % vars(variables)
|
||||||
|
if path and not os.path.exists(path):
|
||||||
|
self.info('mkdir -p %s', path)
|
||||||
|
os.makedirs(path)
|
||||||
|
|
||||||
|
def output(self, *args, **kwargs):
|
||||||
|
args = flatten_expand_list(args)
|
||||||
|
self.info(' '.join(args))
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(args, **kwargs)
|
||||||
|
with open(self.name, 'w') as f:
|
||||||
|
f.write(output)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
self.clean(recurse=False)
|
||||||
|
self.error(e)
|
||||||
|
|
||||||
|
def rm_rf(self, *args):
|
||||||
|
args = flatten_expand_list(args)
|
||||||
|
for arg in args:
|
||||||
|
self.info('rm -rf %s', arg)
|
||||||
|
shutil.rmtree(arg, ignore_errors=True)
|
||||||
|
|
||||||
|
def run(self, *args, **kwargs):
|
||||||
|
args = flatten_expand_list(args)
|
||||||
|
self.info(' '.join(args))
|
||||||
|
try:
|
||||||
|
subprocess.check_call(args, **kwargs)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
self.clean(recurse=False)
|
||||||
|
self.error(e)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def tempdir(self):
|
||||||
|
tempdir = tempfile.mkdtemp()
|
||||||
|
self.info('mkdir -p %s', tempdir)
|
||||||
|
try:
|
||||||
|
yield tempdir
|
||||||
|
finally:
|
||||||
|
self.info('rm -rf %s', tempdir)
|
||||||
|
shutil.rmtree(tempdir, ignore_errors=True)
|
||||||
|
|
||||||
|
def touch(self):
|
||||||
|
if os.path.exists(self.name):
|
||||||
|
os.utime(self.name, None)
|
||||||
|
else:
|
||||||
|
with open(self.name, 'w'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TargetCollection(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.default = None
|
||||||
|
self.targets = {}
|
||||||
|
|
||||||
|
def add(self, target):
|
||||||
|
if target.name in self.targets:
|
||||||
|
raise DuplicateTargetError(target)
|
||||||
|
self.targets[target.name] = target
|
||||||
|
if self.default is None:
|
||||||
|
self.default = target
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
if name in self.targets:
|
||||||
|
return self.targets[name]
|
||||||
|
target = None
|
||||||
|
for regexp, f in rules.iteritems():
|
||||||
|
match = regexp.search(name)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
if target is not None:
|
||||||
|
raise AmbiguousRuleError(name)
|
||||||
|
target = f(name, match)
|
||||||
|
if target is None:
|
||||||
|
target = Target(name, precious=True)
|
||||||
|
self.targets[name] = target
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
class VariableCollection(object):
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
for key, value in kwargs.iteritems():
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
if not hasattr(self, key):
|
||||||
|
object.__setattr__(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
|
targets = TargetCollection()
|
||||||
|
rules = {}
|
||||||
|
variables = VariableCollection(**os.environ)
|
||||||
|
|
||||||
|
|
||||||
|
def flatten(*args):
|
||||||
|
for arg in args:
|
||||||
|
if (isinstance(arg, collections.Iterable) and
|
||||||
|
not isinstance(arg, basestring)):
|
||||||
|
for element in flatten(*arg):
|
||||||
|
yield element
|
||||||
|
else:
|
||||||
|
yield arg
|
||||||
|
|
||||||
|
|
||||||
|
def flatten_expand_list(*args):
|
||||||
|
return list(arg % vars(variables) for arg in flatten(args))
|
||||||
|
|
||||||
|
|
||||||
|
def ifind(*paths):
|
||||||
|
for path in paths:
|
||||||
|
for dirpath, dirnames, names in os.walk(path):
|
||||||
|
for name in names:
|
||||||
|
yield os.path.join(dirpath, name)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=sys.argv):
|
||||||
|
option_parser = optparse.OptionParser()
|
||||||
|
option_parser.add_option('-c', '--clean',
|
||||||
|
action='store_true')
|
||||||
|
option_parser.add_option('-g', '--graph',
|
||||||
|
action='store_true')
|
||||||
|
option_parser.add_option('-n', '--dry-run', '--just-print', '--recon',
|
||||||
|
action='store_true')
|
||||||
|
option_parser.add_option('-r', '--really',
|
||||||
|
action='store_true')
|
||||||
|
option_parser.add_option('-v', '--verbose',
|
||||||
|
action='count', dest='logging_level')
|
||||||
|
option_parser.set_defaults(logging_level=0)
|
||||||
|
options, args = option_parser.parse_args(argv[1:])
|
||||||
|
logging.basicConfig(format='%(asctime)s %(name)s: %(message)s',
|
||||||
|
level=logging.INFO - 10 * options.logging_level)
|
||||||
|
targets_ = []
|
||||||
|
for arg in args:
|
||||||
|
match = re.match(r'(?P<key>\w+)=(?P<value>.*)\Z', arg)
|
||||||
|
if match:
|
||||||
|
key, value = match.group('key', 'value')
|
||||||
|
if not hasattr(variables, key):
|
||||||
|
logger.error('%s is not a variable', key)
|
||||||
|
logger.debug('%s=%r', key, value)
|
||||||
|
object.__setattr__(variables, key, value)
|
||||||
|
continue
|
||||||
|
targets_.append(arg)
|
||||||
|
if not targets_:
|
||||||
|
targets_ = (targets.default.name,)
|
||||||
|
try:
|
||||||
|
for target in targets_:
|
||||||
|
target = targets.get(target)
|
||||||
|
if options.clean:
|
||||||
|
target.clean(really=options.really, recurse=True)
|
||||||
|
elif options.graph:
|
||||||
|
sys.stdout.write('digraph "%s" {\n' % (target.name,))
|
||||||
|
target.graph(sys.stdout, set())
|
||||||
|
sys.stdout.write('}\n')
|
||||||
|
else:
|
||||||
|
target.build(dry_run=options.dry_run)
|
||||||
|
except BuildError as e:
|
||||||
|
logger.error(e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def output(*args):
|
||||||
|
args = flatten_expand_list(args)
|
||||||
|
logger.debug(' '.join(args))
|
||||||
|
return subprocess.check_output(args)
|
||||||
|
|
||||||
|
|
||||||
|
def rule(pattern):
|
||||||
|
def f(targetmaker):
|
||||||
|
rules[re.compile(pattern)] = targetmaker
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def target(name, *dependencies, **kwargs):
|
||||||
|
def f(action):
|
||||||
|
target = Target(name, action=action, dependencies=dependencies,
|
||||||
|
**kwargs)
|
||||||
|
targets.add(target)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def virtual(name, *dependencies, **kwargs):
|
||||||
|
target = Target(name, dependencies=dependencies, clean=False, phony=True,
|
||||||
|
**kwargs)
|
||||||
|
targets.add(target)
|
||||||
Reference in New Issue
Block a user