| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library analyzer.src.context.context_builder; |
| 6 |
| 7 import 'dart:collection'; |
| 8 import 'dart:core'; |
| 9 |
| 10 import 'package:analyzer/context/declared_variables.dart'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/plugin/options.dart'; |
| 13 import 'package:analyzer/plugin/resolver_provider.dart'; |
| 14 import 'package:analyzer/source/analysis_options_provider.dart'; |
| 15 import 'package:analyzer/source/package_map_resolver.dart'; |
| 16 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| 17 import 'package:analyzer/src/generated/engine.dart'; |
| 18 import 'package:analyzer/src/generated/sdk.dart'; |
| 19 import 'package:analyzer/src/generated/source.dart'; |
| 20 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| 21 import 'package:analyzer/src/summary/pub_summary.dart'; |
| 22 import 'package:analyzer/src/task/options.dart'; |
| 23 import 'package:package_config/packages.dart'; |
| 24 import 'package:package_config/packages_file.dart'; |
| 25 import 'package:package_config/src/packages_impl.dart'; |
| 26 import 'package:path/src/context.dart'; |
| 27 import 'package:yaml/yaml.dart'; |
| 28 |
| 29 /** |
| 30 * A utility class used to build an analysis context for a given directory. |
| 31 * |
| 32 * The construction of analysis contexts is as follows: |
| 33 * |
| 34 * 1. Determine how package: URI's are to be resolved. This follows the lookup |
| 35 * algorithm defined by the [package specification][1]. |
| 36 * |
| 37 * 2. Using the results of step 1, look in each package for an embedder file |
| 38 * (_embedder.yaml). If one exists then it defines the SDK. If multiple such |
| 39 * files exist then use the first one found. Otherwise, use the default SDK. |
| 40 * |
| 41 * 3. Look in each package for an SDK extension file (_sdkext). For each such |
| 42 * file, add the specified files to the SDK. |
| 43 * |
| 44 * 4. Look for an analysis options file (`analyis_options.yaml` or |
| 45 * `.analysis_options`) and process the options in the file. |
| 46 * |
| 47 * 5. Create a new context. Initialize its source factory based on steps 1, 2 |
| 48 * and 3. Initialize its analysis options from step 4. |
| 49 * |
| 50 * [1]: https://github.com/dart-lang/dart_enhancement_proposals/blob/master/Acce
pted/0005%20-%20Package%20Specification/DEP-pkgspec.md. |
| 51 */ |
| 52 class ContextBuilder { |
| 53 /** |
| 54 * The [ResourceProvider] by which paths are converted into [Resource]s. |
| 55 */ |
| 56 final ResourceProvider resourceProvider; |
| 57 |
| 58 /** |
| 59 * The manager used to manage the DartSdk's that have been created so that |
| 60 * they can be shared across contexts. |
| 61 */ |
| 62 final DartSdkManager sdkManager; |
| 63 |
| 64 /** |
| 65 * The cache containing the contents of overlaid files. |
| 66 */ |
| 67 final ContentCache contentCache; |
| 68 |
| 69 /** |
| 70 * The resolver provider used to create a package: URI resolver, or `null` if |
| 71 * the normal (Package Specification DEP) lookup mechanism is to be used. |
| 72 */ |
| 73 ResolverProvider packageResolverProvider; |
| 74 |
| 75 /** |
| 76 * The resolver provider used to create a file: URI resolver, or `null` if |
| 77 * the normal file URI resolver is to be used. |
| 78 */ |
| 79 ResolverProvider fileResolverProvider; |
| 80 |
| 81 /** |
| 82 * The file path of the .packages file that should be used in place of any |
| 83 * file found using the normal (Package Specification DEP) lookup mechanism, |
| 84 * or `null` if the normal lookup mechanism should be used. |
| 85 */ |
| 86 String defaultPackageFilePath; |
| 87 |
| 88 /** |
| 89 * The file path of the packages directory that should be used in place of any |
| 90 * file found using the normal (Package Specification DEP) lookup mechanism, |
| 91 * or `null` if the normal lookup mechanism should be used. |
| 92 */ |
| 93 String defaultPackagesDirectoryPath; |
| 94 |
| 95 /** |
| 96 * The file path of the analysis options file that should be used in place of |
| 97 * any file in the root directory or a parent of the root directory, or `null` |
| 98 * if the normal lookup mechanism should be used. |
| 99 */ |
| 100 String defaultAnalysisOptionsFilePath; |
| 101 |
| 102 /** |
| 103 * The default analysis options that should be used unless some or all of them |
| 104 * are overridden in the analysis options file, or `null` if the default |
| 105 * defaults should be used. |
| 106 */ |
| 107 AnalysisOptions defaultOptions; |
| 108 |
| 109 /** |
| 110 * A table mapping variable names to values for the declared variables, or |
| 111 * `null` if no additional variables should be declared. |
| 112 */ |
| 113 Map<String, String> declaredVariables; |
| 114 |
| 115 /** |
| 116 * The manager of pub package summaries. |
| 117 */ |
| 118 PubSummaryManager pubSummaryManager; |
| 119 |
| 120 /** |
| 121 * Initialize a newly created builder to be ready to build a context rooted in |
| 122 * the directory with the given [rootDirectoryPath]. |
| 123 */ |
| 124 ContextBuilder(this.resourceProvider, this.sdkManager, this.contentCache); |
| 125 |
| 126 /** |
| 127 * Return an analysis context that is configured correctly to analyze code in |
| 128 * the directory with the given [path]. |
| 129 * |
| 130 * *Note:* This method is not yet fully implemented and should not be used. |
| 131 */ |
| 132 AnalysisContext buildContext(String path) { |
| 133 InternalAnalysisContext context = |
| 134 AnalysisEngine.instance.createAnalysisContext(); |
| 135 AnalysisOptions options = getAnalysisOptions(context, path); |
| 136 context.contentCache = contentCache; |
| 137 context.sourceFactory = createSourceFactory(path, options); |
| 138 context.analysisOptions = options; |
| 139 context.name = path; |
| 140 //_processAnalysisOptions(context, optionMap); |
| 141 declareVariables(context); |
| 142 configureSummaries(context); |
| 143 return context; |
| 144 } |
| 145 |
| 146 /** |
| 147 * Configure the context to make use of summaries. |
| 148 */ |
| 149 void configureSummaries(InternalAnalysisContext context) { |
| 150 if (pubSummaryManager != null) { |
| 151 List<LinkedPubPackage> linkedBundles = |
| 152 pubSummaryManager.getLinkedBundles(context); |
| 153 if (linkedBundles.isNotEmpty) { |
| 154 SummaryDataStore store = new SummaryDataStore([]); |
| 155 for (LinkedPubPackage package in linkedBundles) { |
| 156 store.addBundle(null, package.unlinked); |
| 157 store.addBundle(null, package.linked); |
| 158 } |
| 159 context.resultProvider = |
| 160 new InputPackagesResultProvider(context, store); |
| 161 } |
| 162 } |
| 163 } |
| 164 |
| 165 Map<String, List<Folder>> convertPackagesToMap(Packages packages) { |
| 166 Map<String, List<Folder>> folderMap = new HashMap<String, List<Folder>>(); |
| 167 if (packages != null && packages != Packages.noPackages) { |
| 168 packages.asMap().forEach((String packageName, Uri uri) { |
| 169 String path = resourceProvider.pathContext.fromUri(uri); |
| 170 folderMap[packageName] = [resourceProvider.getFolder(path)]; |
| 171 }); |
| 172 } |
| 173 return folderMap; |
| 174 } |
| 175 |
| 176 // void _processAnalysisOptions( |
| 177 // AnalysisContext context, Map<String, YamlNode> optionMap) { |
| 178 // List<OptionsProcessor> optionsProcessors = |
| 179 // AnalysisEngine.instance.optionsPlugin.optionsProcessors; |
| 180 // try { |
| 181 // optionsProcessors.forEach( |
| 182 // (OptionsProcessor p) => p.optionsProcessed(context, optionMap)); |
| 183 // |
| 184 // // Fill in lint rule defaults in case lints are enabled and rules are |
| 185 // // not specified in an options file. |
| 186 // if (context.analysisOptions.lint && !containsLintRuleEntry(optionMap)) { |
| 187 // setLints(context, linterPlugin.contributedRules); |
| 188 // } |
| 189 // |
| 190 // // Ask engine to further process options. |
| 191 // if (optionMap != null) { |
| 192 // configureContextOptions(context, optionMap); |
| 193 // } |
| 194 // } on Exception catch (e) { |
| 195 // optionsProcessors.forEach((OptionsProcessor p) => p.onError(e)); |
| 196 // } |
| 197 // } |
| 198 |
| 199 /** |
| 200 * Return an analysis options object containing the default option values. |
| 201 */ |
| 202 AnalysisOptions createDefaultOptions() { |
| 203 if (defaultOptions == null) { |
| 204 return new AnalysisOptionsImpl(); |
| 205 } |
| 206 return new AnalysisOptionsImpl.from(defaultOptions); |
| 207 } |
| 208 |
| 209 Packages createPackageMap(String rootDirectoryPath) { |
| 210 if (defaultPackageFilePath != null) { |
| 211 File configFile = resourceProvider.getFile(defaultPackageFilePath); |
| 212 List<int> bytes = configFile.readAsBytesSync(); |
| 213 Map<String, Uri> map = parse(bytes, configFile.toUri()); |
| 214 resolveSymbolicLinks(map); |
| 215 return new MapPackages(map); |
| 216 } else if (defaultPackagesDirectoryPath != null) { |
| 217 Folder folder = resourceProvider.getFolder(defaultPackagesDirectoryPath); |
| 218 return getPackagesFromFolder(folder); |
| 219 } |
| 220 return findPackagesFromFile(rootDirectoryPath); |
| 221 } |
| 222 |
| 223 SourceFactory createSourceFactory( |
| 224 String rootDirectoryPath, AnalysisOptions options) { |
| 225 Folder _folder = null; |
| 226 Folder folder() { |
| 227 return _folder ??= resourceProvider.getFolder(rootDirectoryPath); |
| 228 } |
| 229 |
| 230 UriResolver fileResolver; |
| 231 if (fileResolverProvider != null) { |
| 232 fileResolver = fileResolverProvider(folder()); |
| 233 } |
| 234 fileResolver ??= new ResourceUriResolver(resourceProvider); |
| 235 if (packageResolverProvider != null) { |
| 236 UriResolver packageResolver = packageResolverProvider(folder()); |
| 237 if (packageResolver != null) { |
| 238 // TODO(brianwilkerson) This doesn't support either embedder files or |
| 239 // sdk extensions because we don't have a way to get the package map |
| 240 // from the resolver. |
| 241 List<UriResolver> resolvers = <UriResolver>[ |
| 242 new DartUriResolver(findSdk(null, options)), |
| 243 packageResolver, |
| 244 fileResolver |
| 245 ]; |
| 246 return new SourceFactory(resolvers, null, resourceProvider); |
| 247 } |
| 248 } |
| 249 Packages packages = createPackageMap(rootDirectoryPath); |
| 250 Map<String, List<Folder>> packageMap = convertPackagesToMap(packages); |
| 251 List<UriResolver> resolvers = <UriResolver>[ |
| 252 new DartUriResolver(findSdk(packageMap, options)), |
| 253 new PackageMapUriResolver(resourceProvider, packageMap), |
| 254 fileResolver |
| 255 ]; |
| 256 return new SourceFactory(resolvers, packages, resourceProvider); |
| 257 } |
| 258 |
| 259 /** |
| 260 * Add any [declaredVariables] to the list of declared variables used by the |
| 261 * given [context]. |
| 262 */ |
| 263 void declareVariables(InternalAnalysisContext context) { |
| 264 if (declaredVariables != null && declaredVariables.isNotEmpty) { |
| 265 DeclaredVariables contextVariables = context.declaredVariables; |
| 266 declaredVariables.forEach((String variableName, String value) { |
| 267 contextVariables.define(variableName, value); |
| 268 }); |
| 269 } |
| 270 } |
| 271 |
| 272 /** |
| 273 * Finds a package resolution strategy for the directory at the given absolute |
| 274 * [path]. |
| 275 * |
| 276 * This function first tries to locate a `.packages` file in the directory. If |
| 277 * that is not found, it instead checks for the presence of a `packages/` |
| 278 * directory in the same place. If that also fails, it starts checking parent |
| 279 * directories for a `.packages` file, and stops if it finds it. Otherwise it |
| 280 * gives up and returns [Packages.noPackages]. |
| 281 */ |
| 282 Packages findPackagesFromFile(String path) { |
| 283 Resource location = _findPackagesLocation(path); |
| 284 if (location is File) { |
| 285 List<int> fileBytes = location.readAsBytesSync(); |
| 286 Map<String, Uri> map = |
| 287 parse(fileBytes, resourceProvider.pathContext.toUri(location.path)); |
| 288 resolveSymbolicLinks(map); |
| 289 return new MapPackages(map); |
| 290 } else if (location is Folder) { |
| 291 return getPackagesFromFolder(location); |
| 292 } |
| 293 return Packages.noPackages; |
| 294 } |
| 295 |
| 296 /** |
| 297 * Return the SDK that should be used to analyze code. Use the given |
| 298 * [packageMap] and [options] to locate the SDK. |
| 299 */ |
| 300 DartSdk findSdk( |
| 301 Map<String, List<Folder>> packageMap, AnalysisOptions options) { |
| 302 if (packageMap != null) { |
| 303 SdkExtensionFinder extFinder = new SdkExtensionFinder(packageMap); |
| 304 List<String> extFilePaths = extFinder.extensionFilePaths; |
| 305 EmbedderYamlLocator locator = new EmbedderYamlLocator(packageMap); |
| 306 Map<Folder, YamlMap> embedderYamls = locator.embedderYamls; |
| 307 EmbedderSdk embedderSdk = |
| 308 new EmbedderSdk(resourceProvider, embedderYamls); |
| 309 if (embedderSdk.sdkLibraries.length > 0) { |
| 310 // |
| 311 // There is an embedder file that defines the content of the SDK and |
| 312 // there might be an extension file that extends it. |
| 313 // |
| 314 List<String> paths = <String>[]; |
| 315 for (Folder folder in embedderYamls.keys) { |
| 316 paths.add(folder |
| 317 .getChildAssumingFile(EmbedderYamlLocator.EMBEDDER_FILE_NAME) |
| 318 .path); |
| 319 } |
| 320 paths.addAll(extFilePaths); |
| 321 SdkDescription description = new SdkDescription(paths, options); |
| 322 DartSdk dartSdk = sdkManager.getSdk(description, () { |
| 323 if (extFilePaths.isNotEmpty) { |
| 324 embedderSdk.addExtensions(extFinder.urlMappings); |
| 325 } |
| 326 embedderSdk.analysisOptions = options; |
| 327 embedderSdk.useSummary = sdkManager.canUseSummaries; |
| 328 return embedderSdk; |
| 329 }); |
| 330 return dartSdk; |
| 331 } else if (extFilePaths != null && extFilePaths.isNotEmpty) { |
| 332 // |
| 333 // We have an extension file, but no embedder file. |
| 334 // |
| 335 String sdkPath = sdkManager.defaultSdkDirectory; |
| 336 List<String> paths = <String>[sdkPath]; |
| 337 paths.addAll(extFilePaths); |
| 338 SdkDescription description = new SdkDescription(paths, options); |
| 339 return sdkManager.getSdk(description, () { |
| 340 FolderBasedDartSdk sdk = new FolderBasedDartSdk( |
| 341 resourceProvider, resourceProvider.getFolder(sdkPath)); |
| 342 if (extFilePaths.isNotEmpty) { |
| 343 sdk.addExtensions(extFinder.urlMappings); |
| 344 } |
| 345 sdk.analysisOptions = options; |
| 346 sdk.useSummary = sdkManager.canUseSummaries; |
| 347 return sdk; |
| 348 }); |
| 349 } |
| 350 } |
| 351 String sdkPath = sdkManager.defaultSdkDirectory; |
| 352 SdkDescription description = new SdkDescription(<String>[sdkPath], options); |
| 353 return sdkManager.getSdk(description, () { |
| 354 FolderBasedDartSdk sdk = new FolderBasedDartSdk( |
| 355 resourceProvider, resourceProvider.getFolder(sdkPath)); |
| 356 sdk.analysisOptions = options; |
| 357 sdk.useSummary = sdkManager.canUseSummaries; |
| 358 return sdk; |
| 359 }); |
| 360 } |
| 361 |
| 362 /** |
| 363 * Return the analysis options that should be used when the given [context] is |
| 364 * used to analyze code in the directory with the given [path]. |
| 365 */ |
| 366 AnalysisOptions getAnalysisOptions(AnalysisContext context, String path) { |
| 367 AnalysisOptionsImpl options = createDefaultOptions(); |
| 368 File optionsFile = getOptionsFile(path); |
| 369 if (optionsFile != null) { |
| 370 List<OptionsProcessor> optionsProcessors = |
| 371 AnalysisEngine.instance.optionsPlugin.optionsProcessors; |
| 372 try { |
| 373 Map<String, YamlNode> optionMap = |
| 374 new AnalysisOptionsProvider().getOptionsFromFile(optionsFile); |
| 375 optionsProcessors.forEach( |
| 376 (OptionsProcessor p) => p.optionsProcessed(context, optionMap)); |
| 377 applyToAnalysisOptions(options, optionMap); |
| 378 } on Exception catch (exception) { |
| 379 optionsProcessors.forEach((OptionsProcessor p) => p.onError(exception)); |
| 380 } |
| 381 } |
| 382 return options; |
| 383 } |
| 384 |
| 385 /** |
| 386 * Return the analysis options file that should be used when analyzing code in |
| 387 * the directory with the given [path]. |
| 388 */ |
| 389 File getOptionsFile(String path) { |
| 390 if (defaultAnalysisOptionsFilePath != null) { |
| 391 return resourceProvider.getFile(defaultAnalysisOptionsFilePath); |
| 392 } |
| 393 Folder root = resourceProvider.getFolder(path); |
| 394 for (Folder folder = root; folder != null; folder = folder.parent) { |
| 395 File file = |
| 396 folder.getChildAssumingFile(AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
| 397 if (file.exists) { |
| 398 return file; |
| 399 } |
| 400 file = folder |
| 401 .getChildAssumingFile(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
| 402 if (file.exists) { |
| 403 return file; |
| 404 } |
| 405 } |
| 406 return null; |
| 407 } |
| 408 |
| 409 /** |
| 410 * Create a [Packages] object for a 'package' directory ([folder]). |
| 411 * |
| 412 * Package names are resolved as relative to sub-directories of the package |
| 413 * directory. |
| 414 */ |
| 415 Packages getPackagesFromFolder(Folder folder) { |
| 416 Context pathContext = resourceProvider.pathContext; |
| 417 Map<String, Uri> map = new HashMap<String, Uri>(); |
| 418 for (Resource child in folder.getChildren()) { |
| 419 if (child is Folder) { |
| 420 // Inline resolveSymbolicLinks for performance reasons. |
| 421 String packageName = pathContext.basename(child.path); |
| 422 String folderPath = resolveSymbolicLink(child); |
| 423 String uriPath = pathContext.join(folderPath, '.'); |
| 424 map[packageName] = pathContext.toUri(uriPath); |
| 425 } |
| 426 } |
| 427 return new MapPackages(map); |
| 428 } |
| 429 |
| 430 /** |
| 431 * Resolve any symbolic links encoded in the path to the given [folder]. |
| 432 */ |
| 433 String resolveSymbolicLink(Folder folder) { |
| 434 try { |
| 435 return folder.resolveSymbolicLinksSync().path; |
| 436 } on FileSystemException { |
| 437 return folder.path; |
| 438 } |
| 439 } |
| 440 |
| 441 /** |
| 442 * Resolve any symbolic links encoded in the URI's in the given [map] by |
| 443 * replacing the values in the map. |
| 444 */ |
| 445 void resolveSymbolicLinks(Map<String, Uri> map) { |
| 446 Context pathContext = resourceProvider.pathContext; |
| 447 for (String packageName in map.keys) { |
| 448 Folder folder = |
| 449 resourceProvider.getFolder(pathContext.fromUri(map[packageName])); |
| 450 String folderPath = resolveSymbolicLink(folder); |
| 451 // Add a '.' so that the URI is suitable for resolving relative URI's |
| 452 // against it. |
| 453 String uriPath = pathContext.join(folderPath, '.'); |
| 454 map[packageName] = pathContext.toUri(uriPath); |
| 455 } |
| 456 } |
| 457 |
| 458 /** |
| 459 * Find the location of the package resolution file/directory for the |
| 460 * directory at the given absolute [path]. |
| 461 * |
| 462 * Checks for a `.packages` file in the [path]. If not found, |
| 463 * checks for a `packages` directory in the same directory. If still not |
| 464 * found, starts checking parent directories for `.packages` until reaching |
| 465 * the root directory. |
| 466 * |
| 467 * Return a [File] object representing a `.packages` file if one is found, a |
| 468 * [Folder] object for the `packages/` directory if that is found, or `null` |
| 469 * if neither is found. |
| 470 */ |
| 471 Resource _findPackagesLocation(String path) { |
| 472 Folder folder = resourceProvider.getFolder(path); |
| 473 if (!folder.exists) { |
| 474 throw new ArgumentError.value(path, "path", "Directory does not exist."); |
| 475 } |
| 476 File checkForConfigFile(Folder folder) { |
| 477 File file = folder.getChildAssumingFile('.packages'); |
| 478 if (file.exists) { |
| 479 return file; |
| 480 } |
| 481 return null; |
| 482 } |
| 483 |
| 484 // Check for $cwd/.packages |
| 485 File packagesCfgFile = checkForConfigFile(folder); |
| 486 if (packagesCfgFile != null) { |
| 487 return packagesCfgFile; |
| 488 } |
| 489 // Check for $cwd/packages/ |
| 490 Folder packagesDir = folder.getChildAssumingFolder("packages"); |
| 491 if (packagesDir.exists) { |
| 492 return packagesDir; |
| 493 } |
| 494 // Check for cwd(/..)+/.packages |
| 495 Folder parentDir = folder.parent; |
| 496 while (parentDir != null) { |
| 497 packagesCfgFile = checkForConfigFile(parentDir); |
| 498 if (packagesCfgFile != null) { |
| 499 return packagesCfgFile; |
| 500 } |
| 501 parentDir = parentDir.parent; |
| 502 } |
| 503 return null; |
| 504 } |
| 505 } |
| 506 |
| 507 /** |
| 508 * Given a package map, check in each package's lib directory for the existence |
| 509 * of an `_embedder.yaml` file. If the file contains a top level YamlMap, it |
| 510 * will be added to the [embedderYamls] map. |
| 511 */ |
| 512 class EmbedderYamlLocator { |
| 513 /** |
| 514 * The name of the embedder files being searched for. |
| 515 */ |
| 516 static const String EMBEDDER_FILE_NAME = '_embedder.yaml'; |
| 517 |
| 518 /** |
| 519 * A mapping from a package's library directory to the parsed YamlMap. |
| 520 */ |
| 521 final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>(); |
| 522 |
| 523 /** |
| 524 * Initialize a newly created locator by processing the packages in the given |
| 525 * [packageMap]. |
| 526 */ |
| 527 EmbedderYamlLocator(Map<String, List<Folder>> packageMap) { |
| 528 if (packageMap != null) { |
| 529 _processPackageMap(packageMap); |
| 530 } |
| 531 } |
| 532 |
| 533 /** |
| 534 * Programmatically add an `_embedder.yaml` mapping. |
| 535 */ |
| 536 void addEmbedderYaml(Folder libDir, String embedderYaml) { |
| 537 _processEmbedderYaml(libDir, embedderYaml); |
| 538 } |
| 539 |
| 540 /** |
| 541 * Refresh the map of located files to those found by processing the given |
| 542 * [packageMap]. |
| 543 */ |
| 544 void refresh(Map<String, List<Folder>> packageMap) { |
| 545 // Clear existing. |
| 546 embedderYamls.clear(); |
| 547 if (packageMap != null) { |
| 548 _processPackageMap(packageMap); |
| 549 } |
| 550 } |
| 551 |
| 552 /** |
| 553 * Given the yaml for an embedder ([embedderYaml]) and a folder ([libDir]), |
| 554 * setup the uri mapping. |
| 555 */ |
| 556 void _processEmbedderYaml(Folder libDir, String embedderYaml) { |
| 557 try { |
| 558 YamlNode yaml = loadYaml(embedderYaml); |
| 559 if (yaml is YamlMap) { |
| 560 embedderYamls[libDir] = yaml; |
| 561 } |
| 562 } catch (_) { |
| 563 // Ignored |
| 564 } |
| 565 } |
| 566 |
| 567 /** |
| 568 * Given a package [name] and a list of folders ([libDirs]), process any |
| 569 * `_embedder.yaml` files that are found in any of the folders. |
| 570 */ |
| 571 void _processPackage(String name, List<Folder> libDirs) { |
| 572 for (Folder libDir in libDirs) { |
| 573 String embedderYaml = _readEmbedderYaml(libDir); |
| 574 if (embedderYaml != null) { |
| 575 _processEmbedderYaml(libDir, embedderYaml); |
| 576 } |
| 577 } |
| 578 } |
| 579 |
| 580 /** |
| 581 * Process each of the entries in the [packageMap]. |
| 582 */ |
| 583 void _processPackageMap(Map<String, List<Folder>> packageMap) { |
| 584 packageMap.forEach(_processPackage); |
| 585 } |
| 586 |
| 587 /** |
| 588 * Read and return the contents of [libDir]/[EMBEDDER_FILE_NAME], or `null` if |
| 589 * the file doesn't exist. |
| 590 */ |
| 591 String _readEmbedderYaml(Folder libDir) { |
| 592 File file = libDir.getChild(EMBEDDER_FILE_NAME); |
| 593 try { |
| 594 return file.readAsStringSync(); |
| 595 } on FileSystemException { |
| 596 // File can't be read. |
| 597 return null; |
| 598 } |
| 599 } |
| 600 } |
| OLD | NEW |