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