Skip to content

Commit 36da1b5

Browse files
committed
[native_assets_builder] Report dart sources as dependencies of hooks
1 parent 7e9897b commit 36da1b5

File tree

9 files changed

+118
-53
lines changed

9 files changed

+118
-53
lines changed

.github/workflows/native.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ permissions: read-all
77

88
on:
99
pull_request:
10-
branches: [main]
10+
# No `branches:` to enable stacked PRs on GitHub.
1111
paths:
1212
- ".github/workflows/native.yaml"
1313
- "pkgs/native_assets_builder/**"

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

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class NativeAssetsBuildRunner {
157157
'Build configuration for ${package.name} contains errors', errors);
158158
}
159159

160-
final hookOutput = await _runHookForPackageCached(
160+
final (hookOutput, hookDeps) = await _runHookForPackageCached(
161161
Hook.build,
162162
config,
163163
(config, output) =>
@@ -168,7 +168,7 @@ class NativeAssetsBuildRunner {
168168
packageLayout,
169169
);
170170
if (hookOutput == null) return null;
171-
hookResult = hookResult.copyAdd(hookOutput);
171+
hookResult = hookResult.copyAdd(hookOutput, hookDeps!);
172172
globalMetadata[package.name] = (hookOutput as BuildOutput).metadata;
173173
}
174174

@@ -259,7 +259,7 @@ class NativeAssetsBuildRunner {
259259
'Link configuration for ${package.name} contains errors', errors);
260260
}
261261

262-
final hookOutput = await _runHookForPackageCached(
262+
final (hookOutput, hookDeps) = await _runHookForPackageCached(
263263
Hook.link,
264264
config,
265265
(config, output) =>
@@ -270,7 +270,7 @@ class NativeAssetsBuildRunner {
270270
packageLayout,
271271
);
272272
if (hookOutput == null) return null;
273-
hookResult = hookResult.copyAdd(hookOutput);
273+
hookResult = hookResult.copyAdd(hookOutput, hookDeps!);
274274
}
275275

276276
final errors = await applicationAssetValidator(hookResult.encodedAssets);
@@ -437,12 +437,12 @@ class NativeAssetsBuildRunner {
437437
),
438438
);
439439
if (buildOutput == null) return null;
440-
hookResult = hookResult.copyAdd(buildOutput);
440+
hookResult = hookResult.copyAdd(buildOutput, [/*dry run is not cached*/]);
441441
}
442442
return hookResult;
443443
}
444444

445-
Future<HookOutput?> _runHookForPackageCached(
445+
Future<(HookOutput?, List<Uri>?)> _runHookForPackageCached(
446446
Hook hook,
447447
HookConfig config,
448448
_HookValidator validator,
@@ -464,7 +464,7 @@ class NativeAssetsBuildRunner {
464464
final (
465465
compileSuccess,
466466
hookKernelFile,
467-
hookHashesFile,
467+
hookHashes,
468468
) = await _compileHookForPackageCached(
469469
config.packageName,
470470
config.outputDirectory,
@@ -473,7 +473,7 @@ class NativeAssetsBuildRunner {
473473
workingDirectory,
474474
);
475475
if (!compileSuccess) {
476-
return null;
476+
return (null, null);
477477
}
478478

479479
final buildOutputFile =
@@ -497,7 +497,7 @@ ${hook.outputName} contained a format error.
497497
Contents: ${buildOutputFile.readAsStringSync()}.
498498
${e.message}
499499
''');
500-
return null;
500+
return (null, null);
501501
}
502502

503503
final outdatedDependency =
@@ -510,7 +510,7 @@ ${e.message}
510510
);
511511
// All build flags go into [outDir]. Therefore we do not have to
512512
// check here whether the config is equal.
513-
return output;
513+
return (output, hookHashes.fileSystemEntities);
514514
}
515515
logger.info(
516516
'Rerunning ${hook.name} for ${config.packageName}'
@@ -538,7 +538,7 @@ ${e.message}
538538
[
539539
...result.dependencies,
540540
// Also depend on the hook source code.
541-
hookHashesFile.uri,
541+
hookHashes.file.uri,
542542
],
543543
lastModifiedCutoffTime,
544544
environment,
@@ -547,7 +547,7 @@ ${e.message}
547547
logger.severe('File modified during build. Build must be rerun.');
548548
}
549549
}
550-
return result;
550+
return (result, hookHashes.fileSystemEntities);
551551
},
552552
);
553553
}
@@ -685,7 +685,7 @@ ${e.message}
685685
///
686686
/// TODO(https://github.com/dart-lang/native/issues/1578): Compile only once
687687
/// instead of per config. This requires more locking.
688-
Future<(bool success, File kernelFile, File cacheFile)>
688+
Future<(bool success, File kernelFile, DependenciesHashFile cacheFile)>
689689
_compileHookForPackageCached(
690690
String packageName,
691691
Uri outputDirectory,
@@ -721,7 +721,7 @@ ${e.message}
721721
}
722722

723723
if (!mustCompile) {
724-
return (true, kernelFile, dependenciesHashFile);
724+
return (true, kernelFile, dependenciesHashes);
725725
}
726726

727727
final success = await _compileHookForPackage(
@@ -734,7 +734,7 @@ ${e.message}
734734
);
735735
if (!success) {
736736
await dependenciesHashFile.delete();
737-
return (success, kernelFile, dependenciesHashFile);
737+
return (success, kernelFile, dependenciesHashes);
738738
}
739739

740740
final dartSources = await _readDepFile(depFile);
@@ -751,19 +751,7 @@ ${e.message}
751751
logger.severe('File modified during build. Build must be rerun.');
752752
}
753753

754-
return (success, kernelFile, dependenciesHashFile);
755-
}
756-
757-
Future<List<Uri>> _readDepFile(File depFile) async {
758-
// Format: `path/to/my.dill: path/to/my.dart, path/to/more.dart`
759-
final depFileContents = await depFile.readAsString();
760-
final dartSources = depFileContents
761-
.trim()
762-
.split(' ')
763-
.skip(1) // '<kernel file>:'
764-
.map(Uri.file)
765-
.toList();
766-
return dartSources;
754+
return (success, kernelFile, dependenciesHashes);
767755
}
768756

769757
Future<bool> _compileHookForPackage(
@@ -927,3 +915,42 @@ ${compileResult.stdout}
927915
extension on Uri {
928916
Uri get parent => File(toFilePath()).parent.uri;
929917
}
918+
919+
/// Parses depfile contents.
920+
///
921+
/// Format: `path/to/my.dill: path/to/my.dart, path/to/more.dart`
922+
///
923+
/// However, the spaces in paths are escaped with backslashes, and the
924+
/// backslashes are escaped with backslashes:
925+
///
926+
/// ```dart
927+
/// String _escapePath(String path) {
928+
/// return path.replaceAll('\\', '\\\\').replaceAll(' ', '\\ ');
929+
/// }
930+
/// ```
931+
List<String> parseDepFileInputs(String contents) {
932+
final output = contents.split(': ').first;
933+
contents = contents.substring(output.length + ': '.length).trim();
934+
final inputs = <String>[];
935+
var currentWord = '';
936+
var escape = false;
937+
for (var i = 0; i < contents.length; i++) {
938+
if (contents[i] == r'\' && !escape) {
939+
escape = true;
940+
} else if (contents[i] == ' ' && !escape) {
941+
inputs.add(currentWord);
942+
currentWord = '';
943+
} else {
944+
currentWord += contents[i];
945+
escape = false;
946+
}
947+
}
948+
inputs.add(currentWord);
949+
return inputs;
950+
}
951+
952+
Future<List<Uri>> _readDepFile(File depFile) async {
953+
final depFileContents = await depFile.readAsString();
954+
final dartSources = parseDepFileInputs(depFileContents);
955+
return dartSources.map(Uri.file).toList();
956+
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,21 @@ import '../utils/uri.dart';
1313

1414
class DependenciesHashFile {
1515
DependenciesHashFile({
16-
required File file,
17-
}) : _file = file;
16+
required this.file,
17+
});
1818

19-
final File _file;
19+
final File file;
2020
FileSystemHashes _hashes = FileSystemHashes();
2121

22+
List<Uri> get fileSystemEntities => _hashes.files.map((e) => e.path).toList();
23+
2224
Future<void> _readFile() async {
23-
if (!await _file.exists()) {
25+
if (!await file.exists()) {
2426
_hashes = FileSystemHashes();
2527
return;
2628
}
2729
final jsonObject =
28-
(json.decode(utf8.decode(await _file.readAsBytes())) as Map)
30+
(json.decode(utf8.decode(await file.readAsBytes())) as Map)
2931
.cast<String, Object>();
3032
_hashes = FileSystemHashes.fromJson(jsonObject);
3133
}
@@ -70,7 +72,7 @@ class DependenciesHashFile {
7072
return modifiedAfterTimeStamp;
7173
}
7274

73-
Future<void> _persist() => _file.writeAsString(json.encode(_hashes.toJson()));
75+
Future<void> _persist() => file.writeAsString(json.encode(_hashes.toJson()));
7476

7577
/// Reads the file with hashes and reports if there is an outdated file,
7678
/// directory or environment variable.

pkgs/native_assets_builder/lib/src/model/hook_result.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ final class HookResult implements BuildResult, BuildDryRunResult, LinkResult {
3939
dependencies: dependencies ?? [],
4040
);
4141

42-
HookResult copyAdd(HookOutput hookOutput) {
42+
HookResult copyAdd(HookOutput hookOutput, List<Uri> dependencies) {
4343
final mergedMaps = mergeMaps(
4444
encodedAssetsForLinking,
4545
hookOutput is BuildOutput
@@ -59,8 +59,9 @@ final class HookResult implements BuildResult, BuildDryRunResult, LinkResult {
5959
],
6060
encodedAssetsForLinking: mergedMaps,
6161
dependencies: [
62-
...dependencies,
62+
...this.dependencies,
6363
...hookOutput.dependencies,
64+
...dependencies,
6465
]..sort(_uriCompare),
6566
);
6667
}

pkgs/native_assets_builder/test/build_runner/build_dependencies_test.dart

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,28 @@ void main() async {
5050
expect(result.encodedAssets.length, 2);
5151
expect(
5252
result.dependencies,
53-
[
54-
tempUri.resolve('native_add/').resolve('src/native_add.c'),
55-
tempUri
56-
.resolve('native_subtract/')
57-
.resolve('src/native_subtract.c'),
58-
],
53+
containsAll([
54+
tempUri.resolve('native_add/src/native_add.c'),
55+
tempUri.resolve('native_subtract/src/native_subtract.c'),
56+
if (!Platform.isWindows) ...[
57+
tempUri.resolve('native_add/hook/build.dart'),
58+
tempUri.resolve('native_subtract/hook/build.dart'),
59+
],
60+
]),
5961
);
62+
if (Platform.isWindows) {
63+
expect(
64+
// https://github.com/dart-lang/sdk/issues/59657
65+
// Deps file on windows sometimes have lowercase drive letters.
66+
// File.exists will work, but Uri equality doesn't.
67+
result.dependencies
68+
.map((e) => Uri.file(e.toFilePath().toLowerCase())),
69+
containsAll([
70+
tempUri.resolve('native_add/hook/build.dart'),
71+
tempUri.resolve('native_subtract/hook/build.dart'),
72+
].map((e) => Uri.file(e.toFilePath().toLowerCase()))),
73+
);
74+
}
6075
}
6176
});
6277
});

pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ void main() async {
4444
);
4545
expect(
4646
result.dependencies,
47-
[
47+
contains(
4848
packageUri.resolve('src/native_add.c'),
49-
],
49+
),
5050
);
5151
}
5252

@@ -80,9 +80,9 @@ void main() async {
8080
);
8181
expect(
8282
result.dependencies,
83-
[
83+
contains(
8484
packageUri.resolve('src/native_add.c'),
85-
],
85+
),
8686
);
8787
}
8888
});

pkgs/native_assets_builder/test/build_runner/build_runner_failure_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ void main() async {
3939
symbols: ['add']);
4040
expect(
4141
result.dependencies,
42-
[
42+
contains(
4343
packageUri.resolve('src/native_add.c'),
44-
],
44+
),
4545
);
4646
}
4747

@@ -95,9 +95,9 @@ void main() async {
9595
symbols: ['add']);
9696
expect(
9797
result.dependencies,
98-
[
98+
contains(
9999
packageUri.resolve('src/native_add.c'),
100-
],
100+
),
101101
);
102102
}
103103
});

pkgs/native_assets_builder/test/build_runner/build_runner_non_root_package_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ void main() async {
5555
expect(result.encodedAssets, isNotEmpty);
5656
expect(
5757
result.dependencies,
58-
[
58+
contains(
5959
packageUri.resolve('src/native_add.c'),
60-
],
60+
),
6161
);
6262
expect(
6363
logMessages.join('\n'),
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:native_assets_builder/src/build_runner/build_runner.dart';
6+
import 'package:test/test.dart';
7+
8+
void main() {
9+
test('parseDepFileInputs', () {
10+
expect(
11+
parseDepFileInputs(
12+
r'C:\\Program\ Files\\foo.dill: C:\\Program\ Files\\foo.dart C:\\Program\ Files\\bar.dart',
13+
),
14+
[
15+
r'C:\Program Files\foo.dart',
16+
r'C:\Program Files\bar.dart',
17+
],
18+
);
19+
});
20+
}

0 commit comments

Comments
 (0)