Index: lib/src/graph/transform_node.dart |
diff --git a/lib/src/graph/transform_node.dart b/lib/src/graph/transform_node.dart |
index 61bab3f258943d925ef0be951fec42fe2f1156e5..2a24335b612077348302493624974e477670bdfb 100644 |
--- a/lib/src/graph/transform_node.dart |
+++ b/lib/src/graph/transform_node.dart |
@@ -23,6 +23,10 @@ import 'node_streams.dart'; |
import 'phase.dart'; |
import 'transformer_classifier.dart'; |
+/// Every `_applyLogDuration`, we will issue a fine log entry letting the user |
+/// know that the transform is still executing. |
+const _applyLogDuration = const Duration(seconds: 10); |
+ |
/// Describes a transform on a set of assets and its relationship to the build |
/// dependency graph. |
/// |
@@ -171,9 +175,11 @@ class TransformNode { |
/// [_State.NEEDS_DECLARE], and always `null` otherwise. |
AggregateTransformController _applyController; |
- /// The number of secondary inputs that have been requested but not yet |
- /// produced. |
- int _pendingSecondaryInputs = 0; |
+ /// Map to track pending requests for secondary inputs. |
+ /// |
+ /// Keys are the secondary inputs that have been requested but not yet |
+ /// produced. Values are the number of requests for that input. |
+ final _pendingSecondaryInputs = <AssetId, int>{}; |
/// A stopwatch that tracks the total time spent in a transformer's `apply` |
/// function. |
@@ -577,7 +583,9 @@ class TransformNode { |
/// If an input with [id] cannot be found, throws an [AssetNotFoundException]. |
Future<Asset> getInput(AssetId id) { |
_timeAwaitingInputs.start(); |
- _pendingSecondaryInputs++; |
+ _pendingSecondaryInputs[id] = _pendingSecondaryInputs.containsKey(id) |
+ ? _pendingSecondaryInputs[id] + 1 |
+ : 1; |
return phase.previous.getOutput(id).then((node) { |
// Throw if the input isn't found. This ensures the transformer's apply |
// is exited. We'll then catch this and report it through the proper |
@@ -610,8 +618,13 @@ class TransformNode { |
return node.asset; |
}).whenComplete(() { |
- _pendingSecondaryInputs--; |
- if (_pendingSecondaryInputs != 0) _timeAwaitingInputs.stop(); |
+ assert(_pendingSecondaryInputs.containsKey(id)); |
+ if (_pendingSecondaryInputs[id] == 1) { |
+ _pendingSecondaryInputs.remove(id); |
+ } else { |
+ _pendingSecondaryInputs[id]--; |
+ } |
+ if (_pendingSecondaryInputs.isEmpty) _timeAwaitingInputs.stop(); |
}); |
} |
@@ -628,12 +641,36 @@ class TransformNode { |
} |
_maybeFinishApplyController(); |
+ var transformCounterTimer; |
+ |
return syncFuture(() { |
_timeInTransformer.reset(); |
_timeAwaitingInputs.reset(); |
_timeInTransformer.start(); |
+ |
+ transformCounterTimer = new Timer.periodic(_applyLogDuration, (_) { |
+ if (_streams.onLogController.isClosed || |
+ !_timeInTransformer.isRunning) { |
+ return; |
+ } |
+ |
+ var message = new StringBuffer("Not yet complete after " |
+ "${niceDuration(_timeInTransformer.elapsed)}"); |
+ if (_pendingSecondaryInputs.isNotEmpty) { |
+ message.write(", waiting on input(s) " |
+ "${_pendingSecondaryInputs.keys.join(", ")}"); |
+ } |
+ _streams.onLogController.add(new LogEntry( |
+ info, |
+ info.primaryId, |
+ LogLevel.FINE, |
+ message.toString(), |
+ null)); |
+ }); |
+ |
return transformer.apply(controller.transform); |
}).whenComplete(() { |
+ transformCounterTimer.cancel(); |
_timeInTransformer.stop(); |
_timeAwaitingInputs.stop(); |