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_preprocessor | |
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 Loading... | |
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': |
dgozman
2017/01/10 21:47:35
FYI: this is never true anymore, so we should foll
chenwilliam
2017/01/10 23:08:56
made a todo.
| |
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', []): |
252 list = dependents_by_module_name.get(dep) | 242 list = dependents_by_module_name.get(dep) |
253 if not list: | 243 if not list: |
254 list = [] | 244 list = [] |
255 dependents_by_module_name[dep] = list | 245 dependents_by_module_name[dep] = list |
256 list.append(module_name) | 246 list.append(module_name) |
257 | 247 |
258 | 248 |
259 def check_conditional_dependencies(): | 249 def check_conditional_dependencies(): |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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_preprocessor.DependencyPreprocessor(descriptors, temp_f rontend_path, devtools_frontend_path) |
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 args.extend(['--js', protocol_externs_file]) | |
315 command += args | |
316 command = [arg.replace(devtools_frontend_path, temp_frontend_path) for arg i n command] | |
dgozman
2017/01/10 21:47:34
Please double this is necessary.
chenwilliam
2017/01/10 23:08:56
just double checked it's a full path.
| |
317 compiler_args_file = tempfile.NamedTemporaryFile(mode='wt', delete=False) | |
318 try: | |
319 compiler_args_file.write('devtools_frontend %s' % (' '.join(command))) | |
320 finally: | |
321 compiler_args_file.close() | |
322 return compiler_args_file.name | |
321 | 323 |
322 command = '' | 324 compiler_args_file_path = prepare_closure_frontend_compile() |
323 dependencies = module.get('dependencies', []) | 325 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 if name == 'protocol': | |
331 filtered_scripts.append(protocol_externs_file) | |
332 command += str(len(filtered_scripts)) | |
333 first_dependency = True | |
334 for dependency in dependencies + [runtime_module_name]: | |
335 if first_dependency: | |
336 command += ':' | |
337 else: | |
338 command += ',' | |
339 first_dependency = False | |
340 command += jsmodule_name_prefix + dependency | |
341 for script in filtered_scripts: | |
342 command += ' --js ' + to_platform_path(script) | |
343 return command | |
344 | 326 |
345 print 'Compiling frontend...' | 327 print 'Compiling devtools_compatibility.js...' |
346 | 328 |
347 compiler_args_file = tempfile.NamedTemporaryFile(mode='wt', delete=False) | 329 closure_compiler_command = java_exec + [ |
348 try: | |
349 runtime_js_path = to_platform_path(path.join(devtools_frontend_path, 'Runtim e.js')) | |
350 checked_modules = modules_to_check() | |
351 for name in checked_modules: | |
352 closure_args = ' '.join(common_closure_args) | |
353 closure_args += ' --externs ' + to_platform_path(global_externs_file) | |
354 runtime_module = module_arg(runtime_module_name) + ':1 --js ' + runtime_ js_path | |
355 closure_args += runtime_module + dump_module(name, True, {}) | |
356 compiler_args_file.write('%s %s%s' % (name, closure_args, os.linesep)) | |
357 finally: | |
358 compiler_args_file.close() | |
359 | |
360 modular_compiler_proc = popen(java_exec + ['-jar', closure_runner_jar, '--compil er-args-file', to_platform_path_exact(compiler_args_file.name)]) | |
361 | |
362 spawned_compiler_command = java_exec + [ | |
363 '-jar', | 330 '-jar', |
364 closure_compiler_jar | 331 closure_compiler_jar |
365 ] + common_closure_args | 332 ] + common_closure_args |
366 | 333 |
367 print 'Compiling devtools_compatibility.js...' | 334 devtools_js_compile_command = closure_compiler_command + [ |
368 | |
369 command = spawned_compiler_command + [ | |
370 '--externs', to_platform_path(global_externs_file), | 335 '--externs', to_platform_path(global_externs_file), |
371 '--externs', to_platform_path(path.join(devtools_frontend_path, 'host', 'Ins pectorFrontendHostAPI.js')), | 336 '--externs', to_platform_path(path.join(devtools_frontend_path, 'host', 'Ins pectorFrontendHostAPI.js')), |
372 '--jscomp_off=externsValidation', | 337 '--jscomp_off=externsValidation', |
373 '--module', jsmodule_name_prefix + 'devtools__compatibility_js' + ':1', | |
374 '--js', to_platform_path(path.join(devtools_frontend_path, 'devtools_compati bility.js')) | 338 '--js', to_platform_path(path.join(devtools_frontend_path, 'devtools_compati bility.js')) |
375 ] | 339 ] |
376 devtools_js_compile_proc = popen(command) | 340 devtools_js_compile_proc = popen(devtools_js_compile_command) |
377 | 341 |
378 print 'Verifying JSDoc comments...' | 342 print 'Verifying JSDoc comments...' |
379 errors_found |= verify_jsdoc() | 343 errors_found |= verify_jsdoc() |
380 (jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra() | 344 (jsdoc_validator_proc, jsdoc_validator_file_list) = verify_jsdoc_extra() |
381 | 345 |
382 print | 346 print |
383 | 347 |
384 (jsdoc_validator_out, _) = jsdoc_validator_proc.communicate() | 348 (jsdoc_validator_out, _) = jsdoc_validator_proc.communicate() |
385 if jsdoc_validator_out: | 349 if jsdoc_validator_out: |
386 print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out)) | 350 print ('JSDoc validator output:%s%s' % (os.linesep, jsdoc_validator_out)) |
387 errors_found = True | 351 errors_found = True |
388 | 352 |
389 os.remove(jsdoc_validator_file_list.name) | 353 os.remove(jsdoc_validator_file_list.name) |
390 | 354 |
391 (module_compile_out, _) = modular_compiler_proc.communicate() | |
392 print 'Modular compilation output:' | |
393 | |
394 start_module_regex = re.compile(r'^@@ START_MODULE:(.+) @@$') | |
395 end_module_regex = re.compile(r'^@@ END_MODULE @@$') | |
396 | |
397 in_module = False | |
398 skipped_modules = {} | |
399 error_count = 0 | |
400 | |
401 def skip_dependents(module_name): | |
402 for skipped_module in dependents_by_module_name.get(module_name, []): | |
403 skipped_modules[skipped_module] = True | |
404 | |
405 has_module_output = False | |
406 | |
407 # pylint: disable=E1103 | |
408 for line in module_compile_out.splitlines(): | |
409 if not in_module: | |
410 match = re.search(start_module_regex, line) | |
411 if not match: | |
412 continue | |
413 in_module = True | |
414 has_module_output = True | |
415 module_error_count = 0 | |
416 module_output = [] | |
417 module_name = match.group(1) | |
418 skip_module = skipped_modules.get(module_name) | |
419 if skip_module: | |
420 skip_dependents(module_name) | |
421 else: | |
422 match = re.search(end_module_regex, line) | |
423 if not match: | |
424 if not skip_module: | |
425 module_output.append(line) | |
426 if has_errors(line): | |
427 error_count += 1 | |
428 module_error_count += 1 | |
429 skip_dependents(module_name) | |
430 continue | |
431 | |
432 in_module = False | |
433 if skip_module: | |
434 print 'Skipping module %s...' % module_name | |
435 elif not module_error_count: | |
436 print 'Module %s compiled successfully: %s' % (module_name, module_o utput[0]) | |
437 else: | |
438 print 'Module %s compile failed: %s errors%s' % (module_name, module _error_count, os.linesep) | |
439 print os.linesep.join(module_output) | |
440 | |
441 if not has_module_output: | |
442 print module_compile_out | |
443 | |
444 if error_count: | |
445 print 'Total Closure errors: %d%s' % (error_count, os.linesep) | |
446 errors_found = True | |
447 | |
448 (devtools_js_compile_out, _) = devtools_js_compile_proc.communicate() | 355 (devtools_js_compile_out, _) = devtools_js_compile_proc.communicate() |
449 print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_j s_compile_out | 356 print 'devtools_compatibility.js compilation output:%s' % os.linesep, devtools_j s_compile_out |
450 errors_found |= has_errors(devtools_js_compile_out) | 357 errors_found |= has_errors(devtools_js_compile_out) |
451 | 358 |
452 os.remove(compiler_args_file.name) | 359 (frontend_compile_out, _) = frontend_compile_proc.communicate() |
360 print 'devtools frontend compilation output:' | |
361 for line in frontend_compile_out.splitlines(): | |
362 if "@@ START_MODULE" in line or "@@ END_MODULE" in line: | |
363 continue | |
364 print line | |
365 errors_found |= has_errors(frontend_compile_out) | |
366 | |
453 os.remove(protocol_externs_file) | 367 os.remove(protocol_externs_file) |
454 shutil.rmtree(modules_dir, True) | 368 os.remove(compiler_args_file_path) |
369 shutil.rmtree(temp_devtools_path, True) | |
455 | 370 |
456 if errors_found: | 371 if errors_found: |
457 print 'ERRORS DETECTED' | 372 print 'ERRORS DETECTED' |
458 sys.exit(1) | 373 sys.exit(1) |
374 print 'DONE - compiled without errors' | |
OLD | NEW |