Chromium Code Reviews| Index: sdk/lib/_internal/pub/lib/src/barback/transformer_cache.dart |
| diff --git a/sdk/lib/_internal/pub/lib/src/barback/transformer_cache.dart b/sdk/lib/_internal/pub/lib/src/barback/transformer_cache.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..37e2577d36f900efb05571e9fd5aa5882c01ed6d |
| --- /dev/null |
| +++ b/sdk/lib/_internal/pub/lib/src/barback/transformer_cache.dart |
| @@ -0,0 +1,152 @@ |
| +// Copyright (c) 2014, 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.barback.transformer_cache; |
| + |
| +import 'package:path/path.dart' as p; |
| + |
| +import '../io.dart'; |
| +import '../log.dart' as log; |
| +import '../package_graph.dart'; |
| +import '../sdk.dart' as sdk; |
| +import '../source/cached.dart'; |
| +import '../utils.dart'; |
| +import 'asset_environment.dart'; |
| +import 'transformer_id.dart'; |
| + |
| +/// A cache for managing a snapshot of the first "phase" of transformers to |
| +/// load. |
| +/// |
| +/// This uses the [_phaseTransformers] notion of a phase. Transformers are |
|
Bob Nystrom
2014/09/12 21:17:17
Maybe we need a different term here. "stage"?
nweiz
2014/09/16 00:10:53
Done.
|
| +/// divided into phases for loading based on which transformers are needed to |
| +/// load one another. For example, if a transformer T1 produces a file that's |
| +/// imported by another transformer T2, T2 must be put in a phase after T1. |
| +/// |
| +/// We only cache the first phase because it's the only phase whose contents are |
| +/// independent of any configuration. |
|
Bob Nystrom
2014/09/12 21:17:17
I'd add that since it's pretty rare for transforme
nweiz
2014/09/16 00:10:53
Done.
|
| +class TransformerCache { |
| + final PackageGraph _graph; |
| + |
| + /// The set of transformer ids that were previously cached. |
| + /// |
| + /// If there was no previous cache, this will be empty. |
| + Set<TransformerId> _oldTransformers; |
| + |
| + /// The set of transformer ids that are newly cached or re-used from the |
| + /// previous cache. |
| + Set<TransformerId> _newTransformers; |
| + |
| + /// The directory in which transformers are cached. |
| + /// |
| + /// This may be `null` if there's no physical entrypoint directory. |
| + String _dir; |
| + |
| + /// The directory of the manifest listing which transformers were cached. |
| + String get _manifestPath => p.join(_dir, "manifest.txt"); |
| + |
| + /// Loads the transformer cache for [environment]. |
| + /// |
| + /// This may modify the cache. |
| + TransformerCache.load(PackageGraph graph) |
| + : _graph = graph, |
| + _dir = p.join(graph.entrypoint.root.dir, ".pub/transformers") { |
| + _oldTransformers = _parseManifest(); |
| + } |
| + |
| + /// Clear the cache if it depends on any package in [changedPackages]. |
| + void clearIfOutdated(Set<String> changedPackages) { |
| + var snapshotDependencies = unionAll(_oldTransformers.map((id) { |
| + return _graph.transitiveDependencies(id.package) |
| + .map((package) => package.name).toSet(); |
| + })); |
| + |
| + // If none of the snapshot's dependencies have changed, then we can reuse |
| + // it. |
| + if (!changedPackages.any(snapshotDependencies.contains)) return; |
| + |
| + // Otherwise, delete it. |
| + deleteEntry(_dir); |
| + _oldTransformers = new Set(); |
| + } |
| + |
| + /// Returns the path for the transformer snapshot for [transformers], or |
| + /// `null` if the transformers shouldn't be cached. |
| + /// |
| + /// There may or may not exist a file at the returned path. If one does exist, |
| + /// it can safely be used to load the phase. Otherwise, a snapshot of the |
| + /// phase should be written there. |
| + String snapshotPath(Set<TransformerId> transformers) { |
| + // A transformer is considered mutable if it comes from the entrypoint |
| + // package or a path dependency. |
| + // |
| + // TODO(nweiz): Consider git packages with mutable (transitive) dependencies |
| + // to be mutable themselves. |
| + var usesMutableTransformer = transformers.any((id) { |
| + // The entrypoint package doesn't appear in the lockfile. |
| + var package = _graph.lockFile.packages[id.package]; |
| + if (package == null) return true; |
| + var source = _graph.entrypoint.cache.sources[package.source]; |
| + return source is! CachedSource; |
| + }); |
| + |
| + var path = p.join(_dir, "transformers.snapshot"); |
| + if (usesMutableTransformer) { |
| + log.fine("Not caching mutable transformers."); |
| + deleteEntry(_dir); |
| + return null; |
| + } |
| + |
| + if (!_oldTransformers.containsAll(transformers)) { |
| + log.fine("Cached transformer snapshot is out-of-date, deleting."); |
| + deleteEntry(path); |
| + } else { |
| + log.fine("Using cached transformer snapshot."); |
| + } |
| + |
| + _newTransformers = transformers; |
| + return path; |
| + } |
| + |
| + /// Saves the manifest to the transformer cache. |
| + void save() { |
| + // If we didn't write any snapshots, there's no need to write a manifest. |
| + if (_newTransformers == null) { |
| + if (_dir != null) deleteEntry(_dir); |
| + return; |
| + } |
| + |
| + // We only need to rewrite the manifest if we created a new snapshot. |
| + if (_oldTransformers.containsAll(_newTransformers)) return; |
| + |
| + ensureDir(_dir); |
| + writeTextFile(_manifestPath, |
| + "${sdk.version}\n" + |
| + ordered(_newTransformers.map((id) => id.serialize())).join(",")); |
| + } |
| + |
| + /// Parses the cache manifest and returns the set of previously-cached |
| + /// transformers. |
| + /// |
| + /// If the manifest indicates that the SDK version is out-of-date, this |
| + /// deletes the existing cache. Otherwise, |
| + Set<TransformerId> _parseManifest() { |
| + if (!fileExists(_manifestPath)) return new Set(); |
| + |
| + var manifest = readTextFile(_manifestPath).split("\n"); |
| + |
| + // The first line of the manifest is the SDK version. We want to clear out |
| + // the snapshots even if they're VM-compatible, since pub's transformer |
| + // isolate scaffolding may have changed. |
| + if (manifest.removeAt(0) != sdk.version.toString()) { |
| + deleteEntry(_dir); |
| + return new Set(); |
| + } |
| + |
| + /// The second line of the manifest is a list of transformer ids used to |
| + /// create the existing snapshot. |
| + return manifest.single.split(",") |
| + .map((id) => new TransformerId.parse(id, null)) |
| + .toSet(); |
| + } |
| +} |