Skip to content

Commit 98d37cf

Browse files
committed
Update BSP connection build server config lookup path
Resolves #1695 Adopt `<workspace_root>/.bsp` search locations in addition to `<workspace_root>/`.
1 parent 9e2b1c9 commit 98d37cf

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

Sources/BuildSystemIntegration/ExternalBuildSystemAdapter.swift

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ struct ExecutableNotFoundError: Error {
5252
let executableName: String
5353
}
5454

55+
enum BuildServerNotFoundError: Error {
56+
case fileNotFound
57+
}
58+
5559
private struct BuildServerConfig: Codable {
5660
/// The name of the build tool.
5761
let name: String
@@ -94,7 +98,7 @@ actor ExternalBuildSystemAdapter {
9498
private var lastRestart: Date?
9599

96100
static package func projectRoot(for workspaceFolder: AbsolutePath, options: SourceKitLSPOptions) -> AbsolutePath? {
97-
guard localFileSystem.isFile(workspaceFolder.appending(component: "buildServer.json")) else {
101+
guard let _ = getConfigPath(for: workspaceFolder) else {
98102
return nil
99103
}
100104
return workspaceFolder
@@ -142,7 +146,10 @@ actor ExternalBuildSystemAdapter {
142146

143147
/// Create a new JSONRPCConnection to the build server.
144148
private func createConnectionToBspServer() async throws -> JSONRPCConnection {
145-
let configPath = projectRoot.appending(component: "buildServer.json")
149+
guard let configPath = ExternalBuildSystemAdapter.getConfigPath(for: self.projectRoot) else {
150+
throw BuildServerNotFoundError.fileNotFound
151+
}
152+
146153
let serverConfig = try BuildServerConfig.load(from: configPath)
147154
var serverPath = try AbsolutePath(validating: serverConfig.argv[0], relativeTo: projectRoot)
148155
var serverArgs = Array(serverConfig.argv[1...])
@@ -178,6 +185,48 @@ actor ExternalBuildSystemAdapter {
178185
).connection
179186
}
180187

188+
private static func getConfigPath(for workspaceFolder: AbsolutePath? = nil) -> AbsolutePath? {
189+
var buildServerConfigLocations: [AbsolutePath?] = []
190+
if let workspaceFolder = workspaceFolder {
191+
buildServerConfigLocations.append(workspaceFolder.appending(component: ".bsp"))
192+
}
193+
194+
#if os(Windows)
195+
let localAppDataPath = AbsolutePath(validatingOrNil: ProcessInfo.processInfo.environment["LOCALAPPDATA\\bsp\\"])
196+
let programDataPath = AbsolutePath(validatingOrNil: ProcessInfo.processInfo.environment["PROGRAMDATA\\bsp\\"])
197+
198+
buildServerConfigLocations.append(contentsOf: [localAppDataPath, programDataPath])
199+
#else
200+
let xdgDataHomePath = AbsolutePath(validatingOrNil: ProcessInfo.processInfo.environment["XDG_DATA_HOME\\bsp\\"])
201+
let xdgDataDirsPath = AbsolutePath(validatingOrNil: ProcessInfo.processInfo.environment["XDG_DATA_DIRS\\bsp\\"])
202+
203+
buildServerConfigLocations.append(contentsOf: [xdgDataHomePath, xdgDataDirsPath])
204+
205+
if let libraryUrl = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
206+
let libraryPath = AbsolutePath(validatingOrNil: libraryUrl.absoluteString)?.appending(component: "bsp")
207+
buildServerConfigLocations.append(libraryPath)
208+
}
209+
#endif
210+
211+
for buildServerConfigLocation in buildServerConfigLocations {
212+
guard let buildServerConfigLocation else {
213+
continue
214+
}
215+
let fileManager = FileManager.default
216+
do {
217+
let items = try fileManager.contentsOfDirectory(atPath: buildServerConfigLocation.pathString)
218+
let jsonFiles = items.filter { $0.hasSuffix(".json") }
219+
220+
if let configFilePath = jsonFiles.sorted().first {
221+
return buildServerConfigLocation.appending(component: configFilePath)
222+
}
223+
} catch {
224+
logger.error("Failed to read build server config file at \(buildServerConfigLocation): \(error)")
225+
}
226+
}
227+
return nil
228+
}
229+
181230
/// Restart the BSP server after it has crashed.
182231
private func handleBspServerCrash() async throws {
183232
// Set `connectionToBuildServer` to `nil` to indicate that there is currently no BSP server running.

Tests/BuildSystemIntegrationTests/BuildServerBuildSystemTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,4 +303,27 @@ final class BuildServerBuildSystemTests: XCTestCase {
303303
}
304304

305305
}
306+
307+
func testBuildServerConfigPath() async throws {
308+
let fileManager = FileManager.default
309+
let jsonConfig = """
310+
{
311+
"name": "My Build Tool",
312+
"version": "21.3",
313+
"bspVersion": "2.0.0",
314+
"languages": ["scala", "javascript", "rust"],
315+
"argv": ["my-build-tool", "bsp"]
316+
}
317+
"""
318+
319+
do {
320+
let directoryPath = FileManager.default.currentDirectoryPath.appending(".bsp")
321+
let filePath = directoryPath.appending("build_config.json")
322+
323+
try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true)
324+
fileManager.createFile(atPath: filePath, contents: jsonConfig.data(using: .utf8))
325+
} catch {
326+
print("Error creating directory: \(error.localizedDescription)")
327+
}
328+
}
306329
}

0 commit comments

Comments
 (0)