| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** | 5 /** |
| 6 * Helper functionality to make working with IO easier. | 6 * Helper functionality to make working with IO easier. |
| 7 */ | 7 */ |
| 8 library io; | 8 library io; |
| 9 | 9 |
| 10 import 'dart:io'; | 10 import 'dart:io'; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 | 156 |
| 157 var completer = new Completer<File>(); | 157 var completer = new Completer<File>(); |
| 158 var file = new File(path); | 158 var file = new File(path); |
| 159 var outputStream = file.openOutputStream(); | 159 var outputStream = file.openOutputStream(); |
| 160 stream.pipe(outputStream); | 160 stream.pipe(outputStream); |
| 161 | 161 |
| 162 outputStream.onClosed = () { | 162 outputStream.onClosed = () { |
| 163 completer.complete(file); | 163 completer.complete(file); |
| 164 }; | 164 }; |
| 165 | 165 |
| 166 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 167 var stackTrace; |
| 168 try { |
| 169 throw null; |
| 170 } catch (_, localStackTrace) { |
| 171 stackTrace = localStackTrace; |
| 172 } |
| 173 |
| 166 completeError(error) { | 174 completeError(error) { |
| 167 if (!completer.isComplete) completer.completeException(error); | 175 if (!completer.isComplete) completer.completeException(error, stackTrace); |
| 168 } | 176 } |
| 169 | 177 |
| 170 stream.onError = completeError; | 178 stream.onError = completeError; |
| 171 outputStream.onError = completeError; | 179 outputStream.onError = completeError; |
| 172 | 180 |
| 173 return completer.future; | 181 return completer.future; |
| 174 } | 182 } |
| 175 | 183 |
| 176 /** | 184 /** |
| 177 * Creates a directory [dir]. Returns a [Future] that completes when the | 185 * Creates a directory [dir]. Returns a [Future] that completes when the |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 | 252 |
| 245 dir = _getDirectory(dir); | 253 dir = _getDirectory(dir); |
| 246 var lister = dir.list(recursive: recursive); | 254 var lister = dir.list(recursive: recursive); |
| 247 | 255 |
| 248 lister.onDone = (done) { | 256 lister.onDone = (done) { |
| 249 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile | 257 // TODO(rnystrom): May need to sort here if it turns out onDir and onFile |
| 250 // aren't guaranteed to be called in a certain order. So far, they seem to. | 258 // aren't guaranteed to be called in a certain order. So far, they seem to. |
| 251 if (done) completer.complete(contents); | 259 if (done) completer.complete(contents); |
| 252 }; | 260 }; |
| 253 | 261 |
| 254 lister.onError = (error) => completer.completeException(error); | 262 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 263 var stackTrace; |
| 264 try { |
| 265 throw null; |
| 266 } catch (_, localStackTrace) { |
| 267 stackTrace = localStackTrace; |
| 268 } |
| 269 |
| 270 lister.onError = (error) => completer.completeException(error, stackTrace); |
| 255 lister.onDir = (file) => contents.add(file); | 271 lister.onDir = (file) => contents.add(file); |
| 256 lister.onFile = (file) { | 272 lister.onFile = (file) { |
| 257 if (!includeHiddenFiles && basename(file).startsWith('.')) return; | 273 if (!includeHiddenFiles && basename(file).startsWith('.')) return; |
| 258 contents.add(file); | 274 contents.add(file); |
| 259 }; | 275 }; |
| 260 | 276 |
| 261 return completer.future; | 277 return completer.future; |
| 262 } | 278 } |
| 263 | 279 |
| 264 /** | 280 /** |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 /// A [StringInputStream] passed to this should have no callbacks registered. | 408 /// A [StringInputStream] passed to this should have no callbacks registered. |
| 393 Future<String> readLine([StringInputStream stream]) { | 409 Future<String> readLine([StringInputStream stream]) { |
| 394 if (stream == null) stream = _stringStdin; | 410 if (stream == null) stream = _stringStdin; |
| 395 if (stream.closed) return new Future.immediate(''); | 411 if (stream.closed) return new Future.immediate(''); |
| 396 void removeCallbacks() { | 412 void removeCallbacks() { |
| 397 stream.onClosed = null; | 413 stream.onClosed = null; |
| 398 stream.onLine = null; | 414 stream.onLine = null; |
| 399 stream.onError = null; | 415 stream.onError = null; |
| 400 } | 416 } |
| 401 | 417 |
| 418 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 419 var stackTrace; |
| 420 try { |
| 421 throw null; |
| 422 } catch (_, localStackTrace) { |
| 423 stackTrace = localStackTrace; |
| 424 } |
| 425 |
| 402 var completer = new Completer(); | 426 var completer = new Completer(); |
| 403 stream.onClosed = () { | 427 stream.onClosed = () { |
| 404 removeCallbacks(); | 428 removeCallbacks(); |
| 405 completer.complete(''); | 429 completer.complete(''); |
| 406 }; | 430 }; |
| 407 | 431 |
| 408 stream.onLine = () { | 432 stream.onLine = () { |
| 409 removeCallbacks(); | 433 removeCallbacks(); |
| 410 completer.complete(stream.readLine()); | 434 completer.complete(stream.readLine()); |
| 411 }; | 435 }; |
| 412 | 436 |
| 413 stream.onError = (e) { | 437 stream.onError = (e) { |
| 414 removeCallbacks(); | 438 removeCallbacks(); |
| 415 completer.completeException(e); | 439 completer.completeException(e, stackTrace); |
| 416 }; | 440 }; |
| 417 | 441 |
| 418 return completer.future; | 442 return completer.future; |
| 419 } | 443 } |
| 420 | 444 |
| 421 // TODO(nweiz): make this configurable | 445 // TODO(nweiz): make this configurable |
| 422 /** | 446 /** |
| 423 * The amount of time in milliseconds to allow HTTP requests before assuming | 447 * The amount of time in milliseconds to allow HTTP requests before assuming |
| 424 * they've failed. | 448 * they've failed. |
| 425 */ | 449 */ |
| 426 final HTTP_TIMEOUT = 30 * 1000; | 450 final HTTP_TIMEOUT = 30 * 1000; |
| 427 | 451 |
| 428 /** | 452 /** |
| 429 * Opens an input stream for a HTTP GET request to [uri], which may be a | 453 * Opens an input stream for a HTTP GET request to [uri], which may be a |
| 430 * [String] or [Uri]. | 454 * [String] or [Uri]. |
| 431 * | 455 * |
| 432 * Callers should be sure to use [timeout] to make sure that the HTTP request | 456 * Callers should be sure to use [timeout] to make sure that the HTTP request |
| 433 * doesn't last indefinitely | 457 * doesn't last indefinitely |
| 434 */ | 458 */ |
| 435 Future<InputStream> httpGet(uri) { | 459 Future<InputStream> httpGet(uri) { |
| 436 // TODO(nweiz): This could return an InputStream synchronously if issue 3657 | 460 // TODO(nweiz): This could return an InputStream synchronously if issue 3657 |
| 437 // were fixed and errors could be propagated through it. Then we could also | 461 // were fixed and errors could be propagated through it. Then we could also |
| 438 // automatically attach a timeout to that stream. | 462 // automatically attach a timeout to that stream. |
| 439 uri = _getUri(uri); | 463 uri = _getUri(uri); |
| 440 | 464 |
| 441 var completer = new Completer<InputStream>(); | 465 var completer = new Completer<InputStream>(); |
| 442 var client = new HttpClient(); | 466 var client = new HttpClient(); |
| 443 var connection = client.getUrl(uri); | 467 var connection = client.getUrl(uri); |
| 444 | 468 |
| 469 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 470 var stackTrace; |
| 471 try { |
| 472 throw null; |
| 473 } catch (_, localStackTrace) { |
| 474 stackTrace = localStackTrace; |
| 475 } |
| 476 |
| 445 connection.onError = (e) { | 477 connection.onError = (e) { |
| 446 // Show a friendly error if the URL couldn't be resolved. | 478 // Show a friendly error if the URL couldn't be resolved. |
| 447 if (e is SocketIOException && | 479 if (e is SocketIOException && |
| 448 e.osError != null && | 480 e.osError != null && |
| 449 (e.osError.errorCode == 8 || | 481 (e.osError.errorCode == 8 || |
| 450 e.osError.errorCode == -2 || | 482 e.osError.errorCode == -2 || |
| 451 e.osError.errorCode == -5 || | 483 e.osError.errorCode == -5 || |
| 452 e.osError.errorCode == 11004)) { | 484 e.osError.errorCode == 11004)) { |
| 453 e = 'Could not resolve URL "${uri.origin}".'; | 485 e = 'Could not resolve URL "${uri.origin}".'; |
| 454 } | 486 } |
| 455 | 487 |
| 456 client.shutdown(); | 488 client.shutdown(); |
| 457 completer.completeException(e); | 489 completer.completeException(e, stackTrace); |
| 458 }; | 490 }; |
| 459 | 491 |
| 460 connection.onResponse = (response) { | 492 connection.onResponse = (response) { |
| 461 if (response.statusCode >= 400) { | 493 if (response.statusCode >= 400) { |
| 462 client.shutdown(); | 494 client.shutdown(); |
| 463 completer.completeException( | 495 completer.completeException( |
| 464 new PubHttpException(response.statusCode, response.reasonPhrase)); | 496 new PubHttpException(response.statusCode, response.reasonPhrase), |
| 497 stackTrace); |
| 465 return; | 498 return; |
| 466 } | 499 } |
| 467 | 500 |
| 468 completer.complete(response.inputStream); | 501 completer.complete(response.inputStream); |
| 469 }; | 502 }; |
| 470 | 503 |
| 471 return completer.future; | 504 return completer.future; |
| 472 } | 505 } |
| 473 | 506 |
| 474 /** | 507 /** |
| (...skipping 22 matching lines...) Expand all Loading... |
| 497 source.onError = (e) { throw e; }; | 530 source.onError = (e) { throw e; }; |
| 498 return completer.future; | 531 return completer.future; |
| 499 } | 532 } |
| 500 | 533 |
| 501 /** | 534 /** |
| 502 * Buffers all input from an InputStream and returns it as a future. | 535 * Buffers all input from an InputStream and returns it as a future. |
| 503 */ | 536 */ |
| 504 Future<List<int>> consumeInputStream(InputStream stream) { | 537 Future<List<int>> consumeInputStream(InputStream stream) { |
| 505 if (stream.closed) return new Future.immediate(<int>[]); | 538 if (stream.closed) return new Future.immediate(<int>[]); |
| 506 | 539 |
| 540 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 541 var stackTrace; |
| 542 try { |
| 543 throw null; |
| 544 } catch (_, localStackTrace) { |
| 545 stackTrace = localStackTrace; |
| 546 } |
| 547 |
| 507 var completer = new Completer<List<int>>(); | 548 var completer = new Completer<List<int>>(); |
| 508 var buffer = <int>[]; | 549 var buffer = <int>[]; |
| 509 stream.onClosed = () => completer.complete(buffer); | 550 stream.onClosed = () => completer.complete(buffer); |
| 510 stream.onData = () => buffer.addAll(stream.read()); | 551 stream.onData = () => buffer.addAll(stream.read()); |
| 511 stream.onError = (e) => completer.completeException(e); | 552 stream.onError = (e) => completer.completeException(e, stackTrace); |
| 512 return completer.future; | 553 return completer.future; |
| 513 } | 554 } |
| 514 | 555 |
| 515 /// Buffers all input from a StringInputStream and returns it as a future. | 556 /// Buffers all input from a StringInputStream and returns it as a future. |
| 516 Future<String> consumeStringInputStream(StringInputStream stream) { | 557 Future<String> consumeStringInputStream(StringInputStream stream) { |
| 517 if (stream.closed) return new Future.immediate(''); | 558 if (stream.closed) return new Future.immediate(''); |
| 518 | 559 |
| 560 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 561 var stackTrace; |
| 562 try { |
| 563 throw null; |
| 564 } catch (_, localStackTrace) { |
| 565 stackTrace = localStackTrace; |
| 566 } |
| 567 |
| 519 var completer = new Completer<String>(); | 568 var completer = new Completer<String>(); |
| 520 var buffer = new StringBuffer(); | 569 var buffer = new StringBuffer(); |
| 521 stream.onClosed = () => completer.complete(buffer.toString()); | 570 stream.onClosed = () => completer.complete(buffer.toString()); |
| 522 stream.onData = () => buffer.add(stream.read()); | 571 stream.onData = () => buffer.add(stream.read()); |
| 523 stream.onError = (e) => completer.completeException(e); | 572 stream.onError = (e) => completer.completeException(e, stackTrace); |
| 524 return completer.future; | 573 return completer.future; |
| 525 } | 574 } |
| 526 | 575 |
| 527 /// Spawns and runs the process located at [executable], passing in [args]. | 576 /// Spawns and runs the process located at [executable], passing in [args]. |
| 528 /// Returns a [Future] that will complete with the results of the process after | 577 /// Returns a [Future] that will complete with the results of the process after |
| 529 /// it has ended. | 578 /// it has ended. |
| 530 /// | 579 /// |
| 531 /// The spawned process will inherit its parent's environment variables. If | 580 /// The spawned process will inherit its parent's environment variables. If |
| 532 /// [environment] is provided, that will be used to augment (not replace) the | 581 /// [environment] is provided, that will be used to augment (not replace) the |
| 533 /// the inherited variables. | 582 /// the inherited variables. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 | 633 |
| 585 return fn(executable, args, options); | 634 return fn(executable, args, options); |
| 586 } | 635 } |
| 587 | 636 |
| 588 /// Closes [response] while ignoring the body of [request]. Returns a Future | 637 /// Closes [response] while ignoring the body of [request]. Returns a Future |
| 589 /// that completes once the response is closed. | 638 /// that completes once the response is closed. |
| 590 /// | 639 /// |
| 591 /// Due to issue 6984, it's necessary to drain the request body before closing | 640 /// Due to issue 6984, it's necessary to drain the request body before closing |
| 592 /// the response. | 641 /// the response. |
| 593 Future closeHttpResponse(HttpRequest request, HttpResponse response) { | 642 Future closeHttpResponse(HttpRequest request, HttpResponse response) { |
| 643 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 644 var stackTrace; |
| 645 try { |
| 646 throw null; |
| 647 } catch (_, localStackTrace) { |
| 648 stackTrace = localStackTrace; |
| 649 } |
| 650 |
| 594 var completer = new Completer(); | 651 var completer = new Completer(); |
| 595 request.inputStream.onError = completer.completeException; | 652 request.inputStream.onError = (e) => |
| 653 completer.completeException(e, stackTrace); |
| 596 request.inputStream.onData = request.inputStream.read; | 654 request.inputStream.onData = request.inputStream.read; |
| 597 request.inputStream.onClosed = () { | 655 request.inputStream.onClosed = () { |
| 598 response.outputStream.close(); | 656 response.outputStream.close(); |
| 599 completer.complete(null); | 657 completer.complete(null); |
| 600 }; | 658 }; |
| 601 return completer.future; | 659 return completer.future; |
| 602 } | 660 } |
| 603 | 661 |
| 604 /** | 662 /** |
| 605 * Wraps [input] to provide a timeout. If [input] completes before | 663 * Wraps [input] to provide a timeout. If [input] completes before |
| 606 * [milliseconds] have passed, then the return value completes in the same way. | 664 * [milliseconds] have passed, then the return value completes in the same way. |
| 607 * However, if [milliseconds] pass before [input] has completed, it completes | 665 * However, if [milliseconds] pass before [input] has completed, it completes |
| 608 * with a [TimeoutException] with [description] (which should be a fragment | 666 * with a [TimeoutException] with [description] (which should be a fragment |
| 609 * describing the action that timed out). | 667 * describing the action that timed out). |
| 610 * | 668 * |
| 611 * Note that timing out will not cancel the asynchronous operation behind | 669 * Note that timing out will not cancel the asynchronous operation behind |
| 612 * [input]. | 670 * [input]. |
| 613 */ | 671 */ |
| 614 Future timeout(Future input, int milliseconds, String description) { | 672 Future timeout(Future input, int milliseconds, String description) { |
| 615 var completer = new Completer(); | 673 var completer = new Completer(); |
| 616 var timer = new Timer(milliseconds, (_) { | 674 var timer = new Timer(milliseconds, (_) { |
| 617 if (completer.future.isComplete) return; | 675 if (completer.future.isComplete) return; |
| 618 completer.completeException(new TimeoutException( | 676 completer.completeException(new TimeoutException( |
| 619 'Timed out while $description.')); | 677 'Timed out while $description.')); |
| 620 }); | 678 }); |
| 621 input.handleException((e) { | 679 input.handleException((e) { |
| 622 if (completer.future.isComplete) return false; | 680 if (completer.future.isComplete) return false; |
| 623 timer.cancel(); | 681 timer.cancel(); |
| 624 completer.completeException(e); | 682 completer.completeException(e, input.stackTrace); |
| 625 return true; | 683 return true; |
| 626 }); | 684 }); |
| 627 input.then((value) { | 685 input.then((value) { |
| 628 if (completer.future.isComplete) return; | 686 if (completer.future.isComplete) return; |
| 629 timer.cancel(); | 687 timer.cancel(); |
| 630 completer.complete(value); | 688 completer.complete(value); |
| 631 }); | 689 }); |
| 632 return completer.future; | 690 return completer.future; |
| 633 } | 691 } |
| 634 | 692 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 var completer = new Completer<int>(); | 779 var completer = new Completer<int>(); |
| 722 var processFuture = Process.start("tar", | 780 var processFuture = Process.start("tar", |
| 723 ["--extract", "--gunzip", "--directory", destination]); | 781 ["--extract", "--gunzip", "--directory", destination]); |
| 724 processFuture.then((process) { | 782 processFuture.then((process) { |
| 725 process.onExit = completer.complete; | 783 process.onExit = completer.complete; |
| 726 stream.pipe(process.stdin); | 784 stream.pipe(process.stdin); |
| 727 process.stdout.pipe(stdout, close: false); | 785 process.stdout.pipe(stdout, close: false); |
| 728 process.stderr.pipe(stderr, close: false); | 786 process.stderr.pipe(stderr, close: false); |
| 729 }); | 787 }); |
| 730 processFuture.handleException((error) { | 788 processFuture.handleException((error) { |
| 731 completer.completeException(error); | 789 completer.completeException(error, processFuture.stackTrace); |
| 732 return true; | 790 return true; |
| 733 }); | 791 }); |
| 734 | 792 |
| 735 return completer.future.transform((exitCode) => exitCode == 0); | 793 return completer.future.transform((exitCode) => exitCode == 0); |
| 736 } | 794 } |
| 737 | 795 |
| 738 Future<bool> _extractTarGzWindows(InputStream stream, String destination) { | 796 Future<bool> _extractTarGzWindows(InputStream stream, String destination) { |
| 739 // TODO(rnystrom): In the repo's history, there is an older implementation of | 797 // TODO(rnystrom): In the repo's history, there is an older implementation of |
| 740 // this that does everything in memory by piping streams directly together | 798 // this that does everything in memory by piping streams directly together |
| 741 // instead of writing out temp files. The code is simpler, but unfortunately, | 799 // instead of writing out temp files. The code is simpler, but unfortunately, |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 return new Directory(entry); | 981 return new Directory(entry); |
| 924 } | 982 } |
| 925 | 983 |
| 926 /** | 984 /** |
| 927 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 985 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
| 928 */ | 986 */ |
| 929 Uri _getUri(uri) { | 987 Uri _getUri(uri) { |
| 930 if (uri is Uri) return uri; | 988 if (uri is Uri) return uri; |
| 931 return new Uri.fromString(uri); | 989 return new Uri.fromString(uri); |
| 932 } | 990 } |
| OLD | NEW |