@@ -319,6 +319,52 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
319319 }
320320 }
321321
322+ /// Loading the build description sometimes fails non-deterministically on Windows because it's unable to write
323+ /// `output-file-map.json`, probably due to https://github.com/swiftlang/swift-package-manager/issues/8038.
324+ /// If this happens, retry loading the build description up to `maxLoadAttempt` times.
325+ private func loadBuildDescriptionWithRetryOnOutputFileMapWriteErrorOnWindows(
326+ modulesGraph: ModulesGraph ,
327+ maxLoadAttempts: Int = 5
328+ ) async throws -> ( description: SourceKitLSPAPI . BuildDescription , errors: String ) {
329+ // TODO: Remove this workaround once https://github.com/swiftlang/swift-package-manager/issues/8038 is fixed.
330+ var loadAttempt = 0
331+ while true {
332+ loadAttempt += 1
333+ do {
334+ return try await BuildDescription . load (
335+ destinationBuildParameters: destinationBuildParameters,
336+ toolsBuildParameters: toolsBuildParameters,
337+ packageGraph: modulesGraph,
338+ pluginConfiguration: pluginConfiguration,
339+ traitConfiguration: traitConfiguration,
340+ disableSandbox: options. swiftPMOrDefault. disableSandbox ?? false ,
341+ scratchDirectory: swiftPMWorkspace. location. scratchDirectory. asURL,
342+ fileSystem: localFileSystem,
343+ observabilityScope: observabilitySystem. topScope. makeChildScope (
344+ description: " Create SwiftPM build description "
345+ )
346+ )
347+ } catch let error as NSError {
348+ #if os(Windows)
349+ if error. domain == NSCocoaErrorDomain, error. code == CocoaError . fileWriteNoPermission. rawValue,
350+ let url = error. userInfo [ " NSURL " ] as? URL , url. lastPathComponent == " output-file-map.json " ,
351+ loadAttempt < maxLoadAttempts
352+ {
353+ logger. log (
354+ """
355+ Loading the build description failed to write output-file-map.json \
356+ (attempt \( loadAttempt) / \( maxLoadAttempts) ), trying again.
357+ \( error)
358+ """
359+ )
360+ continue
361+ }
362+ #endif
363+ throw error
364+ }
365+ }
366+ }
367+
322368 /// (Re-)load the package settings by parsing the manifest and resolving all the targets and
323369 /// dependencies.
324370 ///
@@ -356,17 +402,7 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
356402 // plugins, without having to worry about messing up any regular build state.
357403 let buildDescription : SourceKitLSPAPI . BuildDescription
358404 if isForIndexBuild && !( options. swiftPMOrDefault. skipPlugins ?? false ) {
359- let loaded = try await BuildDescription . load (
360- destinationBuildParameters: destinationBuildParameters,
361- toolsBuildParameters: toolsBuildParameters,
362- packageGraph: modulesGraph,
363- pluginConfiguration: pluginConfiguration,
364- traitConfiguration: traitConfiguration,
365- disableSandbox: options. swiftPMOrDefault. disableSandbox ?? false ,
366- scratchDirectory: swiftPMWorkspace. location. scratchDirectory. asURL,
367- fileSystem: localFileSystem,
368- observabilityScope: observabilitySystem. topScope. makeChildScope ( description: " Create SwiftPM build description " )
369- )
405+ let loaded = try await loadBuildDescriptionWithRetryOnOutputFileMapWriteErrorOnWindows ( modulesGraph: modulesGraph)
370406 if !loaded. errors. isEmpty {
371407 logger. error ( " Loading SwiftPM description had errors: \( loaded. errors) " )
372408 }
0 commit comments