Skip to content

Commit 956742d

Browse files
authored
Merge pull request #2049 from ahoppen/cancellation-custom-build-server
Support cancellation in `CustomBuildServer`
2 parents a1ca0d3 + 6414796 commit 956742d

File tree

5 files changed

+63
-2
lines changed

5 files changed

+63
-2
lines changed

Sources/SKTestSupport/CustomBuildServerTestProject.swift

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,59 @@ import XCTest
2424

2525
// MARK: - CustomBuildServer
2626

27+
package actor CustomBuildServerInProgressRequestTracker {
28+
private var inProgressRequests: [RequestID: Task<Void, Never>] = [:]
29+
private let queue = AsyncQueue<Serial>()
30+
31+
package init() {}
32+
33+
private func setInProgressRequestImpl(_ id: RequestID, task: Task<Void, Never>) {
34+
guard inProgressRequests[id] == nil else {
35+
logger.fault("Received duplicate request for id: \(id, privacy: .public)")
36+
return
37+
}
38+
inProgressRequests[id] = task
39+
}
40+
41+
fileprivate nonisolated func setInProgressRequest(_ id: RequestID, task: Task<Void, Never>) {
42+
queue.async {
43+
await self.setInProgressRequestImpl(id, task: task)
44+
}
45+
}
46+
47+
private func markTaskAsFinishedImpl(_ id: RequestID) {
48+
guard inProgressRequests[id] != nil else {
49+
logger.fault("Cannot mark request \(id, privacy: .public) as finished because it is not being tracked.")
50+
return
51+
}
52+
inProgressRequests[id] = nil
53+
}
54+
55+
fileprivate nonisolated func markTaskAsFinished(_ id: RequestID) {
56+
queue.async {
57+
await self.markTaskAsFinishedImpl(id)
58+
}
59+
}
60+
61+
private func cancelTaskImpl(_ id: RequestID) {
62+
guard let task = inProgressRequests[id] else {
63+
logger.fault("Cannot cancel task \(id, privacy: .public) because it isn't tracked")
64+
return
65+
}
66+
task.cancel()
67+
}
68+
69+
fileprivate nonisolated func cancelTask(_ id: RequestID) {
70+
queue.async {
71+
await self.cancelTaskImpl(id)
72+
}
73+
}
74+
}
75+
2776
/// A build server that can be injected into `CustomBuildServerTestProject`.
2877
package protocol CustomBuildServer: MessageHandler {
78+
var inProgressRequestsTracker: CustomBuildServerInProgressRequestTracker { get }
79+
2980
init(projectRoot: URL, connectionToSourceKitLSP: any Connection)
3081

3182
func initializeBuildRequest(_ request: InitializeBuildRequest) async throws -> InitializeBuildResponse
@@ -74,13 +125,15 @@ extension CustomBuildServer {
74125
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
75126
) {
76127
func handle<R: RequestType>(_ request: R, using handler: @Sendable @escaping (R) async throws -> R.Response) {
77-
Task {
128+
let task = Task {
129+
defer { inProgressRequestsTracker.markTaskAsFinished(id) }
78130
do {
79131
reply(.success(try await handler(request) as! Request.Response))
80132
} catch {
81133
reply(.failure(ResponseError(error)))
82134
}
83135
}
136+
inProgressRequestsTracker.setInProgressRequest(id, task: task)
84137
}
85138

86139
switch request {
@@ -174,7 +227,9 @@ package extension CustomBuildServer {
174227
return VoidResponse()
175228
}
176229

177-
nonisolated func cancelRequest(_ notification: CancelRequestNotification) throws {}
230+
nonisolated func cancelRequest(_ notification: CancelRequestNotification) throws {
231+
inProgressRequestsTracker.cancelTask(notification.id)
232+
}
178233
}
179234

180235
// MARK: - CustomBuildServerTestProject

Tests/BuildSystemIntegrationTests/BuildServerBuildSystemTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ final class BuildServerBuildSystemTests: XCTestCase {
527527
func testDontBlockBuildServerInitializationIfBuildSystemIsUnresponsive() async throws {
528528
// A build server that responds to the initialize request but not to any other requests.
529529
final class UnresponsiveBuildServer: CustomBuildServer {
530+
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
531+
530532
init(projectRoot: URL, connectionToSourceKitLSP: any Connection) {}
531533

532534
func buildTargetSourcesRequest(_ request: BuildTargetSourcesRequest) async throws -> BuildTargetSourcesResponse {

Tests/BuildSystemIntegrationTests/BuildSystemManagerTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import ToolchainRegistry
2323
import XCTest
2424

2525
fileprivate actor TestBuildSystem: CustomBuildServer {
26+
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
2627
private let connectionToSourceKitLSP: any Connection
2728
private var buildSettingsByFile: [DocumentURI: TextDocumentSourceKitOptionsResponse] = [:]
2829

Tests/SourceKitLSPTests/BackgroundIndexingTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,7 @@ final class BackgroundIndexingTests: XCTestCase {
19581958

19591959
func testIndexFileIfBuildTargetsChange() async throws {
19601960
actor BuildServer: CustomBuildServer {
1961+
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
19611962
private let projectRoot: URL
19621963
private let connectionToSourceKitLSP: any Connection
19631964
private var buildSettingsByFile: [DocumentURI: TextDocumentSourceKitOptionsResponse] = [:]
@@ -2109,6 +2110,7 @@ final class BackgroundIndexingTests: XCTestCase {
21092110
// response file to invoke the indexer.
21102111

21112112
final class BuildServer: CustomBuildServer {
2113+
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
21122114
private let projectRoot: URL
21132115
private var testFileURL: URL { projectRoot.appendingPathComponent("Test File.swift") }
21142116

Tests/SourceKitLSPTests/BuildSystemTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import ToolchainRegistry
2424
import XCTest
2525

2626
fileprivate actor TestBuildSystem: CustomBuildServer {
27+
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
2728
private let connectionToSourceKitLSP: any Connection
2829
private var buildSettingsByFile: [DocumentURI: TextDocumentSourceKitOptionsResponse] = [:]
2930

0 commit comments

Comments
 (0)