| Index: runtime/bin/process_impl.dart
|
| diff --git a/runtime/bin/process_impl.dart b/runtime/bin/process_impl.dart
|
| index b62491534bad2b5e9c417db3b532b833dcca9e3a..43c5129bad884b551ca2474c7fb2a70220db722a 100644
|
| --- a/runtime/bin/process_impl.dart
|
| +++ b/runtime/bin/process_impl.dart
|
| @@ -8,11 +8,39 @@ class _ProcessStartStatus {
|
| }
|
|
|
|
|
| +// Abstract factory class capable of producing interactive and
|
| +// non-interactive processes.
|
| class _Process implements Process {
|
|
|
| - _Process.start(String path,
|
| - List<String> arguments,
|
| - [String workingDirectory]) {
|
| + _Process();
|
| +
|
| + factory _Process.start(String path,
|
| + List<String> arguments,
|
| + [String workingDirectory]) {
|
| + return new _InteractiveProcess.start(path, arguments, workingDirectory);
|
| + }
|
| +
|
| + factory _Process.startNonInteractive(String path,
|
| + List<String> arguments,
|
| + String workingDirectory,
|
| + void callback(int exitCode,
|
| + String stdout,
|
| + String stderr)) {
|
| + return new _NonInteractiveProcess.start(path,
|
| + arguments,
|
| + workingDirectory,
|
| + callback);
|
| + }
|
| +}
|
| +
|
| +
|
| +// _InteractiveProcess is the actual implementation of all processes
|
| +// started from Dart code.
|
| +class _InteractiveProcess extends _Process {
|
| +
|
| + _InteractiveProcess.start(String path,
|
| + List<String> arguments,
|
| + String workingDirectory) {
|
| if (path is !String) {
|
| throw new ProcessException("Path is not a String: $path");
|
| }
|
| @@ -259,3 +287,99 @@ class _Process implements Process {
|
| Function _onError;
|
| Function _onStart;
|
| }
|
| +
|
| +
|
| +// _NonInteractiveProcess is a wrapper around an interactive process
|
| +// that restricts the interface to disallow access to the streams and
|
| +// buffers output so it can be delivered to the callback when the
|
| +// process exits.
|
| +class _NonInteractiveProcess extends _Process {
|
| +
|
| + _NonInteractiveProcess.start(String path,
|
| + List<String> arguments,
|
| + String workingDirectory,
|
| + Function this._callback) {
|
| + _process = new _InteractiveProcess.start(path, arguments, workingDirectory);
|
| +
|
| + // Setup process exit handling.
|
| + _process.onExit = (exitCode) {
|
| + _exitCode = exitCode;
|
| + _checkDone();
|
| + };
|
| +
|
| + // Setup stdout handling.
|
| + _stdoutBuffer = new StringBuffer();
|
| + var stdoutStream = new StringInputStream(_process.stdout);
|
| + stdoutStream.onData = () {
|
| + var data = stdoutStream.read();
|
| + if (data != null) _stdoutBuffer.add(data);
|
| + };
|
| + stdoutStream.onClosed = () {
|
| + _stdoutClosed = true;
|
| + _checkDone();
|
| + };
|
| +
|
| + // Setup stderr handling.
|
| + _stderrBuffer = new StringBuffer();
|
| + var stderrStream = new StringInputStream(_process.stderr);
|
| + stderrStream.onData = () {
|
| + var data = stderrStream.read();
|
| + if (data != null) _stderrBuffer.add(data);
|
| + };
|
| + stderrStream.onClosed = () {
|
| + _stderrClosed = true;
|
| + _checkDone();
|
| + };
|
| + }
|
| +
|
| + void _checkDone() {
|
| + if (_exitCode != null && _stderrClosed && _stdoutClosed) {
|
| + _callback(_exitCode, _stdoutBuffer.toString(), _stderrBuffer.toString());
|
| + }
|
| + }
|
| +
|
| + InputStream get stdout() {
|
| + throw new ProcessException(
|
| + 'Cannot get stdout stream for process started with '
|
| + 'the startNonInteractive constructor. The entire stdout '
|
| + 'will be supplied in the callback on completion.');
|
| + }
|
| +
|
| + InputStream get stderr() {
|
| + throw new ProcessException(
|
| + 'Cannot get stderr stream for process started with '
|
| + 'the startNonInteractive constructor. The entire stderr '
|
| + 'will be supplied in the callback on completion.');
|
| + }
|
| +
|
| + OutputStream get stdin() {
|
| + throw new ProcessException(
|
| + 'Cannot communicate via stdin with process started with '
|
| + 'the startNonInteractive constructor');
|
| + }
|
| +
|
| + void set onStart(void callback()) => _process.onStart = callback;
|
| +
|
| + void set onExit(void callback(int exitCode)) {
|
| + throw new ProcessException(
|
| + 'Cannot set exit handler on process started with '
|
| + 'the startNonInteractive constructor. The exit code will '
|
| + 'be supplied in the callback on completion.');
|
| + }
|
| +
|
| + void set onError(void callback(ProcessException error)) {
|
| + _process.onError = callback;
|
| + }
|
| +
|
| + void kill() => _process.kill();
|
| +
|
| + void close() => _process.close();
|
| +
|
| + Process _process;
|
| + Function _callback;
|
| + StringBuffer _stdoutBuffer;
|
| + StringBuffer _stderrBuffer;
|
| + int _exitCode;
|
| + bool _stdoutClosed = false;
|
| + bool _stderrClosed = false;
|
| +}
|
|
|