| 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 patch class _WindowsCodePageDecoder { | 5 patch class _WindowsCodePageDecoder { |
| 6 /* patch */ static String _decodeBytes(List<int> bytes) | 6 /* patch */ static String _decodeBytes(List<int> bytes) |
| 7 native "SystemEncodingToString"; | 7 native "SystemEncodingToString"; |
| 8 } | 8 } |
| 9 | 9 |
| 10 | 10 |
| 11 patch class _WindowsCodePageEncoder { | 11 patch class _WindowsCodePageEncoder { |
| 12 /* patch */ static List<int> _encodeString(String string) | 12 /* patch */ static List<int> _encodeString(String string) |
| 13 native "StringToSystemEncoding"; | 13 native "StringToSystemEncoding"; |
| 14 } | 14 } |
| 15 | 15 |
| 16 | 16 |
| 17 patch class Process { | 17 patch class Process { |
| 18 /* patch */ static Future<Process> start( | 18 /* patch */ static Future<Process> start( |
| 19 String executable, | 19 String executable, |
| 20 List<String> arguments, | 20 List<String> arguments, |
| 21 {String workingDirectory, | 21 {String workingDirectory, |
| 22 Map<String, String> environment, | 22 Map<String, String> environment, |
| 23 bool includeParentEnvironment: true, | 23 bool includeParentEnvironment: true, |
| 24 bool runInShell: false, | 24 bool runInShell: false, |
| 25 bool detach: false}) { | 25 ProcessStartMode mode: ProcessStartMode.NORMAL}) { |
| 26 _ProcessImpl process = new _ProcessImpl(executable, | 26 _ProcessImpl process = new _ProcessImpl(executable, |
| 27 arguments, | 27 arguments, |
| 28 workingDirectory, | 28 workingDirectory, |
| 29 environment, | 29 environment, |
| 30 includeParentEnvironment, | 30 includeParentEnvironment, |
| 31 runInShell, | 31 runInShell, |
| 32 detach); | 32 mode); |
| 33 return process._start(); | 33 return process._start(); |
| 34 } | 34 } |
| 35 | 35 |
| 36 /* patch */ static Future<ProcessResult> run( | 36 /* patch */ static Future<ProcessResult> run( |
| 37 String executable, | 37 String executable, |
| 38 List<String> arguments, | 38 List<String> arguments, |
| 39 {String workingDirectory, | 39 {String workingDirectory, |
| 40 Map<String, String> environment, | 40 Map<String, String> environment, |
| 41 bool includeParentEnvironment: true, | 41 bool includeParentEnvironment: true, |
| 42 bool runInShell: false, | 42 bool runInShell: false, |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 implements Process { | 169 implements Process { |
| 170 // Use default Map so we keep order. | 170 // Use default Map so we keep order. |
| 171 static Map<int, _ProcessImpl> _processes = new Map<int, _ProcessImpl>(); | 171 static Map<int, _ProcessImpl> _processes = new Map<int, _ProcessImpl>(); |
| 172 | 172 |
| 173 _ProcessImpl(String path, | 173 _ProcessImpl(String path, |
| 174 List<String> arguments, | 174 List<String> arguments, |
| 175 String this._workingDirectory, | 175 String this._workingDirectory, |
| 176 Map<String, String> environment, | 176 Map<String, String> environment, |
| 177 bool includeParentEnvironment, | 177 bool includeParentEnvironment, |
| 178 bool runInShell, | 178 bool runInShell, |
| 179 bool detach) : super() { | 179 ProcessStartMode mode) : super() { |
| 180 _processes[_serviceId] = this; | 180 _processes[_serviceId] = this; |
| 181 if (runInShell) { | 181 if (runInShell) { |
| 182 arguments = _getShellArguments(path, arguments); | 182 arguments = _getShellArguments(path, arguments); |
| 183 path = _getShellCommand(); | 183 path = _getShellCommand(); |
| 184 } | 184 } |
| 185 | 185 |
| 186 if (path is !String) { | 186 if (path is !String) { |
| 187 throw new ArgumentError("Path is not a String: $path"); | 187 throw new ArgumentError("Path is not a String: $path"); |
| 188 } | 188 } |
| 189 _path = path; | 189 _path = path; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 Platform.environment.forEach((key, value) { | 226 Platform.environment.forEach((key, value) { |
| 227 assert(key is String); | 227 assert(key is String); |
| 228 assert(value is String); | 228 assert(value is String); |
| 229 // Do not override keys already set as part of environment. | 229 // Do not override keys already set as part of environment. |
| 230 if (!environment.containsKey(key)) { | 230 if (!environment.containsKey(key)) { |
| 231 _environment.add('$key=$value'); | 231 _environment.add('$key=$value'); |
| 232 } | 232 } |
| 233 }); | 233 }); |
| 234 } | 234 } |
| 235 | 235 |
| 236 if (detach is !bool) { | 236 if (mode is !ProcessStartMode) { |
| 237 throw new ArgumentError("Detach is not a boolean: $detach"); | 237 throw new ArgumentError("Mode is not a ProcessStartMode: $mode"); |
| 238 } | 238 } |
| 239 _detach = detach; | 239 _mode = mode; |
| 240 | 240 |
| 241 | 241 if (mode != ProcessStartMode.DETACHED) { |
| 242 if (!detach) { | |
| 243 // stdin going to process. | 242 // stdin going to process. |
| 244 _stdin = new _StdSink(new _Socket._writePipe()); | 243 _stdin = new _StdSink(new _Socket._writePipe()); |
| 245 _stdin._sink._owner = this; | 244 _stdin._sink._owner = this; |
| 246 // stdout coming from process. | 245 // stdout coming from process. |
| 247 _stdout = new _StdStream(new _Socket._readPipe()); | 246 _stdout = new _StdStream(new _Socket._readPipe()); |
| 248 _stdout._stream._owner = this; | 247 _stdout._stream._owner = this; |
| 249 // stderr coming from process. | 248 // stderr coming from process. |
| 250 _stderr = new _StdStream(new _Socket._readPipe()); | 249 _stderr = new _StdStream(new _Socket._readPipe()); |
| 251 _stderr._stream._owner = this; | 250 _stderr._stream._owner = this; |
| 251 } |
| 252 if (mode == ProcessStartMode.NORMAL) { |
| 252 _exitHandler = new _Socket._readPipe(); | 253 _exitHandler = new _Socket._readPipe(); |
| 253 } | 254 } |
| 254 _ended = false; | 255 _ended = false; |
| 255 _started = false; | 256 _started = false; |
| 256 } | 257 } |
| 257 | 258 |
| 258 String get _serviceTypePath => 'io/processes'; | 259 String get _serviceTypePath => 'io/processes'; |
| 259 String get _serviceTypeName => 'Process'; | 260 String get _serviceTypeName => 'Process'; |
| 260 | 261 |
| 261 Map _toJSON(bool ref) { | 262 Map _toJSON(bool ref) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 | 368 |
| 368 int _intFromBytes(List<int> bytes, int offset) { | 369 int _intFromBytes(List<int> bytes, int offset) { |
| 369 return (bytes[offset] + | 370 return (bytes[offset] + |
| 370 (bytes[offset + 1] << 8) + | 371 (bytes[offset + 1] << 8) + |
| 371 (bytes[offset + 2] << 16) + | 372 (bytes[offset + 2] << 16) + |
| 372 (bytes[offset + 3] << 24)); | 373 (bytes[offset + 3] << 24)); |
| 373 } | 374 } |
| 374 | 375 |
| 375 Future<Process> _start() { | 376 Future<Process> _start() { |
| 376 var completer = new Completer(); | 377 var completer = new Completer(); |
| 377 if (!_detach) { | 378 if (_mode == ProcessStartMode.NORMAL) { |
| 378 _exitCode = new Completer<int>(); | 379 _exitCode = new Completer<int>(); |
| 379 } | 380 } |
| 380 // TODO(ager): Make the actual process starting really async instead of | 381 // TODO(ager): Make the actual process starting really async instead of |
| 381 // simulating it with a timer. | 382 // simulating it with a timer. |
| 382 Timer.run(() { | 383 Timer.run(() { |
| 383 var status = new _ProcessStartStatus(); | 384 var status = new _ProcessStartStatus(); |
| 384 bool success = | 385 bool success = |
| 385 _startNative(_path, | 386 _startNative(_path, |
| 386 _arguments, | 387 _arguments, |
| 387 _workingDirectory, | 388 _workingDirectory, |
| 388 _environment, | 389 _environment, |
| 389 _detach, | 390 _mode.index, |
| 390 _detach ? null : _stdin._sink._nativeSocket, | 391 _mode == ProcessStartMode.DETACHED |
| 391 _detach ? null : _stdout._stream._nativeSocket, | 392 ? null : _stdin._sink._nativeSocket, |
| 392 _detach ? null : _stderr._stream._nativeSocket, | 393 _mode == ProcessStartMode.DETACHED |
| 393 _detach ? null : _exitHandler._nativeSocket, | 394 ? null : _stdout._stream._nativeSocket, |
| 395 _mode == ProcessStartMode.DETACHED |
| 396 ? null : _stderr._stream._nativeSocket, |
| 397 _mode != ProcessStartMode.NORMAL |
| 398 ? null : _exitHandler._nativeSocket, |
| 394 status); | 399 status); |
| 395 if (!success) { | 400 if (!success) { |
| 396 completer.completeError( | 401 completer.completeError( |
| 397 new ProcessException(_path, | 402 new ProcessException(_path, |
| 398 _arguments, | 403 _arguments, |
| 399 status._errorMessage, | 404 status._errorMessage, |
| 400 status._errorCode)); | 405 status._errorCode)); |
| 401 return; | 406 return; |
| 402 } | 407 } |
| 403 | 408 |
| 404 _started = true; | 409 _started = true; |
| 405 | 410 |
| 406 // Setup an exit handler to handle internal cleanup and possible | 411 // Setup an exit handler to handle internal cleanup and possible |
| 407 // callback when a process terminates. | 412 // callback when a process terminates. |
| 408 if (!_detach) { | 413 if (_mode == ProcessStartMode.NORMAL) { |
| 409 int exitDataRead = 0; | 414 int exitDataRead = 0; |
| 410 final int EXIT_DATA_SIZE = 8; | 415 final int EXIT_DATA_SIZE = 8; |
| 411 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); | 416 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); |
| 412 _exitHandler.listen((data) { | 417 _exitHandler.listen((data) { |
| 413 | 418 |
| 414 int exitCode(List<int> ints) { | 419 int exitCode(List<int> ints) { |
| 415 var code = _intFromBytes(ints, 0); | 420 var code = _intFromBytes(ints, 0); |
| 416 var negative = _intFromBytes(ints, 4); | 421 var negative = _intFromBytes(ints, 4); |
| 417 assert(negative == 0 || negative == 1); | 422 assert(negative == 0 || negative == 1); |
| 418 return (negative == 0) ? code : -code; | 423 return (negative == 0) ? code : -code; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 441 } | 446 } |
| 442 | 447 |
| 443 ProcessResult _runAndWait(Encoding stdoutEncoding, | 448 ProcessResult _runAndWait(Encoding stdoutEncoding, |
| 444 Encoding stderrEncoding) { | 449 Encoding stderrEncoding) { |
| 445 var status = new _ProcessStartStatus(); | 450 var status = new _ProcessStartStatus(); |
| 446 _exitCode = new Completer<int>(); | 451 _exitCode = new Completer<int>(); |
| 447 bool success = _startNative(_path, | 452 bool success = _startNative(_path, |
| 448 _arguments, | 453 _arguments, |
| 449 _workingDirectory, | 454 _workingDirectory, |
| 450 _environment, | 455 _environment, |
| 451 false, | 456 ProcessStartMode.NORMAL.index, |
| 452 _stdin._sink._nativeSocket, | 457 _stdin._sink._nativeSocket, |
| 453 _stdout._stream._nativeSocket, | 458 _stdout._stream._nativeSocket, |
| 454 _stderr._stream._nativeSocket, | 459 _stderr._stream._nativeSocket, |
| 455 _exitHandler._nativeSocket, | 460 _exitHandler._nativeSocket, |
| 456 status); | 461 status); |
| 457 if (!success) { | 462 if (!success) { |
| 458 throw new ProcessException(_path, | 463 throw new ProcessException(_path, |
| 459 _arguments, | 464 _arguments, |
| 460 status._errorMessage, | 465 status._errorMessage, |
| 461 status._errorCode); | 466 status._errorCode); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 478 result[0], | 483 result[0], |
| 479 result[1], | 484 result[1], |
| 480 getOutput(result[2], stdoutEncoding), | 485 getOutput(result[2], stdoutEncoding), |
| 481 getOutput(result[3], stderrEncoding)); | 486 getOutput(result[3], stderrEncoding)); |
| 482 } | 487 } |
| 483 | 488 |
| 484 bool _startNative(String path, | 489 bool _startNative(String path, |
| 485 List<String> arguments, | 490 List<String> arguments, |
| 486 String workingDirectory, | 491 String workingDirectory, |
| 487 List<String> environment, | 492 List<String> environment, |
| 488 bool detach, | 493 int mode, |
| 489 _NativeSocket stdin, | 494 _NativeSocket stdin, |
| 490 _NativeSocket stdout, | 495 _NativeSocket stdout, |
| 491 _NativeSocket stderr, | 496 _NativeSocket stderr, |
| 492 _NativeSocket exitHandler, | 497 _NativeSocket exitHandler, |
| 493 _ProcessStartStatus status) native "Process_Start"; | 498 _ProcessStartStatus status) native "Process_Start"; |
| 494 | 499 |
| 495 _wait(_NativeSocket stdin, | 500 _wait(_NativeSocket stdin, |
| 496 _NativeSocket stdout, | 501 _NativeSocket stdout, |
| 497 _NativeSocket stderr, | 502 _NativeSocket stderr, |
| 498 _NativeSocket exitHandler) native "Process_Wait"; | 503 _NativeSocket exitHandler) native "Process_Wait"; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 522 } | 527 } |
| 523 | 528 |
| 524 bool _kill(Process p, int signal) native "Process_Kill"; | 529 bool _kill(Process p, int signal) native "Process_Kill"; |
| 525 | 530 |
| 526 int get pid => _ProcessUtils._pid(this); | 531 int get pid => _ProcessUtils._pid(this); |
| 527 | 532 |
| 528 String _path; | 533 String _path; |
| 529 List<String> _arguments; | 534 List<String> _arguments; |
| 530 String _workingDirectory; | 535 String _workingDirectory; |
| 531 List<String> _environment; | 536 List<String> _environment; |
| 532 bool _detach; | 537 ProcessStartMode _mode; |
| 533 // Private methods of Socket are used by _in, _out, and _err. | 538 // Private methods of Socket are used by _in, _out, and _err. |
| 534 _StdSink _stdin; | 539 _StdSink _stdin; |
| 535 _StdStream _stdout; | 540 _StdStream _stdout; |
| 536 _StdStream _stderr; | 541 _StdStream _stderr; |
| 537 Socket _exitHandler; | 542 Socket _exitHandler; |
| 538 bool _ended; | 543 bool _ended; |
| 539 bool _started; | 544 bool _started; |
| 540 Completer<int> _exitCode; | 545 Completer<int> _exitCode; |
| 541 } | 546 } |
| 542 | 547 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 bool includeParentEnvironment, | 606 bool includeParentEnvironment, |
| 602 bool runInShell, | 607 bool runInShell, |
| 603 Encoding stdoutEncoding, | 608 Encoding stdoutEncoding, |
| 604 Encoding stderrEncoding) { | 609 Encoding stderrEncoding) { |
| 605 var process = new _ProcessImpl(executable, | 610 var process = new _ProcessImpl(executable, |
| 606 arguments, | 611 arguments, |
| 607 workingDirectory, | 612 workingDirectory, |
| 608 environment, | 613 environment, |
| 609 includeParentEnvironment, | 614 includeParentEnvironment, |
| 610 runInShell, | 615 runInShell, |
| 611 false); | 616 ProcessStartMode.NORMAL); |
| 612 return process._runAndWait(stdoutEncoding, stderrEncoding); | 617 return process._runAndWait(stdoutEncoding, stderrEncoding); |
| 613 } | 618 } |
| 614 | 619 |
| 615 | 620 |
| 616 class _ProcessResult implements ProcessResult { | 621 class _ProcessResult implements ProcessResult { |
| 617 const _ProcessResult(int this.pid, | 622 const _ProcessResult(int this.pid, |
| 618 int this.exitCode, | 623 int this.exitCode, |
| 619 this.stdout, | 624 this.stdout, |
| 620 this.stderr); | 625 this.stderr); |
| 621 | 626 |
| 622 final int pid; | 627 final int pid; |
| 623 final int exitCode; | 628 final int exitCode; |
| 624 final stdout; | 629 final stdout; |
| 625 final stderr; | 630 final stderr; |
| 626 } | 631 } |
| OLD | NEW |