1#!/usr/bin/env python2.7 2# Copyright 2015 gRPC authors. 3# 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 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 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. 15"""Simple Mako renderer. 16 17Just a wrapper around the mako rendering library. 18 19""" 20 21import getopt 22import imp 23import os 24import cPickle as pickle 25import shutil 26import sys 27 28from mako.lookup import TemplateLookup 29from mako.runtime import Context 30from mako.template import Template 31import bunch 32import yaml 33 34 35# Imports a plugin 36def import_plugin(name): 37 _, base_ex = os.path.split(name) 38 base, _ = os.path.splitext(base_ex) 39 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 45 46 47def out(msg): 48 print >> sys.stderr, msg 49 50 51def showhelp(): 52 out('mako-renderer.py [-o out] [-m cache] [-P preprocessed_input] [-d dict] [-d dict...]' 53 ' [-t template] [-w preprocessed_output]') 54 55 56def main(argv): 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 67 68 try: 69 opts, args = getopt.getopt(argv, 'hM:m:d:o:p:t:P:w:') 70 except getopt.GetoptError: 71 out('Unknown option') 72 showhelp() 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 == {} 102 sys.path.insert(0, 103 os.path.abspath( 104 os.path.join( 105 os.path.dirname(sys.argv[0]), 'plugins'))) 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') 187 showhelp() 188 189 190if __name__ == '__main__': 191 main(sys.argv[1:]) 192