aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/buildgen
diff options
context:
space:
mode:
authorGravatar Nicolas Noble <nnoble@google.com>2015-01-06 18:08:25 -0800
committerGravatar Nicolas Noble <nnoble@google.com>2015-01-06 18:08:25 -0800
commitddef24620a67fa352d94415dc56121c01e3d8af8 (patch)
treef2383ee6e84a21e92f1524d23436ab28cfe04756 /tools/buildgen
parent9f2b09e112f5b95e843de786d7d3ecfd026170b6 (diff)
Adding the tools directory to the git export.
Diffstat (limited to 'tools/buildgen')
-rwxr-xr-xtools/buildgen/bunch.py37
-rwxr-xr-xtools/buildgen/generate_projects.sh48
-rwxr-xr-xtools/buildgen/mako_renderer.py105
-rwxr-xr-xtools/buildgen/plugins/expand_filegroups.py45
-rwxr-xr-xtools/buildgen/plugins/list_protos.py41
5 files changed, 276 insertions, 0 deletions
diff --git a/tools/buildgen/bunch.py b/tools/buildgen/bunch.py
new file mode 100755
index 0000000000..e859d53388
--- /dev/null
+++ b/tools/buildgen/bunch.py
@@ -0,0 +1,37 @@
+"""Allows dot-accessible dictionaries."""
+
+
+class Bunch(dict):
+
+ def __init__(self, d):
+ dict.__init__(self, d)
+ self.__dict__.update(d)
+
+
+# Converts any kind of variable to a Bunch
+def to_bunch(var):
+ if isinstance(var, list):
+ return [to_bunch(i) for i in var]
+ if isinstance(var, dict):
+ ret = {}
+ for k, v in var.items():
+ if isinstance(v, (list, dict)):
+ v = to_bunch(v)
+ ret[k] = v
+ return Bunch(ret)
+ else:
+ return var
+
+
+# Merges JSON 'add' into JSON 'dst'
+def merge_json(dst, add):
+ if isinstance(dst, dict) and isinstance(add, dict):
+ for k, v in add.items():
+ if k in dst:
+ merge_json(dst[k], v)
+ else:
+ dst[k] = v
+ elif isinstance(dst, list) and isinstance(add, list):
+ dst.extend(add)
+ else:
+ raise Exception('Tried to merge incompatible objects %r, %r' % (dst, add))
diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh
new file mode 100755
index 0000000000..f4e367d620
--- /dev/null
+++ b/tools/buildgen/generate_projects.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -ex
+
+if [ "x$TEST" == "x" ] ; then
+ TEST=false
+fi
+
+
+cd `dirname $0`/..
+mako_renderer=tools/buildgen/mako_renderer.py
+gen_build_json=test/core/end2end/gen_build_json.py
+
+end2end_test_build=`mktemp`
+$gen_build_json > $end2end_test_build
+
+global_plugins=`find ./tools/buildgen/plugins -name '*.py' |
+ sort | grep -v __init__ |
+ while read p ; do echo -n "-p $p " ; done`
+
+for dir in . ; do
+ local_plugins=`find $dir/templates -name '*.py' |
+ sort | grep -v __init__ |
+ while read p ; do echo -n "-p $p " ; done`
+
+ plugins="$global_plugins $local_plugins"
+
+ find -L $dir/templates -type f -and -name *.template | while read file ; do
+ out=${dir}/${file#$dir/templates/} # strip templates dir prefix
+ out=${out%.*} # strip template extension
+ json_files="build.json $end2end_test_build"
+ data=`for i in $json_files; do echo -n "-d $i "; done`
+ if [ $TEST == true ] ; then
+ actual_out=$out
+ out=`mktemp`
+ else
+ g4 open $out || true
+ fi
+ $mako_renderer $plugins $data -o $out $file
+ if [ $TEST == true ] ; then
+ diff -q $out $actual_out
+ rm $out
+ fi
+ done
+done
+
+rm $end2end_test_build
+
diff --git a/tools/buildgen/mako_renderer.py b/tools/buildgen/mako_renderer.py
new file mode 100755
index 0000000000..29c7cf0307
--- /dev/null
+++ b/tools/buildgen/mako_renderer.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python
+
+"""Simple Mako renderer.
+
+Just a wrapper around the mako rendering library.
+
+"""
+
+import getopt
+import imp
+import os
+import sys
+
+
+from mako.lookup import TemplateLookup
+from mako.runtime import Context
+from mako.template import Template
+import simplejson
+import bunch
+
+
+# Imports a plugin
+def import_plugin(name):
+ _, base_ex = os.path.split(name)
+ base, _ = os.path.splitext(base_ex)
+
+ with open(name, 'r') as plugin_file:
+ plugin_code = plugin_file.read()
+ plugin_module = imp.new_module(base)
+ exec plugin_code in plugin_module.__dict__
+ return plugin_module
+
+
+def out(msg):
+ print >> sys.stderr, msg
+
+
+def showhelp():
+ out('mako-renderer.py [-o out] [-m cache] [-d dict] [-d dict...] template')
+
+
+def main(argv):
+ got_input = False
+ module_directory = None
+ dictionary = {}
+ json_dict = {}
+ got_output = False
+ output_file = sys.stdout
+ plugins = []
+
+ try:
+ opts, args = getopt.getopt(argv, 'hm:d:o:p:')
+ except getopt.GetoptError:
+ out('Unknown option')
+ showhelp()
+ sys.exit(2)
+
+ for opt, arg in opts:
+ if opt == '-h':
+ out('Displaying showhelp')
+ showhelp()
+ sys.exit()
+ elif opt == '-o':
+ if got_output:
+ out('Got more than one output')
+ showhelp()
+ sys.exit(3)
+ got_output = True
+ output_file = open(arg, 'w')
+ elif opt == '-m':
+ if module_directory is not None:
+ out('Got more than one cache directory')
+ showhelp()
+ sys.exit(4)
+ module_directory = arg
+ elif opt == '-d':
+ dict_file = open(arg, 'r')
+ bunch.merge_json(json_dict, simplejson.loads(dict_file.read()))
+ dict_file.close()
+ elif opt == '-p':
+ plugins.append(import_plugin(arg))
+
+ for plugin in plugins:
+ plugin.mako_plugin(json_dict)
+
+ for k, v in json_dict.items():
+ dictionary[k] = bunch.to_bunch(v)
+
+ ctx = Context(output_file, **dictionary)
+
+ for arg in args:
+ got_input = True
+ template = Template(filename=arg,
+ module_directory=module_directory,
+ lookup=TemplateLookup(directories=['.']))
+ template.render_context(ctx)
+
+ if not got_input:
+ out('Got nothing to do')
+ showhelp()
+
+ output_file.close()
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/tools/buildgen/plugins/expand_filegroups.py b/tools/buildgen/plugins/expand_filegroups.py
new file mode 100755
index 0000000000..108debefd5
--- /dev/null
+++ b/tools/buildgen/plugins/expand_filegroups.py
@@ -0,0 +1,45 @@
+"""Buildgen expand filegroups plugin.
+
+This takes the list of libs from our json dictionary,
+and expands any and all filegroup.
+
+"""
+
+
+def excluded(filename, exclude_res):
+ for r in exclude_res:
+ if r.search(filename):
+ return True
+ return False
+
+
+def mako_plugin(dictionary):
+ """The exported plugin code for expand_filegroups.
+
+ The list of libs in the build.json file can contain "filegroups" tags.
+ These refer to the filegroups in the root object. We will expand and
+ merge filegroups on the src, headers and public_headers properties.
+
+ """
+ libs = dictionary.get('libs')
+ filegroups_list = dictionary.get('filegroups')
+ filegroups = {}
+
+ for fg in filegroups_list:
+ filegroups[fg['name']] = fg
+
+ for lib in libs:
+ for fg_name in lib.get('filegroups', []):
+ fg = filegroups[fg_name]
+
+ src = lib.get('src', [])
+ src.extend(fg.get('src', []))
+ lib['src'] = src
+
+ headers = lib.get('headers', [])
+ headers.extend(fg.get('headers', []))
+ lib['headers'] = headers
+
+ public_headers = lib.get('public_headers', [])
+ public_headers.extend(fg.get('public_headers', []))
+ lib['public_headers'] = public_headers
diff --git a/tools/buildgen/plugins/list_protos.py b/tools/buildgen/plugins/list_protos.py
new file mode 100755
index 0000000000..c5a09dd4d0
--- /dev/null
+++ b/tools/buildgen/plugins/list_protos.py
@@ -0,0 +1,41 @@
+"""Buildgen .proto files list plugin.
+
+This parses the list of targets from the json build file, and creates
+a list called "protos" that contains all of the proto file names.
+
+"""
+
+
+import re
+
+
+def mako_plugin(dictionary):
+ """The exported plugin code for list_protos.
+
+ Some projects generators may want to get the full list of unique .proto files
+ that are being included in a project. This code extracts all files referenced
+ in any library or target that ends in .proto, and builds and exports that as
+ a list called "protos".
+
+ """
+
+ libs = dictionary.get('libs', [])
+ targets = dictionary.get('targets', [])
+
+ proto_re = re.compile('(.*)\\.proto')
+
+ protos = set()
+ for lib in libs:
+ for src in lib.get('src', []):
+ m = proto_re.match(src)
+ if m:
+ protos.add(m.group(1))
+ for tgt in targets:
+ for src in tgt.get('src', []):
+ m = proto_re.match(src)
+ if m:
+ protos.add(m.group(1))
+
+ protos = sorted(protos)
+
+ dictionary['protos'] = protos