| 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 /// Helper functionality to make working with IO easier. | 5 /// Helper functionality to make working with IO easier. |
| 6 library io; | 6 library io; |
| 7 | 7 |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 import 'dart:isolate'; | 10 import 'dart:isolate'; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 } | 150 } |
| 151 } | 151 } |
| 152 | 152 |
| 153 return dir; | 153 return dir; |
| 154 } | 154 } |
| 155 | 155 |
| 156 /// Creates a temp directory whose name will be based on [dir] with a unique | 156 /// Creates a temp directory whose name will be based on [dir] with a unique |
| 157 /// suffix appended to it. If [dir] is not provided, a temp directory will be | 157 /// suffix appended to it. If [dir] is not provided, a temp directory will be |
| 158 /// created in a platform-dependent temporary location. Returns a [Future] that | 158 /// created in a platform-dependent temporary location. Returns a [Future] that |
| 159 /// completes when the directory is created. | 159 /// completes when the directory is created. |
| 160 Future<Directory> createTempDir([dir = '']) { | 160 Directory createTempDir([dir = '']) { |
| 161 dir = _getDirectory(dir); | 161 var tempDir = _getDirectory(dir).createTempSync(); |
| 162 return log.ioAsync("create temp directory ${dir.path}", | 162 log.io("Created temp directory ${tempDir.path}"); |
| 163 dir.createTemp()); | 163 return tempDir; |
| 164 } | 164 } |
| 165 | 165 |
| 166 /// Asynchronously recursively deletes [dir], which can be a [String] or a | 166 /// Asynchronously recursively deletes [dir], which can be a [String] or a |
| 167 /// [Directory]. Returns a [Future] that completes when the deletion is done. | 167 /// [Directory]. Returns a [Future] that completes when the deletion is done. |
| 168 Future<Directory> deleteDir(dir) { | 168 Future<Directory> deleteDir(dir) { |
| 169 dir = _getDirectory(dir); | 169 dir = _getDirectory(dir); |
| 170 | 170 |
| 171 return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}", | 171 return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}", |
| 172 dir.delete(recursive: true))); | 172 dir.delete(recursive: true))); |
| 173 } | 173 } |
| (...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 if (completed) return; | 715 if (completed) return; |
| 716 timer.cancel(); | 716 timer.cancel(); |
| 717 completer.completeError(e.error, e.stackTrace); | 717 completer.completeError(e.error, e.stackTrace); |
| 718 }); | 718 }); |
| 719 return completer.future; | 719 return completer.future; |
| 720 } | 720 } |
| 721 | 721 |
| 722 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] | 722 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] |
| 723 /// returned by [fn] completes, the temporary directory and all its contents | 723 /// returned by [fn] completes, the temporary directory and all its contents |
| 724 /// will be deleted. | 724 /// will be deleted. |
| 725 /// |
| 726 /// Returns a future that completes to the value that the future returned from |
| 727 /// [fn] completes to. |
| 725 Future withTempDir(Future fn(String path)) { | 728 Future withTempDir(Future fn(String path)) { |
| 726 var tempDir; | 729 return defer(() { |
| 727 return createTempDir().then((dir) { | 730 var tempDir = createTempDir(); |
| 728 tempDir = dir; | 731 return fn(tempDir.path).whenComplete(() { |
| 729 return fn(tempDir.path); | 732 return deleteDir(tempDir); |
| 730 }).whenComplete(() { | 733 }); |
| 731 log.fine('Cleaning up temp directory ${tempDir.path}.'); | |
| 732 return deleteDir(tempDir); | |
| 733 }); | 734 }); |
| 734 } | 735 } |
| 735 | 736 |
| 736 /// Extracts a `.tar.gz` file from [stream] to [destination], which can be a | 737 /// Extracts a `.tar.gz` file from [stream] to [destination], which can be a |
| 737 /// directory or a path. Returns whether or not the extraction was successful. | 738 /// directory or a path. Returns whether or not the extraction was successful. |
| 738 Future<bool> extractTarGz(Stream<List<int>> stream, destination) { | 739 Future<bool> extractTarGz(Stream<List<int>> stream, destination) { |
| 739 destination = _getPath(destination); | 740 destination = _getPath(destination); |
| 740 | 741 |
| 741 log.fine("Extracting .tar.gz stream to $destination."); | 742 log.fine("Extracting .tar.gz stream to $destination."); |
| 742 | 743 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 772 // instead of writing out temp files. The code is simpler, but unfortunately, | 773 // instead of writing out temp files. The code is simpler, but unfortunately, |
| 773 // 7zip seems to periodically fail when we invoke it from Dart and tell it to | 774 // 7zip seems to periodically fail when we invoke it from Dart and tell it to |
| 774 // read from stdin instead of a file. Consider resurrecting that version if | 775 // read from stdin instead of a file. Consider resurrecting that version if |
| 775 // we can figure out why it fails. | 776 // we can figure out why it fails. |
| 776 | 777 |
| 777 // Note: This line of code gets munged by create_sdk.py to be the correct | 778 // Note: This line of code gets munged by create_sdk.py to be the correct |
| 778 // relative path to 7zip in the SDK. | 779 // relative path to 7zip in the SDK. |
| 779 var pathTo7zip = '../../third_party/7zip/7za.exe'; | 780 var pathTo7zip = '../../third_party/7zip/7za.exe'; |
| 780 var command = relativeToPub(pathTo7zip); | 781 var command = relativeToPub(pathTo7zip); |
| 781 | 782 |
| 782 var tempDir; | 783 return withTempDir((tempDir) { |
| 784 // Write the archive to a temp file. |
| 785 return createFileFromStream(stream, join(tempDir, 'data.tar.gz')).then((_) { |
| 786 // 7zip can't unarchive from gzip -> tar -> destination all in one step |
| 787 // first we un-gzip it to a tar file. |
| 788 // Note: Setting the working directory instead of passing in a full file |
| 789 // path because 7zip says "A full path is not allowed here." |
| 790 return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir); |
| 791 }).then((result) { |
| 792 if (result.exitCode != 0) { |
| 793 throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n' |
| 794 '${Strings.join(result.stdout, "\n")}\n' |
| 795 '${Strings.join(result.stderr, "\n")}'; |
| 796 } |
| 797 // Find the tar file we just created since we don't know its name. |
| 798 return listDir(tempDir); |
| 799 }).then((files) { |
| 800 var tarFile; |
| 801 for (var file in files) { |
| 802 if (path.extension(file) == '.tar') { |
| 803 tarFile = file; |
| 804 break; |
| 805 } |
| 806 } |
| 783 | 807 |
| 784 // TODO(rnystrom): Use withTempDir(). | 808 if (tarFile == null) throw 'The gzip file did not contain a tar file.'; |
| 785 return createTempDir().then((temp) { | 809 |
| 786 // Write the archive to a temp file. | 810 // Untar the archive into the destination directory. |
| 787 tempDir = temp; | 811 return runProcess(command, ['x', tarFile], workingDir: destination); |
| 788 return createFileFromStream(stream, join(tempDir, 'data.tar.gz')); | 812 }).then((result) { |
| 789 }).then((_) { | 813 if (result.exitCode != 0) { |
| 790 // 7zip can't unarchive from gzip -> tar -> destination all in one step | 814 throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n' |
| 791 // first we un-gzip it to a tar file. | 815 '${Strings.join(result.stdout, "\n")}\n' |
| 792 // Note: Setting the working directory instead of passing in a full file | 816 '${Strings.join(result.stderr, "\n")}'; |
| 793 // path because 7zip says "A full path is not allowed here." | |
| 794 return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir); | |
| 795 }).then((result) { | |
| 796 if (result.exitCode != 0) { | |
| 797 throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n' | |
| 798 '${Strings.join(result.stdout, "\n")}\n' | |
| 799 '${Strings.join(result.stderr, "\n")}'; | |
| 800 } | |
| 801 // Find the tar file we just created since we don't know its name. | |
| 802 return listDir(tempDir); | |
| 803 }).then((files) { | |
| 804 var tarFile; | |
| 805 for (var file in files) { | |
| 806 if (path.extension(file) == '.tar') { | |
| 807 tarFile = file; | |
| 808 break; | |
| 809 } | 817 } |
| 810 } | 818 return true; |
| 811 | 819 }); |
| 812 if (tarFile == null) throw 'The gzip file did not contain a tar file.'; | 820 }); |
| 813 | |
| 814 // Untar the archive into the destination directory. | |
| 815 return runProcess(command, ['x', tarFile], workingDir: destination); | |
| 816 }).then((result) { | |
| 817 if (result.exitCode != 0) { | |
| 818 throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n' | |
| 819 '${Strings.join(result.stdout, "\n")}\n' | |
| 820 '${Strings.join(result.stderr, "\n")}'; | |
| 821 } | |
| 822 | |
| 823 log.fine('Clean up 7zip temp directory ${tempDir.path}.'); | |
| 824 // TODO(rnystrom): Should also delete this if anything fails. | |
| 825 return deleteDir(tempDir); | |
| 826 }).then((_) => true); | |
| 827 } | 821 } |
| 828 | 822 |
| 829 /// Create a .tar.gz archive from a list of entries. Each entry can be a | 823 /// Create a .tar.gz archive from a list of entries. Each entry can be a |
| 830 /// [String], [Directory], or [File] object. The root of the archive is | 824 /// [String], [Directory], or [File] object. The root of the archive is |
| 831 /// considered to be [baseDir], which defaults to the current working directory. | 825 /// considered to be [baseDir], which defaults to the current working directory. |
| 832 /// Returns a [ByteStream] that will emit the contents of the archive. | 826 /// Returns a [ByteStream] that will emit the contents of the archive. |
| 833 ByteStream createTarGz(List contents, {baseDir}) { | 827 ByteStream createTarGz(List contents, {baseDir}) { |
| 834 var buffer = new StringBuffer(); | 828 var buffer = new StringBuffer(); |
| 835 buffer.add('Creating .tag.gz stream containing:\n'); | 829 buffer.add('Creating .tag.gz stream containing:\n'); |
| 836 contents.forEach((file) => buffer.add('$file\n')); | 830 contents.forEach((file) => buffer.add('$file\n')); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 947 Directory _getDirectory(entry) { | 941 Directory _getDirectory(entry) { |
| 948 if (entry is Directory) return entry; | 942 if (entry is Directory) return entry; |
| 949 return new Directory(entry); | 943 return new Directory(entry); |
| 950 } | 944 } |
| 951 | 945 |
| 952 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 946 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
| 953 Uri _getUri(uri) { | 947 Uri _getUri(uri) { |
| 954 if (uri is Uri) return uri; | 948 if (uri is Uri) return uri; |
| 955 return Uri.parse(uri); | 949 return Uri.parse(uri); |
| 956 } | 950 } |
| OLD | NEW |