OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 package_config.discovery; | 5 library package_config.discovery; |
6 | 6 |
7 import "dart:async"; | 7 import "dart:async"; |
8 import "dart:io"; | 8 import "dart:io"; |
9 import "dart:typed_data" show Uint8List; | 9 import "dart:typed_data" show Uint8List; |
10 | 10 |
(...skipping 10 matching lines...) Expand all Loading... |
21 /// Currently that means the URI must have a `file`, `http` or `https` scheme, | 21 /// Currently that means the URI must have a `file`, `http` or `https` scheme, |
22 /// and that the file can be loaded and its contents parsed correctly. | 22 /// and that the file can be loaded and its contents parsed correctly. |
23 /// | 23 /// |
24 /// If the [loader] is provided, it is used to fetch non-`file` URIs, and | 24 /// If the [loader] is provided, it is used to fetch non-`file` URIs, and |
25 /// it can support other schemes or set up more complex HTTP requests. | 25 /// it can support other schemes or set up more complex HTTP requests. |
26 /// | 26 /// |
27 /// This function can be used to load an explicitly configured package | 27 /// This function can be used to load an explicitly configured package |
28 /// resolution file, for example one specified using a `--packages` | 28 /// resolution file, for example one specified using a `--packages` |
29 /// command-line parameter. | 29 /// command-line parameter. |
30 Future<Packages> loadPackagesFile(Uri packagesFile, | 30 Future<Packages> loadPackagesFile(Uri packagesFile, |
31 {Future<List<int>> loader(Uri uri)}) { | 31 {Future<List<int>> loader(Uri uri)}) async { |
32 Packages parseBytes(List<int> bytes) { | 32 Packages parseBytes(List<int> bytes) { |
33 Map<String, Uri> packageMap = pkgfile.parse(bytes, packagesFile); | 33 Map<String, Uri> packageMap = pkgfile.parse(bytes, packagesFile); |
34 return new MapPackages(packageMap); | 34 return new MapPackages(packageMap); |
35 } | 35 } |
36 if (packagesFile.scheme == "file") { | 36 if (packagesFile.scheme == "file") { |
37 File file = new File.fromUri(packagesFile); | 37 File file = new File.fromUri(packagesFile); |
38 return file.readAsBytes().then(parseBytes); | 38 return parseBytes(await file.readAsBytes()); |
39 } | 39 } |
40 if (loader == null) { | 40 if (loader == null) { |
41 return _httpGet(packagesFile).then(parseBytes); | 41 return parseBytes(await _httpGet(packagesFile)); |
42 } | 42 } |
43 return loader(packagesFile).then(parseBytes); | 43 return parseBytes(await loader(packagesFile)); |
44 } | 44 } |
45 | 45 |
46 | |
47 /// Create a [Packages] object for a package directory. | 46 /// Create a [Packages] object for a package directory. |
48 /// | 47 /// |
49 /// The [packagesDir] URI should refer to a directory. | 48 /// The [packagesDir] URI should refer to a directory. |
50 /// Package names are resolved as relative to sub-directories of the | 49 /// Package names are resolved as relative to sub-directories of the |
51 /// package directory. | 50 /// package directory. |
52 /// | 51 /// |
53 /// This function can be used for explicitly configured package directories, | 52 /// This function can be used for explicitly configured package directories, |
54 /// for example one specified using a `--package-root` comand-line parameter. | 53 /// for example one specified using a `--package-root` comand-line parameter. |
55 Packages getPackagesDirectory(Uri packagesDir) { | 54 Packages getPackagesDirectory(Uri packagesDir) { |
56 if (packagesDir.scheme == "file") { | 55 if (packagesDir.scheme == "file") { |
57 Directory directory = new Directory.fromUri(packagesDir); | 56 Directory directory = new Directory.fromUri(packagesDir); |
58 return new FilePackagesDirectoryPackages(directory); | 57 return new FilePackagesDirectoryPackages(directory); |
59 } | 58 } |
60 if (!packagesDir.path.endsWith('/')) { | 59 if (!packagesDir.path.endsWith('/')) { |
61 packagesDir = packagesDir.replace(path: packagesDir.path + '/'); | 60 packagesDir = packagesDir.replace(path: packagesDir.path + '/'); |
62 } | 61 } |
63 return new NonFilePackagesDirectoryPackages(packagesDir); | 62 return new NonFilePackagesDirectoryPackages(packagesDir); |
64 } | 63 } |
65 | 64 |
66 | |
67 /// Discover the package configuration for a Dart script. | 65 /// Discover the package configuration for a Dart script. |
68 /// | 66 /// |
69 /// The [baseUri] points to either the Dart script or its directory. | 67 /// The [baseUri] points to either the Dart script or its directory. |
70 /// A package resolution strategy is found by going through the following steps, | 68 /// A package resolution strategy is found by going through the following steps, |
71 /// and stopping when something is found. | 69 /// and stopping when something is found. |
72 /// | 70 /// |
73 /// * Check if a `.packages` file exists in the same directory. | 71 /// * Check if a `.packages` file exists in the same directory. |
74 /// * If `baseUri`'s scheme is not `file`, then assume a `packages` directory | 72 /// * If `baseUri`'s scheme is not `file`, then assume a `packages` directory |
75 /// in the same directory, and resolve packages relative to that. | 73 /// in the same directory, and resolve packages relative to that. |
76 /// * If `baseUri`'s scheme *is* `file`: | 74 /// * If `baseUri`'s scheme *is* `file`: |
77 /// * Check if a `packages` directory exists. | 75 /// * Check if a `packages` directory exists. |
78 /// * Otherwise check each successive parent directory of `baseUri` for a | 76 /// * Otherwise check each successive parent directory of `baseUri` for a |
79 /// `.packages` file. | 77 /// `.packages` file. |
80 /// | 78 /// |
81 /// If any of these tests succeed, a `Packages` class is returned. | 79 /// If any of these tests succeed, a `Packages` class is returned. |
82 /// Returns the constant [noPackages] if no resolution strategy is found. | 80 /// Returns the constant [noPackages] if no resolution strategy is found. |
83 /// | 81 /// |
84 /// This function currently only supports `file`, `http` and `https` URIs. | 82 /// This function currently only supports `file`, `http` and `https` URIs. |
85 /// It needs to be able to load a `.packages` file from the URI, so only | 83 /// It needs to be able to load a `.packages` file from the URI, so only |
86 /// recognized schemes are accepted. | 84 /// recognized schemes are accepted. |
87 /// | 85 /// |
88 /// To support other schemes, or more complex HTTP requests, | 86 /// To support other schemes, or more complex HTTP requests, |
89 /// an optional [loader] function can be supplied. | 87 /// an optional [loader] function can be supplied. |
90 /// It's called to load the `.packages` file for a non-`file` scheme. | 88 /// It's called to load the `.packages` file for a non-`file` scheme. |
91 /// The loader function returns the *contents* of the file | 89 /// The loader function returns the *contents* of the file |
92 /// identified by the URI it's given. | 90 /// identified by the URI it's given. |
93 /// The content should be a UTF-8 encoded `.packages` file, and must return an | 91 /// The content should be a UTF-8 encoded `.packages` file, and must return an |
94 /// error future if loading fails for any reason. | 92 /// error future if loading fails for any reason. |
95 Future<Packages> findPackages(Uri baseUri, | 93 Future<Packages> findPackages(Uri baseUri, |
96 {Future<List<int>> loader(Uri unsupportedUri)}) { | 94 {Future<List<int>> loader(Uri unsupportedUri)}) { |
97 if (baseUri.scheme == "file") { | 95 if (baseUri.scheme == "file") { |
98 return new Future<Packages>.sync(() => findPackagesFromFile(baseUri)); | 96 return new Future<Packages>.sync(() => findPackagesFromFile(baseUri)); |
99 } else if (loader != null) { | 97 } else if (loader != null) { |
100 return findPackagesFromNonFile(baseUri, loader: loader); | 98 return findPackagesFromNonFile(baseUri, loader: loader); |
101 } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { | 99 } else if (baseUri.scheme == "http" || baseUri.scheme == "https") { |
102 return findPackagesFromNonFile(baseUri, loader: _httpGet); | 100 return findPackagesFromNonFile(baseUri, loader: _httpGet); |
103 } else { | 101 } else { |
104 return new Future<Packages>.value(Packages.noPackages); | 102 return new Future<Packages>.value(Packages.noPackages); |
105 } | 103 } |
106 } | 104 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 /// This function first tries to locate a `.packages` file in the [nonFileUri] | 182 /// This function first tries to locate a `.packages` file in the [nonFileUri] |
185 /// directory. If that is not found, it instead assumes a `packages/` directory | 183 /// directory. If that is not found, it instead assumes a `packages/` directory |
186 /// in the same place. | 184 /// in the same place. |
187 /// | 185 /// |
188 /// By default, this function only works for `http:` and `https:` URIs. | 186 /// By default, this function only works for `http:` and `https:` URIs. |
189 /// To support other schemes, a loader must be provided, which is used to | 187 /// To support other schemes, a loader must be provided, which is used to |
190 /// try to load the `.packages` file. The loader should return the contents | 188 /// try to load the `.packages` file. The loader should return the contents |
191 /// of the requested `.packages` file as bytes, which will be assumed to be | 189 /// of the requested `.packages` file as bytes, which will be assumed to be |
192 /// UTF-8 encoded. | 190 /// UTF-8 encoded. |
193 Future<Packages> findPackagesFromNonFile(Uri nonFileUri, | 191 Future<Packages> findPackagesFromNonFile(Uri nonFileUri, |
194 {Future<List<int>> loader(Uri name)}) { | 192 {Future<List<int>> loader(Uri name)}) async { |
195 if (loader == null) loader = _httpGet; | 193 if (loader == null) loader = _httpGet; |
196 Uri packagesFileUri = nonFileUri.resolve(".packages"); | 194 Uri packagesFileUri = nonFileUri.resolve(".packages"); |
197 return loader(packagesFileUri).then((List<int> fileBytes) { | 195 |
| 196 try { |
| 197 List<int> fileBytes = await loader(packagesFileUri); |
198 Map<String, Uri> map = pkgfile.parse(fileBytes, packagesFileUri); | 198 Map<String, Uri> map = pkgfile.parse(fileBytes, packagesFileUri); |
199 return new MapPackages(map); | 199 return new MapPackages(map); |
200 }, onError: (_) { | 200 } catch (_) { |
201 // Didn't manage to load ".packages". Assume a "packages/" directory. | 201 // Didn't manage to load ".packages". Assume a "packages/" directory. |
202 Uri packagesDirectoryUri = nonFileUri.resolve("packages/"); | 202 Uri packagesDirectoryUri = nonFileUri.resolve("packages/"); |
203 return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); | 203 return new NonFilePackagesDirectoryPackages(packagesDirectoryUri); |
204 }); | 204 } |
205 } | 205 } |
206 | 206 |
207 /// Fetches a file over http. | 207 /// Fetches a file over http. |
208 Future<List<int>> _httpGet(Uri uri) async { | 208 Future<List<int>> _httpGet(Uri uri) async { |
209 HttpClient client = new HttpClient(); | 209 HttpClient client = new HttpClient(); |
210 HttpClientRequest request = await client.getUrl(uri); | 210 HttpClientRequest request = await client.getUrl(uri); |
211 HttpClientResponse response = await request.close(); | 211 HttpClientResponse response = await request.close(); |
212 if (response.statusCode != HttpStatus.OK) { | 212 if (response.statusCode != HttpStatus.OK) { |
213 throw 'Failure getting $uri: ' | 213 throw 'Failure getting $uri: ' |
214 '${response.statusCode} ${response.reasonPhrase}'; | 214 '${response.statusCode} ${response.reasonPhrase}'; |
215 } | 215 } |
216 List<List<int>> splitContent = await response.toList(); | 216 List<List<int>> splitContent = await response.toList(); |
217 int totalLength = 0; | 217 int totalLength = 0; |
218 for (var list in splitContent) { | 218 for (var list in splitContent) { |
219 totalLength += list.length; | 219 totalLength += list.length; |
220 } | 220 } |
221 Uint8List result = new Uint8List(totalLength); | 221 Uint8List result = new Uint8List(totalLength); |
222 int offset = 0; | 222 int offset = 0; |
223 for (List<int> contentPart in splitContent) { | 223 for (List<int> contentPart in splitContent) { |
224 result.setRange(offset, offset + contentPart.length, contentPart); | 224 result.setRange(offset, offset + contentPart.length, contentPart); |
225 offset += contentPart.length; | 225 offset += contentPart.length; |
226 } | 226 } |
227 return result; | 227 return result; |
228 } | 228 } |
OLD | NEW |