@@ -83,7 +83,7 @@ public final class TibsTestWorkspace {
83
83
let fm = FileManager . default
84
84
_ = try ? fm. removeItem ( at: tmpDir)
85
85
86
- try fm. createDirectory ( at: persistentBuildDir, withIntermediateDirectories : true , attributes : nil )
86
+ try fm. tibs_createDirectoryWithIntermediates ( at: persistentBuildDir)
87
87
let databaseDir = tmpDir
88
88
89
89
self . sources = try TestSources ( rootDirectory: projectDir)
@@ -128,7 +128,7 @@ public final class TibsTestWorkspace {
128
128
_ = try ? fm. removeItem ( at: tmpDir)
129
129
130
130
let buildDir = tmpDir. appendingPathComponent ( " build " , isDirectory: true )
131
- try fm. createDirectory ( at: buildDir, withIntermediateDirectories : true , attributes : nil )
131
+ try fm. tibs_createDirectoryWithIntermediates ( at: buildDir)
132
132
let sourceDir = tmpDir. appendingPathComponent ( " src " , isDirectory: true )
133
133
try fm. copyItem ( at: projectDir, to: sourceDir)
134
134
let databaseDir = tmpDir. appendingPathComponent ( " db " , isDirectory: true )
@@ -287,3 +287,33 @@ extension XCTestCase {
287
287
return " \( className) . \( methodName) "
288
288
}
289
289
}
290
+
291
+ extension FileManager {
292
+
293
+ /// Wrapper for Foundation.createDirectory that works around a spurious EEXIST
294
+ /// if we race to create.
295
+ public func tibs_createDirectoryWithIntermediates( at url: URL ) throws
296
+ {
297
+ #if os(macOS)
298
+ try self . createDirectory ( at: url, withIntermediateDirectories: true , attributes: nil )
299
+ #else
300
+ var i = 0
301
+ let maxRetries = 3
302
+
303
+ while true {
304
+ do {
305
+ try self . createDirectory ( at: url, withIntermediateDirectories: true , attributes: nil )
306
+ return
307
+ } catch let error as NSError where error. code == CocoaError . fileWriteFileExists. rawValue {
308
+ // May be spurious if we raced.
309
+ i += 1
310
+ if i < maxRetries {
311
+ continue
312
+ } else {
313
+ throw error
314
+ }
315
+ }
316
+ }
317
+ #endif
318
+ }
319
+ }
0 commit comments