| 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 |