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 bbb289a50e740578e00f8e128e92d1fb09d31c51..08f9fb1a544e57b55396aa90669b740c8950313b 100644 |
--- a/sdk/lib/_internal/pub/lib/src/global_packages.dart |
+++ b/sdk/lib/_internal/pub/lib/src/global_packages.dart |
@@ -8,14 +8,19 @@ import 'dart:async'; |
import 'dart:io'; |
import 'package:path/path.dart' as p; |
+import 'package:barback/barback.dart'; |
+import 'barback/asset_environment.dart'; |
import 'entrypoint.dart'; |
+import 'executable.dart' as exe; |
import 'io.dart'; |
import 'lock_file.dart'; |
import 'log.dart' as log; |
import 'package.dart'; |
import 'pubspec.dart'; |
+import 'package_graph.dart'; |
import 'system_cache.dart'; |
+import 'sdk.dart' as sdk; |
import 'solver/version_solver.dart'; |
import 'source/cached.dart'; |
import 'source/git.dart'; |
@@ -69,6 +74,10 @@ class GlobalPackages { |
// Call this just to log what the current active package is, if any. |
_describeActive(name); |
+ // TODO(nweiz): Add some special handling for git repos that contain path |
+ // dependencies. Their executables shouldn't be cached, and there should |
+ // be a mechanism for redoing dependency resolution if a path pubspec has |
+ // changed (see also issue 20499). |
return _installInCache( |
new PackageDep(name, "git", VersionConstraint.any, repo)); |
}); |
@@ -96,7 +105,13 @@ class GlobalPackages { |
var fullPath = canonicalize(entrypoint.root.dir); |
var id = new PackageId(name, "path", entrypoint.root.version, |
PathSource.describePath(fullPath)); |
+ |
+ // TODO(rnystrom): Look in "bin" and display list of binaries that |
+ // user can run. |
_writeLockFile(name, new LockFile([id])); |
+ |
+ var binDir = p.join(_directory, name, 'bin'); |
+ if (dirExists(binDir)) deleteEntry(binDir); |
}); |
} |
@@ -120,9 +135,36 @@ class GlobalPackages { |
result.showReport(SolveType.GET); |
// Make sure all of the dependencies are locally installed. |
- return Future.wait(result.packages.map(_cacheDependency)); |
- }).then((ids) { |
- _writeLockFile(dep.name, new LockFile(ids)); |
+ return Future.wait(result.packages.map(_cacheDependency)).then((ids) { |
+ var lockFile = new LockFile(ids); |
+ |
+ // Load the package graph from [result] so we don't need to re-parse all |
+ // the pubspecs. |
+ return new Entrypoint.inMemory(root, lockFile, cache) |
+ .loadPackageGraph(result) |
+ .then((graph) => _precompileExecutables(graph.entrypoint, dep.name)) |
+ .then((_) => _writeLockFile(dep.name, lockFile)); |
+ }); |
+ }); |
+ } |
+ |
+ /// Precompiles the executables for [package] and saves them in the global |
+ /// cache. |
+ Future _precompileExecutables(Entrypoint entrypoint, String package) { |
+ return log.progress("Precompiling executables", () { |
+ var binDir = p.join(_directory, package, 'bin'); |
+ var sdkVersionPath = p.join(binDir, 'sdk-version'); |
+ cleanDir(binDir); |
+ writeTextFile(sdkVersionPath, "${sdk.version}\n"); |
+ |
+ return AssetEnvironment.create(entrypoint, BarbackMode.RELEASE, |
+ useDart2JS: false).then((environment) { |
+ environment.barback.errors.listen((error) { |
+ log.error(log.red("Build error:\n$error")); |
+ }); |
+ |
+ return environment.precompileExecutables(package, binDir); |
+ }); |
}); |
} |
@@ -142,15 +184,20 @@ class GlobalPackages { |
/// Finishes activating package [package] by saving [lockFile] in the cache. |
void _writeLockFile(String package, LockFile lockFile) { |
- ensureDir(_directory); |
+ ensureDir(p.join(_directory, package)); |
+ |
+ // TODO(nweiz): This cleans up Dart 1.6's old lockfile location. Remove it |
+ // when Dart 1.6 is old enough that we don't think anyone will have these |
+ // lockfiles anymore (issue 20703). |
+ var oldPath = p.join(_directory, "$package.lock"); |
+ if (fileExists(oldPath)) deleteEntry(oldPath); |
+ |
writeTextFile(_getLockFilePath(package), |
lockFile.serialize(cache.rootDir, cache.sources)); |
var id = lockFile.packages[package]; |
log.message('Activated ${_formatPackage(id)}.'); |
- // TODO(rnystrom): Look in "bin" and display list of binaries that |
- // user can run. |
} |
/// Shows the user the currently active package with [name], if any. |
@@ -184,18 +231,17 @@ class GlobalPackages { |
/// |
/// Returns `false` if no package with [name] was currently active. |
bool deactivate(String name, {bool logDeactivate: 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); |
+ var dir = p.join(_directory, name); |
+ if (!dirExists(dir)) return false; |
if (logDeactivate) { |
+ var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); |
+ var id = lockFile.packages[name]; |
log.message('Deactivated package ${_formatPackage(id)}.'); |
} |
+ deleteEntry(dir); |
+ |
return true; |
} |
@@ -204,12 +250,25 @@ class GlobalPackages { |
/// Returns an [Entrypoint] loaded with the active package if found. |
Future<Entrypoint> find(String name) { |
return syncFuture(() { |
+ var lockFilePath = _getLockFilePath(name); |
var lockFile; |
try { |
- lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); |
+ lockFile = new LockFile.load(lockFilePath, cache.sources); |
} on IOException catch (error) { |
- // If we couldn't read the lock file, it's not activated. |
- dataError("No active package ${log.bold(name)}."); |
+ var oldLockFilePath = p.join(_directory, '$name.lock'); |
+ try { |
+ // TODO(nweiz): This looks for Dart 1.6's old lockfile location. |
+ // Remove it when Dart 1.6 is old enough that we don't think anyone |
+ // will have these lockfiles anymore (issue 20703). |
+ lockFile = new LockFile.load(oldLockFilePath, cache.sources); |
+ } on IOException catch (error) { |
+ // If we couldn't read the lock file, it's not activated. |
+ dataError("No active package ${log.bold(name)}."); |
+ } |
+ |
+ // Move the old lockfile to its new location. |
+ ensureDir(p.dirname(lockFilePath)); |
+ new File(oldLockFilePath).renameSync(lockFilePath); |
} |
// Load the package from the cache. |
@@ -235,25 +294,65 @@ class GlobalPackages { |
}); |
} |
+ /// Runs [package]'s [executable] with [args]. |
+ /// |
+ /// If [executable] is available in its precompiled form, that will be |
+ /// recompiled if the SDK has been upgraded since it was first compiled and |
+ /// then run. Otherwise, it will be run from source. |
+ /// |
+ /// Returns the exit code from the executable. |
+ Future<int> runExecutable(String package, String executable, |
+ Iterable<String> args) { |
+ var binDir = p.join(_directory, package, 'bin'); |
+ if (!fileExists(p.join(binDir, '$executable.dart.snapshot'))) { |
+ return find(package).then((entrypoint) { |
+ return exe.runExecutable(entrypoint, package, executable, args, |
+ isGlobal: true); |
+ }); |
+ } |
+ |
+ // Unless the user overrides the verbosity, we want to filter out the |
+ // normal pub output shown while loading the environment. |
+ if (log.verbosity == log.Verbosity.NORMAL) { |
+ log.verbosity = log.Verbosity.WARNING; |
+ } |
+ |
+ return syncFuture(() { |
+ var sdkVersionPath = p.join(binDir, 'sdk-version'); |
+ var snapshotVersion = readTextFile(sdkVersionPath); |
+ if (snapshotVersion == "${sdk.version}\n") return null; |
+ log.fine("$package:$executable was compiled with Dart " |
+ "${snapshotVersion.trim()} and needs to be recompiled."); |
+ |
+ return find(package) |
+ .then((entrypoint) => entrypoint.loadPackageGraph()) |
+ .then((graph) => _precompileExecutables(graph.entrypoint, package)); |
+ }).then((_) => |
+ exe.runSnapshot(p.join(binDir, '$executable.dart.snapshot'), args)); |
+ } |
+ |
/// Gets the path to the lock file for an activated cached package with |
/// [name]. |
- String _getLockFilePath(name) => p.join(_directory, name + ".lock"); |
+ String _getLockFilePath(String name) => |
+ p.join(_directory, name, "pubspec.lock"); |
/// Shows to the user formatted list of globally activated packages. |
void listActivePackages() { |
if (!dirExists(_directory)) return; |
// Loads lock [file] and returns [PackageId] of the activated package. |
- loadPackageId(file) { |
- var name = p.basenameWithoutExtension(file); |
+ loadPackageId(file, name) { |
var lockFile = new LockFile.load(p.join(_directory, file), cache.sources); |
return lockFile.packages[name]; |
} |
- var packages = listDir(_directory, includeDirs: false) |
- .where((file) => p.extension(file) == '.lock') |
- .map(loadPackageId) |
- .toList(); |
+ var packages = listDir(_directory).map((entry) { |
+ if (fileExists(entry)) { |
+ return loadPackageId(entry, p.basenameWithoutExtension(entry)); |
+ } else { |
+ return loadPackageId(p.join(entry, 'pubspec.lock'), p.basename(entry)); |
+ } |
+ }).toList(); |
packages |
..sort((id1, id2) => id1.name.compareTo(id2.name)) |