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( 103 0, 104 os.path.abspath( 105 os.path.join(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(src, 140 filename=arg, 141 module_directory=module_directory, 142 lookup=TemplateLookup(directories=['.'])) 143 with open(output_name, 'w') as output_file: 144 template.render_context(Context(output_file, **dictionary)) 145 else: 146 # we have optional control data: this template represents 147 # a directory 148 if not cleared_dir: 149 if not os.path.exists(output_name): 150 pass 151 elif os.path.isfile(output_name): 152 os.unlink(output_name) 153 else: 154 shutil.rmtree(output_name, ignore_errors=True) 155 cleared_dir = True 156 items = [] 157 if 'foreach' in src: 158 for el in dictionary[src['foreach']]: 159 if 'cond' in src: 160 args = dict(dictionary) 161 args['selected'] = el 162 if not eval(src['cond'], {}, args): 163 continue 164 items.append(el) 165 assert items 166 else: 167 items = [None] 168 for item in items: 169 args = dict(dictionary) 170 args['selected'] = item 171 item_output_name = os.path.join( 172 output_name, 173 Template(src['output_name']).render(**args)) 174 if not os.path.exists(os.path.dirname(item_output_name)): 175 os.makedirs(os.path.dirname(item_output_name)) 176 template = Template( 177 src['template'], 178 filename=arg, 179 module_directory=module_directory, 180 lookup=TemplateLookup(directories=['.'])) 181 with open(item_output_name, 'w') as output_file: 182 template.render_context(Context(output_file, **args)) 183 184 if not got_input and not preprocessed_output: 185 out('Got nothing to do') 186 showhelp() 187 188 189if __name__ == '__main__': 190 main(sys.argv[1:]) 191