mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
The interaction to an out-of-process BSP server still went through the `BuildServerBuildSystem`, which doesn’t forward all messages to the build system and uses the old push-based model for build settings. If we discover that the BSP server supports the new pull-based build settings model, we now forward all methods to it directly, without going through `BuiltInBuildSystemAdapter`, which has been renamed to `LegacyBuildServerBuildSystem`. rdar://136106323 rdar://127606323 rdar://126493405 Fixes #1226 Fixes #1173
125 lines
4.0 KiB
Swift
125 lines
4.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import BuildServerProtocol
|
|
import Foundation
|
|
import LanguageServerProtocol
|
|
import LanguageServerProtocolJSONRPC
|
|
import SKOptions
|
|
|
|
import struct TSCBasic.AbsolutePath
|
|
import func TSCBasic.getEnvSearchPaths
|
|
import var TSCBasic.localFileSystem
|
|
import func TSCBasic.lookupExecutablePath
|
|
|
|
private func executable(_ name: String) -> String {
|
|
#if os(Windows)
|
|
guard !name.hasSuffix(".exe") else { return name }
|
|
return "\(name).exe"
|
|
#else
|
|
return name
|
|
#endif
|
|
}
|
|
|
|
private let python3ExecutablePath: AbsolutePath? = {
|
|
let pathVariable: String
|
|
#if os(Windows)
|
|
pathVariable = "Path"
|
|
#else
|
|
pathVariable = "PATH"
|
|
#endif
|
|
let searchPaths =
|
|
getEnvSearchPaths(
|
|
pathString: ProcessInfo.processInfo.environment[pathVariable],
|
|
currentWorkingDirectory: localFileSystem.currentWorkingDirectory
|
|
)
|
|
|
|
return lookupExecutablePath(filename: executable("python3"), searchPaths: searchPaths)
|
|
?? lookupExecutablePath(filename: executable("python"), searchPaths: searchPaths)
|
|
}()
|
|
|
|
struct ExecutableNotFoundError: Error {
|
|
let executableName: String
|
|
}
|
|
|
|
private struct BuildServerConfig: Codable {
|
|
/// The name of the build tool.
|
|
let name: String
|
|
|
|
/// The version of the build tool.
|
|
let version: String
|
|
|
|
/// The bsp version of the build tool.
|
|
let bspVersion: String
|
|
|
|
/// A collection of languages supported by this BSP server.
|
|
let languages: [String]
|
|
|
|
/// Command arguments runnable via system processes to start a BSP server.
|
|
let argv: [String]
|
|
|
|
static func load(from path: AbsolutePath) throws -> BuildServerConfig {
|
|
let decoder = JSONDecoder()
|
|
let fileData = try localFileSystem.readFileContents(path).contents
|
|
return try decoder.decode(BuildServerConfig.self, from: Data(fileData))
|
|
}
|
|
}
|
|
|
|
/// Launches a subprocess that is a BSP server and manages the process's lifetime.
|
|
actor ExternalBuildSystemAdapter {
|
|
/// The JSON-RPC connection between SourceKit-LSP and the BSP server.
|
|
let connectionToBuildServer: JSONRPCConnection
|
|
|
|
/// The `BuildSystemManager` that handles messages from the BSP server to SourceKit-LSP.
|
|
let messagesToSourceKitLSPHandler: MessageHandler
|
|
|
|
static package func projectRoot(for workspaceFolder: AbsolutePath, options: SourceKitLSPOptions) -> AbsolutePath? {
|
|
guard localFileSystem.isFile(workspaceFolder.appending(component: "buildServer.json")) else {
|
|
return nil
|
|
}
|
|
return workspaceFolder
|
|
}
|
|
|
|
init(
|
|
projectRoot: AbsolutePath,
|
|
messagesToSourceKitLSPHandler: MessageHandler
|
|
) async throws {
|
|
self.messagesToSourceKitLSPHandler = messagesToSourceKitLSPHandler
|
|
|
|
let configPath = projectRoot.appending(component: "buildServer.json")
|
|
let serverConfig = try BuildServerConfig.load(from: configPath)
|
|
var serverPath = try AbsolutePath(validating: serverConfig.argv[0], relativeTo: projectRoot)
|
|
var serverArgs = Array(serverConfig.argv[1...])
|
|
|
|
if serverPath.suffix == ".py" {
|
|
serverArgs = [serverPath.pathString] + serverArgs
|
|
guard let interpreterPath = python3ExecutablePath else {
|
|
throw ExecutableNotFoundError(executableName: "python3")
|
|
}
|
|
|
|
serverPath = interpreterPath
|
|
}
|
|
|
|
connectionToBuildServer = try JSONRPCConnection.start(
|
|
executable: serverPath.asURL,
|
|
arguments: serverArgs,
|
|
name: "BSP-Server",
|
|
protocol: bspRegistry,
|
|
stderrLoggingCategory: "bsp-server-stderr",
|
|
client: messagesToSourceKitLSPHandler,
|
|
terminationHandler: { _ in
|
|
// TODO: Handle BSP server restart (https://github.com/swiftlang/sourcekit-lsp/issues/1686)
|
|
}
|
|
).connection
|
|
}
|
|
}
|