@@ -341,6 +341,52 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
341
341
}
342
342
}
343
343
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
+
344
390
/// (Re-)load the package settings by parsing the manifest and resolving all the targets and
345
391
/// dependencies.
346
392
///
@@ -372,17 +418,7 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
372
418
// plugins, without having to worry about messing up any regular build state.
373
419
let buildDescription : SourceKitLSPAPI . BuildDescription
374
420
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)
386
422
if !loaded. errors. isEmpty {
387
423
logger. error ( " Loading SwiftPM description had errors: \( loaded. errors) " )
388
424
}
0 commit comments