Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(286)

Side by Side Diff: utils/pub/io.dart

Issue 11031015: Extract archives by writing .tar.gz to temp file on Windows. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 } 133 }
134 134
135 /** 135 /**
136 * Asynchronously deletes [file], which can be a [String] or a [File]. Returns a 136 * Asynchronously deletes [file], which can be a [String] or a [File]. Returns a
137 * [Future] that completes when the deletion is done. 137 * [Future] that completes when the deletion is done.
138 */ 138 */
139 Future<File> deleteFile(file) { 139 Future<File> deleteFile(file) {
140 return new File(_getPath(file)).delete(); 140 return new File(_getPath(file)).delete();
141 } 141 }
142 142
143 /// Writes [stream] to a new file at [path], which may be a [String] or a
144 /// [File]. Will replace any file already at that path. Completes when the file
145 /// is done being written.
146 Future<File> createFileFromStream(InputStream stream, path) {
147 path = _getPath(path);
148
149 var completer = new Completer<File>();
150 var file = new File(path);
151 var outputStream = file.openOutputStream();
152 stream.pipe(outputStream);
153
154 outputStream.onClosed = () {
155 completer.complete(file);
156 };
157
158 stream.onError = completer.completeException;
159 outputStream.onError = completer.completeException;
nweiz 2012/10/02 01:04:13 It's possible that both streams could throw errors
Bob Nystrom 2012/10/02 01:36:37 Done.
160
161 return completer.future;
162 }
163
143 /** 164 /**
144 * Creates a directory [dir]. Returns a [Future] that completes when the 165 * Creates a directory [dir]. Returns a [Future] that completes when the
145 * directory is created. 166 * directory is created.
146 */ 167 */
147 Future<Directory> createDir(dir) { 168 Future<Directory> createDir(dir) {
148 dir = _getDirectory(dir); 169 dir = _getDirectory(dir);
149 return dir.create(); 170 return dir.create();
150 } 171 }
151 172
152 /** 173 /**
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 } 648 }
628 649
629 Future<bool> _extractTarGzWindows(InputStream stream, String destination) { 650 Future<bool> _extractTarGzWindows(InputStream stream, String destination) {
630 // Find 7zip. 651 // Find 7zip.
631 var scriptPath = new File(new Options().script).fullPathSync(); 652 var scriptPath = new File(new Options().script).fullPathSync();
632 var scriptDir = new Path.fromNative(scriptPath).directoryPath; 653 var scriptDir = new Path.fromNative(scriptPath).directoryPath;
633 654
634 // Note: This line of code gets munged by create_sdk.py to be the correct 655 // Note: This line of code gets munged by create_sdk.py to be the correct
635 // relative path to 7zip in the SDK. 656 // relative path to 7zip in the SDK.
636 var pathTo7zip = '../../third_party/7zip/7za.exe'; 657 var pathTo7zip = '../../third_party/7zip/7za.exe';
658 var command = scriptDir.append(pathTo7zip).canonicalize().toNativePath();
659
660 var tempDir;
661
662 return createTempDir().chain((temp) {
663 // Write the archive to a temp file.
664 tempDir = temp;
665 return createFileFromStream(stream, join(tempDir, 'data.tar.gz'));
666 }).chain((tarGz) {
667 // 7zip can't unarchive from gzip -> tar -> destination all in one step
668 // first we un-gzip it to a tar file.
669 // TODO(rnystrom): Setting the working directory instead of passing in
nweiz 2012/10/02 01:04:13 I don't know if this is really a TODO, since you c
Bob Nystrom 2012/10/02 01:36:37 Done.
670 // a full file path because 7zip says "A full path is not allowed here."
671 return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir);
672 }).chain((result) {
673 if (result.exitCode != 0) {
674 throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n'
675 '${Strings.join(result.stderr, "\n")}';
676 }
677
678 // Find the tar file we just created since we don't know its name.
679 return listDir(tempDir);
680 }).chain((files) {
681 var tarFile;
682 for (var file in files) {
683 if (new Path(file).extension == 'tar') {
684 tarFile = file;
685 break;
686 }
687 }
688
689 if (tarFile == null) throw 'The gzip file did not contain a tar file.';
690
691 // Untar the archive into the destination directory.
692 return runProcess(command, ['x', '-o"$destination"', tarFile],
693 workingDir: tempDir);
694 }).chain((result) {
695 if (result.exitCode != 0) {
696 throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
697 '${Strings.join(result.stderr, "\n")}';
698 }
699
700 // Clean up the temp directory.
701 // TODO(rnystrom): Should also delete this if anything fails.
702 return deleteDir(tempDir);
703 }).transform((_) => true);
704 }
705
706 // TODO(rnystrom): The following is a cleaner way of extracting archives on
707 // Windows. It does everything in memory by piping streams directly together
708 // instead of writing out temp files. Unfortunately, 7zip seems to periodically
709 // fail when we invoke it from Dart and tell it to read from stdin instead of
710 // a file. Leaving this code here since it's otherwise cleaner, and maybe we
711 // can resurrect it at some point.
712 /*
nweiz 2012/10/02 01:04:13 I don't like checking in commented-out code. I fee
Bob Nystrom 2012/10/02 01:36:37 Done.
713 Future<bool> _extractTarGzWindows(InputStream stream, String destination) {
714 // Find 7zip.
715 var scriptPath = new File(new Options().script).fullPathSync();
716 var scriptDir = new Path.fromNative(scriptPath).directoryPath;
717
718 // Note: This line of code gets munged by create_sdk.py to be the correct
719 // relative path to 7zip in the SDK.
720 var pathTo7zip = '../../third_party/7zip/7za.exe';
637 721
638 var command = scriptDir.append(pathTo7zip).canonicalize().toNativePath(); 722 var command = scriptDir.append(pathTo7zip).canonicalize().toNativePath();
639 723
640 // 7zip can't unarchive from gzip -> tar -> destination all in one step so 724 // 7zip can't unarchive from gzip -> tar -> destination all in one step so
641 // we spawn it twice and pipe them together. 725 // we spawn it twice and pipe them together.
642 var completer = new Completer<bool>(); 726 var completer = new Completer<bool>();
643 var gzipProcess = Process.start(command, ['e', '-si', '-tgzip', '-so']); 727 var gzipProcess = Process.start(command, ['e', '-si', '-tgzip', '-so']);
644 728
645 // TODO(rnystrom): Even though we are quoting the destination directory here, 729 // TODO(rnystrom): Even though we are quoting the destination directory here,
646 // 7zip still seems to barf if there is a space in the path. For now we'll 730 // 7zip still seems to barf if there is a space in the path. For now we'll
(...skipping 28 matching lines...) Expand all
675 } else { 759 } else {
676 completer.complete(true); 760 completer.complete(true);
677 } 761 }
678 }; 762 };
679 763
680 tarProcess.onError = completer.completeException; 764 tarProcess.onError = completer.completeException;
681 gzipProcess.onError = completer.completeException; 765 gzipProcess.onError = completer.completeException;
682 766
683 return completer.future; 767 return completer.future;
684 } 768 }
769 */
685 770
686 /** 771 /**
687 * Exception thrown when an HTTP operation fails. 772 * Exception thrown when an HTTP operation fails.
688 */ 773 */
689 class PubHttpException implements Exception { 774 class PubHttpException implements Exception {
690 final int statusCode; 775 final int statusCode;
691 final String reason; 776 final String reason;
692 777
693 const PubHttpException(this.statusCode, this.reason); 778 const PubHttpException(this.statusCode, this.reason);
694 } 779 }
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 return new Directory(entry); 821 return new Directory(entry);
737 } 822 }
738 823
739 /** 824 /**
740 * Gets a [Uri] for [uri], which can either already be one, or be a [String]. 825 * Gets a [Uri] for [uri], which can either already be one, or be a [String].
741 */ 826 */
742 Uri _getUri(uri) { 827 Uri _getUri(uri) {
743 if (uri is Uri) return uri; 828 if (uri is Uri) return uri;
744 return new Uri.fromString(uri); 829 return new Uri.fromString(uri);
745 } 830 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698