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 |