OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import os.path | 5 import os.path |
6 import sys | 6 import sys |
7 import optparse | 7 import optparse |
8 try: | 8 try: |
9 import json | 9 import json |
10 except ImportError: | 10 except ImportError: |
(...skipping 30 matching lines...) Expand all Loading... |
41 deps_dir = os.path.normpath(os.path.join( | 41 deps_dir = os.path.normpath(os.path.join( |
42 module_path, os.pardir, os.pardir, os.pardir, os.pardir, "third_party")) | 42 module_path, os.pardir, os.pardir, os.pardir, os.pardir, "third_party")) |
43 | 43 |
44 if os.path.isdir(deps_dir): | 44 if os.path.isdir(deps_dir): |
45 sys.path.insert(1, os.path.join(deps_dir, "jinja2")) | 45 sys.path.insert(1, os.path.join(deps_dir, "jinja2")) |
46 sys.path.insert(1, os.path.join(deps_dir, "markupsafe")) | 46 sys.path.insert(1, os.path.join(deps_dir, "markupsafe")) |
47 | 47 |
48 import jinja2 | 48 import jinja2 |
49 | 49 |
50 cmdline_parser = optparse.OptionParser() | 50 cmdline_parser = optparse.OptionParser() |
51 cmdline_parser.add_option("--protocol") | 51 cmdline_parser.add_option("--output_base") |
52 cmdline_parser.add_option("--include") | 52 cmdline_parser.add_option("--config") |
53 cmdline_parser.add_option("--include_package") | 53 |
54 cmdline_parser.add_option("--string_type") | |
55 cmdline_parser.add_option("--export_macro") | |
56 cmdline_parser.add_option("--output_dir") | |
57 cmdline_parser.add_option("--output_package") | |
58 cmdline_parser.add_option("--exported_dir") | |
59 cmdline_parser.add_option("--exported_package") | |
60 | 54 |
61 try: | 55 try: |
62 arg_options, arg_values = cmdline_parser.parse_args() | 56 arg_options, arg_values = cmdline_parser.parse_args() |
63 protocol_file = arg_options.protocol | 57 output_base = arg_options.output_base |
64 if not protocol_file: | 58 if not output_base: |
65 raise Exception("Protocol directory must be specified") | 59 raise Exception("Base output directory must be specified") |
66 include_file = arg_options.include | 60 config_file = arg_options.config |
67 include_package = arg_options.include_package | 61 if not config_file: |
68 if include_file and not include_package: | 62 raise Exception("Config file name must be specified") |
69 raise Exception("Include package must be specified when using include fi
le") | 63 config_dir = os.path.dirname(config_file) |
70 if include_package and not include_file: | |
71 raise Exception("Include file must be specified when using include packa
ge") | |
72 output_dirname = arg_options.output_dir | |
73 if not output_dirname: | |
74 raise Exception("Output directory must be specified") | |
75 output_package = arg_options.output_package | |
76 if not output_package: | |
77 raise Exception("Output package must be specified") | |
78 exported_dirname = arg_options.exported_dir | |
79 if not exported_dirname: | |
80 exported_dirname = os.path.join(output_dirname, "exported") | |
81 exported_package = arg_options.exported_package | |
82 if not exported_package: | |
83 exported_package = os.path.join(output_package, "exported") | |
84 string_type = arg_options.string_type | |
85 if not string_type: | |
86 raise Exception("String type must be specified") | |
87 export_macro = arg_options.export_macro | |
88 if not export_macro: | |
89 raise Exception("Export macro must be specified") | |
90 except Exception: | 64 except Exception: |
91 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html | 65 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html |
92 exc = sys.exc_info()[1] | 66 exc = sys.exc_info()[1] |
93 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) | 67 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) |
94 exit(1) | 68 exit(1) |
95 | 69 |
96 | 70 |
97 input_file = open(protocol_file, "r") | 71 try: |
98 json_string = input_file.read() | 72 config_json_string = open(config_file, "r").read() |
99 parsed_json = json.loads(json_string) | 73 config = json.loads(config_json_string) |
| 74 |
| 75 protocol_file = config["protocol"]["path"] |
| 76 if not protocol_file: |
| 77 raise Exception("Config is missing protocol.path") |
| 78 protocol_file = os.path.join(config_dir, protocol_file) |
| 79 output_dirname = config["protocol"]["output"] |
| 80 if not output_dirname: |
| 81 raise Exception("Config is missing protocol.output") |
| 82 output_dirname = os.path.join(output_base, output_dirname) |
| 83 output_package = config["protocol"]["package"] |
| 84 if not output_package: |
| 85 raise Exception("Config is missing protocol.package") |
| 86 |
| 87 importing = False |
| 88 if "import" in config: |
| 89 importing = True |
| 90 imported_file = config["import"]["path"] |
| 91 if not imported_file: |
| 92 raise Exception("Config is missing import.path") |
| 93 imported_file = os.path.join(config_dir, imported_file) |
| 94 imported_package = config["import"]["package"] |
| 95 if not imported_package: |
| 96 raise Exception("Config is missing import.package") |
| 97 |
| 98 exporting = False |
| 99 if "export" in config: |
| 100 exporting = True |
| 101 exported_dirname = config["export"]["output"] |
| 102 if not exported_dirname: |
| 103 raise Exception("Config is missing export.output") |
| 104 exported_dirname = os.path.join(output_base, exported_dirname) |
| 105 exported_package = config["export"]["package"] |
| 106 if not exported_package: |
| 107 raise Exception("Config is missing export.package") |
| 108 |
| 109 string_type = config["string"]["class_name"] |
| 110 if not string_type: |
| 111 raise Exception("Config is missing string.class_name") |
| 112 |
| 113 export_macro = config["export_macro"] |
| 114 if not export_macro: |
| 115 raise Exception("Config is missing export_macro") |
| 116 except Exception: |
| 117 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html |
| 118 exc = sys.exc_info()[1] |
| 119 sys.stderr.write("Failed to parse config file: %s\n\n" % exc) |
| 120 exit(1) |
100 | 121 |
101 | 122 |
102 # Make gyp / make generatos happy, otherwise make rebuilds world. | 123 # Make gyp / make generatos happy, otherwise make rebuilds world. |
103 def up_to_date(): | 124 def up_to_date(): |
104 template_ts = max( | 125 template_ts = max( |
105 os.path.getmtime(__file__), | 126 os.path.getmtime(__file__), |
106 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_h.template")), | 127 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_h.template")), |
107 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_cpp.template")
), | 128 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_cpp.template")
), |
108 os.path.getmtime(os.path.join(templates_dir, "Exported_h.template")), | 129 os.path.getmtime(os.path.join(templates_dir, "Exported_h.template")), |
109 os.path.getmtime(os.path.join(templates_dir, "Imported_h.template")), | 130 os.path.getmtime(os.path.join(templates_dir, "Imported_h.template")), |
| 131 os.path.getmtime(config_file), |
110 os.path.getmtime(protocol_file)) | 132 os.path.getmtime(protocol_file)) |
| 133 if importing: |
| 134 template_ts = max(template_ts, os.path.getmtime(imported_file)) |
111 | 135 |
112 for domain in parsed_json["domains"]: | 136 for domain in json_api["domains"]: |
113 name = domain["domain"] | 137 name = domain["domain"] |
114 paths = [] | 138 paths = [] |
115 if name in generate_domains: | 139 if name in generate_domains: |
116 paths = [os.path.join(output_dirname, name + ".h"), os.path.join(out
put_dirname, name + ".cpp")] | 140 paths = [os.path.join(output_dirname, name + ".h"), os.path.join(out
put_dirname, name + ".cpp")] |
117 if domain["has_exports"]: | 141 if domain["has_exports"]: |
118 paths.append(os.path.join(exported_dirname, name + ".h")) | 142 paths.append(os.path.join(exported_dirname, name + ".h")) |
119 if name in include_domains and domain["has_exports"]: | 143 if name in imported_domains and domain["has_exports"]: |
120 paths = [os.path.join(output_dirname, name + '.h')] | 144 paths = [os.path.join(output_dirname, name + '.h')] |
121 for path in paths: | 145 for path in paths: |
122 if not os.path.exists(path): | 146 if not os.path.exists(path): |
123 return False | 147 return False |
124 generated_ts = os.path.getmtime(path) | 148 generated_ts = os.path.getmtime(path) |
125 if generated_ts < template_ts: | 149 if generated_ts < template_ts: |
126 return False | 150 return False |
127 return True | 151 return True |
128 | 152 |
129 | 153 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 for item in json_value: | 210 for item in json_value: |
187 has_exports = calculate_exports_in_json(item) or has_exports | 211 has_exports = calculate_exports_in_json(item) or has_exports |
188 if isinstance(json_value, dict): | 212 if isinstance(json_value, dict): |
189 has_exports = ("exported" in json_value and json_value["exported"])
or has_exports | 213 has_exports = ("exported" in json_value and json_value["exported"])
or has_exports |
190 for key in json_value: | 214 for key in json_value: |
191 has_exports = calculate_exports_in_json(json_value[key]) or has_
exports | 215 has_exports = calculate_exports_in_json(json_value[key]) or has_
exports |
192 return has_exports | 216 return has_exports |
193 | 217 |
194 json_api["has_exports"] = False | 218 json_api["has_exports"] = False |
195 for domain_json in json_api["domains"]: | 219 for domain_json in json_api["domains"]: |
| 220 domain_name = domain_json["domain"] |
196 domain_json["has_exports"] = calculate_exports_in_json(domain_json) | 221 domain_json["has_exports"] = calculate_exports_in_json(domain_json) |
197 json_api["has_exports"] = json_api["has_exports"] or domain_json["has_ex
ports"] | 222 if domain_json["has_exports"] and domain_name in generate_domains: |
| 223 if not exporting: |
| 224 sys.stderr.write("Domain %s is exported, but config is missing e
xport entry\n\n" % domain_name) |
| 225 exit(1) |
| 226 json_api["has_exports"] = True |
198 | 227 |
199 | 228 |
200 def create_include_type_definition(domain_name, type): | 229 def create_imported_type_definition(domain_name, type): |
201 # pylint: disable=W0622 | 230 # pylint: disable=W0622 |
202 return { | 231 return { |
203 "return_type": "std::unique_ptr<protocol::%s::API::%s>" % (domain_name,
type["id"]), | 232 "return_type": "std::unique_ptr<protocol::%s::API::%s>" % (domain_name,
type["id"]), |
204 "pass_type": "std::unique_ptr<protocol::%s::API::%s>" % (domain_name, ty
pe["id"]), | 233 "pass_type": "std::unique_ptr<protocol::%s::API::%s>" % (domain_name, ty
pe["id"]), |
205 "to_raw_type": "%s.get()", | 234 "to_raw_type": "%s.get()", |
206 "to_pass_type": "std::move(%s)", | 235 "to_pass_type": "std::move(%s)", |
207 "to_rvalue": "std::move(%s)", | 236 "to_rvalue": "std::move(%s)", |
208 "type": "std::unique_ptr<protocol::%s::API::%s>" % (domain_name, type["i
d"]), | 237 "type": "std::unique_ptr<protocol::%s::API::%s>" % (domain_name, type["i
d"]), |
209 "raw_type": "protocol::%s::API::%s" % (domain_name, type["id"]), | 238 "raw_type": "protocol::%s::API::%s" % (domain_name, type["id"]), |
210 "raw_pass_type": "protocol::%s::API::%s*" % (domain_name, type["id"]), | 239 "raw_pass_type": "protocol::%s::API::%s*" % (domain_name, type["id"]), |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 } | 357 } |
329 | 358 |
330 | 359 |
331 def create_type_definitions(): | 360 def create_type_definitions(): |
332 for domain in json_api["domains"]: | 361 for domain in json_api["domains"]: |
333 type_definitions[domain["domain"] + ".string"] = create_string_type_defi
nition(domain["domain"]) | 362 type_definitions[domain["domain"] + ".string"] = create_string_type_defi
nition(domain["domain"]) |
334 if not ("types" in domain): | 363 if not ("types" in domain): |
335 continue | 364 continue |
336 for type in domain["types"]: | 365 for type in domain["types"]: |
337 type_name = domain["domain"] + "." + type["id"] | 366 type_name = domain["domain"] + "." + type["id"] |
338 if type["type"] == "object" and domain["domain"] in include_domains: | 367 if type["type"] == "object" and domain["domain"] in imported_domains
: |
339 type_definitions[type_name] = create_include_type_definition(dom
ain["domain"], type) | 368 type_definitions[type_name] = create_imported_type_definition(do
main["domain"], type) |
340 elif type["type"] == "object": | 369 elif type["type"] == "object": |
341 type_definitions[type_name] = create_user_type_definition(domain
["domain"], type) | 370 type_definitions[type_name] = create_user_type_definition(domain
["domain"], type) |
342 elif type["type"] == "array": | 371 elif type["type"] == "array": |
343 items_type = type["items"]["type"] | 372 items_type = type["items"]["type"] |
344 type_definitions[type_name] = wrap_array_definition(type_definit
ions[items_type]) | 373 type_definitions[type_name] = wrap_array_definition(type_definit
ions[items_type]) |
345 elif type["type"] == domain["domain"] + ".string": | 374 elif type["type"] == domain["domain"] + ".string": |
346 type_definitions[type_name] = create_string_type_definition(doma
in["domain"]) | 375 type_definitions[type_name] = create_string_type_definition(doma
in["domain"]) |
347 else: | 376 else: |
348 type_definitions[type_name] = create_primitive_type_definition(t
ype["type"]) | 377 type_definitions[type_name] = create_primitive_type_definition(t
ype["type"]) |
349 | 378 |
(...skipping 18 matching lines...) Expand all Loading... |
368 return result | 397 return result |
369 | 398 |
370 | 399 |
371 def has_disable(commands): | 400 def has_disable(commands): |
372 for command in commands: | 401 for command in commands: |
373 if command["name"] == "disable": | 402 if command["name"] == "disable": |
374 return True | 403 return True |
375 return False | 404 return False |
376 | 405 |
377 | 406 |
| 407 def generate_with_context(template_context, template, file_name): |
| 408 out_file = output_file(file_name) |
| 409 out_file.write(template.render(template_context)) |
| 410 out_file.close() |
| 411 |
| 412 |
378 def generate(domain_object, template, file_name): | 413 def generate(domain_object, template, file_name): |
379 template_context = { | 414 template_context = { |
380 "domain": domain_object, | 415 "domain": domain_object, |
381 "join_arrays": join_arrays, | 416 "join_arrays": join_arrays, |
382 "resolve_type": resolve_type, | 417 "resolve_type": resolve_type, |
383 "type_definition": type_definition, | 418 "type_definition": type_definition, |
384 "has_disable": has_disable, | 419 "has_disable": has_disable, |
385 "export_macro": export_macro, | 420 "export_macro": export_macro, |
386 "output_package": output_package, | 421 "output_package": output_package |
387 "exported_package": exported_package, | |
388 "include_package": include_package | |
389 } | 422 } |
390 out_file = output_file(file_name) | 423 if exporting: |
391 out_file.write(template.render(template_context)) | 424 template_context["exported_package"] = exported_package |
392 out_file.close() | 425 if importing: |
| 426 template_context["imported_package"] = imported_package |
| 427 generate_with_context(template_context, template, file_name) |
393 | 428 |
394 | 429 |
395 generate_domains = [] | 430 def read_protocol_file(file_name, all_domains): |
396 include_domains = [] | 431 input_file = open(file_name, "r") |
397 json_api = {} | |
398 json_api["domains"] = parsed_json["domains"] | |
399 | |
400 for domain in parsed_json["domains"]: | |
401 generate_domains.append(domain["domain"]) | |
402 | |
403 if include_file: | |
404 input_file = open(include_file, "r") | |
405 json_string = input_file.read() | 432 json_string = input_file.read() |
406 parsed_json = json.loads(json_string) | 433 parsed_json = json.loads(json_string) |
| 434 domains = [] |
407 for domain in parsed_json["domains"]: | 435 for domain in parsed_json["domains"]: |
408 include_domains.append(domain["domain"]) | 436 domains.append(domain["domain"]) |
409 json_api["domains"] += parsed_json["domains"] | 437 all_domains["domains"] += parsed_json["domains"] |
| 438 return domains |
410 | 439 |
| 440 |
| 441 json_api = {"domains": []} |
| 442 generate_domains = read_protocol_file(protocol_file, json_api) |
| 443 imported_domains = read_protocol_file(imported_file, json_api) if importing else
[] |
411 patch_full_qualified_refs() | 444 patch_full_qualified_refs() |
412 calculate_exports() | 445 calculate_exports() |
413 create_type_definitions() | 446 create_type_definitions() |
414 | 447 |
415 if up_to_date(): | 448 if up_to_date(): |
416 sys.exit() | 449 sys.exit() |
417 if not os.path.exists(output_dirname): | 450 if not os.path.exists(output_dirname): |
418 os.mkdir(output_dirname) | 451 os.mkdir(output_dirname) |
419 if json_api["has_exports"] and not os.path.exists(exported_dirname): | 452 if json_api["has_exports"] and not os.path.exists(exported_dirname): |
420 os.mkdir(exported_dirname) | 453 os.mkdir(exported_dirname) |
421 | 454 |
422 jinja_env = initialize_jinja_env(output_dirname) | 455 jinja_env = initialize_jinja_env(output_dirname) |
423 h_template = jinja_env.get_template("/TypeBuilder_h.template") | 456 h_template = jinja_env.get_template("/TypeBuilder_h.template") |
424 cpp_template = jinja_env.get_template("/TypeBuilder_cpp.template") | 457 cpp_template = jinja_env.get_template("/TypeBuilder_cpp.template") |
425 exported_template = jinja_env.get_template("/Exported_h.template") | 458 exported_template = jinja_env.get_template("/Exported_h.template") |
426 imported_template = jinja_env.get_template("/Imported_h.template") | 459 imported_template = jinja_env.get_template("/Imported_h.template") |
427 | 460 |
428 for domain in json_api["domains"]: | 461 for domain in json_api["domains"]: |
429 class_name = domain["domain"] | 462 class_name = domain["domain"] |
430 if domain["domain"] in generate_domains: | 463 if domain["domain"] in generate_domains: |
431 generate(domain, h_template, output_dirname + "/" + class_name + ".h") | 464 generate(domain, h_template, os.path.join(output_dirname, class_name + "
.h")) |
432 generate(domain, cpp_template, output_dirname + "/" + class_name + ".cpp
") | 465 generate(domain, cpp_template, os.path.join(output_dirname, class_name +
".cpp")) |
433 if domain["has_exports"]: | 466 if domain["has_exports"]: |
434 generate(domain, exported_template, exported_dirname + "/" + class_n
ame + ".h") | 467 generate(domain, exported_template, os.path.join(exported_dirname, c
lass_name + ".h")) |
435 if domain["domain"] in include_domains and domain["has_exports"]: | 468 if domain["domain"] in imported_domains and domain["has_exports"]: |
436 generate(domain, imported_template, output_dirname + "/" + class_name +
".h") | 469 generate(domain, imported_template, os.path.join(output_dirname, class_n
ame + ".h")) |
OLD | NEW |