@@ -341,6 +341,52 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
341341 }
342342 }
343343
344+ /// Loading the build description sometimes fails non-deterministically on Windows because it's unable to write
345+ /// `output-file-map.json`, probably due to https://github.com/swiftlang/swift-package-manager/issues/8038.
346+ /// If this happens, retry loading the build description up to `maxLoadAttempt` times.
347+ private func loadBuildDescriptionWithRetryOnOutputFileMapWriteErrorOnWindows(
348+ modulesGraph: ModulesGraph ,
349+ maxLoadAttempts: Int = 5
350+ ) async throws -> ( description: SourceKitLSPAPI . BuildDescription , errors: String ) {
351+ // TODO: Remove this workaround once https://github.com/swiftlang/swift-package-manager/issues/8038 is fixed.
352+ var loadAttempt = 0
353+ while true {
354+ loadAttempt += 1
355+ do {
356+ return try await BuildDescription . load (
357+ destinationBuildParameters: destinationBuildParameters,
358+ toolsBuildParameters: toolsBuildParameters,
359+ packageGraph: modulesGraph,
360+ pluginConfiguration: pluginConfiguration,
361+ traitConfiguration: traitConfiguration,
362+ disableSandbox: options. swiftPMOrDefault. disableSandbox ?? false ,
363+ scratchDirectory: swiftPMWorkspace. location. scratchDirectory. asURL,
364+ fileSystem: localFileSystem,
365+ observabilityScope: observabilitySystem. topScope. makeChildScope (
366+ description: " Create SwiftPM build description "
367+ )
368+ )
369+ } catch let error as NSError {
370+ #if os(Windows)
371+ if error. domain == NSCocoaErrorDomain, error. code == CocoaError . fileWriteNoPermission. rawValue,
372+ let url = error. userInfo [ " NSURL " ] as? URL , url. lastPathComponent == " output-file-map.json " ,
373+ loadAttempt < maxLoadAttempts
374+ {
375+ logger. log (
376+ """
377+ Loading the build description failed to write output-file-map.json \
378+ (attempt \( loadAttempt) / \( maxLoadAttempts) ), trying again.
379+ \( error)
380+ """
381+ )
382+ continue
383+ }
384+ #endif
385+ throw error
386+ }
387+ }
388+ }
389+
344390 /// (Re-)load the package settings by parsing the manifest and resolving all the targets and
345391 /// dependencies.
346392 ///
@@ -372,17 +418,7 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
372418 // plugins, without having to worry about messing up any regular build state.
373419 let buildDescription : SourceKitLSPAPI . BuildDescription
374420 if isForIndexBuild && !( options. swiftPMOrDefault. skipPlugins ?? false ) {
375- let loaded = try await BuildDescription . load (
376- destinationBuildParameters: destinationBuildParameters,
377- toolsBuildParameters: toolsBuildParameters,
378- packageGraph: modulesGraph,
379- pluginConfiguration: pluginConfiguration,
380- traitConfiguration: traitConfiguration,
381- disableSandbox: options. swiftPMOrDefault. disableSandbox ?? false ,
382- scratchDirectory: swiftPMWorkspace. location. scratchDirectory. asURL,
383- fileSystem: localFileSystem,
384- observabilityScope: observabilitySystem. topScope. makeChildScope ( description: " Create SwiftPM build description " )
385- )
421+ let loaded = try await loadBuildDescriptionWithRetryOnOutputFileMapWriteErrorOnWindows ( modulesGraph: modulesGraph)
386422 if !loaded. errors. isEmpty {
387423 logger. error ( " Loading SwiftPM description had errors: \( loaded. errors) " )
388424 }
0 commit comments