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 library pub.source.hosted; | 5 library pub.source.hosted; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:io' as io; | 8 import 'dart:io' as io; |
9 import "dart:convert"; | 9 import "dart:convert"; |
10 | 10 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 var parsed = _parseDescription(id.description); | 75 var parsed = _parseDescription(id.description); |
76 _throwFriendlyError(error, stackTrace, id.name, parsed.last); | 76 _throwFriendlyError(error, stackTrace, id.name, parsed.last); |
77 } | 77 } |
78 | 78 |
79 return new Pubspec.fromMap( | 79 return new Pubspec.fromMap( |
80 version['pubspec'], systemCache.sources, | 80 version['pubspec'], systemCache.sources, |
81 expectedName: id.name, location: url); | 81 expectedName: id.name, location: url); |
82 } | 82 } |
83 | 83 |
84 /// Downloads the package identified by [id] to the system cache. | 84 /// Downloads the package identified by [id] to the system cache. |
85 Future<Package> downloadToSystemCache(PackageId id) { | 85 Future<Package> downloadToSystemCache(PackageId id) async { |
86 return isInSystemCache(id).then((inCache) { | 86 if (!(await isInSystemCache(id))) { |
87 // Already cached so don't download it. | |
88 if (inCache) return true; | |
89 | |
90 var packageDir = _getDirectory(id); | 87 var packageDir = _getDirectory(id); |
91 ensureDir(path.dirname(packageDir)); | 88 ensureDir(path.dirname(packageDir)); |
92 var parsed = _parseDescription(id.description); | 89 var parsed = _parseDescription(id.description); |
93 return _download(parsed.last, parsed.first, id.version, packageDir); | 90 await _download(parsed.last, parsed.first, id.version, packageDir); |
94 }).then((found) { | 91 } |
95 if (!found) fail('Package $id not found.'); | 92 |
96 return new Package.load(id.name, _getDirectory(id), systemCache.sources); | 93 return new Package.load(id.name, _getDirectory(id), systemCache.sources); |
97 }); | |
98 } | 94 } |
99 | 95 |
100 /// The system cache directory for the hosted source contains subdirectories | 96 /// The system cache directory for the hosted source contains subdirectories |
101 /// for each separate repository URL that's used on the system. | 97 /// for each separate repository URL that's used on the system. |
102 /// | 98 /// |
103 /// Each of these subdirectories then contains a subdirectory for each | 99 /// Each of these subdirectories then contains a subdirectory for each |
104 /// package downloaded from that site. | 100 /// package downloaded from that site. |
105 Future<String> getDirectory(PackageId id) => | 101 Future<String> getDirectory(PackageId id) => |
106 new Future.value(_getDirectory(id)); | 102 new Future.value(_getDirectory(id)); |
107 | 103 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 var cacheDir = path.join(systemCacheRoot, dir); | 168 var cacheDir = path.join(systemCacheRoot, dir); |
173 if (!dirExists(cacheDir)) return []; | 169 if (!dirExists(cacheDir)) return []; |
174 | 170 |
175 return listDir(cacheDir) | 171 return listDir(cacheDir) |
176 .map((entry) => new Package.load(null, entry, systemCache.sources)) | 172 .map((entry) => new Package.load(null, entry, systemCache.sources)) |
177 .toList(); | 173 .toList(); |
178 } | 174 } |
179 | 175 |
180 /// Downloads package [package] at [version] from [server], and unpacks it | 176 /// Downloads package [package] at [version] from [server], and unpacks it |
181 /// into [destPath]. | 177 /// into [destPath]. |
182 Future<bool> _download(String server, String package, Version version, | 178 Future _download(String server, String package, Version version, |
183 String destPath) { | 179 String destPath) async { |
184 return new Future.sync(() { | 180 var url = Uri.parse("$server/packages/$package/versions/$version.tar.gz"); |
185 var url = Uri.parse("$server/packages/$package/versions/$version.tar.gz"); | 181 log.io("Get package from $url."); |
186 log.io("Get package from $url."); | 182 log.message('Downloading ${log.bold(package)} ${version}...'); |
187 log.message('Downloading ${log.bold(package)} ${version}...'); | |
188 | 183 |
189 // Download and extract the archive to a temp directory. | 184 // Download and extract the archive to a temp directory. |
190 var tempDir = systemCache.createTempDir(); | 185 var tempDir = systemCache.createTempDir(); |
191 return httpClient.send(new http.Request("GET", url)) | 186 var response = await httpClient.send(new http.Request("GET", url)); |
192 .then((response) => response.stream) | 187 await extractTarGz(response.stream, tempDir); |
193 .then((stream) { | |
194 return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT, url, | |
195 'downloading $url'); | |
196 }).then((_) { | |
197 // Remove the existing directory if it exists. This will happen if | |
198 // we're forcing a download to repair the cache. | |
199 if (dirExists(destPath)) deleteEntry(destPath); | |
200 | 188 |
201 // Now that the get has succeeded, move it to the real location in the | 189 // Remove the existing directory if it exists. This will happen if |
202 // cache. This ensures that we don't leave half-busted ghost | 190 // we're forcing a download to repair the cache. |
203 // directories in the user's pub cache if a get fails. | 191 if (dirExists(destPath)) deleteEntry(destPath); |
204 renameDir(tempDir, destPath); | 192 |
205 return true; | 193 // Now that the get has succeeded, move it to the real location in the |
206 }); | 194 // cache. This ensures that we don't leave half-busted ghost |
207 }); | 195 // directories in the user's pub cache if a get fails. |
| 196 renameDir(tempDir, destPath); |
208 } | 197 } |
209 | 198 |
210 /// When an error occurs trying to read something about [package] from [url], | 199 /// When an error occurs trying to read something about [package] from [url], |
211 /// this tries to translate into a more user friendly error message. | 200 /// this tries to translate into a more user friendly error message. |
212 /// | 201 /// |
213 /// Always throws an error, either the original one or a better one. | 202 /// Always throws an error, either the original one or a better one. |
214 void _throwFriendlyError(error, StackTrace stackTrace, String package, | 203 void _throwFriendlyError(error, StackTrace stackTrace, String package, |
215 String url) { | 204 String url) { |
216 if (error is PubHttpException && | 205 if (error is PubHttpException && |
217 error.response.statusCode == 404) { | 206 error.response.statusCode == 404) { |
218 throw new PackageNotFoundException( | 207 throw new PackageNotFoundException( |
219 "Could not find package $package at $url.", error, stackTrace); | 208 "Could not find package $package at $url.", error, stackTrace); |
220 } | 209 } |
221 | 210 |
222 if (error is TimeoutException) { | |
223 fail("Timed out trying to find package $package at $url.", | |
224 error, stackTrace); | |
225 } | |
226 | |
227 if (error is io.SocketException) { | 211 if (error is io.SocketException) { |
228 fail("Got socket error trying to find package $package at $url.", | 212 fail("Got socket error trying to find package $package at $url.", |
229 error, stackTrace); | 213 error, stackTrace); |
230 } | 214 } |
231 | 215 |
232 // Otherwise re-throw the original exception. | 216 // Otherwise re-throw the original exception. |
233 throw error; | 217 throw error; |
234 } | 218 } |
235 } | 219 } |
236 | 220 |
(...skipping 16 matching lines...) Expand all Loading... |
253 | 237 |
254 // If there are no versions in the cache, report a clearer error. | 238 // If there are no versions in the cache, report a clearer error. |
255 if (versions.isEmpty) { | 239 if (versions.isEmpty) { |
256 throw new PackageNotFoundException( | 240 throw new PackageNotFoundException( |
257 "Could not find package $name in cache."); | 241 "Could not find package $name in cache."); |
258 } | 242 } |
259 | 243 |
260 return versions; | 244 return versions; |
261 } | 245 } |
262 | 246 |
263 Future<bool> _download(String server, String package, Version version, | 247 Future _download(String server, String package, Version version, |
264 String destPath) { | 248 String destPath) { |
265 // Since HostedSource is cached, this will only be called for uncached | 249 // Since HostedSource is cached, this will only be called for uncached |
266 // packages. | 250 // packages. |
267 throw new UnsupportedError("Cannot download packages when offline."); | 251 throw new UnsupportedError("Cannot download packages when offline."); |
268 } | 252 } |
269 | 253 |
270 Future<Pubspec> describeUncached(PackageId id) { | 254 Future<Pubspec> describeUncached(PackageId id) { |
271 throw new PackageNotFoundException( | 255 throw new PackageNotFoundException( |
272 "${id.name} ${id.version} is not available in your system cache."); | 256 "${id.name} ${id.version} is not available in your system cache."); |
273 } | 257 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 var name = description["name"]; | 347 var name = description["name"]; |
364 if (name is! String) { | 348 if (name is! String) { |
365 throw new FormatException("The 'name' key must have a string value."); | 349 throw new FormatException("The 'name' key must have a string value."); |
366 } | 350 } |
367 | 351 |
368 var url = description["url"]; | 352 var url = description["url"]; |
369 if (url == null) url = HostedSource.defaultUrl; | 353 if (url == null) url = HostedSource.defaultUrl; |
370 | 354 |
371 return new Pair<String, String>(name, url); | 355 return new Pair<String, String>(name, url); |
372 } | 356 } |
OLD | NEW |