Chromium Code Reviews| Index: lib/src/entrypoint.dart |
| diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart |
| index 507b12cc3956b41636f2306a081717a03fc8d613..fad67e63d7b71906414ddba6b8e5427aedb70809 100644 |
| --- a/lib/src/entrypoint.dart |
| +++ b/lib/src/entrypoint.dart |
| @@ -7,9 +7,10 @@ library pub.entrypoint; |
| import 'dart:async'; |
| import 'dart:io'; |
| +import 'package:barback/barback.dart'; |
| import 'package:package_config/packages_file.dart' as packages_file; |
| import 'package:path/path.dart' as p; |
| -import 'package:barback/barback.dart'; |
| +import 'package:pub_semver/pub_semver.dart'; |
| import 'barback/asset_environment.dart'; |
| import 'io.dart'; |
| @@ -20,9 +21,13 @@ import 'package_graph.dart'; |
| import 'sdk.dart' as sdk; |
| import 'solver/version_solver.dart'; |
| import 'source/cached.dart'; |
| +import 'source/unknown.dart'; |
| import 'system_cache.dart'; |
| import 'utils.dart'; |
| +/// A RegExp to match the SDK constraint in a lock file. |
| +final _sdkConstraint = new RegExp(r'^sdk: "?([^"]*)"?$', multiLine: true); |
| + |
| /// The context surrounding the root package pub is operating on. |
| /// |
| /// Pub operates over a directed graph of dependencies that starts at a root |
| @@ -86,10 +91,7 @@ class Entrypoint { |
| assertUpToDate(); |
| var packages = new Map.fromIterable(lockFile.packages.values, |
| key: (id) => id.name, |
| - value: (id) { |
| - var dir = cache.sources[id.source].getDirectory(id); |
| - return new Package.load(id.name, dir, cache.sources); |
| - }); |
| + value: (id) => cache.sources.load(id)); |
| packages[root.name] = root; |
| _packageGraph = new PackageGraph(this, lockFile, packages); |
| @@ -174,7 +176,7 @@ class Entrypoint { |
| } |
| await Future.wait(result.packages.map(_get)); |
| - _saveLockFile(result.packages); |
| + _saveLockFile(result); |
| if (_packageSymlinks) _linkSelf(); |
| _linkOrDeleteSecondaryPackageDirs(); |
| @@ -420,11 +422,17 @@ class Entrypoint { |
| dataError('No .packages file found, please run "pub get" first.'); |
| } |
| + // Manually parse the lockfile because a full YAML parse is relatively slow |
| + // and this is on the hot path for "pub run". |
| + var lockFileText = readTextFile(lockFilePath); |
| + var hasPathDependencies = lockFileText.contains("\n source: path\n"); |
|
Bob Nystrom
2015/12/21 20:55:03
This feels really sketchy to me. We don't for cert
nweiz
2016/01/04 23:27:29
Discussed offline.
|
| + |
| var pubspecModified = new File(pubspecPath).lastModifiedSync(); |
| var lockFileModified = new File(lockFilePath).lastModifiedSync(); |
| var touchedLockFile = false; |
| - if (lockFileModified.isBefore(pubspecModified)) { |
| + if (lockFileModified.isBefore(pubspecModified) || |
| + hasPathDependencies) { |
| if (_isLockFileUpToDate() && _arePackagesAvailable()) { |
| touchedLockFile = true; |
| touch(lockFilePath); |
| @@ -445,41 +453,60 @@ class Entrypoint { |
| } else if (touchedLockFile) { |
| touch(packagesFile); |
| } |
| + |
| + var sdkConstraint = _sdkConstraint.firstMatch(lockFileText); |
| + if (sdkConstraint != null) { |
| + var parsedConstraint = new VersionConstraint.parse(sdkConstraint[1]); |
| + if (!parsedConstraint.allows(sdk.version)) { |
| + dataError("Dart ${sdk.version} is incompatible with your dependencies' " |
| + "SDK constraints. Please run \"pub get\" again."); |
| + } |
| + } |
| } |
| /// Determines whether or not the lockfile is out of date with respect to the |
| /// pubspec. |
| /// |
| - /// This will be `false` if the pubspec contains dependencies that are not in |
| - /// the lockfile or that don't match what's in there. |
| + /// This will be `false` if any mutable pubspec contains dependencies that are |
| + /// not in the lockfile or that don't match what's in there. |
| bool _isLockFileUpToDate() { |
| - return root.immediateDependencies.every((package) { |
| - var locked = lockFile.packages[package.name]; |
| - if (locked == null) return false; |
| + if (!root.immediateDependencies.every(_isDependencyUpToDate)) return false; |
| - if (package.source != locked.source) return false; |
| + var overrides = root.dependencyOverrides.map((dep) => dep.name).toSet(); |
| - if (!package.constraint.allows(locked.version)) return false; |
| + // Check that path dependencies' pubspecs are also still satisfied, since |
| + // they're mutable and may have changed since the last get. |
| + return lockFile.packages.values.every((id) { |
| + if (id.source != 'path') return true; |
|
Bob Nystrom
2015/12/21 20:55:03
Instead of checking for path specifically, how abo
nweiz
2016/01/04 23:27:29
Done.
|
| - var source = cache.sources[package.source]; |
| - if (source == null) return false; |
| - |
| - return source.descriptionsEqual(package.description, locked.description); |
| + return cache.sources.load(id).dependencies.every((dep) { |
| + if (overrides.contains(dep.name)) return true; |
| + return _isDependencyUpToDate(dep); |
| + }); |
|
Bob Nystrom
2015/12/21 20:55:03
return cache.sources.load(id).dependencies.every(
nweiz
2016/01/04 23:27:29
Done.
|
| }); |
| } |
| + /// Returns whether the locked version of [dep] matches the dependency. |
| + bool _isDependencyUpToDate(PackageDep dep) { |
| + var locked = lockFile.packages[dep.name]; |
| + if (locked == null) return false; |
| + |
| + if (dep.source != locked.source) return false; |
| + |
| + if (!dep.constraint.allows(locked.version)) return false; |
| + |
| + var source = cache.sources[dep.source]; |
| + if (source == null) return false; |
| + |
| + return source.descriptionsEqual(dep.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`. |
| bool _arePackagesAvailable() { |
| return lockFile.packages.values.every((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); |
| + if (source is UnknownSource) return false; |
| // 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 |
| @@ -542,8 +569,8 @@ class Entrypoint { |
| } |
| /// Saves a list of concrete package versions to the `pubspec.lock` file. |
| - void _saveLockFile(List<PackageId> packageIds) { |
| - _lockFile = new LockFile(packageIds, cache.sources); |
| + void _saveLockFile(SolveResult result) { |
| + _lockFile = result.lockFile; |
| var lockFilePath = root.path('pubspec.lock'); |
| writeTextFile(lockFilePath, _lockFile.serialize(root.dir)); |
| } |