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 |