[flutter_tools] provide more context for build_system invalidation (#77961)

This commit is contained in:
Jonah Williams 2021-03-11 15:53:53 -08:00 committed by GitHub
parent 541bff4058
commit 32474dca20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 8 deletions

View file

@ -1027,12 +1027,16 @@ class Node {
/// One or more reasons why a task was invalidated.
///
/// May be empty if the task was skipped.
final Set<InvalidatedReason> invalidatedReasons = <InvalidatedReason>{};
final Map<InvalidatedReasonKind, InvalidatedReason> invalidatedReasons = <InvalidatedReasonKind, InvalidatedReason>{};
/// Whether this node needs an action performed.
bool get dirty => _dirty;
bool _dirty = false;
InvalidatedReason _invalidate(InvalidatedReasonKind kind) {
return invalidatedReasons[kind] ??= InvalidatedReason(kind);
}
/// Collect hashes for all inputs to determine if any have changed.
///
/// Returns whether this target can be skipped.
@ -1060,7 +1064,8 @@ class Node {
if (fileStore.currentAssetKeys.containsKey(absolutePath)) {
final String currentHash = fileStore.currentAssetKeys[absolutePath];
if (currentHash != previousAssetKey) {
invalidatedReasons.add(InvalidatedReason.inputChanged);
final InvalidatedReason reason = _invalidate(InvalidatedReasonKind.inputChanged);
reason.data.add(absolutePath);
_dirty = true;
}
} else {
@ -1074,13 +1079,15 @@ class Node {
// output paths changed.
if (!currentOutputPaths.contains(previousOutput)) {
_dirty = true;
invalidatedReasons.add(InvalidatedReason.outputSetChanged);
final InvalidatedReason reason = _invalidate(InvalidatedReasonKind.outputSetChanged);
reason.data.add(previousOutput);
// if this isn't a current output file there is no reason to compute the key.
continue;
}
final File file = fileSystem.file(previousOutput);
if (!file.existsSync()) {
invalidatedReasons.add(InvalidatedReason.outputMissing);
final InvalidatedReason reason = _invalidate(InvalidatedReasonKind.outputMissing);
reason.data.add(file.path);
_dirty = true;
continue;
}
@ -1089,7 +1096,8 @@ class Node {
if (fileStore.currentAssetKeys.containsKey(absolutePath)) {
final String currentHash = fileStore.currentAssetKeys[absolutePath];
if (currentHash != previousHash) {
invalidatedReasons.add(InvalidatedReason.outputChanged);
final InvalidatedReason reason = _invalidate(InvalidatedReasonKind.outputChanged);
reason.data.add(absolutePath);
_dirty = true;
}
} else {
@ -1104,7 +1112,8 @@ class Node {
_dirty = true;
final String missingMessage = missingInputs.map((File file) => file.path).join(', ');
logger.printTrace('invalidated build due to missing files: $missingMessage');
invalidatedReasons.add(InvalidatedReason.inputMissing);
final InvalidatedReason reason = _invalidate(InvalidatedReasonKind.inputMissing);
reason.data.addAll(missingInputs.map((File file) => file.path));
}
// If we have files to diff, compute them asynchronously and then
@ -1112,7 +1121,8 @@ class Node {
if (sourcesToDiff.isNotEmpty) {
final List<File> dirty = fileStore.diffFileList(sourcesToDiff);
if (dirty.isNotEmpty) {
invalidatedReasons.add(InvalidatedReason.inputChanged);
final InvalidatedReason reason = _invalidate(InvalidatedReasonKind.inputChanged);
reason.data.addAll(dirty.map((File file) => file.path));
_dirty = true;
}
}
@ -1120,8 +1130,35 @@ class Node {
}
}
/// Data about why a target was re-run.
class InvalidatedReason {
InvalidatedReason(this.kind);
final InvalidatedReasonKind kind;
/// Absolute file paths of inputs or outputs, depending on [kind].
final List<String> data = <String>[];
@override
String toString() {
switch (kind) {
case InvalidatedReasonKind.inputMissing:
return 'The following inputs were missing: ${data.join(',')}';
case InvalidatedReasonKind.inputChanged:
return 'The following inputs have updated contents: ${data.join(',')}';
case InvalidatedReasonKind.outputChanged:
return 'The following outputs have updated contents: ${data.join(',')}';
case InvalidatedReasonKind.outputMissing:
return 'The following outputs were missing: ${data.join(',')}';
case InvalidatedReasonKind.outputSetChanged:
return 'The following outputs were removed from the output set: ${data.join(',')}';
}
assert(false);
return null;
}
}
/// A description of why a target was rerun.
enum InvalidatedReason {
enum InvalidatedReasonKind {
/// An input file that was expected is missing. This can occur when using
/// depfile dependencies, or if a target is incorrectly specified.
inputMissing,

View file

@ -0,0 +1,30 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/build_system/build_system.dart';
import '../../src/common.dart';
void main() {
testWithoutContext('InvalidatedReason formats message per invalidation kind', () {
final InvalidatedReason inputChanged = InvalidatedReason(InvalidatedReasonKind.inputChanged)
..data.add('a.dart');
final InvalidatedReason outputChanged = InvalidatedReason(InvalidatedReasonKind.outputChanged)
..data.add('b.dart');
final InvalidatedReason inputMissing = InvalidatedReason(InvalidatedReasonKind.inputMissing)
..data.add('c.dart');
final InvalidatedReason outputMissing = InvalidatedReason(InvalidatedReasonKind.outputMissing)
..data.add('d.dart');
final InvalidatedReason outputSetChanged = InvalidatedReason(InvalidatedReasonKind.outputSetChanged)
..data.add('e.dart');
expect(inputChanged.toString(), 'The following inputs have updated contents: a.dart');
expect(outputChanged.toString(), 'The following outputs have updated contents: b.dart');
expect(inputMissing.toString(), 'The following inputs were missing: c.dart');
expect(outputMissing.toString(), 'The following outputs were missing: d.dart');
expect(outputSetChanged.toString(), 'The following outputs were removed from the output set: e.dart');
});
}