| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 // TODO(ager): The only reason for this class is that we | 7 // TODO(ager): The only reason for this class is that we |
| 8 // cannot patch a top-level at this point. | 8 // cannot patch a top-level at this point. |
| 9 class _ProcessUtils { | 9 class _ProcessUtils { |
| 10 external static void _exit(int status); | 10 external static void _exit(int status); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 * Besides this the Dart executable itself uses an exit code of `254` | 36 * Besides this the Dart executable itself uses an exit code of `254` |
| 37 * for reporting compile time errors and an exit code of `255` for | 37 * for reporting compile time errors and an exit code of `255` for |
| 38 * reporting runtime error (unhandled exception). | 38 * reporting runtime error (unhandled exception). |
| 39 * | 39 * |
| 40 * Due to these facts it is recommended to only use exit codes in the | 40 * Due to these facts it is recommended to only use exit codes in the |
| 41 * range [0..127] for communicating the result of running a Dart | 41 * range [0..127] for communicating the result of running a Dart |
| 42 * program to the surrounding environment. This will avoid any | 42 * program to the surrounding environment. This will avoid any |
| 43 * cross-platform issues. | 43 * cross-platform issues. |
| 44 */ | 44 */ |
| 45 void exit(int code) { | 45 void exit(int code) { |
| 46 if (code is !int) { | 46 if (code is! int) { |
| 47 throw new ArgumentError("Integer value for exit code expected"); | 47 throw new ArgumentError("Integer value for exit code expected"); |
| 48 } | 48 } |
| 49 _ProcessUtils._exit(code); | 49 _ProcessUtils._exit(code); |
| 50 } | 50 } |
| 51 | 51 |
| 52 /** | 52 /** |
| 53 * Set the global exit code for the Dart VM. | 53 * Set the global exit code for the Dart VM. |
| 54 * | 54 * |
| 55 * The exit code is global for the Dart VM and the last assignment to | 55 * The exit code is global for the Dart VM and the last assignment to |
| 56 * exitCode from any isolate determines the exit code of the Dart VM | 56 * exitCode from any isolate determines the exit code of the Dart VM |
| 57 * on normal termination. | 57 * on normal termination. |
| 58 * | 58 * |
| 59 * Default value is `0`. | 59 * Default value is `0`. |
| 60 * | 60 * |
| 61 * See [exit] for more information on how to chose a value for the | 61 * See [exit] for more information on how to chose a value for the |
| 62 * exit code. | 62 * exit code. |
| 63 */ | 63 */ |
| 64 void set exitCode(int code) { | 64 void set exitCode(int code) { |
| 65 if (code is !int) { | 65 if (code is! int) { |
| 66 throw new ArgumentError("Integer value for exit code expected"); | 66 throw new ArgumentError("Integer value for exit code expected"); |
| 67 } | 67 } |
| 68 _ProcessUtils._setExitCode(code); | 68 _ProcessUtils._setExitCode(code); |
| 69 } | 69 } |
| 70 | 70 |
| 71 /** | 71 /** |
| 72 * Get the global exit code for the Dart VM. | 72 * Get the global exit code for the Dart VM. |
| 73 * | 73 * |
| 74 * The exit code is global for the Dart VM and the last assignment to | 74 * The exit code is global for the Dart VM and the last assignment to |
| 75 * exitCode from any isolate determines the exit code of the Dart VM | 75 * exitCode from any isolate determines the exit code of the Dart VM |
| (...skipping 22 matching lines...) Expand all Loading... |
| 98 * Returns the PID of the current process. | 98 * Returns the PID of the current process. |
| 99 */ | 99 */ |
| 100 int get pid => _ProcessUtils._pid(null); | 100 int get pid => _ProcessUtils._pid(null); |
| 101 | 101 |
| 102 /** | 102 /** |
| 103 * Modes for running a new process. | 103 * Modes for running a new process. |
| 104 */ | 104 */ |
| 105 enum ProcessStartMode { | 105 enum ProcessStartMode { |
| 106 /// Normal child process. | 106 /// Normal child process. |
| 107 NORMAL, | 107 NORMAL, |
| 108 |
| 108 /// Detached child process with no open communication channel. | 109 /// Detached child process with no open communication channel. |
| 109 DETACHED, | 110 DETACHED, |
| 111 |
| 110 /// Detached child process with stdin, stdout and stderr still open | 112 /// Detached child process with stdin, stdout and stderr still open |
| 111 /// for communication with the child. | 113 /// for communication with the child. |
| 112 DETACHED_WITH_STDIO | 114 DETACHED_WITH_STDIO |
| 113 } | 115 } |
| 114 | 116 |
| 115 /** | 117 /** |
| 116 * The means to execute a program. | 118 * The means to execute a program. |
| 117 * | 119 * |
| 118 * Use the static [start] and [run] methods to start a new process. | 120 * Use the static [start] and [run] methods to start a new process. |
| 119 * The run method executes the process non-interactively to completion. | 121 * The run method executes the process non-interactively to completion. |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 * If `mode` is [ProcessStartMode.DETACHED_WITH_STDIO] a detached | 287 * If `mode` is [ProcessStartMode.DETACHED_WITH_STDIO] a detached |
| 286 * process will be created where the `stdin`, `stdout` and `stderr` | 288 * process will be created where the `stdin`, `stdout` and `stderr` |
| 287 * are connected. The creator can communicate with the child through | 289 * are connected. The creator can communicate with the child through |
| 288 * these. The detached process will keep running even if these | 290 * these. The detached process will keep running even if these |
| 289 * communication channels are closed. The process' exit code will | 291 * communication channels are closed. The process' exit code will |
| 290 * not become available when it terminated. | 292 * not become available when it terminated. |
| 291 * | 293 * |
| 292 * The default value for `mode` is `ProcessStartMode.NORMAL`. | 294 * The default value for `mode` is `ProcessStartMode.NORMAL`. |
| 293 */ | 295 */ |
| 294 external static Future<Process> start( | 296 external static Future<Process> start( |
| 295 String executable, | 297 String executable, List<String> arguments, |
| 296 List<String> arguments, | |
| 297 {String workingDirectory, | 298 {String workingDirectory, |
| 298 Map<String, String> environment, | 299 Map<String, String> environment, |
| 299 bool includeParentEnvironment: true, | 300 bool includeParentEnvironment: true, |
| 300 bool runInShell: false, | 301 bool runInShell: false, |
| 301 ProcessStartMode mode: ProcessStartMode.NORMAL}); | 302 ProcessStartMode mode: ProcessStartMode.NORMAL}); |
| 302 | 303 |
| 303 /** | 304 /** |
| 304 * Starts a process and runs it non-interactively to completion. The | 305 * Starts a process and runs it non-interactively to completion. The |
| 305 * process run is [executable] with the specified [arguments]. | 306 * process run is [executable] with the specified [arguments]. |
| 306 * | 307 * |
| 307 * Use [workingDirectory] to set the working directory for the process. Note | 308 * Use [workingDirectory] to set the working directory for the process. Note |
| 308 * that the change of directory occurs before executing the process on some | 309 * that the change of directory occurs before executing the process on some |
| 309 * platforms, which may have impact when using relative paths for the | 310 * platforms, which may have impact when using relative paths for the |
| 310 * executable and the arguments. | 311 * executable and the arguments. |
| 311 * | 312 * |
| (...skipping 23 matching lines...) Expand all Loading... |
| 335 * | 336 * |
| 336 * The following code uses `Process.run` to grep for `main` in the | 337 * The following code uses `Process.run` to grep for `main` in the |
| 337 * file `test.dart` on Linux. | 338 * file `test.dart` on Linux. |
| 338 * | 339 * |
| 339 * Process.run('grep', ['-i', 'main', 'test.dart']).then((result) { | 340 * Process.run('grep', ['-i', 'main', 'test.dart']).then((result) { |
| 340 * stdout.write(result.stdout); | 341 * stdout.write(result.stdout); |
| 341 * stderr.write(result.stderr); | 342 * stderr.write(result.stderr); |
| 342 * }); | 343 * }); |
| 343 */ | 344 */ |
| 344 external static Future<ProcessResult> run( | 345 external static Future<ProcessResult> run( |
| 345 String executable, | 346 String executable, List<String> arguments, |
| 346 List<String> arguments, | |
| 347 {String workingDirectory, | 347 {String workingDirectory, |
| 348 Map<String, String> environment, | 348 Map<String, String> environment, |
| 349 bool includeParentEnvironment: true, | 349 bool includeParentEnvironment: true, |
| 350 bool runInShell: false, | 350 bool runInShell: false, |
| 351 Encoding stdoutEncoding: SYSTEM_ENCODING, | 351 Encoding stdoutEncoding: SYSTEM_ENCODING, |
| 352 Encoding stderrEncoding: SYSTEM_ENCODING}); | 352 Encoding stderrEncoding: SYSTEM_ENCODING}); |
| 353 | |
| 354 | 353 |
| 355 /** | 354 /** |
| 356 * Starts a process and runs it to completion. This is a synchronous | 355 * Starts a process and runs it to completion. This is a synchronous |
| 357 * call and will block until the child process terminates. | 356 * call and will block until the child process terminates. |
| 358 * | 357 * |
| 359 * The arguments are the same as for `Process.run`. | 358 * The arguments are the same as for `Process.run`. |
| 360 * | 359 * |
| 361 * Returns a `ProcessResult` with the result of running the process, | 360 * Returns a `ProcessResult` with the result of running the process, |
| 362 * i.e., exit code, standard out and standard in. | 361 * i.e., exit code, standard out and standard in. |
| 363 */ | 362 */ |
| 364 external static ProcessResult runSync( | 363 external static ProcessResult runSync( |
| 365 String executable, | 364 String executable, List<String> arguments, |
| 366 List<String> arguments, | |
| 367 {String workingDirectory, | 365 {String workingDirectory, |
| 368 Map<String, String> environment, | 366 Map<String, String> environment, |
| 369 bool includeParentEnvironment: true, | 367 bool includeParentEnvironment: true, |
| 370 bool runInShell: false, | 368 bool runInShell: false, |
| 371 Encoding stdoutEncoding: SYSTEM_ENCODING, | 369 Encoding stdoutEncoding: SYSTEM_ENCODING, |
| 372 Encoding stderrEncoding: SYSTEM_ENCODING}); | 370 Encoding stderrEncoding: SYSTEM_ENCODING}); |
| 373 | 371 |
| 374 /** | 372 /** |
| 375 * Kills the process with id [pid]. | 373 * Kills the process with id [pid]. |
| 376 * | 374 * |
| 377 * Where possible, sends the [signal] to the process with id | 375 * Where possible, sends the [signal] to the process with id |
| 378 * `pid`. This includes Linux and OS X. The default signal is | 376 * `pid`. This includes Linux and OS X. The default signal is |
| 379 * [ProcessSignal.SIGTERM] which will normally terminate the | 377 * [ProcessSignal.SIGTERM] which will normally terminate the |
| 380 * process. | 378 * process. |
| 381 * | 379 * |
| 382 * On platforms without signal support, including Windows, the call | 380 * On platforms without signal support, including Windows, the call |
| 383 * just terminates the process with id `pid` in a platform specific | 381 * just terminates the process with id `pid` in a platform specific |
| 384 * way, and the `signal` parameter is ignored. | 382 * way, and the `signal` parameter is ignored. |
| 385 * | 383 * |
| 386 * Returns `true` if the signal is successfully delivered to the | 384 * Returns `true` if the signal is successfully delivered to the |
| 387 * process. Otherwise the signal could not be sent, usually meaning | 385 * process. Otherwise the signal could not be sent, usually meaning |
| 388 * that the process is already dead. | 386 * that the process is already dead. |
| 389 */ | 387 */ |
| 390 external static bool killPid( | 388 external static bool killPid(int pid, |
| 391 int pid, [ProcessSignal signal = ProcessSignal.SIGTERM]); | 389 [ProcessSignal signal = ProcessSignal.SIGTERM]); |
| 392 | 390 |
| 393 /** | 391 /** |
| 394 * Returns the standard output stream of the process as a [:Stream:]. | 392 * Returns the standard output stream of the process as a [:Stream:]. |
| 395 */ | 393 */ |
| 396 Stream<List<int>> get stdout; | 394 Stream<List<int>> get stdout; |
| 397 | 395 |
| 398 /** | 396 /** |
| 399 * Returns the standard error stream of the process as a [:Stream:]. | 397 * Returns the standard error stream of the process as a [:Stream:]. |
| 400 */ | 398 */ |
| 401 Stream<List<int>> get stderr; | 399 Stream<List<int>> get stderr; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 421 * just terminates the process in a platform specific way, and the | 419 * just terminates the process in a platform specific way, and the |
| 422 * `signal` parameter is ignored. | 420 * `signal` parameter is ignored. |
| 423 * | 421 * |
| 424 * Returns `true` if the signal is successfully delivered to the | 422 * Returns `true` if the signal is successfully delivered to the |
| 425 * process. Otherwise the signal could not be sent, usually meaning | 423 * process. Otherwise the signal could not be sent, usually meaning |
| 426 * that the process is already dead. | 424 * that the process is already dead. |
| 427 */ | 425 */ |
| 428 bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]); | 426 bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]); |
| 429 } | 427 } |
| 430 | 428 |
| 431 | |
| 432 /** | 429 /** |
| 433 * [ProcessResult] represents the result of running a non-interactive | 430 * [ProcessResult] represents the result of running a non-interactive |
| 434 * process started with [Process.run] or [Process.runSync]. | 431 * process started with [Process.run] or [Process.runSync]. |
| 435 */ | 432 */ |
| 436 class ProcessResult { | 433 class ProcessResult { |
| 437 /** | 434 /** |
| 438 * Exit code for the process. | 435 * Exit code for the process. |
| 439 * | 436 * |
| 440 * See [Process.exitCode] for more information in the exit code | 437 * See [Process.exitCode] for more information in the exit code |
| 441 * value. | 438 * value. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 459 final stderr; | 456 final stderr; |
| 460 | 457 |
| 461 /** | 458 /** |
| 462 * Process id of the process. | 459 * Process id of the process. |
| 463 */ | 460 */ |
| 464 final int pid; | 461 final int pid; |
| 465 | 462 |
| 466 ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr); | 463 ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr); |
| 467 } | 464 } |
| 468 | 465 |
| 469 | |
| 470 /** | 466 /** |
| 471 * On Posix systems, [ProcessSignal] is used to send a specific signal | 467 * On Posix systems, [ProcessSignal] is used to send a specific signal |
| 472 * to a child process, see [:Process.kill:]. | 468 * to a child process, see [:Process.kill:]. |
| 473 * | 469 * |
| 474 * Some [ProcessSignal]s can also be watched, as a way to intercept the default | 470 * Some [ProcessSignal]s can also be watched, as a way to intercept the default |
| 475 * signal handler and implement another. See [ProcessSignal.watch] for more | 471 * signal handler and implement another. See [ProcessSignal.watch] for more |
| 476 * information. | 472 * information. |
| 477 */ | 473 */ |
| 478 class ProcessSignal { | 474 class ProcessSignal { |
| 479 static const ProcessSignal SIGHUP = const ProcessSignal._(1, "SIGHUP"); | 475 static const ProcessSignal SIGHUP = const ProcessSignal._(1, "SIGHUP"); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 * * [ProcessSignal.SIGWINCH]. Not available on Windows. | 522 * * [ProcessSignal.SIGWINCH]. Not available on Windows. |
| 527 * | 523 * |
| 528 * Other signals are disallowed, as they may be used by the VM. | 524 * Other signals are disallowed, as they may be used by the VM. |
| 529 * | 525 * |
| 530 * A signal can be watched multiple times, from multiple isolates, where all | 526 * A signal can be watched multiple times, from multiple isolates, where all |
| 531 * callbacks are invoked when signaled, in no specific order. | 527 * callbacks are invoked when signaled, in no specific order. |
| 532 */ | 528 */ |
| 533 Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this); | 529 Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this); |
| 534 } | 530 } |
| 535 | 531 |
| 536 | |
| 537 class SignalException implements IOException { | 532 class SignalException implements IOException { |
| 538 final String message; | 533 final String message; |
| 539 final osError; | 534 final osError; |
| 540 | 535 |
| 541 const SignalException(this.message, [this.osError = null]); | 536 const SignalException(this.message, [this.osError = null]); |
| 542 | 537 |
| 543 String toString() { | 538 String toString() { |
| 544 var msg = ""; | 539 var msg = ""; |
| 545 if (osError != null) { | 540 if (osError != null) { |
| 546 msg = ", osError: $osError"; | 541 msg = ", osError: $osError"; |
| 547 } | 542 } |
| 548 return "SignalException: $message$msg"; | 543 return "SignalException: $message$msg"; |
| 549 } | 544 } |
| 550 } | 545 } |
| 551 | 546 |
| 552 | |
| 553 class ProcessException implements IOException { | 547 class ProcessException implements IOException { |
| 554 /** | 548 /** |
| 555 * Contains the executable provided for the process. | 549 * Contains the executable provided for the process. |
| 556 */ | 550 */ |
| 557 final String executable; | 551 final String executable; |
| 558 | 552 |
| 559 /** | 553 /** |
| 560 * Contains the arguments provided for the process. | 554 * Contains the arguments provided for the process. |
| 561 */ | 555 */ |
| 562 final List<String> arguments; | 556 final List<String> arguments; |
| 563 | 557 |
| 564 /** | 558 /** |
| 565 * Contains the system message for the process exception if any. | 559 * Contains the system message for the process exception if any. |
| 566 */ | 560 */ |
| 567 final String message; | 561 final String message; |
| 568 | 562 |
| 569 /** | 563 /** |
| 570 * Contains the OS error code for the process exception if any. | 564 * Contains the OS error code for the process exception if any. |
| 571 */ | 565 */ |
| 572 final int errorCode; | 566 final int errorCode; |
| 573 | 567 |
| 574 const ProcessException(this.executable, this.arguments, [this.message = "", | 568 const ProcessException(this.executable, this.arguments, |
| 575 this.errorCode = 0]); | 569 [this.message = "", this.errorCode = 0]); |
| 576 String toString() { | 570 String toString() { |
| 577 var msg = (message == null) ? 'OS error code: $errorCode' : message; | 571 var msg = (message == null) ? 'OS error code: $errorCode' : message; |
| 578 var args = arguments.join(' '); | 572 var args = arguments.join(' '); |
| 579 return "ProcessException: $msg\n Command: $executable $args"; | 573 return "ProcessException: $msg\n Command: $executable $args"; |
| 580 } | 574 } |
| 581 } | 575 } |
| OLD | NEW |