@@ -94,48 +94,51 @@ public func testWithTemporaryDirectory(
9494 try ? localFileSystem. removeFileTree ( tmpDirPath)
9595 }
9696
97- // Construct the expected path of the fixture.
98- // FIXME: This seems quite hacky; we should provide some control over where fixtures are found.
99- let fixtureDir = AbsolutePath ( " ../../../Fixtures " , relativeTo: #file)
100- . appending ( fixtureSubpath)
101-
102- // Check that the fixture is really there.
103- guard localFileSystem. isDirectory ( fixtureDir) else {
104- XCTFail ( " No such fixture: \( fixtureDir) " , file: file, line: line)
105- throw SwiftPMError . packagePathNotFound
106- }
107-
108- // The fixture contains either a checkout or just a Git directory.
109- if localFileSystem. isFile ( fixtureDir. appending ( " Package.swift " ) ) {
110- // It's a single package, so copy the whole directory as-is.
111- let dstDir = tmpDirPath. appending ( component: copyName)
112- #if os(Windows)
113- try localFileSystem. copy ( from: fixtureDir, to: dstDir)
114- #else
115- try systemQuietly ( " cp " , " -R " , " -H " , fixtureDir. pathString, dstDir. pathString)
116- #endif
97+ let fixtureDir = try verifyFixtureExists ( at: fixtureSubpath, file: file, line: line)
98+ let preparedFixture = try setup (
99+ fixtureDir: fixtureDir,
100+ in: tmpDirPath,
101+ copyName: copyName,
102+ createGitRepo: createGitRepo
103+ )
104+ return try body ( preparedFixture)
105+ }
106+ } catch SwiftPMError . executionFailure( let error, let output, let stderr) {
107+ print ( " **** FAILURE EXECUTING SUBPROCESS **** " )
108+ print ( " output: " , output)
109+ print ( " stderr: " , stderr)
110+ throw error
111+ }
112+ }
113+ @discardableResult public func fixture< T> (
114+ name: String ,
115+ createGitRepo: Bool = true ,
116+ file: StaticString = #file,
117+ line: UInt = #line,
118+ body: ( AbsolutePath ) async throws -> T
119+ ) async throws -> T {
120+ do {
121+ // Make a suitable test directory name from the fixture subpath.
122+ let fixtureSubpath = try RelativePath ( validating: name)
123+ let copyName = fixtureSubpath. components. joined ( separator: " _ " )
117124
118- // Invoke the block, passing it the path of the copied fixture.
119- return try body ( dstDir)
120- } else {
121- // Copy each of the package directories and construct a git repo in it.
122- for fileName in try localFileSystem. getDirectoryContents ( fixtureDir) . sorted ( ) {
123- let srcDir = fixtureDir. appending ( component: fileName)
124- guard localFileSystem. isDirectory ( srcDir) else { continue }
125- let dstDir = tmpDirPath. appending ( component: fileName)
126- #if os(Windows)
127- try localFileSystem. copy ( from: srcDir, to: dstDir)
128- #else
129- try systemQuietly ( " cp " , " -R " , " -H " , srcDir. pathString, dstDir. pathString)
130- #endif
131- if createGitRepo {
132- initGitRepo ( dstDir, tag: " 1.2.3 " , addFile: false )
133- }
134- }
125+ // Create a temporary directory for the duration of the block.
126+ return try await withTemporaryDirectory ( prefix: copyName) { tmpDirPath in
135127
136- // Invoke the block, passing it the path of the copied fixture.
137- return try body ( tmpDirPath)
128+ defer {
129+ // Unblock and remove the tmp dir on deinit.
130+ try ? localFileSystem. chmod ( . userWritable, path: tmpDirPath, options: [ . recursive] )
131+ try ? localFileSystem. removeFileTree ( tmpDirPath)
138132 }
133+
134+ let fixtureDir = try verifyFixtureExists ( at: fixtureSubpath, file: file, line: line)
135+ let preparedFixture = try setup (
136+ fixtureDir: fixtureDir,
137+ in: tmpDirPath,
138+ copyName: copyName,
139+ createGitRepo: createGitRepo
140+ )
141+ return try await body ( preparedFixture)
139142 }
140143 } catch SwiftPMError . executionFailure( let error, let output, let stderr) {
141144 print ( " **** FAILURE EXECUTING SUBPROCESS **** " )
@@ -145,6 +148,51 @@ public func testWithTemporaryDirectory(
145148 }
146149}
147150
151+ fileprivate func verifyFixtureExists( at fixtureSubpath: RelativePath , file: StaticString = #file, line: UInt = #line) throws -> AbsolutePath {
152+ let fixtureDir = AbsolutePath ( " ../../../Fixtures " , relativeTo: #file)
153+ . appending ( fixtureSubpath)
154+
155+ // Check that the fixture is really there.
156+ guard localFileSystem. isDirectory ( fixtureDir) else {
157+ XCTFail ( " No such fixture: \( fixtureDir) " , file: file, line: line)
158+ throw SwiftPMError . packagePathNotFound
159+ }
160+
161+ return fixtureDir
162+ }
163+
164+ fileprivate func setup( fixtureDir: AbsolutePath , in tmpDirPath: AbsolutePath , copyName: String , createGitRepo: Bool = true ) throws -> AbsolutePath {
165+
166+ func copy( from srcDir: AbsolutePath , to dstDir: AbsolutePath ) throws {
167+ #if os(Windows)
168+ try localFileSystem. copy ( from: srcDir, to: dstDir)
169+ #else
170+ try systemQuietly ( " cp " , " -R " , " -H " , srcDir. pathString, dstDir. pathString)
171+ #endif
172+ }
173+
174+ // The fixture contains either a checkout or just a Git directory.
175+ if localFileSystem. isFile ( fixtureDir. appending ( " Package.swift " ) ) {
176+ // It's a single package, so copy the whole directory as-is.
177+ let dstDir = tmpDirPath. appending ( component: copyName)
178+ try copy ( from: fixtureDir, to: dstDir)
179+ // Invoke the block, passing it the path of the copied fixture.
180+ return dstDir
181+ }
182+ // Copy each of the package directories and construct a git repo in it.
183+ for fileName in try localFileSystem. getDirectoryContents ( fixtureDir) . sorted ( ) {
184+ let srcDir = fixtureDir. appending ( component: fileName)
185+ guard localFileSystem. isDirectory ( srcDir) else { continue }
186+ let dstDir = tmpDirPath. appending ( component: fileName)
187+
188+ try copy ( from: srcDir, to: dstDir)
189+ if createGitRepo {
190+ initGitRepo ( dstDir, tag: " 1.2.3 " , addFile: false )
191+ }
192+ }
193+ return tmpDirPath
194+ }
195+
148196/// Test-helper function that creates a new Git repository in a directory. The new repository will contain
149197/// exactly one empty file unless `addFile` is `false`, and if a tag name is provided, a tag with that name will be
150198/// created.
0 commit comments