summaryrefslogtreecommitdiff
path: root/grpc/tools/buildgen/_mako_renderer.py
diff options
context:
space:
mode:
Diffstat (limited to 'grpc/tools/buildgen/_mako_renderer.py')
-rwxr-xr-xgrpc/tools/buildgen/_mako_renderer.py172
1 files changed, 172 insertions, 0 deletions
diff --git a/grpc/tools/buildgen/_mako_renderer.py b/grpc/tools/buildgen/_mako_renderer.py
new file mode 100755
index 00000000..77c3c49f
--- /dev/null
+++ b/grpc/tools/buildgen/_mako_renderer.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Simple Mako renderer.
+
+Just a wrapper around the mako rendering library.
+"""
+
+import getopt
+import glob
+import importlib.util
+import os
+import pickle
+import shutil
+import sys
+from typing import List
+
+import yaml
+from mako import exceptions
+from mako.lookup import TemplateLookup
+from mako.runtime import Context
+from mako.template import Template
+
+PROJECT_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..",
+ "..")
+# TODO(lidiz) find a better way for plugins to reference each other
+sys.path.append(os.path.join(PROJECT_ROOT, 'tools', 'buildgen', 'plugins'))
+
+
+def out(msg: str) -> None:
+ print(msg, file=sys.stderr)
+
+
+def showhelp() -> None:
+ out('mako-renderer.py [-o out] [-m cache] [-P preprocessed_input] [-d dict] [-d dict...]'
+ ' [-t template] [-w preprocessed_output]')
+
+
+def render_template(template: Template, context: Context) -> None:
+ """Render the mako template with given context.
+
+ Prints an error template to indicate where and what in the template caused
+ the render failure.
+ """
+ try:
+ template.render_context(context)
+ except:
+ out(exceptions.text_error_template().render())
+ raise
+
+
+def main(argv: List[str]) -> None:
+ got_input = False
+ module_directory = None
+ preprocessed_output = None
+ dictionary = {}
+ json_dict = {}
+ got_output = False
+ output_name = None
+ got_preprocessed_input = False
+ output_merged = None
+
+ try:
+ opts, args = getopt.getopt(argv, 'hM:m:o:t: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_name = arg
+ 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 == '-M':
+ if output_merged is not None:
+ out('Got more than one output merged path')
+ showhelp()
+ sys.exit(5)
+ output_merged = arg
+ elif opt == '-P':
+ assert not got_preprocessed_input
+ assert json_dict == {}
+ with open(arg, 'rb') as dict_file:
+ dictionary = pickle.load(dict_file)
+ got_preprocessed_input = True
+
+ cleared_dir = False
+ for arg in args:
+ got_input = True
+ with open(arg) as f:
+ srcs = list(yaml.load_all(f.read(), Loader=yaml.FullLoader))
+ for src in srcs:
+ if isinstance(src, str):
+ assert len(srcs) == 1
+ template = Template(src,
+ filename=arg,
+ module_directory=module_directory,
+ lookup=TemplateLookup(directories=['.']))
+ with open(output_name, 'w') as output_file:
+ render_template(template, Context(output_file,
+ **dictionary))
+ else:
+ # we have optional control data: this template represents
+ # a directory
+ if not cleared_dir:
+ if not os.path.exists(output_name):
+ pass
+ elif os.path.isfile(output_name):
+ os.unlink(output_name)
+ else:
+ shutil.rmtree(output_name, ignore_errors=True)
+ cleared_dir = True
+ items = []
+ if 'foreach' in src:
+ for el in dictionary[src['foreach']]:
+ if 'cond' in src:
+ args = dict(dictionary)
+ args['selected'] = el
+ if not eval(src['cond'], {}, args):
+ continue
+ items.append(el)
+ assert items
+ else:
+ items = [None]
+ for item in items:
+ args = dict(dictionary)
+ args['selected'] = item
+ item_output_name = os.path.join(
+ output_name,
+ Template(src['output_name']).render(**args))
+ if not os.path.exists(os.path.dirname(item_output_name)):
+ os.makedirs(os.path.dirname(item_output_name))
+ template = Template(
+ src['template'],
+ filename=arg,
+ module_directory=module_directory,
+ lookup=TemplateLookup(directories=['.']))
+ with open(item_output_name, 'w') as output_file:
+ render_template(template, Context(output_file, **args))
+
+ if not got_input and not preprocessed_output:
+ out('Got nothing to do')
+ showhelp()
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])