OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, 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 library unittest.util.compiler_pool; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:collection'; | |
9 import 'dart:io'; | |
10 | |
11 import 'package:path/path.dart' as p; | |
12 import 'package:pool/pool.dart'; | |
13 | |
14 import '../../util/io.dart'; | |
15 import '../load_exception.dart'; | |
16 | |
17 /// A pool of `dart2js` instances. | |
18 /// | |
19 /// This limits the number of compiler instances running concurrently. It also | |
20 /// ensures that their output doesn't intermingle; only one instance is | |
21 /// "visible" (that is, having its output printed) at a time, and the other | |
22 /// instances' output is buffered until it's their turn to be visible. | |
23 class CompilerPool { | |
24 /// The internal pool that controls the number of process running at once. | |
25 final Pool _pool; | |
26 | |
27 /// The currently-active compilers. | |
28 /// | |
29 /// The first one is the only visible the compiler; the rest will become | |
30 /// visible in queue order. Note that some of these processes may actually | |
31 /// have already exited; they're kept around so that their output can be | |
32 /// emitted once they become visible. | |
33 final _compilers = new Queue<_Compiler>(); | |
34 | |
35 /// Creates a compiler pool that runs up to [parallel] instances of `dart2js` | |
36 /// at once. | |
37 /// | |
38 /// If [parallel] isn't provided, it defaults to 4. | |
kevmoo
2015/02/27 21:12:26
How 'bout Platform.numberOfProcessors ?
nweiz
2015/02/27 21:17:34
dart2js is really heavyweight, and not just in ter
| |
39 CompilerPool({int parallel}) | |
40 : _pool = new Pool(parallel == null ? 4 : parallel); | |
41 | |
42 /// Compile the Dart code at [dartPath] to [jsPath]. | |
43 /// | |
44 /// This wraps the Dart code in the standard browser-testing wrapper. If | |
45 /// [packageRoot] is provided, it's used as the package root for the | |
46 /// compilation. | |
47 /// | |
48 /// The returned [Future] will complete once the `dart2js` process completes | |
49 /// *and* all its output has been printed to the command line. | |
50 Future compile(String dartPath, String jsPath, {String packageRoot}) { | |
51 return _pool.withResource(() { | |
52 return withTempDir((dir) { | |
53 var wrapperPath = p.join(dir, "runInBrowser.dart"); | |
54 new File(wrapperPath).writeAsStringSync(''' | |
55 import "package:unittest/src/runner/browser/iframe_listener.dart"; | |
56 | |
57 import "${p.toUri(p.absolute(dartPath))}" as test; | |
58 | |
59 void main(_) { | |
60 IframeListener.start(() => test.main); | |
61 } | |
62 '''); | |
63 | |
64 // TODO: properly detect this. | |
65 var dart2jsPath = "/usr/local/google/home/nweiz/goog/dart/dart/out/Relea seIA32/dart-sdk/bin/dart2js"; | |
Bob Nystrom
2015/02/27 21:04:40
This path has limited portability. :)
nweiz
2015/02/27 21:17:34
haha oops :-p
| |
66 | |
67 var args = ["--checked", wrapperPath, "--out=$jsPath"]; | |
68 | |
69 if (packageRoot != null) { | |
70 args.add("--package-root=${p.absolute(packageRoot)}"); | |
71 } | |
72 | |
73 if (canUseSpecialChars) { | |
74 args.add("--enable-diagnostic-colors"); | |
75 } | |
76 | |
77 return Process.start(dart2jsPath, args).then((process) { | |
78 var compiler = new _Compiler(dartPath, process); | |
79 | |
80 if (_compilers.isEmpty) _showProcess(compiler); | |
81 _compilers.add(compiler); | |
82 | |
83 return compiler.onDone; | |
84 }); | |
85 }); | |
86 }); | |
87 } | |
88 | |
89 /// Mark [compiler] as the visible instance. | |
90 /// | |
91 /// This prints all [compiler]'s standard output and error. | |
92 void _showProcess(_Compiler compiler) { | |
93 print("Compiling ${compiler.path}..."); | |
94 | |
95 // We wait for stdout and stderr to close and for exitCode to fire to ensure | |
96 // that we're done printing everything about one process before we start the | |
97 // next. | |
98 Future.wait([ | |
99 compiler.process.stdout.listen(stdout.add).asFuture(), | |
100 compiler.process.stderr.listen(stderr.add).asFuture(), | |
101 compiler.process.exitCode.then((exitCode) { | |
102 if (exitCode == 0) return; | |
103 throw new LoadException(compiler.path, "dart2js failed."); | |
104 }) | |
105 ]).then(compiler.onDoneCompleter.complete) | |
106 .catchError(compiler.onDoneCompleter.completeError) | |
107 .then((_) { | |
108 _compilers.removeFirst(); | |
109 if (_compilers.isEmpty) return; | |
110 | |
111 var next = _compilers.first; | |
112 | |
113 // Wait a bit before printing the next progress in case the current one | |
114 // threw an error that needs to be printed. | |
115 Timer.run(() => _showProcess(next)); | |
116 }); | |
117 } | |
118 } | |
119 | |
120 /// A running instance of `dart2js`. | |
121 class _Compiler { | |
122 /// The path of the Dart file being compiled. | |
123 final String path; | |
124 | |
125 /// The underlying process. | |
126 final Process process; | |
127 | |
128 /// A future that will complete once this instance has finished running and | |
129 /// all its output has been printed. | |
130 Future get onDone => onDoneCompleter.future; | |
131 final onDoneCompleter = new Completer(); | |
132 | |
133 _Compiler(this.path, this.process); | |
134 } | |
OLD | NEW |