Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'dart:convert' show JSON; | 5 import 'dart:convert' show JSON; |
| 6 import 'dart:io'; | 6 import 'dart:io'; |
| 7 import 'package:args/command_runner.dart'; | |
| 8 import 'package:analyzer/src/generated/source.dart' show Source; | 7 import 'package:analyzer/src/generated/source.dart' show Source; |
| 9 import 'package:analyzer/src/summary/package_bundle_reader.dart' | 8 import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| 10 show InSummarySource; | 9 show InSummarySource; |
| 10 import 'package:args/args.dart' show ArgParser, ArgResults; | |
| 11 import 'package:args/command_runner.dart' show UsageException; | |
| 12 import 'package:path/path.dart' as path; | |
| 13 | |
| 11 import 'compiler.dart' | 14 import 'compiler.dart' |
| 12 show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler; | 15 show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler; |
| 13 import '../analyzer/context.dart' show AnalyzerOptions; | 16 import '../analyzer/context.dart' show AnalyzerOptions; |
| 14 import 'package:path/path.dart' as path; | |
| 15 | 17 |
| 16 typedef void MessageHandler(Object message); | 18 typedef void MessageHandler(Object message); |
| 17 | 19 |
| 18 /// The command for invoking the modular compiler. | 20 /// The command for invoking the modular compiler. |
| 19 class CompileCommand extends Command { | 21 class CompileCommand { |
| 20 final MessageHandler messageHandler; | 22 final MessageHandler _print; |
| 21 CompilerOptions _compilerOptions; | 23 CompilerOptions _compilerOptions; |
| 24 final ArgParser _argParser = new ArgParser(); | |
|
nweiz
2016/08/12 20:30:57
Nit: this doesn't need to be type-annotated.
Jennifer Messerly
2016/08/12 21:08:01
true. Although it unfortunately needs the type ann
| |
| 22 | 25 |
| 23 CompileCommand({MessageHandler messageHandler}) | 26 CompileCommand({MessageHandler messageHandler}) |
| 24 : this.messageHandler = messageHandler ?? print { | 27 : _print = messageHandler ?? print { |
| 25 argParser.addOption('out', abbr: 'o', help: 'Output file (required)'); | 28 _argParser.addOption('out', abbr: 'o', help: 'Output file (required)'); |
| 26 argParser.addOption('module-root', | 29 _argParser.addOption('module-root', |
| 27 help: 'Root module directory. ' | 30 help: 'Root module directory.\n' |
| 28 'Generated module paths are relative to this root.'); | 31 'Generated module paths are relative to this root.'); |
| 29 argParser.addOption('library-root', | 32 _argParser.addOption('library-root', |
| 30 help: 'Root of source files. ' | 33 help: 'Root of source files.\n' |
| 31 'Generated library names are relative to this root.'); | 34 'Generated library names are relative to this root.'); |
| 32 argParser.addOption('build-root', | 35 _argParser.addOption('build-root', |
| 33 help: 'Deprecated in favor of --library-root'); | 36 help: 'Deprecated in favor of --library-root', hide: true); |
| 34 CompilerOptions.addArguments(argParser); | 37 CompilerOptions.addArguments(_argParser); |
| 35 AnalyzerOptions.addArguments(argParser); | 38 AnalyzerOptions.addArguments(_argParser); |
| 36 } | 39 } |
| 37 | 40 |
| 38 get name => 'compile'; | 41 int run(List<String> args) { |
| 39 get description => 'Compile a set of Dart files into a JavaScript module.'; | 42 try { |
| 43 _run(_argParser.parse(args)); | |
| 44 return 0; | |
| 45 } on UsageException catch (error) { | |
| 46 // Incorrect usage, input file not found, etc. | |
| 47 _print(error); | |
| 48 return 64; | |
| 49 } on CompileErrorException catch (error) { | |
| 50 // Code has error(s) and failed to compile. | |
| 51 _print(error); | |
| 52 return 1; | |
| 53 } catch (error, stackTrace) { | |
| 54 // Anything else is likely a compiler bug. | |
| 55 // | |
| 56 // --unsafe-force-compile is a bit of a grey area, but it's nice not to | |
| 57 // crash while compiling | |
| 58 // (of course, output code may crash, if it had errors). | |
| 59 // | |
| 60 _print(""); | |
| 61 _print("We're sorry, you've found a bug in our compiler."); | |
| 62 _print("You can report this bug at:"); | |
| 63 _print(" https://github.com/dart-lang/dev_compiler/issues"); | |
| 64 _print(""); | |
| 65 _print( | |
| 66 "Please include the information below in your report, along with"); | |
| 67 _print( | |
| 68 "any other information that may help us track it down. Thanks!"); | |
| 69 _print(""); | |
| 70 _print(" dartdevc arguments: " + args.join(' ')); | |
| 71 _print(" dart --version: ${Platform.version}"); | |
| 72 _print(""); | |
| 73 _print("```"); | |
| 74 _print(error); | |
| 75 _print(stackTrace); | |
| 76 _print("```"); | |
|
nweiz
2016/08/12 20:30:57
Make this a multi-line string rather than calling
Jennifer Messerly
2016/08/12 21:08:01
Done. As a general rule I try and not fix-all-the-
nweiz
2016/08/12 21:16:37
My philosophy is, if I don't fix incidental stuff
| |
| 77 return 70; | |
| 78 } | |
| 79 } | |
| 40 | 80 |
| 41 @override | 81 void _run(ArgResults argResults) { |
| 42 void run() { | |
| 43 var compiler = | 82 var compiler = |
| 44 new ModuleCompiler(new AnalyzerOptions.fromArguments(argResults)); | 83 new ModuleCompiler(new AnalyzerOptions.fromArguments(argResults)); |
| 45 _compilerOptions = new CompilerOptions.fromArguments(argResults); | 84 _compilerOptions = new CompilerOptions.fromArguments(argResults); |
| 46 var outPath = argResults['out']; | 85 var outPath = argResults['out']; |
| 47 | 86 |
| 48 if (outPath == null) { | 87 if (outPath == null) { |
| 49 usageException('Please include the output file location. For example:\n' | 88 _usageException('Please include the output file location. For example:\n' |
| 50 ' -o PATH/TO/OUTPUT_FILE.js'); | 89 ' -o PATH/TO/OUTPUT_FILE.js'); |
| 51 } | 90 } |
| 52 | 91 |
| 53 var libraryRoot = argResults['library-root'] as String; | 92 var libraryRoot = argResults['library-root'] as String; |
| 54 libraryRoot ??= argResults['build-root'] as String; | 93 libraryRoot ??= argResults['build-root'] as String; |
| 55 if (libraryRoot != null) { | 94 if (libraryRoot != null) { |
| 56 libraryRoot = path.absolute(libraryRoot); | 95 libraryRoot = path.absolute(libraryRoot); |
| 57 } else { | 96 } else { |
| 58 libraryRoot = Directory.current.path; | 97 libraryRoot = Directory.current.path; |
| 59 } | 98 } |
| 60 var moduleRoot = argResults['module-root'] as String; | 99 var moduleRoot = argResults['module-root'] as String; |
| 61 String modulePath; | 100 String modulePath; |
| 62 if (moduleRoot != null) { | 101 if (moduleRoot != null) { |
| 63 moduleRoot = path.absolute(moduleRoot); | 102 moduleRoot = path.absolute(moduleRoot); |
| 64 if (!path.isWithin(moduleRoot, outPath)) { | 103 if (!path.isWithin(moduleRoot, outPath)) { |
| 65 usageException('Output file $outPath must be within the module root ' | 104 _usageException('Output file $outPath must be within the module root ' |
| 66 'directory $moduleRoot'); | 105 'directory $moduleRoot'); |
| 67 } | 106 } |
| 68 modulePath = | 107 modulePath = |
| 69 path.withoutExtension(path.relative(outPath, from: moduleRoot)); | 108 path.withoutExtension(path.relative(outPath, from: moduleRoot)); |
| 70 } else { | 109 } else { |
| 71 moduleRoot = path.dirname(outPath); | 110 moduleRoot = path.dirname(outPath); |
| 72 modulePath = path.basenameWithoutExtension(outPath); | 111 modulePath = path.basenameWithoutExtension(outPath); |
| 73 } | 112 } |
| 74 | 113 |
| 75 var unit = new BuildUnit(modulePath, libraryRoot, argResults.rest, | 114 var unit = new BuildUnit(modulePath, libraryRoot, argResults.rest, |
| 76 (source) => _moduleForLibrary(moduleRoot, source)); | 115 (source) => _moduleForLibrary(moduleRoot, source)); |
| 77 | 116 |
| 78 JSModuleFile module = compiler.compile(unit, _compilerOptions); | 117 JSModuleFile module = compiler.compile(unit, _compilerOptions); |
| 79 module.errors.forEach(messageHandler); | 118 module.errors.forEach(_print); |
| 80 | 119 |
| 81 if (!module.isValid) throw new CompileErrorException(); | 120 if (!module.isValid) throw new CompileErrorException(); |
| 82 | 121 |
| 83 // Write JS file, as well as source map and summary (if requested). | 122 // Write JS file, as well as source map and summary (if requested). |
| 84 new File(outPath).writeAsStringSync(module.code); | 123 new File(outPath).writeAsStringSync(module.code); |
| 85 if (module.sourceMap != null) { | 124 if (module.sourceMap != null) { |
| 86 var mapPath = outPath + '.map'; | 125 var mapPath = outPath + '.map'; |
| 87 new File(mapPath) | 126 new File(mapPath) |
| 88 .writeAsStringSync(JSON.encode(module.placeSourceMap(mapPath))); | 127 .writeAsStringSync(JSON.encode(module.placeSourceMap(mapPath))); |
| 89 } | 128 } |
| 90 if (module.summaryBytes != null) { | 129 if (module.summaryBytes != null) { |
| 91 var summaryPath = path.withoutExtension(outPath) + | 130 var summaryPath = path.withoutExtension(outPath) + |
| 92 '.${_compilerOptions.summaryExtension}'; | 131 '.${_compilerOptions.summaryExtension}'; |
| 93 new File(summaryPath).writeAsBytesSync(module.summaryBytes); | 132 new File(summaryPath).writeAsBytesSync(module.summaryBytes); |
| 94 } | 133 } |
| 95 } | 134 } |
| 96 | 135 |
| 97 String _moduleForLibrary(String moduleRoot, Source source) { | 136 String _moduleForLibrary(String moduleRoot, Source source) { |
| 98 if (source is InSummarySource) { | 137 if (source is InSummarySource) { |
| 99 var summaryPath = source.summaryPath; | 138 var summaryPath = source.summaryPath; |
| 100 var ext = '.${_compilerOptions.summaryExtension}'; | 139 var ext = '.${_compilerOptions.summaryExtension}'; |
| 101 if (path.isWithin(moduleRoot, summaryPath) && summaryPath.endsWith(ext)) { | 140 if (path.isWithin(moduleRoot, summaryPath) && summaryPath.endsWith(ext)) { |
| 102 var buildUnitPath = | 141 var buildUnitPath = |
| 103 summaryPath.substring(0, summaryPath.length - ext.length); | 142 summaryPath.substring(0, summaryPath.length - ext.length); |
| 104 return path.relative(buildUnitPath, from: moduleRoot); | 143 return path.relative(buildUnitPath, from: moduleRoot); |
| 105 } | 144 } |
| 106 | 145 |
| 107 throw usageException( | 146 _usageException( |
| 108 'Imported file ${source.uri} is not within the module root ' | 147 'Imported file ${source.uri} is not within the module root ' |
| 109 'directory $moduleRoot'); | 148 'directory $moduleRoot'); |
| 110 } | 149 } |
| 111 | 150 |
| 112 throw usageException( | 151 _usageException( |
| 113 'Imported file "${source.uri}" was not found as a summary or source ' | 152 'Imported file "${source.uri}" was not found as a summary or source ' |
| 114 'file. Please pass in either the summary or the source file ' | 153 'file. Please pass in either the summary or the source file ' |
| 115 'for this import.'); | 154 'for this import.'); |
| 155 return null; // unreachable | |
| 156 } | |
| 157 | |
| 158 void _usageException(String message) { | |
| 159 throw new UsageException( | |
| 160 message, | |
| 161 'Dart Development Compiler compiles Dart into a JavaScript module.' | |
| 162 '\n\n${_argParser.usage}'); | |
| 116 } | 163 } |
| 117 } | 164 } |
| 118 | 165 |
| 119 /// Thrown when the input source code has errors. | 166 /// Thrown when the input source code has errors. |
| 120 class CompileErrorException implements Exception { | 167 class CompileErrorException implements Exception { |
| 121 toString() => '\nPlease fix all errors before compiling (warnings are okay).'; | 168 toString() => '\nPlease fix all errors before compiling (warnings are okay).'; |
| 122 } | 169 } |
| OLD | NEW |