diff --git a/Sources/Basics/AuthorizationProvider.swift b/Sources/Basics/AuthorizationProvider.swift index 11e80cb79ed..89326664a3c 100644 --- a/Sources/Basics/AuthorizationProvider.swift +++ b/Sources/Basics/AuthorizationProvider.swift @@ -17,8 +17,7 @@ import struct Foundation.URL import Security #endif -public protocol AuthorizationProvider { - @Sendable +public protocol AuthorizationProvider: Sendable { func authentication(for url: URL) -> (user: String, password: String)? } @@ -80,7 +79,7 @@ extension AuthorizationProvider { // MARK: - netrc -public class NetrcAuthorizationProvider: AuthorizationProvider, AuthorizationWriter { +public final class NetrcAuthorizationProvider: AuthorizationProvider, AuthorizationWriter { // marked internal for testing internal let path: AbsolutePath private let fileSystem: FileSystem @@ -202,7 +201,7 @@ public class NetrcAuthorizationProvider: AuthorizationProvider, AuthorizationWri // MARK: - Keychain #if canImport(Security) -public class KeychainAuthorizationProvider: AuthorizationProvider, AuthorizationWriter { +public final class KeychainAuthorizationProvider: AuthorizationProvider, AuthorizationWriter { private let observabilityScope: ObservabilityScope private let cache = ThreadSafeKeyValueStore() diff --git a/Sources/Basics/HTTPClient/LegacyHTTPClient.swift b/Sources/Basics/HTTPClient/LegacyHTTPClient.swift index 8b53d663b4d..b5294ccfabf 100644 --- a/Sources/Basics/HTTPClient/LegacyHTTPClient.swift +++ b/Sources/Basics/HTTPClient/LegacyHTTPClient.swift @@ -26,8 +26,8 @@ public final class LegacyHTTPClient: Cancellable { public typealias Request = LegacyHTTPClientRequest public typealias Response = HTTPClientResponse public typealias Handler = (Request, ProgressHandler?, @escaping (Result) -> Void) -> Void - public typealias ProgressHandler = (_ bytesReceived: Int64, _ totalBytes: Int64?) throws -> Void - public typealias CompletionHandler = (Result) -> Void + public typealias ProgressHandler = @Sendable (_ bytesReceived: Int64, _ totalBytes: Int64?) throws -> Void + public typealias CompletionHandler = @Sendable (Result) -> Void public var configuration: LegacyHTTPClientConfiguration private let underlying: Handler @@ -121,7 +121,7 @@ public final class LegacyHTTPClient: Cancellable { requestNumber: 0, observabilityScope: observabilityScope, progress: progress.map { handler in - { received, expected in + { @Sendable received, expected in // call back on the requested queue callbackQueue.async { do { @@ -312,7 +312,7 @@ extension LegacyHTTPClient { headers: HTTPClientHeaders = .init(), options: Request.Options = .init(), observabilityScope: ObservabilityScope? = .none, - completion: @escaping (Result) -> Void + completion: @Sendable @escaping (Result) -> Void ) { self.execute( Request(method: .head, url: url, headers: headers, body: nil, options: options), @@ -326,7 +326,7 @@ extension LegacyHTTPClient { headers: HTTPClientHeaders = .init(), options: Request.Options = .init(), observabilityScope: ObservabilityScope? = .none, - completion: @escaping (Result) -> Void + completion: @Sendable @escaping (Result) -> Void ) { self.execute( Request(method: .get, url: url, headers: headers, body: nil, options: options), @@ -341,7 +341,7 @@ extension LegacyHTTPClient { headers: HTTPClientHeaders = .init(), options: Request.Options = .init(), observabilityScope: ObservabilityScope? = .none, - completion: @escaping (Result) -> Void + completion: @Sendable @escaping (Result) -> Void ) { self.execute( Request(method: .put, url: url, headers: headers, body: body, options: options), @@ -356,7 +356,7 @@ extension LegacyHTTPClient { headers: HTTPClientHeaders = .init(), options: Request.Options = .init(), observabilityScope: ObservabilityScope? = .none, - completion: @escaping (Result) -> Void + completion: @Sendable @escaping (Result) -> Void ) { self.execute( Request(method: .post, url: url, headers: headers, body: body, options: options), @@ -370,7 +370,7 @@ extension LegacyHTTPClient { headers: HTTPClientHeaders = .init(), options: Request.Options = .init(), observabilityScope: ObservabilityScope? = .none, - completion: @escaping (Result) -> Void + completion: @Sendable @escaping (Result) -> Void ) { self.execute( Request(method: .delete, url: url, headers: headers, body: nil, options: options), @@ -383,7 +383,7 @@ extension LegacyHTTPClient { // MARK: - LegacyHTTPClientConfiguration public struct LegacyHTTPClientConfiguration { - public typealias AuthorizationProvider = (URL) -> String? + public typealias AuthorizationProvider = @Sendable (URL) -> String? public var requestHeaders: HTTPClientHeaders? public var requestTimeout: DispatchTimeInterval? diff --git a/Sources/Basics/HTTPClient/URLSessionHTTPClient.swift b/Sources/Basics/HTTPClient/URLSessionHTTPClient.swift index a3d4102da64..b706b173d39 100644 --- a/Sources/Basics/HTTPClient/URLSessionHTTPClient.swift +++ b/Sources/Basics/HTTPClient/URLSessionHTTPClient.swift @@ -19,7 +19,7 @@ import struct TSCUtility.Versioning import FoundationNetworking #endif -final class URLSessionHTTPClient { +final class URLSessionHTTPClient: Sendable { private let dataTaskManager: DataTaskManager private let downloadTaskManager: DownloadTaskManager @@ -42,7 +42,7 @@ final class URLSessionHTTPClient { urlRequest: urlRequest, authorizationProvider: request.options.authorizationProvider, progress: progress, - completion: continuation.resume(with:) + completion: { continuation.resume(with: $0) } ) case .download(_, let destination): task = self.downloadTaskManager.makeTask( @@ -52,13 +52,14 @@ final class URLSessionHTTPClient { fileSystem: localFileSystem, destination: destination, progress: progress, - completion: continuation.resume(with:) + completion: { continuation.resume(with: $0) } ) } task.resume() } } + @Sendable public func execute( _ request: LegacyHTTPClient.Request, progress: LegacyHTTPClient.ProgressHandler?, @@ -140,8 +141,8 @@ private class WeakDataTaskManager: NSObject, URLSessionDataDelegate { } } -private class DataTaskManager { - private var tasks = ThreadSafeKeyValueStore() +private final class DataTaskManager: @unchecked Sendable { + private let tasks = ThreadSafeKeyValueStore() private let delegateQueue: OperationQueue private var session: URLSession! @@ -179,11 +180,13 @@ private class DataTaskManager { didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void ) { - guard let task = self.tasks[dataTask.taskIdentifier] else { + guard var task = self.tasks[dataTask.taskIdentifier] else { return completionHandler(.cancel) } task.response = response as? HTTPURLResponse task.expectedContentLength = response.expectedContentLength + self.tasks[dataTask.taskIdentifier] = task + do { try task.progressHandler?(0, response.expectedContentLength) completionHandler(.allow) @@ -193,7 +196,7 @@ private class DataTaskManager { } public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { - guard let task = self.tasks[dataTask.taskIdentifier] else { + guard var task = self.tasks[dataTask.taskIdentifier] else { return } if task.buffer != nil { @@ -201,6 +204,7 @@ private class DataTaskManager { } else { task.buffer = data } + self.tasks[dataTask.taskIdentifier] = task do { // safe since created in the line above @@ -246,7 +250,7 @@ private class DataTaskManager { completionHandler(request) } - class DataTask { + struct DataTask: Sendable { let task: URLSessionDataTask let completionHandler: LegacyHTTPClient.CompletionHandler /// A strong reference to keep the `DataTaskManager` alive so it can handle the callbacks from the @@ -318,9 +322,11 @@ private class WeakDownloadTaskManager: NSObject, URLSessionDownloadDelegate { } } -private class DownloadTaskManager { - private var tasks = ThreadSafeKeyValueStore() +private final class DownloadTaskManager: @unchecked Sendable { + private let tasks = ThreadSafeKeyValueStore() private let delegateQueue: OperationQueue + + // FIXME: can't be `let` instead of `var`, as `URLSession` holds a reference to `self`. private var session: URLSession! init(configuration: URLSessionConfiguration) { @@ -379,7 +385,7 @@ private class DownloadTaskManager { downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL ) { - guard let task = self.tasks[downloadTask.taskIdentifier] else { + guard var task = self.tasks[downloadTask.taskIdentifier] else { return } @@ -392,6 +398,7 @@ private class DownloadTaskManager { try task.fileSystem.move(from: path, to: task.destination) } catch { task.moveFileError = error + self.tasks[downloadTask.taskIdentifier] = task } } @@ -419,7 +426,7 @@ private class DownloadTaskManager { } } - class DownloadTask { + struct DownloadTask: Sendable { let task: URLSessionDownloadTask let fileSystem: FileSystem let destination: AbsolutePath diff --git a/Sources/Build/BuildOperation.swift b/Sources/Build/BuildOperation.swift index 48ab75d839c..847f941bc46 100644 --- a/Sources/Build/BuildOperation.swift +++ b/Sources/Build/BuildOperation.swift @@ -12,8 +12,6 @@ import Basics -import Build - import LLBuildManifest import PackageGraph import PackageLoading diff --git a/Sources/PackageRegistry/RegistryClient.swift b/Sources/PackageRegistry/RegistryClient.swift index ff8ec74b5c6..a13fc4cd8f6 100644 --- a/Sources/PackageRegistry/RegistryClient.swift +++ b/Sources/PackageRegistry/RegistryClient.swift @@ -1651,7 +1651,7 @@ public final class RegistryClient: Cancellable { result.tryMap { response in observabilityScope .emit( - debug: "server response for \(request.url): \(response.statusCode) in \(start.distance(to: .now()).descriptionInSeconds)" + debug: "server response for \(url): \(response.statusCode) in \(start.distance(to: .now()).descriptionInSeconds)" ) switch response.statusCode { case 201: