Skip to content

Commit 3832e4b

Browse files
authored
[native_assets_cli] Add HookInput.outputFile (#1882)
Pass in a path to where the `output.json` should be written. This enables the output file to not be written into the output directory but next to it. This is cleaner. I don't remember where we discussed this, but some references to adding the output json can be found in the discussions here: * #1738
1 parent ba55784 commit 3832e4b

40 files changed

+154
-41
lines changed

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

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class NativeAssetsBuildRunner {
146146
inputBuilder.setupShared(
147147
packageName: package.name,
148148
packageRoot: packageLayout.packageRoot(package.name),
149+
outputFile: buildDirUri.resolve('output.json'),
149150
outputDirectory: outDirUri,
150151
outputDirectoryShared: outDirSharedUri,
151152
);
@@ -244,6 +245,7 @@ class NativeAssetsBuildRunner {
244245
inputBuilder.setupShared(
245246
packageName: package.name,
246247
packageRoot: packageLayout.packageRoot(package.name),
248+
outputFile: buildDirUri.resolve('output.json'),
247249
outputDirectory: outDirUri,
248250
outputDirectoryShared: outDirSharedUri,
249251
);
@@ -350,21 +352,27 @@ class NativeAssetsBuildRunner {
350352
}
351353
final (hookKernelFile, hookHashes) = hookCompileResult;
352354

353-
final buildOutputFile =
354-
_fileSystem.file(input.outputDirectory.resolve(hook.outputName));
355+
final buildOutputFile = _fileSystem.file(input.outputFile);
356+
final buildOutputFileDeprecated = _fileSystem
357+
// ignore: deprecated_member_use
358+
.file(input.outputDirectory.resolve(hook.outputNameDeprecated));
359+
355360
final dependenciesHashFile = input.outputDirectory
356361
.resolve('../dependencies.dependencies_hash_file.json');
357362
final dependenciesHashes =
358363
DependenciesHashFile(_fileSystem, fileUri: dependenciesHashFile);
359364
final lastModifiedCutoffTime = DateTime.now();
360-
if (buildOutputFile.existsSync() && await dependenciesHashes.exists()) {
365+
if ((buildOutputFile.existsSync() ||
366+
buildOutputFileDeprecated.existsSync()) &&
367+
await dependenciesHashes.exists()) {
361368
late final HookOutput output;
362369
try {
363-
output = _readHookOutputFromUri(hook, buildOutputFile);
370+
output = _readHookOutputFromUri(
371+
hook, buildOutputFile, buildOutputFileDeprecated);
364372
} on FormatException catch (e) {
365373
logger.severe('''
366374
Building assets for package:${input.packageName} failed.
367-
${hook.outputName} contained a format error.
375+
${input.outputFile.toFilePath()} contained a format error.
368376
369377
Contents: ${buildOutputFile.readAsStringSync()}.
370378
${e.message}
@@ -458,12 +466,20 @@ ${e.message}
458466
const JsonEncoder.withIndent(' ').convert(input.json);
459467
logger.info('input.json contents: $inputFileContents');
460468
await _fileSystem.file(inputFile).writeAsString(inputFileContents);
461-
final hookOutputUri = input.outputDirectory.resolve(hook.outputName);
469+
final hookOutputUri = input.outputFile;
462470
final hookOutputFile = _fileSystem.file(hookOutputUri);
463471
if (await hookOutputFile.exists()) {
464472
// Ensure we'll never read outdated build results.
465473
await hookOutputFile.delete();
466474
}
475+
final hookOutputUriDeprecated =
476+
// ignore: deprecated_member_use
477+
input.outputDirectory.resolve(hook.outputNameDeprecated);
478+
final hookOutputFileDeprecated = _fileSystem.file(hookOutputUriDeprecated);
479+
if (await hookOutputFileDeprecated.exists()) {
480+
// Ensure we'll never read outdated build results.
481+
await hookOutputFileDeprecated.delete();
482+
}
467483

468484
final arguments = [
469485
'--packages=${packageConfigUri.toFilePath()}',
@@ -508,7 +524,11 @@ ${e.message}
508524
return null;
509525
}
510526

511-
final output = _readHookOutputFromUri(hook, hookOutputFile);
527+
final output = _readHookOutputFromUri(
528+
hook,
529+
hookOutputFile,
530+
hookOutputFileDeprecated,
531+
);
512532
final errors = await _validate(input, output, packageLayout, validator);
513533
if (errors.isNotEmpty) {
514534
_printErrors(
@@ -521,7 +541,7 @@ ${e.message}
521541
} on FormatException catch (e) {
522542
logger.severe('''
523543
Building assets for package:${input.packageName} failed.
524-
${hook.outputName} contained a format error.
544+
${input.outputFile.toFilePath()} contained a format error.
525545
526546
Contents: ${hookOutputFile.readAsStringSync()}.
527547
${e.message}
@@ -780,10 +800,17 @@ ${compileResult.stdout}
780800
return (buildPlan, packageGraph);
781801
}
782802

783-
HookOutput _readHookOutputFromUri(Hook hook, File hookOutputFile) {
803+
HookOutput _readHookOutputFromUri(
804+
Hook hook,
805+
File hookOutputFile,
806+
// TODO(dcharkes): Remove when hooks with 1.7.0 are no longer supported.
807+
File hookOutputFileDeprecated,
808+
) {
784809
final decode = const Utf8Decoder().fuse(const JsonDecoder()).convert;
810+
final file =
811+
hookOutputFile.existsSync() ? hookOutputFile : hookOutputFileDeprecated;
785812
final hookOutputJson =
786-
decode(hookOutputFile.readAsBytesSync()) as Map<String, Object?>;
813+
decode(file.readAsBytesSync()) as Map<String, Object?>;
787814
return hook == Hook.build
788815
? BuildOutput(hookOutputJson)
789816
: LinkOutput(hookOutputJson);

pkgs/native_assets_builder/test/build_runner/build_runner_build_output_format_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void main() async {
4949
} else {
5050
expect(
5151
fullLog,
52-
contains('build_output.json contained a format error.'),
52+
contains('output.json contained a format error.'),
5353
);
5454
}
5555
}

pkgs/native_assets_builder/test/test_data/native_dynamic_linking_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ void main() async {
2121
test(
2222
'native_dynamic_linking build',
2323
() => inTempDir((tempUri) async {
24+
final buildOutputUri = tempUri.resolve('build_output.json');
2425
final outputDirectory = tempUri.resolve('out/');
2526
await Directory.fromUri(outputDirectory).create();
2627
final outputDirectoryShared = tempUri.resolve('out_shared/');
@@ -35,6 +36,7 @@ void main() async {
3536
..setupShared(
3637
packageName: name,
3738
packageRoot: testPackageUri,
39+
outputFile: buildOutputUri,
3840
outputDirectory: outputDirectory,
3941
outputDirectoryShared: outputDirectoryShared,
4042
)
@@ -69,7 +71,6 @@ void main() async {
6971
}
7072
expect(processResult.exitCode, 0);
7173

72-
final buildOutputUri = outputDirectory.resolve('build_output.json');
7374
final buildOutput = BuildOutput(
7475
json.decode(await File.fromUri(buildOutputUri).readAsString())
7576
as Map<String, Object?>);

pkgs/native_assets_builder/test/test_data/transformer_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ void main() async {
3333
logger: logger,
3434
);
3535

36+
final buildOutputUri = tempUri.resolve('build_output.json');
3637
final outputDirectory = tempUri.resolve('out/');
3738
await Directory.fromUri(outputDirectory).create();
3839
final outputDirectoryShared = tempUri.resolve('out_shared/');
@@ -50,6 +51,7 @@ void main() async {
5051
..setupShared(
5152
packageName: packageName,
5253
packageRoot: packageUri,
54+
outputFile: buildOutputUri,
5355
outputDirectory: outputDirectory,
5456
outputDirectoryShared: outputDirectoryShared,
5557
)
@@ -87,7 +89,6 @@ void main() async {
8789
expect(processResult.exitCode, 0);
8890
stdout = processResult.stdout as String;
8991

90-
final buildOutputUri = outputDirectory.resolve('build_output.json');
9192
output = BuildOutput(
9293
json.decode(await File.fromUri(buildOutputUri).readAsString())
9394
as Map<String, Object?>);

pkgs/native_assets_builder/test_data/wrong_build_output/hook/build.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ void main(List<String> args) async {
1212
final inputPath = getInputArgument(args);
1313
final buildInput = BuildInput(
1414
json.decode(File(inputPath).readAsStringSync()) as Map<String, Object?>);
15-
await File.fromUri(buildInput.outputDirectory.resolve('build_output.json'))
16-
.writeAsString(_wrongContents);
15+
await File.fromUri(buildInput.outputFile).writeAsString(_wrongContents);
1716
}
1817

1918
const _wrongContents = '''

pkgs/native_assets_builder/test_data/wrong_build_output_2/hook/build.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ void main(List<String> args) async {
1212
final inputPath = getInputArgument(args);
1313
final buildInput = BuildInput(
1414
json.decode(File(inputPath).readAsStringSync()) as Map<String, Object?>);
15-
await File.fromUri(buildInput.outputDirectory.resolve('build_output.json'))
16-
.writeAsString(_wrongContents);
15+
await File.fromUri(buildInput.outputFile).writeAsString(_wrongContents);
1716
}
1817

1918
const _wrongContents = '''

pkgs/native_assets_builder/test_data/wrong_build_output_3/hook/build.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ void main(List<String> args) async {
1212
final inputPath = getInputArgument(args);
1313
final buildInput = BuildInput(
1414
json.decode(File(inputPath).readAsStringSync()) as Map<String, Object?>);
15-
await File.fromUri(buildInput.outputDirectory.resolve('build_output.json'))
16-
.writeAsString(_rightContents);
15+
await File.fromUri(buildInput.outputFile).writeAsString(_rightContents);
1716
exit(1);
1817
}
1918

@@ -22,5 +21,5 @@ const _rightContents = '''{
2221
"encodedAssets": [],
2322
"dependencies": [],
2423
"metadata": {},
25-
"version": "1.7.0"
24+
"version": "1.8.0"
2625
}''';

pkgs/native_assets_cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
shouldn't change on subsequent invocations of the same flutter or dart command
77
for the same target. The `outputDirectory` is the same if the config is the
88
same.
9+
- **Breaking change** The `output.json` is now part of `BuildInput`.
910

1011
## 0.10.0
1112

pkgs/native_assets_cli/example/build/download_asset/tool/build.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,15 @@ BuildInput createBuildInput(
7070
packageRoot.resolve('.dart_tool/download_asset/$targetName/');
7171
final outputDirectoryShared =
7272
packageRoot.resolve('.dart_tool/download_asset/shared/');
73+
final outputFile =
74+
packageRoot.resolve('.dart_tool/download_asset/output.json');
7375

7476
final os = OS.fromString(osString);
7577
final inputBuilder = BuildInputBuilder()
7678
..setupShared(
7779
packageRoot: packageRoot,
7880
packageName: 'download_asset',
81+
outputFile: outputFile,
7982
outputDirectory: outputDirectory,
8083
outputDirectoryShared: outputDirectoryShared)
8184
..config.setupShared(

pkgs/native_assets_cli/lib/src/api/build.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ Future<void> build(
110110
if (errors.isEmpty) {
111111
final jsonOutput =
112112
const JsonEncoder().fuse(const Utf8Encoder()).convert(output.json);
113-
await File.fromUri(input.outputDirectory.resolve('build_output.json'))
114-
.writeAsBytes(jsonOutput);
113+
await File.fromUri(input.outputFile).writeAsBytes(jsonOutput);
115114
} else {
116115
final message = [
117116
'The output contained unsupported output:',

pkgs/native_assets_cli/lib/src/api/link.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ Future<void> link(
5151
if (errors.isEmpty) {
5252
final jsonOutput =
5353
const JsonEncoder().fuse(const Utf8Encoder()).convert(output.json);
54-
await File.fromUri(input.outputDirectory.resolve('link_output.json'))
55-
.writeAsBytes(jsonOutput);
54+
await File.fromUri(input.outputFile).writeAsBytes(jsonOutput);
5655
} else {
5756
final message = [
5857
'The output contained unsupported output:',

pkgs/native_assets_cli/lib/src/config.dart

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ sealed class HookInput {
5252
/// each other.
5353
final Uri outputDirectoryShared;
5454

55+
/// The file to write the [HookOutput] to at the end of a hook invocation.
56+
Uri get outputFile;
57+
5558
/// The name of the package the assets are built for.
5659
final String packageName;
5760

@@ -91,9 +94,11 @@ sealed class HookInputBuilder {
9194
required String packageName,
9295
required Uri outputDirectory,
9396
required Uri outputDirectoryShared,
97+
required Uri outputFile,
9498
}) {
9599
json[_packageNameInputKey] = packageName;
96100
json[_packageRootInputKey] = packageRoot.toFilePath();
101+
json[_outputFileKey] = outputFile.toFilePath();
97102
json[_outDirInputKey] = outputDirectory.toFilePath();
98103
json[_outDirSharedInputKey] = outputDirectoryShared.toFilePath();
99104
}
@@ -121,6 +126,7 @@ sealed class HookInputBuilder {
121126
// TODO: Bump min-SDK constraint to 3.7 and remove once stable.
122127
const _buildModeInputKeyDeprecated = 'build_mode';
123128
const _metadataConfigKey = 'metadata';
129+
const _outputFileKey = 'out_file';
124130
const _outDirInputKey = 'out_dir';
125131
const _outDirSharedInputKey = 'out_dir_shared';
126132
const _packageNameInputKey = 'package_name';
@@ -133,8 +139,13 @@ const _configKey = 'config';
133139
final class BuildInput extends HookInput {
134140
final Map<String, Metadata> metadata;
135141

142+
@override
143+
final Uri outputFile;
144+
136145
BuildInput(super.json)
137-
: metadata = {
146+
: outputFile = json.optionalPath(_outputFileKey) ??
147+
json.path(_outDirInputKey).resolve('build_output.json'),
148+
metadata = {
138149
for (final entry
139150
in (json.optionalMap(_dependencyMetadataKey) ?? {}).entries)
140151
entry.key: Metadata.fromJson(as<Map<String, Object?>>(entry.value)),
@@ -204,8 +215,13 @@ final class LinkInput extends HookInput {
204215

205216
final Uri? recordedUsagesFile;
206217

218+
@override
219+
final Uri outputFile;
220+
207221
LinkInput(super.json)
208-
: _encodedAssets =
222+
: outputFile = json.optionalPath(_outputFileKey) ??
223+
json.path(_outDirInputKey).resolve('link_output.json'),
224+
_encodedAssets =
209225
_parseAssets(json.getOptional<List<Object?>>(_assetsKey)),
210226
recordedUsagesFile = json.optionalPath(_recordedUsagesFileInputKey);
211227

@@ -578,7 +594,7 @@ extension type EncodedAssetLinkOutputBuilder._(LinkOutputBuilder _builder) {
578594
///
579595
/// We'll never bump the major version. Removing old keys from the input and
580596
/// output is done via modifying [latestParsableVersion].
581-
final latestVersion = Version(1, 7, 0);
597+
final latestVersion = Version(1, 8, 0);
582598

583599
/// The parser can deal with inputs and outputs down to this version.
584600
///

pkgs/native_assets_cli/lib/src/model/build_config_CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## 1.8.0
2+
3+
- Add `BuildInput.outputFile` to specify the outfile. This means the out file
4+
can be outside the `outputDirectory` and avoid potential conflicts.
5+
Compatibility with older hooks: If the file doesn't exist, try the previous
6+
location.
7+
Compatibility with older SDKs: Default the location to where it was.
8+
9+
## 1.7.0
10+
11+
- Complete rewrite of JSON
12+
Compatibility with older hooks: also emit old structure.
13+
Compatibility with older SDKs: keep parsing old structure.
14+
115
## 1.6.0
216

317
- `BuildConfig.supportedAssetTypes` renamed to `BuildConfig.buildAssetTypes`.

pkgs/native_assets_cli/lib/src/model/hook.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ enum Hook {
1616

1717
String get scriptName => '$_scriptName.dart';
1818

19-
String get outputName => '${_scriptName}_output.json';
19+
@Deprecated('Use HookInput.outputFile instead.')
20+
String get outputNameDeprecated => '${_scriptName}_output.json';
2021
}

pkgs/native_assets_cli/lib/test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import 'dart:io';
99
import 'package:yaml/yaml.dart';
1010

1111
import 'native_assets_cli_builder.dart';
12-
import 'native_assets_cli_internal.dart' show Hook;
1312
import 'src/validation.dart';
1413

1514
export 'native_assets_cli_builder.dart';
@@ -41,6 +40,7 @@ Future<void> testBuildHook({
4140
Directory(await tempDir.resolveSymbolicLinks()).uri.normalizePath();
4241
final outputDirectory = tempUri.resolve('output/');
4342
final outputDirectoryShared = tempUri.resolve('output_shared/');
43+
final outputFile = tempUri.resolve('output.json');
4444

4545
await Directory.fromUri(outputDirectory).create();
4646
await Directory.fromUri(outputDirectoryShared).create();
@@ -50,6 +50,7 @@ Future<void> testBuildHook({
5050
..setupShared(
5151
packageRoot: Directory.current.uri,
5252
packageName: _readPackageNameFromPubspec(),
53+
outputFile: outputFile,
5354
outputDirectory: outputDirectory,
5455
outputDirectoryShared: outputDirectoryShared,
5556
)
@@ -61,11 +62,10 @@ Future<void> testBuildHook({
6162

6263
final input = BuildInput(inputBuilder.json);
6364

64-
final inputUri = tempUri.resolve(Hook.build.outputName);
65+
final inputUri = tempUri.resolve('input.json');
6566
_writeJsonTo(inputUri, input.json);
6667
await mainMethod(['--config=${inputUri.toFilePath()}']);
67-
final output = BuildOutput(
68-
_readJsonFrom(input.outputDirectory.resolve(Hook.build.outputName)));
68+
final output = BuildOutput(_readJsonFrom(input.outputFile));
6969

7070
// Test conformance of protocol invariants.
7171
final validationErrors = await validateBuildOutput(input, output);

0 commit comments

Comments
 (0)