• 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(
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