| Index: runtime/bin/process_impl.dart | 
| diff --git a/runtime/bin/process_impl.dart b/runtime/bin/process_impl.dart | 
| index b0092dc7318a87135b67498bf302c5f16d49cbb3..c786f9cb3ffbd1757a90bd2935d191f9aa4221ce 100644 | 
| --- a/runtime/bin/process_impl.dart | 
| +++ b/runtime/bin/process_impl.dart | 
| @@ -8,37 +8,22 @@ class _ProcessStartStatus { | 
| } | 
|  | 
|  | 
| -// Abstract factory class capable of producing interactive and | 
| -// non-interactive processes. | 
| -class _Process { | 
| - | 
| -  factory Process.start(String path, | 
| -                        List<String> arguments, | 
| -                        [ProcessOptions options]) { | 
| -    return new _InteractiveProcess.start(path, arguments, options); | 
| +class _Process extends Process { | 
| +  static Process start(String path, | 
| +                                  List<String> arguments, | 
| +                                  [ProcessOptions options]) { | 
| +    return new _Process.start(path, arguments, options); | 
| } | 
|  | 
| -  factory Process.run(String path, | 
| -                      List<String> arguments, | 
| -                      ProcessOptions options, | 
| -                      void callback(int exitCode, | 
| -                                    String stdout, | 
| -                                    String stderr)) { | 
| -    return new _NonInteractiveProcess.start(path, | 
| -                                            arguments, | 
| -                                            options, | 
| -                                            callback); | 
| +  static Future<ProcessResult> run(String path, | 
| +                                   List<String> arguments, | 
| +                                   [ProcessOptions options]) { | 
| +    return new _NonInteractiveProcess._start(path, arguments, options)._result; | 
| } | 
| -} | 
| - | 
|  | 
| -// _InteractiveProcess is the actual implementation of all processes | 
| -// started from Dart code. | 
| -class _InteractiveProcess implements Process { | 
| - | 
| -  _InteractiveProcess.start(String path, | 
| -                            List<String> arguments, | 
| -                            ProcessOptions options) { | 
| +  _Process.start(String path, | 
| +                 List<String> arguments, | 
| +                 ProcessOptions options) { | 
| if (path is !String) { | 
| throw new IllegalArgumentException("Path is not a String: $path"); | 
| } | 
| @@ -97,7 +82,7 @@ class _InteractiveProcess implements Process { | 
| _onExit = null; | 
| // TODO(ager): Make the actual process starting really async instead of | 
| // simulating it with a timer. | 
| -    new Timer(0, (Timer ignore) => start()); | 
| +    new Timer(0, (Timer ignore) => _start()); | 
| } | 
|  | 
| String _windowsArgumentEscape(String argument) { | 
| @@ -153,20 +138,21 @@ class _InteractiveProcess implements Process { | 
| (bytes[offset + 3] << 24)); | 
| } | 
|  | 
| -  void start() { | 
| +  void _start() { | 
| var status = new _ProcessStartStatus(); | 
| -    bool success = _start(_path, | 
| -                          _arguments, | 
| -                          _workingDirectory, | 
| -                          _environment, | 
| -                          _in, | 
| -                          _out, | 
| -                          _err, | 
| -                          _exitHandler, | 
| -                          status); | 
| +    bool success = _startNative(_path, | 
| +                                _arguments, | 
| +                                _workingDirectory, | 
| +                                _environment, | 
| +                                _in, | 
| +                                _out, | 
| +                                _err, | 
| +                                _exitHandler, | 
| +                                status); | 
| if (!success) { | 
| close(); | 
| -      _reportError(new ProcessException(status._errorMessage, status._errorCode)); | 
| +      _reportError(new ProcessException(status._errorMessage, | 
| +                                        status._errorCode)); | 
| return; | 
| } | 
| _started = true; | 
| @@ -207,15 +193,15 @@ class _InteractiveProcess implements Process { | 
| } | 
| } | 
|  | 
| -  bool _start(String path, | 
| -              List<String> arguments, | 
| -              String workingDirectory, | 
| -              List<String> environment, | 
| -              Socket input, | 
| -              Socket output, | 
| -              Socket error, | 
| -              Socket exitHandler, | 
| -              _ProcessStartStatus status) native "Process_Start"; | 
| +  bool _startNative(String path, | 
| +                    List<String> arguments, | 
| +                    String workingDirectory, | 
| +                    List<String> environment, | 
| +                    Socket input, | 
| +                    Socket output, | 
| +                    Socket error, | 
| +                    Socket exitHandler, | 
| +                    _ProcessStartStatus status) native "Process_Start"; | 
|  | 
| InputStream get stdout() { | 
| if (_closed) { | 
| @@ -314,14 +300,14 @@ class _InteractiveProcess implements Process { | 
|  | 
|  | 
| // _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 implements Process { | 
| -  _NonInteractiveProcess.start(String path, | 
| -                               List<String> arguments, | 
| -                               ProcessOptions options, | 
| -                               Function this._callback) { | 
| +// that buffers output so it can be delivered when the process exits. | 
| +// _NonInteractiveProcess is used to implement the Process.run | 
| +// method. | 
| +class _NonInteractiveProcess { | 
| +  _NonInteractiveProcess._start(String path, | 
| +                                List<String> arguments, | 
| +                                ProcessOptions options) { | 
| +    _completer = new Completer<ProcessResult>(); | 
| // Extract output encoding options and verify arguments. | 
| var stdoutEncoding = Encoding.UTF_8; | 
| var stderrEncoding = Encoding.UTF_8; | 
| @@ -343,7 +329,10 @@ class _NonInteractiveProcess implements Process { | 
| } | 
|  | 
| // Start the underlying process. | 
| -    _process = new _InteractiveProcess.start(path, arguments, options); | 
| +    _process = new _Process.start(path, arguments, options); | 
| + | 
| +    // Setup process error handling. | 
| +    _process.onError = (e) => _completer.completeException(e); | 
|  | 
| // Setup process exit handling. | 
| _process.onExit = (exitCode) { | 
| @@ -378,52 +367,30 @@ class _NonInteractiveProcess implements Process { | 
|  | 
| void _checkDone() { | 
| if (_exitCode != null && _stderrClosed && _stdoutClosed) { | 
| -      _callback(_exitCode, _stdoutBuffer.toString(), _stderrBuffer.toString()); | 
| +      _completer.complete(new _ProcessResult(_exitCode, | 
| +                                             _stdoutBuffer.toString(), | 
| +                                             _stderrBuffer.toString())); | 
| } | 
| } | 
|  | 
| -  InputStream get stdout() { | 
| -    throw new UnsupportedOperationException( | 
| -        'Cannot get stdout stream for process started with ' | 
| -        'the run constructor. The entire stdout ' | 
| -        'will be supplied in the callback on completion.'); | 
| -  } | 
| - | 
| -  InputStream get stderr() { | 
| -    throw new UnsupportedOperationException( | 
| -        'Cannot get stderr stream for process started with ' | 
| -        'the run constructor. The entire stderr ' | 
| -        'will be supplied in the callback on completion.'); | 
| -  } | 
| - | 
| -  OutputStream get stdin() { | 
| -    throw new UnsupportedOperationException( | 
| -        'Cannot communicate via stdin with process started with ' | 
| -        'the run constructor'); | 
| -  } | 
| - | 
| -  void set onStart(void callback()) => _process.onStart = callback; | 
| - | 
| -  void set onExit(void callback(int exitCode)) { | 
| -    throw new UnsupportedOperationException( | 
| -        'Cannot set exit handler on process started with ' | 
| -        'the run constructor. The exit code will ' | 
| -        'be supplied in the callback on completion.'); | 
| -  } | 
| - | 
| -  void set onError(void callback(e)) { | 
| -    _process.onError = callback; | 
| -  } | 
| - | 
| -  void kill() => _process.kill(); | 
| - | 
| -  void close() => _process.close(); | 
| +  Future<ProcessResult> get _result() => _completer.future; | 
|  | 
| +  Completer<ProcessResult> _completer; | 
| Process _process; | 
| -  Function _callback; | 
| StringBuffer _stdoutBuffer; | 
| StringBuffer _stderrBuffer; | 
| int _exitCode; | 
| bool _stdoutClosed = false; | 
| bool _stderrClosed = false; | 
| } | 
| + | 
| + | 
| +class _ProcessResult implements ProcessResult { | 
| +  const _ProcessResult(int this.exitCode, | 
| +                       String this.stdout, | 
| +                       String this.stderr); | 
| + | 
| +  final int exitCode; | 
| +  final String stdout; | 
| +  final String stderr; | 
| +} | 
|  |