Index: mojo/public/dart/third_party/test/lib/src/runner/browser/compiler_pool.dart |
diff --git a/mojo/public/dart/third_party/test/lib/src/runner/browser/compiler_pool.dart b/mojo/public/dart/third_party/test/lib/src/runner/browser/compiler_pool.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..edc41bf20dd41f7191d43ea6518273063be29d6d |
--- /dev/null |
+++ b/mojo/public/dart/third_party/test/lib/src/runner/browser/compiler_pool.dart |
@@ -0,0 +1,152 @@ |
+// 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 test.util.compiler_pool; |
+ |
+import 'dart:async'; |
+import 'dart:convert'; |
+import 'dart:io'; |
+ |
+import 'package:async/async.dart'; |
+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. |
+class CompilerPool { |
+ /// The internal pool that controls the number of process running at once. |
+ final Pool _pool; |
+ |
+ /// Whether to enable colors on dart2js. |
+ final bool _color; |
+ |
+ /// The currently-active dart2js processes. |
+ final _processes = new Set<Process>(); |
+ |
+ /// Whether [close] has been called. |
+ bool get _closed => _closeMemo.hasRun; |
+ |
+ /// The memoizer for running [close] exactly once. |
+ final _closeMemo = new AsyncMemoizer(); |
+ |
+ /// Creates a compiler pool that runs up to [concurrency] instances of |
+ /// `dart2js` at once. |
+ /// |
+ /// If [concurrency] isn't provided, it defaults to 4. |
+ /// |
+ /// If [color] is true, `dart2js` will be run with colors enabled. |
+ CompilerPool({int concurrency, bool color: false}) |
+ : _pool = new Pool(concurrency == null ? 4 : concurrency), |
+ _color = color; |
+ |
+ /// 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(() { |
+ if (_closed) return null; |
+ |
+ return withTempDir((dir) async { |
+ var wrapperPath = p.join(dir, "runInBrowser.dart"); |
+ new File(wrapperPath).writeAsStringSync(''' |
+import "package:test/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", "--show-package-warnings"]; |
+ |
+ if (packageRoot != null) { |
+ args.add("--package-root=${p.toUri(p.absolute(packageRoot))}"); |
+ } |
+ |
+ if (_color) args.add("--enable-diagnostic-colors"); |
+ |
+ var process = await Process.start(dart2jsPath, args); |
+ if (_closed) { |
+ process.kill(); |
+ return; |
+ } |
+ |
+ _processes.add(process); |
+ |
+ /// Wait until the process is entirely done to print out any output. |
+ /// This can produce a little extra time for users to wait with no |
+ /// update, but it also avoids some really nasty-looking interleaved |
+ /// output. Write both stdout and stderr to the same buffer in case |
+ /// they're intended to be printed in order. |
+ var buffer = new StringBuffer(); |
+ |
+ await Future.wait([ |
+ _printOutputStream(process.stdout, buffer), |
+ _printOutputStream(process.stderr, buffer), |
+ ]); |
+ |
+ var exitCode = await process.exitCode; |
+ _processes.remove(process); |
+ if (_closed) return; |
+ |
+ if (buffer.isNotEmpty) print(buffer); |
+ |
+ if (exitCode != 0) throw new LoadException(dartPath, "dart2js failed."); |
+ |
+ _fixSourceMap(jsPath + '.map'); |
+ }); |
+ }); |
+ } |
+ |
+ // TODO(nweiz): Remove this when sdk#17544 is fixed. |
+ /// Fix up the source map at [mapPath] so that it points to absolute file: |
+ /// URIs that are resolvable by the browser. |
+ void _fixSourceMap(String mapPath) { |
+ var map = JSON.decode(new File(mapPath).readAsStringSync()); |
+ var root = map['sourceRoot']; |
+ |
+ map['sources'] = map['sources'].map((source) { |
+ var url = Uri.parse(root + source); |
+ if (url.scheme != '' && url.scheme != 'file') return source; |
+ if (url.path.endsWith("/runInBrowser.dart")) return ""; |
+ return p.toUri(mapPath).resolveUri(url).toString(); |
+ }).toList(); |
+ |
+ new File(mapPath).writeAsStringSync(JSON.encode(map)); |
+ } |
+ |
+ /// Sanitizes the bytes emitted by [stream], converts them to text, and writes |
+ /// them to [buffer]. |
+ Future _printOutputStream(Stream<List<int>> stream, StringBuffer buffer) { |
+ return sanitizeForWindows(stream) |
+ .listen((data) => buffer.write(UTF8.decode(data))).asFuture(); |
+ } |
+ |
+ /// Closes the compiler pool. |
+ /// |
+ /// This kills all currently-running compilers and ensures that no more will |
+ /// be started. It returns a [Future] that completes once all the compilers |
+ /// have been killed and all resources released. |
+ Future close() { |
+ return _closeMemo.runOnce(() async { |
+ await Future.wait(_processes.map((process) async { |
+ process.kill(); |
+ await process.exitCode; |
+ })); |
+ }); |
+ } |
+} |