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 |