@@ -505,6 +505,25 @@ public final class ManifestLoader: ManifestLoaderProtocol {
505
505
)
506
506
}
507
507
508
+ /// Represents behavior that can be deferred until a more appropriate time.
509
+ internal struct DelayableAction < T> {
510
+ var target : T ?
511
+ var action : ( ( T ) -> Void ) ?
512
+
513
+ func perform( ) {
514
+ if let value = target, let cleanup = action {
515
+ cleanup ( value)
516
+ }
517
+ }
518
+
519
+ mutating func delay( ) -> DelayableAction {
520
+ let next = DelayableAction ( target: target, action: action)
521
+ target = nil
522
+ action = nil
523
+ return next
524
+ }
525
+ }
526
+
508
527
private func parseAndCacheManifest(
509
528
at path: AbsolutePath ,
510
529
packageIdentity: PackageIdentity ,
@@ -530,7 +549,8 @@ public final class ManifestLoader: ManifestLoaderProtocol {
530
549
}
531
550
532
551
// TODO: we could wrap the failure here with diagnostics if it wasn't optional throughout
533
- defer { try ? cache? . close ( ) }
552
+ var closeAfterRead = DelayableAction ( target: cache) { try ? $0. close ( ) }
553
+ defer { closeAfterRead. perform ( ) }
534
554
535
555
let key : CacheKey
536
556
do {
@@ -564,6 +584,9 @@ public final class ManifestLoader: ManifestLoaderProtocol {
564
584
return completion ( . failure( error) )
565
585
}
566
586
587
+ // delay closing cache until after write.
588
+ let closeAfterWrite = closeAfterRead. delay ( )
589
+
567
590
// shells out and compiles the manifest, finally output a JSON
568
591
self . evaluateManifest (
569
592
packageIdentity: key. packageIdentity,
@@ -573,6 +596,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
573
596
delegateQueue: delegateQueue
574
597
) { result in
575
598
do {
599
+ defer { closeAfterWrite. perform ( ) }
576
600
let evaluationResult = try result. get ( )
577
601
// only cache successfully parsed manifests
578
602
let parseManifest = try self . parseManifest (
@@ -818,6 +842,9 @@ public final class ManifestLoader: ManifestLoaderProtocol {
818
842
819
843
// Compile the manifest.
820
844
Process . popen ( arguments: cmd, environment: toolchain. swiftCompilerEnvironment) { result in
845
+ var cleanupIfError = DelayableAction ( target: tmpDir, action: cleanupTmpDir)
846
+ defer { cleanupIfError. perform ( ) }
847
+
821
848
let compilerResult : ProcessResult
822
849
do {
823
850
compilerResult = try result. get ( )
@@ -870,9 +897,10 @@ public final class ManifestLoader: ManifestLoaderProtocol {
870
897
let windowsPathComponent = runtimePath. pathString. replacingOccurrences ( of: " / " , with: " \\ " )
871
898
environment [ " Path " ] = " \( windowsPathComponent) ; \( environment [ " Path " ] ?? " " ) "
872
899
#endif
873
-
900
+
901
+ let cleanupAfterRunning = cleanupIfError. delay ( )
874
902
Process . popen ( arguments: cmd, environment: environment) { result in
875
- defer { cleanupTmpDir ( tmpDir ) }
903
+ defer { cleanupAfterRunning . perform ( ) }
876
904
fclose ( jsonOutputFileDesc)
877
905
878
906
do {
0 commit comments