Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit 0a99384

Browse files
Pete Bloismhevery
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 #889
1 parent 0784388 commit 0a99384

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)