diff --git a/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift b/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift index 28bf48e2..682c2332 100644 --- a/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift +++ b/Sources/SwiftBuild/ConsoleCommands/SWBServiceConsoleBuildCommand.swift @@ -345,6 +345,35 @@ class SWBServiceConsolePrepareForIndexCommand: SWBServiceConsoleCommand { } } +class SWBServiceConsoleDependencyInfoCommand: SWBServiceConsoleCommand { + public static let name = "generateDependencyInfo" + + static func usage() -> String { + return name + " [options] " + } + + static func validate(invocation: SWBServiceConsoleCommandInvocation) -> SWBServiceConsoleError? { + return nil + } + + static func perform(invocation: SWBServiceConsoleCommandInvocation) async -> SWBCommandResult { + return await SWBServiceConsoleBuildCommand.perform(invocation: invocation, operationFunc: generateDependencyInfo) + } +} + +fileprivate func generateDependencyInfo(startInfo: SwiftBuildMessage.BuildStartedInfo, session: SWBBuildServiceSession, sessionCreationDiagnostics: [SwiftBuildMessage.DiagnosticInfo], request: SWBBuildRequest) async -> SWBCommandResult { + do { + let output = try await withTemporaryDirectory(removeTreeOnDeinit: true) { + let outputPath = $0.join("dump.json") + try await session.dumpBuildDependencyInfo(for: request, to: outputPath.str) + return try String(contentsOf: URL(fileURLWithPath: outputPath.str)) + } + return .success(.init(output: output)) + } catch { + return .failure(.failedCommandError(description: "\(error)")) + } +} + extension SWBWorkspaceInfo { func configuredTargets(targetNames: [String], parameters: SWBBuildParameters) throws -> [SWBConfiguredTarget] { return try targetNames.map { targetName in @@ -499,6 +528,7 @@ func registerBuildCommands() { SWBServiceConsoleBuildCommand.self, SWBServiceConsolePrepareForIndexCommand.self, SWBServiceConsoleCreateBuildDescriptionCommand.self, + SWBServiceConsoleDependencyInfoCommand.self, ] as [any SWBServiceConsoleCommand.Type]) { SWBServiceConsoleCommandRegistry.registerCommandClass(commandClass) } } diff --git a/Sources/SwiftBuild/SWBBuildService.swift b/Sources/SwiftBuild/SWBBuildService.swift index 5403d4c8..66429672 100644 --- a/Sources/SwiftBuild/SWBBuildService.swift +++ b/Sources/SwiftBuild/SWBBuildService.swift @@ -301,6 +301,18 @@ public final class SWBBuildService: Sendable { } } + public func dumpBuildDependencyInfo(session: SWBBuildServiceSession, request: SWBBuildRequest, outputPath: String) async { + let (channel, _): (UInt64, Bool) = await withCheckedContinuation { continuation in + Task { + let channel = self.openChannel { channel, message in + } + + _ = await send(DumpBuildDependencyInfoRequest(sessionHandle: session.name, responseChannel: channel, request: request.messagePayloadRepresentation, outputPath: outputPath)) + } + } + self.connection.close(channel: channel) + } + @available(*, deprecated, message: "Do not use.") public func appleSystemFrameworkNames(developerPath: String?) async throws -> Set { try await Set(send(request: AppleSystemFrameworkNamesRequest(developerPath: developerPath.map(Path.init))).value) diff --git a/Tests/SwiftBuildTests/ConsoleCommands/GeneralCommandsTests.swift b/Tests/SwiftBuildTests/ConsoleCommands/GeneralCommandsTests.swift index bb5fb76d..af1c9b8d 100644 --- a/Tests/SwiftBuildTests/ConsoleCommands/GeneralCommandsTests.swift +++ b/Tests/SwiftBuildTests/ConsoleCommands/GeneralCommandsTests.swift @@ -78,6 +78,7 @@ fileprivate struct GeneralCommandsTests { dumpMsgPack\r dumpPID\r exit\r + generateDependencyInfo\r headermap\r help\r isAlive\r @@ -141,6 +142,7 @@ fileprivate struct GeneralCommandsTests { "dumpMsgPack", "dumpPID", "exit", + "generateDependencyInfo", "headermap", "help", "isAlive",