#!/usr/bin/env python import datetime import glob import os import rdflib import shutil import subprocess import sys from waflib.extras import autowaf as autowaf import waflib.Logs as Logs import waflib.Options as Options # Version of this package (even if built as a child) LV2EXT_VERSION = datetime.date.isoformat(datetime.datetime.now()).replace('-', '.') # Variables for 'waf dist' APPNAME = 'lv2world' VERSION = LV2EXT_VERSION # Mandatory variables top = '.' out = 'build' def options(opt): opt.load('compiler_cc') opt.load('compiler_cxx') autowaf.set_options(opt) opt.add_option('--test', action='store_true', default=False, dest='build_tests', help="Build unit tests") opt.add_option('--experimental', action='store_true', default=False, dest='experimental', help='Install unreleased experimental extensions') for i in ['lv2/lv2plug.in/ns/lv2core']: opt.recurse(i) def get_subdirs(with_plugins=True): subdirs = ['lv2/lv2plug.in/ns/lv2core/'] subdirs += glob.glob('lv2/lv2plug.in/ns/ext/*/') subdirs += glob.glob('lv2/lv2plug.in/ns/extensions/*/') if with_plugins: subdirs += glob.glob('plugins/*/') return subdirs def configure(conf): conf.load('compiler_cc') conf.load('compiler_cxx') autowaf.configure(conf) autowaf.set_recursive() conf.env.append_unique('CFLAGS', '-std=c99') subdirs = get_subdirs() for i in subdirs: conf.recurse(i) conf.env['LV2_SUBDIRS'] = subdirs # Rule for copying a file to the build directory def copy(task): shutil.copy(task.inputs[0].abspath(), task.outputs[0].abspath()) def chop_lv2_prefix(s): if s.startswith('lv2/lv2plug.in/'): return s[len('lv2/lv2plug.in/'):] return s # Rule for calling lv2specgen on a spec bundle def specgen(task): import rdflib doap = rdflib.Namespace('http://usefulinc.com/ns/doap#') lv2 = rdflib.Namespace('http://lv2plug.in/ns/lv2core#') owl = rdflib.Namespace('http://www.w3.org/2002/07/owl#') rdf = rdflib.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#') sys.path.append("./lv2specgen") import lv2specgen spec = task.inputs[0] path = os.path.dirname(spec.srcpath()) indir = os.path.dirname(spec.abspath()) outdir = os.path.abspath(os.path.join(out, chop_lv2_prefix(path))) bundle = str(outdir) b = os.path.basename(outdir) if not os.access(spec.abspath(), os.R_OK): print('warning: extension %s has no %s.ttl file' % (root, root)) return try: model = rdflib.ConjunctiveGraph() for i in glob.glob('%s/*.ttl' % bundle): model.parse(i, format='n3') except: e = sys.exc_info()[1] print('error parsing %s: %s' % (bundle, str(e))) return # Get extension URI ext_node = model.value(None, rdf.type, lv2.Specification) if not ext_node: print('no extension found in %s' % bundle) return ext = str(ext_node) # Get version minor = 0 micro = 0 try: minor = int(model.value(ext_node, lv2.minorVersion, None)) micro = int(model.value(ext_node, lv2.microVersion, None)) except Exception as e: print("warning: %s: failed to find version for %s" % (bundle, ext)) # Get date date = None for r in model.triples([ext_node, doap.release, None]): revision = model.value(r[2], doap.revision, None) if revision == ("%d.%d" % (minor, micro)): date = model.value(r[2], doap.created, None) break # Verify that this date is the latest for r in model.triples([ext_node, doap.release, None]): revision = model.value(r[2], doap.revision, None) this_date = model.value(r[2], doap.created, None) if this_date > date: print("warning: revision %d.%d (%s) is not the latest release" % ( minor, micro, date)) break # Get short description shortdesc = model.value(ext_node, doap.shortdesc, None) SPECGENDIR = 'lv2specgen' STYLEPATH = 'build/aux/style.css' TAGFILE = 'build/tags' specdoc = lv2specgen.specgen( spec.abspath(), SPECGENDIR, os.path.relpath('doc', bundle), os.path.relpath(STYLEPATH, bundle), os.path.abspath('build'), 'doc/html/', TAGFILE, instances=True) lv2specgen.save(task.outputs[0].abspath(), specdoc) # Name (comment is to act as a sort key) row = '%s' % ( b, path[len('lv2/lv2plug.in/ns/'):], b) # Description if shortdesc: row += '' + str(shortdesc) + '' else: row += '' # Version version_str = '%s.%s' % (minor, micro) if minor == 0 or (micro % 2 != 0): row += '' + version_str + '' else: row += '' + version_str + '' # Date row += '%s' % (str(date) if date else '') # Status deprecated = model.value(ext_node, owl.deprecated, None) if minor == 0: row += 'Experimental' elif deprecated and str(deprecated[2]) != "false": row += 'Deprecated' elif micro % 2 == 0: row += 'Stable' row += '' index = open(os.path.join('build', 'index_rows', b), 'w') index.write(row) index.close() def subst_file(template, output, dict): i = open(template, 'r') o = open(output, 'w') for line in i: for key in dict: line = line.replace(key, dict[key]) o.write(line) i.close() o.close() # Task to build extension index def build_index(task): global index_lines rows = [] for f in task.inputs: if not f.abspath().endswith('index.html.in'): rowfile = open(f.abspath(), 'r') rows += rowfile.readlines() rowfile.close() subst_file(task.inputs[0].abspath(), task.outputs[0].abspath(), { '@ROWS@': ''.join(rows), '@TIME@': datetime.datetime.utcnow().strftime('%F %H:%M UTC') }) def build(bld): for i in bld.env['LV2_SUBDIRS']: bld.recurse(i) if bld.env['DOCS']: # Build Doxygen documentation (and tags file) autowaf.build_dox(bld, 'LV2', VERSION, top, out) # Copy stylesheet to build directory obj = bld(rule = copy, name = 'copy', source = 'doc/style.css', target = 'aux/style.css') index_files = [] # Generate .htaccess files (and directory skeleton) for i in bld.env['LV2_SUBDIRS']: if i.startswith('lv2/lv2plug.in'): # Copy spec files to build dir for f in bld.path.ant_glob(i + '*.*'): obj = bld(rule = copy, name = 'copy', source = f, target = chop_lv2_prefix(f.srcpath())) base = i[len('lv2/lv2plug.in'):] name = os.path.basename(i[:len(i)-1]) index_file = os.path.join('index_rows', name) index_files += [index_file] # Generate .htaccess file obj = bld(features = 'subst', source = 'doc/htaccess.in', target = os.path.join(base, '.htaccess'), install_path = None, NAME = name, BASE = base) bld.add_group() # Call lv2specgen to generate spec docs obj = bld(rule = specgen, name = 'specgen', source = os.path.join(i, name + '.ttl'), target = ['%s%s.html' % (chop_lv2_prefix(i), name), index_file]) # Build extension index obj = bld(rule = build_index, name = 'index', source = ['lv2/lv2plug.in/ns/index.html.in'] + index_files, target = 'ns/index.html') def release(ctx): lv2 = rdflib.Namespace('http://lv2plug.in/ns/lv2core#') rdf = rdflib.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#') doap = rdflib.Namespace('http://usefulinc.com/ns/doap#') try: shutil.rmtree('build/spec') except: pass os.makedirs('build/spec') manifests = glob.glob('lv2/lv2plug.in/ns/lv2core/manifest.ttl') manifests += glob.glob('lv2/lv2plug.in/ns/*/*/manifest.ttl') for manifest in manifests: dir = os.path.dirname(manifest) name = os.path.basename(dir).replace('.lv2', '') m = rdflib.ConjunctiveGraph() m.parse(manifest, format='n3') uri = minor = micro = None try: spec = m.value(None, rdf.type, lv2.Specification) uri = str(spec) minor = int(m.value(spec, lv2.minorVersion, None)) micro = int(m.value(spec, lv2.microVersion, None)) except: e = sys.exc_info()[1] Logs.error('error: %s: %s' % (manifest, str(e))) continue if minor != 0 and micro % 2 == 0: autowaf.display_header('\nBuilding %s Release\n' % dir) try: subprocess.call( ['./waf', 'distclean', 'configure', 'build', 'distcheck'], cwd=dir) for i in glob.glob(dir + '/*.tar.bz2'): shutil.move(i, 'build/spec') except: Logs.error('Error building %s release' % (name, e)) subprocess.call(['./waf', 'distclean'], cwd=dir) def news(ctx): ctx.recurse(get_subdirs(False)) def lint(ctx): for i in (['lv2/lv2plug.in/ns/lv2core/lv2.h'] + glob.glob('lv2/lv2plug.in/ns/ext/*/*.h') + glob.glob('lv2/lv2plug.in/ns/extensions/*/*.h')): subprocess.call('cpplint.py --filter=+whitespace/comments,-whitespace/tab,-whitespace/braces,-whitespace/labels,-whitespace/blank_line,-build/header_guard,-readability/casting,-readability/todo,-build/include ' + i, shell=True)