@@ -201,8 +201,6 @@ class AssetGraph implements GeneratedAssetHider {
201201 var existing = get (node.id);
202202 if (existing != null ) {
203203 if (existing.type == NodeType .missingSource) {
204- // Don't call _removeRecursive, that recursively removes all transitive
205- // primary outputs. We only want to remove this node.
206204 _nodesByPackage[existing.id.package]! .remove (existing.id.path);
207205 node = node.rebuild ((b) {
208206 b.primaryOutputs.addAll (existing.primaryOutputs);
@@ -263,60 +261,23 @@ class AssetGraph implements GeneratedAssetHider {
263261 );
264262 }
265263
266- /// Removes the node representing [id] from the graph, and all of its
267- /// `primaryOutput` s.
268- ///
269- /// Also removes all edges between all removed nodes and remaining nodes.
270- ///
271- /// Returns the IDs of removed asset nodes.
272- Set <AssetId > _removeRecursive (AssetId id, {Set <AssetId >? removedIds}) {
264+ /// Changes [id] and its transitive`primaryOutput` s to `missingSource` nodes.
265+ void _setMissingRecursive (AssetId id, {Set <AssetId >? removedIds}) {
273266 removedIds ?? = < AssetId > {};
274267 var node = get (id);
275- if (node == null ) return removedIds ;
268+ if (node == null ) return ;
276269 removedIds.add (id);
277270 for (var output in node.primaryOutputs.toList ()) {
278- _removeRecursive (output, removedIds: removedIds);
279- }
280- final outputs = computeOutputs ();
281- for (var output in (outputs[node.id] ?? const < AssetId > {})) {
282- updateNodeIfPresent (output, (nodeBuilder) {
283- if (nodeBuilder.type == NodeType .generated) {
284- nodeBuilder.generatedNodeState.inputs.remove (id);
285- } else if (nodeBuilder.type == NodeType .glob) {
286- nodeBuilder.globNodeState
287- ..inputs.remove (id)
288- ..results.remove (id);
289- }
290- });
291- }
292-
293- if (node.type == NodeType .generated) {
294- for (var input in node.generatedNodeState! .inputs) {
295- // We may have already removed this node entirely.
296- updateNodeIfPresent (input, (nodeBuilder) {
297- nodeBuilder.primaryOutputs.remove (id);
298- });
299- }
300- } else if (node.type == NodeType .glob) {
301- for (var input in node.globNodeState! .inputs) {
302- // We may have already removed this node entirely.
303- updateNodeIfPresent (input, (nodeBuilder) {
304- nodeBuilder.primaryOutputs.remove (id);
305- });
306- }
307- }
308-
309- // Missing source nodes need to be kept to retain dependency tracking.
310- if (node.type != NodeType .missingSource) {
311- _nodesByPackage[id.package]! .remove (id.path);
271+ _setMissingRecursive (output, removedIds: removedIds);
312272 }
273+ updateNode (id, (nodeBuilder) {
274+ nodeBuilder.replace (AssetNode .missingSource (id));
275+ });
313276
314277 // Remove post build action applications with removed assets as inputs.
315278 for (final packageOutputs in _postProcessBuildStepOutputs.values) {
316279 packageOutputs.removeWhere ((id, _) => removedIds! .contains (id.input));
317280 }
318-
319- return removedIds;
320281 }
321282
322283 /// Computes node outputs: the inverse of the graph described by the `inputs`
@@ -401,8 +362,12 @@ class AssetGraph implements GeneratedAssetHider {
401362 /// Updates graph structure, invalidating and deleting any outputs that were
402363 /// affected.
403364 ///
404- /// Returns the list of [AssetId] s that were invalidated.
405- Future <Set <AssetId >> updateAndInvalidate (
365+ /// Outputs that are deleted from the filesystem are retained in the graph as
366+ /// `missingSource` nodes.
367+ ///
368+ /// Returns the set of [AssetId] s that were deleted, and the set that was
369+ /// invalidated.
370+ Future <(Set <AssetId >, Set <AssetId >)> updateAndInvalidate (
406371 BuildPhases buildPhases,
407372 Map <AssetId , ChangeType > updates,
408373 String rootPackage,
@@ -572,23 +537,22 @@ class AssetGraph implements GeneratedAssetHider {
572537 }
573538 }
574539
575- // Delete all the invalidated assets, then remove them from the graph. This
576- // order is important because some `AssetWriter`s throw if the id is not in
577- // the graph.
540+ // Delete all the invalidated assets.
578541 await Future .wait (idsToDelete.map (delete));
579542
580- // Remove all deleted source assets from the graph, which also recursively
581- // removes all their primary outputs.
543+ // Change deleted source assets and their transitive primary outputs to
544+ // `missingSource` nodes, rather than deleting them. This allows them to
545+ // remain referenced in `inputs` in order to trigger rebuilds if necessary.
582546 for (final id in removeIds) {
583547 final node = get (id);
584548 if (node != null && node.type == NodeType .source) {
585549 invalidateNodeAndDeps (id);
586- _removeRecursive (id);
550+ _setMissingRecursive (id);
587551 }
588552 }
589553
590554 _outputs = null ;
591- return invalidatedIds;
555+ return (idsToDelete, invalidatedIds) ;
592556 }
593557
594558 /// Crawl up primary inputs to see if the original Source file matches the
@@ -713,9 +677,9 @@ class AssetGraph implements GeneratedAssetHider {
713677 ///
714678 /// If there are existing [AssetNode.source] s or [AssetNode.missingSource] s
715679 /// that overlap the [AssetNode.generated] s, then they will be replaced with
716- /// [AssetNode.generated] s, and all their `primaryOutputs` will be removed
717- /// from from the graph as well . The return value is the set of assets that
718- /// were removed from the graph.
680+ /// [AssetNode.generated] s, and their transitive `primaryOutputs` will be
681+ /// changed to `missingSource` nodes . The return value is the set of assets
682+ /// that were removed from the graph.
719683 Set <AssetId > _addGeneratedOutputs (
720684 Iterable <AssetId > outputs,
721685 int phaseNumber,
@@ -745,7 +709,7 @@ class AssetGraph implements GeneratedAssetHider {
745709 buildPhases.inBuildPhases[phaseNumber].builderLabel,
746710 );
747711 }
748- _removeRecursive (output, removedIds: removed);
712+ _setMissingRecursive (output, removedIds: removed);
749713 }
750714
751715 var newNode = AssetNode .generated (
@@ -769,9 +733,16 @@ class AssetGraph implements GeneratedAssetHider {
769733 @override
770734 String toString () => allNodes.toList ().toString ();
771735
772- // TODO remove once tests are updated
773736 void add (AssetNode node) => _add (node);
774- Set <AssetId > remove (AssetId id) => _removeRecursive (id);
737+
738+ /// Removes a generated node that was output by a post process build step.
739+ /// TODO(davidmorgan): look at removing them from the graph altogether.
740+ void removePostProcessOutput (AssetId id) {
741+ _nodesByPackage[id.package]! .remove (id.path);
742+ }
743+
744+ void removeForTest (AssetId id) =>
745+ _nodesByPackage[id.package]? .remove (id.path);
775746
776747 /// Adds [input] to all [outputs] if they track inputs.
777748 ///
0 commit comments