Chromium Code Reviews| 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 |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..76f244f7913354207f4ca36d80cbb136e035fdd4 |
| --- /dev/null |
| +++ b/sdk/lib/_internal/pub/lib/src/global_packages.dart |
| @@ -0,0 +1,129 @@ |
| +// 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. |
| + |
| +library pub.global_packages; |
| + |
| +import 'dart:async'; |
| +import 'dart:io'; |
| + |
| +import 'package:path/path.dart' as path; |
| + |
| +import 'io.dart'; |
| +import 'lock_file.dart'; |
| +import 'log.dart' as log; |
| +import 'package.dart'; |
| +import 'system_cache.dart'; |
| +import 'solver/version_solver.dart'; |
| +import 'source/cached.dart'; |
| +import 'utils.dart'; |
| +import 'version.dart'; |
| + |
| +/// Maintains the set of packages that have been globally activated. |
| +/// |
| +/// These have been hand-chosen by the user to be made available to the entire |
| +/// system. This lets them access a package even when the current working |
| +/// directory is not inside another entrypoint package. |
|
nweiz
2014/06/26 22:43:25
Make it clear that availability is just in terms o
Bob Nystrom
2014/06/27 00:30:23
Done.
|
| +/// |
| +/// 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. |
| +class GlobalPackages { |
| + /// The [SystemCache] containing the global packages. |
| + final SystemCache cache; |
| + |
| + /// The directory where the lockfiles for activated packages are stored. |
| + String get _directory => path.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. |
| + /// |
| + /// The directory may not physically exist yet. If not, this will create it |
| + /// when needed. |
| + GlobalPackages(this.cache); |
| + |
| + /// Finds the latest version of hosted package with [name] that matches |
|
nweiz
2014/06/26 22:43:25
"of hosted" -> "of the hosted"
Bob Nystrom
2014/06/27 00:30:23
Done.
|
| + /// [constraint] and makes it the active global version. |
| + Future activate(String name, VersionConstraint constraint) { |
| + var lockFilePath = path.join(_directory, name + ".lock"); |
| + var versionFilePath = path.join(_directory, name + ".version"); |
|
nweiz
2014/06/26 22:43:25
It seems a little weird to store the version in a
Bob Nystrom
2014/06/27 00:30:23
That felt a little weird at first, but I realized
|
| + |
| + // See if we already have it activated. |
| + var lockFile; |
| + var currentVersion; |
| + try { |
| + lockFile = new LockFile.load(lockFilePath, cache.sources); |
| + currentVersion = new Version.parse(readTextFile(versionFilePath)); |
| + |
| + 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 and version file, it's not activated. |
| + lockFile = new LockFile.empty(); |
| + } |
| + |
| + var package; |
| + return _selectVersion(name, currentVersion, constraint).then((version) { |
| + // Make sure it's in the cache. |
| + var id = new PackageId(name, _source.name, version, name); |
| + return _source.downloadToSystemCache(id); |
| + }).then((p) { |
| + package = p; |
| + // Resolve it and download its dependencies. |
| + return resolveVersions(cache.sources, package, lockFile: lockFile); |
| + }).then((result) { |
| + if (!result.succeeded) throw result.error; |
| + result.showReport(); |
| + |
| + // Make sure all of the dependencies are locally installed. |
| + 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) { |
| + // Write the lock file. |
| + var lockFile = new LockFile(ids); |
| + ensureDir(_directory); |
| + writeTextFile(lockFilePath, |
| + lockFile.serialize(cache.rootDir, cache.sources)); |
|
nweiz
2014/06/26 22:43:25
Indent this line.
Bob Nystrom
2014/06/27 00:30:23
Done.
|
| + |
| + // Write the version file. |
| + writeTextFile(versionFilePath, package.version.toString()); |
| + |
| + log.message("Activated ${log.bold(package.name)} ${package.version}."); |
|
nweiz
2014/06/26 22:43:25
For consistency with the message above, maybe word
Bob Nystrom
2014/06/27 00:30:23
I don't like to start a message with a package nam
nweiz
2014/06/30 19:42:28
In that case the "already active" message shouldn'
Bob Nystrom
2014/06/30 20:36:01
I made it bold there to stress that the version is
|
| + // TODO(rnystrom): Look in "bin" display list of binaries that |
|
nweiz
2014/06/26 22:43:26
"display" -> "and display"
Bob Nystrom
2014/06/27 00:30:23
Done.
|
| + // user can run. |
| + }); |
| + } |
| + |
| + /// Picks the best version of [package] to activate that meets [constraint]. |
| + /// |
| + /// If [version] is not `null`, will try to maintain that version if possible. |
|
nweiz
2014/06/26 22:43:25
"will" -> "this will"
Bob Nystrom
2014/06/27 00:30:23
Done.
|
| + Future<Version> _selectVersion(String package, Version version, |
| + VersionConstraint constraint) { |
|
nweiz
2014/06/26 22:43:25
Nit: this isn't how we usually indent long version
Bob Nystrom
2014/06/27 00:30:23
Done. Just switched to IntelliJ so I'm still getti
|
| + // If we already have a valid active version, just use it. |
| + if (version != null && constraint.allows(version)) { |
| + return new Future.value(version); |
| + } |
| + |
| + // Otherwise, select the best version the matches the constraint. |
| + return _source.getVersions(package, package).then((versions) { |
| + versions = versions.where(constraint.allows).toList(); |
| + |
| + if (versions.isEmpty) { |
| + // TODO(rnystrom): Show most recent unmatching version? |
|
nweiz
2014/06/26 22:43:25
I like this idea.
Bob Nystrom
2014/06/27 00:30:23
Leaving it as a TODO for now, but I do too.
|
| + dataError("Package $package has no versions that match $constraint."); |
|
nweiz
2014/06/26 22:43:25
Bold the package name. Maybe the constraint too?
Bob Nystrom
2014/06/27 00:30:23
Done the former, not the latter.
|
| + } |
| + |
| + // Pick the best matching version. |
| + versions.sort(Version.prioritize); |
| + return versions.last; |
| + }); |
| + } |
| +} |