@@ -155,7 +155,7 @@ extension Workspace {
155
155
if !indexFiles. isEmpty {
156
156
let errors = ThreadSafeArrayStore < Error > ( )
157
157
158
- zipArtifacts. append ( contentsOf: try await withThrowingTaskGroup (
158
+ try await zipArtifacts. append ( contentsOf: withThrowingTaskGroup (
159
159
of: RemoteArtifact ? . self,
160
160
returning: [ RemoteArtifact ] . self
161
161
) { group in
@@ -164,7 +164,8 @@ extension Workspace {
164
164
group. addTask {
165
165
var request = HTTPClient . Request ( method: . get, url: indexFile. url)
166
166
request. options. validResponseCodes = [ 200 ]
167
- request. options. authorizationProvider = self . authorizationProvider? . httpAuthorizationHeader ( for: )
167
+ request. options. authorizationProvider = self . authorizationProvider?
168
+ . httpAuthorizationHeader ( for: )
168
169
do {
169
170
let response = try await self . httpClient. execute ( request)
170
171
guard let body = response. body else {
@@ -227,7 +228,10 @@ extension Workspace {
227
228
group. addTask { ( ) -> ManagedArtifact ? in
228
229
let destinationDirectory = artifactsDirectory
229
230
. appending ( components: [ artifact. packageRef. identity. description, artifact. targetName] )
230
- guard observabilityScope. trap ( { try fileSystem. createDirectory ( destinationDirectory, recursive: true ) } )
231
+ guard observabilityScope. trap ( { try fileSystem. createDirectory (
232
+ destinationDirectory,
233
+ recursive: true
234
+ ) } )
231
235
else {
232
236
return nil
233
237
}
@@ -295,7 +299,8 @@ extension Workspace {
295
299
return nil
296
300
}
297
301
298
- observabilityScope. emit ( debug: " extracting \( archivePath) to \( tempExtractionDirectory) " )
302
+ observabilityScope
303
+ . emit ( debug: " extracting \( archivePath) to \( tempExtractionDirectory) " )
299
304
do {
300
305
try await self . archiver. extract (
301
306
from: archivePath,
@@ -326,7 +331,8 @@ extension Workspace {
326
331
debug: " no first level component stripping needed for \( tempExtractionDirectory) "
327
332
)
328
333
}
329
- let content = try self . fileSystem. getDirectoryContents ( tempExtractionDirectory)
334
+ let content = try self . fileSystem
335
+ . getDirectoryContents ( tempExtractionDirectory)
330
336
// copy from temp location to actual location
331
337
for file in content {
332
338
let source = tempExtractionDirectory
@@ -350,8 +356,8 @@ extension Workspace {
350
356
observabilityScope: observabilityScope
351
357
) else {
352
358
observabilityScope. emit ( BinaryArtifactsManagerError . remoteArtifactNotFound (
353
- artifactURL: artifact. url,
354
- targetName: artifact. targetName
359
+ artifactURL: artifact. url,
360
+ targetName: artifact. targetName
355
361
) )
356
362
return nil
357
363
}
@@ -432,7 +438,7 @@ extension Workspace {
432
438
artifactsDirectory: AbsolutePath ,
433
439
observabilityScope: ObservabilityScope
434
440
) async throws -> [ ManagedArtifact ] {
435
- return try await withThrowingTaskGroup ( of: ManagedArtifact ? . self) { group in
441
+ try await withThrowingTaskGroup ( of: ManagedArtifact ? . self) { group in
436
442
for artifact in artifacts {
437
443
group. addTask { ( ) -> ManagedArtifact ? in
438
444
let destinationDirectory = artifactsDirectory
@@ -458,7 +464,9 @@ extension Workspace {
458
464
acceptableExtensions: BinaryModule . Kind. allCases. map ( \. fileExtension)
459
465
) {
460
466
observabilityScope
461
- . emit ( debug: " stripping first level component from \( tempExtractionDirectory) " )
467
+ . emit (
468
+ debug: " stripping first level component from \( tempExtractionDirectory) "
469
+ )
462
470
try self . fileSystem. stripFirstLevel ( of: tempExtractionDirectory)
463
471
} else {
464
472
observabilityScope. emit (
@@ -564,7 +572,7 @@ extension Workspace {
564
572
artifact: RemoteArtifact ,
565
573
destination: AbsolutePath ,
566
574
observabilityScope: ObservabilityScope ,
567
- progress: @escaping @Sendable ( Int64 , Optional < Int64 > ) -> Void
575
+ progress: @escaping @Sendable ( Int64 , Int64 ? ) -> Void
568
576
) async throws -> Bool {
569
577
// not using cache, download directly
570
578
guard let cachePath = self . cachePath else {
@@ -591,7 +599,8 @@ extension Workspace {
591
599
let cachedArtifactPath = cachePath. appending ( cacheKey)
592
600
593
601
if self . fileSystem. exists ( cachedArtifactPath) {
594
- observabilityScope. emit ( debug: " copying cached binary artifact for \( artifact. url) from \( cachedArtifactPath) " )
602
+ observabilityScope
603
+ . emit ( debug: " copying cached binary artifact for \( artifact. url) from \( cachedArtifactPath) " )
595
604
self . delegate? . willDownloadBinaryArtifact ( from: artifact. url. absoluteString, fromCache: true )
596
605
597
606
// copy from cache to destination
@@ -600,7 +609,8 @@ extension Workspace {
600
609
}
601
610
602
611
// download to the cache
603
- observabilityScope. emit ( debug: " downloading binary artifact for \( artifact. url) to cache at \( cachedArtifactPath) " )
612
+ observabilityScope
613
+ . emit ( debug: " downloading binary artifact for \( artifact. url) to cache at \( cachedArtifactPath) " )
604
614
605
615
self . delegate? . willDownloadBinaryArtifact ( from: artifact. url. absoluteString, fromCache: false )
606
616
@@ -623,7 +633,7 @@ extension Workspace {
623
633
artifact: RemoteArtifact ,
624
634
destination: AbsolutePath ,
625
635
observabilityScope: ObservabilityScope ,
626
- progress: @escaping @Sendable ( Int64 , Optional < Int64 > ) -> Void
636
+ progress: @escaping @Sendable ( Int64 , Int64 ? ) -> Void
627
637
) async throws {
628
638
observabilityScope. emit ( debug: " downloading \( artifact. url) to \( destination) " )
629
639
@@ -800,6 +810,26 @@ extension Workspace {
800
810
manifests: DependencyManifests ,
801
811
addedOrUpdatedPackages: [ PackageReference ] ,
802
812
observabilityScope: ObservabilityScope
813
+ ) async throws {
814
+ try await withAsyncThrowing {
815
+ try await self . _updateBinaryArtifacts (
816
+ manifests: manifests,
817
+ addedOrUpdatedPackages: addedOrUpdatedPackages,
818
+ observabilityScope: observabilityScope
819
+ )
820
+ } defer: {
821
+ // Make sure the workspace state is saved exactly once, even if the method exits early.
822
+ // Files may have been deleted, download, etc. and the state needs to reflect that.
823
+ await observabilityScope. trap {
824
+ try await self . state. save ( )
825
+ }
826
+ }
827
+ }
828
+
829
+ private func _updateBinaryArtifacts(
830
+ manifests: DependencyManifests ,
831
+ addedOrUpdatedPackages: [ PackageReference ] ,
832
+ observabilityScope: ObservabilityScope
803
833
) async throws {
804
834
let manifestArtifacts = try self . binaryArtifactsManager. parseArtifacts (
805
835
from: manifests,
@@ -893,7 +923,10 @@ extension Workspace {
893
923
// Remove the artifacts and directories which are not needed anymore.
894
924
await observabilityScope. trap {
895
925
for artifact in artifactsToRemove {
896
- await state. artifacts. remove ( packageIdentity: artifact. packageRef. identity, targetName: artifact. targetName)
926
+ await state. artifacts. remove (
927
+ packageIdentity: artifact. packageRef. identity,
928
+ targetName: artifact. targetName
929
+ )
897
930
898
931
if isAtArtifactsDirectory ( artifact) {
899
932
try fileSystem. removeFileTree ( artifact. path)
@@ -937,10 +970,6 @@ extension Workspace {
937
970
throw Diagnostics . fatalError
938
971
}
939
972
940
- await observabilityScope. trap {
941
- try await self . state. save ( )
942
- }
943
-
944
973
func isAtArtifactsDirectory( _ artifact: ManagedArtifact ) -> Bool {
945
974
artifact. path. isDescendant ( of: self . location. artifactsDirectory)
946
975
}
0 commit comments