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

Side by Side Diff: CodeGenerator.py

Issue 2495353004: [inspector_protocol] Support chromium code style. (Closed)
Patch Set: Created 4 years, 1 month 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 | lib/Collections_h.template » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 import collections 8 import collections
9 import functools 9 import functools
10 import re
10 try: 11 try:
11 import json 12 import json
12 except ImportError: 13 except ImportError:
13 import simplejson as json 14 import simplejson as json
14 15
15 # Path handling for libraries and templates 16 # Path handling for libraries and templates
16 # Paths have to be normalized because Jinja uses the exact template path to 17 # Paths have to be normalized because Jinja uses the exact template path to
17 # determine the hash used in the cache filename, and we need a pre-caching step 18 # determine the hash used in the cache filename, and we need a pre-caching step
18 # to be concurrency-safe. Use absolute path because __file__ is absolute if 19 # to be concurrency-safe. Use absolute path because __file__ is absolute if
19 # module is imported, and relative if executed directly. 20 # module is imported, and relative if executed directly.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 exc = sys.exc_info()[1] 73 exc = sys.exc_info()[1]
73 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) 74 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
74 exit(1) 75 exit(1)
75 76
76 try: 77 try:
77 config_json_file = open(config_file, "r") 78 config_json_file = open(config_file, "r")
78 config_json_string = config_json_file.read() 79 config_json_string = config_json_file.read()
79 config_partial = json_to_object(config_json_string, output_base, config_ base) 80 config_partial = json_to_object(config_json_string, output_base, config_ base)
80 config_json_file.close() 81 config_json_file.close()
81 defaults = { 82 defaults = {
83 ".use_snake_file_names": False,
84 ".use_title_case_methods": False,
82 ".imported": False, 85 ".imported": False,
83 ".imported.export_macro": "", 86 ".imported.export_macro": "",
84 ".imported.export_header": False, 87 ".imported.export_header": False,
85 ".imported.header": False, 88 ".imported.header": False,
86 ".imported.package": False, 89 ".imported.package": False,
87 ".protocol.export_macro": "", 90 ".protocol.export_macro": "",
88 ".protocol.export_header": False, 91 ".protocol.export_header": False,
89 ".protocol.options": False, 92 ".protocol.options": False,
90 ".exported": False, 93 ".exported": False,
91 ".exported.export_macro": "", 94 ".exported.export_macro": "",
(...skipping 19 matching lines...) Expand all
111 114
112 115
113 def dash_to_camelcase(word): 116 def dash_to_camelcase(word):
114 prefix = "" 117 prefix = ""
115 if word[0] == "-": 118 if word[0] == "-":
116 prefix = "Negative" 119 prefix = "Negative"
117 word = word[1:] 120 word = word[1:]
118 return prefix + "".join(to_title_case(x) or "-" for x in word.split("-")) 121 return prefix + "".join(to_title_case(x) or "-" for x in word.split("-"))
119 122
120 123
121 def initialize_jinja_env(jinja_dir, cache_dir): 124 def to_snake_case(name):
125 return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name, sys.maxint).lower()
126
127
128 def to_method_case(config, name):
129 if config.use_title_case_methods:
130 return to_title_case(name)
131 return name
132
133
134 def initialize_jinja_env(jinja_dir, cache_dir, config):
122 # pylint: disable=F0401 135 # pylint: disable=F0401
123 sys.path.insert(1, os.path.abspath(jinja_dir)) 136 sys.path.insert(1, os.path.abspath(jinja_dir))
124 import jinja2 137 import jinja2
125 138
126 jinja_env = jinja2.Environment( 139 jinja_env = jinja2.Environment(
127 loader=jinja2.FileSystemLoader(module_path), 140 loader=jinja2.FileSystemLoader(module_path),
128 # Bytecode cache is not concurrency-safe unless pre-cached: 141 # Bytecode cache is not concurrency-safe unless pre-cached:
129 # if pre-cached this is read-only, but writing creates a race condition. 142 # if pre-cached this is read-only, but writing creates a race condition.
130 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), 143 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
131 keep_trailing_newline=True, # newline-terminate generated files 144 keep_trailing_newline=True, # newline-terminate generated files
132 lstrip_blocks=True, # so can indent control flow tags 145 lstrip_blocks=True, # so can indent control flow tags
133 trim_blocks=True) 146 trim_blocks=True)
134 jinja_env.filters.update({"to_title_case": to_title_case, "dash_to_camelcase ": dash_to_camelcase}) 147 jinja_env.filters.update({"to_title_case": to_title_case, "dash_to_camelcase ": dash_to_camelcase, "to_method_case": functools.partial(to_method_case, config )})
135 jinja_env.add_extension("jinja2.ext.loopcontrols") 148 jinja_env.add_extension("jinja2.ext.loopcontrols")
136 return jinja_env 149 return jinja_env
137 150
138 151
139 def patch_full_qualified_refs(protocol): 152 def patch_full_qualified_refs(protocol):
140 def patch_full_qualified_refs_in_domain(json, domain_name): 153 def patch_full_qualified_refs_in_domain(json, domain_name):
141 if isinstance(json, list): 154 if isinstance(json, list):
142 for item in json: 155 for item in json:
143 patch_full_qualified_refs_in_domain(item, domain_name) 156 patch_full_qualified_refs_in_domain(item, domain_name)
144 157
145 if not isinstance(json, dict): 158 if not isinstance(json, dict):
146 return 159 return
147 for key in json: 160 for key in json:
148 if key == "type" and json[key] == "string": 161 if key == "type" and json[key] == "string":
149 json[key] = domain_name + ".string" 162 json[key] = domain_name + ".string"
150 if key != "$ref": 163 if key != "$ref":
151 patch_full_qualified_refs_in_domain(json[key], domain_name) 164 patch_full_qualified_refs_in_domain(json[key], domain_name)
152 continue 165 continue
153 if json["$ref"].find(".") == -1: 166 if json["$ref"].find(".") == -1:
154 json["$ref"] = domain_name + "." + json["$ref"] 167 json["$ref"] = domain_name + "." + json["$ref"]
155 return 168 return
156 169
157 for domain in protocol.json_api["domains"]: 170 for domain in protocol.json_api["domains"]:
158 patch_full_qualified_refs_in_domain(domain, domain["domain"]) 171 patch_full_qualified_refs_in_domain(domain, domain["domain"])
159 172
160 173
161 def calculate_exports(protocol): 174 def calculate_imports_and_exports(config, protocol):
162 def calculate_exports_in_json(json_value): 175 def has_exports(json_value, clear):
163 has_exports = False 176 result = False
164 if isinstance(json_value, list): 177 if isinstance(json_value, list):
165 for item in json_value: 178 for item in json_value:
166 has_exports = calculate_exports_in_json(item) or has_exports 179 result = has_exports(item, clear) or result
167 if isinstance(json_value, dict): 180 if isinstance(json_value, dict):
168 has_exports = ("exported" in json_value and json_value["exported"]) or has_exports 181 if "exported" in json_value and json_value["exported"]:
182 result = True
183 if "exported" in json_value and clear:
184 del json_value["exported"]
169 for key in json_value: 185 for key in json_value:
170 has_exports = calculate_exports_in_json(json_value[key]) or has_ exports 186 result = has_exports(json_value[key], clear) or result
171 return has_exports 187 return result
172 188
173 protocol.json_api["has_exports"] = False 189 imported_domains = protocol.imported_domains
190 if config.protocol.options:
191 protocol.generate_domains = [rule.domain for rule in config.protocol.opt ions]
192 imported_domains = list(set(protocol.imported_domains) - set(protocol.ge nerate_domains))
193 exported_domains = protocol.generate_domains
194
195 protocol.imported_domains = []
196 protocol.exported_domains = []
174 for domain_json in protocol.json_api["domains"]: 197 for domain_json in protocol.json_api["domains"]:
175 domain_json["has_exports"] = calculate_exports_in_json(domain_json) 198 domain = domain_json["domain"]
176 if domain_json["has_exports"] and domain_json["domain"] in protocol.gene rate_domains: 199 clear = domain not in exported_domains and domain not in imported_domain s
177 protocol.json_api["has_exports"] = True 200 if not has_exports(domain_json, clear):
201 continue
202 if domain in exported_domains:
203 protocol.exported_domains.append(domain)
204 if domain in imported_domains:
205 protocol.imported_domains.append(domain)
178 206
179 207
180 def create_imported_type_definition(domain_name, type, imported_namespace): 208 def create_imported_type_definition(domain_name, type, imported_namespace):
181 # pylint: disable=W0622 209 # pylint: disable=W0622
182 return { 210 return {
183 "return_type": "std::unique_ptr<%s::%s::API::%s>" % (imported_namespace, domain_name, type["id"]), 211 "return_type": "std::unique_ptr<%s::%s::API::%s>" % (imported_namespace, domain_name, type["id"]),
184 "pass_type": "std::unique_ptr<%s::%s::API::%s>" % (imported_namespace, d omain_name, type["id"]), 212 "pass_type": "std::unique_ptr<%s::%s::API::%s>" % (imported_namespace, d omain_name, type["id"]),
185 "to_raw_type": "%s.get()", 213 "to_raw_type": "%s.get()",
186 "to_pass_type": "std::move(%s)", 214 "to_pass_type": "std::move(%s)",
187 "to_rvalue": "std::move(%s)", 215 "to_rvalue": "std::move(%s)",
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 415
388 def generate_disable(protocol, config, domain): 416 def generate_disable(protocol, config, domain):
389 if "commands" not in domain: 417 if "commands" not in domain:
390 return True 418 return True
391 for command in domain["commands"]: 419 for command in domain["commands"]:
392 if command["name"] == "disable" and generate_command(protocol, config, d omain["domain"], "disable"): 420 if command["name"] == "disable" and generate_command(protocol, config, d omain["domain"], "disable"):
393 return False 421 return False
394 return True 422 return True
395 423
396 424
397 def format_include(header): 425 def format_include(config, header, file_name=None):
398 return "\"" + header + "\"" if header[0] not in "<\"" else header 426 if file_name is not None:
427 header = header + "/" + file_name + ".h"
428 header = "\"" + header + "\"" if header[0] not in "<\"" else header
429 if config.use_snake_file_names:
430 header = to_snake_case(header)
431 return header
432
433
434 def to_file_name(config, file_name):
435 if config.use_snake_file_names:
436 return to_snake_case(file_name).replace(".cpp", ".cc")
437 return file_name
399 438
400 439
401 def read_protocol_file(file_name, json_api): 440 def read_protocol_file(file_name, json_api):
402 input_file = open(file_name, "r") 441 input_file = open(file_name, "r")
403 json_string = input_file.read() 442 json_string = input_file.read()
404 input_file.close() 443 input_file.close()
405 parsed_json = json.loads(json_string) 444 parsed_json = json.loads(json_string)
406 version = parsed_json["version"]["major"] + "." + parsed_json["version"]["mi nor"] 445 version = parsed_json["version"]["major"] + "." + parsed_json["version"]["mi nor"]
407 domains = [] 446 domains = []
408 for domain in parsed_json["domains"]: 447 for domain in parsed_json["domains"]:
409 domains.append(domain["domain"]) 448 domains.append(domain["domain"])
410 domain["version"] = version 449 domain["version"] = version
411 json_api["domains"] += parsed_json["domains"] 450 json_api["domains"] += parsed_json["domains"]
412 return domains 451 return domains
413 452
414 453
415 class Protocol(object): 454 class Protocol(object):
416 def __init__(self): 455 def __init__(self):
417 self.json_api = {} 456 self.json_api = {}
418 self.generate_domains = [] 457 self.generate_domains = []
419 self.imported_domains = [] 458 self.imported_domains = []
459 self.exported_domains = []
420 460
421 461
422 def main(): 462 def main():
423 jinja_dir, config_file, config = read_config() 463 jinja_dir, config_file, config = read_config()
424 464
425 protocol = Protocol() 465 protocol = Protocol()
426 protocol.json_api = {"domains": []} 466 protocol.json_api = {"domains": []}
427 protocol.generate_domains = read_protocol_file(config.protocol.path, protoco l.json_api) 467 protocol.generate_domains = read_protocol_file(config.protocol.path, protoco l.json_api)
428 protocol.imported_domains = read_protocol_file(config.imported.path, protoco l.json_api) if config.imported else [] 468 protocol.imported_domains = read_protocol_file(config.imported.path, protoco l.json_api) if config.imported else []
429 patch_full_qualified_refs(protocol) 469 patch_full_qualified_refs(protocol)
430 calculate_exports(protocol) 470 calculate_imports_and_exports(config, protocol)
431 create_type_definitions(protocol, "::".join(config.imported.namespace) if co nfig.imported else "") 471 create_type_definitions(protocol, "::".join(config.imported.namespace) if co nfig.imported else "")
432 472
433 if not config.exported: 473 if not config.exported and len(protocol.exported_domains):
434 for domain_json in protocol.json_api["domains"]: 474 sys.stderr.write("Domains [%s] are exported, but config is missing expor t entry\n\n" % ", ".join(protocol.exported_domains))
435 if domain_json["has_exports"] and domain_json["domain"] in protocol. generate_domains: 475 exit(1)
436 sys.stderr.write("Domain %s is exported, but config is missing e xport entry\n\n" % domain_json["domain"])
437 exit(1)
438 476
439 if not os.path.exists(config.protocol.output): 477 if not os.path.exists(config.protocol.output):
440 os.mkdir(config.protocol.output) 478 os.mkdir(config.protocol.output)
441 if protocol.json_api["has_exports"] and not os.path.exists(config.exported.o utput): 479 if len(protocol.exported_domains) and not os.path.exists(config.exported.out put):
442 os.mkdir(config.exported.output) 480 os.mkdir(config.exported.output)
443 jinja_env = initialize_jinja_env(jinja_dir, config.protocol.output) 481 jinja_env = initialize_jinja_env(jinja_dir, config.protocol.output, config)
444 482
445 inputs = [] 483 inputs = []
446 inputs.append(__file__) 484 inputs.append(__file__)
447 inputs.append(config_file) 485 inputs.append(config_file)
448 inputs.append(config.protocol.path) 486 inputs.append(config.protocol.path)
449 if config.imported: 487 if config.imported:
450 inputs.append(config.imported.path) 488 inputs.append(config.imported.path)
451 templates_dir = os.path.join(module_path, "templates") 489 templates_dir = os.path.join(module_path, "templates")
452 inputs.append(os.path.join(templates_dir, "TypeBuilder_h.template")) 490 inputs.append(os.path.join(templates_dir, "TypeBuilder_h.template"))
453 inputs.append(os.path.join(templates_dir, "TypeBuilder_cpp.template")) 491 inputs.append(os.path.join(templates_dir, "TypeBuilder_cpp.template"))
(...skipping 12 matching lines...) Expand all
466 template_context = { 504 template_context = {
467 "config": config, 505 "config": config,
468 "domain": domain, 506 "domain": domain,
469 "join_arrays": join_arrays, 507 "join_arrays": join_arrays,
470 "resolve_type": functools.partial(resolve_type, protocol), 508 "resolve_type": functools.partial(resolve_type, protocol),
471 "type_definition": functools.partial(type_definition, protocol), 509 "type_definition": functools.partial(type_definition, protocol),
472 "generate_command": functools.partial(generate_command, protocol, co nfig), 510 "generate_command": functools.partial(generate_command, protocol, co nfig),
473 "generate_event": functools.partial(generate_event, protocol, config ), 511 "generate_event": functools.partial(generate_event, protocol, config ),
474 "is_async_command": functools.partial(is_async_command, protocol, co nfig), 512 "is_async_command": functools.partial(is_async_command, protocol, co nfig),
475 "generate_disable": functools.partial(generate_disable, protocol, co nfig), 513 "generate_disable": functools.partial(generate_disable, protocol, co nfig),
476 "format_include": format_include 514 "format_include": functools.partial(format_include, config),
477 } 515 }
478 516
479 if domain["domain"] in protocol.generate_domains: 517 if domain["domain"] in protocol.generate_domains:
480 outputs[os.path.join(config.protocol.output, class_name + ".h")] = h _template.render(template_context) 518 outputs[os.path.join(config.protocol.output, to_file_name(config, cl ass_name + ".h"))] = h_template.render(template_context)
481 outputs[os.path.join(config.protocol.output, class_name + ".cpp")] = cpp_template.render(template_context) 519 outputs[os.path.join(config.protocol.output, to_file_name(config, cl ass_name + ".cpp"))] = cpp_template.render(template_context)
482 if domain["has_exports"]: 520 if domain["domain"] in protocol.exported_domains:
483 outputs[os.path.join(config.exported.output, class_name + ".h")] = exported_template.render(template_context) 521 outputs[os.path.join(config.exported.output, to_file_name(config , class_name + ".h"))] = exported_template.render(template_context)
484 if domain["domain"] in protocol.imported_domains and domain["has_exports "]: 522 if domain["domain"] in protocol.imported_domains:
485 outputs[os.path.join(config.protocol.output, class_name + ".h")] = i mported_template.render(template_context) 523 outputs[os.path.join(config.protocol.output, to_file_name(config, cl ass_name + ".h"))] = imported_template.render(template_context)
486 524
487 if config.lib: 525 if config.lib:
488 template_context = { 526 template_context = {
489 "config": config, 527 "config": config,
490 "format_include": format_include, 528 "format_include": functools.partial(format_include, config),
491 } 529 }
492 530
493 lib_templates_dir = os.path.join(module_path, "lib") 531 lib_templates_dir = os.path.join(module_path, "lib")
494 # Note these should be sorted in the right order. 532 # Note these should be sorted in the right order.
495 # TODO(dgozman): sort them programmatically based on commented includes. 533 # TODO(dgozman): sort them programmatically based on commented includes.
496 lib_h_templates = [ 534 lib_h_templates = [
497 "Collections_h.template", 535 "Collections_h.template",
498 "ErrorSupport_h.template", 536 "ErrorSupport_h.template",
499 "Values_h.template", 537 "Values_h.template",
500 "Object_h.template", 538 "Object_h.template",
(...skipping 20 matching lines...) Expand all
521 ] 559 ]
522 560
523 def generate_lib_file(file_name, template_files): 561 def generate_lib_file(file_name, template_files):
524 parts = [] 562 parts = []
525 for template_file in template_files: 563 for template_file in template_files:
526 inputs.append(os.path.join(lib_templates_dir, template_file)) 564 inputs.append(os.path.join(lib_templates_dir, template_file))
527 template = jinja_env.get_template("lib/" + template_file) 565 template = jinja_env.get_template("lib/" + template_file)
528 parts.append(template.render(template_context)) 566 parts.append(template.render(template_context))
529 outputs[file_name] = "\n\n".join(parts) 567 outputs[file_name] = "\n\n".join(parts)
530 568
531 generate_lib_file(os.path.join(config.lib.output, "Forward.h"), forward_ h_templates) 569 generate_lib_file(os.path.join(config.lib.output, to_file_name(config, " Forward.h")), forward_h_templates)
532 generate_lib_file(os.path.join(config.lib.output, "Protocol.h"), lib_h_t emplates) 570 generate_lib_file(os.path.join(config.lib.output, to_file_name(config, " Protocol.h")), lib_h_templates)
533 generate_lib_file(os.path.join(config.lib.output, "Protocol.cpp"), lib_c pp_templates) 571 generate_lib_file(os.path.join(config.lib.output, to_file_name(config, " Protocol.cpp")), lib_cpp_templates)
534 572
535 # Make gyp / make generatos happy, otherwise make rebuilds world. 573 # Make gyp / make generatos happy, otherwise make rebuilds world.
536 inputs_ts = max(map(os.path.getmtime, inputs)) 574 inputs_ts = max(map(os.path.getmtime, inputs))
537 up_to_date = True 575 up_to_date = True
538 for output_file in outputs.iterkeys(): 576 for output_file in outputs.iterkeys():
539 if not os.path.exists(output_file) or os.path.getmtime(output_file) < in puts_ts: 577 if not os.path.exists(output_file) or os.path.getmtime(output_file) < in puts_ts:
540 up_to_date = False 578 up_to_date = False
541 break 579 break
542 if up_to_date: 580 if up_to_date:
543 sys.exit() 581 sys.exit()
544 582
545 for file_name, content in outputs.iteritems(): 583 for file_name, content in outputs.iteritems():
546 out_file = open(file_name, "w") 584 out_file = open(file_name, "w")
547 out_file.write(content) 585 out_file.write(content)
548 out_file.close() 586 out_file.close()
549 587
550 588
551 main() 589 main()
OLDNEW
« no previous file with comments | « no previous file | lib/Collections_h.template » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698