ovsdb-idlc: Remove "sha" deprecation warning
[sliver-openvswitch.git] / ovsdb / ovsdb-idlc.in
1 #! @PYTHON@
2
3 import getopt
4 import re
5 import sys
6
7 sys.path.insert(0, "@abs_top_srcdir@/ovsdb")
8 import simplejson as json
9
10 argv0 = sys.argv[0]
11
12 class Error(Exception):
13     def __init__(self, msg):
14         Exception.__init__(self)
15         self.msg = msg
16
17 def getMember(json, name, validTypes, description, default=None):
18     if name in json:
19         member = json[name]
20         if type(member) not in validTypes:
21             raise Error("%s: type mismatch for '%s' member"
22                         % (description, name))
23         return member
24     return default
25
26 def mustGetMember(json, name, expectedType, description):
27     member = getMember(json, name, expectedType, description)
28     if member == None:
29         raise Error("%s: missing '%s' member" % (description, name))
30     return member
31
32 class DbSchema:
33     def __init__(self, name, comment, tables):
34         self.name = name
35         self.comment = comment
36         self.tables = tables
37
38     @staticmethod
39     def fromJson(json):
40         name = mustGetMember(json, 'name', [unicode], 'database')
41         comment = getMember(json, 'comment', [unicode], 'database')
42         tablesJson = mustGetMember(json, 'tables', [dict], 'database')
43         tables = {}
44         for name, json in tablesJson.iteritems():
45             tables[name] = TableSchema.fromJson(json, "%s table" % name)
46         return DbSchema(name, comment, tables)
47
48     def toJson(self):
49         d = {"name": self.name,
50              "tables": {}}
51         for name, table in self.tables.iteritems():
52             d["tables"][name] = table.toJson()
53         if self.comment != None:
54             d["comment"] = self.comment
55         return d
56
57 class TableSchema:
58     def __init__(self, comment, columns):
59         self.comment = comment
60         self.columns = columns
61
62     @staticmethod
63     def fromJson(json, description):
64         comment = getMember(json, 'comment', [unicode], description)
65         columnsJson = mustGetMember(json, 'columns', [dict], description)
66         columns = {}
67         for name, json in columnsJson.iteritems():
68             columns[name] = ColumnSchema.fromJson(
69                 json, "column %s in %s" % (name, description))
70         return TableSchema(comment, columns)
71
72     def toJson(self):
73         d = {"columns": {}}
74         for name, column in self.columns.iteritems():
75             d["columns"][name] = column.toJson()
76         if self.comment != None:
77             d["comment"] = self.comment
78         return d
79
80 class ColumnSchema:
81     def __init__(self, comment, type, persistent):
82         self.comment = comment
83         self.type = type
84         self.persistent = persistent
85
86     @staticmethod
87     def fromJson(json, description):
88         comment = getMember(json, 'comment', [unicode], description)
89         type = Type.fromJson(mustGetMember(json, 'type', [dict, unicode],
90                                            description),
91                              'type of %s' % description)
92         ephemeral = getMember(json, 'ephemeral', [True,False], description)
93         persistent = ephemeral != True
94         return ColumnSchema(comment, type, persistent)
95
96     def toJson(self):
97         d = {"type": self.type.toJson()}
98         if self.persistent == False:
99             d["ephemeral"] = True
100         if self.comment != None:
101             d["comment"] = self.comment
102         return d
103
104 class Type:
105     def __init__(self, key, keyRefTable=None, value=None, valueRefTable=None,
106                  min=1, max=1):
107         self.key = key
108         self.keyRefTable = keyRefTable
109         self.value = value
110         self.valueRefTable = valueRefTable
111         self.min = min
112         self.max = max
113     
114     @staticmethod
115     def fromJson(json, description):
116         if type(json) == unicode:
117             return Type(json)
118         else:
119             key = mustGetMember(json, 'key', [unicode], description)
120             keyRefTable = getMember(json, 'keyRefTable', [unicode], description)
121             value = getMember(json, 'value', [unicode], description)
122             valueRefTable = getMember(json, 'valueRefTable', [unicode], description)
123             min = getMember(json, 'min', [int], description, 1)
124             max = getMember(json, 'max', [int, unicode], description, 1)
125             return Type(key, keyRefTable, value, valueRefTable, min, max)
126
127     def toJson(self):
128         if self.value == None and self.min == 1 and self.max == 1:
129             return self.key
130         else:
131             d = {"key": self.key}
132             if self.value != None:
133                 d["value"] = self.value
134             if self.min != 1:
135                 d["min"] = self.min
136             if self.max != 1:
137                 d["max"] = self.max
138             return d
139
140 def parseSchema(filename):
141     file = open(filename, "r")
142     s = ""
143     for line in file:
144         if not line.startswith('//'):
145             s += line
146     return DbSchema.fromJson(json.loads(s))
147
148 def cBaseType(prefix, type, refTable=None):
149     if type == 'uuid' and refTable:
150         return "struct %s%s *" % (prefix, refTable.lower())
151     else:
152         return {'integer': 'int64_t ',
153                 'real': 'double ',
154                 'uuid': 'struct uuid ',
155                 'boolean': 'bool ',
156                 'string': 'char *'}[type]
157
158 def printCIDLHeader(schema):
159     prefix = 'ovsrec_'
160     print '''\
161 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
162
163 #ifndef %(prefix)sIDL_HEADER
164 #define %(prefix)sIDL_HEADER 1
165
166 #include <stdbool.h>
167 #include <stddef.h>
168 #include <stdint.h>
169 #include "uuid.h"''' % {'prefix': prefix.upper()}
170     for tableName, table in schema.tables.iteritems():
171         print
172         if table.comment != None:
173             print "/* %s table (%s). */" % (tableName, table.comment)
174         else:
175             print "/* %s table. */" % (tableName)
176         print "struct %s%s {" % (prefix, tableName.lower())
177         print "\t/* Columns automatically included in every table. */"
178         print "\tstruct uuid uuid_;"
179         print "\tstruct uuid version_;"
180         for columnName, column in table.columns.iteritems():
181             print "\n\t/* %s column. */" % columnName
182             type = column.type
183             if type.min == 1 and type.max == 1:
184                 singleton = True
185                 pointer = ''
186             else:
187                 singleton = False
188                 pointer = '*'
189             if type.value:
190                 print "\tkey_%s%s%s;" % (cBaseType(prefix, type.key, type.keyRefTable), pointer, columnName)
191                 print "\tvalue_%s%s%s;" % (cBaseType(prefix, type.value, type.valueRefTable), pointer, columnName)
192             else:
193                 print "\t%s%s%s;" % (cBaseType(prefix, type.key, type.keyRefTable), pointer, columnName)
194             if not singleton:
195                 print "\tsize_t n_%s;" % columnName
196         print "};"
197     print
198     print "#endif /* %(prefix)sIDL_HEADER */" % {'prefix': prefix.upper()}
199
200 def ovsdb_escape(string):
201     def escape(match):
202         c = match.group(0)
203         if c == '\0':
204             raise Error("strings may not contain null bytes")
205         elif c == '\\':
206             return '\\\\'
207         elif c == '\n':
208             return '\\n'
209         elif c == '\r':
210             return '\\r'
211         elif c == '\t':
212             return '\\t'
213         elif c == '\b':
214             return '\\b'
215         elif c == '\a':
216             return '\\a'
217         else:
218             return '\\x%02x' % ord(c)
219     return re.sub(r'["\\\000-\037]', escape, string)
220
221 def printOVSDBSchema(schema):
222     json.dump(schema.toJson(), sys.stdout, sort_keys=True, indent=2)
223
224 def usage():
225     print """\
226 %(argv0)s: ovsdb schema compiler
227 usage: %(argv0)s [OPTIONS] ACTION SCHEMA
228 where SCHEMA is the ovsdb schema to read (in JSON format).
229
230 One of the following actions must specified:
231   validate                    validate schema without taking any other action
232   c-idl-header                print C header file for IDL
233   c-idl-source                print C source file for IDL implementation
234   ovsdb-schema                print ovsdb parseable schema
235
236 The following options are also available:
237   -h, --help                  display this help message
238   -V, --version               display version information\
239 """ % {'argv0': argv0}
240     sys.exit(0)
241
242 if __name__ == "__main__":
243     try:
244         try:
245             options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
246                                               ['help',
247                                                'version'])
248         except getopt.GetoptError, geo:
249             sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
250             sys.exit(1)
251             
252         optKeys = [key for key, value in options]
253         if '-h' in optKeys or '--help' in optKeys:
254             usage()
255         elif '-V' in optKeys or '--version' in optKeys:
256             print "ovsdb-idlc (Open vSwitch) @VERSION@"
257             sys.exit(0)
258
259         if len(args) != 2:
260             sys.stderr.write("%s: exactly two non-option arguments are "
261                              "required (use --help for help)\n" % argv0)
262             sys.exit(1)
263
264         action, inputFile = args
265         schema = parseSchema(inputFile)
266         if action == 'validate':
267             pass
268         elif action == 'ovsdb-schema':
269             printOVSDBSchema(schema)
270         elif action == 'c-idl-header':
271             printCIDLHeader(schema)
272         elif action == 'c-idl-source':
273             printCIDLSource(schema)
274         else:
275             sys.stderr.write(
276                 "%s: unknown action '%s' (use --help for help)\n" %
277                 (argv0, action))
278             sys.exit(1)
279     except Error, e:
280         sys.stderr.write("%s: %s\n" % (argv0, e.msg))
281         sys.exit(1)
282
283 # Local variables:
284 # mode: python
285 # End: