| OLD | NEW |
| 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 Loading... |
| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 | 208 |
| 217 if not is_ok: | 209 if not is_ok: |
| 218 print 'NOTE: Java executable version %d.%d or above not found in $PATH.'
% (required_major, required_minor) | 210 print 'NOTE: Java executable version %d.%d or above not found in $PATH.'
% (required_major, required_minor) |
| 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')) | |
| 227 jsdoc_validator_jar = to_platform_path(path.join(scripts_path, 'jsdoc_validator'
, 'jsdoc_validator.jar')) | 218 jsdoc_validator_jar = to_platform_path(path.join(scripts_path, 'jsdoc_validator'
, 'jsdoc_validator.jar')) |
| 228 | 219 |
| 229 modules_dir = tempfile.mkdtemp() | |
| 230 common_closure_args = [ | 220 common_closure_args = [ |
| 231 '--summary_detail_level', '3', | 221 '--summary_detail_level', '3', |
| 232 '--jscomp_error', 'visibility', | 222 '--jscomp_error', 'visibility', |
| 233 '--jscomp_warning', 'missingOverride', | 223 '--jscomp_warning', 'missingOverride', |
| 234 '--compilation_level', 'SIMPLE_OPTIMIZATIONS', | 224 '--compilation_level', 'SIMPLE_OPTIMIZATIONS', |
| 235 '--warning_level', 'VERBOSE', | 225 '--warning_level', 'VERBOSE', |
| 236 '--language_in=ES6_STRICT', | 226 '--language_in=ES6_STRICT', |
| 237 '--language_out=ES5_STRICT', | 227 '--language_out=ES5_STRICT', |
| 238 '--extra_annotation_name', 'suppressReceiverCheck', | 228 '--extra_annotation_name', 'suppressReceiverCheck', |
| 239 '--extra_annotation_name', 'suppressGlobalPropertiesCheck', | 229 '--extra_annotation_name', 'suppressGlobalPropertiesCheck', |
| 240 '--checks-only', | 230 '--checks-only', |
| 241 '--module_output_path_prefix', to_platform_path_exact(modules_dir + path.sep
) | |
| 242 ] | 231 ] |
| 243 | 232 |
| 244 worker_modules_by_name = {} | 233 worker_modules_by_name = {} |
| 245 dependents_by_module_name = {} | 234 dependents_by_module_name = {} |
| 246 | 235 |
| 247 for module_name in descriptors.application: | 236 for module_name in descriptors.application: |
| 248 module = descriptors.modules[module_name] | 237 module = descriptors.modules[module_name] |
| 249 if descriptors.application[module_name].get('type', None) == 'worker': | 238 if descriptors.application[module_name].get('type', None) == 'worker': |
| 250 worker_modules_by_name[module_name] = module | 239 worker_modules_by_name[module_name] = module |
| 251 for dep in module.get('dependencies', []): | 240 for dep in module.get('dependencies', []): |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 if referencing_module: | 283 if referencing_module: |
| 295 log_error('Duplicate use of %s in "%s" (previously seen in "%s")
' % (source, name, referencing_module)) | 284 log_error('Duplicate use of %s in "%s" (previously seen in "%s")
' % (source, name, referencing_module)) |
| 296 seen_files[source] = name | 285 seen_files[source] = name |
| 297 | 286 |
| 298 for module_name in worker_modules_by_name: | 287 for module_name in worker_modules_by_name: |
| 299 check_module(worker_modules_by_name[module_name], {}, {}) | 288 check_module(worker_modules_by_name[module_name], {}, {}) |
| 300 | 289 |
| 301 print 'Checking duplicate files across modules...' | 290 print 'Checking duplicate files across modules...' |
| 302 check_duplicate_files() | 291 check_duplicate_files() |
| 303 | 292 |
| 304 | |
| 305 def module_arg(module_name): | |
| 306 return ' --module ' + jsmodule_name_prefix + module_name | |
| 307 | |
| 308 | |
| 309 def modules_to_check(): | |
| 310 if len(sys.argv) == 1: | |
| 311 return descriptors.sorted_modules() | |
| 312 print 'Compiling only these modules: %s' % sys.argv[1:] | |
| 313 return [module for module in descriptors.sorted_modules() if module in set(s
ys.argv[1:])] | |
| 314 | |
| 315 | |
| 316 def dump_module(name, recursively, processed_modules): | |
| 317 if name in processed_modules: | |
| 318 return '' | |
| 319 processed_modules[name] = True | |
| 320 module = modules_by_name[name] | |
| 321 | |
| 322 command = '' | |
| 323 dependencies = module.get('dependencies', []) | |
| 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 | |
| 346 print 'Compiling frontend...' | 293 print 'Compiling frontend...' |
| 347 | 294 |
| 348 compiler_args_file = tempfile.NamedTemporaryFile(mode='wt', delete=False) | 295 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', | 296 '-jar', |
| 365 closure_compiler_jar | 297 closure_compiler_jar |
| 366 ] + common_closure_args | 298 ] + common_closure_args |
| 367 | 299 |
| 300 temp_devtools_path = tempfile.mkdtemp() |
| 301 temp_frontend_path = path.join(temp_devtools_path, 'front_end') |
| 302 |
| 303 |
| 304 def prepare_closure_frontend_compile(): |
| 305 checker = dependency_checker.DependencyChecker(descriptors, temp_frontend_pa
th) |
| 306 checker.enforce_dependencies() |
| 307 |
| 308 command = closure_compiler_command + [ |
| 309 '--externs', to_platform_path(global_externs_file), |
| 310 '--js', runtime_file, |
| 311 ] |
| 312 |
| 313 all_files = descriptors.all_compiled_files() |
| 314 args = [] |
| 315 for file in all_files: |
| 316 args.extend(['--js', file]) |
| 317 if "InspectorBackend.js" in file: |
| 318 # TODO(dgozman): move to separate module |
| 319 args.extend(['--js', protocol_externs_file]) |
| 320 command += args |
| 321 command = [arg.replace(devtools_frontend_path, temp_frontend_path) for arg i
n command] |
| 322 return command |
| 323 |
| 324 frontend_compile_proc = popen(prepare_closure_frontend_compile()) |
| 325 |
| 368 print 'Compiling devtools_compatibility.js...' | 326 print 'Compiling devtools_compatibility.js...' |
| 369 | 327 |
| 370 command = spawned_compiler_command + [ | 328 devtools_js_compile_command = closure_compiler_command + [ |
| 371 '--externs', to_platform_path(global_externs_file), | 329 '--externs', to_platform_path(global_externs_file), |
| 372 '--externs', to_platform_path(path.join(devtools_frontend_path, 'host', 'Ins
pectorFrontendHostAPI.js')), | 330 '--externs', to_platform_path(path.join(devtools_frontend_path, 'host', 'Ins
pectorFrontendHostAPI.js')), |
| 373 '--jscomp_off=externsValidation', | 331 '--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')) | 332 '--js', to_platform_path(path.join(devtools_frontend_path, 'devtools_compati
bility.js')) |
| 376 ] | 333 ] |
| 377 devtools_js_compile_proc = popen(command) | 334 devtools_js_compile_proc = popen(devtools_js_compile_command) |
| 378 | 335 |
| 379 print 'Verifying JSDoc comments...' | 336 print 'Verifying JSDoc comments...' |
| 380 errors_found |= verify_jsdoc() | 337 errors_found |= verify_jsdoc() |
| 381 (jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra() | 338 (jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra() |
| 382 | 339 |
| 383 print | 340 print |
| 384 | 341 |
| 385 (jsdoc_validator_out, _) = jsdoc_validator_proc.communicate() | 342 (jsdoc_validator_out, _) = jsdoc_validator_proc.communicate() |
| 386 if jsdoc_validator_out: | 343 if jsdoc_validator_out: |
| 387 print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out)) | 344 print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out)) |
| 388 errors_found = True | 345 errors_found = True |
| 389 | 346 |
| 390 os.remove(jsdoc_validator_file_list.name) | 347 os.remove(jsdoc_validator_file_list.name) |
| 391 | 348 |
| 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() | 349 (devtools_js_compile_out, _) = devtools_js_compile_proc.communicate() |
| 450 print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_j
s_compile_out | 350 print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_j
s_compile_out |
| 451 errors_found |= has_errors(devtools_js_compile_out) | 351 errors_found |= has_errors(devtools_js_compile_out) |
| 452 | 352 |
| 453 os.remove(compiler_args_file.name) | 353 (frontend_compile_out, _) = frontend_compile_proc.communicate() |
| 354 print 'devtools frontend compilation output:%s' % os.linesep, frontend_compile_o
ut |
| 355 errors_found |= has_errors(devtools_js_compile_out) |
| 356 |
| 454 os.remove(protocol_externs_file) | 357 os.remove(protocol_externs_file) |
| 455 shutil.rmtree(modules_dir, True) | 358 shutil.rmtree(temp_devtools_path, True) |
| 456 | 359 |
| 457 if errors_found: | 360 if errors_found: |
| 458 print 'ERRORS DETECTED' | 361 print 'ERRORS DETECTED' |
| 459 sys.exit(1) | 362 sys.exit(1) |
| OLD | NEW |