Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: tools/json_schema_compiler/compiler.py

Issue 12041098: Initial commit of the Dart Chrome Extension APIs generators (Closed) Base URL: http://git.chromium.org/chromium/src.git@file_path_bugfix
Patch Set: Fixed to work with json_schema_compiler changes, fixed style & structure issues, and implemented a … Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 """Generator for C++ structs from api json files. 5 """Generator for C++ structs from api json files.
6 6
7 The purpose of this tool is to remove the need for hand-written code that 7 The purpose of this tool is to remove the need for hand-written code that
8 converts to and from base::Value types when receiving javascript api calls. 8 converts to and from base::Value types when receiving javascript api calls.
9 Originally written for generating code for extension apis. Reference schemas 9 Originally written for generating code for extension apis. Reference schemas
10 are in chrome/common/extensions/api. 10 are in chrome/common/extensions/api.
11 11
12 Usage example: 12 Usage example:
13 compiler.py --root /home/Work/src --namespace extensions windows.json 13 compiler.py --root /home/Work/src --namespace extensions windows.json
14 tabs.json 14 tabs.json
15 compiler.py --destdir gen --root /home/Work/src 15 compiler.py --destdir gen --root /home/Work/src
16 --namespace extensions windows.json tabs.json 16 --namespace extensions windows.json tabs.json
17 """ 17 """
18 18
19 import cc_generator 19 import cc_generator
20 import cpp_type_generator 20 import cpp_type_generator
21 import h_generator 21 import h_generator
22 import dart_generator
22 import idl_schema 23 import idl_schema
23 import json_schema 24 import json_schema
24 import model 25 import model
25 import schema_bundle_generator 26 import schema_bundle_generator
26 27
27 import optparse 28 import optparse
28 import os.path 29 import os.path
29 import sys 30 import sys
30 31
32 # List of supported languages to build; first is default.
33 SUPPORTED_LANGS = ['c++', 'dart']
34
35 # For each language, the corresponding "ignore string" to remove that node from
36 # the returned namespace.
37 # TODO(sashab): Remove nodart from this list - all dart overrides must use the
38 # custom_dart_directory option.
not at google - send to devlin 2013/01/29 16:37:08 sgtm
sashab 2013/01/30 05:26:03 Done.
39 NODE_IGNORE_STR = {
40 'c++': 'nocompile',
41 'dart': 'nodart',
42 }
43
31 def load_schema(schema): 44 def load_schema(schema):
32 schema_filename, schema_extension = os.path.splitext(schema) 45 schema_filename, schema_extension = os.path.splitext(schema)
33 46
34 if schema_extension == '.json': 47 if schema_extension == '.json':
35 api_defs = json_schema.Load(schema) 48 api_defs = json_schema.Load(schema)
36 elif schema_extension == '.idl': 49 elif schema_extension == '.idl':
37 api_defs = idl_schema.Load(schema) 50 api_defs = idl_schema.Load(schema)
38 else: 51 else:
39 sys.exit("Did not recognize file extension %s for schema %s" % 52 sys.exit('Did not recognize file extension %s for schema %s' %
40 (schema_extension, schema)) 53 (schema_extension, schema))
41 if len(api_defs) != 1: 54 if len(api_defs) != 1:
42 sys.exit("File %s has multiple schemas. Files are only allowed to contain a" 55 sys.exit('File %s has multiple schemas. Files are only allowed to contain a'
43 " single schema." % schema) 56 ' single schema.' % schema)
44 57
45 return api_defs 58 return api_defs
46 59
47 def handle_single_schema(filename, dest_dir, root, root_namespace): 60 def handle_single_schema(filename, dest_dir, root, root_namespace, lang,
61 custom_dart_folder):
48 schema = os.path.normpath(filename) 62 schema = os.path.normpath(filename)
49 schema_filename, schema_extension = os.path.splitext(schema) 63 schema_filename, schema_extension = os.path.splitext(schema)
50 path, short_filename = os.path.split(schema_filename) 64 path, short_filename = os.path.split(schema_filename)
51 api_defs = json_schema.DeleteNocompileNodes(load_schema(schema)) 65 api_defs = json_schema.DeleteNodes(load_schema(schema),
66 NODE_IGNORE_STR[lang])
52 67
53 api_model = model.Model() 68 api_model = model.Model()
54 69
55 for target_namespace in api_defs: 70 for target_namespace in api_defs:
56 referenced_schemas = target_namespace.get('dependencies', []) 71 referenced_schemas = target_namespace.get('dependencies', [])
57 # Load type dependencies into the model. 72 # Load type dependencies into the model.
58 # TODO(miket): do we need this in IDL? 73 # TODO(miket): do we need this in IDL?
59 for referenced_schema in referenced_schemas: 74 for referenced_schema in referenced_schemas:
60 split_schema = referenced_schema.split(':', 1) 75 split_schema = referenced_schema.split(':', 1)
61 if len(split_schema) > 1: 76 if len(split_schema) > 1:
(...skipping 14 matching lines...) Expand all
76 # Gets the relative path from opts.root to the schema to correctly determine 91 # Gets the relative path from opts.root to the schema to correctly determine
77 # the include path. 92 # the include path.
78 relpath = os.path.relpath(schema, opts.root) 93 relpath = os.path.relpath(schema, opts.root)
79 namespace = api_model.AddNamespace(target_namespace, 94 namespace = api_model.AddNamespace(target_namespace,
80 relpath, 95 relpath,
81 include_compiler_options=True) 96 include_compiler_options=True)
82 if not namespace: 97 if not namespace:
83 continue 98 continue
84 99
85 if short_filename != namespace.unix_name: 100 if short_filename != namespace.unix_name:
86 sys.exit("Filename %s is illegal. Name files using unix_hacker style." % 101 sys.exit('Filename %s is illegal. Name files using unix_hacker style.' %
87 filename) 102 filename)
88 103
89 # The output filename must match the input filename for gyp to deal with it 104 # The output filename must match the input filename for gyp to deal with it
90 # properly. 105 # properly.
91 out_file = namespace.unix_name 106 out_file = namespace.unix_name
92 type_generator = cpp_type_generator.CppTypeGenerator(
93 root_namespace, namespace, namespace.unix_name)
94 for referenced_namespace in api_model.namespaces.values():
95 if referenced_namespace == namespace:
96 continue
97 type_generator.AddNamespace(
98 referenced_namespace,
99 referenced_namespace.unix_name)
100 107
101 h_code = (h_generator.HGenerator(namespace, type_generator) 108 if lang.lower() == 'c++':
102 .Generate().Render()) 109 type_generator = cpp_type_generator.CppTypeGenerator(
103 cc_code = (cc_generator.CCGenerator(namespace, type_generator) 110 root_namespace, namespace, namespace.unix_name)
104 .Generate().Render()) 111 for referenced_namespace in api_model.namespaces.values():
112 if referenced_namespace == namespace:
113 continue
114 type_generator.AddNamespace(
115 referenced_namespace,
116 referenced_namespace.unix_name)
105 117
106 if dest_dir: 118 h_code = (h_generator.HGenerator(namespace, type_generator)
107 with open( 119 .Generate().Render())
108 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.cc'), 120 cc_code = (cc_generator.CCGenerator(namespace, type_generator)
109 'w') as cc_file: 121 .Generate().Render())
110 cc_file.write(cc_code) 122
111 with open( 123 if dest_dir:
112 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.h'), 124 with open(
113 'w') as h_file: 125 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.cc'),
114 h_file.write(h_code) 126 'w') as cc_file:
127 cc_file.write(cc_code)
128 with open(
129 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.h'),
130 'w') as h_file:
131 h_file.write(h_code)
132 else:
133 print '%s.h' % out_file
134 print
135 print h_code
136 print
137 print '%s.cc' % out_file
138 print
139 print cc_code
140
141 elif lang.lower() == 'dart':
142 dart_code = (dart_generator.DartGenerator(namespace, custom_dart_folder)
143 .Generate().Render())
144
145 if dest_dir:
146 with open(os.path.join(dest_dir, out_file + '.dart'), 'w') as dart_file:
147 dart_file.write(dart_code)
148 else:
149 print '%s.dart' % out_file
150 print
151 print dart_code
152
115 else: 153 else:
116 print '%s.h' % out_file 154 raise Exception('Unrecognised language %s. Supported languages are %s.' %
117 print 155 (lang, SUPPORTED_LANGS))
118 print h_code
119 print
120 print '%s.cc' % out_file
121 print
122 print cc_code
123 156
124 def handle_bundle_schema(filenames, dest_dir, root, root_namespace): 157 def handle_bundle_schema(filenames, dest_dir, root, root_namespace, lang):
125 # Merge the source files into a single list of schemas. 158 # Merge the source files into a single list of schemas.
126 api_defs = [] 159 api_defs = []
127 for filename in filenames: 160 for filename in filenames:
128 schema = os.path.normpath(filename) 161 schema = os.path.normpath(filename)
129 schema_filename, schema_extension = os.path.splitext(schema) 162 schema_filename, schema_extension = os.path.splitext(schema)
130 api_defs.extend(load_schema(schema)) 163 api_defs.extend(load_schema(schema))
131 164
132 api_model = model.Model() 165 api_model = model.Model()
133 relpath = os.path.relpath(os.path.normpath(filenames[0]), root) 166 relpath = os.path.relpath(os.path.normpath(filenames[0]), root)
134 167
135 for target_namespace, schema_filename in zip(api_defs, filenames): 168 for target_namespace, schema_filename in zip(api_defs, filenames):
136 namespace = api_model.AddNamespace(target_namespace, 169 namespace = api_model.AddNamespace(target_namespace,
137 relpath, 170 relpath,
138 include_compiler_options=True) 171 include_compiler_options=True)
139 path, filename = os.path.split(schema_filename) 172 path, filename = os.path.split(schema_filename)
140 short_filename, extension = os.path.splitext(filename) 173 short_filename, extension = os.path.splitext(filename)
141 174
142 # Filenames are checked against the unix_names of the namespaces they 175 # Filenames are checked against the unix_names of the namespaces they
143 # generate because the gyp uses the names of the JSON files to generate 176 # generate because the gyp uses the names of the JSON files to generate
144 # the names of the .cc and .h files. We want these to be using unix_names. 177 # the names of the .cc and .h files. We want these to be using unix_names.
145 if namespace.unix_name != short_filename: 178 if namespace.unix_name != short_filename:
146 sys.exit("Filename %s is illegal. Name files using unix_hacker style." % 179 sys.exit('Filename %s is illegal. Name files using unix_hacker style.' %
147 schema_filename) 180 schema_filename)
148 181
149 type_generator = cpp_type_generator.CppTypeGenerator(root_namespace) 182 if lang == 'c++':
150 for referenced_namespace in api_model.namespaces.values(): 183 type_generator = cpp_type_generator.CppTypeGenerator(root_namespace)
151 type_generator.AddNamespace( 184 for referenced_namespace in api_model.namespaces.values():
152 referenced_namespace, 185 type_generator.AddNamespace(
153 referenced_namespace.unix_name) 186 referenced_namespace,
187 referenced_namespace.unix_name)
154 188
155 generator = schema_bundle_generator.SchemaBundleGenerator( 189 generator = schema_bundle_generator.SchemaBundleGenerator(
156 root, api_model, api_defs, type_generator) 190 root, api_model, api_defs, type_generator)
157 api_h_code = generator.GenerateAPIHeader().Render() 191 api_h_code = generator.GenerateAPIHeader().Render()
158 schemas_h_code = generator.GenerateSchemasHeader().Render() 192 schemas_h_code = generator.GenerateSchemasHeader().Render()
159 schemas_cc_code = generator.GenerateSchemasCC().Render() 193 schemas_cc_code = generator.GenerateSchemasCC().Render()
160 194
161 if dest_dir: 195 if dest_dir:
162 basedir = os.path.join(dest_dir, 'chrome/common/extensions/api') 196 basedir = os.path.join(dest_dir, 'chrome/common/extensions/api')
163 with open(os.path.join(basedir, 'generated_api.h'), 'w') as h_file: 197 with open(os.path.join(basedir, 'generated_api.h'), 'w') as h_file:
164 h_file.write(api_h_code) 198 h_file.write(api_h_code)
165 with open(os.path.join(basedir, 'generated_schemas.h'), 'w') as h_file: 199 with open(os.path.join(basedir, 'generated_schemas.h'), 'w') as h_file:
166 h_file.write(schemas_h_code) 200 h_file.write(schemas_h_code)
167 with open(os.path.join(basedir, 'generated_schemas.cc'), 'w') as cc_file: 201 with open(os.path.join(basedir, 'generated_schemas.cc'), 'w') as cc_file:
168 cc_file.write(schemas_cc_code) 202 cc_file.write(schemas_cc_code)
203 else:
204 print 'generated_api.h'
205 print
206 print api_h_code
207 print
208 print 'generated_schemas.h'
209 print
210 print schemas_h_code
211 print
212 print 'generated_schemas.cc'
213 print
214 print schemas_cc_code
215
216 elif lang == 'dart':
217 raise Exception('Dart is not supported in bundle mode.')
218
169 else: 219 else:
170 print 'generated_api.h' 220 raise Exception("Unrecognised language %s. Supported languages are %s." %
171 print 221 (lang, SUPPORTED_LANG))
172 print api_h_code
173 print
174 print 'generated_schemas.h'
175 print
176 print schemas_h_code
177 print
178 print 'generated_schemas.cc'
179 print
180 print schemas_cc_code
181 222
182 if __name__ == '__main__': 223 if __name__ == '__main__':
183 parser = optparse.OptionParser( 224 parser = optparse.OptionParser(
184 description='Generates a C++ model of an API from JSON schema', 225 description='Generates a C++ model of an API from JSON schema',
185 usage='usage: %prog [option]... schema') 226 usage='usage: %prog [option]... schema')
186 parser.add_option('-r', '--root', default='.', 227 parser.add_option('-r', '--root', default='.',
187 help='logical include root directory. Path to schema files from specified' 228 help='logical include root directory. Path to schema files from specified'
188 'dir will be the include path.') 229 'dir will be the include path.')
189 parser.add_option('-d', '--destdir', 230 parser.add_option('-d', '--destdir',
190 help='root directory to output generated files.') 231 help='root directory to output generated files.')
191 parser.add_option('-n', '--namespace', default='generated_api_schemas', 232 parser.add_option('-n', '--namespace', default='generated_api_schemas',
192 help='C++ namespace for generated files. e.g extensions::api.') 233 help='C++ namespace for generated files. e.g extensions::api.')
193 parser.add_option('-b', '--bundle', action="store_true", help= 234 parser.add_option('-b', '--bundle', action='store_true', help=
194 '''if supplied, causes compiler to generate bundle files for the given set of 235 '''if supplied, causes compiler to generate bundle files for the given set of
195 source files.''') 236 source files.''')
237 parser.add_option('-l', '--lang', default=SUPPORTED_LANGS[0],
238 help=
239 '''The language to generate the output in. Currently supported options are
240 %s.''' % SUPPORTED_LANGS)
241 parser.add_option('-D', '--custom-dart-folder', dest='custom_dart_folder',
242 help='Adds custom dart from files in the given folder (Dart only).')
196 243
197 (opts, args) = parser.parse_args() 244 (opts, args) = parser.parse_args()
198 245
199 if not args: 246 if not args:
200 sys.exit(0) # This is OK as a no-op 247 sys.exit(0) # This is OK as a no-op
201 dest_dir = opts.destdir 248 dest_dir = opts.destdir
202 root_namespace = opts.namespace 249 root_namespace = opts.namespace
203 250
204 if opts.bundle: 251 if opts.bundle:
205 handle_bundle_schema(args, dest_dir, opts.root, root_namespace) 252 handle_bundle_schema(args, dest_dir, opts.root, root_namespace, opts.lang)
206 else: 253 else:
207 handle_single_schema(args[0], dest_dir, opts.root, root_namespace) 254 handle_single_schema(args[0], dest_dir, opts.root, root_namespace,
255 opts.lang, opts.custom_dart_folder)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698