diff --git a/CHANGELOG.md b/CHANGELOG.md index d81018c..e42904a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ +## 0.1.3 + +* Add automatic intercepting of print calls and append them to + `response.output`. This makes more libraries work out of the box, as printing + would previously cause an error due to communication over stdin/stdout. + * Note that using stdin/stdout directly will still cause an error, but that is + less common. + ## 0.1.2 -* Add better handling for the case where stdin gives an error instead of an EOF. +* Add better handling for the case where stdin gives an error instead of an EOF. ## 0.1.1 diff --git a/lib/src/async_worker_loop.dart b/lib/src/async_worker_loop.dart index 4583ba2..bf6c893 100644 --- a/lib/src/async_worker_loop.dart +++ b/lib/src/async_worker_loop.dart @@ -41,7 +41,16 @@ abstract class AsyncWorkerLoop implements WorkerLoop { try { var request = await connection.readRequest(); if (request == null) break; - response = await performRequest(request); + var printMessages = new StringBuffer(); + response = await runZoned(() => performRequest(request), + zoneSpecification: + new ZoneSpecification(print: (self, parent, zone, message) { + printMessages.writeln(); + printMessages.write(message); + })); + if (printMessages.isNotEmpty) { + response.output = '${response.output}$printMessages'; + } // In case they forget to set this. response.exitCode ??= EXIT_CODE_OK; } catch (e, s) { diff --git a/lib/src/sync_worker_loop.dart b/lib/src/sync_worker_loop.dart index 3b2a05b..a3528a5 100644 --- a/lib/src/sync_worker_loop.dart +++ b/lib/src/sync_worker_loop.dart @@ -1,7 +1,7 @@ // Copyright (c) 2016, 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. - +import 'dart:async'; import 'dart:io'; import 'constants.dart'; @@ -39,7 +39,15 @@ abstract class SyncWorkerLoop implements WorkerLoop { try { var request = connection.readRequest(); if (request == null) break; - response = performRequest(request); + var printMessages = new StringBuffer(); + response = runZoned(() => performRequest(request), zoneSpecification: + new ZoneSpecification(print: (self, parent, zone, message) { + printMessages.writeln(); + printMessages.write(message); + })); + if (printMessages.isNotEmpty) { + response.output = '${response.output}$printMessages'; + } // In case they forget to set this. response.exitCode ??= EXIT_CODE_OK; } catch (e, s) { diff --git a/lib/testing.dart b/lib/testing.dart index 882097f..1afd231 100644 --- a/lib/testing.dart +++ b/lib/testing.dart @@ -101,6 +101,9 @@ abstract class TestWorkerConnection implements WorkerConnection { /// Interface for a [TestWorkerLoop] which allows you to enqueue responses. abstract class TestWorkerLoop implements WorkerLoop { void enqueueResponse(WorkResponse response); + + /// If set, this message will be printed during the call to `performRequest`. + String get printMessage; } /// A [StdSyncWorkerConnection] which records its responses. @@ -123,12 +126,16 @@ class TestSyncWorkerLoop extends SyncWorkerLoop implements TestWorkerLoop { final List requests = []; final Queue _responses = new Queue(); - TestSyncWorkerLoop(SyncWorkerConnection connection) + @override + final String printMessage; + + TestSyncWorkerLoop(SyncWorkerConnection connection, {this.printMessage}) : super(connection: connection); @override WorkResponse performRequest(WorkRequest request) { requests.add(request); + if (printMessage != null) print(printMessage); return _responses.removeFirst(); } @@ -161,12 +168,16 @@ class TestAsyncWorkerLoop extends AsyncWorkerLoop implements TestWorkerLoop { final List requests = []; final Queue _responses = new Queue(); - TestAsyncWorkerLoop(AsyncWorkerConnection connection) + @override + final String printMessage; + + TestAsyncWorkerLoop(AsyncWorkerConnection connection, {this.printMessage}) : super(connection: connection); @override Future performRequest(WorkRequest request) async { requests.add(request); + if (printMessage != null) print(printMessage); return _responses.removeFirst(); } diff --git a/pubspec.yaml b/pubspec.yaml index e7e589e..e6ca01b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: bazel_worker -version: 0.1.2 +version: 0.1.3 description: Tools for creating a bazel persistent worker. author: Dart Team homepage: https://github.com/dart-lang/bazel_worker diff --git a/test/worker_loop_test.dart b/test/worker_loop_test.dart index ac4dd11..1ef2845 100644 --- a/test/worker_loop_test.dart +++ b/test/worker_loop_test.dart @@ -28,6 +28,24 @@ void main() { (TestAsyncWorkerConnection connection) => new TestAsyncWorkerLoop(connection)); }); + + group('SyncWorkerLoopWithPrint', () { + runTests( + () => new TestStdinSync(), + (Stdin stdinStream, Stdout stdoutStream) => + new TestSyncWorkerConnection(stdinStream, stdoutStream), + (TestSyncWorkerConnection connection) => + new TestSyncWorkerLoop(connection, printMessage: 'Goodbye!')); + }); + + group('AsyncWorkerLoopWithPrint', () { + runTests( + () => new TestStdinAsync(), + (Stdin stdinStream, Stdout stdoutStream) => + new TestAsyncWorkerConnection(stdinStream, stdoutStream), + (TestAsyncWorkerConnection connection) => + new TestAsyncWorkerLoop(connection, printMessage: 'Goodbye!')); + }); } void runTests/**/( @@ -54,10 +72,23 @@ void runTests/**/( var response = new WorkResponse()..output = 'Hello World'; workerLoop.enqueueResponse(response); - await workerLoop.run(); + + // Make sure `print` never gets called in the parent zone. + var printMessages = []; + await runZoned(() => workerLoop.run(), zoneSpecification: + new ZoneSpecification(print: (self, parent, zone, message) { + printMessages.add(message); + })); + expect(printMessages, isEmpty, + reason: 'The worker loop should hide all print calls from the parent ' + 'zone.'); expect(connection.responses, hasLength(1)); expect(connection.responses[0], response); + if (workerLoop.printMessage != null) { + expect(response.output, endsWith(workerLoop.printMessage), + reason: 'Print messages should get appended to the response output.'); + } // Check that a serialized version was written to std out. expect(stdoutStream.writes, hasLength(1));