@@ -6,6 +6,7 @@ import 'dart:async';
6
6
import 'dart:io' ;
7
7
8
8
import 'package:logging/logging.dart' ;
9
+ import 'package:native_assets_cli/locking.dart' ;
9
10
import 'package:native_assets_cli/native_assets_cli.dart' as api;
10
11
import 'package:native_assets_cli/native_assets_cli_internal.dart' ;
11
12
import 'package:package_config/package_config.dart' ;
@@ -34,11 +35,13 @@ typedef DependencyMetadata = Map<String, Metadata>;
34
35
class NativeAssetsBuildRunner {
35
36
final Logger logger;
36
37
final Uri dartExecutable;
38
+ final Duration singleHookTimeout;
37
39
38
40
NativeAssetsBuildRunner ({
39
41
required this .logger,
40
42
required this .dartExecutable,
41
- });
43
+ Duration ? singleHookTimeout,
44
+ }) : singleHookTimeout = singleHookTimeout ?? const Duration (minutes: 5 );
42
45
43
46
/// [workingDirectory] is expected to contain `.dart_tool` .
44
47
///
@@ -413,14 +416,19 @@ class NativeAssetsBuildRunner {
413
416
continue ;
414
417
}
415
418
// TODO(https://github.com/dart-lang/native/issues/1321): Should dry runs be cached?
416
- var (buildOutput, packageSuccess) = await _runHookForPackage (
417
- hook,
418
- config,
419
- packageConfigUri,
420
- workingDirectory,
421
- includeParentEnvironment,
422
- null ,
423
- hookKernelFile,
419
+ var (buildOutput, packageSuccess) = await runUnderDirectoryLock (
420
+ Directory .fromUri (config.outputDirectory.parent),
421
+ timeout: singleHookTimeout,
422
+ logger: logger,
423
+ () => _runHookForPackage (
424
+ hook,
425
+ config,
426
+ packageConfigUri,
427
+ workingDirectory,
428
+ includeParentEnvironment,
429
+ null ,
430
+ hookKernelFile,
431
+ ),
424
432
);
425
433
buildOutput = _expandArchsNativeCodeAssets (buildOutput);
426
434
hookResult = hookResult.copyAdd (buildOutput, packageSuccess);
@@ -460,47 +468,54 @@ class NativeAssetsBuildRunner {
460
468
Uri ? resources,
461
469
) async {
462
470
final outDir = config.outputDirectory;
463
- final (
464
- compileSuccess,
465
- hookKernelFile,
466
- hookLastSourceChange,
467
- ) = await _compileHookForPackageCached (
468
- config,
469
- packageConfigUri,
470
- workingDirectory,
471
- includeParentEnvironment,
472
- );
473
- if (! compileSuccess) {
474
- return (HookOutputImpl (), false );
475
- }
476
-
477
- final hookOutput = HookOutputImpl .readFromFile (file: config.outputFile);
478
- if (hookOutput != null ) {
479
- final lastBuilt = hookOutput.timestamp.roundDownToSeconds ();
480
- final dependenciesLastChange =
481
- await hookOutput.dependenciesModel.lastModified ();
482
- if (lastBuilt.isAfter (dependenciesLastChange) &&
483
- lastBuilt.isAfter (hookLastSourceChange)) {
484
- logger.info (
485
- 'Skipping ${hook .name } for ${config .packageName } in $outDir . '
486
- 'Last build on $lastBuilt . '
487
- 'Last dependencies change on $dependenciesLastChange . '
488
- 'Last hook change on $hookLastSourceChange .' ,
471
+ return await runUnderDirectoryLock (
472
+ Directory .fromUri (config.outputDirectory.parent),
473
+ timeout: singleHookTimeout,
474
+ logger: logger,
475
+ () async {
476
+ final (
477
+ compileSuccess,
478
+ hookKernelFile,
479
+ hookLastSourceChange,
480
+ ) = await _compileHookForPackageCached (
481
+ config,
482
+ packageConfigUri,
483
+ workingDirectory,
484
+ includeParentEnvironment,
489
485
);
490
- // All build flags go into [outDir]. Therefore we do not have to check
491
- // here whether the config is equal.
492
- return (hookOutput, true );
493
- }
494
- }
486
+ if (! compileSuccess) {
487
+ return (HookOutputImpl (), false );
488
+ }
489
+
490
+ final hookOutput = HookOutputImpl .readFromFile (file: config.outputFile);
491
+ if (hookOutput != null ) {
492
+ final lastBuilt = hookOutput.timestamp.roundDownToSeconds ();
493
+ final dependenciesLastChange =
494
+ await hookOutput.dependenciesModel.lastModified ();
495
+ if (lastBuilt.isAfter (dependenciesLastChange) &&
496
+ lastBuilt.isAfter (hookLastSourceChange)) {
497
+ logger.info (
498
+ 'Skipping ${hook .name } for ${config .packageName } in $outDir . '
499
+ 'Last build on $lastBuilt . '
500
+ 'Last dependencies change on $dependenciesLastChange . '
501
+ 'Last hook change on $hookLastSourceChange .' ,
502
+ );
503
+ // All build flags go into [outDir]. Therefore we do not have to
504
+ // check here whether the config is equal.
505
+ return (hookOutput, true );
506
+ }
507
+ }
495
508
496
- return await _runHookForPackage (
497
- hook,
498
- config,
499
- packageConfigUri,
500
- workingDirectory,
501
- includeParentEnvironment,
502
- resources,
503
- hookKernelFile,
509
+ return await _runHookForPackage (
510
+ hook,
511
+ config,
512
+ packageConfigUri,
513
+ workingDirectory,
514
+ includeParentEnvironment,
515
+ resources,
516
+ hookKernelFile,
517
+ );
518
+ },
504
519
);
505
520
}
506
521
@@ -849,3 +864,7 @@ extension on DateTime {
849
864
DateTime .fromMillisecondsSinceEpoch (millisecondsSinceEpoch -
850
865
millisecondsSinceEpoch % const Duration (seconds: 1 ).inMilliseconds);
851
866
}
867
+
868
+ extension on Uri {
869
+ Uri get parent => File (toFilePath ()).parent.uri;
870
+ }
0 commit comments