| Index: sdk/lib/_internal/pub_generated/lib/src/entrypoint.dart
|
| diff --git a/sdk/lib/_internal/pub_generated/lib/src/entrypoint.dart b/sdk/lib/_internal/pub_generated/lib/src/entrypoint.dart
|
| index eadf9a997c76aec1888035644eb5d7fcd0ff9d6b..58498435690fcff2a053983daf72ebb67f4cfc11 100644
|
| --- a/sdk/lib/_internal/pub_generated/lib/src/entrypoint.dart
|
| +++ b/sdk/lib/_internal/pub_generated/lib/src/entrypoint.dart
|
| @@ -1,7 +1,14 @@
|
| +// Copyright (c) 2012, 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.entrypoint;
|
| +
|
| import 'dart:async';
|
| +
|
| import 'package:path/path.dart' as path;
|
| import 'package:barback/barback.dart';
|
| +
|
| import 'barback/asset_environment.dart';
|
| import 'io.dart';
|
| import 'lock_file.dart';
|
| @@ -13,31 +20,96 @@ import 'solver/version_solver.dart';
|
| import 'source/cached.dart';
|
| import 'system_cache.dart';
|
| import 'utils.dart';
|
| +
|
| +/// The context surrounding the root package pub is operating on.
|
| +///
|
| +/// Pub operates over a directed graph of dependencies that starts at a root
|
| +/// "entrypoint" package. This is typically the package where the current
|
| +/// working directory is located. An entrypoint knows the [root] package it is
|
| +/// associated with and is responsible for managing the "packages" directory
|
| +/// for it.
|
| +///
|
| +/// That directory contains symlinks to all packages used by an app. These links
|
| +/// point either to the [SystemCache] or to some other location on the local
|
| +/// filesystem.
|
| +///
|
| +/// While entrypoints are typically applications, a pure library package may end
|
| +/// up being used as an entrypoint. Also, a single package may be used as an
|
| +/// entrypoint in one context but not in another. For example, a package that
|
| +/// contains a reusable library may not be the entrypoint when used by an app,
|
| +/// but may be the entrypoint when you're running its tests.
|
| class Entrypoint {
|
| + /// The root package this entrypoint is associated with.
|
| final Package root;
|
| +
|
| + /// The system-wide cache which caches packages that need to be fetched over
|
| + /// the network.
|
| final SystemCache cache;
|
| +
|
| + /// Whether to create and symlink a "packages" directory containing links to
|
| + /// the installed packages.
|
| final bool _packageSymlinks;
|
| +
|
| + /// The lockfile for the entrypoint.
|
| + ///
|
| + /// If not provided to the entrypoint, it will be laoded lazily from disc.
|
| LockFile _lockFile;
|
| +
|
| + /// The graph of all packages reachable from the entrypoint.
|
| PackageGraph _packageGraph;
|
| +
|
| + /// Loads the entrypoint from a package at [rootDir].
|
| + ///
|
| + /// If [packageSymlinks] is `true`, this will create a "packages" directory
|
| + /// with symlinks to the installed packages. This directory will be symlinked
|
| + /// into any directory that might contain an entrypoint.
|
| Entrypoint(String rootDir, SystemCache cache, {bool packageSymlinks: true})
|
| : root = new Package.load(null, rootDir, cache.sources),
|
| cache = cache,
|
| _packageSymlinks = packageSymlinks;
|
| +
|
| + /// Creates an entrypoint given package and lockfile objects.
|
| Entrypoint.inMemory(this.root, this._lockFile, this.cache)
|
| : _packageSymlinks = false;
|
| +
|
| + /// The path to the entrypoint's "packages" directory.
|
| String get packagesDir => root.path('packages');
|
| +
|
| + /// `true` if the entrypoint package currently has a lock file.
|
| bool get lockFileExists => _lockFile != null || entryExists(lockFilePath);
|
| +
|
| LockFile get lockFile {
|
| if (_lockFile != null) return _lockFile;
|
| +
|
| if (!lockFileExists) {
|
| _lockFile = new LockFile.empty();
|
| } else {
|
| _lockFile = new LockFile.load(lockFilePath, cache.sources);
|
| }
|
| +
|
| return _lockFile;
|
| }
|
| +
|
| + /// The path to the entrypoint package's pubspec.
|
| String get pubspecPath => root.path('pubspec.yaml');
|
| +
|
| + /// The path to the entrypoint package's lockfile.
|
| String get lockFilePath => root.path('pubspec.lock');
|
| +
|
| + /// Gets all dependencies of the [root] package.
|
| + ///
|
| + /// Performs version resolution according to [SolveType].
|
| + ///
|
| + /// [useLatest], if provided, defines a list of packages that will be
|
| + /// unlocked and forced to their latest versions. If [upgradeAll] is
|
| + /// true, the previous lockfile is ignored and all packages are re-resolved
|
| + /// from scratch. Otherwise, it will attempt to preserve the versions of all
|
| + /// previously locked packages.
|
| + ///
|
| + /// Shows a report of the changes made relative to the previous lockfile. If
|
| + /// this is an upgrade or downgrade, all transitive dependencies are shown in
|
| + /// the report. Otherwise, only dependencies that were changed are shown. If
|
| + /// [dryRun] is `true`, no physical changes are made.
|
| Future acquireDependencies(SolveType type, {List<String> useLatest,
|
| bool dryRun: false}) {
|
| final completer0 = new Completer();
|
| @@ -74,12 +146,10 @@ class Entrypoint {
|
| })).catchError(((error, stackTrace) {
|
| log.exception(error, stackTrace);
|
| })));
|
| - } catch (e2) {
|
| - completer0.completeError(e2);
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e3) {
|
| - completer0.completeError(e3);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (_packageSymlinks) {
|
| _linkSelf();
|
| @@ -87,12 +157,10 @@ class Entrypoint {
|
| } else {
|
| join3();
|
| }
|
| - } catch (e1) {
|
| - completer0.completeError(e1);
|
| + } catch (e1, s1) {
|
| + completer0.completeError(e1, s1);
|
| }
|
| - }, onError: (e4) {
|
| - completer0.completeError(e4);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (_packageSymlinks) {
|
| cleanDir(packagesDir);
|
| @@ -110,22 +178,26 @@ class Entrypoint {
|
| }
|
| }
|
| if (!result.succeeded) {
|
| - completer0.completeError(result.error);
|
| + throw result.error;
|
| + join0();
|
| } else {
|
| join0();
|
| }
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + } catch (e2, s2) {
|
| + completer0.completeError(e2, s2);
|
| }
|
| - }, onError: (e5) {
|
| - completer0.completeError(e5);
|
| - });
|
| - } catch (e6) {
|
| - completer0.completeError(e6);
|
| + }, onError: completer0.completeError);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| }
|
| +
|
| + /// Precompile any transformed dependencies of the entrypoint.
|
| + ///
|
| + /// If [changed] is passed, only dependencies whose contents might be changed
|
| + /// if one of the given packages changes will be recompiled.
|
| Future precompileDependencies({Iterable<String> changed}) {
|
| final completer0 = new Completer();
|
| scheduleMicrotask(() {
|
| @@ -145,17 +217,20 @@ class Entrypoint {
|
| graph.transitiveDependencies(
|
| package.name).map((package) => package.name).toSet(),
|
| changed);
|
| - })).map(((package) => package.name)).toSet();
|
| + })).map(((package) {
|
| + return package.name;
|
| + })).toSet();
|
| join1() {
|
| log.progress("Precompiling dependencies", (() {
|
| final completer0 = new Completer();
|
| scheduleMicrotask(() {
|
| try {
|
| var packagesToLoad = unionAll(
|
| - dependenciesToPrecompile.map(
|
| - graph.transitiveDependencies)).map(((package) => package.name)).toSet();
|
| + dependenciesToPrecompile.map(graph.transitiveDependencies)).map(((package) {
|
| + return package.name;
|
| + })).toSet();
|
| var it0 = dependenciesToPrecompile.iterator;
|
| - break0(x4) {
|
| + break0() {
|
| AssetEnvironment.create(
|
| this,
|
| BarbackMode.DEBUG,
|
| @@ -163,7 +238,8 @@ class Entrypoint {
|
| useDart2JS: false).then((x0) {
|
| try {
|
| var environment = x0;
|
| - environment.barback.errors.listen(((_) {}));
|
| + environment.barback.errors.listen(((_) {
|
| + }));
|
| environment.barback.getAllAssets().then((x1) {
|
| try {
|
| var assets = x1;
|
| @@ -180,13 +256,11 @@ class Entrypoint {
|
| destPath).then((x0) {
|
| try {
|
| x0;
|
| - completer0.complete(null);
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + completer0.complete();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e1) {
|
| - completer0.completeError(e1);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (!dependenciesToPrecompile.contains(
|
| asset.id.package)) {
|
| @@ -194,8 +268,8 @@ class Entrypoint {
|
| } else {
|
| join0();
|
| }
|
| - } catch (e2) {
|
| - completer0.completeError(e2);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| @@ -206,70 +280,61 @@ class Entrypoint {
|
| "Precompiled " +
|
| toSentence(ordered(dependenciesToPrecompile).map(log.bold)) +
|
| ".");
|
| - completer0.complete(null);
|
| - } catch (e2) {
|
| - completer0.completeError(e2);
|
| + completer0.complete();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e3) {
|
| - completer0.completeError(e3);
|
| - });
|
| - } catch (e1) {
|
| - completer0.completeError(e1);
|
| + }, onError: completer0.completeError);
|
| + } catch (e1, s1) {
|
| + completer0.completeError(e1, s1);
|
| }
|
| - }, onError: (e4) {
|
| - completer0.completeError(e4);
|
| - });
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + }, onError: completer0.completeError);
|
| + } catch (e2, s2) {
|
| + completer0.completeError(e2, s2);
|
| }
|
| - }, onError: (e5) {
|
| - completer0.completeError(e5);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| - continue0(x5) {
|
| + var trampoline0;
|
| + continue0() {
|
| + trampoline0 = null;
|
| if (it0.moveNext()) {
|
| - Future.wait([]).then((x3) {
|
| - var package = it0.current;
|
| - deleteEntry(path.join(depsDir, package));
|
| - continue0(null);
|
| - });
|
| + var package = it0.current;
|
| + deleteEntry(path.join(depsDir, package));
|
| + trampoline0 = continue0;
|
| } else {
|
| - break0(null);
|
| + break0();
|
| }
|
| }
|
| - continue0(null);
|
| - } catch (e6) {
|
| - completer0.completeError(e6);
|
| + trampoline0 = continue0;
|
| + do trampoline0(); while (trampoline0 != null);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| })).catchError(((error) {
|
| - for (var package in dependenciesToPrecompile) {
|
| + for (package in dependenciesToPrecompile) {
|
| deleteEntry(path.join(depsDir, package));
|
| }
|
| throw error;
|
| })).then((x1) {
|
| try {
|
| x1;
|
| - completer0.complete(null);
|
| - } catch (e1) {
|
| - completer0.completeError(e1);
|
| + completer0.complete();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e2) {
|
| - completer0.completeError(e2);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (dependenciesToPrecompile.isEmpty) {
|
| completer0.complete(null);
|
| } else {
|
| join1();
|
| }
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + } catch (e1, s1) {
|
| + completer0.completeError(e1, s1);
|
| }
|
| - }, onError: (e3) {
|
| - completer0.completeError(e3);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (changed != null) {
|
| changed = changed.toSet();
|
| @@ -277,12 +342,15 @@ class Entrypoint {
|
| } else {
|
| join0();
|
| }
|
| - } catch (e4) {
|
| - completer0.completeError(e4);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| }
|
| +
|
| + /// Precompiles all executables from dependencies that don't transitively
|
| + /// depend on [this] or on a path dependency.
|
| Future precompileExecutables({Iterable<String> changed}) {
|
| final completer0 = new Completer();
|
| scheduleMicrotask(() {
|
| @@ -297,12 +365,14 @@ class Entrypoint {
|
| loadPackageGraph().then((x0) {
|
| try {
|
| var graph = x0;
|
| - var executables = new Map.fromIterable(
|
| - root.immediateDependencies,
|
| - key: ((dep) => dep.name),
|
| - value: ((dep) => _executablesForPackage(graph, dep.name, changed)));
|
| + var executables =
|
| + new Map.fromIterable(root.immediateDependencies, key: ((dep) {
|
| + return dep.name;
|
| + }), value: ((dep) {
|
| + return _executablesForPackage(graph, dep.name, changed);
|
| + }));
|
| var it0 = executables.keys.toList().iterator;
|
| - break0(x3) {
|
| + break0() {
|
| join2() {
|
| join3() {
|
| log.progress("Precompiling executables", (() {
|
| @@ -311,11 +381,14 @@ class Entrypoint {
|
| try {
|
| ensureDir(binDir);
|
| writeTextFile(sdkVersionPath, "${sdk.version}\n");
|
| - var packagesToLoad = unionAll(
|
| - executables.keys.map(
|
| - graph.transitiveDependencies)).map(((package) => package.name)).toSet();
|
| + var packagesToLoad =
|
| + unionAll(executables.keys.map(graph.transitiveDependencies)).map(((package) {
|
| + return package.name;
|
| + })).toSet();
|
| var executableIds =
|
| - unionAll(executables.values.map(((ids) => ids.toSet())));
|
| + unionAll(executables.values.map(((ids) {
|
| + return ids.toSet();
|
| + })));
|
| AssetEnvironment.create(
|
| this,
|
| BarbackMode.RELEASE,
|
| @@ -340,49 +413,41 @@ class Entrypoint {
|
| executableIds: executables[package]).then((x0) {
|
| try {
|
| x0;
|
| - completer0.complete(null);
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + completer0.complete();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e1) {
|
| - completer0.completeError(e1);
|
| - });
|
| - } catch (e2) {
|
| - completer0.completeError(e2);
|
| + }, onError: completer0.completeError);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| }))).then((x1) {
|
| try {
|
| x1;
|
| - completer0.complete(null);
|
| - } catch (e1) {
|
| - completer0.completeError(e1);
|
| + completer0.complete();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e2) {
|
| - completer0.completeError(e2);
|
| - });
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + }, onError: completer0.completeError);
|
| + } catch (e1, s1) {
|
| + completer0.completeError(e1, s1);
|
| }
|
| - }, onError: (e3) {
|
| - completer0.completeError(e3);
|
| - });
|
| - } catch (e4) {
|
| - completer0.completeError(e4);
|
| + }, onError: completer0.completeError);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| })).then((x1) {
|
| try {
|
| x1;
|
| - completer0.complete(null);
|
| - } catch (e1) {
|
| - completer0.completeError(e1);
|
| + completer0.complete();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| }
|
| - }, onError: (e2) {
|
| - completer0.completeError(e2);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (executables.isEmpty) {
|
| completer0.complete(null);
|
| @@ -397,31 +462,30 @@ class Entrypoint {
|
| join2();
|
| }
|
| }
|
| - continue0(x4) {
|
| + var trampoline0;
|
| + continue0() {
|
| + trampoline0 = null;
|
| if (it0.moveNext()) {
|
| - Future.wait([]).then((x2) {
|
| - var package = it0.current;
|
| - join4() {
|
| - continue0(null);
|
| - }
|
| - if (executables[package].isEmpty) {
|
| - executables.remove(package);
|
| - join4();
|
| - } else {
|
| - join4();
|
| - }
|
| - });
|
| + var package = it0.current;
|
| + join4() {
|
| + trampoline0 = continue0;
|
| + }
|
| + if (executables[package].isEmpty) {
|
| + executables.remove(package);
|
| + join4();
|
| + } else {
|
| + join4();
|
| + }
|
| } else {
|
| - break0(null);
|
| + break0();
|
| }
|
| }
|
| - continue0(null);
|
| - } catch (e0) {
|
| - completer0.completeError(e0);
|
| + trampoline0 = continue0;
|
| + do trampoline0(); while (trampoline0 != null);
|
| + } catch (e1, s1) {
|
| + completer0.completeError(e1, s1);
|
| }
|
| - }, onError: (e3) {
|
| - completer0.completeError(e3);
|
| - });
|
| + }, onError: completer0.completeError);
|
| }
|
| if (!sdkMatches) {
|
| changed = null;
|
| @@ -436,24 +500,40 @@ class Entrypoint {
|
| } else {
|
| join0();
|
| }
|
| - } catch (e4) {
|
| - completer0.completeError(e4);
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| }
|
| });
|
| return completer0.future;
|
| }
|
| +
|
| + /// 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,
|
| Set<String> changed) {
|
| var package = graph.packages[packageName];
|
| var binDir = package.path('bin');
|
| if (!dirExists(binDir)) return [];
|
| if (graph.isPackageMutable(packageName)) return [];
|
| +
|
| var executables = package.executableIds;
|
| +
|
| + // If we don't know which packages were changed, always precompile the
|
| + // executables.
|
| if (changed == null) return executables;
|
| +
|
| + // If any of the package's dependencies changed, recompile the executables.
|
| if (graph.transitiveDependencies(
|
| packageName).any((package) => changed.contains(package.name))) {
|
| return executables;
|
| }
|
| +
|
| + // If any executables doesn't exist, precompile them regardless of what
|
| + // changed. Since we delete the bin directory before recompiling, we need to
|
| + // recompile all executables.
|
| var executablesExist = executables.every(
|
| (executable) =>
|
| fileExists(
|
| @@ -463,46 +543,87 @@ class Entrypoint {
|
| packageName,
|
| "${path.url.basename(executable.path)}.snapshot")));
|
| if (!executablesExist) return executables;
|
| +
|
| + // Otherwise, we don't need to recompile.
|
| return [];
|
| }
|
| +
|
| + /// Makes sure the package at [id] is locally available.
|
| + ///
|
| + /// This automatically downloads the package to the system-wide cache as well
|
| + /// if it requires network access to retrieve (specifically, if the package's
|
| + /// source is a [CachedSource]).
|
| Future<PackageId> _get(PackageId id) {
|
| if (id.isRoot) return new Future.value(id);
|
| +
|
| var source = cache.sources[id.source];
|
| return new Future.sync(() {
|
| if (!_packageSymlinks) {
|
| if (source is! CachedSource) return null;
|
| return source.downloadToSystemCache(id);
|
| }
|
| +
|
| var packageDir = path.join(packagesDir, id.name);
|
| if (entryExists(packageDir)) deleteEntry(packageDir);
|
| return source.get(id, packageDir);
|
| }).then((_) => source.resolveId(id));
|
| }
|
| +
|
| + /// Determines whether or not the lockfile is out of date with respect to the
|
| + /// pubspec.
|
| + ///
|
| + /// This will be `false` if there is no lockfile at all, or if the pubspec
|
| + /// contains dependencies that are not in the lockfile or that don't match
|
| + /// what's in there.
|
| bool _isLockFileUpToDate(LockFile lockFile) {
|
| return root.immediateDependencies.every((package) {
|
| var locked = lockFile.packages[package.name];
|
| if (locked == null) return false;
|
| +
|
| if (package.source != locked.source) return false;
|
| if (!package.constraint.allows(locked.version)) return false;
|
| +
|
| var source = cache.sources[package.source];
|
| if (source == null) return false;
|
| +
|
| return source.descriptionsEqual(package.description, locked.description);
|
| });
|
| }
|
| +
|
| + /// Determines whether all of the packages in the lockfile are already
|
| + /// installed and available.
|
| + ///
|
| + /// Note: this assumes [isLockFileUpToDate] has already been called and
|
| + /// returned `true`.
|
| Future<bool> _arePackagesAvailable(LockFile lockFile) {
|
| return Future.wait(lockFile.packages.values.map((package) {
|
| var source = cache.sources[package.source];
|
| +
|
| + // This should only be called after [_isLockFileUpToDate] has returned
|
| + // `true`, which ensures all of the sources in the lock file are valid.
|
| assert(source != null);
|
| +
|
| + // We only care about cached sources. Uncached sources aren't "installed".
|
| + // If one of those is missing, we want to show the user the file not
|
| + // found error later since installing won't accomplish anything.
|
| if (source is! CachedSource) return new Future.value(true);
|
| +
|
| + // Get the directory.
|
| return source.getDirectory(package).then((dir) {
|
| + // See if the directory is there and looks like a package.
|
| return dirExists(dir) || fileExists(path.join(dir, "pubspec.yaml"));
|
| });
|
| })).then((results) {
|
| + // Make sure they are all true.
|
| return results.every((result) => result);
|
| });
|
| }
|
| +
|
| + /// Gets dependencies if the lockfile is out of date with respect to the
|
| + /// pubspec.
|
| Future ensureLockFileIsUpToDate() {
|
| return new Future.sync(() {
|
| + // If we don't have a current lock file, we definitely need to install.
|
| if (!_isLockFileUpToDate(lockFile)) {
|
| if (lockFileExists) {
|
| log.message(
|
| @@ -511,13 +632,19 @@ class Entrypoint {
|
| log.message(
|
| "You don't have a lockfile, so we need to generate that:");
|
| }
|
| +
|
| return false;
|
| }
|
| +
|
| + // If we do have a lock file, we still need to make sure the packages
|
| + // are actually installed. The user may have just gotten a package that
|
| + // includes a lockfile.
|
| return _arePackagesAvailable(lockFile).then((available) {
|
| if (!available) {
|
| log.message(
|
| "You are missing some dependencies, so we need to install them " "first:");
|
| }
|
| +
|
| return available;
|
| });
|
| }).then((upToDate) {
|
| @@ -525,8 +652,16 @@ class Entrypoint {
|
| return acquireDependencies(SolveType.GET);
|
| });
|
| }
|
| +
|
| + /// Loads the package graph for the application and all of its transitive
|
| + /// dependencies.
|
| + ///
|
| + /// If [result] is passed, this loads the graph from it without re-parsing the
|
| + /// lockfile or any pubspecs. Otherwise, before loading, this makes sure the
|
| + /// lockfile and dependencies are installed and up to date.
|
| Future<PackageGraph> loadPackageGraph([SolveResult result]) {
|
| if (_packageGraph != null) return new Future.value(_packageGraph);
|
| +
|
| return new Future.sync(() {
|
| if (result != null) {
|
| return Future.wait(result.packages.map((id) {
|
| @@ -556,13 +691,19 @@ class Entrypoint {
|
| return graph;
|
| });
|
| }
|
| +
|
| + /// Saves a list of concrete package versions to the `pubspec.lock` file.
|
| void _saveLockFile(List<PackageId> packageIds) {
|
| _lockFile = new LockFile(packageIds);
|
| var lockFilePath = root.path('pubspec.lock');
|
| writeTextFile(lockFilePath, _lockFile.serialize(root.dir, cache.sources));
|
| }
|
| +
|
| + /// Creates a self-referential symlink in the `packages` directory that allows
|
| + /// a package to import its own files using `package:`.
|
| void _linkSelf() {
|
| var linkPath = path.join(packagesDir, root.name);
|
| + // Create the symlink if it doesn't exist.
|
| if (entryExists(linkPath)) return;
|
| ensureDir(packagesDir);
|
| createPackageSymlink(
|
| @@ -572,19 +713,39 @@ class Entrypoint {
|
| isSelfLink: true,
|
| relative: true);
|
| }
|
| +
|
| + /// If [packageSymlinks] is true, add "packages" directories to the whitelist
|
| + /// of directories that may contain Dart entrypoints.
|
| + ///
|
| + /// Otherwise, delete any "packages" directories in the whitelist of
|
| + /// directories that may contain Dart entrypoints.
|
| void _linkOrDeleteSecondaryPackageDirs() {
|
| + // Only the main "bin" directory gets a "packages" directory, not its
|
| + // subdirectories.
|
| var binDir = root.path('bin');
|
| if (dirExists(binDir)) _linkOrDeleteSecondaryPackageDir(binDir);
|
| +
|
| + // The others get "packages" directories in subdirectories too.
|
| for (var dir in ['benchmark', 'example', 'test', 'tool', 'web']) {
|
| _linkOrDeleteSecondaryPackageDirsRecursively(root.path(dir));
|
| }
|
| }
|
| +
|
| + /// If [packageSymlinks] is true, creates a symlink to the "packages"
|
| + /// directory in [dir] and all its subdirectories.
|
| + ///
|
| + /// Otherwise, deletes any "packages" directories in [dir] and all its
|
| + /// subdirectories.
|
| void _linkOrDeleteSecondaryPackageDirsRecursively(String dir) {
|
| if (!dirExists(dir)) return;
|
| _linkOrDeleteSecondaryPackageDir(dir);
|
| _listDirWithoutPackages(
|
| dir).where(dirExists).forEach(_linkOrDeleteSecondaryPackageDir);
|
| }
|
| +
|
| + // TODO(nweiz): roll this into [listDir] in io.dart once issue 4775 is fixed.
|
| + /// Recursively lists the contents of [dir], excluding hidden `.DS_Store`
|
| + /// files and `package` files.
|
| List<String> _listDirWithoutPackages(dir) {
|
| return flatten(listDir(dir).map((file) {
|
| if (path.basename(file) == 'packages') return [];
|
| @@ -594,6 +755,11 @@ class Entrypoint {
|
| return fileAndSubfiles;
|
| }));
|
| }
|
| +
|
| + /// If [packageSymlinks] is true, creates a symlink to the "packages"
|
| + /// directory in [dir].
|
| + ///
|
| + /// Otherwise, deletes a "packages" directories in [dir] if one exists.
|
| void _linkOrDeleteSecondaryPackageDir(String dir) {
|
| var symlink = path.join(dir, 'packages');
|
| if (entryExists(symlink)) deleteEntry(symlink);
|
|
|