Nathaniel Manista | ae4fbcd | 2015-09-23 16:29:44 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python2.7 |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 2 | # Copyright 2015 gRPC authors. |
Craig Tiller | c2c7921 | 2015-02-16 12:00:01 -0800 | [diff] [blame] | 3 | # |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
Craig Tiller | c2c7921 | 2015-02-16 12:00:01 -0800 | [diff] [blame] | 7 | # |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
Craig Tiller | c2c7921 | 2015-02-16 12:00:01 -0800 | [diff] [blame] | 9 | # |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 15 | """Simple Mako renderer. |
| 16 | |
| 17 | Just a wrapper around the mako rendering library. |
| 18 | |
| 19 | """ |
| 20 | |
| 21 | import getopt |
| 22 | import imp |
| 23 | import os |
Craig Tiller | 560c901 | 2016-02-24 16:34:38 -0800 | [diff] [blame] | 24 | import cPickle as pickle |
Craig Tiller | 1ebb7c8 | 2015-08-31 15:53:36 -0700 | [diff] [blame] | 25 | import shutil |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 26 | import sys |
| 27 | |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 28 | from mako.lookup import TemplateLookup |
| 29 | from mako.runtime import Context |
| 30 | from mako.template import Template |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 31 | import bunch |
Craig Tiller | 1ebb7c8 | 2015-08-31 15:53:36 -0700 | [diff] [blame] | 32 | import yaml |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 33 | |
| 34 | |
| 35 | # Imports a plugin |
| 36 | def import_plugin(name): |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 37 | _, base_ex = os.path.split(name) |
| 38 | base, _ = os.path.splitext(base_ex) |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 39 | |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 40 | with open(name, 'r') as plugin_file: |
| 41 | plugin_code = plugin_file.read() |
| 42 | plugin_module = imp.new_module(base) |
| 43 | exec plugin_code in plugin_module.__dict__ |
| 44 | return plugin_module |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 45 | |
| 46 | |
| 47 | def out(msg): |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 48 | print >> sys.stderr, msg |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 49 | |
| 50 | |
| 51 | def showhelp(): |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 52 | out('mako-renderer.py [-o out] [-m cache] [-P preprocessed_input] [-d dict] [-d dict...]' |
| 53 | ' [-t template] [-w preprocessed_output]') |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 54 | |
| 55 | |
| 56 | def main(argv): |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 57 | got_input = False |
| 58 | module_directory = None |
| 59 | preprocessed_output = None |
| 60 | dictionary = {} |
| 61 | json_dict = {} |
| 62 | got_output = False |
| 63 | plugins = [] |
| 64 | output_name = None |
| 65 | got_preprocessed_input = False |
| 66 | output_merged = None |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 67 | |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 68 | try: |
| 69 | opts, args = getopt.getopt(argv, 'hM:m:d:o:p:t:P:w:') |
| 70 | except getopt.GetoptError: |
| 71 | out('Unknown option') |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 72 | showhelp() |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 73 | sys.exit(2) |
| 74 | |
| 75 | for opt, arg in opts: |
| 76 | if opt == '-h': |
| 77 | out('Displaying showhelp') |
| 78 | showhelp() |
| 79 | sys.exit() |
| 80 | elif opt == '-o': |
| 81 | if got_output: |
| 82 | out('Got more than one output') |
| 83 | showhelp() |
| 84 | sys.exit(3) |
| 85 | got_output = True |
| 86 | output_name = arg |
| 87 | elif opt == '-m': |
| 88 | if module_directory is not None: |
| 89 | out('Got more than one cache directory') |
| 90 | showhelp() |
| 91 | sys.exit(4) |
| 92 | module_directory = arg |
| 93 | elif opt == '-M': |
| 94 | if output_merged is not None: |
| 95 | out('Got more than one output merged path') |
| 96 | showhelp() |
| 97 | sys.exit(5) |
| 98 | output_merged = arg |
| 99 | elif opt == '-P': |
| 100 | assert not got_preprocessed_input |
| 101 | assert json_dict == {} |
Mehrdad Afshari | 87cd994 | 2018-01-02 14:40:00 -0800 | [diff] [blame] | 102 | sys.path.insert(0, |
| 103 | os.path.abspath( |
| 104 | os.path.join( |
| 105 | os.path.dirname(sys.argv[0]), 'plugins'))) |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 106 | with open(arg, 'r') as dict_file: |
| 107 | dictionary = pickle.load(dict_file) |
| 108 | got_preprocessed_input = True |
| 109 | elif opt == '-d': |
| 110 | assert not got_preprocessed_input |
| 111 | with open(arg, 'r') as dict_file: |
| 112 | bunch.merge_json(json_dict, yaml.load(dict_file.read())) |
| 113 | elif opt == '-p': |
| 114 | plugins.append(import_plugin(arg)) |
| 115 | elif opt == '-w': |
| 116 | preprocessed_output = arg |
| 117 | |
| 118 | if not got_preprocessed_input: |
| 119 | for plugin in plugins: |
| 120 | plugin.mako_plugin(json_dict) |
| 121 | if output_merged: |
| 122 | with open(output_merged, 'w') as yaml_file: |
| 123 | yaml_file.write(yaml.dump(json_dict)) |
| 124 | for k, v in json_dict.items(): |
| 125 | dictionary[k] = bunch.to_bunch(v) |
| 126 | |
| 127 | if preprocessed_output: |
| 128 | with open(preprocessed_output, 'w') as dict_file: |
| 129 | pickle.dump(dictionary, dict_file) |
| 130 | |
| 131 | cleared_dir = False |
| 132 | for arg in args: |
| 133 | got_input = True |
| 134 | with open(arg) as f: |
| 135 | srcs = list(yaml.load_all(f.read())) |
| 136 | for src in srcs: |
| 137 | if isinstance(src, basestring): |
| 138 | assert len(srcs) == 1 |
| 139 | template = Template( |
| 140 | src, |
| 141 | filename=arg, |
| 142 | module_directory=module_directory, |
| 143 | lookup=TemplateLookup(directories=['.'])) |
| 144 | with open(output_name, 'w') as output_file: |
| 145 | template.render_context(Context(output_file, **dictionary)) |
| 146 | else: |
| 147 | # we have optional control data: this template represents |
| 148 | # a directory |
| 149 | if not cleared_dir: |
| 150 | if not os.path.exists(output_name): |
| 151 | pass |
| 152 | elif os.path.isfile(output_name): |
| 153 | os.unlink(output_name) |
| 154 | else: |
| 155 | shutil.rmtree(output_name, ignore_errors=True) |
| 156 | cleared_dir = True |
| 157 | items = [] |
| 158 | if 'foreach' in src: |
| 159 | for el in dictionary[src['foreach']]: |
| 160 | if 'cond' in src: |
| 161 | args = dict(dictionary) |
| 162 | args['selected'] = el |
| 163 | if not eval(src['cond'], {}, args): |
| 164 | continue |
| 165 | items.append(el) |
| 166 | assert items |
| 167 | else: |
| 168 | items = [None] |
| 169 | for item in items: |
| 170 | args = dict(dictionary) |
| 171 | args['selected'] = item |
| 172 | item_output_name = os.path.join( |
| 173 | output_name, |
| 174 | Template(src['output_name']).render(**args)) |
| 175 | if not os.path.exists(os.path.dirname(item_output_name)): |
| 176 | os.makedirs(os.path.dirname(item_output_name)) |
| 177 | template = Template( |
| 178 | src['template'], |
| 179 | filename=arg, |
| 180 | module_directory=module_directory, |
| 181 | lookup=TemplateLookup(directories=['.'])) |
| 182 | with open(item_output_name, 'w') as output_file: |
| 183 | template.render_context(Context(output_file, **args)) |
| 184 | |
| 185 | if not got_input and not preprocessed_output: |
| 186 | out('Got nothing to do') |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 187 | showhelp() |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 188 | |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 189 | |
Nicolas Noble | ddef246 | 2015-01-06 18:08:25 -0800 | [diff] [blame] | 190 | if __name__ == '__main__': |
ncteisen | 26d70b1 | 2017-12-11 16:40:56 -0800 | [diff] [blame] | 191 | main(sys.argv[1:]) |