OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 analyzer.src.context.context_builder; | 5 library analyzer.src.context.context_builder; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'dart:core' hide Resource; | 8 import 'dart:core' hide Resource; |
9 | 9 |
10 import 'package:analyzer/context/declared_variables.dart'; | 10 import 'package:analyzer/context/declared_variables.dart'; |
11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/plugin/options.dart'; |
12 import 'package:analyzer/plugin/resolver_provider.dart'; | 13 import 'package:analyzer/plugin/resolver_provider.dart'; |
13 import 'package:analyzer/source/analysis_options_provider.dart'; | 14 import 'package:analyzer/source/analysis_options_provider.dart'; |
14 import 'package:analyzer/source/package_map_resolver.dart'; | 15 import 'package:analyzer/source/package_map_resolver.dart'; |
15 import 'package:analyzer/src/dart/sdk/sdk.dart'; | 16 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
16 import 'package:analyzer/src/generated/engine.dart'; | 17 import 'package:analyzer/src/generated/engine.dart'; |
17 import 'package:analyzer/src/generated/sdk.dart'; | 18 import 'package:analyzer/src/generated/sdk.dart'; |
18 import 'package:analyzer/src/generated/source.dart'; | 19 import 'package:analyzer/src/generated/source.dart'; |
19 import 'package:analyzer/src/task/options.dart'; | 20 import 'package:analyzer/src/task/options.dart'; |
20 import 'package:package_config/packages.dart'; | 21 import 'package:package_config/packages.dart'; |
21 import 'package:package_config/packages_file.dart'; | 22 import 'package:package_config/packages_file.dart'; |
22 import 'package:package_config/src/packages_impl.dart'; | 23 import 'package:package_config/src/packages_impl.dart'; |
| 24 import 'package:path/src/context.dart'; |
23 import 'package:yaml/yaml.dart'; | 25 import 'package:yaml/yaml.dart'; |
24 | 26 |
25 /** | 27 /** |
26 * A utility class used to build an analysis context for a given directory. | 28 * A utility class used to build an analysis context for a given directory. |
27 * | 29 * |
28 * The construction of analysis contexts is as follows: | 30 * The construction of analysis contexts is as follows: |
29 * | 31 * |
30 * 1. Determine how package: URI's are to be resolved. This follows the lookup | 32 * 1. Determine how package: URI's are to be resolved. This follows the lookup |
31 * algorithm defined by the [package specification][1]. | 33 * algorithm defined by the [package specification][1]. |
32 * | 34 * |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 */ | 116 */ |
115 ContextBuilder(this.resourceProvider, this.sdkManager, this.contentCache); | 117 ContextBuilder(this.resourceProvider, this.sdkManager, this.contentCache); |
116 | 118 |
117 /** | 119 /** |
118 * Return an analysis context that is configured correctly to analyze code in | 120 * Return an analysis context that is configured correctly to analyze code in |
119 * the directory with the given [path]. | 121 * the directory with the given [path]. |
120 * | 122 * |
121 * *Note:* This method is not yet fully implemented and should not be used. | 123 * *Note:* This method is not yet fully implemented and should not be used. |
122 */ | 124 */ |
123 AnalysisContext buildContext(String path) { | 125 AnalysisContext buildContext(String path) { |
124 // TODO(brianwilkerson) Split getAnalysisOptions so we can capture the | |
125 // option map and use it to run the options processors. | |
126 AnalysisOptions options = getAnalysisOptions(path); | |
127 InternalAnalysisContext context = | 126 InternalAnalysisContext context = |
128 AnalysisEngine.instance.createAnalysisContext(); | 127 AnalysisEngine.instance.createAnalysisContext(); |
| 128 AnalysisOptions options = getAnalysisOptions(context, path); |
129 context.contentCache = contentCache; | 129 context.contentCache = contentCache; |
130 context.sourceFactory = createSourceFactory(path, options); | 130 context.sourceFactory = createSourceFactory(path, options); |
131 context.analysisOptions = options; | 131 context.analysisOptions = options; |
132 //_processAnalysisOptions(context, optionMap); | 132 //_processAnalysisOptions(context, optionMap); |
133 declareVariables(context); | 133 declareVariables(context); |
134 return context; | 134 return context; |
135 } | 135 } |
136 | 136 |
137 Map<String, List<Folder>> convertPackagesToMap(Packages packages) { | 137 Map<String, List<Folder>> convertPackagesToMap(Packages packages) { |
138 if (packages == null || packages == Packages.noPackages) { | 138 if (packages == null || packages == Packages.noPackages) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 return new AnalysisOptionsImpl(); | 177 return new AnalysisOptionsImpl(); |
178 } | 178 } |
179 return new AnalysisOptionsImpl.from(defaultOptions); | 179 return new AnalysisOptionsImpl.from(defaultOptions); |
180 } | 180 } |
181 | 181 |
182 Packages createPackageMap(String rootDirectoryPath) { | 182 Packages createPackageMap(String rootDirectoryPath) { |
183 if (defaultPackageFilePath != null) { | 183 if (defaultPackageFilePath != null) { |
184 File configFile = resourceProvider.getFile(defaultPackageFilePath); | 184 File configFile = resourceProvider.getFile(defaultPackageFilePath); |
185 List<int> bytes = configFile.readAsBytesSync(); | 185 List<int> bytes = configFile.readAsBytesSync(); |
186 Map<String, Uri> map = parse(bytes, configFile.toUri()); | 186 Map<String, Uri> map = parse(bytes, configFile.toUri()); |
| 187 resolveSymbolicLinks(map); |
187 return new MapPackages(map); | 188 return new MapPackages(map); |
188 } else if (defaultPackagesDirectoryPath != null) { | 189 } else if (defaultPackagesDirectoryPath != null) { |
189 Folder folder = resourceProvider.getFolder(defaultPackagesDirectoryPath); | 190 Folder folder = resourceProvider.getFolder(defaultPackagesDirectoryPath); |
190 return getPackagesFromFolder(folder); | 191 return getPackagesFromFolder(folder); |
191 } | 192 } |
192 return findPackagesFromFile(rootDirectoryPath); | 193 return findPackagesFromFile(rootDirectoryPath); |
193 } | 194 } |
194 | 195 |
195 SourceFactory createSourceFactory( | 196 SourceFactory createSourceFactory( |
196 String rootDirectoryPath, AnalysisOptions options) { | 197 String rootDirectoryPath, AnalysisOptions options) { |
(...skipping 11 matching lines...) Expand all Loading... |
208 UriResolver packageResolver = packageResolverProvider(folder()); | 209 UriResolver packageResolver = packageResolverProvider(folder()); |
209 if (packageResolver != null) { | 210 if (packageResolver != null) { |
210 // TODO(brianwilkerson) This doesn't support either embedder files or | 211 // TODO(brianwilkerson) This doesn't support either embedder files or |
211 // sdk extensions because we don't have a way to get the package map | 212 // sdk extensions because we don't have a way to get the package map |
212 // from the resolver. | 213 // from the resolver. |
213 List<UriResolver> resolvers = <UriResolver>[ | 214 List<UriResolver> resolvers = <UriResolver>[ |
214 new DartUriResolver(findSdk(null, options)), | 215 new DartUriResolver(findSdk(null, options)), |
215 packageResolver, | 216 packageResolver, |
216 fileResolver | 217 fileResolver |
217 ]; | 218 ]; |
218 return new SourceFactory(resolvers); | 219 return new SourceFactory(resolvers, null, resourceProvider); |
219 } | 220 } |
220 } | 221 } |
221 Packages packages = createPackageMap(rootDirectoryPath); | 222 Packages packages = createPackageMap(rootDirectoryPath); |
222 Map<String, List<Folder>> packageMap = convertPackagesToMap(packages); | 223 Map<String, List<Folder>> packageMap = convertPackagesToMap(packages); |
223 List<UriResolver> resolvers = <UriResolver>[]; | 224 List<UriResolver> resolvers = <UriResolver>[]; |
224 resolvers.add(new DartUriResolver(findSdk(packageMap, options))); | 225 resolvers.add(new DartUriResolver(findSdk(packageMap, options))); |
225 if (packageMap != null) { | 226 if (packageMap != null) { |
226 // TODO(brianwilkerson) I think that we don't need a PackageUriResolver | 227 // TODO(brianwilkerson) I think that we don't need a PackageUriResolver |
227 // when we can pass the packages object to the source factory directly. | 228 // when we can pass the packages object to the source factory directly. |
| 229 // Actually, I think we're using it to restoreUri, which could lead to |
| 230 // inconsistencies. |
228 resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap)); | 231 resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap)); |
229 } | 232 } |
230 resolvers.add(fileResolver); | 233 resolvers.add(fileResolver); |
231 return new SourceFactory(resolvers); | 234 return new SourceFactory(resolvers, packages, resourceProvider); |
232 } | 235 } |
233 | 236 |
234 /** | 237 /** |
235 * Add any [declaredVariables] to the list of declared variables used by the | 238 * Add any [declaredVariables] to the list of declared variables used by the |
236 * given [context]. | 239 * given [context]. |
237 */ | 240 */ |
238 void declareVariables(InternalAnalysisContext context) { | 241 void declareVariables(InternalAnalysisContext context) { |
239 if (declaredVariables != null && declaredVariables.isNotEmpty) { | 242 if (declaredVariables != null && declaredVariables.isNotEmpty) { |
240 DeclaredVariables contextVariables = context.declaredVariables; | 243 DeclaredVariables contextVariables = context.declaredVariables; |
241 declaredVariables.forEach((String variableName, String value) { | 244 declaredVariables.forEach((String variableName, String value) { |
(...skipping 11 matching lines...) Expand all Loading... |
253 * directory in the same place. If that also fails, it starts checking parent | 256 * directory in the same place. If that also fails, it starts checking parent |
254 * directories for a `.packages` file, and stops if it finds it. Otherwise it | 257 * directories for a `.packages` file, and stops if it finds it. Otherwise it |
255 * gives up and returns [Packages.noPackages]. | 258 * gives up and returns [Packages.noPackages]. |
256 */ | 259 */ |
257 Packages findPackagesFromFile(String path) { | 260 Packages findPackagesFromFile(String path) { |
258 Resource location = _findPackagesLocation(path); | 261 Resource location = _findPackagesLocation(path); |
259 if (location is File) { | 262 if (location is File) { |
260 List<int> fileBytes = location.readAsBytesSync(); | 263 List<int> fileBytes = location.readAsBytesSync(); |
261 Map<String, Uri> map = | 264 Map<String, Uri> map = |
262 parse(fileBytes, resourceProvider.pathContext.toUri(location.path)); | 265 parse(fileBytes, resourceProvider.pathContext.toUri(location.path)); |
| 266 resolveSymbolicLinks(map); |
263 return new MapPackages(map); | 267 return new MapPackages(map); |
264 } else if (location is Folder) { | 268 } else if (location is Folder) { |
265 return getPackagesFromFolder(location); | 269 return getPackagesFromFolder(location); |
266 } | 270 } |
267 return Packages.noPackages; | 271 return Packages.noPackages; |
268 } | 272 } |
269 | 273 |
270 /** | 274 /** |
271 * Return the SDK that should be used to analyze code. Use the given | 275 * Return the SDK that should be used to analyze code. Use the given |
272 * [packageMap] and [options] to locate the SDK. | 276 * [packageMap] and [options] to locate the SDK. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 return sdkManager.getSdk(description, () { | 331 return sdkManager.getSdk(description, () { |
328 FolderBasedDartSdk sdk = new FolderBasedDartSdk( | 332 FolderBasedDartSdk sdk = new FolderBasedDartSdk( |
329 resourceProvider, resourceProvider.getFolder(sdkPath)); | 333 resourceProvider, resourceProvider.getFolder(sdkPath)); |
330 sdk.analysisOptions = options; | 334 sdk.analysisOptions = options; |
331 sdk.useSummary = sdkManager.canUseSummaries; | 335 sdk.useSummary = sdkManager.canUseSummaries; |
332 return sdk; | 336 return sdk; |
333 }); | 337 }); |
334 } | 338 } |
335 | 339 |
336 /** | 340 /** |
337 * Return the analysis options that should be used when analyzing code in the | 341 * Return the analysis options that should be used when the given [context] is |
338 * directory with the given [path]. | 342 * used to analyze code in the directory with the given [path]. |
339 */ | 343 */ |
340 AnalysisOptions getAnalysisOptions(String path) { | 344 AnalysisOptions getAnalysisOptions(AnalysisContext context, String path) { |
341 AnalysisOptionsImpl options = createDefaultOptions(); | 345 AnalysisOptionsImpl options = createDefaultOptions(); |
342 File optionsFile = getOptionsFile(path); | 346 File optionsFile = getOptionsFile(path); |
343 if (optionsFile != null) { | 347 if (optionsFile != null) { |
344 Map<String, YamlNode> fileOptions = | 348 List<OptionsProcessor> optionsProcessors = |
345 new AnalysisOptionsProvider().getOptionsFromFile(optionsFile); | 349 AnalysisEngine.instance.optionsPlugin.optionsProcessors; |
346 applyToAnalysisOptions(options, fileOptions); | 350 try { |
| 351 Map<String, YamlNode> optionMap = |
| 352 new AnalysisOptionsProvider().getOptionsFromFile(optionsFile); |
| 353 optionsProcessors.forEach( |
| 354 (OptionsProcessor p) => p.optionsProcessed(context, optionMap)); |
| 355 applyToAnalysisOptions(options, optionMap); |
| 356 } on Exception catch (exception) { |
| 357 optionsProcessors.forEach((OptionsProcessor p) => p.onError(exception)); |
| 358 } |
347 } | 359 } |
348 return options; | 360 return options; |
349 } | 361 } |
350 | 362 |
351 /** | 363 /** |
352 * Return the analysis options file that should be used when analyzing code in | 364 * Return the analysis options file that should be used when analyzing code in |
353 * the directory with the given [path]. | 365 * the directory with the given [path]. |
354 */ | 366 */ |
355 File getOptionsFile(String path) { | 367 File getOptionsFile(String path) { |
356 if (defaultAnalysisOptionsFilePath != null) { | 368 if (defaultAnalysisOptionsFilePath != null) { |
(...skipping 15 matching lines...) Expand all Loading... |
372 return null; | 384 return null; |
373 } | 385 } |
374 | 386 |
375 /** | 387 /** |
376 * Create a [Packages] object for a 'package' directory ([folder]). | 388 * Create a [Packages] object for a 'package' directory ([folder]). |
377 * | 389 * |
378 * Package names are resolved as relative to sub-directories of the package | 390 * Package names are resolved as relative to sub-directories of the package |
379 * directory. | 391 * directory. |
380 */ | 392 */ |
381 Packages getPackagesFromFolder(Folder folder) { | 393 Packages getPackagesFromFolder(Folder folder) { |
| 394 Context pathContext = resourceProvider.pathContext; |
382 Map<String, Uri> map = new HashMap<String, Uri>(); | 395 Map<String, Uri> map = new HashMap<String, Uri>(); |
383 for (Resource child in folder.getChildren()) { | 396 for (Resource child in folder.getChildren()) { |
384 if (child is Folder) { | 397 if (child is Folder) { |
385 String packageName = resourceProvider.pathContext.basename(child.path); | 398 // Inline resolveSymbolicLinks for performance reasons. |
386 // Create a file URI (rather than a directory URI) and add a '.' so that | 399 String packageName = pathContext.basename(child.path); |
387 // the URI is suitable for resolving relative URI's against it. | 400 String folderPath = resolveSymbolicLink(child); |
388 // | 401 String uriPath = pathContext.join(folderPath, '.'); |
389 // TODO(brianwilkerson) Decide whether we need to pass in a 'windows:' | 402 map[packageName] = pathContext.toUri(uriPath); |
390 // argument for testing purposes. | |
391 map[packageName] = resourceProvider.pathContext.toUri( | |
392 resourceProvider.pathContext.join(folder.path, packageName, '.')); | |
393 } | 403 } |
394 } | 404 } |
395 return new MapPackages(map); | 405 return new MapPackages(map); |
396 } | 406 } |
397 | 407 |
398 /** | 408 /** |
| 409 * Resolve any symbolic links encoded in the path to the given [folder]. |
| 410 */ |
| 411 String resolveSymbolicLink(Folder folder) { |
| 412 try { |
| 413 return folder.resolveSymbolicLinksSync().path; |
| 414 } on FileSystemException { |
| 415 return folder.path; |
| 416 } |
| 417 } |
| 418 |
| 419 /** |
| 420 * Resolve any symbolic links encoded in the URI's in the given [map] by |
| 421 * replacing the values in the map. |
| 422 */ |
| 423 void resolveSymbolicLinks(Map<String, Uri> map) { |
| 424 Context pathContext = resourceProvider.pathContext; |
| 425 for (String packageName in map.keys) { |
| 426 Folder folder = |
| 427 resourceProvider.getFolder(pathContext.fromUri(map[packageName])); |
| 428 String folderPath = resolveSymbolicLink(folder); |
| 429 // Add a '.' so that the URI is suitable for resolving relative URI's |
| 430 // against it. |
| 431 String uriPath = pathContext.join(folderPath, '.'); |
| 432 map[packageName] = pathContext.toUri(uriPath); |
| 433 } |
| 434 } |
| 435 |
| 436 /** |
399 * Find the location of the package resolution file/directory for the | 437 * Find the location of the package resolution file/directory for the |
400 * directory at the given absolute [path]. | 438 * directory at the given absolute [path]. |
401 * | 439 * |
402 * Checks for a `.packages` file in the [path]. If not found, | 440 * Checks for a `.packages` file in the [path]. If not found, |
403 * checks for a `packages` directory in the same directory. If still not | 441 * checks for a `packages` directory in the same directory. If still not |
404 * found, starts checking parent directories for `.packages` until reaching | 442 * found, starts checking parent directories for `.packages` until reaching |
405 * the root directory. | 443 * the root directory. |
406 * | 444 * |
407 * Return a [File] object representing a `.packages` file if one is found, a | 445 * Return a [File] object representing a `.packages` file if one is found, a |
408 * [Folder] object for the `packages/` directory if that is found, or `null` | 446 * [Folder] object for the `packages/` directory if that is found, or `null` |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 String _readEmbedderYaml(Folder libDir) { | 569 String _readEmbedderYaml(Folder libDir) { |
532 File file = libDir.getChild(EMBEDDER_FILE_NAME); | 570 File file = libDir.getChild(EMBEDDER_FILE_NAME); |
533 try { | 571 try { |
534 return file.readAsStringSync(); | 572 return file.readAsStringSync(); |
535 } on FileSystemException { | 573 } on FileSystemException { |
536 // File can't be read. | 574 // File can't be read. |
537 return null; | 575 return null; |
538 } | 576 } |
539 } | 577 } |
540 } | 578 } |
OLD | NEW |