OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 version_solver; | 5 library version_solver; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:json' as json; | 8 import 'dart:json' as json; |
9 | 9 |
10 import '../lock_file.dart'; | 10 import '../lock_file.dart'; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 | 63 |
64 return 'Took $attemptedSolutions tries to resolve to\n' | 64 return 'Took $attemptedSolutions tries to resolve to\n' |
65 '- ${packages.join("\n- ")}'; | 65 '- ${packages.join("\n- ")}'; |
66 } | 66 } |
67 } | 67 } |
68 | 68 |
69 /// Maintains a cache of previously-requested data: pubspecs and version lists. | 69 /// Maintains a cache of previously-requested data: pubspecs and version lists. |
70 /// Used to avoid requesting the same pubspec from the server repeatedly. | 70 /// Used to avoid requesting the same pubspec from the server repeatedly. |
71 class PubspecCache { | 71 class PubspecCache { |
72 final SourceRegistry _sources; | 72 final SourceRegistry _sources; |
73 final _versions = new Map<PackageId, List<PackageId>>(); | 73 final _versions = new Map<PackageRef, List<PackageId>>(); |
74 final _pubspecs = new Map<PackageId, Pubspec>(); | 74 final _pubspecs = new Map<PackageId, Pubspec>(); |
75 | 75 |
76 /// The number of times a version list was requested and it wasn't cached and | 76 /// The number of times a version list was requested and it wasn't cached and |
77 /// had to be requested from the source. | 77 /// had to be requested from the source. |
78 int versionCacheMisses = 0; | 78 int versionCacheMisses = 0; |
79 | 79 |
80 /// The number of times a version list was requested and the cached version | 80 /// The number of times a version list was requested and the cached version |
81 /// was returned. | 81 /// was returned. |
82 int versionCacheHits = 0; | 82 int versionCacheHits = 0; |
83 | 83 |
(...skipping 28 matching lines...) Expand all Loading... |
112 _pubspecs[id] = pubspec; | 112 _pubspecs[id] = pubspec; |
113 return pubspec; | 113 return pubspec; |
114 }); | 114 }); |
115 } | 115 } |
116 | 116 |
117 /// Returns the previously cached pubspec for the package identified by [id] | 117 /// Returns the previously cached pubspec for the package identified by [id] |
118 /// or returns `null` if not in the cache. | 118 /// or returns `null` if not in the cache. |
119 Pubspec getCachedPubspec(PackageId id) => _pubspecs[id]; | 119 Pubspec getCachedPubspec(PackageId id) => _pubspecs[id]; |
120 | 120 |
121 /// Gets the list of versions for [package] in descending order. | 121 /// Gets the list of versions for [package] in descending order. |
122 Future<List<PackageId>> getVersions(String package, Source source, | 122 Future<List<PackageId>> getVersions(PackageRef package) { |
123 description) { | |
124 // Create a fake ID to use as a key. | |
125 // TODO(rnystrom): Create a separate type for (name, source, description) | |
126 // without a version. | |
127 var id = new PackageId(package, source, Version.none, description); | |
128 | |
129 // See if we have it cached. | 123 // See if we have it cached. |
130 var versions = _versions[id]; | 124 var versions = _versions[package]; |
131 if (versions != null) { | 125 if (versions != null) { |
132 versionCacheHits++; | 126 versionCacheHits++; |
133 return new Future.value(versions); | 127 return new Future.value(versions); |
134 } | 128 } |
135 | 129 |
136 versionCacheMisses++; | 130 versionCacheMisses++; |
137 return source.getVersions(package, description).then((versions) { | 131 return package.getVersions().then((ids) { |
138 var ids = versions | |
139 .map((version) => new PackageId(package, source, version, | |
140 description)) | |
141 .toList(); | |
142 | |
143 // Sort by descending version so we try newer versions first. | 132 // Sort by descending version so we try newer versions first. |
144 ids.sort((a, b) => b.version.compareTo(a.version)); | 133 ids.sort((a, b) => b.version.compareTo(a.version)); |
145 | 134 |
146 log.solver('requested $package version list'); | 135 log.solver('requested $package version list'); |
147 _versions[id] = ids; | 136 _versions[package] = ids; |
148 return ids; | 137 return ids; |
149 }); | 138 }); |
150 } | 139 } |
151 } | 140 } |
152 | 141 |
153 /// A reference from a depending package to a package that it depends on. | 142 /// A reference from a depending package to a package that it depends on. |
154 class Dependency { | 143 class Dependency { |
155 /// The name of the package that has this dependency. | 144 /// The name of the package that has this dependency. |
156 final String depender; | 145 final String depender; |
157 | 146 |
158 /// The referenced dependent package. | 147 /// The package being depended on. |
159 final PackageRef ref; | 148 final PackageDep dep; |
160 | 149 |
161 Dependency(this.depender, this.ref); | 150 Dependency(this.depender, this.dep); |
162 | 151 |
163 String toString() => '$depender -> $ref'; | 152 String toString() => '$depender -> $dep'; |
164 } | 153 } |
165 | 154 |
166 /// Base class for all failures that can occur while trying to resolve versions. | 155 /// Base class for all failures that can occur while trying to resolve versions. |
167 class SolveFailure implements Exception { | 156 class SolveFailure implements Exception { |
168 /// The name of the package whose version could not be solved. Will be `null` | 157 /// The name of the package whose version could not be solved. Will be `null` |
169 /// if the failure is not specific to one package. | 158 /// if the failure is not specific to one package. |
170 final String package; | 159 final String package; |
171 | 160 |
172 /// The known dependencies on [package] at the time of the failure. Will be | 161 /// The known dependencies on [package] at the time of the failure. Will be |
173 /// an empty collection if the failure is not specific to one package. | 162 /// an empty collection if the failure is not specific to one package. |
174 final Iterable<Dependency> dependencies; | 163 final Iterable<Dependency> dependencies; |
175 | 164 |
176 SolveFailure(this.package, Iterable<Dependency> dependencies) | 165 SolveFailure(this.package, Iterable<Dependency> dependencies) |
177 : dependencies = dependencies != null ? dependencies : <Dependency>[]; | 166 : dependencies = dependencies != null ? dependencies : <Dependency>[]; |
178 | 167 |
179 /// Writes [dependencies] to [buffer] as a bullet list. If [describe] is | 168 /// Writes [dependencies] to [buffer] as a bullet list. If [describe] is |
180 /// passed, it will be called for each dependency and the result will be | 169 /// passed, it will be called for each dependency and the result will be |
181 /// written next to the dependency. | 170 /// written next to the dependency. |
182 void writeDependencies(StringBuffer buffer, | 171 void writeDependencies(StringBuffer buffer, |
183 [String describe(PackageRef ref)]) { | 172 [String describe(PackageDep dep)]) { |
184 var map = {}; | 173 var map = {}; |
185 for (var dep in dependencies) { | 174 for (var dep in dependencies) { |
186 map[dep.depender] = dep.ref; | 175 map[dep.depender] = dep.dep; |
187 } | 176 } |
188 | 177 |
189 var names = map.keys.toList(); | 178 var names = map.keys.toList(); |
190 names.sort(); | 179 names.sort(); |
191 | 180 |
192 for (var name in names) { | 181 for (var name in names) { |
193 buffer.writeln("- '$name' "); | 182 buffer.writeln("- '$name' "); |
194 if (describe != null) { | 183 if (describe != null) { |
195 buffer.writeln(describe(map[name])); | 184 buffer.writeln(describe(map[name])); |
196 } else { | 185 } else { |
197 buffer.writeln("depends on version ${map[name].constraint}"); | 186 buffer.writeln("depends on version ${map[name].constraint}"); |
198 } | 187 } |
199 } | 188 } |
200 } | 189 } |
201 | 190 |
202 String toString() { | 191 String toString() { |
203 if (dependencies.isEmpty) return _message; | 192 if (dependencies.isEmpty) return _message; |
204 | 193 |
205 var buffer = new StringBuffer(); | 194 var buffer = new StringBuffer(); |
206 buffer.writeln("$_message:"); | 195 buffer.writeln("$_message:"); |
207 | 196 |
208 var map = {}; | 197 var map = {}; |
209 for (var dep in dependencies) { | 198 for (var dep in dependencies) { |
210 map[dep.depender] = dep.ref; | 199 map[dep.depender] = dep.dep; |
211 } | 200 } |
212 | 201 |
213 var names = map.keys.toList(); | 202 var names = map.keys.toList(); |
214 names.sort(); | 203 names.sort(); |
215 | 204 |
216 for (var name in names) { | 205 for (var name in names) { |
217 buffer.writeln("- '$name' ${_describeDependency(map[name])}"); | 206 buffer.writeln("- '$name' ${_describeDependency(map[name])}"); |
218 } | 207 } |
219 | 208 |
220 return buffer.toString(); | 209 return buffer.toString(); |
221 } | 210 } |
222 | 211 |
223 /// A message describing the specific kind of solve failure. | 212 /// A message describing the specific kind of solve failure. |
224 String get _message; | 213 String get _message; |
225 | 214 |
226 /// Describes a dependencie's reference in the output message. Override this | 215 /// Describes a dependencie's reference in the output message. Override this |
227 /// to highlight which aspect of [ref] led to the failure. | 216 /// to highlight which aspect of [dep] led to the failure. |
228 String _describeDependency(PackageRef ref) => | 217 String _describeDependency(PackageDep dep) => |
229 "depends on version ${ref.constraint}"; | 218 "depends on version ${dep.constraint}"; |
230 } | 219 } |
231 | 220 |
232 /// Exception thrown when the [VersionSolver] fails to find a solution after a | 221 /// Exception thrown when the [VersionSolver] fails to find a solution after a |
233 /// certain number of iterations. | 222 /// certain number of iterations. |
234 class CouldNotSolveException extends SolveFailure { | 223 class CouldNotSolveException extends SolveFailure { |
235 CouldNotSolveException([String message]) | 224 CouldNotSolveException([String message]) |
236 : super(null, null), | 225 : super(null, null), |
237 _message = (message != null) ? message : | 226 _message = (message != null) ? message : |
238 "Could not find a solution that met all constraints."; | 227 "Could not find a solution that met all constraints."; |
239 | 228 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 | 270 |
282 /// Exception thrown when two packages with the same name but different sources | 271 /// Exception thrown when two packages with the same name but different sources |
283 /// are depended upon. | 272 /// are depended upon. |
284 class SourceMismatchException extends SolveFailure { | 273 class SourceMismatchException extends SolveFailure { |
285 | 274 |
286 SourceMismatchException(String package, Iterable<Dependency> dependencies) | 275 SourceMismatchException(String package, Iterable<Dependency> dependencies) |
287 : super(package, dependencies); | 276 : super(package, dependencies); |
288 | 277 |
289 String get _message => "Incompatible dependencies on '$package'"; | 278 String get _message => "Incompatible dependencies on '$package'"; |
290 | 279 |
291 String _describeDependency(PackageRef ref) => | 280 String _describeDependency(PackageDep dep) => |
292 "depends on it from source ${ref.source}"; | 281 "depends on it from source ${dep.source}"; |
293 } | 282 } |
294 | 283 |
295 /// Exception thrown when two packages with the same name and source but | 284 /// Exception thrown when two packages with the same name and source but |
296 /// different descriptions are depended upon. | 285 /// different descriptions are depended upon. |
297 class DescriptionMismatchException extends SolveFailure { | 286 class DescriptionMismatchException extends SolveFailure { |
298 DescriptionMismatchException(String package, | 287 DescriptionMismatchException(String package, |
299 Iterable<Dependency> dependencies) | 288 Iterable<Dependency> dependencies) |
300 : super(package, dependencies); | 289 : super(package, dependencies); |
301 | 290 |
302 String get _message => "Incompatible dependencies on '$package'"; | 291 String get _message => "Incompatible dependencies on '$package'"; |
303 | 292 |
304 String _describeDependency(PackageRef ref) { | 293 String _describeDependency(PackageDep dep) { |
305 // TODO(nweiz): Dump descriptions to YAML when that's supported. | 294 // TODO(nweiz): Dump descriptions to YAML when that's supported. |
306 return "depends on it with description ${json.stringify(ref.description)}"; | 295 return "depends on it with description ${json.stringify(dep.description)}"; |
307 } | 296 } |
308 } | 297 } |
OLD | NEW |