Skip to content

Commit 1209b8a

Browse files
committed
Lazily compute outputs.
1 parent 04dcd63 commit 1209b8a

File tree

12 files changed

+128
-236
lines changed

12 files changed

+128
-236
lines changed

build_runner/bin/graph_inspector.dart

+7-2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class InspectNodeCommand extends Command<bool> {
118118

119119
@override
120120
bool run() {
121+
var computedOutputs = assetGraph.computeOutputs();
121122
var argResults = this.argResults!;
122123
var stringUris = argResults.rest;
123124
if (stringUris.isEmpty) {
@@ -157,12 +158,16 @@ class InspectNodeCommand extends Command<bool> {
157158
node.primaryOutputs.forEach(printAsset);
158159

159160
description.writeln(' secondary outputs:');
160-
node.outputs.difference(node.primaryOutputs).forEach(printAsset);
161+
(computedOutputs[node.id] ?? const <AssetId>{})
162+
.difference(node.primaryOutputs.asSet())
163+
.forEach(printAsset);
161164

162165
if (node.type == NodeType.generated || node.type == NodeType.glob) {
163166
description.writeln(' inputs:');
164167
assetGraph.allNodes
165-
.where((n) => n.outputs.contains(node.id))
168+
.where(
169+
(n) => (computedOutputs[n.id] ?? <AssetId>{}).contains(node.id),
170+
)
166171
.map((n) => n.id)
167172
.forEach(printAsset);
168173
}

build_runner/lib/src/server/asset_graph_handler.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ class AssetGraphHandler {
115115
{'id': '${node.id}', 'label': '${node.id}'},
116116
];
117117
var edges = <Map<String, String>>[];
118-
for (final output in node.outputs) {
118+
var computedOutputs = _assetGraph.computeOutputs();
119+
for (final output in (computedOutputs[node.id] ?? <AssetId>{})) {
119120
if (filterGlob != null && !filterGlob.matches(output.toString())) {
120121
continue;
121122
}

build_runner/test/generate/watch_test.dart

-6
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,6 @@ void main() {
382382
inputs: [makeAssetId('a|web/b.txt')],
383383
isHidden: false,
384384
);
385-
builderOptionsNode = builderOptionsNode.rebuild(
386-
(b) => b..outputs.add(bCopyNode.id),
387-
);
388385
expectedGraph
389386
..add(bCopyNode)
390387
..add(
@@ -407,9 +404,6 @@ void main() {
407404
inputs: [makeAssetId('a|web/c.txt')],
408405
isHidden: false,
409406
);
410-
builderOptionsNode = builderOptionsNode.rebuild(
411-
(b) => b..outputs.add(cCopyNode.id),
412-
);
413407
expectedGraph
414408
..add(cCopyNode)
415409
..add(

build_runner_core/lib/src/asset_graph/graph.dart

+50-39
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class AssetGraph implements GeneratedAssetHider {
4848

4949
final BuiltMap<String, LanguageVersion?> packageLanguageVersions;
5050

51+
Map<AssetId, Set<AssetId>>? _outputs;
52+
5153
/// All post process build steps outputs, indexed by package then
5254
/// [PostProcessBuildStepId].
5355
///
@@ -128,6 +130,15 @@ class AssetGraph implements GeneratedAssetHider {
128130
if (node == null) throw StateError('Missing node: $id');
129131
final updatedNode = node.rebuild(updates);
130132
_nodesByPackage[id.package]![id.path] = updatedNode;
133+
134+
if (updatedNode.type == NodeType.generated) {
135+
if (node.type != NodeType.generated ||
136+
updatedNode.generatedNodeState!.inputs !=
137+
node.generatedNodeState!.inputs) {
138+
_outputs = null;
139+
}
140+
}
141+
131142
return updatedNode;
132143
}
133144

@@ -144,6 +155,16 @@ class AssetGraph implements GeneratedAssetHider {
144155
if (node == null) return null;
145156
final updatedNode = node.rebuild(updates);
146157
_nodesByPackage[id.package]![id.path] = updatedNode;
158+
159+
// TODO(davidmorgan): dedupe.
160+
if (updatedNode.type == NodeType.generated) {
161+
if (node.type != NodeType.generated ||
162+
updatedNode.generatedNodeState!.inputs !=
163+
node.generatedNodeState!.inputs) {
164+
_outputs = null;
165+
}
166+
}
167+
147168
return updatedNode;
148169
}
149170

@@ -161,7 +182,6 @@ class AssetGraph implements GeneratedAssetHider {
161182
// primary outputs. We only want to remove this node.
162183
_nodesByPackage[existing.id.package]!.remove(existing.id.path);
163184
node = node.rebuild((b) {
164-
b.outputs.addAll(existing.outputs);
165185
b.primaryOutputs.addAll(existing.primaryOutputs);
166186
});
167187
} else {
@@ -173,6 +193,10 @@ class AssetGraph implements GeneratedAssetHider {
173193
}
174194
_nodesByPackage.putIfAbsent(node.id.package, () => {})[node.id.path] = node;
175195

196+
if (node.type == NodeType.generated || node.type == NodeType.glob) {
197+
_outputs = null;
198+
}
199+
176200
return node;
177201
}
178202

@@ -269,7 +293,8 @@ class AssetGraph implements GeneratedAssetHider {
269293
anchorOutputs: anchorOutputs,
270294
);
271295
}
272-
for (var output in node.outputs) {
296+
final outputs = computeOutputs();
297+
for (var output in (outputs[node.id] ?? const <AssetId>{})) {
273298
updateNodeIfPresent(output, (nodeBuilder) {
274299
if (nodeBuilder.type == NodeType.generated) {
275300
nodeBuilder.generatedNodeState.inputs.remove(id);
@@ -285,23 +310,14 @@ class AssetGraph implements GeneratedAssetHider {
285310
for (var input in node.generatedNodeState!.inputs) {
286311
// We may have already removed this node entirely.
287312
updateNodeIfPresent(input, (nodeBuilder) {
288-
nodeBuilder
289-
..outputs.remove(id)
290-
..primaryOutputs.remove(id);
313+
nodeBuilder.primaryOutputs.remove(id);
291314
});
292315
}
293-
updateNode(node.generatedNodeConfiguration!.builderOptionsId, (
294-
nodeBuilder,
295-
) {
296-
nodeBuilder.outputs.remove(id);
297-
});
298316
} else if (node.type == NodeType.glob) {
299317
for (var input in node.globNodeState!.inputs) {
300318
// We may have already removed this node entirely.
301319
updateNodeIfPresent(input, (nodeBuilder) {
302-
nodeBuilder
303-
..outputs.remove(id)
304-
..primaryOutputs.remove(id);
320+
nodeBuilder.primaryOutputs.remove(id);
305321
});
306322
}
307323
}
@@ -319,6 +335,23 @@ class AssetGraph implements GeneratedAssetHider {
319335
return removedIds;
320336
}
321337

338+
Map<AssetId, Set<AssetId>> computeOutputs() {
339+
if (_outputs != null) return _outputs!;
340+
final result = <AssetId, Set<AssetId>>{};
341+
for (final node in allNodes) {
342+
if (node.type == NodeType.generated) {
343+
result
344+
.putIfAbsent(node.id, () => {})
345+
.addAll(node.generatedNodeState!.inputs);
346+
} else if (node.type == NodeType.glob) {
347+
result
348+
.putIfAbsent(node.id, () => {})
349+
.addAll(node.globNodeState!.inputs);
350+
}
351+
}
352+
return _outputs = result;
353+
}
354+
322355
/// All nodes in the graph, whether source files or generated outputs.
323356
Iterable<AssetNode> get allNodes =>
324357
_nodesByPackage.values.expand((pkdIds) => pkdIds.values);
@@ -410,8 +443,7 @@ class AssetGraph implements GeneratedAssetHider {
410443
.where(
411444
(node) =>
412445
node.isTrackedInput &&
413-
(node.outputs.isNotEmpty ||
414-
node.primaryOutputs.isNotEmpty ||
446+
(node.primaryOutputs.isNotEmpty ||
415447
node.lastKnownDigest != null),
416448
)
417449
.map((node) => node.id),
@@ -460,6 +492,7 @@ class AssetGraph implements GeneratedAssetHider {
460492
// Transitively invalidates all assets. This needs to happen after the
461493
// structure of the graph has been updated.
462494
var invalidatedIds = <AssetId>{};
495+
final computedOutputs = computeOutputs();
463496

464497
void invalidateNodeAndDeps(AssetId startNodeId) {
465498
if (!invalidatedIds.add(startNodeId)) return;
@@ -486,7 +519,8 @@ class AssetGraph implements GeneratedAssetHider {
486519
});
487520

488521
if (invalidatedNode != null) {
489-
for (final id in invalidatedNode.outputs) {
522+
for (final id
523+
in (computedOutputs[invalidatedNode.id] ?? const <AssetId>{})) {
490524
if (invalidatedIds.add(id)) {
491525
nodesToInvalidate.add(id);
492526
}
@@ -713,14 +747,6 @@ class AssetGraph implements GeneratedAssetHider {
713747
builderOptionsId: builderOptionsNode.id,
714748
isHidden: isHidden,
715749
);
716-
if (existing != null) {
717-
newNode = newNode.rebuild((b) => b..outputs.addAll(existing!.outputs));
718-
// Ensure we set up the reverse link for NodeWithInput nodes.
719-
_addInput(existing.outputs, output);
720-
}
721-
updateNode(builderOptionsNode.id, (nodeBuilder) {
722-
nodeBuilder.outputs.add(output);
723-
});
724750
_add(newNode);
725751
}
726752
return removed;
@@ -733,21 +759,6 @@ class AssetGraph implements GeneratedAssetHider {
733759
void add(AssetNode node) => _add(node);
734760
Set<AssetId> remove(AssetId id) => _removeRecursive(id);
735761

736-
/// Adds [input] to all [outputs] if they track inputs.
737-
///
738-
/// Nodes that track inputs are [AssetNode.generated] or [AssetNode.glob].
739-
void _addInput(Iterable<AssetId> outputs, AssetId input) {
740-
for (var output in outputs) {
741-
updateNodeIfPresent(output, (nodeBuilder) {
742-
if (nodeBuilder.type == NodeType.generated) {
743-
nodeBuilder.generatedNodeState.inputs.add(input);
744-
} else if (nodeBuilder.type == NodeType.glob) {
745-
nodeBuilder.globNodeState.inputs.add(input);
746-
}
747-
});
748-
}
749-
}
750-
751762
@override
752763
AssetId maybeHide(AssetId id, String rootPackage) {
753764
if (id.path.startsWith(generatedOutputDirectory) ||

build_runner_core/lib/src/asset_graph/node.dart

-6
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
5757
/// when run on this asset.
5858
BuiltSet<AssetId> get primaryOutputs;
5959

60-
/// The [AssetId]s of all generated assets which are output by a [Builder]
61-
/// which reads this asset.
62-
BuiltSet<AssetId> get outputs;
63-
6460
/// The [Digest] for this node in its last known state.
6561
///
6662
/// May be `null` if this asset has no outputs, or if it doesn't actually
@@ -96,7 +92,6 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
9692
bool get changesRequireRebuild =>
9793
type == NodeType.internal ||
9894
type == NodeType.glob ||
99-
outputs.isNotEmpty ||
10095
lastKnownDigest != null;
10196

10297
factory AssetNode([void Function(AssetNodeBuilder) updates]) = _$AssetNode;
@@ -124,7 +119,6 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
124119
b.id = id;
125120
b.type = NodeType.source;
126121
b.primaryOutputs.replace(primaryOutputs ?? {});
127-
b.outputs.replace(outputs ?? {});
128122
b.lastKnownDigest = lastKnownDigest;
129123
});
130124

build_runner_core/lib/src/asset_graph/node.g.dart

-38
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)