Skip to content

Commit 8b06e67

Browse files
Pete Bloistravis@travis-ci.org
Pete Blois
authored andcommitted
fix(transformer): Serializing execution of transformers
When executing under pub serve the order of apply for the transformers may not be the same as the phase ordering. This was causing deadlocks for the transformers sharing a resolver as the read of an asset for one transformer was invoking the apply for a different transformer, which would then deadlock waiting for the resolver. Closes dart-archive#889
1 parent e35a5e1 commit 8b06e67

File tree

1 file changed

+33
-4
lines changed

1 file changed

+33
-4
lines changed

lib/transformer.dart

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
library angular.transformer;
22

3+
import 'dart:async';
34
import 'dart:io';
45
import 'package:angular/tools/transformer/expression_generator.dart';
56
import 'package:angular/tools/transformer/metadata_generator.dart';
@@ -123,9 +124,37 @@ List<List<Transformer>> _createPhases(TransformOptions options) {
123124
var resolvers = new Resolvers(options.sdkDirectory);
124125
return [
125126
[new HtmlDartReferencesGenerator(options)],
126-
[new ExpressionGenerator(options, resolvers)],
127-
[new di.InjectorGenerator(options.diOptions, resolvers)],
128-
[new MetadataGenerator(options, resolvers)],
129-
[new StaticAngularGenerator(options, resolvers)],
127+
[new _SerialTransformer([
128+
new ExpressionGenerator(options, resolvers),
129+
new di.InjectorGenerator(options.diOptions, resolvers),
130+
new MetadataGenerator(options, resolvers),
131+
new StaticAngularGenerator(options, resolvers)
132+
])]
130133
];
131134
}
135+
136+
/// Helper which runs a group of transformers serially and ensures that
137+
/// transformers with shared data are always applied in a specific order.
138+
///
139+
/// Transformers which communicate only via assets do not need this additional
140+
/// synchronization.
141+
///
142+
/// This is used by Angular to ensure ordering of references to the cached
143+
/// resolvers.
144+
class _SerialTransformer extends Transformer {
145+
final Iterable<Transformer> _transformers;
146+
_SerialTransformer(this._transformers);
147+
148+
Future<bool> isPrimary(Asset input) =>
149+
Future.wait(_transformers.map((t) => t.isPrimary(input)))
150+
.then((l) => l.any((result) => result));
151+
152+
Future apply(Transform transform) {
153+
return Future.forEach(_transformers, (t) {
154+
return new Future.value(t.isPrimary(transform.primaryInput))
155+
.then((isPrimary) {
156+
if (isPrimary) return t.apply(transform);
157+
});
158+
});
159+
}
160+
}

0 commit comments

Comments
 (0)