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