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

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

Issue 557563002: Store the async-await compiled pub code directly in the repo. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 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
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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:io'; 5 import 'dart:io';
6 6
7 import 'package:args/args.dart';
8 import 'package:analyzer/src/services/formatter_impl.dart';
7 import 'package:async_await/async_await.dart' as async_await; 9 import 'package:async_await/async_await.dart' as async_await;
8 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
9 11
10 /// A changing string that indicates the "version" or timestamp of the compiler
11 /// that the current sources were compiled against.
12 ///
13 /// Increment this whenever a meaningful change in the async/await compiler
14 /// itself is landed. Bumping this will force all previously compiled files
15 /// that were compiled against an older compiler to be recompiled.
16 const COMPILER_VERSION = "2";
17
18 /// The path to pub's root directory (sdk/lib/_internal/pub) in the Dart repo. 12 /// The path to pub's root directory (sdk/lib/_internal/pub) in the Dart repo.
19 /// 13 ///
20 /// This assumes this script is itself being run from within the repo. 14 /// This assumes this script is itself being run from within the repo.
21 final sourceDir = p.dirname(p.dirname(p.fromUri(Platform.script))); 15 final sourceDir = p.dirname(p.dirname(p.fromUri(Platform.script)));
22 16
23 /// The [sourceDir] as a URL, for use in import strings. 17 /// The [sourceDir] as a URL, for use in import strings.
24 final sourceUrl = p.toUri(sourceDir).toString(); 18 final sourceUrl = p.toUri(sourceDir).toString();
25 19
26 /// The directory that compiler output should be written to. 20 /// The directory that compiler output should be written to.
27 String buildDir; 21 final generatedDir = p.join(p.dirname(sourceDir), 'pub_generated');
28 22
29 /// `true` if any file failed to compile. 23 /// `true` if any file failed to compile.
30 bool hadFailure = false; 24 bool hadFailure = false;
31 25
26 bool verbose = false;
27
28 /// Prefix for imports in pub that import dart2js libraries.
32 final _compilerPattern = new RegExp(r"import '(\.\./)+compiler"); 29 final _compilerPattern = new RegExp(r"import '(\.\./)+compiler");
33 30
31 /// Matches the Git commit hash of the compiler stored in the README.md file.
32 ///
33 /// This is used both to find the current commit and replace it with the new
34 /// one.
35 final _commitPattern = new RegExp(r"[a-f0-9]{40,40}");
nweiz 2014/09/08 23:17:05 "{40,40}" -> "{40}"
Bob Nystrom 2014/09/09 17:01:04 Done.
36
34 /// This runs the async/await compiler on all of the pub source code. 37 /// This runs the async/await compiler on all of the pub source code.
35 /// 38 ///
36 /// It reads from the repo and writes the compiled output into the given build 39 /// It reads from the repo and writes the compiled output into the given build
37 /// directory (using the same file names and relative layout). Does not 40 /// directory (using the same file names and relative layout). Does not
38 /// compile files that haven't changed since the last time they were compiled. 41 /// compile files that haven't changed since the last time they were compiled.
39 // TODO(rnystrom): Remove this when #104 is fixed. 42 // TODO(rnystrom): Remove this when #104 is fixed.
40 void main(List<String> arguments) { 43 void main(List<String> arguments) {
41 _validate(arguments.isNotEmpty, "Missing build directory."); 44 var parser = new ArgParser(allowTrailingOptions: true);
42 _validate(arguments.length <= 2, "Unexpected arguments."); 45
43 if (arguments.length == 2) { 46 parser.addFlag("verbose", callback: (value) => verbose = value);
44 _validate(arguments[1] == "--silent", 47
45 "Invalid argument '${arguments[1]}"); 48 var force = false;
49 parser.addFlag("force", callback: (value) => force = value);
50
51 var buildDir;
52
53 try {
54 var rest = parser.parse(arguments).rest;
55 if (rest.isEmpty) {
56 throw new FormatException('Missing build directory.');
57 } else if (rest.length > 1) {
58 throw new FormatException(
59 'Unexpected arguments: ${rest.skip(1).join(" ")}.');
60 }
61
62 buildDir = rest.first;
63 } on FormatException catch(ex) {
64 stderr.writeln(ex);
65 stderr.writeln();
66 stderr.writeln(
67 "Usage: dart async_compile.dart [--verbose] [--force] <build dir>");
68 exit(64);
46 } 69 }
47 70
48 // Create the build output directory if it's not already there. 71 // See what version (i.e. Git commit) of the async-await compiler we
49 buildDir = p.join(p.normalize(arguments[0]), "pub_async"); 72 // currently have. If this is different from the version that was used to
50 new Directory(buildDir).createSync(recursive: true); 73 // compile the sources, recompile everything.
51 74 var result = Process.runSync("git", ["rev-parse", "HEAD"], workingDirectory:
52 // See if the current sources were compiled against a different version of the 75 p.join(sourceDir, "../../../../third_party/pkg/async_await"));
53 // compiler. 76 if (result.exitCode != 0) {
54 var versionPath = p.join(buildDir, "compiler.version"); 77 stderr.writeln("Could not get Git revision of async_await compiler.");
55 var version = "none"; 78 exit(1);
56 try {
57 version = new File(versionPath).readAsStringSync();
58 } on IOException catch (ex) {
59 // Do nothing. The version file didn't exist.
60 } 79 }
61 80
62 var silent = arguments.length == 2 && arguments[1] == "--silent"; 81 var currentCommit = result.stdout.trim();
82
83 var readmePath = p.join(generatedDir, "README.md");
84 var lastCommit;
85 var readme = new File(readmePath).readAsStringSync();
86 var match = _commitPattern.firstMatch(readme);
87 if (match == null) {
88 stderr.writeln("Could not find compiler commit hash in README.md.");
89 exit(1);
90 }
91
92 lastCommit = match[0];
93
63 var numFiles = 0; 94 var numFiles = 0;
64 var numCompiled = 0; 95 var numCompiled = 0;
65 96
66 // Compile any modified or missing files. 97 // Compile any modified or missing files.
67 for (var entry in new Directory(sourceDir).listSync(recursive: true)) { 98 for (var entry in new Directory(sourceDir).listSync(recursive: true)) {
68 if (p.extension(entry.path) != ".dart") continue; 99 if (p.extension(entry.path) != ".dart") continue;
69 100
70 // Skip tests.
71 // TODO(rnystrom): Do we want to use this for tests too?
72 if (p.isWithin(p.join(sourceDir, "test"), entry.path)) continue;
73
74 numFiles++; 101 numFiles++;
75 var relative = p.relative(entry.path, from: sourceDir); 102 var relative = p.relative(entry.path, from: sourceDir);
76 103
77 var sourceFile = entry as File; 104 var sourceFile = entry as File;
78 var destPath = p.join(buildDir, relative); 105 var destPath = p.join(generatedDir, relative);
79 var destFile = new File(destPath); 106 var destFile = new File(destPath);
80 if (version != COMPILER_VERSION || 107 if (force ||
108 currentCommit != lastCommit ||
81 !destFile.existsSync() || 109 !destFile.existsSync() ||
82 entry.lastModifiedSync().isAfter(destFile.lastModifiedSync())) { 110 entry.lastModifiedSync().isAfter(destFile.lastModifiedSync())) {
83 _compile(sourceFile.path, sourceFile.readAsStringSync(), destPath); 111 _compile(sourceFile.path, sourceFile.readAsStringSync(), destPath);
84 numCompiled++; 112 numCompiled++;
85 if (!silent) print("Compiled ${sourceFile.path}."); 113 if (verbose) print("Compiled $relative");
86 } 114 }
87 } 115 }
88 116
89 _writeFile(versionPath, COMPILER_VERSION); 117 // Update the README.
118 if (currentCommit != lastCommit) {
119 readme = readme.replaceAll(_commitPattern, currentCommit);
120 _writeFile(readmePath, readme);
121 }
90 122
91 if (!silent) print("Compiled $numCompiled out of $numFiles files."); 123 if (verbose) print("Compiled $numCompiled out of $numFiles files");
124
125 if (numCompiled > 0) _generateSnapshot(buildDir);
92 126
93 if (hadFailure) exit(1); 127 if (hadFailure) exit(1);
94 } 128 }
95 129
96 void _compile(String sourcePath, String source, String destPath) { 130 void _compile(String sourcePath, String source, String destPath) {
97 var destDir = new Directory(p.dirname(destPath)); 131 var destDir = new Directory(p.dirname(destPath));
98 destDir.createSync(recursive: true); 132 destDir.createSync(recursive: true);
99 133
100 source = _translateAsyncAwait(sourcePath, source); 134 source = _translateAsyncAwait(sourcePath, source);
101 if (source != null) source = _fixDart2jsImports(sourcePath, source, destPath); 135 if (source != null) source = _fixDart2jsImports(sourcePath, source, destPath);
(...skipping 11 matching lines...) Expand all
113 /// 147 ///
114 /// Returns the translated Dart code or `null` if the compiler failed. 148 /// Returns the translated Dart code or `null` if the compiler failed.
115 String _translateAsyncAwait(String sourcePath, String source) { 149 String _translateAsyncAwait(String sourcePath, String source) {
116 if (p.isWithin(p.join(sourceDir, "asset"), sourcePath)) { 150 if (p.isWithin(p.join(sourceDir, "asset"), sourcePath)) {
117 // Don't run the async compiler on the special "asset" source files. These 151 // Don't run the async compiler on the special "asset" source files. These
118 // have preprocessor comments that get discarded by the compiler. 152 // have preprocessor comments that get discarded by the compiler.
119 return source; 153 return source;
120 } 154 }
121 155
122 try { 156 try {
123 return async_await.compile(source); 157 source = async_await.compile(source);
158
159 // Reformat the result since the compiler ditches all whitespace.
160 // TODO(rnystrom): Remove when this is fixed:
161 // https://github.com/dart-lang/async_await/issues/12
162 var result = new CodeFormatter().format(CodeKind.COMPILATION_UNIT, source);
163 return result.source;
124 } catch (ex) { 164 } catch (ex) {
125 stderr.writeln("Async compile failed on $sourcePath:\n$ex"); 165 stderr.writeln("Async compile failed on $sourcePath:\n$ex");
126 hadFailure = true; 166 hadFailure = true;
127 return null; 167 return null;
128 } 168 }
129 } 169 }
130 170
131 /// Fix relative imports to dart2js libraries. 171 /// Fix relative imports to dart2js libraries.
132 /// 172 ///
133 /// Pub imports dart2js using relative imports that reach outside of pub's 173 /// Pub imports dart2js using relative imports that reach outside of pub's
134 /// source tree. Since the build directory is in a different location, we need 174 /// source tree. Since the build directory is in a different location, we need
135 /// to fix those to be valid relative imports from the build directory. 175 /// to fix those to be valid relative imports from the build directory.
136 String _fixDart2jsImports(String sourcePath, String source, String destPath) { 176 String _fixDart2jsImports(String sourcePath, String source, String destPath) {
137 var compilerDir = p.url.join(sourceUrl, "../compiler"); 177 var compilerDir = p.url.join(sourceUrl, "../compiler");
138 var relative = p.url.relative(compilerDir, from: p.dirname(destPath)); 178 var relative = p.url.relative(compilerDir, from: p.dirname(destPath));
139 return source.replaceAll(_compilerPattern, "import '$relative"); 179 return source.replaceAll(_compilerPattern, "import '$relative");
140 } 180 }
141 181
142 /// Validates command-line argument usage and exits with [message] if [valid] 182 /// Regenerate the pub snapshot from the async/await-compiled output. We do
143 /// is `false`. 183 /// this here since the tests need it and it's faster than doing a full SDK
144 void _validate(bool valid, String message) { 184 /// build.
145 if (valid) return; 185 void _generateSnapshot(String buildDir) {
186 buildDir = p.normalize(buildDir);
146 187
147 stderr.writeln(message); 188 var entrypoint = p.join(generatedDir, 'bin/pub.dart');
148 stderr.writeln(); 189 var packageRoot = p.join(buildDir, 'packages');
149 stderr.writeln("Usage: dart async_compile.dart <build dir> [--silent]"); 190 var snapshot = p.join(buildDir, 'dart-sdk/bin/snapshots/pub.dart.snapshot');
150 exit(64); 191
192 var result = Process.runSync(Platform.executable, [
193 "--package-root=$packageRoot",
194 "--snapshot=$snapshot",
195 entrypoint
196 ]);
197
198 if (result.exitCode != 0) {
199 stderr.writeln("Failed to generate snapshot:");
200 if (result.stderr.trim().isNotEmpty) stderr.writeln(result.stderr);
201 if (result.stdout.trim().isNotEmpty) stderr.writeln(result.stdout);
202 exit(result.exitCode);
203 }
204
205 if (verbose) print("Created pub snapshot");
151 } 206 }
152 207
153 /// Deletes the file at [path], ignoring any IO errors that occur. 208 /// Deletes the file at [path], ignoring any IO errors that occur.
154 /// 209 ///
155 /// This swallows errors to accommodate multiple compilers running concurrently. 210 /// This swallows errors to accommodate multiple compilers running concurrently.
156 /// Since they will produce the same output anyway, a failure of one is fine. 211 /// Since they will produce the same output anyway, a failure of one is fine.
157 void _deleteFile(String path) { 212 void _deleteFile(String path) {
158 try { 213 try {
159 new File(path).deleteSync(); 214 new File(path).deleteSync();
160 } on IOException catch (ex) { 215 } on IOException catch (ex) {
161 // Do nothing. 216 // Do nothing.
162 } 217 }
163 } 218 }
164 219
165 /// Writes [contents] to [path], ignoring any IO errors that occur. 220 /// Writes [contents] to [path], ignoring any IO errors that occur.
166 /// 221 ///
167 /// This swallows errors to accommodate multiple compilers running concurrently. 222 /// This swallows errors to accommodate multiple compilers running concurrently.
168 /// Since they will produce the same output anyway, a failure of one is fine. 223 /// Since they will produce the same output anyway, a failure of one is fine.
169 void _writeFile(String path, String contents) { 224 void _writeFile(String path, String contents) {
170 try { 225 try {
171 new File(path).writeAsStringSync(contents); 226 new File(path).writeAsStringSync(contents);
172 } on IOException catch (ex) { 227 } on IOException catch (ex) {
173 // Do nothing. 228 // Do nothing.
174 } 229 }
175 } 230 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698