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 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 | 364 |
365 // Using Path.join here instead of File().fullPathSync() because the former | 365 // Using Path.join here instead of File().fullPathSync() because the former |
366 // does not require an actual file to exist at that path. | 366 // does not require an actual file to exist at that path. |
367 return new Path.fromNative(currentWorkingDir).join(new Path(path)) | 367 return new Path.fromNative(currentWorkingDir).join(new Path(path)) |
368 .toNativePath(); | 368 .toNativePath(); |
369 } | 369 } |
370 | 370 |
371 /// Resolves [path] relative to the location of pub.dart. | 371 /// Resolves [path] relative to the location of pub.dart. |
372 String relativeToPub(String path) { | 372 String relativeToPub(String path) { |
373 var scriptPath = new File(new Options().script).fullPathSync(); | 373 var scriptPath = new File(new Options().script).fullPathSync(); |
374 var scriptDir = new Path.fromNative(scriptPath).directoryPath; | 374 |
375 return scriptDir.append(path).canonicalize().toNativePath(); | 375 // Walk up until we hit the "utils" directory. This lets us figure out where |
| 376 // we are if this function is called from pub.dart, or one of the tests, |
| 377 // which also live under "utils". |
| 378 var utilsDir = new Path.fromNative(scriptPath).directoryPath; |
| 379 while (utilsDir.filename != 'utils') { |
| 380 utilsDir = utilsDir.directoryPath; |
| 381 } |
| 382 |
| 383 return utilsDir.append('pub').append(path).canonicalize().toNativePath(); |
376 } | 384 } |
377 | 385 |
378 /// A StringInputStream reading from stdin. | 386 /// A StringInputStream reading from stdin. |
379 final _stringStdin = new StringInputStream(stdin); | 387 final _stringStdin = new StringInputStream(stdin); |
380 | 388 |
381 /// Returns a single line read from a [StringInputStream]. By default, reads | 389 /// Returns a single line read from a [StringInputStream]. By default, reads |
382 /// from stdin. | 390 /// from stdin. |
383 /// | 391 /// |
384 /// A [StringInputStream] passed to this should have no callbacks registered. | 392 /// A [StringInputStream] passed to this should have no callbacks registered. |
385 Future<String> readLine([StringInputStream stream]) { | 393 Future<String> readLine([StringInputStream stream]) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 */ | 477 */ |
470 Future<String> httpGetString(uri) { | 478 Future<String> httpGetString(uri) { |
471 var future = httpGet(uri).chain((stream) => consumeInputStream(stream)) | 479 var future = httpGet(uri).chain((stream) => consumeInputStream(stream)) |
472 .transform((bytes) => new String.fromCharCodes(bytes)); | 480 .transform((bytes) => new String.fromCharCodes(bytes)); |
473 return timeout(future, HTTP_TIMEOUT, 'fetching URL "$uri"'); | 481 return timeout(future, HTTP_TIMEOUT, 'fetching URL "$uri"'); |
474 } | 482 } |
475 | 483 |
476 /** | 484 /** |
477 * Takes all input from [source] and writes it to [sink]. | 485 * Takes all input from [source] and writes it to [sink]. |
478 * | 486 * |
479 * [onClosed] is called when [source] is closed. | 487 * Returns a future that completes when [source] is closed. |
480 */ | 488 */ |
481 void pipeInputToInput(InputStream source, ListInputStream sink, | 489 Future pipeInputToInput(InputStream source, ListInputStream sink) { |
482 [void onClosed()]) { | 490 var completer = new Completer(); |
483 source.onClosed = () { | 491 source.onClosed = () { |
484 sink.markEndOfStream(); | 492 sink.markEndOfStream(); |
485 if (onClosed != null) onClosed(); | 493 completer.complete(null); |
486 }; | 494 }; |
487 source.onData = () => sink.write(source.read()); | 495 source.onData = () => sink.write(source.read()); |
488 // TODO(nweiz): propagate this error to the sink. See issue 3657. | 496 // TODO(nweiz): propagate this error to the sink. See issue 3657. |
489 source.onError = (e) { throw e; }; | 497 source.onError = (e) { throw e; }; |
| 498 return completer.future; |
490 } | 499 } |
491 | 500 |
492 /** | 501 /** |
493 * Buffers all input from an InputStream and returns it as a future. | 502 * Buffers all input from an InputStream and returns it as a future. |
494 */ | 503 */ |
495 Future<List<int>> consumeInputStream(InputStream stream) { | 504 Future<List<int>> consumeInputStream(InputStream stream) { |
496 if (stream.closed) return new Future.immediate(<int>[]); | 505 if (stream.closed) return new Future.immediate(<int>[]); |
497 | 506 |
498 var completer = new Completer<List<int>>(); | 507 var completer = new Completer<List<int>>(); |
499 var buffer = <int>[]; | 508 var buffer = <int>[]; |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 completer.complete(value); | 630 completer.complete(value); |
622 }); | 631 }); |
623 return completer.future; | 632 return completer.future; |
624 } | 633 } |
625 | 634 |
626 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] | 635 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] |
627 /// returned by [fn] completes, the temporary directory and all its contents | 636 /// returned by [fn] completes, the temporary directory and all its contents |
628 /// will be deleted. | 637 /// will be deleted. |
629 Future withTempDir(Future fn(String path)) { | 638 Future withTempDir(Future fn(String path)) { |
630 var tempDir; | 639 var tempDir; |
631 var future = new Directory('').createTemp().chain((dir) { | 640 var future = createTempDir().chain((dir) { |
632 tempDir = dir; | 641 tempDir = dir; |
633 return fn(tempDir.path); | 642 return fn(tempDir.path); |
634 }); | 643 }); |
635 future.onComplete((_) => tempDir.delete(recursive: true)); | 644 future.onComplete((_) => tempDir.delete(recursive: true)); |
636 return future; | 645 return future; |
637 } | 646 } |
638 | 647 |
639 /// Tests whether or not the git command-line app is available for use. | 648 /// Tests whether or not the git command-line app is available for use. |
640 Future<bool> get isGitInstalled { | 649 Future<bool> get isGitInstalled { |
641 if (_isGitInstalledCache != null) { | 650 if (_isGitInstalledCache != null) { |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
734 // read from stdin instead of a file. Consider resurrecting that version if | 743 // read from stdin instead of a file. Consider resurrecting that version if |
735 // we can figure out why it fails. | 744 // we can figure out why it fails. |
736 | 745 |
737 // Note: This line of code gets munged by create_sdk.py to be the correct | 746 // Note: This line of code gets munged by create_sdk.py to be the correct |
738 // relative path to 7zip in the SDK. | 747 // relative path to 7zip in the SDK. |
739 var pathTo7zip = '../../third_party/7zip/7za.exe'; | 748 var pathTo7zip = '../../third_party/7zip/7za.exe'; |
740 var command = relativeToPub(pathTo7zip); | 749 var command = relativeToPub(pathTo7zip); |
741 | 750 |
742 var tempDir; | 751 var tempDir; |
743 | 752 |
| 753 // TODO(rnystrom): Use withTempDir(). |
744 return createTempDir().chain((temp) { | 754 return createTempDir().chain((temp) { |
745 // Write the archive to a temp file. | 755 // Write the archive to a temp file. |
746 tempDir = temp; | 756 tempDir = temp; |
747 return createFileFromStream(stream, join(tempDir, 'data.tar.gz')); | 757 return createFileFromStream(stream, join(tempDir, 'data.tar.gz')); |
748 }).chain((_) { | 758 }).chain((_) { |
749 // 7zip can't unarchive from gzip -> tar -> destination all in one step | 759 // 7zip can't unarchive from gzip -> tar -> destination all in one step |
750 // first we un-gzip it to a tar file. | 760 // first we un-gzip it to a tar file. |
751 // Note: Setting the working directory instead of passing in a full file | 761 // Note: Setting the working directory instead of passing in a full file |
752 // path because 7zip says "A full path is not allowed here." | 762 // path because 7zip says "A full path is not allowed here." |
753 return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir); | 763 return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 // Create the tar file. | 832 // Create the tar file. |
823 var tarFile = join(tempDir, "intermediate.tar"); | 833 var tarFile = join(tempDir, "intermediate.tar"); |
824 var args = ["a", "-w$baseDir", tarFile]; | 834 var args = ["a", "-w$baseDir", tarFile]; |
825 args.addAll(contents.map((entry) => '-i!"$entry"')); | 835 args.addAll(contents.map((entry) => '-i!"$entry"')); |
826 | 836 |
827 // Note: This line of code gets munged by create_sdk.py to be the correct | 837 // Note: This line of code gets munged by create_sdk.py to be the correct |
828 // relative path to 7zip in the SDK. | 838 // relative path to 7zip in the SDK. |
829 var pathTo7zip = '../../third_party/7zip/7za.exe'; | 839 var pathTo7zip = '../../third_party/7zip/7za.exe'; |
830 var command = relativeToPub(pathTo7zip); | 840 var command = relativeToPub(pathTo7zip); |
831 | 841 |
832 return runProcess(command, args).chain((_) { | 842 // We're passing 'baseDir' both as '-w' and setting it as the working |
| 843 // directory explicitly here intentionally. The former ensures that the |
| 844 // files added to the archive have the correct relative path in the archive. |
| 845 // The latter enables relative paths in the "-i" args to be resolved. |
| 846 return runProcess(command, args, workingDir: baseDir).chain((_) { |
833 // GZIP it. 7zip doesn't support doing both as a single operation. Send | 847 // GZIP it. 7zip doesn't support doing both as a single operation. Send |
834 // the output to stdout. | 848 // the output to stdout. |
835 args = ["a", "not used", "-so", tarFile]; | 849 args = ["a", "unused", "-tgzip", "-so", tarFile]; |
836 return startProcess(command, args); | 850 return startProcess(command, args); |
837 }).transform((process) { | 851 }).chain((process) { |
838 pipeInputToInput(process.stdout, stream); | |
839 process.stderr.pipe(stderr, close: false); | 852 process.stderr.pipe(stderr, close: false); |
| 853 return pipeInputToInput(process.stdout, stream); |
840 }); | 854 }); |
841 }); | 855 }); |
842 return stream; | 856 return stream; |
843 } | 857 } |
844 | 858 |
845 /** | 859 /** |
846 * Exception thrown when an HTTP operation fails. | 860 * Exception thrown when an HTTP operation fails. |
847 */ | 861 */ |
848 class PubHttpException implements Exception { | 862 class PubHttpException implements Exception { |
849 final int statusCode; | 863 final int statusCode; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 return new Directory(entry); | 923 return new Directory(entry); |
910 } | 924 } |
911 | 925 |
912 /** | 926 /** |
913 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 927 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
914 */ | 928 */ |
915 Uri _getUri(uri) { | 929 Uri _getUri(uri) { |
916 if (uri is Uri) return uri; | 930 if (uri is Uri) return uri; |
917 return new Uri.fromString(uri); | 931 return new Uri.fromString(uri); |
918 } | 932 } |
OLD | NEW |