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 |