Skip to content
Snippets Groups Projects
Commit 3bd1e9d3 authored by Natalie Weizenbaum's avatar Natalie Weizenbaum
Browse files

Add a CompilerPool class.

This will allow the test runner to compile test files to JavaScript.
It runs dart2js instances in parallel but prints their output
sequentially.

See #5

R=rnystrom@google.com, kevmoo@google.com

Review URL: https://codereview.chromium.org//960723002
parent 602ab1ab
No related branches found
No related tags found
No related merge requests found
// 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);
}
......@@ -9,6 +9,10 @@ import 'dart:io';
import 'package:path/path.dart' as p;
/// The root directory of the Dart SDK.
final String sdkDir = _computeSdkDir();
String _computeSdkDir() => p.dirname(p.dirname(Platform.executable));
/// Returns whether the current Dart version supports [Isolate.kill].
final bool supportsIsolateKill = _supportsIsolateKill;
bool get _supportsIsolateKill {
......
......@@ -48,5 +48,3 @@ String _libraryPath(Symbol libraryName) {
var lib = currentMirrorSystem().findLibrary(libraryName);
return p.fromUri(lib.uri);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment