| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library source.optimizing_pub_package_map_provider; | |
| 6 | |
| 7 import 'dart:core' hide Resource; | |
| 8 | |
| 9 import 'package:analyzer/file_system/file_system.dart'; | |
| 10 import 'package:analyzer/source/package_map_provider.dart'; | |
| 11 import 'package:analyzer/source/pub_package_map_provider.dart'; | |
| 12 import 'package:analyzer/src/generated/sdk_io.dart'; | |
| 13 | |
| 14 /** | |
| 15 * Extension of [PackageMapInfo] that tracks the modification timestamps of | |
| 16 * pub dependencies. This allows the analysis server to avoid making redundant | |
| 17 * calls to "pub list" when nothing has changed. | |
| 18 */ | |
| 19 class OptimizingPubPackageMapInfo extends PackageMapInfo { | |
| 20 /** | |
| 21 * Map from file path to the file's modification timestamp prior to running | |
| 22 * "pub list". Since the set of dependencies is not always known prior to | |
| 23 * running "pub list", some or all of the dependencies may be missing from | |
| 24 * this map. | |
| 25 */ | |
| 26 final Map<String, int> modificationTimes; | |
| 27 | |
| 28 OptimizingPubPackageMapInfo(Map<String, List<Folder>> packageMap, | |
| 29 Set<String> dependencies, this.modificationTimes) | |
| 30 : super(packageMap, dependencies); | |
| 31 | |
| 32 /** | |
| 33 * Return `true` if the given [path] is listed as a dependency, and we cannot | |
| 34 * prove using modification timestamps that it is unchanged. | |
| 35 * [resourceProvider] is used (if necessary) to read the [path]'s | |
| 36 * modification time. | |
| 37 */ | |
| 38 bool isChangedDependency(String path, ResourceProvider resourceProvider) { | |
| 39 if (!dependencies.contains(path)) { | |
| 40 // Path is not a dependency. | |
| 41 return false; | |
| 42 } | |
| 43 int lastModificationTime = modificationTimes[path]; | |
| 44 if (lastModificationTime != null) { | |
| 45 Resource resource = resourceProvider.getResource(path); | |
| 46 if (resource is File) { | |
| 47 try { | |
| 48 if (resource.modificationStamp == lastModificationTime) { | |
| 49 // Path is a dependency, but it hasn't changed since the last run | |
| 50 // of "pub list". | |
| 51 return false; | |
| 52 } | |
| 53 } on FileSystemException { | |
| 54 // Path is a dependency, but we can't read its timestamp. Assume | |
| 55 // it's changed to be safe. | |
| 56 } | |
| 57 } | |
| 58 } | |
| 59 // Path is a dependency, and we couldn't prove that it hadn't changed. | |
| 60 // Assume it's changed to be safe. | |
| 61 return true; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 /** | |
| 66 * Extension of [PubPackageMapProvider] that outputs additional information to | |
| 67 * allow the analysis server to avoid making redundant calls to "pub list" when | |
| 68 * nothing has changed. | |
| 69 */ | |
| 70 class OptimizingPubPackageMapProvider extends PubPackageMapProvider { | |
| 71 OptimizingPubPackageMapProvider( | |
| 72 ResourceProvider resourceProvider, DirectoryBasedDartSdk sdk, [RunPubList
runPubList]) | |
| 73 : super(resourceProvider, sdk, runPubList); | |
| 74 | |
| 75 /** | |
| 76 * Compute a package map for the given folder by executing "pub list". If | |
| 77 * [previousInfo] is provided, it is used as a guess of which files the | |
| 78 * package map is likely to depend on; the modification times of those files | |
| 79 * are captured prior to executing "pub list" so that they can be used to | |
| 80 * avoid making redundant calls to "pub list" in the future. | |
| 81 * | |
| 82 * Also, in the case where dependencies can't be determined because of an | |
| 83 * error, the dependencies from [previousInfo] will be preserved. | |
| 84 */ | |
| 85 OptimizingPubPackageMapInfo computePackageMap(Folder folder, | |
| 86 [OptimizingPubPackageMapInfo previousInfo]) { | |
| 87 // Prior to running "pub list", read the modification timestamps of all of | |
| 88 // the old dependencies (if known). | |
| 89 Map<String, int> modificationTimes = <String, int>{}; | |
| 90 if (previousInfo != null) { | |
| 91 for (String path in previousInfo.dependencies) { | |
| 92 Resource resource = resourceProvider.getResource(path); | |
| 93 if (resource is File) { | |
| 94 try { | |
| 95 modificationTimes[path] = resource.modificationStamp; | |
| 96 } on FileSystemException { | |
| 97 // File no longer exists. Don't record a timestamp for it; this | |
| 98 // will ensure that if the file reappears, we will re-run "pub | |
| 99 // list" regardless of the timestamp it reappears with. | |
| 100 } | |
| 101 } | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 // Try running "pub list". | |
| 106 PackageMapInfo info = super.computePackageMap(folder); | |
| 107 if (info == null) { | |
| 108 // Computing the package map resulted in an error. Merge the old | |
| 109 // dependencies with the new ones, if possible. | |
| 110 info = super.computePackageMapError(folder); | |
| 111 if (previousInfo != null) { | |
| 112 info.dependencies.addAll(previousInfo.dependencies); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 // Discard any elements of modificationTimes that are no longer | |
| 117 // dependencies. | |
| 118 if (previousInfo != null) { | |
| 119 for (String dependency | |
| 120 in previousInfo.dependencies.difference(info.dependencies)) { | |
| 121 modificationTimes.remove(dependency); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 // Bundle the modificationTimes with the other info. | |
| 126 return new OptimizingPubPackageMapInfo( | |
| 127 info.packageMap, info.dependencies, modificationTimes); | |
| 128 } | |
| 129 | |
| 130 @override | |
| 131 PackageMapInfo computePackageMapError(Folder folder) { | |
| 132 // Return null to indicate to our override of computePackageMap that there | |
| 133 // was an error, so it can compute dependencies correctly. | |
| 134 return null; | |
| 135 } | |
| 136 } | |
| OLD | NEW |