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

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

Issue 12218151: Added unit tests for the Dart Chrome.* API wrappers. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Remove print statement if outputting to file. 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
« no previous file with comments | « no previous file | tools/json_schema_compiler/dart_generator_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
(...skipping 14 matching lines...) Expand all
25 import json_schema 25 import json_schema
26 26
27 import optparse 27 import optparse
28 import os.path 28 import os.path
29 import sys 29 import sys
30 30
31 # Names of supported code generators, as specified on the command-line. 31 # Names of supported code generators, as specified on the command-line.
32 # First is default. 32 # First is default.
33 GENERATORS = ['cpp', 'cpp-bundle', 'dart'] 33 GENERATORS = ['cpp', 'cpp-bundle', 'dart']
34 34
35 def load_schema(schema): 35 def _LoadSchema(schema):
36 schema_filename, schema_extension = os.path.splitext(schema) 36 schema_filename, schema_extension = os.path.splitext(schema)
37 37
38 if schema_extension == '.json': 38 if schema_extension == '.json':
39 api_defs = json_schema.Load(schema) 39 api_defs = json_schema.Load(schema)
40 elif schema_extension == '.idl': 40 elif schema_extension == '.idl':
41 api_defs = idl_schema.Load(schema) 41 api_defs = idl_schema.Load(schema)
42 else: 42 else:
43 sys.exit('Did not recognize file extension %s for schema %s' % 43 sys.exit('Did not recognize file extension %s for schema %s' %
44 (schema_extension, schema)) 44 (schema_extension, schema))
45 if len(api_defs) != 1: 45 if len(api_defs) != 1:
46 sys.exit('File %s has multiple schemas. Files are only allowed to contain a' 46 sys.exit('File %s has multiple schemas. Files are only allowed to contain a'
47 ' single schema.' % schema) 47 ' single schema.' % schema)
48 48
49 return api_defs 49 return api_defs
50 50
51 if __name__ == '__main__': 51 def GenerateSchema(generator,
52 parser = optparse.OptionParser( 52 filenames,
53 description='Generates a C++ model of an API from JSON schema', 53 root,
54 usage='usage: %prog [option]... schema') 54 destdir,
55 parser.add_option('-r', '--root', default='.', 55 root_namespace,
56 help='logical include root directory. Path to schema files from specified' 56 dart_overrides_dir):
57 'dir will be the include path.')
58 parser.add_option('-d', '--destdir',
59 help='root directory to output generated files.')
60 parser.add_option('-n', '--namespace', default='generated_api_schemas',
61 help='C++ namespace for generated files. e.g extensions::api.')
62 parser.add_option('-g', '--generator', default=GENERATORS[0],
63 choices=GENERATORS,
64 help='The generator to use to build the output code. Supported values are'
65 ' %s' % GENERATORS)
66 parser.add_option('-D', '--dart-overrides-dir', dest='dart_overrides_dir',
67 help='Adds custom dart from files in the given directory (Dart only).')
68
69 (opts, filenames) = parser.parse_args()
70
71 if not filenames:
72 sys.exit(0) # This is OK as a no-op
73
74 # Unless in bundle mode, only one file should be specified.
75 if opts.generator != 'cpp-bundle' and len(filenames) > 1:
76 # TODO(sashab): Could also just use filenames[0] here and not complain.
77 raise Exception(
78 "Unless in bundle mode, only one file can be specified at a time.")
79
80 # Merge the source files into a single list of schemas. 57 # Merge the source files into a single list of schemas.
81 api_defs = [] 58 api_defs = []
82 for filename in filenames: 59 for filename in filenames:
83 schema = os.path.normpath(filename) 60 schema = os.path.normpath(filename)
84 schema_filename, schema_extension = os.path.splitext(schema) 61 schema_filename, schema_extension = os.path.splitext(schema)
85 path, short_filename = os.path.split(schema_filename) 62 path, short_filename = os.path.split(schema_filename)
86 api_def = load_schema(schema) 63 api_def = _LoadSchema(schema)
87 64
88 # If compiling the C++ model code, delete 'nocompile' nodes. 65 # If compiling the C++ model code, delete 'nocompile' nodes.
89 if opts.generator == 'cpp': 66 if generator == 'cpp':
90 api_def = json_schema.DeleteNodes(api_def, 'nocompile') 67 api_def = json_schema.DeleteNodes(api_def, 'nocompile')
91 api_defs.extend(api_def) 68 api_defs.extend(api_def)
92 69
93 api_model = Model() 70 api_model = Model()
94 71
95 # Load type dependencies into the model. 72 # Load type dependencies into the model.
96 # 73 #
97 # HACK(kalman): bundle mode doesn't work with dependencies, because not all 74 # HACK(kalman): bundle mode doesn't work with dependencies, because not all
98 # schemas work in bundle mode. 75 # schemas work in bundle mode.
99 # 76 #
100 # TODO(kalman): load dependencies lazily (get rid of the 'dependencies' list) 77 # TODO(kalman): load dependencies lazily (get rid of the 'dependencies' list)
101 # and this problem will go away. 78 # and this problem will go away.
102 if opts.generator != 'cpp-bundle': 79 if generator != 'cpp-bundle':
103 for target_namespace in api_defs: 80 for target_namespace in api_defs:
104 for referenced_schema in target_namespace.get('dependencies', []): 81 for referenced_schema in target_namespace.get('dependencies', []):
105 split_schema = referenced_schema.split(':', 1) 82 split_schema = referenced_schema.split(':', 1)
106 if len(split_schema) > 1: 83 if len(split_schema) > 1:
107 if split_schema[0] != 'api': 84 if split_schema[0] != 'api':
108 continue 85 continue
109 else: 86 else:
110 referenced_schema = split_schema[1] 87 referenced_schema = split_schema[1]
111 88
112 referenced_schema_path = os.path.join( 89 referenced_schema_path = os.path.join(
113 os.path.dirname(schema), referenced_schema + '.json') 90 os.path.dirname(schema), referenced_schema + '.json')
114 referenced_api_defs = json_schema.Load(referenced_schema_path) 91 referenced_api_defs = json_schema.Load(referenced_schema_path)
115 92
116 for namespace in referenced_api_defs: 93 for namespace in referenced_api_defs:
117 api_model.AddNamespace( 94 api_model.AddNamespace(
118 namespace, 95 namespace,
119 os.path.relpath(referenced_schema_path, opts.root), 96 os.path.relpath(referenced_schema_path, root),
120 include_compiler_options=True) 97 include_compiler_options=True)
121 98
122 # For single-schema compilation make sure that the first (i.e. only) schema 99 # For single-schema compilation make sure that the first (i.e. only) schema
123 # is the default one. 100 # is the default one.
124 default_namespace = None 101 default_namespace = None
125 102
126 # Load the actual namespaces into the model. 103 # Load the actual namespaces into the model.
127 for target_namespace, schema_filename in zip(api_defs, filenames): 104 for target_namespace, schema_filename in zip(api_defs, filenames):
128 relpath = os.path.relpath(os.path.normpath(schema_filename), opts.root) 105 relpath = os.path.relpath(os.path.normpath(schema_filename), root)
129 namespace = api_model.AddNamespace(target_namespace, 106 namespace = api_model.AddNamespace(target_namespace,
130 relpath, 107 relpath,
131 include_compiler_options=True) 108 include_compiler_options=True)
132 if default_namespace is None: 109 if default_namespace is None:
133 default_namespace = namespace 110 default_namespace = namespace
134 111
135 path, filename = os.path.split(schema_filename) 112 path, filename = os.path.split(schema_filename)
136 short_filename, extension = os.path.splitext(filename) 113 short_filename, extension = os.path.splitext(filename)
137 114
138 # Filenames are checked against the unix_names of the namespaces they 115 # Filenames are checked against the unix_names of the namespaces they
139 # generate because the gyp uses the names of the JSON files to generate 116 # generate because the gyp uses the names of the JSON files to generate
140 # the names of the .cc and .h files. We want these to be using unix_names. 117 # the names of the .cc and .h files. We want these to be using unix_names.
141 if namespace.unix_name != short_filename: 118 if namespace.unix_name != short_filename:
142 sys.exit("Filename %s is illegal. Name files using unix_hacker style." % 119 sys.exit("Filename %s is illegal. Name files using unix_hacker style." %
143 schema_filename) 120 schema_filename)
144 121
145 # The output filename must match the input filename for gyp to deal with it 122 # The output filename must match the input filename for gyp to deal with it
146 # properly. 123 # properly.
147 out_file = namespace.unix_name 124 out_file = namespace.unix_name
148 125
149 # Construct the type generator with all the namespaces in this model. 126 # Construct the type generator with all the namespaces in this model.
150 type_generator = CppTypeGenerator(api_model, 127 type_generator = CppTypeGenerator(api_model,
151 default_namespace=default_namespace) 128 default_namespace=default_namespace)
152 129
153 if opts.generator == 'cpp-bundle': 130 if generator == 'cpp-bundle':
154 cpp_bundle_generator = CppBundleGenerator(opts.root, 131 cpp_bundle_generator = CppBundleGenerator(root,
155 api_model, 132 api_model,
156 api_defs, 133 api_defs,
157 type_generator, 134 type_generator,
158 opts.namespace) 135 root_namespace)
159 generators = [ 136 generators = [
160 ('generated_api.cc', cpp_bundle_generator.api_cc_generator), 137 ('generated_api.cc', cpp_bundle_generator.api_cc_generator),
161 ('generated_api.h', cpp_bundle_generator.api_h_generator), 138 ('generated_api.h', cpp_bundle_generator.api_h_generator),
162 ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator), 139 ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator),
163 ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator) 140 ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator)
164 ] 141 ]
165 elif opts.generator == 'cpp': 142 elif generator == 'cpp':
166 cpp_generator = CppGenerator(type_generator, opts.namespace) 143 cpp_generator = CppGenerator(type_generator, root_namespace)
167 generators = [ 144 generators = [
168 ('%s.h' % namespace.unix_name, cpp_generator.h_generator), 145 ('%s.h' % namespace.unix_name, cpp_generator.h_generator),
169 ('%s.cc' % namespace.unix_name, cpp_generator.cc_generator) 146 ('%s.cc' % namespace.unix_name, cpp_generator.cc_generator)
170 ] 147 ]
171 elif opts.generator == 'dart': 148 elif generator == 'dart':
172 generators = [ 149 generators = [
173 ('%s.dart' % namespace.unix_name, DartGenerator( 150 ('%s.dart' % namespace.unix_name, DartGenerator(
174 opts.dart_overrides_dir)) 151 dart_overrides_dir))
175 ] 152 ]
176 else: 153 else:
177 raise Exception('Unrecognised generator %s' % opts.generator) 154 raise Exception('Unrecognised generator %s' % generator)
178 155
156 output_code = []
179 for filename, generator in generators: 157 for filename, generator in generators:
180 code = generator.Generate(namespace).Render() 158 code = generator.Generate(namespace).Render()
181 if opts.destdir: 159 if destdir:
182 with open(os.path.join(opts.destdir, namespace.source_file_dir, 160 with open(os.path.join(destdir, namespace.source_file_dir,
183 filename), 'w') as f: 161 filename), 'w') as f:
184 f.write(code) 162 f.write(code)
185 else: 163 output_code += [filename, '', code, '']
186 print filename 164
187 print 165 return '\n'.join(output_code)
188 print code 166
189 print 167 if __name__ == '__main__':
168 parser = optparse.OptionParser(
169 description='Generates a C++ model of an API from JSON schema',
170 usage='usage: %prog [option]... schema')
171 parser.add_option('-r', '--root', default='.',
172 help='logical include root directory. Path to schema files from specified'
173 'dir will be the include path.')
174 parser.add_option('-d', '--destdir',
175 help='root directory to output generated files.')
176 parser.add_option('-n', '--namespace', default='generated_api_schemas',
177 help='C++ namespace for generated files. e.g extensions::api.')
178 parser.add_option('-g', '--generator', default=GENERATORS[0],
179 choices=GENERATORS,
180 help='The generator to use to build the output code. Supported values are'
181 ' %s' % GENERATORS)
182 parser.add_option('-D', '--dart-overrides-dir', dest='dart_overrides_dir',
183 help='Adds custom dart from files in the given directory (Dart only).')
184
185 (opts, filenames) = parser.parse_args()
186
187 if not filenames:
188 sys.exit(0) # This is OK as a no-op
189
190 # Unless in bundle mode, only one file should be specified.
191 if opts.generator != 'cpp-bundle' and len(filenames) > 1:
192 # TODO(sashab): Could also just use filenames[0] here and not complain.
193 raise Exception(
194 "Unless in bundle mode, only one file can be specified at a time.")
195
196 result = GenerateSchema(opts.generator, filenames, opts.root, opts.destdir,
197 opts.namespace, opts.dart_overrides_dir)
198 if not opts.destdir:
199 print result
OLDNEW
« no previous file with comments | « no previous file | tools/json_schema_compiler/dart_generator_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698