| 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
|
|
|