root / autotools / build-rpc @ a09f9847
History | View | Annotate | Download (4.9 kB)
1 |
#!/usr/bin/python |
---|---|
2 |
# |
3 |
|
4 |
# Copyright (C) 2011 Google Inc. |
5 |
# |
6 |
# This program is free software; you can redistribute it and/or modify |
7 |
# it under the terms of the GNU General Public License as published by |
8 |
# the Free Software Foundation; either version 2 of the License, or |
9 |
# (at your option) any later version. |
10 |
# |
11 |
# This program is distributed in the hope that it will be useful, but |
12 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
# General Public License for more details. |
15 |
# |
16 |
# You should have received a copy of the GNU General Public License |
17 |
# along with this program; if not, write to the Free Software |
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 |
# 02110-1301, USA. |
20 |
|
21 |
|
22 |
"""Script to generate RPC code. |
23 |
|
24 |
""" |
25 |
|
26 |
# pylint: disable=C0103 |
27 |
# [C0103] Invalid name |
28 |
|
29 |
import sys |
30 |
import re |
31 |
import itertools |
32 |
import textwrap |
33 |
from cStringIO import StringIO |
34 |
|
35 |
from ganeti import utils |
36 |
from ganeti import compat |
37 |
from ganeti import build |
38 |
|
39 |
|
40 |
_SINGLE = "single-node" |
41 |
_MULTI = "multi-node" |
42 |
|
43 |
|
44 |
def _WritePreamble(sw): |
45 |
"""Writes a preamble for the RPC wrapper output. |
46 |
|
47 |
""" |
48 |
sw.Write("# This code is automatically generated at build time.") |
49 |
sw.Write("# Do not modify manually.") |
50 |
sw.Write("") |
51 |
sw.Write("\"\"\"Automatically generated RPC client wrappers.") |
52 |
sw.Write("") |
53 |
sw.Write("\"\"\"") |
54 |
sw.Write("") |
55 |
|
56 |
|
57 |
def _WrapCode(line): |
58 |
"""Wraps Python code. |
59 |
|
60 |
""" |
61 |
return textwrap.wrap(line, width=70, expand_tabs=False, |
62 |
fix_sentence_endings=False, break_long_words=False, |
63 |
replace_whitespace=True, |
64 |
subsequent_indent=utils.ShellWriter.INDENT_STR) |
65 |
|
66 |
|
67 |
def _WriteDocstring(sw, name, timeout, kind, args, desc): |
68 |
"""Writes a docstring for an RPC wrapper. |
69 |
|
70 |
""" |
71 |
sw.Write("\"\"\"Wrapper for RPC call '%s'", name) |
72 |
sw.Write("") |
73 |
if desc: |
74 |
sw.Write(desc) |
75 |
sw.Write("") |
76 |
|
77 |
note = ["This is a %s call" % kind] |
78 |
if timeout: |
79 |
note.append(" with a timeout of %s" % utils.FormatSeconds(timeout)) |
80 |
sw.Write("@note: %s", "".join(note)) |
81 |
|
82 |
if kind == _SINGLE: |
83 |
sw.Write("@type node: string") |
84 |
sw.Write("@param node: Node name") |
85 |
else: |
86 |
sw.Write("@type node_list: list of string") |
87 |
sw.Write("@param node_list: List of node names") |
88 |
|
89 |
if args: |
90 |
for (argname, _, argtext) in args: |
91 |
if argtext: |
92 |
docline = "@param %s: %s" % (argname, argtext) |
93 |
for line in _WrapCode(docline): |
94 |
sw.Write(line) |
95 |
sw.Write("") |
96 |
sw.Write("\"\"\"") |
97 |
|
98 |
|
99 |
def _WriteBaseClass(sw, clsname, calls): |
100 |
"""Write RPC wrapper class. |
101 |
|
102 |
""" |
103 |
sw.Write("") |
104 |
sw.Write("class %s(object):", clsname) |
105 |
sw.IncIndent() |
106 |
try: |
107 |
sw.Write("# E1101: Non-existent members") |
108 |
sw.Write("# R0904: Too many public methods") |
109 |
sw.Write("# pylint: disable=E1101,R0904") |
110 |
|
111 |
if not calls: |
112 |
sw.Write("pass") |
113 |
return |
114 |
|
115 |
for (name, kind, timeout, args, postproc, desc) in calls: |
116 |
funcargs = ["self"] |
117 |
|
118 |
if kind == _SINGLE: |
119 |
funcargs.append("node") |
120 |
elif kind == _MULTI: |
121 |
funcargs.append("node_list") |
122 |
else: |
123 |
raise Exception("Unknown kind '%s'" % kind) |
124 |
|
125 |
funcargs.extend(map(compat.fst, args)) |
126 |
|
127 |
assert "read_timeout" not in funcargs |
128 |
funcargs.append("read_timeout=%s" % timeout) |
129 |
|
130 |
funcdef = "def call_%s(%s):" % (name, utils.CommaJoin(funcargs)) |
131 |
for line in _WrapCode(funcdef): |
132 |
sw.Write(line) |
133 |
|
134 |
sw.IncIndent() |
135 |
try: |
136 |
_WriteDocstring(sw, name, timeout, kind, args, desc) |
137 |
|
138 |
buf = StringIO() |
139 |
buf.write("return ") |
140 |
|
141 |
# In case line gets too long and is wrapped in a bad spot |
142 |
buf.write("( ") |
143 |
|
144 |
if postproc: |
145 |
buf.write("%s(" % postproc) |
146 |
buf.write("self._Call(") |
147 |
if kind == _SINGLE: |
148 |
buf.write("[node]") |
149 |
else: |
150 |
buf.write("node_list") |
151 |
|
152 |
buf.write(", \"%s\", read_timeout, [%s], [%s])" % |
153 |
(name, |
154 |
# Argument definitions |
155 |
utils.CommaJoin(map(compat.snd, args)), |
156 |
# Function arguments |
157 |
utils.CommaJoin(map(compat.fst, args)))) |
158 |
|
159 |
if kind == _SINGLE: |
160 |
buf.write("[node]") |
161 |
if postproc: |
162 |
buf.write(")") |
163 |
buf.write(")") |
164 |
|
165 |
for line in _WrapCode(buf.getvalue()): |
166 |
sw.Write(line) |
167 |
finally: |
168 |
sw.DecIndent() |
169 |
sw.Write("") |
170 |
finally: |
171 |
sw.DecIndent() |
172 |
|
173 |
|
174 |
def main(): |
175 |
"""Main function. |
176 |
|
177 |
""" |
178 |
buf = StringIO() |
179 |
sw = utils.ShellWriter(buf) |
180 |
|
181 |
_WritePreamble(sw) |
182 |
|
183 |
for filename in sys.argv[1:]: |
184 |
sw.Write("# Definitions from '%s'", filename) |
185 |
|
186 |
module = build.LoadModule(filename) |
187 |
|
188 |
# Call types are re-defined in definitions file to avoid imports. Verify |
189 |
# here to ensure they're equal to local constants. |
190 |
assert module.SINGLE == _SINGLE |
191 |
assert module.MULTI == _MULTI |
192 |
|
193 |
for (clsname, calls) in module.CALLS.items(): |
194 |
_WriteBaseClass(sw, clsname, calls.values()) |
195 |
|
196 |
print buf.getvalue() |
197 |
|
198 |
|
199 |
if __name__ == "__main__": |
200 |
main() |