| Index: lib/src/runner/browser/compiler_pool.dart
|
| diff --git a/lib/src/runner/browser/compiler_pool.dart b/lib/src/runner/browser/compiler_pool.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cf77fe06ed553ba04f020fe2b8a707dc9caf2a4f
|
| --- /dev/null
|
| +++ b/lib/src/runner/browser/compiler_pool.dart
|
| @@ -0,0 +1,134 @@
|
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library unittest.util.compiler_pool;
|
| +
|
| +import 'dart:async';
|
| +import 'dart:collection';
|
| +import 'dart:io';
|
| +
|
| +import 'package:path/path.dart' as p;
|
| +import 'package:pool/pool.dart';
|
| +
|
| +import '../../util/io.dart';
|
| +import '../load_exception.dart';
|
| +
|
| +/// A pool of `dart2js` instances.
|
| +///
|
| +/// This limits the number of compiler instances running concurrently. It also
|
| +/// ensures that their output doesn't intermingle; only one instance is
|
| +/// "visible" (that is, having its output printed) at a time, and the other
|
| +/// instances' output is buffered until it's their turn to be visible.
|
| +class CompilerPool {
|
| + /// The internal pool that controls the number of process running at once.
|
| + final Pool _pool;
|
| +
|
| + /// The currently-active compilers.
|
| + ///
|
| + /// The first one is the only visible the compiler; the rest will become
|
| + /// visible in queue order. Note that some of these processes may actually
|
| + /// have already exited; they're kept around so that their output can be
|
| + /// emitted once they become visible.
|
| + final _compilers = new Queue<_Compiler>();
|
| +
|
| + /// Creates a compiler pool that runs up to [parallel] instances of `dart2js`
|
| + /// at once.
|
| + ///
|
| + /// If [parallel] isn't provided, it defaults to 4.
|
| + CompilerPool({int parallel})
|
| + : _pool = new Pool(parallel == null ? 4 : parallel);
|
| +
|
| + /// Compile the Dart code at [dartPath] to [jsPath].
|
| + ///
|
| + /// This wraps the Dart code in the standard browser-testing wrapper. If
|
| + /// [packageRoot] is provided, it's used as the package root for the
|
| + /// compilation.
|
| + ///
|
| + /// The returned [Future] will complete once the `dart2js` process completes
|
| + /// *and* all its output has been printed to the command line.
|
| + Future compile(String dartPath, String jsPath, {String packageRoot}) {
|
| + return _pool.withResource(() {
|
| + return withTempDir((dir) {
|
| + var wrapperPath = p.join(dir, "runInBrowser.dart");
|
| + new File(wrapperPath).writeAsStringSync('''
|
| +import "package:unittest/src/runner/browser/iframe_listener.dart";
|
| +
|
| +import "${p.toUri(p.absolute(dartPath))}" as test;
|
| +
|
| +void main(_) {
|
| + IframeListener.start(() => test.main);
|
| +}
|
| +''');
|
| +
|
| + var dart2jsPath = p.join(sdkDir, 'bin', 'dart2js');
|
| + if (Platform.isWindows) dart2jsPath += '.bat';
|
| +
|
| + var args = ["--checked", wrapperPath, "--out=$jsPath"];
|
| +
|
| + if (packageRoot != null) {
|
| + args.add("--package-root=${p.absolute(packageRoot)}");
|
| + }
|
| +
|
| + if (canUseSpecialChars) {
|
| + args.add("--enable-diagnostic-colors");
|
| + }
|
| +
|
| + return Process.start(dart2jsPath, args).then((process) {
|
| + var compiler = new _Compiler(dartPath, process);
|
| +
|
| + if (_compilers.isEmpty) _showProcess(compiler);
|
| + _compilers.add(compiler);
|
| +
|
| + return compiler.onDone;
|
| + });
|
| + });
|
| + });
|
| + }
|
| +
|
| + /// Mark [compiler] as the visible instance.
|
| + ///
|
| + /// This prints all [compiler]'s standard output and error.
|
| + void _showProcess(_Compiler compiler) {
|
| + print("Compiling ${compiler.path}...");
|
| +
|
| + // We wait for stdout and stderr to close and for exitCode to fire to ensure
|
| + // that we're done printing everything about one process before we start the
|
| + // next.
|
| + Future.wait([
|
| + compiler.process.stdout.listen(stdout.add).asFuture(),
|
| + compiler.process.stderr.listen(stderr.add).asFuture(),
|
| + compiler.process.exitCode.then((exitCode) {
|
| + if (exitCode == 0) return;
|
| + throw new LoadException(compiler.path, "dart2js failed.");
|
| + })
|
| + ]).then(compiler.onDoneCompleter.complete)
|
| + .catchError(compiler.onDoneCompleter.completeError)
|
| + .then((_) {
|
| + _compilers.removeFirst();
|
| + if (_compilers.isEmpty) return;
|
| +
|
| + var next = _compilers.first;
|
| +
|
| + // Wait a bit before printing the next progress in case the current one
|
| + // threw an error that needs to be printed.
|
| + Timer.run(() => _showProcess(next));
|
| + });
|
| + }
|
| +}
|
| +
|
| +/// A running instance of `dart2js`.
|
| +class _Compiler {
|
| + /// The path of the Dart file being compiled.
|
| + final String path;
|
| +
|
| + /// The underlying process.
|
| + final Process process;
|
| +
|
| + /// A future that will complete once this instance has finished running and
|
| + /// all its output has been printed.
|
| + Future get onDone => onDoneCompleter.future;
|
| + final onDoneCompleter = new Completer();
|
| +
|
| + _Compiler(this.path, this.process);
|
| +}
|
|
|