| Index: sdk/lib/_internal/pub/lib/src/global_packages.dart
|
| diff --git a/sdk/lib/_internal/pub/lib/src/global_packages.dart b/sdk/lib/_internal/pub/lib/src/global_packages.dart
|
| index 3f9f8db05397e85243c7f270aaa19b18580508b8..b9bb54881fc29e904daf9b3afdc69add61c7c97e 100644
|
| --- a/sdk/lib/_internal/pub/lib/src/global_packages.dart
|
| +++ b/sdk/lib/_internal/pub/lib/src/global_packages.dart
|
| @@ -16,9 +16,7 @@ import 'log.dart' as log;
|
| import 'package.dart';
|
| import 'system_cache.dart';
|
| import 'solver/version_solver.dart';
|
| -import 'source.dart';
|
| import 'source/cached.dart';
|
| -import 'source/path.dart';
|
| import 'utils.dart';
|
| import 'version.dart';
|
|
|
| @@ -31,21 +29,6 @@ import 'version.dart';
|
| /// Only one version of a given package name can be globally activated at a
|
| /// time. Activating a different version of a package will deactivate the
|
| /// previous one.
|
| -///
|
| -/// This handles packages from uncached and cached sources a little differently.
|
| -/// For a cached source, the package is physically in the user's pub cache and
|
| -/// we don't want to mess with it by putting a lockfile in there. Instead, when
|
| -/// we activate the package, we create a full lockfile and put it in the
|
| -/// "global_packages" directory. It's named "<package>.lock". Unlike a normal
|
| -/// lockfile, it also contains an entry for the root package itself, so that we
|
| -/// know the version and description that was activated.
|
| -///
|
| -/// Uncached packages (i.e. "path" packages) are somewhere else on the user's
|
| -/// local file system and can have a lockfile directly in place. (And, in fact,
|
| -/// we want to ensure we honor the user's lockfile there.) To activate it, we
|
| -/// just need to know where that package directory is. For that, we create a
|
| -/// lockfile that *only* contains the root package's [PackageId] -- basically
|
| -/// just the path to the directory where the real lockfile lives.
|
| class GlobalPackages {
|
| /// The [SystemCache] containing the global packages.
|
| final SystemCache cache;
|
| @@ -53,6 +36,10 @@ class GlobalPackages {
|
| /// The directory where the lockfiles for activated packages are stored.
|
| String get _directory => p.join(cache.rootDir, "global_packages");
|
|
|
| + /// The source that global packages can be activated from.
|
| + // TODO(rnystrom): Allow activating packages from other sources.
|
| + CachedSource get _source => cache.sources["hosted"] as CachedSource;
|
| +
|
| /// Creates a new global package registry backed by the given directory on
|
| /// the user's file system.
|
| ///
|
| @@ -60,213 +47,111 @@ class GlobalPackages {
|
| /// when needed.
|
| GlobalPackages(this.cache);
|
|
|
| - /// Activates the Git repo described by [ref] for package [name].
|
| - Future activateGit(String name, String ref) {
|
| - // See if we already have it activated.
|
| - var lockFile = _describeActive(name);
|
| - var id;
|
| - if (lockFile != null) {
|
| - id = lockFile.packages[name];
|
| - } else {
|
| - id = new PackageId(name, "git", Version.none, ref);
|
| - }
|
| -
|
| - return _installInCache(id, lockFile);
|
| - }
|
| -
|
| /// Finds the latest version of the hosted package with [name] that matches
|
| /// [constraint] and makes it the active global version.
|
| - Future activateHosted(String name, VersionConstraint constraint) {
|
| + Future activate(String name, VersionConstraint constraint) {
|
| // See if we already have it activated.
|
| - var lockFile = _describeActive(name);
|
| + var lockFile;
|
| var currentVersion;
|
| - if (lockFile != null) {
|
| - var id = lockFile.packages[name];
|
| -
|
| - // Try to preserve the current version if we've already activated the
|
| - // hosted package.
|
| - if (id.source == "hosted") currentVersion = id.version;
|
| + try {
|
| + lockFile = new LockFile.load(_getLockFilePath(name), cache.sources);
|
| + currentVersion = lockFile.packages[name].version;
|
|
|
| // Pull the root package out of the lock file so the solver doesn't see
|
| // it.
|
| lockFile.packages.remove(name);
|
| - } else {
|
| +
|
| + log.message("Package ${log.bold(name)} is already active at "
|
| + "version ${log.bold(currentVersion)}.");
|
| + } on IOException catch (error) {
|
| + // If we couldn't read the lock file, it's not activated.
|
| lockFile = new LockFile.empty();
|
| }
|
|
|
| + var package;
|
| + var id;
|
| return _selectVersion(name, currentVersion, constraint).then((version) {
|
| // Make sure it's in the cache.
|
| - var id = new PackageId(name, "hosted", version, name);
|
| - return _installInCache(id, lockFile);
|
| - });
|
| - }
|
| -
|
| - /// Makes the local package at [path] globally active.
|
| - Future activatePath(String path) {
|
| - return syncFuture(() {
|
| - var entrypoint = new Entrypoint(path, cache);
|
| -
|
| - var name = entrypoint.root.name;
|
| - _describeActive(name);
|
| -
|
| - // Write a lockfile that points to the local package.
|
| - var fullPath = canonicalize(entrypoint.root.dir);
|
| - var id = new PackageId(name, "path", entrypoint.root.version,
|
| - PathSource.describePath(fullPath));
|
| - _finishActivation(id, new LockFile.empty());
|
| - });
|
| - }
|
| -
|
| - /// Installs the package [id] with [lockFile] into the system cache.
|
| - Future _installInCache(PackageId id, LockFile lockFile) {
|
| - var source = cache.sources[id.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);
|
| - }
|
| -
|
| - return source.resolveId(id).then((id_) {
|
| - id = id_;
|
| -
|
| - // Resolve it and download its dependencies.
|
| - return resolveVersions(SolveType.GET, cache.sources, package,
|
| - lockFile: lockFile);
|
| - });
|
| + id = new PackageId(name, _source.name, version, name);
|
| + return _source.downloadToSystemCache(id);
|
| + }).then((p) {
|
| + package = p;
|
| + // Resolve it and download its dependencies.
|
| + return resolveVersions(SolveType.GET, cache.sources, package,
|
| + lockFile: lockFile);
|
| }).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));
|
| + return Future.wait(result.packages.map((id) {
|
| + var source = cache.sources[id.source];
|
| + if (source is! CachedSource) return new Future.value();
|
| + return source.downloadToSystemCache(id)
|
| + .then((_) => source.resolveId(id));
|
| + }));
|
| }).then((ids) {
|
| - _finishActivation(id, new LockFile(ids));
|
| - });
|
| - }
|
| -
|
| - /// Downloads [id] into the system cache if it's a cached package.
|
| - ///
|
| - /// Returns the resolved [PackageId] for [id].
|
| - Future<PackageId> _cacheDependency(PackageId id) {
|
| - var source = cache.sources[id.source];
|
| -
|
| - return syncFuture(() {
|
| - if (id.isRoot) return null;
|
| - if (source is! CachedSource) return null;
|
| -
|
| - return source.downloadToSystemCache(id);
|
| - }).then((_) => source.resolveId(id));
|
| - }
|
| -
|
| - /// Finishes activating package [id] by saving [lockFile] in the cache.
|
| - void _finishActivation(PackageId id, LockFile lockFile) {
|
| - deactivate(id.name);
|
| + var lockFile = new LockFile(ids);
|
|
|
| - // Add the root package to the lockfile.
|
| - lockFile.packages[id.name] = id;
|
| + // Add the root package itself to the lockfile.
|
| + lockFile.packages[name] = id;
|
|
|
| - ensureDir(_directory);
|
| - writeTextFile(_getLockFilePath(id.name),
|
| - lockFile.serialize(cache.rootDir, cache.sources));
|
| + ensureDir(_directory);
|
| + writeTextFile(_getLockFilePath(name),
|
| + lockFile.serialize(cache.rootDir, cache.sources));
|
|
|
| - log.message("Activated ${log.bold(id.name)} ${id.version}.");
|
| - // TODO(rnystrom): Look in "bin" and display list of binaries that
|
| - // user can run.
|
| + log.message("Activated ${log.bold(package.name)} ${package.version}.");
|
| + // TODO(rnystrom): Look in "bin" and display list of binaries that
|
| + // user can run.
|
| + });
|
| }
|
|
|
| - /// Gets the lock file for the currently activate package with [name].
|
| - ///
|
| - /// Displays a message to the user about the current package, if any. Returns
|
| - /// the [LockFile] for the active package or `null` otherwise.
|
| - LockFile _describeActive(String package) {
|
| + /// Deactivates a previously-activated package named [name] or fails with
|
| + /// an error if [name] is not an active package.
|
| + void deactivate(String name) {
|
| + // See if we already have it activated.
|
| try {
|
| - var lockFile = new LockFile.load(_getLockFilePath(package),
|
| - cache.sources);
|
| - var id = lockFile.packages[package];
|
| + var lockFilePath = p.join(_directory, "$name.lock");
|
| + var lockFile = new LockFile.load(lockFilePath, cache.sources);
|
| + var version = lockFile.packages[name].version;
|
|
|
| - if (id.source == "path") {
|
| - var path = PathSource.pathFromDescription(id.description);
|
| - log.message('Package ${log.bold(package)} is already active at '
|
| - 'path "$path".');
|
| - } else {
|
| - log.message("Package ${log.bold(package)} is already active at "
|
| - "version ${log.bold(id.version)}.");
|
| - }
|
| -
|
| - return lockFile;
|
| + deleteEntry(lockFilePath);
|
| + log.message("Deactivated package ${log.bold(name)} $version.");
|
| } on IOException catch (error) {
|
| - // If we couldn't read the lock file, it's not activated.
|
| + dataError("No active package ${log.bold(name)}.");
|
| }
|
| }
|
|
|
| - /// Deactivates a previously-activated package named [name].
|
| - ///
|
| - /// If [logDeletion] is true, displays to the user when a package is
|
| - /// deactivated. Otherwise, deactivates silently.
|
| - ///
|
| - /// Returns `false` if no package with [name] was currently active.
|
| - bool deactivate(String name, {bool logDeletion: false}) {
|
| - var lockFilePath = _getLockFilePath(name);
|
| - if (!fileExists(lockFilePath)) return false;
|
| -
|
| - var lockFile = new LockFile.load(lockFilePath, cache.sources);
|
| - var id = lockFile.packages[name];
|
| -
|
| - deleteEntry(lockFilePath);
|
| -
|
| - if (logDeletion) {
|
| - if (id.source == "path") {
|
| - var path = PathSource.pathFromDescription(id.description);
|
| - log.message('Deactivated package ${log.bold(name)} at path "$path".');
|
| - } else {
|
| - log.message("Deactivated package ${log.bold(name)} ${id.version}.");
|
| - }
|
| - }
|
| -
|
| - return true;
|
| - }
|
| -
|
| - /// Finds the active package with [name].
|
| + /// Finds the active packge with [name].
|
| ///
|
| /// Returns an [Entrypoint] loaded with the active package if found.
|
| Future<Entrypoint> find(String name) {
|
| + var lockFile;
|
| + var version;
|
| return syncFuture(() {
|
| - var lockFile;
|
| try {
|
| lockFile = new LockFile.load(_getLockFilePath(name), cache.sources);
|
| + version = lockFile.packages[name].version;
|
| } on IOException catch (error) {
|
| // If we couldn't read the lock file, it's not activated.
|
| dataError("No active package ${log.bold(name)}.");
|
| }
|
| -
|
| + }).then((_) {
|
| // Load the package from the cache.
|
| - var id = lockFile.packages[name];
|
| + var id = new PackageId(name, _source.name, version, name);
|
| + return _source.getDirectory(id);
|
| + }).then((dir) {
|
| + return new Package.load(name, dir, cache.sources);
|
| + }).then((package) {
|
| + // Pull the root package out of the lock file so the solver doesn't see
|
| + // it.
|
| lockFile.packages.remove(name);
|
|
|
| - var source = cache.sources[id.source];
|
| - if (source is CachedSource) {
|
| - // For cached sources, the package itself is in the cache and the
|
| - // lockfile is the one we just loaded.
|
| - return cache.sources[id.source].getDirectory(id)
|
| - .then((dir) => new Package.load(name, dir, cache.sources))
|
| - .then((package) {
|
| - return new Entrypoint.inMemory(package, lockFile, cache);
|
| - });
|
| - }
|
| -
|
| - // For uncached sources (i.e. path), the ID just points to the real
|
| - // directory for the package.
|
| - assert(id.source == "path");
|
| - return new Entrypoint(PathSource.pathFromDescription(id.description),
|
| - cache);
|
| + return new Entrypoint.inMemory(package, lockFile, cache);
|
| });
|
| }
|
|
|
| - /// Picks the best hosted version of [package] to activate that meets
|
| - /// [constraint].
|
| + /// Picks the best version of [package] to activate that meets [constraint].
|
| ///
|
| /// If [version] is not `null`, this tries to maintain that version if
|
| /// possible.
|
| @@ -278,8 +163,7 @@ class GlobalPackages {
|
| }
|
|
|
| // Otherwise, select the best version the matches the constraint.
|
| - var source = cache.sources["hosted"];
|
| - return source.getVersions(package, package).then((versions) {
|
| + return _source.getVersions(package, package).then((versions) {
|
| versions = versions.where(constraint.allows).toList();
|
|
|
| if (versions.isEmpty) {
|
| @@ -294,7 +178,6 @@ class GlobalPackages {
|
| });
|
| }
|
|
|
| - /// Gets the path to the lock file for an activated cached package with
|
| - /// [name].
|
| + /// Gets the path to the lock file for an activated package with [name].
|
| String _getLockFilePath(name) => p.join(_directory, name + ".lock");
|
| }
|
|
|