Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Side by Side Diff: sdk/lib/_internal/pub/bin/async_compile.dart

Issue 937243002: Revert "Revert "Use native async/await support in pub."" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/bin/pub.bat ('k') | sdk/lib/_internal/pub/test/async_compile_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'dart:io';
6
7 import 'package:args/args.dart';
8 import 'package:analyzer/src/services/formatter_impl.dart';
9 import 'package:async_await/async_await.dart' as async_await;
10 import 'package:stack_trace/stack_trace.dart';
11 import 'package:path/path.dart' as p;
12
13 /// The path to pub's root directory (sdk/lib/_internal/pub) in the Dart repo.
14 ///
15 /// This assumes this script is itself being run from within the repo.
16 final sourceDir = p.dirname(p.dirname(p.fromUri(Platform.script)));
17
18 /// The [sourceDir] as a URL, for use in import strings.
19 final sourceUrl = p.toUri(sourceDir).toString();
20
21 /// The directory that compiler output should be written to.
22 String generatedDir;
23
24 /// `true` if any file failed to compile.
25 bool hadFailure = false;
26
27 bool verbose = false;
28
29 /// Prefix for imports in pub that import dart2js libraries.
30 final _compilerPattern = new RegExp(r"import '(\.\./)+compiler");
31
32 /// Matches the Git commit hash of the compiler stored in the README.md file.
33 ///
34 /// This is used both to find the current commit and replace it with the new
35 /// one.
36 final _commitPattern = new RegExp(r"[a-f0-9]{40}");
37
38 /// The template for the README that's added to the generated source.
39 ///
40 /// This is used to store the current commit of the async_await compiler.
41 const _README = """
42 Pub is currently dogfooding the new Dart async/await syntax. Since the Dart VM
43 doesn't natively support it yet, we are using the [async-await][] compiler
44 package.
45
46 [async-await]: https://github.com/dart-lang/async_await
47
48 We run that to compile pub-using-await from sdk/lib/_internal/pub down to
49 vanilla Dart code which is what you see here. To interoperate more easily with
50 the rest of the repositry, we check in that generated code.
51
52 When bug #104 is fixed, we can remove this entirely.
53
54 The code here was compiled using the async-await compiler at commit:
55
56 <<COMMIT>>
57
58 (Note: this file is also parsed by a tool to update the above commit, so be
59 careful not to reformat it.)
60 """;
61
62 /// This runs the async/await compiler on all of the pub source code.
63 ///
64 /// It reads from the repo and writes the compiled output into the given build
65 /// directory (using the same file names and relative layout). Does not
66 /// compile files that haven't changed since the last time they were compiled.
67 // TODO(rnystrom): Remove this when #104 is fixed.
68 void main(List<String> arguments) {
69 var parser = new ArgParser(allowTrailingOptions: true);
70
71 parser.addFlag("verbose", callback: (value) => verbose = value);
72
73 var force = false;
74 parser.addFlag("force", callback: (value) => force = value);
75
76 var buildDir;
77 parser.addOption("snapshot-build-dir", callback: (value) => buildDir = value);
78
79 try {
80 var rest = parser.parse(arguments).rest;
81 if (rest.isEmpty) {
82 throw new FormatException('Missing generated directory.');
83 } else if (rest.length > 1) {
84 throw new FormatException(
85 'Unexpected arguments: ${rest.skip(1).join(" ")}.');
86 }
87
88 generatedDir = rest.first;
89 } on FormatException catch(ex) {
90 stderr.writeln(ex);
91 stderr.writeln();
92 stderr.writeln(
93 "Usage: dart async_compile.dart [--verbose] [--force] "
94 "[--snapshot-build-dir <dir>] <generated dir>");
95 exit(64);
96 }
97
98 // See what version (i.e. Git commit) of the async-await compiler we
99 // currently have. If this is different from the version that was used to
100 // compile the sources, recompile everything.
101 var currentCommit = _getCurrentCommit();
102
103 var readmePath = p.join(generatedDir, "README.md");
104 var lastCommit;
105 try {
106 var readme = new File(readmePath).readAsStringSync();
107 var match = _commitPattern.firstMatch(readme);
108 if (match == null) {
109 stderr.writeln("Could not find compiler commit hash in README.md.");
110 exit(1);
111 }
112
113 lastCommit = match[0];
114 } on IOException catch (error, stackTrace) {
115 if (verbose) {
116 stderr.writeln("Failed to load $readmePath: $error\n"
117 "${new Trace.from(stackTrace)}");
118 }
119 }
120
121 var numFiles = 0;
122 var numCompiled = 0;
123
124 // Compile any modified or missing files.
125 var sources = new Set();
126 for (var entry in new Directory(sourceDir).listSync(recursive: true)) {
127 if (p.extension(entry.path) != ".dart") continue;
128
129 numFiles++;
130 var relative = p.relative(entry.path, from: sourceDir);
131 sources.add(relative);
132
133 var sourceFile = entry as File;
134 var destPath = p.join(generatedDir, relative);
135 var destFile = new File(destPath);
136 if (force ||
137 currentCommit != lastCommit ||
138 !destFile.existsSync() ||
139 entry.lastModifiedSync().isAfter(destFile.lastModifiedSync())) {
140 _compile(sourceFile.path, sourceFile.readAsStringSync(), destPath);
141 numCompiled++;
142 if (verbose) print("Compiled $relative");
143 }
144 }
145
146 // Delete any previously compiled files whose source no longer exists.
147 for (var entry in new Directory(generatedDir).listSync(recursive: true)) {
148 if (p.extension(entry.path) != ".dart") continue;
149
150 var relative = p.relative(entry.path, from: generatedDir);
151
152 if (!sources.contains(relative)) {
153 _deleteFile(entry.path);
154 if (verbose) print("Deleted $relative");
155 }
156 }
157
158 // Update the README.
159 if (currentCommit != lastCommit) {
160 _writeFile(readmePath, _README.replaceAll("<<COMMIT>>", currentCommit));
161 if (verbose) print("Updated README.md");
162 }
163
164 if (numCompiled > 0 && buildDir != null) _generateSnapshot(buildDir);
165
166 if (verbose) print("Compiled $numCompiled out of $numFiles files");
167
168 if (hadFailure) exit(1);
169 }
170
171 String _getCurrentCommit() {
172 var command = "git";
173 var args = ["rev-parse", "HEAD"];
174
175 // Spawning a process on Windows will not look for the executable in the
176 // system path so spawn git through a shell to find it.
177 if (Platform.operatingSystem == "windows") {
178 command = "cmd";
179 args = ["/c", "git"]..addAll(args);
180 }
181
182 var result = Process.runSync(command, args, workingDirectory:
183 p.join(sourceDir, "../../../../third_party/pkg/async_await"));
184 if (result.exitCode != 0) {
185 stderr.writeln("Could not get Git revision of async_await compiler.");
186 exit(1);
187 }
188
189 return result.stdout.trim();
190 }
191
192 void _compile(String sourcePath, String source, String destPath) {
193 var destDir = new Directory(p.dirname(destPath));
194 destDir.createSync(recursive: true);
195
196 source = _translateAsyncAwait(sourcePath, source);
197 if (source != null) source = _fixDart2jsImports(sourcePath, source, destPath);
198
199 if (source == null) {
200 // If the async compile fails, delete the file so that we don't try to
201 // run the stale previous output and so that we try to recompile it later.
202 _deleteFile(destPath);
203 } else {
204 _writeFile(destPath, source);
205 }
206 }
207
208 /// Runs the async/await compiler on [source].
209 ///
210 /// Returns the translated Dart code or `null` if the compiler failed.
211 String _translateAsyncAwait(String sourcePath, String source) {
212 if (p.isWithin(p.join(sourceDir, "asset"), sourcePath)) {
213 // Don't run the async compiler on the special "asset" source files. These
214 // have preprocessor comments that get discarded by the compiler.
215 return source;
216 }
217
218 try {
219 source = async_await.compile(source);
220
221 // Reformat the result since the compiler ditches all whitespace.
222 // TODO(rnystrom): Remove when this is fixed:
223 // https://github.com/dart-lang/async_await/issues/12
224 var result = new CodeFormatter().format(CodeKind.COMPILATION_UNIT, source);
225 return result.source;
226 } catch (ex) {
227 stderr.writeln("Async compile failed on $sourcePath:\n$ex");
228 hadFailure = true;
229 return null;
230 }
231 }
232
233 /// Fix relative imports to dart2js libraries.
234 ///
235 /// Pub imports dart2js using relative imports that reach outside of pub's
236 /// source tree. Since the build directory is in a different location, we need
237 /// to fix those to be valid relative imports from the build directory.
238 String _fixDart2jsImports(String sourcePath, String source, String destPath) {
239 var compilerDir = p.url.join(sourceUrl, "../compiler");
240 var relative = p.url.relative(compilerDir,
241 from: p.url.dirname(p.toUri(destPath).toString()));
242 return source.replaceAll(_compilerPattern, "import '$relative");
243 }
244
245 /// Regenerate the pub snapshot from the async/await-compiled output. We do
246 /// this here since the tests need it and it's faster than doing a full SDK
247 /// build.
248 void _generateSnapshot(String buildDir) {
249 buildDir = p.normalize(buildDir);
250 new Directory(buildDir).createSync(recursive: true);
251
252 var entrypoint = p.join(generatedDir, 'bin/pub.dart');
253 var packageRoot = p.join(buildDir, 'packages');
254 var snapshot = p.join(buildDir, 'dart-sdk/bin/snapshots/pub.dart.snapshot');
255
256 var result = Process.runSync(Platform.executable, [
257 "--package-root=$packageRoot",
258 "--snapshot=$snapshot",
259 entrypoint
260 ]);
261
262 if (result.exitCode != 0) {
263 stderr.writeln("Failed to generate snapshot:");
264 if (result.stderr.trim().isNotEmpty) stderr.writeln(result.stderr);
265 if (result.stdout.trim().isNotEmpty) stderr.writeln(result.stdout);
266 exit(result.exitCode);
267 }
268
269 if (verbose) print("Created pub snapshot");
270 }
271
272 /// Deletes the file at [path], ignoring any IO errors that occur.
273 ///
274 /// This swallows errors to accommodate multiple compilers running concurrently.
275 /// Since they will produce the same output anyway, a failure of one is fine.
276 void _deleteFile(String path) {
277 try {
278 new File(path).deleteSync();
279 } on IOException catch (ex) {
280 // Do nothing.
281 }
282 }
283
284 /// Writes [contents] to [path], ignoring any IO errors that occur.
285 ///
286 /// This swallows errors to accommodate multiple compilers running concurrently.
287 /// Since they will produce the same output anyway, a failure of one is fine.
288 void _writeFile(String path, String contents) {
289 try {
290 new File(path).writeAsStringSync(contents);
291 } on IOException catch (ex) {
292 // Do nothing.
293 }
294 }
OLDNEW
« no previous file with comments | « sdk/bin/pub.bat ('k') | sdk/lib/_internal/pub/test/async_compile_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698