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

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

Issue 896623005: Use native async/await support in pub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes 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
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(
117 "Failed to load $readmePath: $error\n" "${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(
183 command,
184 args,
185 workingDirectory: p.join(sourceDir, "../../../../third_party/pkg/async_awa it"));
186 if (result.exitCode != 0) {
187 stderr.writeln("Could not get Git revision of async_await compiler.");
188 exit(1);
189 }
190
191 return result.stdout.trim();
192 }
193
194 void _compile(String sourcePath, String source, String destPath) {
195 var destDir = new Directory(p.dirname(destPath));
196 destDir.createSync(recursive: true);
197
198 source = _translateAsyncAwait(sourcePath, source);
199 if (source != null) source = _fixDart2jsImports(sourcePath, source, destPath);
200
201 if (source == null) {
202 // If the async compile fails, delete the file so that we don't try to
203 // run the stale previous output and so that we try to recompile it later.
204 _deleteFile(destPath);
205 } else {
206 _writeFile(destPath, source);
207 }
208 }
209
210 /// Runs the async/await compiler on [source].
211 ///
212 /// Returns the translated Dart code or `null` if the compiler failed.
213 String _translateAsyncAwait(String sourcePath, String source) {
214 if (p.isWithin(p.join(sourceDir, "asset"), sourcePath)) {
215 // Don't run the async compiler on the special "asset" source files. These
216 // have preprocessor comments that get discarded by the compiler.
217 return source;
218 }
219
220 try {
221 source = async_await.compile(source);
222
223 // Reformat the result since the compiler ditches all whitespace.
224 // TODO(rnystrom): Remove when this is fixed:
225 // https://github.com/dart-lang/async_await/issues/12
226 var result = new CodeFormatter().format(CodeKind.COMPILATION_UNIT, source);
227 return result.source;
228 } catch (ex) {
229 stderr.writeln("Async compile failed on $sourcePath:\n$ex");
230 hadFailure = true;
231 return null;
232 }
233 }
234
235 /// Fix relative imports to dart2js libraries.
236 ///
237 /// Pub imports dart2js using relative imports that reach outside of pub's
238 /// source tree. Since the build directory is in a different location, we need
239 /// to fix those to be valid relative imports from the build directory.
240 String _fixDart2jsImports(String sourcePath, String source, String destPath) {
241 var compilerDir = p.url.join(sourceUrl, "../compiler");
242 var relative =
243 p.url.relative(compilerDir, from: p.url.dirname(p.toUri(destPath).toString ()));
244 return source.replaceAll(_compilerPattern, "import '$relative");
245 }
246
247 /// Regenerate the pub snapshot from the async/await-compiled output. We do
248 /// this here since the tests need it and it's faster than doing a full SDK
249 /// build.
250 void _generateSnapshot(String buildDir) {
251 buildDir = p.normalize(buildDir);
252 new Directory(buildDir).createSync(recursive: true);
253
254 var entrypoint = p.join(generatedDir, 'bin/pub.dart');
255 var packageRoot = p.join(buildDir, 'packages');
256 var snapshot = p.join(buildDir, 'dart-sdk/bin/snapshots/pub.dart.snapshot');
257
258 var result = Process.runSync(
259 Platform.executable,
260 ["--package-root=$packageRoot", "--snapshot=$snapshot", entrypoint]);
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/lib/_internal/pub_generated/asset/dart/utils.dart ('k') | sdk/lib/_internal/pub_generated/bin/pub.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698