OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 part of dart.io; |
| 6 |
| 7 // TODO(ager): The only reason for this class is that we |
| 8 // cannot patch a top-level at this point. |
| 9 class _ProcessUtils { |
| 10 external static void _exit(int status); |
| 11 external static void _setExitCode(int status); |
| 12 external static int _getExitCode(); |
| 13 external static void _sleep(int millis); |
| 14 external static int _pid(Process process); |
| 15 external static Stream<ProcessSignal> _watchSignal(ProcessSignal signal); |
| 16 } |
| 17 |
| 18 /** |
| 19 * Exit the Dart VM process immediately with the given exit code. |
| 20 * |
| 21 * This does not wait for any asynchronous operations to terminate. Using |
| 22 * [exit] is therefore very likely to lose data. |
| 23 * |
| 24 * The handling of exit codes is platform specific. |
| 25 * |
| 26 * On Linux and OS X an exit code for normal termination will always |
| 27 * be in the range [0..255]. If an exit code outside this range is |
| 28 * set the actual exit code will be the lower 8 bits masked off and |
| 29 * treated as an unsigned value. E.g. using an exit code of -1 will |
| 30 * result in an actual exit code of 255 being reported. |
| 31 * |
| 32 * On Windows the exit code can be set to any 32-bit value. However |
| 33 * some of these values are reserved for reporting system errors like |
| 34 * crashes. |
| 35 * |
| 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 |
| 38 * reporting runtime error (unhandled exception). |
| 39 * |
| 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 |
| 42 * program to the surrounding environment. This will avoid any |
| 43 * cross-platform issues. |
| 44 */ |
| 45 void exit(int code) { |
| 46 if (code is !int) { |
| 47 throw new ArgumentError("Integer value for exit code expected"); |
| 48 } |
| 49 _ProcessUtils._exit(code); |
| 50 } |
| 51 |
| 52 /** |
| 53 * Set the global exit code for the Dart VM. |
| 54 * |
| 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 |
| 57 * on normal termination. |
| 58 * |
| 59 * Default value is `0`. |
| 60 * |
| 61 * See [exit] for more information on how to chose a value for the |
| 62 * exit code. |
| 63 */ |
| 64 void set exitCode(int code) { |
| 65 if (code is !int) { |
| 66 throw new ArgumentError("Integer value for exit code expected"); |
| 67 } |
| 68 _ProcessUtils._setExitCode(code); |
| 69 } |
| 70 |
| 71 /** |
| 72 * Get the global exit code for the Dart VM. |
| 73 * |
| 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 |
| 76 * on normal termination. |
| 77 * |
| 78 * See [exit] for more information on how to chose a value for the |
| 79 * exit code. |
| 80 */ |
| 81 int get exitCode => _ProcessUtils._getExitCode(); |
| 82 |
| 83 /** |
| 84 * Sleep for the duration specified in [duration]. |
| 85 * |
| 86 * Use this with care, as no asynchronous operations can be processed |
| 87 * in a isolate while it is blocked in a [sleep] call. |
| 88 */ |
| 89 void sleep(Duration duration) { |
| 90 int milliseconds = duration.inMilliseconds; |
| 91 if (milliseconds < 0) { |
| 92 throw new ArgumentError("sleep: duration cannot be negative"); |
| 93 } |
| 94 _ProcessUtils._sleep(milliseconds); |
| 95 } |
| 96 |
| 97 /** |
| 98 * Returns the PID of the current process. |
| 99 */ |
| 100 int get pid => _ProcessUtils._pid(null); |
| 101 |
| 102 /** |
| 103 * Modes for running a new process. |
| 104 */ |
| 105 enum ProcessStartMode { |
| 106 /// Normal child process. |
| 107 NORMAL, |
| 108 /// Detached child process with no open communication channel. |
| 109 DETACHED, |
| 110 /// Detached child process with stdin, stdout and stderr still open |
| 111 /// for communication with the child. |
| 112 DETACHED_WITH_STDIO |
| 113 } |
| 114 |
| 115 /** |
| 116 * The means to execute a program. |
| 117 * |
| 118 * Use the static [start] and [run] methods to start a new process. |
| 119 * The run method executes the process non-interactively to completion. |
| 120 * In contrast, the start method allows your code to interact with the |
| 121 * running process. |
| 122 * |
| 123 * ## Start a process with the run method |
| 124 * |
| 125 * The following code sample uses the run method to create a process |
| 126 * that runs the UNIX command `ls`, which lists the contents of a directory. |
| 127 * The run method completes with a [ProcessResult] object when the process |
| 128 * terminates. This provides access to the output and exit code from the |
| 129 * process. The run method does not return a Process object; this prevents your |
| 130 * code from interacting with the running process. |
| 131 * |
| 132 * import 'dart:io'; |
| 133 * |
| 134 * main() { |
| 135 * // List all files in the current directory in UNIX-like systems. |
| 136 * Process.run('ls', ['-l']).then((ProcessResult results) { |
| 137 * print(results.stdout); |
| 138 * }); |
| 139 * } |
| 140 * |
| 141 * ## Start a process with the start method |
| 142 * |
| 143 * The following example uses start to create the process. |
| 144 * The start method returns a [Future] for a Process object. |
| 145 * When the future completes the process is started and |
| 146 * your code can interact with the |
| 147 * Process: writing to stdin, listening to stdout, and so on. |
| 148 * |
| 149 * The following sample starts the UNIX `cat` utility, which when given no |
| 150 * command-line arguments, echos its input. |
| 151 * The program writes to the process's standard input stream |
| 152 * and prints data from its standard output stream. |
| 153 * |
| 154 * import 'dart:io'; |
| 155 * import 'dart:convert'; |
| 156 * |
| 157 * main() { |
| 158 * Process.start('cat', []).then((Process process) { |
| 159 * process.stdout |
| 160 * .transform(UTF8.decoder) |
| 161 * .listen((data) { print(data); }); |
| 162 * process.stdin.writeln('Hello, world!'); |
| 163 * process.stdin.writeln('Hello, galaxy!'); |
| 164 * process.stdin.writeln('Hello, universe!'); |
| 165 * }); |
| 166 * } |
| 167 * |
| 168 * ## Standard I/O streams |
| 169 * |
| 170 * As seen in the previous code sample, you can interact with the Process's |
| 171 * standard output stream through the getter [stdout], |
| 172 * and you can interact with the Process's standard input stream through |
| 173 * the getter [stdin]. |
| 174 * In addition, Process provides a getter [stderr] for using the Process's |
| 175 * standard error stream. |
| 176 * |
| 177 * A Process's streams are distinct from the top-level streams |
| 178 * for the current program. |
| 179 * |
| 180 * ## Exit codes |
| 181 * |
| 182 * Call the [exitCode] method to get the exit code of the process. |
| 183 * The exit code indicates whether the program terminated successfully |
| 184 * (usually indicated with an exit code of 0) or with an error. |
| 185 * |
| 186 * If the start method is used, the exitCode is available through a future |
| 187 * on the Process object (as shown in the example below). |
| 188 * If the run method is used, the exitCode is available |
| 189 * through a getter on the ProcessResult instance. |
| 190 * |
| 191 * import 'dart:io'; |
| 192 * |
| 193 * main() { |
| 194 * Process.start('ls', ['-l']).then((process) { |
| 195 * // Get the exit code from the new process. |
| 196 * process.exitCode.then((exitCode) { |
| 197 * print('exit code: $exitCode'); |
| 198 * }); |
| 199 * }); |
| 200 * } |
| 201 * |
| 202 * ## Other resources |
| 203 * |
| 204 * [Dart by Example](https://www.dartlang.org/dart-by-example/#dart-io-and-comma
nd-line-apps) |
| 205 * provides additional task-oriented code samples that show how to use |
| 206 * various API from the [dart:io] library. |
| 207 */ |
| 208 abstract class Process { |
| 209 /** |
| 210 * Returns a [:Future:] which completes with the exit code of the process |
| 211 * when the process completes. |
| 212 * |
| 213 * The handling of exit codes is platform specific. |
| 214 * |
| 215 * On Linux and OS X a normal exit code will be a positive value in |
| 216 * the range [0..255]. If the process was terminated due to a signal |
| 217 * the exit code will be a negative value in the range [-255..-1], |
| 218 * where the absolute value of the exit code is the signal |
| 219 * number. For example, if a process crashes due to a segmentation |
| 220 * violation the exit code will be -11, as the signal SIGSEGV has the |
| 221 * number 11. |
| 222 * |
| 223 * On Windows a process can report any 32-bit value as an exit |
| 224 * code. When returning the exit code this exit code is turned into |
| 225 * a signed value. Some special values are used to report |
| 226 * termination due to some system event. E.g. if a process crashes |
| 227 * due to an access violation the 32-bit exit code is `0xc0000005`, |
| 228 * which will be returned as the negative number `-1073741819`. To |
| 229 * get the original 32-bit value use `(0x100000000 + exitCode) & |
| 230 * 0xffffffff`. |
| 231 */ |
| 232 Future<int> exitCode; |
| 233 |
| 234 /** |
| 235 * Starts a process running the [executable] with the specified |
| 236 * [arguments]. Returns a [:Future<Process>:] that completes with a |
| 237 * Process instance when the process has been successfully |
| 238 * started. That [Process] object can be used to interact with the |
| 239 * process. If the process cannot be started the returned [Future] |
| 240 * completes with an exception. |
| 241 * |
| 242 * Use [workingDirectory] to set the working directory for the process. Note |
| 243 * that the change of directory occurs before executing the process on some |
| 244 * platforms, which may have impact when using relative paths for the |
| 245 * executable and the arguments. |
| 246 * |
| 247 * Use [environment] to set the environment variables for the process. If not |
| 248 * set the environment of the parent process is inherited. Currently, only |
| 249 * US-ASCII environment variables are supported and errors are likely to occur |
| 250 * if an environment variable with code-points outside the US-ASCII range is |
| 251 * passed in. |
| 252 * |
| 253 * If [includeParentEnvironment] is `true`, the process's environment will |
| 254 * include the parent process's environment, with [environment] taking |
| 255 * precedence. Default is `true`. |
| 256 * |
| 257 * If [runInShell] is `true`, the process will be spawned through a system |
| 258 * shell. On Linux and OS X, [:/bin/sh:] is used, while |
| 259 * [:%WINDIR%\system32\cmd.exe:] is used on Windows. |
| 260 * |
| 261 * Users must read all data coming on the [stdout] and [stderr] |
| 262 * streams of processes started with [:Process.start:]. If the user |
| 263 * does not read all data on the streams the underlying system |
| 264 * resources will not be released since there is still pending data. |
| 265 * |
| 266 * The following code uses `Process.start` to grep for `main` in the |
| 267 * file `test.dart` on Linux. |
| 268 * |
| 269 * Process.start('grep', ['-i', 'main', 'test.dart']).then((process) { |
| 270 * stdout.addStream(process.stdout); |
| 271 * stderr.addStream(process.stderr); |
| 272 * }); |
| 273 * |
| 274 * If [mode] is [ProcessStartMode.NORMAL] (the default) a child |
| 275 * process will be started with `stdin`, `stdout` and `stderr` |
| 276 * connected. |
| 277 * |
| 278 * If `mode` is [ProcessStartMode.DETACHED] a detached process will |
| 279 * be created. A detached process has no connection to its parent, |
| 280 * and can keep running on its own when the parent dies. The only |
| 281 * information available from a detached process is its `pid`. There |
| 282 * is no connection to its `stdin`, `stdout` or `stderr`, nor will |
| 283 * the process' exit code become available when it terminates. |
| 284 * |
| 285 * If `mode` is [ProcessStartMode.DETACHED_WITH_STDIO] a detached |
| 286 * process will be created where the `stdin`, `stdout` and `stderr` |
| 287 * are connected. The creator can communicate with the child through |
| 288 * these. The detached process will keep running even if these |
| 289 * communication channels are closed. The process' exit code will |
| 290 * not become available when it terminated. |
| 291 * |
| 292 * The default value for `mode` is `ProcessStartMode.NORMAL`. |
| 293 */ |
| 294 external static Future<Process> start( |
| 295 String executable, |
| 296 List<String> arguments, |
| 297 {String workingDirectory, |
| 298 Map<String, String> environment, |
| 299 bool includeParentEnvironment: true, |
| 300 bool runInShell: false, |
| 301 ProcessStartMode mode: ProcessStartMode.NORMAL}); |
| 302 |
| 303 /** |
| 304 * Starts a process and runs it non-interactively to completion. The |
| 305 * process run is [executable] with the specified [arguments]. |
| 306 * |
| 307 * 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 * platforms, which may have impact when using relative paths for the |
| 310 * executable and the arguments. |
| 311 * |
| 312 * Use [environment] to set the environment variables for the process. If not |
| 313 * set the environment of the parent process is inherited. Currently, only |
| 314 * US-ASCII environment variables are supported and errors are likely to occur |
| 315 * if an environment variable with code-points outside the US-ASCII range is |
| 316 * passed in. |
| 317 * |
| 318 * If [includeParentEnvironment] is `true`, the process's environment will |
| 319 * include the parent process's environment, with [environment] taking |
| 320 * precedence. Default is `true`. |
| 321 * |
| 322 * If [runInShell] is true, the process will be spawned through a system |
| 323 * shell. On Linux and OS X, `/bin/sh` is used, while |
| 324 * `%WINDIR%\system32\cmd.exe` is used on Windows. |
| 325 * |
| 326 * The encoding used for decoding `stdout` and `stderr` into text is |
| 327 * controlled through [stdoutEncoding] and [stderrEncoding]. The |
| 328 * default encoding is [SYSTEM_ENCODING]. If `null` is used no |
| 329 * decoding will happen and the [ProcessResult] will hold binary |
| 330 * data. |
| 331 * |
| 332 * Returns a `Future<ProcessResult>` that completes with the |
| 333 * result of running the process, i.e., exit code, standard out and |
| 334 * standard in. |
| 335 * |
| 336 * The following code uses `Process.run` to grep for `main` in the |
| 337 * file `test.dart` on Linux. |
| 338 * |
| 339 * Process.run('grep', ['-i', 'main', 'test.dart']).then((result) { |
| 340 * stdout.write(result.stdout); |
| 341 * stderr.write(result.stderr); |
| 342 * }); |
| 343 */ |
| 344 external static Future<ProcessResult> run( |
| 345 String executable, |
| 346 List<String> arguments, |
| 347 {String workingDirectory, |
| 348 Map<String, String> environment, |
| 349 bool includeParentEnvironment: true, |
| 350 bool runInShell: false, |
| 351 Encoding stdoutEncoding: SYSTEM_ENCODING, |
| 352 Encoding stderrEncoding: SYSTEM_ENCODING}); |
| 353 |
| 354 |
| 355 /** |
| 356 * Starts a process and runs it to completion. This is a synchronous |
| 357 * call and will block until the child process terminates. |
| 358 * |
| 359 * The arguments are the same as for `Process.run`. |
| 360 * |
| 361 * Returns a `ProcessResult` with the result of running the process, |
| 362 * i.e., exit code, standard out and standard in. |
| 363 */ |
| 364 external static ProcessResult runSync( |
| 365 String executable, |
| 366 List<String> arguments, |
| 367 {String workingDirectory, |
| 368 Map<String, String> environment, |
| 369 bool includeParentEnvironment: true, |
| 370 bool runInShell: false, |
| 371 Encoding stdoutEncoding: SYSTEM_ENCODING, |
| 372 Encoding stderrEncoding: SYSTEM_ENCODING}); |
| 373 |
| 374 /** |
| 375 * Kills the process with id [pid]. |
| 376 * |
| 377 * Where possible, sends the [signal] to the process with id |
| 378 * `pid`. This includes Linux and OS X. The default signal is |
| 379 * [ProcessSignal.SIGTERM] which will normally terminate the |
| 380 * process. |
| 381 * |
| 382 * On platforms without signal support, including Windows, the call |
| 383 * just terminates the process with id `pid` in a platform specific |
| 384 * way, and the `signal` parameter is ignored. |
| 385 * |
| 386 * Returns `true` if the signal is successfully delivered to the |
| 387 * process. Otherwise the signal could not be sent, usually meaning |
| 388 * that the process is already dead. |
| 389 */ |
| 390 external static bool killPid( |
| 391 int pid, [ProcessSignal signal = ProcessSignal.SIGTERM]); |
| 392 |
| 393 /** |
| 394 * Returns the standard output stream of the process as a [:Stream:]. |
| 395 */ |
| 396 Stream<List<int>> get stdout; |
| 397 |
| 398 /** |
| 399 * Returns the standard error stream of the process as a [:Stream:]. |
| 400 */ |
| 401 Stream<List<int>> get stderr; |
| 402 |
| 403 /** |
| 404 * Returns the standard input stream of the process as an [IOSink]. |
| 405 */ |
| 406 IOSink get stdin; |
| 407 |
| 408 /** |
| 409 * Returns the process id of the process. |
| 410 */ |
| 411 int get pid; |
| 412 |
| 413 /** |
| 414 * Kills the process. |
| 415 * |
| 416 * Where possible, sends the [signal] to the process. This includes |
| 417 * Linux and OS X. The default signal is [ProcessSignal.SIGTERM] |
| 418 * which will normally terminate the process. |
| 419 * |
| 420 * On platforms without signal support, including Windows, the call |
| 421 * just terminates the process in a platform specific way, and the |
| 422 * `signal` parameter is ignored. |
| 423 * |
| 424 * Returns `true` if the signal is successfully delivered to the |
| 425 * process. Otherwise the signal could not be sent, usually meaning |
| 426 * that the process is already dead. |
| 427 */ |
| 428 bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]); |
| 429 } |
| 430 |
| 431 |
| 432 /** |
| 433 * [ProcessResult] represents the result of running a non-interactive |
| 434 * process started with [Process.run] or [Process.runSync]. |
| 435 */ |
| 436 class ProcessResult { |
| 437 /** |
| 438 * Exit code for the process. |
| 439 * |
| 440 * See [Process.exitCode] for more information in the exit code |
| 441 * value. |
| 442 */ |
| 443 final int exitCode; |
| 444 |
| 445 /** |
| 446 * Standard output from the process. The value used for the |
| 447 * `stdoutEncoding` argument to `Process.run` determines the type. If |
| 448 * `null` was used this value is of type `List<int> otherwise it is |
| 449 * of type `String`. |
| 450 */ |
| 451 final stdout; |
| 452 |
| 453 /** |
| 454 * Standard error from the process. The value used for the |
| 455 * `stderrEncoding` argument to `Process.run` determines the type. If |
| 456 * `null` was used this value is of type `List<int> |
| 457 * otherwise it is of type `String`. |
| 458 */ |
| 459 final stderr; |
| 460 |
| 461 /** |
| 462 * Process id of the process. |
| 463 */ |
| 464 final int pid; |
| 465 |
| 466 ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr); |
| 467 } |
| 468 |
| 469 |
| 470 /** |
| 471 * On Posix systems, [ProcessSignal] is used to send a specific signal |
| 472 * to a child process, see [:Process.kill:]. |
| 473 * |
| 474 * 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 |
| 476 * information. |
| 477 */ |
| 478 class ProcessSignal { |
| 479 static const ProcessSignal SIGHUP = const ProcessSignal._(1, "SIGHUP"); |
| 480 static const ProcessSignal SIGINT = const ProcessSignal._(2, "SIGINT"); |
| 481 static const ProcessSignal SIGQUIT = const ProcessSignal._(3, "SIGQUIT"); |
| 482 static const ProcessSignal SIGILL = const ProcessSignal._(4, "SIGILL"); |
| 483 static const ProcessSignal SIGTRAP = const ProcessSignal._(5, "SIGTRAP"); |
| 484 static const ProcessSignal SIGABRT = const ProcessSignal._(6, "SIGABRT"); |
| 485 static const ProcessSignal SIGBUS = const ProcessSignal._(7, "SIGBUS"); |
| 486 static const ProcessSignal SIGFPE = const ProcessSignal._(8, "SIGFPE"); |
| 487 static const ProcessSignal SIGKILL = const ProcessSignal._(9, "SIGKILL"); |
| 488 static const ProcessSignal SIGUSR1 = const ProcessSignal._(10, "SIGUSR1"); |
| 489 static const ProcessSignal SIGSEGV = const ProcessSignal._(11, "SIGSEGV"); |
| 490 static const ProcessSignal SIGUSR2 = const ProcessSignal._(12, "SIGUSR2"); |
| 491 static const ProcessSignal SIGPIPE = const ProcessSignal._(13, "SIGPIPE"); |
| 492 static const ProcessSignal SIGALRM = const ProcessSignal._(14, "SIGALRM"); |
| 493 static const ProcessSignal SIGTERM = const ProcessSignal._(15, "SIGTERM"); |
| 494 static const ProcessSignal SIGCHLD = const ProcessSignal._(17, "SIGCHLD"); |
| 495 static const ProcessSignal SIGCONT = const ProcessSignal._(18, "SIGCONT"); |
| 496 static const ProcessSignal SIGSTOP = const ProcessSignal._(19, "SIGSTOP"); |
| 497 static const ProcessSignal SIGTSTP = const ProcessSignal._(20, "SIGTSTP"); |
| 498 static const ProcessSignal SIGTTIN = const ProcessSignal._(21, "SIGTTIN"); |
| 499 static const ProcessSignal SIGTTOU = const ProcessSignal._(22, "SIGTTOU"); |
| 500 static const ProcessSignal SIGURG = const ProcessSignal._(23, "SIGURG"); |
| 501 static const ProcessSignal SIGXCPU = const ProcessSignal._(24, "SIGXCPU"); |
| 502 static const ProcessSignal SIGXFSZ = const ProcessSignal._(25, "SIGXFSZ"); |
| 503 static const ProcessSignal SIGVTALRM = const ProcessSignal._(26, "SIGVTALRM"); |
| 504 static const ProcessSignal SIGPROF = const ProcessSignal._(27, "SIGPROF"); |
| 505 static const ProcessSignal SIGWINCH = const ProcessSignal._(28, "SIGWINCH"); |
| 506 static const ProcessSignal SIGPOLL = const ProcessSignal._(29, "SIGPOLL"); |
| 507 static const ProcessSignal SIGSYS = const ProcessSignal._(31, "SIGSYS"); |
| 508 |
| 509 final int _signalNumber; |
| 510 final String _name; |
| 511 |
| 512 const ProcessSignal._(this._signalNumber, this._name); |
| 513 |
| 514 String toString() => _name; |
| 515 |
| 516 /** |
| 517 * Watch for process signals. |
| 518 * |
| 519 * The following [ProcessSignal]s can be listened to: |
| 520 * |
| 521 * * [ProcessSignal.SIGHUP]. |
| 522 * * [ProcessSignal.SIGINT]. Signal sent by e.g. CTRL-C. |
| 523 * * [ProcessSignal.SIGTERM]. Not available on Windows. |
| 524 * * [ProcessSignal.SIGUSR1]. Not available on Windows. |
| 525 * * [ProcessSignal.SIGUSR2]. Not available on Windows. |
| 526 * * [ProcessSignal.SIGWINCH]. Not available on Windows. |
| 527 * |
| 528 * Other signals are disallowed, as they may be used by the VM. |
| 529 * |
| 530 * A signal can be watched multiple times, from multiple isolates, where all |
| 531 * callbacks are invoked when signaled, in no specific order. |
| 532 */ |
| 533 Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this); |
| 534 } |
| 535 |
| 536 |
| 537 class SignalException implements IOException { |
| 538 final String message; |
| 539 final osError; |
| 540 |
| 541 const SignalException(this.message, [this.osError = null]); |
| 542 |
| 543 String toString() { |
| 544 var msg = ""; |
| 545 if (osError != null) { |
| 546 msg = ", osError: $osError"; |
| 547 } |
| 548 return "SignalException: $message$msg"; |
| 549 } |
| 550 } |
| 551 |
| 552 |
| 553 class ProcessException implements IOException { |
| 554 /** |
| 555 * Contains the executable provided for the process. |
| 556 */ |
| 557 final String executable; |
| 558 |
| 559 /** |
| 560 * Contains the arguments provided for the process. |
| 561 */ |
| 562 final List<String> arguments; |
| 563 |
| 564 /** |
| 565 * Contains the system message for the process exception if any. |
| 566 */ |
| 567 final String message; |
| 568 |
| 569 /** |
| 570 * Contains the OS error code for the process exception if any. |
| 571 */ |
| 572 final int errorCode; |
| 573 |
| 574 const ProcessException(this.executable, this.arguments, [this.message = "", |
| 575 this.errorCode = 0]); |
| 576 String toString() { |
| 577 var msg = (message == null) ? 'OS error code: $errorCode' : message; |
| 578 var args = arguments.join(' '); |
| 579 return "ProcessException: $msg\n Command: $executable $args"; |
| 580 } |
| 581 } |
OLD | NEW |