Use cached version listings as heuristic when prefetching (#2851)
diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart
index 87e71b1..2b69c4c 100644
--- a/lib/src/command/outdated.dart
+++ b/lib/src/command/outdated.dart
@@ -8,10 +8,10 @@
import 'dart:math';
import 'package:meta/meta.dart';
-import 'package:pub/src/command_runner.dart';
import 'package:pub_semver/pub_semver.dart';
import '../command.dart';
+import '../command_runner.dart';
import '../entrypoint.dart';
import '../io.dart';
import '../log.dart' as log;
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart
index 10f2126..f4ca367 100644
--- a/lib/src/solver/version_solver.dart
+++ b/lib/src/solver/version_solver.dart
@@ -6,7 +6,6 @@
import 'dart:math' as math;
import 'package:collection/collection.dart';
-import 'package:pub/src/source/hosted.dart';
import 'package:pub_semver/pub_semver.dart';
import '../exceptions.dart';
@@ -15,6 +14,7 @@
import '../package.dart';
import '../package_name.dart';
import '../pubspec.dart';
+import '../source/hosted.dart';
import '../source/unknown.dart';
import '../system_cache.dart';
import '../utils.dart';
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart
index d8c853c..3199a1d 100644
--- a/lib/src/source/hosted.dart
+++ b/lib/src/source/hosted.dart
@@ -206,7 +206,8 @@
throw FormatException('versions must be a list');
}
- Future<Map<PackageId, _VersionInfo>> _fetchVersions(PackageRef ref) async {
+ Future<Map<PackageId, _VersionInfo>> _fetchVersionsNoPrefetching(
+ PackageRef ref) async {
var url = _makeUrl(
ref.description, (server, package) => '$server/api/packages/$package');
log.io('Get versions from $url.');
@@ -230,20 +231,23 @@
if (body.length < 100 * 1024) {
await _cacheVersionListingResponse(body, ref);
}
+ return result;
+ }
- // Prefetch the dependencies of the latest version, we are likely to need
- // them later.
+ Future<Map<PackageId, _VersionInfo>> _fetchVersions(PackageRef ref) async {
final preschedule =
Zone.current[_prefetchingKey] as void Function(PackageRef);
- if (preschedule != null) {
- final latestVersion =
- maxBy(result.keys.map((id) => id.version), (e) => e);
+ /// Prefetch the dependencies of the latest version, we are likely to need
+ /// them later.
+ void prescheduleDependenciesOfLatest(Map<PackageId, _VersionInfo> listing) {
+ if (listing == null) return;
+ final latestVersion =
+ maxBy(listing.keys.map((id) => id.version), (e) => e);
final latestVersionId =
PackageId(ref.name, source, latestVersion, ref.description);
-
final dependencies =
- result[latestVersionId]?.pubspec?.dependencies?.values ?? [];
+ listing[latestVersionId]?.pubspec?.dependencies?.values ?? [];
unawaited(withDependencyType(DependencyType.none, () async {
for (final packageRange in dependencies) {
if (packageRange.source is HostedSource) {
@@ -252,6 +256,21 @@
}
}));
}
+
+ if (preschedule != null) {
+ /// If we have a cached response - preschedule dependencies of that.
+ prescheduleDependenciesOfLatest(
+ await _cachedVersionListingResponse(ref, Duration(days: 365)),
+ );
+ }
+ final result = await _fetchVersionsNoPrefetching(ref);
+
+ if (preschedule != null) {
+ // Preschedule the dependencies from the actual response.
+ // This might overlap with those from the cached response. But the
+ // scheduler ensures each listing will be fetched at most once.
+ prescheduleDependenciesOfLatest(result);
+ }
return result;
}
@@ -356,7 +375,7 @@
/// site.
@override
Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async {
- Map<PackageId, _VersionInfo> versionListing;
+ var versionListing = _scheduler.peek(ref);
if (maxAge != null) {
// Do we have a cached version response on disk?
versionListing ??= await _cachedVersionListingResponse(ref, maxAge);