Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Sources/SWBBuildService/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,14 @@ private struct SetSessionUserPreferencesMsg: MessageHandler {
}
}

private struct LookupToolchainMsg: MessageHandler {
func handle(request: Request, message: LookupToolchainRequest) throws -> LookupToolchainResponse {
let session = try request.session(for: message)
let toolchain = try session.core.toolchainRegistry.lookup(path: message.path)
return LookupToolchainResponse(toolchainIdentifier: toolchain?.identifier)
}
}

/// Start a PIF transfer from the client.
///
/// This will establish a workspace context in the relevant session by exchanging a PIF from the client to the service incrementally, only transferring subobjects as necessary.
Expand Down Expand Up @@ -1543,6 +1551,7 @@ public struct ServiceSessionMessageHandlers: ServiceExtension {
service.registerMessageHandler(SetSessionUserInfoMsg.self)
service.registerMessageHandler(SetSessionUserPreferencesMsg.self)
service.registerMessageHandler(DeveloperPathHandler.self)
service.registerMessageHandler(LookupToolchainMsg.self)
}
}

Expand Down
10 changes: 10 additions & 0 deletions Sources/SWBCore/ToolchainRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,16 @@ public final class ToolchainRegistry: @unchecked Sendable {
}
}

public func lookup(path: Path) throws -> Toolchain? {
let path = try self.fs.realpath(path)
for toolchain in toolchains {
if try self.fs.realpath(toolchain.path) == path {
return toolchain
}
}
return nil
}

public var defaultToolchain: Toolchain? {
return self.lookup("default")
}
Expand Down
27 changes: 27 additions & 0 deletions Sources/SWBProtocol/Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,31 @@ public struct SetSessionUserPreferencesRequest: SessionMessage, RequestMessage,
}
}

public struct LookupToolchainRequest: SessionMessage, RequestMessage, Equatable, SerializableCodable {
public typealias ResponseMessage = LookupToolchainResponse

public static let name = "LOOKUP_TOOLCHAIN"

public let sessionHandle: String

public let path: Path

public init(sessionHandle: String, path: Path) {
self.sessionHandle = sessionHandle
self.path = path
}
}

public struct LookupToolchainResponse: Message, Equatable, SerializableCodable {
public static let name = "LOOKUP_TOOLCHAIN_RESPONSE"

public let toolchainIdentifier: String?

public init(toolchainIdentifier: String?) {
self.toolchainIdentifier = toolchainIdentifier
}
}

public struct ListSessionsRequest: RequestMessage, Equatable {
public typealias ResponseMessage = ListSessionsResponse

Expand Down Expand Up @@ -1176,6 +1201,8 @@ public struct IPCMessage: Serializable, Sendable {
SetSessionSystemInfoRequest.self,
SetSessionUserInfoRequest.self,
SetSessionUserPreferencesRequest.self,
LookupToolchainRequest.self,
LookupToolchainResponse.self,
ListSessionsRequest.self,
ListSessionsResponse.self,
WaitForQuiescenceRequest.self,
Expand Down
8 changes: 8 additions & 0 deletions Sources/SwiftBuild/SWBBuildServiceSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,14 @@ public final class SWBBuildServiceSession: Sendable {
public func setUserPreferences(enableDebugActivityLogs: Bool, enableBuildDebugging: Bool, enableBuildSystemCaching: Bool, activityTextShorteningLevel: Int, usePerConfigurationBuildLocations: Bool?, allowsExternalToolExecution: Bool) async throws {
_ = try await service.send(request: SetSessionUserPreferencesRequest(sessionHandle: self.uid, enableDebugActivityLogs: enableDebugActivityLogs, enableBuildDebugging: enableBuildDebugging, enableBuildSystemCaching: enableBuildSystemCaching, activityTextShorteningLevel: ActivityTextShorteningLevel(rawValue: activityTextShorteningLevel) ?? .default, usePerConfigurationBuildLocations: usePerConfigurationBuildLocations, allowsExternalToolExecution: allowsExternalToolExecution))
}

public func lookupToolchain(at path: String) async throws -> SWBToolchainIdentifier? {
return try await service.send(request: LookupToolchainRequest(sessionHandle: self.uid, path: Path(path))).toolchainIdentifier.map { SWBToolchainIdentifier(rawValue: $0) }
}
}

public struct SWBToolchainIdentifier {
public var rawValue: String
}

extension SWBBuildServiceSession {
Expand Down
8 changes: 4 additions & 4 deletions Sources/SwiftBuildTestSupport/TestUtilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ package actor TestSWBSession {
package nonisolated let sessionDiagnostics: [SwiftBuildMessage.DiagnosticInfo]
private var closed = false

package init(connectionMode: SWBBuildServiceConnectionMode = .default, variant: SWBBuildServiceVariant = .default, temporaryDirectory: NamedTemporaryDirectory?) async throws {
package init(connectionMode: SWBBuildServiceConnectionMode = .default, variant: SWBBuildServiceVariant = .default, temporaryDirectory: NamedTemporaryDirectory?, environment: [String: String] = [:]) async throws {
self.tmpDir = try temporaryDirectory ?? NamedTemporaryDirectory()
// Construct the test session.
self.service = try await SWBBuildService(connectionMode: connectionMode, variant: variant)
let (result, sessionDiagnostics) = await service.createSession(name: #function, cachePath: tmpDir.path.str)
let (result, sessionDiagnostics) = await service.createSession(name: #function, cachePath: tmpDir.path.str, environment: environment)
self.sessionDiagnostics = sessionDiagnostics
do {
self.session = try result.get()
Expand Down Expand Up @@ -203,8 +203,8 @@ extension SWBRunDestinationInfo: _RunDestinationInfo {

extension SWBBuildService {
/// Overload of `createSession` which supplies an inferior products path.
package func createSession(name: String, developerPath: String? = nil, cachePath: String?) async -> (Result<SWBBuildServiceSession, any Error>, [SwiftBuildMessage.DiagnosticInfo]) {
return await createSession(name: name, developerPath: developerPath, cachePath: cachePath, inferiorProductsPath: Core.inferiorProductsPath()?.str, environment: [:])
package func createSession(name: String, developerPath: String? = nil, cachePath: String?, environment: [String:String] = [:]) async -> (Result<SWBBuildServiceSession, any Error>, [SwiftBuildMessage.DiagnosticInfo]) {
return await createSession(name: name, developerPath: developerPath, cachePath: cachePath, inferiorProductsPath: Core.inferiorProductsPath()?.str, environment: environment)
}
}

Expand Down
45 changes: 45 additions & 0 deletions Tests/SwiftBuildTests/ToolchainTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import struct Foundation.UUID

import SwiftBuild
import SwiftBuildTestSupport

import SWBCore
import SWBTestSupport
@_spi(Testing) import SWBUtil

import Testing

@Suite
fileprivate struct ToolchainTests: CoreBasedTests {
@Test(.skipIfEnvironmentVariableSet(key: .externalToolchainsDir))
func toolchainLookupByPath() async throws {
try await withTemporaryDirectory { (temporaryDirectory: NamedTemporaryDirectory) in
let tmpDir = temporaryDirectory.path
try await withAsyncDeferrable { deferrable in
try localFS.createDirectory(tmpDir.join("toolchain.xctoolchain"))
try await localFS.writePlist(tmpDir.join("toolchain.xctoolchain/Info.plist"), .plDict(["Identifier": "com.foo.bar"]))
let testSession = try await TestSWBSession(temporaryDirectory: temporaryDirectory, environment: ["EXTERNAL_TOOLCHAINS_DIR": tmpDir.str])
await deferrable.addBlock {
await #expect(throws: Never.self) {
try await testSession.close()
}
}

let id = try await testSession.session.lookupToolchain(at: tmpDir.join("toolchain.xctoolchain").str)
#expect(id?.rawValue == "com.foo.bar")
}
}
}
}