• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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