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

Side by Side Diff: third_party/WebKit/Source/devtools/scripts/compile_frontend.py

Issue 2588843002: DevTools: speed up closure dependency checking (Closed)
Patch Set: update BUILD.gn Created 3 years, 12 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 Google Inc. All rights reserved. 2 # Copyright (c) 2012 Google Inc. All rights reserved.
3 # 3 #
4 # Redistribution and use in source and binary forms, with or without 4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are 5 # modification, are permitted provided that the following conditions are
6 # met: 6 # met:
7 # 7 #
8 # * Redistributions of source code must retain the above copyright 8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer. 9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above 10 # * Redistributions in binary form must reproduce the above
(...skipping 20 matching lines...) Expand all
31 import os.path as path 31 import os.path as path
32 import re 32 import re
33 import shutil 33 import shutil
34 import subprocess 34 import subprocess
35 import sys 35 import sys
36 import tempfile 36 import tempfile
37 37
38 from build import modular_build 38 from build import modular_build
39 from build import generate_protocol_externs 39 from build import generate_protocol_externs
40 40
41 import dependency_checker
41 import utils 42 import utils
42 43
43 try: 44 try:
44 import simplejson as json 45 import simplejson as json
45 except ImportError: 46 except ImportError:
46 import json 47 import json
47 48
48
49 if len(sys.argv) == 2 and sys.argv[1] == '--help':
50 print("Usage: %s [module_names]" % path.basename(sys.argv[0]))
51 print(" module_names list of modules for which the Closure compilation s hould run.")
52 print(" If absent, the entire frontend will be compiled.")
53 sys.exit(0)
54
55 is_cygwin = sys.platform == 'cygwin' 49 is_cygwin = sys.platform == 'cygwin'
56 50
57 51
58 def popen(arguments): 52 def popen(arguments):
59 return subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess .STDOUT) 53 return subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess .STDOUT)
60 54
61 def to_platform_path(filepath): 55 def to_platform_path(filepath):
62 if not is_cygwin: 56 if not is_cygwin:
63 return filepath 57 return filepath
64 return re.sub(r'^/cygdrive/(\w)', '\\1:', filepath) 58 return re.sub(r'^/cygdrive/(\w)', '\\1:', filepath)
65 59
66 60
67 def to_platform_path_exact(filepath): 61 def to_platform_path_exact(filepath):
68 if not is_cygwin: 62 if not is_cygwin:
69 return filepath 63 return filepath
70 output, _ = popen(['cygpath', '-w', filepath]).communicate() 64 output, _ = popen(['cygpath', '-w', filepath]).communicate()
71 # pylint: disable=E1103 65 # pylint: disable=E1103
72 return output.strip().replace('\\', '\\\\') 66 return output.strip().replace('\\', '\\\\')
73 67
74 scripts_path = path.dirname(path.abspath(__file__)) 68 scripts_path = path.dirname(path.abspath(__file__))
75 devtools_path = path.dirname(scripts_path) 69 devtools_path = path.dirname(scripts_path)
76 inspector_path = path.join(path.dirname(devtools_path), 'core', 'inspector') 70 inspector_path = path.join(path.dirname(devtools_path), 'core', 'inspector')
77 # TODO(dgozman): move these checks to v8. 71 # TODO(dgozman): move these checks to v8.
78 v8_inspector_path = path.normpath(path.join(path.dirname(devtools_path), os.pard ir, os.pardir, os.pardir, 'v8', 'src', 'inspector')) 72 v8_inspector_path = path.normpath(path.join(path.dirname(devtools_path), os.pard ir, os.pardir, os.pardir, 'v8', 'src', 'inspector'))
79 devtools_frontend_path = path.join(devtools_path, 'front_end') 73 devtools_frontend_path = path.join(devtools_path, 'front_end')
80 global_externs_file = to_platform_path(path.join(devtools_frontend_path, 'extern s.js')) 74 global_externs_file = to_platform_path(path.join(devtools_frontend_path, 'extern s.js'))
81 protocol_externs_file = path.join(devtools_frontend_path, 'protocol_externs.js') 75 protocol_externs_file = path.join(devtools_frontend_path, 'protocol_externs.js')
82 76 runtime_file = to_platform_path(path.join(devtools_frontend_path, 'Runtime.js'))
83 jsmodule_name_prefix = 'jsmodule_'
84 runtime_module_name = '_runtime'
85 77
86 type_checked_jsdoc_tags_list = ['param', 'return', 'type', 'enum'] 78 type_checked_jsdoc_tags_list = ['param', 'return', 'type', 'enum']
87 type_checked_jsdoc_tags_or = '|'.join(type_checked_jsdoc_tags_list) 79 type_checked_jsdoc_tags_or = '|'.join(type_checked_jsdoc_tags_list)
88 80
89 # Basic regex for invalid JsDoc types: an object type name ([A-Z][_A-Za-z0-9.]+[ A-Za-z0-9]) not preceded by '!', '?', ':' (this, new), or '.' (object property). 81 # Basic regex for invalid JsDoc types: an object type name ([A-Z][_A-Za-z0-9.]+[ A-Za-z0-9]) not preceded by '!', '?', ':' (this, new), or '.' (object property).
90 invalid_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{. *(?<![!?:._A-Za-z0-9])([A-Z][_A-Za-z0-9.]+[A-Za-z0-9])[^/]*\}') 82 invalid_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{. *(?<![!?:._A-Za-z0-9])([A-Z][_A-Za-z0-9.]+[A-Za-z0-9])[^/]*\}')
91 invalid_type_designator_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*.*(?<![{: ])([?!])=?\}') 83 invalid_type_designator_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*.*(?<![{: ])([?!])=?\}')
92 invalid_non_object_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{.*(![a-z]+)[^/]*\}') 84 invalid_non_object_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{.*(![a-z]+)[^/]*\}')
93 error_warning_regex = re.compile(r'WARNING|ERROR') 85 error_warning_regex = re.compile(r'WARNING|ERROR')
94 loaded_css_regex = re.compile(r'(?:registerRequiredCSS|WebInspector\.View\.creat eStyleElement)\s*\(\s*"(.+)"\s*\)') 86 loaded_css_regex = re.compile(r'(?:registerRequiredCSS|WebInspector\.View\.creat eStyleElement)\s*\(\s*"(.+)"\s*\)')
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 sys.exit(1) 211 sys.exit(1)
220 print 'Java executable: %s%s' % (java_path, '' if has_server_jvm else ' (no server JVM)') 212 print 'Java executable: %s%s' % (java_path, '' if has_server_jvm else ' (no server JVM)')
221 return exec_command 213 return exec_command
222 214
223 java_exec = find_java() 215 java_exec = find_java()
224 216
225 closure_compiler_jar = to_platform_path(path.join(scripts_path, 'closure', 'comp iler.jar')) 217 closure_compiler_jar = to_platform_path(path.join(scripts_path, 'closure', 'comp iler.jar'))
226 closure_runner_jar = to_platform_path(path.join(scripts_path, 'closure', 'closur e_runner', 'closure_runner.jar')) 218 closure_runner_jar = to_platform_path(path.join(scripts_path, 'closure', 'closur e_runner', 'closure_runner.jar'))
227 jsdoc_validator_jar = to_platform_path(path.join(scripts_path, 'jsdoc_validator' , 'jsdoc_validator.jar')) 219 jsdoc_validator_jar = to_platform_path(path.join(scripts_path, 'jsdoc_validator' , 'jsdoc_validator.jar'))
228 220
229 modules_dir = tempfile.mkdtemp()
230 common_closure_args = [ 221 common_closure_args = [
231 '--summary_detail_level', '3', 222 '--summary_detail_level', '3',
232 '--jscomp_error', 'visibility', 223 '--jscomp_error', 'visibility',
233 '--jscomp_warning', 'missingOverride', 224 '--jscomp_warning', 'missingOverride',
234 '--compilation_level', 'SIMPLE_OPTIMIZATIONS', 225 '--compilation_level', 'SIMPLE_OPTIMIZATIONS',
235 '--warning_level', 'VERBOSE', 226 '--warning_level', 'VERBOSE',
236 '--language_in=ES6_STRICT', 227 '--language_in=ES6_STRICT',
237 '--language_out=ES5_STRICT', 228 '--language_out=ES5_STRICT',
238 '--extra_annotation_name', 'suppressReceiverCheck', 229 '--extra_annotation_name', 'suppressReceiverCheck',
239 '--extra_annotation_name', 'suppressGlobalPropertiesCheck', 230 '--extra_annotation_name', 'suppressGlobalPropertiesCheck',
240 '--checks-only', 231 '--checks-only',
241 '--module_output_path_prefix', to_platform_path_exact(modules_dir + path.sep )
242 ] 232 ]
243 233
244 worker_modules_by_name = {} 234 worker_modules_by_name = {}
245 dependents_by_module_name = {} 235 dependents_by_module_name = {}
246 236
247 for module_name in descriptors.application: 237 for module_name in descriptors.application:
248 module = descriptors.modules[module_name] 238 module = descriptors.modules[module_name]
249 if descriptors.application[module_name].get('type', None) == 'worker': 239 if descriptors.application[module_name].get('type', None) == 'worker':
250 worker_modules_by_name[module_name] = module 240 worker_modules_by_name[module_name] = module
251 for dep in module.get('dependencies', []): 241 for dep in module.get('dependencies', []):
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 if referencing_module: 284 if referencing_module:
295 log_error('Duplicate use of %s in "%s" (previously seen in "%s") ' % (source, name, referencing_module)) 285 log_error('Duplicate use of %s in "%s" (previously seen in "%s") ' % (source, name, referencing_module))
296 seen_files[source] = name 286 seen_files[source] = name
297 287
298 for module_name in worker_modules_by_name: 288 for module_name in worker_modules_by_name:
299 check_module(worker_modules_by_name[module_name], {}, {}) 289 check_module(worker_modules_by_name[module_name], {}, {})
300 290
301 print 'Checking duplicate files across modules...' 291 print 'Checking duplicate files across modules...'
302 check_duplicate_files() 292 check_duplicate_files()
303 293
294 print 'Compiling frontend...'
304 295
305 def module_arg(module_name): 296 temp_devtools_path = tempfile.mkdtemp()
306 return ' --module ' + jsmodule_name_prefix + module_name
307 297
308 298
309 def modules_to_check(): 299 def prepare_closure_frontend_compile():
310 if len(sys.argv) == 1: 300 temp_frontend_path = path.join(temp_devtools_path, 'front_end')
311 return descriptors.sorted_modules() 301 checker = dependency_checker.DependencyChecker(descriptors, temp_frontend_pa th)
312 print 'Compiling only these modules: %s' % sys.argv[1:] 302 checker.enforce_dependencies()
313 return [module for module in descriptors.sorted_modules() if module in set(s ys.argv[1:])]
314 303
304 command = common_closure_args + [
305 '--externs', to_platform_path(global_externs_file),
306 '--js', runtime_file,
307 ]
315 308
316 def dump_module(name, recursively, processed_modules): 309 all_files = descriptors.all_compiled_files()
317 if name in processed_modules: 310 args = []
318 return '' 311 for file in all_files:
319 processed_modules[name] = True 312 args.extend(['--js', file])
320 module = modules_by_name[name] 313 if "InspectorBackend.js" in file:
314 # TODO(dgozman): move to separate module
315 args.extend(['--js', protocol_externs_file])
316 command += args
317 command = [arg.replace(devtools_frontend_path, temp_frontend_path) for arg i n command]
318 compiler_args_file = tempfile.NamedTemporaryFile(mode='wt', delete=False)
319 try:
320 compiler_args_file.write(' '.join(command))
321 finally:
322 compiler_args_file.close()
323 return compiler_args_file.name
321 324
322 command = '' 325 compiler_args_file_path = prepare_closure_frontend_compile()
323 dependencies = module.get('dependencies', []) 326 frontend_compile_proc = popen(java_exec + ['-jar', closure_runner_jar, '--compil er-args-file', to_platform_path_exact(compiler_args_file_path)])
324 if recursively:
325 for dependency in dependencies:
326 command += dump_module(dependency, recursively, processed_modules)
327 command += module_arg(name) + ':'
328 filtered_scripts = descriptors.module_compiled_files(name)
329 filtered_scripts = [path.join(devtools_frontend_path, name, script) for scri pt in filtered_scripts]
330 # TODO(dgozman): move to separate module
331 if name == 'sdk':
332 filtered_scripts.append(protocol_externs_file)
333 command += str(len(filtered_scripts))
334 first_dependency = True
335 for dependency in dependencies + [runtime_module_name]:
336 if first_dependency:
337 command += ':'
338 else:
339 command += ','
340 first_dependency = False
341 command += jsmodule_name_prefix + dependency
342 for script in filtered_scripts:
343 command += ' --js ' + to_platform_path(script)
344 return command
345 327
346 print 'Compiling frontend...' 328 print 'Compiling devtools_compatibility.js...'
347 329
348 compiler_args_file = tempfile.NamedTemporaryFile(mode='wt', delete=False) 330 closure_compiler_command = java_exec + [
349 try:
350 runtime_js_path = to_platform_path(path.join(devtools_frontend_path, 'Runtim e.js'))
351 checked_modules = modules_to_check()
352 for name in checked_modules:
353 closure_args = ' '.join(common_closure_args)
354 closure_args += ' --externs ' + to_platform_path(global_externs_file)
355 runtime_module = module_arg(runtime_module_name) + ':1 --js ' + runtime_ js_path
356 closure_args += runtime_module + dump_module(name, True, {})
357 compiler_args_file.write('%s %s%s' % (name, closure_args, os.linesep))
358 finally:
359 compiler_args_file.close()
360
361 modular_compiler_proc = popen(java_exec + ['-jar', closure_runner_jar, '--compil er-args-file', to_platform_path_exact(compiler_args_file.name)])
362
363 spawned_compiler_command = java_exec + [
364 '-jar', 331 '-jar',
365 closure_compiler_jar 332 closure_compiler_jar
366 ] + common_closure_args 333 ] + common_closure_args
367 334
368 print 'Compiling devtools_compatibility.js...' 335 devtools_js_compile_command = closure_compiler_command + [
369
370 command = spawned_compiler_command + [
371 '--externs', to_platform_path(global_externs_file), 336 '--externs', to_platform_path(global_externs_file),
372 '--externs', to_platform_path(path.join(devtools_frontend_path, 'host', 'Ins pectorFrontendHostAPI.js')), 337 '--externs', to_platform_path(path.join(devtools_frontend_path, 'host', 'Ins pectorFrontendHostAPI.js')),
373 '--jscomp_off=externsValidation', 338 '--jscomp_off=externsValidation',
374 '--module', jsmodule_name_prefix + 'devtools__compatibility_js' + ':1',
375 '--js', to_platform_path(path.join(devtools_frontend_path, 'devtools_compati bility.js')) 339 '--js', to_platform_path(path.join(devtools_frontend_path, 'devtools_compati bility.js'))
376 ] 340 ]
377 devtools_js_compile_proc = popen(command) 341 devtools_js_compile_proc = popen(devtools_js_compile_command)
378 342
379 print 'Verifying JSDoc comments...' 343 print 'Verifying JSDoc comments...'
380 errors_found |= verify_jsdoc() 344 errors_found |= verify_jsdoc()
381 (jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra() 345 (jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra()
382 346
383 print 347 print
384 348
385 (jsdoc_validator_out, _) = jsdoc_validator_proc.communicate() 349 (jsdoc_validator_out, _) = jsdoc_validator_proc.communicate()
386 if jsdoc_validator_out: 350 if jsdoc_validator_out:
387 print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out)) 351 print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out))
388 errors_found = True 352 errors_found = True
389 353
390 os.remove(jsdoc_validator_file_list.name) 354 os.remove(jsdoc_validator_file_list.name)
391 355
392 (module_compile_out, _) = modular_compiler_proc.communicate()
393 print 'Modular compilation output:'
394
395 start_module_regex = re.compile(r'^@@ START_MODULE:(.+) @@$')
396 end_module_regex = re.compile(r'^@@ END_MODULE @@$')
397
398 in_module = False
399 skipped_modules = {}
400 error_count = 0
401
402 def skip_dependents(module_name):
403 for skipped_module in dependents_by_module_name.get(module_name, []):
404 skipped_modules[skipped_module] = True
405
406 has_module_output = False
407
408 # pylint: disable=E1103
409 for line in module_compile_out.splitlines():
410 if not in_module:
411 match = re.search(start_module_regex, line)
412 if not match:
413 continue
414 in_module = True
415 has_module_output = True
416 module_error_count = 0
417 module_output = []
418 module_name = match.group(1)
419 skip_module = skipped_modules.get(module_name)
420 if skip_module:
421 skip_dependents(module_name)
422 else:
423 match = re.search(end_module_regex, line)
424 if not match:
425 if not skip_module:
426 module_output.append(line)
427 if has_errors(line):
428 error_count += 1
429 module_error_count += 1
430 skip_dependents(module_name)
431 continue
432
433 in_module = False
434 if skip_module:
435 print 'Skipping module %s...' % module_name
436 elif not module_error_count:
437 print 'Module %s compiled successfully: %s' % (module_name, module_o utput[0])
438 else:
439 print 'Module %s compile failed: %s errors%s' % (module_name, module _error_count, os.linesep)
440 print os.linesep.join(module_output)
441
442 if not has_module_output:
443 print module_compile_out
444
445 if error_count:
446 print 'Total Closure errors: %d%s' % (error_count, os.linesep)
447 errors_found = True
448
449 (devtools_js_compile_out, _) = devtools_js_compile_proc.communicate() 356 (devtools_js_compile_out, _) = devtools_js_compile_proc.communicate()
450 print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_j s_compile_out 357 print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_j s_compile_out
451 errors_found |= has_errors(devtools_js_compile_out) 358 errors_found |= has_errors(devtools_js_compile_out)
452 359
453 os.remove(compiler_args_file.name) 360 (frontend_compile_out, _) = frontend_compile_proc.communicate()
361 print 'devtools frontend compilation output:'
362 for line in frontend_compile_out.splitlines():
363 if "@@ START_MODULE" in line or "@@ END_MODULE" in line:
364 continue
365 print line
366 errors_found |= has_errors(frontend_compile_out)
367
454 os.remove(protocol_externs_file) 368 os.remove(protocol_externs_file)
455 shutil.rmtree(modules_dir, True) 369 os.remove(compiler_args_file_path)
370 shutil.rmtree(temp_devtools_path, True)
456 371
457 if errors_found: 372 if errors_found:
458 print 'ERRORS DETECTED' 373 print 'ERRORS DETECTED'
459 sys.exit(1) 374 sys.exit(1)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698