Skip to content

Commit 9c33168

Browse files
authored
[native_assets_builder] Recompile hook kernel if Dart changes (#1763)
Addresses the remaining comments on #1750. I'm unsure how to test the recompiling of the kernel file if Dart changes without writing a test that downloads a different Dart SDK.
1 parent e69c74d commit 9c33168

File tree

4 files changed

+104
-67
lines changed

4 files changed

+104
-67
lines changed

pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -510,20 +510,23 @@ ${e.message}
510510
''');
511511
return null;
512512
}
513-
514-
final outdated =
515-
(await dependenciesHashes.findOutdatedFileSystemEntity()) != null;
516-
if (!outdated) {
513+
final outdatedFile =
514+
await dependenciesHashes.findOutdatedFileSystemEntity();
515+
if (outdatedFile == null) {
517516
logger.info(
518-
[
519-
'Skipping ${hook.name} for ${config.packageName} in $outDir.',
520-
'Last build on ${output.timestamp}.',
521-
].join(' '),
517+
'Skipping ${hook.name} for ${config.packageName}'
518+
' in ${outDir.toFilePath()}.'
519+
' Last build on ${output.timestamp}.',
522520
);
523521
// All build flags go into [outDir]. Therefore we do not have to
524522
// check here whether the config is equal.
525523
return output;
526524
}
525+
logger.info(
526+
'Rerunning ${hook.name} for ${config.packageName}'
527+
' in ${outDir.toFilePath()}.'
528+
' ${outdatedFile.toFilePath()} changed.',
529+
);
527530
}
528531

529532
final result = await _runHookForPackage(
@@ -542,7 +545,8 @@ ${e.message}
542545
await dependenciesHashFile.delete();
543546
}
544547
} else {
545-
final modifiedDuringBuild = await dependenciesHashes.hashFiles(
548+
final modifiedDuringBuild =
549+
await dependenciesHashes.hashFilesAndDirectories(
546550
[
547551
...result.dependencies,
548552
// Also depend on the hook source code.
@@ -689,50 +693,68 @@ ${e.message}
689693
);
690694
final dependenciesHashes = DependenciesHashFile(file: dependenciesHashFile);
691695
final lastModifiedCutoffTime = DateTime.now();
692-
final bool mustCompile;
696+
var mustCompile = false;
693697
if (!await dependenciesHashFile.exists()) {
694698
mustCompile = true;
695699
} else {
696-
mustCompile =
697-
(await dependenciesHashes.findOutdatedFileSystemEntity()) != null;
700+
final outdatedFile =
701+
await dependenciesHashes.findOutdatedFileSystemEntity();
702+
if (outdatedFile != null) {
703+
mustCompile = true;
704+
logger.info(
705+
'Recompiling ${scriptUri.toFilePath()}, '
706+
'${outdatedFile.toFilePath()} changed.',
707+
);
708+
}
698709
}
699-
final bool success;
710+
700711
if (!mustCompile) {
701-
success = true;
702-
} else {
703-
success = await _compileHookForPackage(
704-
packageName,
705-
scriptUri,
706-
packageConfigUri,
707-
workingDirectory,
708-
includeParentEnvironment,
709-
kernelFile,
710-
depFile,
711-
);
712+
return (true, kernelFile, dependenciesHashFile);
713+
}
712714

713-
if (success) {
714-
// Format: `path/to/my.dill: path/to/my.dart, path/to/more.dart`
715-
final depFileContents = await depFile.readAsString();
716-
final dartSources = depFileContents
717-
.trim()
718-
.split(' ')
719-
.skip(1) // '<kernel file>:'
720-
.map(Uri.file)
721-
.toList();
722-
final modifiedDuringBuild = await dependenciesHashes.hashFiles(
723-
dartSources,
724-
validBeforeLastModified: lastModifiedCutoffTime,
725-
);
726-
if (modifiedDuringBuild != null) {
727-
logger.severe('File modified during build. Build must be rerun.');
728-
}
729-
} else {
730-
await dependenciesHashFile.delete();
731-
}
715+
final success = await _compileHookForPackage(
716+
packageName,
717+
scriptUri,
718+
packageConfigUri,
719+
workingDirectory,
720+
includeParentEnvironment,
721+
kernelFile,
722+
depFile,
723+
);
724+
if (!success) {
725+
await dependenciesHashFile.delete();
726+
return (success, kernelFile, dependenciesHashFile);
727+
}
728+
729+
final dartSources = await _readDepFile(depFile);
730+
final modifiedDuringBuild =
731+
await dependenciesHashes.hashFilesAndDirectories(
732+
[
733+
...dartSources,
734+
// If the Dart version changed, recompile.
735+
dartExecutable.resolve('../version'),
736+
],
737+
validBeforeLastModified: lastModifiedCutoffTime,
738+
);
739+
if (modifiedDuringBuild != null) {
740+
logger.severe('File modified during build. Build must be rerun.');
732741
}
742+
733743
return (success, kernelFile, dependenciesHashFile);
734744
}
735745

746+
Future<List<Uri>> _readDepFile(File depFile) async {
747+
// Format: `path/to/my.dill: path/to/my.dart, path/to/more.dart`
748+
final depFileContents = await depFile.readAsString();
749+
final dartSources = depFileContents
750+
.trim()
751+
.split(' ')
752+
.skip(1) // '<kernel file>:'
753+
.map(Uri.file)
754+
.toList();
755+
return dartSources;
756+
}
757+
736758
Future<bool> _compileHookForPackage(
737759
String packageName,
738760
Uri scriptUri,

pkgs/native_assets_builder/lib/src/dependencies_hash_file/dependencies_hash_file.dart

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class DependenciesHashFile {
2626
}
2727
final jsonObject =
2828
(json.decode(utf8.decode(await _file.readAsBytes())) as Map)
29-
.cast<String, dynamic>();
29+
.cast<String, Object>();
3030
_hashes = FileSystemHashes.fromJson(jsonObject);
3131
}
3232

@@ -38,7 +38,7 @@ class DependenciesHashFile {
3838
/// If [validBeforeLastModified] is provided, any entities that were modified
3939
/// after [validBeforeLastModified] will get a dummy hash so that they will
4040
/// show up as outdated. If any such entity exists, its uri will be returned.
41-
Future<Uri?> hashFiles(
41+
Future<Uri?> hashFilesAndDirectories(
4242
List<Uri> fileSystemEntities, {
4343
DateTime? validBeforeLastModified,
4444
}) async {
@@ -134,32 +134,25 @@ class DependenciesHashFile {
134134
/// [Directory] hashes are a hash of the names of the direct children.
135135
class FileSystemHashes {
136136
FileSystemHashes({
137-
this.version = 1,
138137
List<FilesystemEntityHash>? files,
139138
}) : files = files ?? [];
140139

141-
factory FileSystemHashes.fromJson(Map<String, dynamic> json) {
142-
final version = json[_versionKey] as int;
143-
final rawEntries =
144-
(json[_entitiesKey] as List<dynamic>).cast<Map<String, dynamic>>();
140+
factory FileSystemHashes.fromJson(Map<String, Object> json) {
141+
final rawEntries = (json[_entitiesKey] as List).cast<Object>();
145142
final files = <FilesystemEntityHash>[
146-
for (final Map<String, dynamic> rawEntry in rawEntries)
147-
FilesystemEntityHash._fromJson(rawEntry),
143+
for (final rawEntry in rawEntries)
144+
FilesystemEntityHash._fromJson((rawEntry as Map).cast()),
148145
];
149146
return FileSystemHashes(
150-
version: version,
151147
files: files,
152148
);
153149
}
154150

155-
final int version;
156151
final List<FilesystemEntityHash> files;
157152

158-
static const _versionKey = 'version';
159153
static const _entitiesKey = 'entities';
160154

161155
Map<String, Object> toJson() => <String, Object>{
162-
_versionKey: version,
163156
_entitiesKey: <Object>[
164157
for (final FilesystemEntityHash file in files) file.toJson(),
165158
],
@@ -177,7 +170,7 @@ class FilesystemEntityHash {
177170
this.hash,
178171
);
179172

180-
factory FilesystemEntityHash._fromJson(Map<String, dynamic> json) =>
173+
factory FilesystemEntityHash._fromJson(Map<String, Object> json) =>
181174
FilesystemEntityHash(
182175
_fileSystemPathToUri(json[_pathKey] as String),
183176
json[_hashKey] as int,

pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ void main() async {
6161
buildValidator: validateCodeAssetBuildOutput,
6262
applicationAssetValidator: validateCodeAssetInApplication,
6363
))!;
64+
final hookUri = packageUri.resolve('hook/build.dart');
65+
print(logMessages.join('\n'));
66+
expect(
67+
logMessages.join('\n'),
68+
isNot(contains('Recompiling ${hookUri.toFilePath()}')),
69+
);
6470
expect(
6571
logMessages.join('\n'),
6672
contains('Skipping build for native_add'),
@@ -87,10 +93,14 @@ void main() async {
8793
await copyTestProjects(targetUri: tempUri);
8894
final packageUri = tempUri.resolve('native_add/');
8995

96+
final logMessages = <String>[];
97+
final logger = createCapturingLogger(logMessages);
98+
9099
await runPubGet(
91100
workingDirectory: packageUri,
92101
logger: logger,
93102
);
103+
logMessages.clear();
94104

95105
{
96106
final result = (await build(
@@ -105,6 +115,7 @@ void main() async {
105115
await expectSymbols(
106116
asset: CodeAsset.fromEncoded(result.encodedAssets.single),
107117
symbols: ['add']);
118+
logMessages.clear();
108119
}
109120

110121
await copyTestProjects(
@@ -122,6 +133,18 @@ void main() async {
122133
buildValidator: validateCodeAssetBuildOutput,
123134
applicationAssetValidator: validateCodeAssetInApplication,
124135
))!;
136+
137+
final cUri = packageUri.resolve('src/').resolve('native_add.c');
138+
expect(
139+
logMessages.join('\n'),
140+
stringContainsInOrder(
141+
[
142+
'Rerunning build for native_add in',
143+
'${cUri.toFilePath()} changed.'
144+
],
145+
),
146+
);
147+
125148
await expectSymbols(
126149
asset: CodeAsset.fromEncoded(result.encodedAssets.single),
127150
symbols: ['add', 'subtract'],
@@ -181,14 +204,13 @@ void main() async {
181204
buildValidator: validateCodeAssetBuildOutput,
182205
applicationAssetValidator: validateCodeAssetInApplication,
183206
))!;
184-
{
185-
final compiledHook = logMessages
186-
.where((m) =>
187-
m.contains('dart compile kernel') ||
188-
m.contains('dart.exe compile kernel'))
189-
.isNotEmpty;
190-
expect(compiledHook, isTrue);
191-
}
207+
208+
final hookUri = packageUri.resolve('hook/build.dart');
209+
expect(
210+
logMessages.join('\n'),
211+
contains('Recompiling ${hookUri.toFilePath()}'),
212+
);
213+
192214
logMessages.clear();
193215
await expectSymbols(
194216
asset: CodeAsset.fromEncoded(result.encodedAssets.single),

pkgs/native_assets_builder/test/dependencies_hash_file/dependencies_hash_file_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void main() async {
4343
await tempFile.writeAsString('hello');
4444
await subFile.writeAsString('world');
4545

46-
await hashes.hashFiles([
46+
await hashes.hashFilesAndDirectories([
4747
tempFile.uri,
4848
tempSubDir.uri,
4949
]);
@@ -95,7 +95,7 @@ void main() async {
9595

9696
// If a file is modified after the valid timestamp, it should be marked
9797
// as changed.
98-
await hashes.hashFiles(
98+
await hashes.hashFilesAndDirectories(
9999
[
100100
tempFile.uri,
101101
],

0 commit comments

Comments
 (0)