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 b580f49444f0e46c55768e54f5e170244d8e482b..ae1c1cd9c07bee582d9b7fe1ad635e1d789b0936 100644 |
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart |
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart |
@@ -142,10 +142,8 @@ class Entrypoint { |
// 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) { |
+ return precompileExecutables(changed: result.changedPackages) |
+ .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); |
@@ -156,18 +154,28 @@ class Entrypoint { |
/// Precompiles all executables from dependencies that don't transitively |
/// depend on [this] or on a path dependency. |
- Future precompileExecutables() { |
+ Future precompileExecutables({Iterable<String> changed}) { |
+ if (changed != null) changed = changed.toSet(); |
+ |
+ var binDir = path.join('.pub', 'bin'); |
+ var sdkVersionPath = path.join(binDir, 'sdk-version'); |
+ |
+ // If the existing executable was compiled with a different SDK, we need to |
+ // recompile regardless of what changed. |
+ var sdkMatches = fileExists(sdkVersionPath) && |
+ readTextFile(sdkVersionPath) == "${sdk.version}\n"; |
+ if (!sdkMatches) changed = null; |
+ |
return loadPackageGraph().then((graph) { |
var executables = new Map.fromIterable(root.immediateDependencies, |
key: (dep) => dep.name, |
- value: (dep) => _executablesForPackage(graph, dep.name)); |
+ value: (dep) => _executablesForPackage(graph, dep.name, changed)); |
for (var package in executables.keys.toList()) { |
if (executables[package].isEmpty) executables.remove(package); |
} |
- var binDir = path.join('.pub', 'bin'); |
- deleteEntry(binDir); |
+ if (!sdkMatches) deleteEntry(binDir); |
if (executables.isEmpty) return null; |
return log.progress("Precompiling executables", () { |
@@ -177,7 +185,7 @@ class Entrypoint { |
// Make sure there's a trailing newline so our version file matches the |
// SDK's. |
- writeTextFile(path.join(binDir, 'sdk-version'), "${sdk.version}\n"); |
+ writeTextFile(sdkVersionPath, "${sdk.version}\n"); |
return AssetEnvironment.create(this, BarbackMode.RELEASE, |
WatcherType.NONE, useDart2JS: false).then((environment) { |
environment.barback.errors.listen((error) { |
@@ -198,7 +206,8 @@ class Entrypoint { |
/// |
/// 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) { |
+ List<AssetId> _executablesForPackage(PackageGraph graph, String packageName, |
+ Set<String> changed) { |
var package = graph.packages[packageName]; |
var binDir = path.join(package.dir, 'bin'); |
if (!dirExists(binDir)) return []; |
@@ -206,15 +215,15 @@ class Entrypoint { |
// 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]; |
+ var deps = graph.transitiveDependencies(packageName); |
+ var hasUncachedDependency = deps.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)) |
+ var executables = |
+ ordered(package.listFiles(beneath: binDir, recursive: false)) |
.where((executable) => path.extension(executable) == '.dart') |
.map((executable) { |
return new AssetId( |
@@ -222,16 +231,36 @@ class Entrypoint { |
path.toUri(path.relative(executable, from: package.dir)) |
.toString()); |
}).toList(); |
+ |
+ // 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 (deps.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(path.join('.pub', 'bin', packageName, |
+ "${path.url.basename(executable.path)}.snapshot"))); |
+ if (!executablesExist) return executables; |
+ |
+ // Otherwise, we don't need to recompile. |
+ return []; |
} |
- /// Precompiles all [executables] for [package]. |
- /// |
- /// [executables] is assumed to be a list of Dart executables in [package]'s |
+ /// 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); |
+ cleanDir(cacheDir); |
// TODO(nweiz): Unserve this directory when we're done with it. |
return environment.servePackageBinDirectory(package).then((server) { |