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

Side by Side Diff: third_party/WebKit/Source/platform/inspector_protocol/CodeGenerator.py

Issue 2159633002: [DevTools] Generate public versions of protocol classes to be exposed in v8_inspector/public. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: works Created 4 years, 5 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 # 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 25 matching lines...) Expand all
36 36
37 if os.path.isdir(deps_dir): 37 if os.path.isdir(deps_dir):
38 sys.path.insert(1, os.path.join(deps_dir, "jinja2")) 38 sys.path.insert(1, os.path.join(deps_dir, "jinja2"))
39 sys.path.insert(1, os.path.join(deps_dir, "markupsafe")) 39 sys.path.insert(1, os.path.join(deps_dir, "markupsafe"))
40 40
41 import jinja2 41 import jinja2
42 42
43 cmdline_parser = optparse.OptionParser() 43 cmdline_parser = optparse.OptionParser()
44 cmdline_parser.add_option("--protocol") 44 cmdline_parser.add_option("--protocol")
45 cmdline_parser.add_option("--include") 45 cmdline_parser.add_option("--include")
46 cmdline_parser.add_option("--include_package")
46 cmdline_parser.add_option("--string_type") 47 cmdline_parser.add_option("--string_type")
47 cmdline_parser.add_option("--export_macro") 48 cmdline_parser.add_option("--export_macro")
48 cmdline_parser.add_option("--output_dir") 49 cmdline_parser.add_option("--output_dir")
49 cmdline_parser.add_option("--output_package") 50 cmdline_parser.add_option("--output_package")
51 cmdline_parser.add_option("--exported_dir")
52 cmdline_parser.add_option("--exported_package")
50 53
51 try: 54 try:
52 arg_options, arg_values = cmdline_parser.parse_args() 55 arg_options, arg_values = cmdline_parser.parse_args()
53 protocol_file = arg_options.protocol 56 protocol_file = arg_options.protocol
54 if not protocol_file: 57 if not protocol_file:
55 raise Exception("Protocol directory must be specified") 58 raise Exception("Protocol directory must be specified")
56 include_file = arg_options.include 59 include_file = arg_options.include
60 include_package = arg_options.include_package
61 if include_file and not include_package:
62 raise Exception("Include package must be specified when using include fi le")
63 if include_package and not include_file:
64 raise Exception("Include file must be specified when using include packa ge")
57 output_dirname = arg_options.output_dir 65 output_dirname = arg_options.output_dir
58 if not output_dirname: 66 if not output_dirname:
59 raise Exception("Output directory must be specified") 67 raise Exception("Output directory must be specified")
60 output_package = arg_options.output_package 68 output_package = arg_options.output_package
61 if not output_package: 69 if not output_package:
62 raise Exception("Output package must be specified") 70 raise Exception("Output package must be specified")
71 exported_dirname = arg_options.exported_dir
72 if not exported_dirname:
73 exported_dirname = os.path.join(output_dirname, "exported")
74 exported_package = arg_options.exported_package
75 if not exported_package:
76 exported_package = os.path.join(output_package, "exported")
63 string_type = arg_options.string_type 77 string_type = arg_options.string_type
64 if not string_type: 78 if not string_type:
65 raise Exception("String type must be specified") 79 raise Exception("String type must be specified")
66 export_macro = arg_options.export_macro 80 export_macro = arg_options.export_macro
67 if not export_macro: 81 if not export_macro:
68 raise Exception("Export macro must be specified") 82 raise Exception("Export macro must be specified")
69 except Exception: 83 except Exception:
70 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html 84 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
71 exc = sys.exc_info()[1] 85 exc = sys.exc_info()[1]
72 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) 86 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
73 exit(1) 87 exit(1)
74 88
75 89
76 input_file = open(protocol_file, "r") 90 input_file = open(protocol_file, "r")
77 json_string = input_file.read() 91 json_string = input_file.read()
78 parsed_json = json.loads(json_string) 92 parsed_json = json.loads(json_string)
79 93
80 94
81 # Make gyp / make generatos happy, otherwise make rebuilds world. 95 # Make gyp / make generatos happy, otherwise make rebuilds world.
82 def up_to_date(): 96 def up_to_date():
83 template_ts = max( 97 template_ts = max(
84 os.path.getmtime(__file__), 98 os.path.getmtime(__file__),
85 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_h.template")), 99 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_h.template")),
86 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_cpp.template") ), 100 os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_cpp.template") ),
101 os.path.getmtime(os.path.join(templates_dir, "Exported_h.template")),
87 os.path.getmtime(protocol_file)) 102 os.path.getmtime(protocol_file))
88 103
89 for domain in parsed_json["domains"]: 104 for domain in parsed_json["domains"]:
90 name = domain["domain"] 105 name = domain["domain"]
91 h_path = os.path.join(output_dirname, name + ".h") 106 paths = [os.path.join(output_dirname, name + ".h"), os.path.join(output_ dirname, name + ".cpp")]
pfeldman 2016/07/22 18:02:40 If imports have changed, we should regenerate.
dgozman 2016/07/22 21:21:19 Done.
92 cpp_path = os.path.join(output_dirname, name + ".cpp") 107 if domain["has_exports"]:
93 if not os.path.exists(h_path) or not os.path.exists(cpp_path): 108 paths.append(os.path.join(exported_dirname, name + ".h"))
94 return False 109 for path in paths:
95 generated_ts = max(os.path.getmtime(h_path), os.path.getmtime(cpp_path)) 110 if not os.path.exists(path):
96 if generated_ts < template_ts: 111 return False
97 return False 112 generated_ts = os.path.getmtime(path)
113 if generated_ts < template_ts:
114 return False
98 return True 115 return True
99 116
100 117
101 if up_to_date():
102 sys.exit()
103
104
105 def to_title_case(name): 118 def to_title_case(name):
106 return name[:1].upper() + name[1:] 119 return name[:1].upper() + name[1:]
107 120
108 121
109 def dash_to_camelcase(word): 122 def dash_to_camelcase(word):
110 return "".join(to_title_case(x) or "-" for x in word.split("-")) 123 return "".join(to_title_case(x) or "-" for x in word.split("-"))
111 124
112 125
113 def initialize_jinja_env(cache_dir): 126 def initialize_jinja_env(cache_dir):
114 jinja_env = jinja2.Environment( 127 jinja_env = jinja2.Environment(
115 loader=jinja2.FileSystemLoader(templates_dir), 128 loader=jinja2.FileSystemLoader(templates_dir),
116 # Bytecode cache is not concurrency-safe unless pre-cached: 129 # Bytecode cache is not concurrency-safe unless pre-cached:
117 # if pre-cached this is read-only, but writing creates a race condition. 130 # if pre-cached this is read-only, but writing creates a race condition.
118 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), 131 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
119 keep_trailing_newline=True, # newline-terminate generated files 132 keep_trailing_newline=True, # newline-terminate generated files
120 lstrip_blocks=True, # so can indent control flow tags 133 lstrip_blocks=True, # so can indent control flow tags
121 trim_blocks=True) 134 trim_blocks=True)
122 jinja_env.filters.update({"to_title_case": to_title_case, "dash_to_camelcase ": dash_to_camelcase}) 135 jinja_env.filters.update({"to_title_case": to_title_case, "dash_to_camelcase ": dash_to_camelcase})
123 jinja_env.add_extension("jinja2.ext.loopcontrols") 136 jinja_env.add_extension("jinja2.ext.loopcontrols")
124 return jinja_env 137 return jinja_env
125 138
126 139
127 def output_file(file_name): 140 def output_file(file_name):
128 return open(file_name, "w") 141 return open(file_name, "w")
129 142
130 143
131 def patch_full_qualified_refs(): 144 def patch_full_qualified_refs():
pfeldman 2016/07/22 18:02:40 Copy-paste it.
dgozman 2016/07/22 21:21:19 Done.
132 def patch_full_qualified_refs_in_domain(json, domain_name): 145 def patch_full_qualified_refs_in_domain(json, domain_name):
146 has_exports = False
133 if isinstance(json, list): 147 if isinstance(json, list):
134 for item in json: 148 for item in json:
135 patch_full_qualified_refs_in_domain(item, domain_name) 149 has_exports = patch_full_qualified_refs_in_domain(item, domain_n ame) or has_exports
136 150
137 if not isinstance(json, dict): 151 if not isinstance(json, dict):
138 return 152 return has_exports
153 has_exports = ("exported" in json and json["exported"]) or has_exports
139 for key in json: 154 for key in json:
140 if key == "type" and json[key] == "string": 155 if key == "type" and json[key] == "string":
141 json[key] = domain_name + ".string" 156 json[key] = domain_name + ".string"
142 if key != "$ref": 157 if key != "$ref":
143 patch_full_qualified_refs_in_domain(json[key], domain_name) 158 has_exports = patch_full_qualified_refs_in_domain(json[key], dom ain_name) or has_exports
144 continue 159 continue
145 if json["$ref"].find(".") == -1: 160 if json["$ref"].find(".") == -1:
146 json["$ref"] = domain_name + "." + json["$ref"] 161 json["$ref"] = domain_name + "." + json["$ref"]
162 return has_exports
147 163
164 json_api["has_exports"] = False
148 for domain in json_api["domains"]: 165 for domain in json_api["domains"]:
149 patch_full_qualified_refs_in_domain(domain, domain["domain"]) 166 domain["has_exports"] = patch_full_qualified_refs_in_domain(domain, doma in["domain"])
167 json_api["has_exports"] = json_api["has_exports"] or domain["has_exports "]
168
169
170 def create_include_type_definition(domain_name, type):
171 # pylint: disable=W0622
pfeldman 2016/07/22 18:02:40 While you are so smart...
172 return {
173 "return_type": "std::unique_ptr<protocol::%s::Exported::%s>" % (domain_n ame, type["id"]),
174 "pass_type": "std::unique_ptr<protocol::%s::Exported::%s>" % (domain_nam e, type["id"]),
175 "to_raw_type": "%s.get()",
176 "to_pass_type": "std::move(%s)",
177 "to_rvalue": "std::move(%s)",
178 "type": "std::unique_ptr<protocol::%s::Exported::%s>" % (domain_name, ty pe["id"]),
179 "raw_type": "protocol::%s::Exported::%s" % (domain_name, type["id"]),
180 "raw_pass_type": "protocol::%s::Exported::%s*" % (domain_name, type["id" ]),
181 "raw_return_type": "protocol::%s::Exported::%s*" % (domain_name, type["i d"]),
182 }
150 183
151 184
152 def create_user_type_definition(domain_name, type): 185 def create_user_type_definition(domain_name, type):
153 return { 186 return {
154 "return_type": "std::unique_ptr<protocol::%s::%s>" % (domain_name, type[ "id"]), 187 "return_type": "std::unique_ptr<protocol::%s::%s>" % (domain_name, type[ "id"]),
155 "pass_type": "std::unique_ptr<protocol::%s::%s>" % (domain_name, type["i d"]), 188 "pass_type": "std::unique_ptr<protocol::%s::%s>" % (domain_name, type["i d"]),
156 "to_raw_type": "%s.get()", 189 "to_raw_type": "%s.get()",
157 "to_pass_type": "std::move(%s)", 190 "to_pass_type": "std::move(%s)",
158 "to_rvalue": "std::move(%s)", 191 "to_rvalue": "std::move(%s)",
159 "type": "std::unique_ptr<protocol::%s::%s>" % (domain_name, type["id"]), 192 "type": "std::unique_ptr<protocol::%s::%s>" % (domain_name, type["id"]),
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 "out_type": "protocol::Array<%s>&" % type["raw_type"], 291 "out_type": "protocol::Array<%s>&" % type["raw_type"],
259 } 292 }
260 293
261 294
262 def create_type_definitions(): 295 def create_type_definitions():
263 for domain in json_api["domains"]: 296 for domain in json_api["domains"]:
264 type_definitions[domain["domain"] + ".string"] = create_string_type_defi nition(domain["domain"]) 297 type_definitions[domain["domain"] + ".string"] = create_string_type_defi nition(domain["domain"])
265 if not ("types" in domain): 298 if not ("types" in domain):
266 continue 299 continue
267 for type in domain["types"]: 300 for type in domain["types"]:
268 if type["type"] == "object": 301 type_name = domain["domain"] + "." + type["id"]
269 type_definitions[domain["domain"] + "." + type["id"]] = create_u ser_type_definition(domain["domain"], type) 302 if type["type"] == "object" and domain["domain"] in include_domains:
303 type_definitions[type_name] = create_include_type_definition(dom ain["domain"], type)
304 elif type["type"] == "object":
305 type_definitions[type_name] = create_user_type_definition(domain ["domain"], type)
270 elif type["type"] == "array": 306 elif type["type"] == "array":
271 items_type = type["items"]["type"] 307 items_type = type["items"]["type"]
272 type_definitions[domain["domain"] + "." + type["id"]] = wrap_arr ay_definition(type_definitions[items_type]) 308 type_definitions[type_name] = wrap_array_definition(type_definit ions[items_type])
273 elif type["type"] == domain["domain"] + ".string": 309 elif type["type"] == domain["domain"] + ".string":
274 type_definitions[domain["domain"] + "." + type["id"]] = create_s tring_type_definition(domain["domain"]) 310 type_definitions[type_name] = create_string_type_definition(doma in["domain"])
275 else: 311 else:
276 type_definitions[domain["domain"] + "." + type["id"]] = create_p rimitive_type_definition(type["type"]) 312 type_definitions[type_name] = create_primitive_type_definition(t ype["type"])
277 313
278 314
279 def type_definition(name): 315 def type_definition(name):
280 return type_definitions[name] 316 return type_definitions[name]
281 317
282 318
283 def resolve_type(property): 319 def resolve_type(property):
284 if "$ref" in property: 320 if "$ref" in property:
285 return type_definitions[property["$ref"]] 321 return type_definitions[property["$ref"]]
286 if property["type"] == "array": 322 if property["type"] == "array":
287 return wrap_array_definition(resolve_type(property["items"])) 323 return wrap_array_definition(resolve_type(property["items"]))
288 return type_definitions[property["type"]] 324 return type_definitions[property["type"]]
289 325
290 326
291 def join_arrays(dict, keys): 327 def join_arrays(dict, keys):
292 result = [] 328 result = []
293 for key in keys: 329 for key in keys:
294 if key in dict: 330 if key in dict:
295 result += dict[key] 331 result += dict[key]
296 return result 332 return result
297 333
298 334
299 def has_disable(commands): 335 def has_disable(commands):
300 for command in commands: 336 for command in commands:
301 if command["name"] == "disable": 337 if command["name"] == "disable":
302 return True 338 return True
303 return False 339 return False
304 340
305 341
342 def generate(domain_object, template, file_name):
343 template_context = {
344 "domain": domain_object,
345 "join_arrays": join_arrays,
346 "resolve_type": resolve_type,
347 "type_definition": type_definition,
348 "has_disable": has_disable,
349 "export_macro": export_macro,
350 "output_package": output_package,
351 "exported_package": exported_package,
352 "include_package": include_package
353 }
354 out_file = output_file(file_name)
355 out_file.write(template.render(template_context))
356 out_file.close()
357
358
306 generate_domains = [] 359 generate_domains = []
360 include_domains = []
307 json_api = {} 361 json_api = {}
308 json_api["domains"] = parsed_json["domains"] 362 json_api["domains"] = parsed_json["domains"]
309 363
310 for domain in parsed_json["domains"]: 364 for domain in parsed_json["domains"]:
311 generate_domains.append(domain["domain"]) 365 generate_domains.append(domain["domain"])
312 366
313 if include_file: 367 if include_file:
314 input_file = open(include_file, "r") 368 input_file = open(include_file, "r")
315 json_string = input_file.read() 369 json_string = input_file.read()
316 parsed_json = json.loads(json_string) 370 parsed_json = json.loads(json_string)
371 for domain in parsed_json["domains"]:
372 include_domains.append(domain["domain"])
317 json_api["domains"] += parsed_json["domains"] 373 json_api["domains"] += parsed_json["domains"]
318 374
319
320 patch_full_qualified_refs() 375 patch_full_qualified_refs()
321 create_type_definitions() 376 create_type_definitions()
322 377
378 if up_to_date():
379 sys.exit()
323 if not os.path.exists(output_dirname): 380 if not os.path.exists(output_dirname):
324 os.mkdir(output_dirname) 381 os.mkdir(output_dirname)
382 if json_api["has_exports"] and not os.path.exists(exported_dirname):
383 os.mkdir(exported_dirname)
384
325 jinja_env = initialize_jinja_env(output_dirname) 385 jinja_env = initialize_jinja_env(output_dirname)
326 386 h_template = jinja_env.get_template("/TypeBuilder_h.template")
327 h_template_name = "/TypeBuilder_h.template" 387 cpp_template = jinja_env.get_template("/TypeBuilder_cpp.template")
328 cpp_template_name = "/TypeBuilder_cpp.template" 388 exported_template = jinja_env.get_template("/Exported_h.template")
329 h_template = jinja_env.get_template(h_template_name) 389 imported_template = jinja_env.get_template("/Imported_h.template")
330 cpp_template = jinja_env.get_template(cpp_template_name)
331
332
333 def generate(domain):
334 class_name = domain["domain"]
335 h_file_name = output_dirname + "/" + class_name + ".h"
336 cpp_file_name = output_dirname + "/" + class_name + ".cpp"
337
338 template_context = {
339 "domain": domain,
340 "join_arrays": join_arrays,
341 "resolve_type": resolve_type,
342 "type_definition": type_definition,
343 "has_disable": has_disable,
344 "export_macro": export_macro,
345 "output_package": output_package,
346 }
347 h_file = output_file(h_file_name)
348 cpp_file = output_file(cpp_file_name)
349 h_file.write(h_template.render(template_context))
350 cpp_file.write(cpp_template.render(template_context))
351 h_file.close()
352 cpp_file.close()
353
354 390
355 for domain in json_api["domains"]: 391 for domain in json_api["domains"]:
392 class_name = domain["domain"]
356 if domain["domain"] in generate_domains: 393 if domain["domain"] in generate_domains:
357 generate(domain) 394 generate(domain, h_template, output_dirname + "/" + class_name + ".h")
395 generate(domain, cpp_template, output_dirname + "/" + class_name + ".cpp ")
396 if domain["has_exports"]:
397 generate(domain, exported_template, exported_dirname + "/" + class_n ame + ".h")
398 if domain["domain"] in include_domains and domain["has_exports"]:
399 generate(domain, imported_template, output_dirname + "/" + class_name + ".h")
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698