| Index: runtime/bin/process_patch.dart
|
| diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
|
| index 22b08aa56dde9d15b584bf20dfc92553af6cca3c..d1883818d11b115b0f2520cb4e7302024300432d 100644
|
| --- a/runtime/bin/process_patch.dart
|
| +++ b/runtime/bin/process_patch.dart
|
| @@ -21,13 +21,15 @@ patch class Process {
|
| {String workingDirectory,
|
| Map<String, String> environment,
|
| bool includeParentEnvironment: true,
|
| - bool runInShell: false}) {
|
| + bool runInShell: false,
|
| + bool detach: false}) {
|
| _ProcessImpl process = new _ProcessImpl(executable,
|
| arguments,
|
| workingDirectory,
|
| environment,
|
| includeParentEnvironment,
|
| - runInShell);
|
| + runInShell,
|
| + detach);
|
| return process._start();
|
| }
|
|
|
| @@ -173,7 +175,8 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| String this._workingDirectory,
|
| Map<String, String> environment,
|
| bool includeParentEnvironment,
|
| - bool runInShell) : super() {
|
| + bool runInShell,
|
| + bool detach) : super() {
|
| _processes[_serviceId] = this;
|
| if (runInShell) {
|
| arguments = _getShellArguments(path, arguments);
|
| @@ -230,16 +233,24 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| });
|
| }
|
|
|
| - // stdin going to process.
|
| - _stdin = new _StdSink(new _Socket._writePipe());
|
| - _stdin._sink._owner = this;
|
| - // stdout coming from process.
|
| - _stdout = new _StdStream(new _Socket._readPipe());
|
| - _stdout._stream._owner = this;
|
| - // stderr coming from process.
|
| - _stderr = new _StdStream(new _Socket._readPipe());
|
| - _stderr._stream._owner = this;
|
| - _exitHandler = new _Socket._readPipe();
|
| + if (detach is !bool) {
|
| + throw new ArgumentError("Detach is not a boolean: $detach");
|
| + }
|
| + _detach = detach;
|
| +
|
| +
|
| + if (!detach) {
|
| + // stdin going to process.
|
| + _stdin = new _StdSink(new _Socket._writePipe());
|
| + _stdin._sink._owner = this;
|
| + // stdout coming from process.
|
| + _stdout = new _StdStream(new _Socket._readPipe());
|
| + _stdout._stream._owner = this;
|
| + // stderr coming from process.
|
| + _stderr = new _StdStream(new _Socket._readPipe());
|
| + _stderr._stream._owner = this;
|
| + _exitHandler = new _Socket._readPipe();
|
| + }
|
| _ended = false;
|
| _started = false;
|
| }
|
| @@ -363,19 +374,24 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
|
|
| Future<Process> _start() {
|
| var completer = new Completer();
|
| + if (!_detach) {
|
| + _exitCode = new Completer<int>();
|
| + }
|
| // TODO(ager): Make the actual process starting really async instead of
|
| // simulating it with a timer.
|
| Timer.run(() {
|
| var status = new _ProcessStartStatus();
|
| - bool success = _startNative(_path,
|
| - _arguments,
|
| - _workingDirectory,
|
| - _environment,
|
| - _stdin._sink._nativeSocket,
|
| - _stdout._stream._nativeSocket,
|
| - _stderr._stream._nativeSocket,
|
| - _exitHandler._nativeSocket,
|
| - status);
|
| + bool success =
|
| + _startNative(_path,
|
| + _arguments,
|
| + _workingDirectory,
|
| + _environment,
|
| + _detach,
|
| + _detach ? null : _stdin._sink._nativeSocket,
|
| + _detach ? null : _stdout._stream._nativeSocket,
|
| + _detach ? null : _stderr._stream._nativeSocket,
|
| + _detach ? null : _exitHandler._nativeSocket,
|
| + status);
|
| if (!success) {
|
| completer.completeError(
|
| new ProcessException(_path,
|
| @@ -389,32 +405,35 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
|
|
| // Setup an exit handler to handle internal cleanup and possible
|
| // callback when a process terminates.
|
| - int exitDataRead = 0;
|
| - final int EXIT_DATA_SIZE = 8;
|
| - List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE);
|
| - _exitHandler.listen((data) {
|
| -
|
| - int exitCode(List<int> ints) {
|
| - var code = _intFromBytes(ints, 0);
|
| - var negative = _intFromBytes(ints, 4);
|
| - assert(negative == 0 || negative == 1);
|
| - return (negative == 0) ? code : -code;
|
| - }
|
| -
|
| - void handleExit() {
|
| - _ended = true;
|
| - _exitCode.complete(exitCode(exitDataBuffer));
|
| - // Kill stdin, helping hand if the user forgot to do it.
|
| - _stdin._sink.destroy();
|
| - _processes.remove(_serviceId);
|
| - }
|
| -
|
| - exitDataBuffer.setRange(exitDataRead, exitDataRead + data.length, data);
|
| - exitDataRead += data.length;
|
| - if (exitDataRead == EXIT_DATA_SIZE) {
|
| - handleExit();
|
| - }
|
| - });
|
| + if (!_detach) {
|
| + int exitDataRead = 0;
|
| + final int EXIT_DATA_SIZE = 8;
|
| + List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE);
|
| + _exitHandler.listen((data) {
|
| +
|
| + int exitCode(List<int> ints) {
|
| + var code = _intFromBytes(ints, 0);
|
| + var negative = _intFromBytes(ints, 4);
|
| + assert(negative == 0 || negative == 1);
|
| + return (negative == 0) ? code : -code;
|
| + }
|
| +
|
| + void handleExit() {
|
| + _ended = true;
|
| + _exitCode.complete(exitCode(exitDataBuffer));
|
| + // Kill stdin, helping hand if the user forgot to do it.
|
| + _stdin._sink.destroy();
|
| + _processes.remove(_serviceId);
|
| + }
|
| +
|
| + exitDataBuffer.setRange(
|
| + exitDataRead, exitDataRead + data.length, data);
|
| + exitDataRead += data.length;
|
| + if (exitDataRead == EXIT_DATA_SIZE) {
|
| + handleExit();
|
| + }
|
| + });
|
| + }
|
|
|
| completer.complete(this);
|
| });
|
| @@ -424,10 +443,12 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| ProcessResult _runAndWait(Encoding stdoutEncoding,
|
| Encoding stderrEncoding) {
|
| var status = new _ProcessStartStatus();
|
| + _exitCode = new Completer<int>();
|
| bool success = _startNative(_path,
|
| _arguments,
|
| _workingDirectory,
|
| _environment,
|
| + false,
|
| _stdin._sink._nativeSocket,
|
| _stdout._stream._nativeSocket,
|
| _stderr._stream._nativeSocket,
|
| @@ -464,6 +485,7 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| List<String> arguments,
|
| String workingDirectory,
|
| List<String> environment,
|
| + bool detach,
|
| _NativeSocket stdin,
|
| _NativeSocket stdout,
|
| _NativeSocket stderr,
|
| @@ -487,7 +509,7 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| return _stdin;
|
| }
|
|
|
| - Future<int> get exitCode => _exitCode.future;
|
| + Future<int> get exitCode => _exitCode != null ? _exitCode.future : null;
|
|
|
| bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]) {
|
| if (signal is! ProcessSignal) {
|
| @@ -507,6 +529,7 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| List<String> _arguments;
|
| String _workingDirectory;
|
| List<String> _environment;
|
| + bool _detach;
|
| // Private methods of Socket are used by _in, _out, and _err.
|
| _StdSink _stdin;
|
| _StdStream _stdout;
|
| @@ -514,7 +537,7 @@ class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
|
| Socket _exitHandler;
|
| bool _ended;
|
| bool _started;
|
| - final Completer<int> _exitCode = new Completer<int>();
|
| + Completer<int> _exitCode;
|
| }
|
|
|
|
|
| @@ -584,7 +607,8 @@ ProcessResult _runNonInteractiveProcessSync(
|
| workingDirectory,
|
| environment,
|
| includeParentEnvironment,
|
| - runInShell);
|
| + runInShell,
|
| + false);
|
| return process._runAndWait(stdoutEncoding, stderrEncoding);
|
| }
|
|
|
|
|