| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.cmdline; | 5 library dart2js.cmdline; |
| 6 | 6 |
| 7 import 'dart:async' | 7 import 'dart:async' |
| 8 show Future, EventSink; | 8 show Future, EventSink; |
| 9 import 'dart:io' | 9 import 'dart:io' |
| 10 show exit, File, FileMode, Platform, RandomAccessFile, FileSystemException, | 10 show exit, File, FileMode, Platform, RandomAccessFile, FileSystemException, |
| 11 stdin, stderr; | 11 stdin, stderr; |
| 12 import 'dart:math' as math; | |
| 13 | 12 |
| 14 import '../compiler.dart' as api; | 13 import '../compiler.dart' as api; |
| 15 import 'source_file.dart'; | 14 import 'source_file.dart'; |
| 16 import 'source_file_provider.dart'; | 15 import 'source_file_provider.dart'; |
| 17 import 'filenames.dart'; | 16 import 'filenames.dart'; |
| 18 import 'util/uri_extras.dart'; | 17 import 'util/uri_extras.dart'; |
| 19 import 'util/util.dart' show stackTraceFilePrefix; | 18 import 'util/util.dart' show stackTraceFilePrefix; |
| 20 import 'util/command_line.dart'; | 19 import 'util/command_line.dart'; |
| 21 import '../../libraries.dart'; | 20 import '../../libraries.dart'; |
| 22 | 21 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 continue OUTER; | 93 continue OUTER; |
| 95 } | 94 } |
| 96 } | 95 } |
| 97 throw 'Internal error: "$argument" did not match'; | 96 throw 'Internal error: "$argument" did not match'; |
| 98 } | 97 } |
| 99 } | 98 } |
| 100 | 99 |
| 101 FormattingDiagnosticHandler diagnosticHandler; | 100 FormattingDiagnosticHandler diagnosticHandler; |
| 102 | 101 |
| 103 Future compile(List<String> argv) { | 102 Future compile(List<String> argv) { |
| 104 bool isWindows = (Platform.operatingSystem == 'windows'); | |
| 105 stackTraceFilePrefix = '$currentDirectory'; | 103 stackTraceFilePrefix = '$currentDirectory'; |
| 106 Uri libraryRoot = currentDirectory; | 104 Uri libraryRoot = currentDirectory; |
| 107 Uri out = currentDirectory.resolve('out.js'); | 105 Uri out = currentDirectory.resolve('out.js'); |
| 108 Uri sourceMapOut = currentDirectory.resolve('out.js.map'); | 106 Uri sourceMapOut = currentDirectory.resolve('out.js.map'); |
| 109 Uri packageRoot = null; | 107 Uri packageRoot = null; |
| 110 List<String> options = new List<String>(); | 108 List<String> options = new List<String>(); |
| 111 bool explicitOut = false; | 109 bool explicitOut = false; |
| 112 bool wantHelp = false; | 110 bool wantHelp = false; |
| 113 bool wantVersion = false; | 111 bool wantVersion = false; |
| 114 String outputLanguage = 'JavaScript'; | 112 String outputLanguage = 'JavaScript'; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 break; | 250 break; |
| 253 case 'm': | 251 case 'm': |
| 254 implyCompilation('--minify'); | 252 implyCompilation('--minify'); |
| 255 break; | 253 break; |
| 256 default: | 254 default: |
| 257 throw 'Internal error: "$shortOption" did not match'; | 255 throw 'Internal error: "$shortOption" did not match'; |
| 258 } | 256 } |
| 259 } | 257 } |
| 260 } | 258 } |
| 261 | 259 |
| 262 Uri computePrecompiledUri() { | |
| 263 String extension = 'precompiled.js'; | |
| 264 String outPath = out.path; | |
| 265 if (outPath.endsWith('.js')) { | |
| 266 outPath = outPath.substring(0, outPath.length - 3); | |
| 267 return out.resolve('$outPath.$extension'); | |
| 268 } else { | |
| 269 return out.resolve(extension); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 List<String> arguments = <String>[]; | 260 List<String> arguments = <String>[]; |
| 274 List<OptionHandler> handlers = <OptionHandler>[ | 261 List<OptionHandler> handlers = <OptionHandler>[ |
| 275 new OptionHandler('-[chvm?]+', handleShortOptions), | 262 new OptionHandler('-[chvm?]+', handleShortOptions), |
| 276 new OptionHandler('--throw-on-error(?:=[0-9]+)?', handleThrowOnError), | 263 new OptionHandler('--throw-on-error(?:=[0-9]+)?', handleThrowOnError), |
| 277 new OptionHandler('--suppress-warnings', (_) { | 264 new OptionHandler('--suppress-warnings', (_) { |
| 278 diagnosticHandler.showWarnings = false; | 265 diagnosticHandler.showWarnings = false; |
| 279 passThrough('--suppress-warnings'); | 266 passThrough('--suppress-warnings'); |
| 280 }), | 267 }), |
| 281 new OptionHandler('--suppress-hints', | 268 new OptionHandler('--suppress-hints', |
| 282 (_) => diagnosticHandler.showHints = false), | 269 (_) => diagnosticHandler.showHints = false), |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 }) | 313 }) |
| 327 ]; | 314 ]; |
| 328 | 315 |
| 329 parseCommandLine(handlers, argv); | 316 parseCommandLine(handlers, argv); |
| 330 if (wantHelp || wantVersion) { | 317 if (wantHelp || wantVersion) { |
| 331 helpAndExit(wantHelp, wantVersion, diagnosticHandler.verbose); | 318 helpAndExit(wantHelp, wantVersion, diagnosticHandler.verbose); |
| 332 } | 319 } |
| 333 | 320 |
| 334 if (hasDisallowUnsafeEval) { | 321 if (hasDisallowUnsafeEval) { |
| 335 String precompiledName = | 322 String precompiledName = |
| 336 relativize(currentDirectory, computePrecompiledUri(), isWindows); | 323 relativize(currentDirectory, |
| 324 RandomAccessFileOutputProvider.computePrecompiledUri(out), |
| 325 Platform.isWindows); |
| 337 helpAndFail("Option '--disallow-unsafe-eval' has been removed." | 326 helpAndFail("Option '--disallow-unsafe-eval' has been removed." |
| 338 " Instead, the compiler generates a file named" | 327 " Instead, the compiler generates a file named" |
| 339 " '$precompiledName'."); | 328 " '$precompiledName'."); |
| 340 } | 329 } |
| 341 | 330 |
| 342 if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) { | 331 if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) { |
| 343 helpAndFail("Option '--force-strip' may only be used with " | 332 helpAndFail("Option '--force-strip' may only be used with " |
| 344 "'--output-type=dart'."); | 333 "'--output-type=dart'."); |
| 345 } | 334 } |
| 346 if (arguments.isEmpty) { | 335 if (arguments.isEmpty) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 364 } | 353 } |
| 365 diagnosticHandler.info( | 354 diagnosticHandler.info( |
| 366 "Options $optionsImplyCompilation indicate that output is expected, " | 355 "Options $optionsImplyCompilation indicate that output is expected, " |
| 367 "but compilation is turned off by the option '--analyze-only'.", | 356 "but compilation is turned off by the option '--analyze-only'.", |
| 368 api.Diagnostic.INFO); | 357 api.Diagnostic.INFO); |
| 369 } | 358 } |
| 370 if (analyzeAll) analyzeOnly = true; | 359 if (analyzeAll) analyzeOnly = true; |
| 371 | 360 |
| 372 diagnosticHandler.info('Package root is $packageRoot'); | 361 diagnosticHandler.info('Package root is $packageRoot'); |
| 373 | 362 |
| 374 int totalCharactersWritten = 0; | |
| 375 | |
| 376 options.add('--out=$out'); | 363 options.add('--out=$out'); |
| 377 options.add('--source-map=$sourceMapOut'); | 364 options.add('--source-map=$sourceMapOut'); |
| 378 | 365 |
| 379 List<String> allOutputFiles = new List<String>(); | 366 RandomAccessFileOutputProvider outputProvider = |
| 367 new RandomAccessFileOutputProvider( |
| 368 out, sourceMapOut, onInfo: diagnosticHandler.info, onFailure: fail); |
| 380 | 369 |
| 381 compilationDone(String code) { | 370 compilationDone(String code) { |
| 382 if (analyzeOnly) return; | 371 if (analyzeOnly) return; |
| 383 if (code == null) { | 372 if (code == null) { |
| 384 fail('Compilation failed.'); | 373 fail('Compilation failed.'); |
| 385 } | 374 } |
| 386 writeString(Uri.parse('$out.deps'), | 375 writeString(Uri.parse('$out.deps'), |
| 387 getDepsOutput(inputProvider.sourceFiles)); | 376 getDepsOutput(inputProvider.sourceFiles)); |
| 388 diagnosticHandler.info( | 377 diagnosticHandler.info( |
| 389 'Compiled ${inputProvider.dartCharactersRead} characters Dart ' | 378 'Compiled ${inputProvider.dartCharactersRead} characters Dart ' |
| 390 '-> $totalCharactersWritten characters $outputLanguage ' | 379 '-> ${outputProvider.totalCharactersWritten} characters ' |
| 391 'in ${relativize(currentDirectory, out, isWindows)}'); | 380 '$outputLanguage in ' |
| 381 '${relativize(currentDirectory, out, Platform.isWindows)}'); |
| 392 if (diagnosticHandler.verbose) { | 382 if (diagnosticHandler.verbose) { |
| 393 String input = uriPathToNative(arguments[0]); | 383 String input = uriPathToNative(arguments[0]); |
| 394 print('Dart file ($input) compiled to $outputLanguage.'); | 384 print('Dart file ($input) compiled to $outputLanguage.'); |
| 395 print('Wrote the following files:'); | 385 print('Wrote the following files:'); |
| 396 for (String filename in allOutputFiles) { | 386 for (String filename in outputProvider.allOutputFiles) { |
| 397 print(" $filename"); | 387 print(" $filename"); |
| 398 } | 388 } |
| 399 } else if (!explicitOut) { | 389 } else if (!explicitOut) { |
| 400 String input = uriPathToNative(arguments[0]); | 390 String input = uriPathToNative(arguments[0]); |
| 401 String output = relativize(currentDirectory, out, isWindows); | 391 String output = relativize(currentDirectory, out, Platform.isWindows); |
| 402 print('Dart file ($input) compiled to $outputLanguage: $output'); | 392 print('Dart file ($input) compiled to $outputLanguage: $output'); |
| 403 } | 393 } |
| 404 } | 394 } |
| 405 | 395 |
| 406 EventSink<String> outputProvider(String name, String extension) { | |
| 407 Uri uri; | |
| 408 String sourceMapFileName; | |
| 409 bool isPrimaryOutput = false; | |
| 410 if (name == '') { | |
| 411 if (extension == 'js' || extension == 'dart') { | |
| 412 isPrimaryOutput = true; | |
| 413 uri = out; | |
| 414 sourceMapFileName = | |
| 415 sourceMapOut.path.substring(sourceMapOut.path.lastIndexOf('/') + 1); | |
| 416 } else if (extension == 'precompiled.js') { | |
| 417 uri = computePrecompiledUri(); | |
| 418 diagnosticHandler.info( | |
| 419 "File ($uri) is compatible with header" | |
| 420 " \"Content-Security-Policy: script-src 'self'\""); | |
| 421 } else if (extension == 'js.map' || extension == 'dart.map') { | |
| 422 uri = sourceMapOut; | |
| 423 } else if (extension == 'info.html' || extension == "info.json") { | |
| 424 String outName = out.path.substring(out.path.lastIndexOf('/') + 1); | |
| 425 uri = out.resolve('$outName.$extension'); | |
| 426 } else { | |
| 427 fail('Unknown extension: $extension'); | |
| 428 } | |
| 429 } else { | |
| 430 uri = out.resolve('$name.$extension'); | |
| 431 } | |
| 432 | |
| 433 if (uri.scheme != 'file') { | |
| 434 fail('Unhandled scheme ${uri.scheme} in $uri.'); | |
| 435 } | |
| 436 | |
| 437 RandomAccessFile output; | |
| 438 try { | |
| 439 output = new File(uri.toFilePath()).openSync(mode: FileMode.WRITE); | |
| 440 } on FileSystemException catch(e) { | |
| 441 fail('$e'); | |
| 442 } | |
| 443 | |
| 444 allOutputFiles.add(relativize(currentDirectory, uri, isWindows)); | |
| 445 | |
| 446 int charactersWritten = 0; | |
| 447 | |
| 448 writeStringSync(String data) { | |
| 449 // Write the data in chunks of 8kb, otherwise we risk running OOM. | |
| 450 int chunkSize = 8*1024; | |
| 451 | |
| 452 int offset = 0; | |
| 453 while (offset < data.length) { | |
| 454 output.writeStringSync( | |
| 455 data.substring(offset, math.min(offset + chunkSize, data.length))); | |
| 456 offset += chunkSize; | |
| 457 } | |
| 458 charactersWritten += data.length; | |
| 459 } | |
| 460 | |
| 461 onDone() { | |
| 462 output.closeSync(); | |
| 463 if (isPrimaryOutput) { | |
| 464 totalCharactersWritten += charactersWritten; | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 return new EventSinkWrapper(writeStringSync, onDone); | |
| 469 } | |
| 470 | |
| 471 return compileFunc(uri, libraryRoot, packageRoot, | 396 return compileFunc(uri, libraryRoot, packageRoot, |
| 472 inputProvider, diagnosticHandler, | 397 inputProvider, diagnosticHandler, |
| 473 options, outputProvider, environment) | 398 options, outputProvider, environment) |
| 474 .then(compilationDone); | 399 .then(compilationDone); |
| 475 } | 400 } |
| 476 | 401 |
| 477 class EventSinkWrapper extends EventSink<String> { | |
| 478 var onAdd, onClose; | |
| 479 | |
| 480 EventSinkWrapper(this.onAdd, this.onClose); | |
| 481 | |
| 482 void add(String data) => onAdd(data); | |
| 483 | |
| 484 void addError(error, [StackTrace stackTrace]) => throw error; | |
| 485 | |
| 486 void close() => onClose(); | |
| 487 } | |
| 488 | |
| 489 class AbortLeg { | 402 class AbortLeg { |
| 490 final message; | 403 final message; |
| 491 AbortLeg(this.message); | 404 AbortLeg(this.message); |
| 492 toString() => 'Aborted due to --throw-on-error: $message'; | 405 toString() => 'Aborted due to --throw-on-error: $message'; |
| 493 } | 406 } |
| 494 | 407 |
| 495 void writeString(Uri uri, String text) { | 408 void writeString(Uri uri, String text) { |
| 496 if (uri.scheme != 'file') { | 409 if (uri.scheme != 'file') { |
| 497 fail('Unhandled scheme ${uri.scheme}.'); | 410 fail('Unhandled scheme ${uri.scheme}.'); |
| 498 } | 411 } |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 } else { | 647 } else { |
| 735 print(">>> TEST FAIL"); | 648 print(">>> TEST FAIL"); |
| 736 } | 649 } |
| 737 stderr.writeln(">>> EOF STDERR"); | 650 stderr.writeln(">>> EOF STDERR"); |
| 738 runJob(); | 651 runJob(); |
| 739 }); | 652 }); |
| 740 } | 653 } |
| 741 | 654 |
| 742 runJob(); | 655 runJob(); |
| 743 } | 656 } |
| OLD | NEW |