diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart index f2828ecf215330977f05c61119b1e33ae5c96c47..57f806a14af74b18b587438eab3041b827c7fc01 100644 --- a/lib/src/global_packages.dart +++ b/lib/src/global_packages.dart @@ -14,6 +14,7 @@ import 'io.dart'; import 'lock_file.dart'; import 'log.dart' as log; import 'package.dart'; +import 'pubspec.dart'; import 'system_cache.dart'; import 'solver/version_solver.dart'; import 'source/cached.dart'; @@ -68,8 +69,8 @@ class GlobalPackages { // Call this just to log what the current active package is, if any. _describeActive(name); - var id = new PackageId(name, "git", Version.none, repo); - return _installInCache(id); + return _installInCache( + new PackageDep(name, "git", VersionConstraint.any, repo)); }); } @@ -77,24 +78,7 @@ class GlobalPackages { /// [constraint] and makes it the active global version. Future activateHosted(String name, VersionConstraint constraint) { _describeActive(name); - - var source = cache.sources["hosted"]; - return source.getVersions(name, name).then((versions) { - versions = versions.where(constraint.allows).toList(); - - if (versions.isEmpty) { - // TODO(rnystrom): Show most recent unmatching version? - dataError("Package ${log.bold(name)} has no versions that match " - "$constraint."); - } - - // Pick the best matching version. - versions.sort(Version.prioritize); - - // Make sure it's in the cache. - var id = new PackageId(name, "hosted", versions.last, name); - return _installInCache(id); - }); + return _installInCache(new PackageDep(name, "hosted", constraint, name)); } /// Makes the local package at [path] globally active. @@ -112,36 +96,27 @@ class GlobalPackages { var fullPath = canonicalize(entrypoint.root.dir); var id = new PackageId(name, "path", entrypoint.root.version, PathSource.describePath(fullPath)); - _writeLockFile(id, new LockFile.empty()); + _writeLockFile(name, new LockFile([id])); }); } - /// Installs the package [id] and its dependencies into the system cache. - Future _installInCache(PackageId id) { - var source = cache.sources[id.source]; + /// Installs the package [dep] and its dependencies into the system cache. + Future _installInCache(PackageDep dep) { + var source = cache.sources[dep.source]; - // Put the main package in the cache. - return source.downloadToSystemCache(id).then((package) { - // If we didn't know the version for the ID (which is true for Git - // packages), look it up now that we have it. - if (id.version == Version.none) { - id = id.atVersion(package.version); - } + // Create a dummy package with just [dep] so we can do resolution on it. + var root = new Package.inMemory(new Pubspec("pub global activate", + dependencies: [dep], sources: cache.sources)); - return source.resolveId(id).then((id_) { - id = id_; - - // Resolve it and download its dependencies. - return resolveVersions(SolveType.GET, cache.sources, package); - }); - }).then((result) { + // Resolve it and download its dependencies. + return resolveVersions(SolveType.GET, cache.sources, root).then((result) { if (!result.succeeded) throw result.error; result.showReport(SolveType.GET); // Make sure all of the dependencies are locally installed. return Future.wait(result.packages.map(_cacheDependency)); }).then((ids) { - _writeLockFile(id, new LockFile(ids)); + _writeLockFile(dep.name, new LockFile(ids)); }); } @@ -159,15 +134,13 @@ class GlobalPackages { }).then((_) => source.resolveId(id)); } - /// Finishes activating package [id] by saving [lockFile] in the cache. - void _writeLockFile(PackageId id, LockFile lockFile) { - // Add the root package to the lockfile. - lockFile.packages[id.name] = id; - + /// Finishes activating package [package] by saving [lockFile] in the cache. + void _writeLockFile(String package, LockFile lockFile) { ensureDir(_directory); - writeTextFile(_getLockFilePath(id.name), + writeTextFile(_getLockFilePath(package), lockFile.serialize(cache.rootDir, cache.sources)); + var id = lockFile.packages[package]; if (id.source == "git") { var url = GitSource.urlFromDescription(id.description); log.message('Activated ${log.bold(id.name)} ${id.version} from Git ' diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart index 2ab26b21cdf4731023598d3124e9e0775b1f43c2..7aa573503dbd3d1127a07f07703530f8d6c678e7 100644 --- a/lib/src/pubspec.dart +++ b/lib/src/pubspec.dart @@ -266,11 +266,23 @@ class Pubspec { expectedName: expectedName, location: pubspecUri); } - Pubspec(this._name, this._version, this._dependencies, this._devDependencies, - this._dependencyOverrides, this._environment, this._transformers, - [Map fields]) - : this.fields = fields == null ? new YamlMap() : fields, - _sources = null; + Pubspec(this._name, {Version version, Iterable<PackageDep> dependencies, + Iterable<PackageDep> devDependencies, + Iterable<PackageDep> dependencyOverrides, + VersionConstraint sdkConstraint, + Iterable<Iterable<TransformerConfig>> transformers, + Map fields, SourceRegistry sources}) + : _version = version, + _dependencies = dependencies == null ? null : dependencies.toList(), + _devDependencies = devDependencies == null ? null : + devDependencies.toList(), + _dependencyOverrides = dependencyOverrides == null ? null : + dependencyOverrides.toList(), + _environment = new PubspecEnvironment(sdkConstraint), + _transformers = transformers == null ? [] : + transformers.map((phase) => phase.toSet()).toList(), + fields = fields == null ? new YamlMap() : new YamlMap.wrap(fields), + _sources = sources; Pubspec.empty() : _sources = null, diff --git a/test/global/activate/supports_version_solver_backtracking_test.dart b/test/global/activate/supports_version_solver_backtracking_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..1aa6f5c2030ffa8cd3789ce04796aa4ab5158eaf --- /dev/null +++ b/test/global/activate/supports_version_solver_backtracking_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2014, 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. + +import 'package:scheduled_test/scheduled_test.dart'; + +import '../../descriptor.dart' as d; +import '../../test_pub.dart'; + +main() { + initConfig(); + integration('performs verison solver backtracking if necessary', () { + servePackages([ + packageMap("foo", "1.1.0")..addAll({ + "environment": {"sdk": ">=0.1.2 <0.2.0"} + }), + packageMap("foo", "1.2.0")..addAll({ + "environment": {"sdk": ">=0.1.3 <0.2.0"} + }), + ]); + + schedulePub(args: ["global", "activate", "foo"]); + + // foo 1.2.0 won't be picked because its SDK constraint conflicts with the + // dummy SDK version 0.1.2+3. + d.dir(cachePath, [ + d.dir('global_packages', [ + d.matcherFile('foo.lock', contains('1.1.0')) + ]) + ]).validate(); + }); +} diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart index de0d1135de5fdb45b1a6bb0014c9b123773fe560..d98a5bff0a875b18cb7cd7f58a7641b747111aa3 100644 --- a/test/version_solver_test.dart +++ b/test/version_solver_test.dart @@ -1462,10 +1462,12 @@ Package mockPackage(PackageId id, Map dependencyStrings, Map overrides) { }); } - var pubspec = new Pubspec(id.name, id.version, dependencies, - devDependencies, dependencyOverrides, - new PubspecEnvironment(sdkConstraint), []); - return new Package.inMemory(pubspec); + return new Package.inMemory(new Pubspec(id.name, + version: id.version, + dependencies: dependencies, + devDependencies: devDependencies, + dependencyOverrides: dependencyOverrides, + sdkConstraint: sdkConstraint)); } /// Creates a new [PackageId] parsed from [text], which looks something like