Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Unified Diff: sdk/lib/_internal/pub/lib/src/entrypoint.dart

Issue 482053002: Precompile dependencies' executables for use with "pub run". (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Make our SDK version file match the SDK's. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sdk/lib/_internal/pub/lib/src/executable.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/pub/lib/src/entrypoint.dart
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index 9d2f815b571c42310d35b1a098313fb0253c807a..16b19a59259207afabb4493ae3fd744c18a89e10 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -5,14 +5,19 @@
library pub.entrypoint;
import 'dart:async';
+import 'dart:io';
import 'package:path/path.dart' as path;
+import 'package:barback/barback.dart';
+import 'barback/asset_environment.dart';
+import 'exceptions.dart';
import 'io.dart';
import 'lock_file.dart';
import 'log.dart' as log;
import 'package.dart';
import 'package_graph.dart';
+import 'sdk.dart' as sdk;
import 'solver/version_solver.dart';
import 'source/cached.dart';
import 'system_cache.dart';
@@ -133,10 +138,133 @@ class Entrypoint {
_linkOrDeleteSecondaryPackageDirs();
result.summarizeChanges(type, dryRun: dryRun);
+
+ // TODO(nweiz): we've already parsed all the pubspecs and we know the
+ // lockfile is up to date; there's got to be a way to re-use that
+ // information here.
+ //
+ // Also, don't precompile stuff when the transitive dependencies
+ // haven't changed.
+ return precompileExecutables().catchError((error, stackTrace) {
+ // Just log exceptions here. Since the method is just about acquiring
+ // dependencies, it shouldn't fail unless that fails.
+ log.exception(error, stackTrace);
+ });
});
});
}
+ /// Precompiles all executables from dependencies that don't transitively
+ /// depend on [this] or on a path dependency.
+ Future precompileExecutables() {
+ return loadPackageGraph().then((graph) {
+ var executables = new Map.fromIterable(root.immediateDependencies,
+ key: (dep) => dep.name,
+ value: (dep) => _executablesForPackage(graph, dep.name));
+
+ for (var package in executables.keys.toList()) {
+ if (executables[package].isEmpty) executables.remove(package);
+ }
+
+ var binDir = path.join('.pub', 'bin');
+ deleteEntry(binDir);
+ if (executables.isEmpty) return null;
+
+ return log.progress("Precompiling executables", () {
+ // TODO(nweiz): Only add assets touchable by the executables we're
+ // precompiling.
+ ensureDir(binDir);
+
+ // Make sure there's a trailing newline so our version file matches the
+ // SDK's.
+ writeTextFile(path.join(binDir, 'sdk-version'), "${sdk.version}\n");
+ return AssetEnvironment.create(this, BarbackMode.RELEASE,
+ WatcherType.NONE, useDart2JS: false).then((environment) {
+ environment.barback.errors.listen((error) {
+ log.error(log.red("Build error:\n$error"));
+ });
+
+ return waitAndPrintErrors(executables.keys.map((package) {
+ return _precompileExecutablesForPackage(
+ environment, package, executables[package]);
+ }));
+ });
+ });
+ });
+ }
+
+ /// Returns the list of all executable assets for [packageName] that should be
+ /// precompiled.
+ ///
+ /// If [changed] isn't `null`, executables for [packageName] will only be
+ /// compiled if they might depend on a package in [changed].
+ List<AssetId> _executablesForPackage(PackageGraph graph, String packageName) {
+ var package = graph.packages[packageName];
+ var binDir = path.join(package.dir, 'bin');
+ if (!dirExists(binDir)) return [];
+
+ // If the lockfile has a dependency on the entrypoint or on a path
+ // dependency, its executables could change at any point, so we
+ // shouldn't precompile them.
+ var hasUncachedDependency = graph.transitiveDependencies(packageName)
+ .any((package) {
+ var source = cache.sources[
+ graph.lockFile.packages[package.name].source];
+ return source is! CachedSource;
+ });
+ if (hasUncachedDependency) return [];
+
+ return ordered(package.listFiles(beneath: binDir, recursive: false))
+ .where((executable) => path.extension(executable) == '.dart')
+ .map((executable) {
+ return new AssetId(
+ package.name,
+ path.toUri(path.relative(executable, from: package.dir))
+ .toString());
+ }).toList();
+ }
+
+ /// Precompiles all [executables] for [package].
+ ///
+ /// [executables] is assumed to be a list of Dart executables in [package]'s
+ /// bin directory.
+ Future _precompileExecutablesForPackage(
+ AssetEnvironment environment, String package, List<AssetId> executables) {
+ var cacheDir = path.join('.pub', 'bin', package);
+ ensureDir(cacheDir);
+
+ // TODO(nweiz): Unserve this directory when we're done with it.
+ return environment.servePackageBinDirectory(package).then((server) {
+ return waitAndPrintErrors(executables.map((id) {
+ var basename = path.url.basename(id.path);
+ var snapshotPath = path.join(cacheDir, "$basename.snapshot");
+ return runProcess(Platform.executable, [
+ '--snapshot=$snapshotPath',
+ server.url.resolve(basename).toString()
+ ]).then((result) {
+ if (result.success) {
+ log.message("Precompiled ${_executableName(id)}.");
+ } else {
+ // TODO(nweiz): Stop manually deleting this when issue 20504 is
+ // fixed.
+ deleteEntry(snapshotPath);
+ throw new ApplicationException(
+ log.yellow("Failed to precompile "
+ "${_executableName(id)}:\n") +
+ result.stderr.join('\n'));
+ }
+ });
+ }));
+ });
+ }
+
+ /// Returns the executable name for [id].
+ ///
+ /// [id] is assumed to be an executable in a bin directory. The return value
+ /// is intended for log output and may contain formatting.
+ String _executableName(AssetId id) =>
+ log.bold("${id.package}:${path.basenameWithoutExtension(id.path)}");
+
/// Makes sure the package at [id] is locally available.
///
/// This automatically downloads the package to the system-wide cache as well
« no previous file with comments | « no previous file | sdk/lib/_internal/pub/lib/src/executable.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698