diff options
Diffstat (limited to 'grpc/tools/buildgen/_mako_renderer.py')
-rwxr-xr-x | grpc/tools/buildgen/_mako_renderer.py | 172 |
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:]) |