@@ -52,6 +52,10 @@ struct ExecutableNotFoundError: Error {
52
52
let executableName : String
53
53
}
54
54
55
+ enum BuildServerNotFoundError : Error {
56
+ case fileNotFound
57
+ }
58
+
55
59
private struct BuildServerConfig : Codable {
56
60
/// The name of the build tool.
57
61
let name : String
@@ -94,7 +98,7 @@ actor ExternalBuildSystemAdapter {
94
98
private var lastRestart : Date ?
95
99
96
100
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 {
98
102
return nil
99
103
}
100
104
return workspaceFolder
@@ -142,7 +146,10 @@ actor ExternalBuildSystemAdapter {
142
146
143
147
/// Create a new JSONRPCConnection to the build server.
144
148
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
+
146
153
let serverConfig = try BuildServerConfig . load ( from: configPath)
147
154
var serverPath = try AbsolutePath ( validating: serverConfig. argv [ 0 ] , relativeTo: projectRoot)
148
155
var serverArgs = Array ( serverConfig. argv [ 1 ... ] )
@@ -178,6 +185,61 @@ actor ExternalBuildSystemAdapter {
178
185
) . connection
179
186
}
180
187
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 " ] ) ? . appending ( component: " bsp " )
196
+ let programDataPath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " PROGRAMDATA " ] ) ? . appending ( component: " bsp " )
197
+
198
+ buildServerConfigLocations. append ( contentsOf: [ localAppDataPath, programDataPath] )
199
+ #else
200
+ let xdgDataHomePath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " XDG_DATA_HOME " ] ) ? . appending ( component: " bsp " )
201
+ buildServerConfigLocations. append ( xdgDataHomePath)
202
+
203
+ if let libraryUrl = FileManager . default. urls ( for: . applicationSupportDirectory, in: . userDomainMask) . first {
204
+ let libraryPath = AbsolutePath ( validatingOrNil: libraryUrl. absoluteString) ? . appending ( component: " bsp " )
205
+ buildServerConfigLocations. append ( libraryPath)
206
+ }
207
+
208
+ let xdgDataDirsPath = AbsolutePath ( validatingOrNil: ProcessInfo . processInfo. environment [ " XDG_DATA_DIRS " ] ) ? . appending ( component: " bsp " )
209
+ buildServerConfigLocations. append ( xdgDataDirsPath)
210
+
211
+ if let libraryUrl = FileManager . default. urls ( for: . applicationSupportDirectory, in: . systemDomainMask) . first {
212
+ let libraryPath = AbsolutePath ( validatingOrNil: libraryUrl. absoluteString) ? . appending ( component: " bsp " )
213
+ buildServerConfigLocations. append ( libraryPath)
214
+ }
215
+ #endif
216
+
217
+ for buildServerConfigLocation in buildServerConfigLocations {
218
+ guard let buildServerConfigLocation else {
219
+ continue
220
+ }
221
+ let fileManager = FileManager . default
222
+ do {
223
+ let items = try fileManager. contentsOfDirectory ( atPath: buildServerConfigLocation. pathString)
224
+ let jsonFiles = items. filter { $0. hasSuffix ( " .json " ) }
225
+
226
+ if let configFilePath = jsonFiles. sorted ( ) . first {
227
+ return buildServerConfigLocation. appending ( component: configFilePath)
228
+ }
229
+ } catch {
230
+ logger. error ( " Failed to read build server config file at \( buildServerConfigLocation) : \( error) " )
231
+ }
232
+ }
233
+
234
+ // Backward compatibility
235
+ if let workspaceFolder = workspaceFolder,
236
+ localFileSystem. isFile ( workspaceFolder. appending ( component: " buildServer.json " ) ) {
237
+ return workspaceFolder. appending ( component: " buildServer.json " )
238
+ }
239
+
240
+ return nil
241
+ }
242
+
181
243
/// Restart the BSP server after it has crashed.
182
244
private func handleBspServerCrash( ) async throws {
183
245
// Set `connectionToBuildServer` to `nil` to indicate that there is currently no BSP server running.
0 commit comments