@@ -51,11 +51,20 @@ class NativeAssetsBuildRunner {
51
51
rootPackageRoot: packageLayout.rootPackageRoot,
52
52
packagesWithNativeAssets: packagesWithNativeAssets,
53
53
dartExecutable: Uri .file (Platform .resolvedExecutable),
54
+ logger: logger,
54
55
);
55
- final plan = planner.plan ();
56
+ final (plan, planSuccess) = planner.plan ();
57
+ if (! planSuccess) {
58
+ return _BuildResultImpl (
59
+ assets: [],
60
+ dependencies: [],
61
+ success: false ,
62
+ );
63
+ }
56
64
final assets = < Asset > [];
57
65
final dependencies = < Uri > [];
58
66
final metadata = < String , Metadata > {};
67
+ var success = true ;
59
68
for (final package in plan) {
60
69
final dependencyMetadata = _metadataForPackage (
61
70
packageGraph: planner.packageGraph,
@@ -73,22 +82,28 @@ class NativeAssetsBuildRunner {
73
82
targetIOSSdk: targetIOSSdk,
74
83
targetAndroidNdkApi: targetAndroidNdkApi,
75
84
);
76
- final (packageAssets, packageDependencies, packageMetadata) =
77
- await _buildPackageCached (
85
+ final (
86
+ packageAssets,
87
+ packageDependencies,
88
+ packageMetadata,
89
+ packageSuccess,
90
+ ) = await _buildPackageCached (
78
91
config,
79
92
packageLayout.packageConfigUri,
80
93
workingDirectory,
81
94
includeParentEnvironment,
82
95
);
83
96
assets.addAll (packageAssets);
84
97
dependencies.addAll (packageDependencies);
98
+ success & = packageSuccess;
85
99
if (packageMetadata != null ) {
86
100
metadata[config.packageName] = packageMetadata;
87
101
}
88
102
}
89
103
return _BuildResultImpl (
90
104
assets: assets,
91
105
dependencies: dependencies..sort (_uriCompare),
106
+ success: success,
92
107
);
93
108
}
94
109
@@ -112,9 +127,17 @@ class NativeAssetsBuildRunner {
112
127
rootPackageRoot: packageLayout.rootPackageRoot,
113
128
packagesWithNativeAssets: packagesWithNativeAssets,
114
129
dartExecutable: Uri .file (Platform .resolvedExecutable),
130
+ logger: logger,
115
131
);
116
- final plan = planner.plan ();
132
+ final (plan, planSuccess) = planner.plan ();
133
+ if (! planSuccess) {
134
+ return _DryRunResultImpl (
135
+ assets: [],
136
+ success: false ,
137
+ );
138
+ }
117
139
final assets = < Asset > [];
140
+ var success = true ;
118
141
for (final package in plan) {
119
142
final config = await _cliConfigDryRun (
120
143
packageName: package.name,
@@ -123,21 +146,23 @@ class NativeAssetsBuildRunner {
123
146
linkMode: linkModePreference,
124
147
buildParentDir: packageLayout.dartToolNativeAssetsBuilder,
125
148
);
126
- final (packageAssets, _, _) = await _buildPackage (
149
+ final (packageAssets, _, _, packageSuccess ) = await _buildPackage (
127
150
config,
128
151
packageLayout.packageConfigUri,
129
152
workingDirectory,
130
153
includeParentEnvironment,
131
154
dryRun: true ,
132
155
);
133
156
assets.addAll (packageAssets);
157
+ success & = packageSuccess;
134
158
}
135
159
return _DryRunResultImpl (
136
160
assets: assets,
161
+ success: success,
137
162
);
138
163
}
139
164
140
- Future <( List < Asset >, List < Uri >, Metadata ?) > _buildPackageCached (
165
+ Future <_PackageBuildRecord > _buildPackageCached (
141
166
BuildConfig config,
142
167
Uri packageConfigUri,
143
168
Uri workingDirectory,
@@ -163,7 +188,7 @@ class NativeAssetsBuildRunner {
163
188
final assets = buildOutput! .assets;
164
189
final dependencies = buildOutput.dependencies.dependencies;
165
190
final metadata = buildOutput.metadata;
166
- return (assets, dependencies, metadata);
191
+ return (assets, dependencies, metadata, true );
167
192
}
168
193
169
194
return await _buildPackage (
@@ -175,7 +200,7 @@ class NativeAssetsBuildRunner {
175
200
);
176
201
}
177
202
178
- Future <( List < Asset >, List < Uri >, Metadata ?) > _buildPackage (
203
+ Future <_PackageBuildRecord > _buildPackage (
179
204
BuildConfig config,
180
205
Uri packageConfigUri,
181
206
Uri workingDirectory,
@@ -193,25 +218,77 @@ class NativeAssetsBuildRunner {
193
218
// Ensure we'll never read outdated build results.
194
219
await buildOutputFile.delete ();
195
220
}
196
- await runProcess (
221
+ final arguments = [
222
+ '--packages=${packageConfigUri .toFilePath ()}' ,
223
+ buildDotDart.toFilePath (),
224
+ '--config=${configFile .toFilePath ()}' ,
225
+ ];
226
+ final result = await runProcess (
197
227
workingDirectory: workingDirectory,
198
228
executable: dartExecutable,
199
- arguments: [
200
- '--packages=${packageConfigUri .toFilePath ()}' ,
201
- buildDotDart.toFilePath (),
202
- '--config=${configFile .toFilePath ()}' ,
203
- ],
229
+ arguments: arguments,
204
230
logger: logger,
205
231
includeParentEnvironment: includeParentEnvironment,
206
- expectedExitCode: 0 ,
207
- throwOnUnexpectedExitCode: true ,
208
232
);
209
- final buildOutput = await BuildOutput .readFromFile (outDir: outDir);
210
- final assets = buildOutput? .assets ?? [];
211
- validateAssetsPackage (assets, config.packageName);
212
- final dependencies = buildOutput? .dependencies.dependencies ?? [];
213
- final metadata = dryRun ? null : buildOutput? .metadata;
214
- return (assets, dependencies, metadata);
233
+ var success = true ;
234
+ if (result.exitCode != 0 ) {
235
+ final printWorkingDir = workingDirectory != Directory .current.uri;
236
+ final commandString = [
237
+ if (printWorkingDir) '(cd ${workingDirectory .toFilePath ()};' ,
238
+ dartExecutable.toFilePath (),
239
+ ...arguments.map ((a) => a.contains (' ' ) ? "'$a '" : a),
240
+ if (printWorkingDir) ')' ,
241
+ ].join (' ' );
242
+ logger.severe (
243
+ '''
244
+ Building native assets for package:${config .packageName } failed.
245
+ build.dart returned with exit code: ${result .exitCode }.
246
+ To reproduce run:
247
+ $commandString
248
+ stderr:
249
+ ${result .stderr }
250
+ stdout:
251
+ ${result .stdout }
252
+ ''' ,
253
+ );
254
+ success = false ;
255
+ }
256
+
257
+ try {
258
+ final buildOutput = await BuildOutput .readFromFile (outDir: outDir);
259
+ final assets = buildOutput? .assets ?? [];
260
+ success & = validateAssetsPackage (assets, config.packageName);
261
+ final dependencies = buildOutput? .dependencies.dependencies ?? [];
262
+ final metadata = dryRun ? null : buildOutput? .metadata;
263
+ return (assets, dependencies, metadata, success);
264
+ } on FormatException catch (e) {
265
+ logger.severe ('''
266
+ Building native assets for package:${config .packageName } failed.
267
+ build_output.yaml contained a format error.
268
+ ${e .message }
269
+ ''' );
270
+ success = false ;
271
+ return (< Asset > [], < Uri > [], Metadata ({}), false );
272
+ // TODO(https://github.com/dart-lang/native/issues/109): Stop throwing
273
+ // type errors in native_assets_cli, release a new version of that package
274
+ // and then remove this.
275
+ // ignore: avoid_catching_errors
276
+ } on TypeError {
277
+ logger.severe ('''
278
+ Building native assets for package:${config .packageName } failed.
279
+ build_output.yaml contained a format error.
280
+ ''' );
281
+ success = false ;
282
+ return (< Asset > [], < Uri > [], Metadata ({}), false );
283
+ } finally {
284
+ if (! success) {
285
+ final buildOutputFile =
286
+ File .fromUri (outDir.resolve (BuildOutput .fileName));
287
+ if (await buildOutputFile.exists ()) {
288
+ await buildOutputFile.delete ();
289
+ }
290
+ }
291
+ }
215
292
}
216
293
217
294
static Future <BuildConfig > _cliConfig ({
@@ -292,33 +369,53 @@ class NativeAssetsBuildRunner {
292
369
};
293
370
}
294
371
295
- void validateAssetsPackage (List <Asset > assets, String packageName) {
372
+ bool validateAssetsPackage (List <Asset > assets, String packageName) {
296
373
final invalidAssetIds = assets
297
374
.map ((a) => a.name)
298
375
.where ((n) => ! n.startsWith ('package:$packageName /' ))
299
376
.toSet ()
300
377
.toList ()
301
378
..sort ();
302
- if (invalidAssetIds.isNotEmpty) {
303
- throw FormatException (
379
+ final success = invalidAssetIds.isEmpty;
380
+ if (! success) {
381
+ logger.severe (
304
382
'`package:$packageName ` declares the following assets which do not '
305
383
'start with `package:$packageName /`: ${invalidAssetIds .join (', ' )}.' ,
306
384
);
307
385
}
386
+ return success;
308
387
}
309
388
}
310
389
390
+ typedef _PackageBuildRecord = (
391
+ List <Asset >,
392
+ List <Uri > dependencies,
393
+ Metadata ? ,
394
+ bool success,
395
+ );
396
+
311
397
/// The result from a [NativeAssetsBuildRunner.dryRun] .
312
398
abstract interface class DryRunResult {
313
399
/// The native assets for all [Target] s for the build or dry run.
314
400
List <Asset > get assets;
401
+
402
+ /// Whether all builds completed without errors.
403
+ ///
404
+ /// All error messages are streamed to [NativeAssetsBuildRunner.logger] .
405
+ bool get success;
315
406
}
316
407
317
408
final class _DryRunResultImpl implements DryRunResult {
318
409
@override
319
410
final List <Asset > assets;
320
411
321
- _DryRunResultImpl ({required this .assets});
412
+ @override
413
+ final bool success;
414
+
415
+ _DryRunResultImpl ({
416
+ required this .assets,
417
+ required this .success,
418
+ });
322
419
}
323
420
324
421
/// The result from a [NativeAssetsBuildRunner.build] .
@@ -339,9 +436,13 @@ final class _BuildResultImpl implements BuildResult {
339
436
@override
340
437
final List <Uri > dependencies;
341
438
439
+ @override
440
+ final bool success;
441
+
342
442
_BuildResultImpl ({
343
443
required this .assets,
344
444
required this .dependencies,
445
+ required this .success,
345
446
});
346
447
}
347
448
0 commit comments