blob: 21626378a78027bb6803aa6fa6b7c222844fdaa0 [file] [log] [blame]
// Copyright (c) 2017, 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' as io;
/// A wrapper around an [io.Process] class that adds some convenience methods.
class ProcessWrapper implements io.Process {
/// Constructs a [ProcessWrapper] object that delegates to the specified
/// underlying object.
ProcessWrapper(this._delegate)
: _stdout = new StreamController<List<int>>(),
_stderr = new StreamController<List<int>>(),
_stdoutDone = new Completer<void>(),
_stderrDone = new Completer<void>() {
_monitorStdioStream(_delegate.stdout, _stdout, _stdoutDone);
_monitorStdioStream(_delegate.stderr, _stderr, _stderrDone);
}
final io.Process _delegate;
final StreamController<List<int>> _stdout;
final StreamController<List<int>> _stderr;
final Completer<void> _stdoutDone;
final Completer<void> _stderrDone;
/// Listens to the specified [stream], repeating events on it via
/// [controller], and completing [completer] once the stream is done.
void _monitorStdioStream(
Stream<List<int>> stream,
StreamController<List<int>> controller,
Completer<void> completer,
) {
stream.listen(
controller.add,
onError: controller.addError,
onDone: () {
controller.close;
completer.complete();
},
);
}
@override
Future<int> get exitCode => _delegate.exitCode;
/// A [Future] that completes when the process has exited and its standard
/// output and error streams have closed.
///
/// This exists as an alternative to [exitCode], which does not guarantee
/// that the stdio streams have closed (it is possible for the exit code to
/// be available before stdout and stderr have closed).
///
/// The future returned here will complete with the exit code of the process.
Future<int> get done async {
int result;
await Future.wait<void>(<Future<void>>[
_stdoutDone.future,
_stderrDone.future,
_delegate.exitCode.then((int value) {
result = value;
}),
]);
assert(result != null);
return result;
}
@override
bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) {
return _delegate.kill(signal);
}
@override
int get pid => _delegate.pid;
@override
io.IOSink get stdin => _delegate.stdin;
@override
Stream<List<int>> get stdout => _stdout.stream;
@override
Stream<List<int>> get stderr => _stderr.stream;
}