| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library scheduled_process; | 5 library scheduled_process; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'scheduled_test.dart'; | 10 import 'scheduled_test.dart'; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 /// The process that's scheduled to run. | 31 /// The process that's scheduled to run. |
| 32 ValueFuture<Process> _process; | 32 ValueFuture<Process> _process; |
| 33 | 33 |
| 34 /// A fork of [_stdout] that records the standard output of the process. Used | 34 /// A fork of [_stdout] that records the standard output of the process. Used |
| 35 /// for debugging information. | 35 /// for debugging information. |
| 36 Stream<String> _stdoutLog; | 36 Stream<String> _stdoutLog; |
| 37 | 37 |
| 38 /// A line-by-line view of the standard output stream of the process. | 38 /// A line-by-line view of the standard output stream of the process. |
| 39 Stream<String> _stdout; | 39 Stream<String> _stdout; |
| 40 | 40 |
| 41 /// A subscription that controls both [_stdout] and [_stdoutLog]. | 41 /// A canceller that controls both [_stdout] and [_stdoutLog]. |
| 42 StreamSubscription<String> _stdoutSubscription; | 42 StreamCanceller _stdoutCanceller; |
| 43 | 43 |
| 44 /// A fork of [_stderr] that records the standard error of the process. Used | 44 /// A fork of [_stderr] that records the standard error of the process. Used |
| 45 /// for debugging information. | 45 /// for debugging information. |
| 46 Stream<String> _stderrLog; | 46 Stream<String> _stderrLog; |
| 47 | 47 |
| 48 /// A line-by-line view of the standard error stream of the process. | 48 /// A line-by-line view of the standard error stream of the process. |
| 49 Stream<String> _stderr; | 49 Stream<String> _stderr; |
| 50 | 50 |
| 51 /// A subscription that controls both [_stderr] and [_stderrLog]. | 51 /// A canceller that controls both [_stderr] and [_stderrLog]. |
| 52 StreamSubscription<String> _stderrSubscription; | 52 StreamCanceller _stderrCanceller; |
| 53 | 53 |
| 54 /// The exit code of the process that's scheduled to run. This will naturally | 54 /// The exit code of the process that's scheduled to run. This will naturally |
| 55 /// only complete once the process has terminated. | 55 /// only complete once the process has terminated. |
| 56 ValueFuture<int> _exitCode; | 56 ValueFuture<int> _exitCode; |
| 57 | 57 |
| 58 /// Whether the user has scheduled the end of this process by calling either | 58 /// Whether the user has scheduled the end of this process by calling either |
| 59 /// [shouldExit] or [kill]. | 59 /// [shouldExit] or [kill]. |
| 60 var _endScheduled = false; | 60 var _endScheduled = false; |
| 61 | 61 |
| 62 /// The task that runs immediately before this process is scheduled to end. If | 62 /// The task that runs immediately before this process is scheduled to end. If |
| (...skipping 17 matching lines...) Expand all Loading... |
| 80 {options, String description, Encoding encoding: Encoding.UTF_8}) | 80 {options, String description, Encoding encoding: Encoding.UTF_8}) |
| 81 : _encoding = encoding { | 81 : _encoding = encoding { |
| 82 assert(currentSchedule.state == ScheduleState.SET_UP); | 82 assert(currentSchedule.state == ScheduleState.SET_UP); |
| 83 | 83 |
| 84 _updateDescription(executable, arguments); | 84 _updateDescription(executable, arguments); |
| 85 | 85 |
| 86 _scheduleStartProcess(executable, arguments, options); | 86 _scheduleStartProcess(executable, arguments, options); |
| 87 | 87 |
| 88 _scheduleExceptionCleanup(); | 88 _scheduleExceptionCleanup(); |
| 89 | 89 |
| 90 var stdoutWithSubscription = _lineStreamWithSubscription( | 90 var stdoutWithCanceller = _lineStreamWithCanceller( |
| 91 _process.then((p) => p.stdout)); | 91 _process.then((p) => p.stdout)); |
| 92 _stdoutSubscription = stdoutWithSubscription.last; | 92 _stdoutCanceller = stdoutWithCanceller.last; |
| 93 var stdoutTee = tee(stdoutWithSubscription.first); | 93 var stdoutTee = tee(stdoutWithCanceller.first); |
| 94 _stdout = stdoutTee.first; | 94 _stdout = stdoutTee.first; |
| 95 _stdoutLog = stdoutTee.last; | 95 _stdoutLog = stdoutTee.last; |
| 96 | 96 |
| 97 var stderrWithSubscription = _lineStreamWithSubscription( | 97 var stderrWithCanceller = _lineStreamWithCanceller( |
| 98 _process.then((p) => p.stderr)); | 98 _process.then((p) => p.stderr)); |
| 99 _stderrSubscription = stderrWithSubscription.last; | 99 _stderrCanceller = stderrWithCanceller.last; |
| 100 var stderrTee = tee(stderrWithSubscription.first); | 100 var stderrTee = tee(stderrWithCanceller.first); |
| 101 _stderr = stderrTee.first; | 101 _stderr = stderrTee.first; |
| 102 _stderrLog = stderrTee.last; | 102 _stderrLog = stderrTee.last; |
| 103 } | 103 } |
| 104 | 104 |
| 105 /// Updates [_description] to reflect [executable] and [arguments], which are | 105 /// Updates [_description] to reflect [executable] and [arguments], which are |
| 106 /// the same values as in [start]. | 106 /// the same values as in [start]. |
| 107 void _updateDescription(executable, arguments) { | 107 void _updateDescription(executable, arguments) { |
| 108 if (executable is Future) { | 108 if (executable is Future) { |
| 109 _description = "future process"; | 109 _description = "future process"; |
| 110 } else if (arguments is Future || arguments.any((e) => e is Future)) { | 110 } else if (arguments is Future || arguments.any((e) => e is Future)) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 | 170 |
| 171 if (!_endExpected) { | 171 if (!_endExpected) { |
| 172 throw "Process '${this.description}' ended earlier than scheduled " | 172 throw "Process '${this.description}' ended earlier than scheduled " |
| 173 "with exit code $exitCode."; | 173 "with exit code $exitCode."; |
| 174 } | 174 } |
| 175 })); | 175 })); |
| 176 }); | 176 }); |
| 177 } | 177 } |
| 178 | 178 |
| 179 /// Converts a stream of bytes to a stream of lines and returns that along | 179 /// Converts a stream of bytes to a stream of lines and returns that along |
| 180 /// with a [StreamSubscription] controlling it. | 180 /// with a [StreamCanceller] controlling it. |
| 181 Pair<Stream<String>, StreamSubscription<String>> _lineStreamWithSubscription( | 181 Pair<Stream<String>, StreamCanceller> _lineStreamWithCanceller( |
| 182 Future<Stream<int>> streamFuture) { | 182 Future<Stream<int>> streamFuture) { |
| 183 return streamWithSubscription(futureStream(streamFuture) | 183 return streamWithCanceller(futureStream(streamFuture) |
| 184 .handleError((e) => currentSchedule.signalError(e)) | 184 .handleError((e) => currentSchedule.signalError(e)) |
| 185 .transform(new StringDecoder(_encoding)) | 185 .transform(new StringDecoder(_encoding)) |
| 186 .transform(new LineTransformer())); | 186 .transform(new LineTransformer())); |
| 187 } | 187 } |
| 188 | 188 |
| 189 /// Schedule an exception handler that will clean up the process and provide | 189 /// Schedule an exception handler that will clean up the process and provide |
| 190 /// debug information if an error occurs. | 190 /// debug information if an error occurs. |
| 191 void _scheduleExceptionCleanup() { | 191 void _scheduleExceptionCleanup() { |
| 192 currentSchedule.onException.schedule(() { | 192 currentSchedule.onException.schedule(() { |
| 193 _stdoutSubscription.cancel(); | 193 _stdoutCanceller(); |
| 194 _stderrSubscription.cancel(); | 194 _stderrCanceller(); |
| 195 | 195 |
| 196 if (!_process.hasValue) return; | 196 if (!_process.hasValue) return; |
| 197 | 197 |
| 198 var killedPrematurely = false; | 198 var killedPrematurely = false; |
| 199 if (!_exitCode.hasValue) { | 199 if (!_exitCode.hasValue) { |
| 200 killedPrematurely = true; | 200 killedPrematurely = true; |
| 201 _endExpected = true; | 201 _endExpected = true; |
| 202 _process.value.kill(); | 202 _process.value.kill(); |
| 203 // Ensure that the onException queue waits for the process to actually | 203 // Ensure that the onException queue waits for the process to actually |
| 204 // exit after being killed. | 204 // exit after being killed. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 schedule(() { | 297 schedule(() { |
| 298 _endExpected = true; | 298 _endExpected = true; |
| 299 return _exitCode.then((exitCode) { | 299 return _exitCode.then((exitCode) { |
| 300 if (expectedExitCode != null) { | 300 if (expectedExitCode != null) { |
| 301 expect(exitCode, equals(expectedExitCode)); | 301 expect(exitCode, equals(expectedExitCode)); |
| 302 } | 302 } |
| 303 }); | 303 }); |
| 304 }, "waiting for process '$description' to exit"); | 304 }, "waiting for process '$description' to exit"); |
| 305 } | 305 } |
| 306 } | 306 } |
| OLD | NEW |