From c4298fcf5b6551f44df6bc7339755175cd0cc883 Mon Sep 17 00:00:00 2001 From: "rnystrom@google.com" <rnystrom@google.com> Date: Fri, 19 Apr 2013 22:29:44 +0000 Subject: [PATCH] Use the cached pubspec if possible for describing hosted packages. BUG=https://code.google.com/p/dart/issues/detail?id=9027 Review URL: https://codereview.chromium.org//14241005 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge@21777 260f80e4-7a28-3924-810f-c04153c831b5 --- lib/src/hosted_source.dart | 9 +++- lib/src/package.dart | 2 +- lib/src/system_cache.dart | 7 +++- test/install/hosted/cached_pubspec_test.dart | 43 ++++++++++++++++++++ test/test_pub.dart | 18 ++++++++ test/version_solver_test.dart | 4 ++ 6 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 test/install/hosted/cached_pubspec_test.dart diff --git a/lib/src/hosted_source.dart b/lib/src/hosted_source.dart index bd017e66..86693623 100644 --- a/lib/src/hosted_source.dart +++ b/lib/src/hosted_source.dart @@ -49,11 +49,16 @@ class HostedSource extends Source { /// Downloads and parses the pubspec for a specific version of a package that /// is available from the site. Future<Pubspec> describe(PackageId id) { + // Request it from the server. var url = _makeVersionUrl(id, (server, package, version) => "$server/packages/$package/versions/$version.yaml"); log.io("Describe package at $url."); return httpClient.read(url).then((yaml) { + // TODO(rnystrom): After this is pulled down, we could place it in + // a secondary cache of just pubspecs. This would let us have a + // persistent cache for pubspecs for packages that haven't actually + // been installed. return new Pubspec.parse(null, yaml, systemCache.sources); }).catchError((ex) { var parsed = _parseDescription(id.description); @@ -122,11 +127,11 @@ class HostedSource extends Source { var cacheDir = path.join(systemCacheRoot, _getSourceDirectory(_defaultUrl)); if (!dirExists(cacheDir)) return []; - + return listDir(path.join(cacheDir)).map((entry) => new Package.load(null, entry, systemCache.sources)).toList(); } - + /// When an error occurs trying to read something about [package] from [url], /// this tries to translate into a more user friendly error message. Always /// throws an error, either the original one or a better one. diff --git a/lib/src/package.dart b/lib/src/package.dart index f1f65d30..ce1ad35d 100644 --- a/lib/src/package.dart +++ b/lib/src/package.dart @@ -146,7 +146,7 @@ class PackageId implements Comparable<PackageId> { } /// Returns the pubspec for this package. - Future<Pubspec> describe() => source.describe(this); + Future<Pubspec> describe() => source.systemCache.describe(this); /// Returns a future that completes to the resovled [PackageId] for this id. Future<PackageId> get resolved => source.resolveId(this); diff --git a/lib/src/system_cache.dart b/lib/src/system_cache.dart index 4c0e1760..8a51912a 100644 --- a/lib/src/system_cache.dart +++ b/lib/src/system_cache.dart @@ -70,13 +70,16 @@ class SystemCache { // Try to get it from the system cache first. if (id.source.shouldCache) { return id.systemCacheDirectory.then((packageDir) { - if (!dirExists(packageDir)) return id.describe(); + if (!fileExists(path.join(packageDir, "pubspec.yaml"))) { + return id.source.describe(id); + } + return new Pubspec.load(id.name, packageDir, sources); }); } // Not cached, so get it from the source. - return id.describe(); + return id.source.describe(id); } /// Ensures that the package identified by [id] is installed to the cache, diff --git a/test/install/hosted/cached_pubspec_test.dart b/test/install/hosted/cached_pubspec_test.dart new file mode 100644 index 00000000..c3012060 --- /dev/null +++ b/test/install/hosted/cached_pubspec_test.dart @@ -0,0 +1,43 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library pub_tests; + +import 'package:pathos/path.dart' as path; +import 'package:scheduled_test/scheduled_test.dart'; + +import '../../../../pub/io.dart'; +import '../../descriptor.dart' as d; +import '../../test_pub.dart'; + +main() { + initConfig(); + + integration('does not request a pubspec for a cached package', () { + servePackages([packageMap("foo", "1.2.3")]); + + d.appDir([dependencyMap("foo", "1.2.3")]).create(); + + // Run install once so it gets cached. + schedulePub(args: ['install'], + output: new RegExp("Dependencies installed!\$")); + + // Clear the cache. We don't care about anything that was served during + // the initial install. + getRequestedPaths(); + + d.cacheDir({"foo": "1.2.3"}).validate(); + d.packagesDir({"foo": "1.2.3"}).validate(); + + // Run the solver again now that it's cached. + schedulePub(args: ['install'], + output: new RegExp("Dependencies installed!\$")); + + // The update should not have requested the pubspec since it's installed + // locally already. + getRequestedPaths().then((paths) { + expect(paths, isNot(contains("packages/foo/versions/1.2.3.yaml"))); + }); + }); +} diff --git a/test/test_pub.dart b/test/test_pub.dart index d7fdb1df..f5cb82c3 100644 --- a/test/test_pub.dart +++ b/test/test_pub.dart @@ -57,6 +57,10 @@ bool get runningOnBuildbot => /// The current [HttpServer] created using [serve]. var _server; +/// The list of paths that have been requested from the server since the last +/// call to [getRequestedPaths]. +final _requestedPaths = <String>[]; + /// The cached value for [_portCompleter]. Completer<int> _portCompleterCache; @@ -73,6 +77,16 @@ Completer<int> get _portCompleter { /// A future that will complete to the port used for the current server. Future<int> get port => _portCompleter.future; +/// Gets the list of paths that have been requested from the server since the +/// last time this was called (or since the server was first spun up). +Future<List<String>> getRequestedPaths() { + return schedule(() { + var paths = _requestedPaths.toList(); + _requestedPaths.clear(); + return paths; + }); +} + /// Creates an HTTP server to serve [contents] as static files. This server will /// exist only for the duration of the pub run. /// @@ -88,6 +102,10 @@ void serve([List<d.Descriptor> contents]) { var response = request.response; try { var path = request.uri.path.replaceFirst("/", ""); + + if (_requestedPaths == null) _requestedPaths = <String>[]; + _requestedPaths.add(path); + response.persistentConnection = false; var stream = baseDir.load(path); diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart index 6f24b414..b338e11e 100644 --- a/test/version_solver_test.dart +++ b/test/version_solver_test.dart @@ -888,6 +888,10 @@ class MockSource extends Source { MockSource(this.name); + Future<String> systemCacheDirectory(PackageId id) { + return new Future.value('${id.name}-${id.version}'); + } + Future<List<Version>> getVersions(String name, String description) { return new Future.sync(() { // Make sure the solver doesn't request the same thing twice. -- GitLab