Skip to content

Commit bf5df1a

Browse files
authored
Updates handling (#3933)
* Move handling of updates always to `Build`. * Fix test.
1 parent 850a486 commit bf5df1a

File tree

3 files changed

+67
-57
lines changed

3 files changed

+67
-57
lines changed

build_runner_core/lib/src/generate/build_definition.dart

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ class BuildDefinition {
3434
final AssetGraph assetGraph;
3535
final BuildScriptUpdates? buildScriptUpdates;
3636

37-
BuildDefinition._(this.assetGraph, this.buildScriptUpdates);
37+
/// When reusing serialized state from a previous build: the file updates
38+
/// since that build.
39+
///
40+
/// Or, `null` if there was no serialized state or it was discared due to
41+
/// the current build having an incompatible change.
42+
final Map<AssetId, ChangeType>? updates;
43+
44+
BuildDefinition._(this.assetGraph, this.buildScriptUpdates, this.updates);
3845

3946
static Future<BuildDefinition> prepareWorkspace(
4047
BuildEnvironment environment,
@@ -70,11 +77,12 @@ class _Loader {
7077
var internalSources = await assetTracker.findInternalSources();
7178

7279
BuildScriptUpdates? buildScriptUpdates;
80+
Map<AssetId, ChangeType>? updates;
7381
if (assetGraph != null) {
74-
var updates = await logTimedAsync(
82+
updates = await logTimedAsync(
7583
_logger,
7684
'Checking for updates since last build',
77-
() => _updateAssetGraph(
85+
() => _computeUpdates(
7886
assetGraph!,
7987
assetTracker,
8088
_buildPhases,
@@ -92,7 +100,7 @@ class _Loader {
92100

93101
var buildScriptUpdated =
94102
!_options.skipBuildScriptCheck &&
95-
buildScriptUpdates.hasBeenUpdated(updates.keys.toSet());
103+
buildScriptUpdates.hasBeenUpdated(updates!.keys.toSet());
96104
if (buildScriptUpdated) {
97105
_logger.warning('Invalidating asset graph due to build script update!');
98106

@@ -110,6 +118,7 @@ class _Loader {
110118
inputSources.removeAll(deletedSourceOutputs);
111119
assetGraph = null;
112120
buildScriptUpdates = null;
121+
updates = null;
113122
}
114123
}
115124

@@ -167,7 +176,7 @@ class _Loader {
167176
);
168177
}
169178

170-
return BuildDefinition._(assetGraph!, buildScriptUpdates);
179+
return BuildDefinition._(assetGraph!, buildScriptUpdates, updates);
171180
}
172181

173182
/// Deletes the generated output directory.
@@ -178,11 +187,9 @@ class _Loader {
178187
}
179188
}
180189

181-
/// Updates [assetGraph] based on a the new view of the world.
182-
///
183-
/// Once done, this returns a map of [AssetId] to [ChangeType] for all the
184-
/// changes.
185-
Future<Map<AssetId, ChangeType>> _updateAssetGraph(
190+
/// Returns which sources and builder options changed, and the [ChangeType]
191+
/// describing whether they where added, removed or modified.
192+
Future<Map<AssetId, ChangeType>> _computeUpdates(
186193
AssetGraph assetGraph,
187194
AssetTracker assetTracker,
188195
BuildPhases buildPhases,
@@ -197,15 +204,6 @@ class _Loader {
197204
assetGraph,
198205
);
199206
updates.addAll(_computeBuilderOptionsUpdates(assetGraph, buildPhases));
200-
await assetGraph.updateAndInvalidate(
201-
_buildPhases,
202-
updates,
203-
_options.packageGraph.root.name,
204-
(id) => _environment.writer
205-
.copyWith(generatedAssetHider: assetGraph)
206-
.delete(id),
207-
_environment.reader.copyWith(generatedAssetHider: assetGraph),
208-
);
209207
return updates;
210208
}
211209

build_runner_core/lib/src/generate/build_series.dart

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ class BuildSeries {
5050
final RunnerAssetWriter deleteWriter;
5151
final ResourceManager resourceManager = ResourceManager();
5252

53+
/// For the first build only, updates from the previous serialized build
54+
/// state.
55+
///
56+
/// Null after the first build, or if there was no serialized build state, or
57+
/// if the serialized build state was discarded.
58+
Map<AssetId, ChangeType>? updatesFromLoad;
59+
60+
/// Whether the next build is the first build.
61+
bool firstBuild = true;
62+
5363
Future<void> beforeExit() => resourceManager.beforeExit();
5464

5565
BuildSeries._(
@@ -59,6 +69,7 @@ class BuildSeries {
5969
this.options,
6070
this.buildPhases,
6171
this.finalizedReader,
72+
this.updatesFromLoad,
6273
) : deleteWriter = environment.writer.copyWith(
6374
generatedAssetHider: assetGraph,
6475
),
@@ -72,16 +83,29 @@ class BuildSeries {
7283

7384
/// Runs a single build.
7485
///
75-
/// For the first build, pass empty [updates].
86+
/// For the first build, pass any changes since the `BuildSeries` was created
87+
/// as [updates]. If the first build happens immediately then pass empty
88+
/// `updates`.
7689
///
77-
/// For subsequent builds, pass filesystem changes in [updates].
78-
///
79-
/// TODO(davidmorgan): unify these two codepaths.
90+
/// For further builds, pass the changes since the previous builds as
91+
/// [updates].
8092
Future<BuildResult> run(
8193
Map<AssetId, ChangeType> updates, {
8294
Set<BuildDirectory> buildDirs = const <BuildDirectory>{},
8395
Set<BuildFilter> buildFilters = const {},
8496
}) async {
97+
if (firstBuild) {
98+
if (updatesFromLoad != null) {
99+
updates = updatesFromLoad!..addAll(updates);
100+
updatesFromLoad = null;
101+
}
102+
firstBuild = false;
103+
} else {
104+
if (updatesFromLoad != null) {
105+
throw StateError('Only first build can have updates from load.');
106+
}
107+
}
108+
85109
finalizedReader.reset(BuildDirectory.buildPaths(buildDirs), buildFilters);
86110
final build = Build(
87111
environment: environment,
@@ -142,6 +166,7 @@ class BuildSeries {
142166
options,
143167
buildPhases,
144168
finalizedReader,
169+
buildDefinition.updates,
145170
);
146171
return build;
147172
}

build_runner_core/test/generate/build_definition_test.dart

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import 'package:package_config/package_config.dart';
2323
import 'package:path/path.dart' as p;
2424
import 'package:test/test.dart';
2525
import 'package:test_descriptor/test_descriptor.dart' as d;
26+
import 'package:watcher/watcher.dart';
2627

2728
void main() {
2829
final languageVersion = LanguageVersion(2, 0);
@@ -138,7 +139,7 @@ targets:
138139
addTearDown(options.logListener.cancel);
139140
});
140141

141-
group('updates the asset graph', () {
142+
group('reports updates', () {
142143
test('for deleted source and generated nodes', () async {
143144
await createFile(p.join('lib', 'a.txt'), 'a');
144145
await createFile(p.join('lib', 'b.txt'), 'b');
@@ -169,23 +170,15 @@ targets:
169170
options,
170171
buildPhases,
171172
);
172-
var newAssetGraph = buildDefinition.assetGraph;
173-
174-
var generatedANode = newAssetGraph.get(generatedAId)!;
175-
expect(generatedANode, isNotNull);
176-
expect(
177-
generatedANode.generatedNodeState!.pendingBuildAction,
178-
PendingBuildAction.build,
179-
);
180173

181-
expect(newAssetGraph.contains(makeAssetId('a|lib/b.txt')), isFalse);
174+
expect(buildDefinition.updates![generatedAId], ChangeType.REMOVE);
182175
expect(
183-
newAssetGraph.contains(makeAssetId('a|lib/b.txt.copy')),
184-
isFalse,
176+
buildDefinition.updates![makeAssetId('a|lib/b.txt')],
177+
ChangeType.REMOVE,
185178
);
186179
});
187180

188-
test('for new sources and generated nodes', () async {
181+
test('for new sources', () async {
189182
var buildPhases = BuildPhases([
190183
InBuildPhase(TestBuilder(), 'a', hideOutput: true),
191184
]);
@@ -206,17 +199,10 @@ targets:
206199
options,
207200
buildPhases,
208201
);
209-
var newAssetGraph = buildDefinition.assetGraph;
210202

211-
expect(newAssetGraph.contains(makeAssetId('a|lib/a.txt')), isTrue);
212-
213-
var generatedANode =
214-
newAssetGraph.get(makeAssetId('a|lib/a.txt.copy'))!;
215-
expect(generatedANode, isNotNull);
216-
// New nodes definitely need an update.
217203
expect(
218-
generatedANode.generatedNodeState!.pendingBuildAction,
219-
PendingBuildAction.build,
204+
buildDefinition.updates![makeAssetId('a|lib/a.txt')],
205+
ChangeType.ADD,
220206
);
221207
});
222208

@@ -253,14 +239,10 @@ targets:
253239
options,
254240
buildPhases,
255241
);
256-
var newAssetGraph = buildDefinition.assetGraph;
257242

258-
var generatedANode =
259-
newAssetGraph.get(makeAssetId('a|lib/a.txt.copy'))!;
260-
expect(generatedANode, isNotNull);
261243
expect(
262-
generatedANode.generatedNodeState!.pendingBuildAction,
263-
PendingBuildAction.buildIfInputsChanged,
244+
buildDefinition.updates![makeAssetId('a|lib/a.txt')],
245+
ChangeType.MODIFY,
264246
);
265247
});
266248

@@ -355,22 +337,27 @@ targets:
355337
options,
356338
newBuildPhases,
357339
);
340+
358341
var newAssetGraph = buildDefinition.assetGraph;
359342

360343
// The *.copy node should be invalidated, its builder options changed.
361344
var generatedACopyNode = newAssetGraph.get(generatedACopyId)!;
362-
expect(generatedACopyNode, isNotNull);
363345
expect(
364-
generatedACopyNode.generatedNodeState!.pendingBuildAction,
365-
PendingBuildAction.buildIfInputsChanged,
346+
buildDefinition.updates![generatedACopyNode
347+
.generatedNodeConfiguration!
348+
.builderOptionsId],
349+
ChangeType.MODIFY,
366350
);
367351

368352
// But the *.clone node should remain the same since its options didn't.
369353
var generatedACloneNode = newAssetGraph.get(generatedACloneId)!;
370-
expect(generatedACloneNode, isNotNull);
371354
expect(
372-
generatedACloneNode.generatedNodeState!.pendingBuildAction,
373-
PendingBuildAction.none,
355+
buildDefinition.updates!.keys,
356+
isNot(
357+
contains(
358+
generatedACloneNode.generatedNodeConfiguration!.builderOptionsId,
359+
),
360+
),
374361
);
375362
});
376363
});

0 commit comments

Comments
 (0)