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

Side by Side Diff: lib/src/io.dart

Issue 1235013002: Remove the timeout for downloading packages. (Closed) Base URL: git@github.com:dart-lang/pub.git@master
Patch Set: Code review changes Created 5 years, 5 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
« no previous file with comments | « lib/src/http.dart ('k') | lib/src/source/hosted.dart » ('j') | 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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 pub.io; 6 library pub.io;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:collection'; 9 import 'dart:collection';
10 import 'dart:convert'; 10 import 'dart:convert';
(...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after
822 executable = "cmd"; 822 executable = "cmd";
823 } 823 }
824 824
825 log.process(executable, args, workingDir == null ? '.' : workingDir); 825 log.process(executable, args, workingDir == null ? '.' : workingDir);
826 826
827 return fn(executable, args, 827 return fn(executable, args,
828 workingDirectory: workingDir, 828 workingDirectory: workingDir,
829 environment: environment); 829 environment: environment);
830 } 830 }
831 831
832 /// Wraps [input], an asynchronous network operation to provide a timeout.
833 ///
834 /// If [input] completes before [milliseconds] have passed, then the return
835 /// value completes in the same way. However, if [milliseconds] pass before
836 /// [input] has completed, it completes with a [TimeoutException] with
837 /// [description] (which should be a fragment describing the action that timed
838 /// out).
839 ///
840 /// [url] is the URL being accessed asynchronously.
841 ///
842 /// Note that timing out will not cancel the asynchronous operation behind
843 /// [input].
844 Future timeout(Future input, int milliseconds, Uri url, String description) {
845 // TODO(nwiez): Replace this with [Future.timeout].
846 var completer = new Completer();
847 var duration = new Duration(milliseconds: milliseconds);
848 var timer = new Timer(duration, () {
849 // Include the duration ourselves in the message instead of passing it to
850 // TimeoutException since we show nicer output.
851 var message = 'Timed out after ${niceDuration(duration)} while '
852 '$description.';
853
854 if (url.host == "pub.dartlang.org" ||
855 url.host == "storage.googleapis.com") {
856 message += "\nThis is likely a transient error. Please try again later.";
857 }
858
859 completer.completeError(new TimeoutException(message), new Chain.current());
860 });
861 input.then((value) {
862 if (completer.isCompleted) return;
863 timer.cancel();
864 completer.complete(value);
865 }).catchError((e, stackTrace) {
866 if (completer.isCompleted) return;
867 timer.cancel();
868 completer.completeError(e, stackTrace);
869 });
870 return completer.future;
871 }
872
873 /// Creates a temporary directory and passes its path to [fn]. 832 /// Creates a temporary directory and passes its path to [fn].
874 /// 833 ///
875 /// Once the [Future] returned by [fn] completes, the temporary directory and 834 /// Once the [Future] returned by [fn] completes, the temporary directory and
876 /// all its contents are deleted. [fn] can also return `null`, in which case 835 /// all its contents are deleted. [fn] can also return `null`, in which case
877 /// the temporary directory is deleted immediately afterwards. 836 /// the temporary directory is deleted immediately afterwards.
878 /// 837 ///
879 /// Returns a future that completes to the value that the future returned from 838 /// Returns a future that completes to the value that the future returned from
880 /// [fn] completes to. 839 /// [fn] completes to.
881 Future withTempDir(Future fn(String path)) { 840 Future withTempDir(Future fn(String path)) {
882 return new Future.sync(() { 841 return new Future.sync(() {
883 var tempDir = createSystemTempDir(); 842 var tempDir = createSystemTempDir();
884 return new Future.sync(() => fn(tempDir)) 843 return new Future.sync(() => fn(tempDir))
885 .whenComplete(() => deleteEntry(tempDir)); 844 .whenComplete(() => deleteEntry(tempDir));
886 }); 845 });
887 } 846 }
888 847
889 /// Binds an [HttpServer] to [host] and [port]. 848 /// Binds an [HttpServer] to [host] and [port].
890 /// 849 ///
891 /// If [host] is "localhost", this will automatically listen on both the IPv4 850 /// If [host] is "localhost", this will automatically listen on both the IPv4
892 /// and IPv6 loopback addresses. 851 /// and IPv6 loopback addresses.
893 Future<HttpServer> bindServer(String host, int port) { 852 Future<HttpServer> bindServer(String host, int port) {
894 if (host == 'localhost') return HttpMultiServer.loopback(port); 853 if (host == 'localhost') return HttpMultiServer.loopback(port);
895 return HttpServer.bind(host, port); 854 return HttpServer.bind(host, port);
896 } 855 }
897 856
898 /// Extracts a `.tar.gz` file from [stream] to [destination]. 857 /// Extracts a `.tar.gz` file from [stream] to [destination].
899 /// 858 Future extractTarGz(Stream<List<int>> stream, String destination) async {
900 /// Returns whether or not the extraction was successful.
901 Future<bool> extractTarGz(Stream<List<int>> stream, String destination) {
902 log.fine("Extracting .tar.gz stream to $destination."); 859 log.fine("Extracting .tar.gz stream to $destination.");
903 860
904 if (Platform.operatingSystem == "windows") { 861 if (Platform.operatingSystem == "windows") {
905 return _extractTarGzWindows(stream, destination); 862 return await _extractTarGzWindows(stream, destination);
906 } 863 }
907 864
908 var args = ["--extract", "--gunzip", "--directory", destination]; 865 var args = ["--extract", "--gunzip", "--directory", destination];
909 if (_noUnknownKeyword) { 866 if (_noUnknownKeyword) {
910 // BSD tar (the default on OS X) can insert strange headers to a tarfile 867 // BSD tar (the default on OS X) can insert strange headers to a tarfile
911 // that GNU tar (the default on Linux) is unable to understand. This will 868 // that GNU tar (the default on Linux) is unable to understand. This will
912 // cause GNU tar to emit a number of harmless but scary-looking warnings 869 // cause GNU tar to emit a number of harmless but scary-looking warnings
913 // which are silenced by this flag. 870 // which are silenced by this flag.
914 args.insert(0, "--warning=no-unknown-keyword"); 871 args.insert(0, "--warning=no-unknown-keyword");
915 } 872 }
916 873
917 return startProcess("tar", args).then((process) { 874 var process = await startProcess("tar", args);
918 // Ignore errors on process.std{out,err}. They'll be passed to 875
919 // process.exitCode, and we don't want them being top-levelled by 876 // Ignore errors on process.std{out,err}. They'll be passed to
920 // std{out,err}Sink. 877 // process.exitCode, and we don't want them being top-levelled by
921 store(process.stdout.handleError((_) {}), stdout, closeSink: false); 878 // std{out,err}Sink.
922 store(process.stderr.handleError((_) {}), stderr, closeSink: false); 879 store(process.stdout.handleError((_) {}), stdout, closeSink: false);
923 return Future.wait([ 880 store(process.stderr.handleError((_) {}), stderr, closeSink: false);
924 store(stream, process.stdin), 881 var results = await Future.wait([
925 process.exitCode 882 store(stream, process.stdin),
926 ]); 883 process.exitCode
927 }).then((results) { 884 ]);
928 var exitCode = results[1]; 885
929 if (exitCode != exit_codes.SUCCESS) { 886 var exitCode = results[1];
930 throw new Exception("Failed to extract .tar.gz stream to $destination " 887 if (exitCode != exit_codes.SUCCESS) {
931 "(exit code $exitCode)."); 888 throw new Exception("Failed to extract .tar.gz stream to $destination "
932 } 889 "(exit code $exitCode).");
933 log.fine("Extracted .tar.gz stream to $destination. Exit code $exitCode."); 890 }
934 }); 891 log.fine("Extracted .tar.gz stream to $destination. Exit code $exitCode.");
935 } 892 }
936 893
937 /// Whether to include "--warning=no-unknown-keyword" when invoking tar. 894 /// Whether to include "--warning=no-unknown-keyword" when invoking tar.
938 /// 895 ///
939 /// This flag quiets warnings that come from opening OS X-generated tarballs on 896 /// This flag quiets warnings that come from opening OS X-generated tarballs on
940 /// Linux, but only GNU tar >= 1.26 supports it. 897 /// Linux, but only GNU tar >= 1.26 supports it.
941 final bool _noUnknownKeyword = _computeNoUnknownKeyword(); 898 final bool _noUnknownKeyword = _computeNoUnknownKeyword();
942 bool _computeNoUnknownKeyword() { 899 bool _computeNoUnknownKeyword() {
943 if (!Platform.isLinux) return false; 900 if (!Platform.isLinux) return false;
944 var result = Process.runSync("tar", ["--version"]); 901 var result = Process.runSync("tar", ["--version"]);
945 if (result.exitCode != 0) { 902 if (result.exitCode != 0) {
946 throw new ApplicationException( 903 throw new ApplicationException(
947 "Failed to run tar (exit code ${result.exitCode}):\n${result.stderr}"); 904 "Failed to run tar (exit code ${result.exitCode}):\n${result.stderr}");
948 } 905 }
949 906
950 var match = new RegExp(r"^tar \(GNU tar\) (\d+).(\d+)\n") 907 var match = new RegExp(r"^tar \(GNU tar\) (\d+).(\d+)\n")
951 .firstMatch(result.stdout); 908 .firstMatch(result.stdout);
952 if (match == null) return false; 909 if (match == null) return false;
953 910
954 var major = int.parse(match[1]); 911 var major = int.parse(match[1]);
955 var minor = int.parse(match[2]); 912 var minor = int.parse(match[2]);
956 return major >= 2 || (major == 1 && minor >= 23); 913 return major >= 2 || (major == 1 && minor >= 23);
957 } 914 }
958 915
959 final String pathTo7zip = (() { 916 final String pathTo7zip = (() {
960 if (!runningFromDartRepo) return sdkAssetPath(path.join('7zip', '7za.exe')); 917 if (!runningFromDartRepo) return sdkAssetPath(path.join('7zip', '7za.exe'));
961 return path.join(dartRepoRoot, 'third_party', '7zip', '7za.exe'); 918 return path.join(dartRepoRoot, 'third_party', '7zip', '7za.exe');
962 })(); 919 })();
963 920
964 Future<bool> _extractTarGzWindows(Stream<List<int>> stream, 921 Future _extractTarGzWindows(Stream<List<int>> stream, String destination) {
965 String destination) {
966 // TODO(rnystrom): In the repo's history, there is an older implementation of 922 // TODO(rnystrom): In the repo's history, there is an older implementation of
967 // this that does everything in memory by piping streams directly together 923 // this that does everything in memory by piping streams directly together
968 // instead of writing out temp files. The code is simpler, but unfortunately, 924 // instead of writing out temp files. The code is simpler, but unfortunately,
969 // 7zip seems to periodically fail when we invoke it from Dart and tell it to 925 // 7zip seems to periodically fail when we invoke it from Dart and tell it to
970 // read from stdin instead of a file. Consider resurrecting that version if 926 // read from stdin instead of a file. Consider resurrecting that version if
971 // we can figure out why it fails. 927 // we can figure out why it fails.
972 928
973 return withTempDir((tempDir) { 929 return withTempDir((tempDir) async {
974 // Write the archive to a temp file. 930 // Write the archive to a temp file.
975 var dataFile = path.join(tempDir, 'data.tar.gz'); 931 var dataFile = path.join(tempDir, 'data.tar.gz');
976 return createFileFromStream(stream, dataFile).then((_) { 932 await createFileFromStream(stream, dataFile);
977 // 7zip can't unarchive from gzip -> tar -> destination all in one step
978 // first we un-gzip it to a tar file.
979 // Note: Setting the working directory instead of passing in a full file
980 // path because 7zip says "A full path is not allowed here."
981 return runProcess(pathTo7zip, ['e', 'data.tar.gz'], workingDir: tempDir);
982 }).then((result) {
983 if (result.exitCode != exit_codes.SUCCESS) {
984 throw new Exception('Could not un-gzip (exit code ${result.exitCode}). '
985 'Error:\n'
986 '${result.stdout.join("\n")}\n'
987 '${result.stderr.join("\n")}');
988 }
989 933
990 // Find the tar file we just created since we don't know its name. 934 // 7zip can't unarchive from gzip -> tar -> destination all in one step
991 var tarFile = listDir(tempDir).firstWhere( 935 // first we un-gzip it to a tar file.
992 (file) => path.extension(file) == '.tar', 936 // Note: Setting the working directory instead of passing in a full file
993 orElse: () { 937 // path because 7zip says "A full path is not allowed here."
994 throw new FormatException('The gzip file did not contain a tar file.'); 938 var unzipResult = await runProcess(pathTo7zip, ['e', 'data.tar.gz'],
995 }); 939 workingDir: tempDir);
996 940
997 // Untar the archive into the destination directory. 941 if (unzipResult.exitCode != exit_codes.SUCCESS) {
998 return runProcess(pathTo7zip, ['x', tarFile], workingDir: destination); 942 throw new Exception(
999 }).then((result) { 943 'Could not un-gzip (exit code ${unzipResult.exitCode}). Error:\n'
1000 if (result.exitCode != exit_codes.SUCCESS) { 944 '${unzipResult.stdout.join("\n")}\n'
1001 throw new Exception('Could not un-tar (exit code ${result.exitCode}). ' 945 '${unzipResult.stderr.join("\n")}');
1002 'Error:\n' 946 }
1003 '${result.stdout.join("\n")}\n' 947
1004 '${result.stderr.join("\n")}'); 948 // Find the tar file we just created since we don't know its name.
1005 } 949 var tarFile = listDir(tempDir).firstWhere(
1006 return true; 950 (file) => path.extension(file) == '.tar',
951 orElse: () {
952 throw new FormatException('The gzip file did not contain a tar file.');
1007 }); 953 });
954
955 // Untar the archive into the destination directory.
956 var untarResult = await runProcess(pathTo7zip, ['x', tarFile],
957 workingDir: destination);
958 if (untarResult.exitCode != exit_codes.SUCCESS) {
959 throw new Exception(
960 'Could not un-tar (exit code ${untarResult.exitCode}). Error:\n'
961 '${untarResult.stdout.join("\n")}\n'
962 '${untarResult.stderr.join("\n")}');
963 }
1008 }); 964 });
1009 } 965 }
1010 966
1011 /// Create a .tar.gz archive from a list of entries. 967 /// Create a .tar.gz archive from a list of entries.
1012 /// 968 ///
1013 /// Each entry can be a [String], [Directory], or [File] object. The root of 969 /// Each entry can be a [String], [Directory], or [File] object. The root of
1014 /// the archive is considered to be [baseDir], which defaults to the current 970 /// the archive is considered to be [baseDir], which defaults to the current
1015 /// working directory. 971 /// working directory.
1016 /// 972 ///
1017 /// Returns a [ByteStream] that emits the contents of the archive. 973 /// Returns a [ByteStream] that emits the contents of the archive.
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1093 1049
1094 // TODO(rnystrom): Remove this and change to returning one string. 1050 // TODO(rnystrom): Remove this and change to returning one string.
1095 static List<String> _toLines(String output) { 1051 static List<String> _toLines(String output) {
1096 var lines = splitLines(output); 1052 var lines = splitLines(output);
1097 if (!lines.isEmpty && lines.last == "") lines.removeLast(); 1053 if (!lines.isEmpty && lines.last == "") lines.removeLast();
1098 return lines; 1054 return lines;
1099 } 1055 }
1100 1056
1101 bool get success => exitCode == exit_codes.SUCCESS; 1057 bool get success => exitCode == exit_codes.SUCCESS;
1102 } 1058 }
OLDNEW
« no previous file with comments | « lib/src/http.dart ('k') | lib/src/source/hosted.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698