File: BuiltInBuildSystemAdapter.swift

package info (click to toggle)
swiftlang 6.1.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,791,748 kB
  • sloc: cpp: 9,901,738; ansic: 2,201,433; asm: 1,091,827; python: 308,252; objc: 82,166; f90: 80,126; lisp: 38,358; pascal: 25,559; sh: 20,429; ml: 5,058; perl: 4,745; makefile: 4,484; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (145 lines) | stat: -rw-r--r-- 5,659 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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 LanguageServerProtocol
import LanguageServerProtocolExtensions
import SKLogging
import SKOptions
import SwiftExtensions
import ToolchainRegistry

#if compiler(>=6)
package import Foundation
#else
import Foundation
#endif

/// The details necessary to create a `BuildSystemAdapter`.
package struct BuildSystemSpec {
  package enum Kind {
    case buildServer
    case compilationDatabase
    case swiftPM
    case injected(BuildSystemInjector)
  }

  package var kind: Kind

  /// The folder that best describes the root of the project that this build system handles.
  package var projectRoot: URL

  /// The main path that provides the build system configuration.
  package var configPath: URL

  package init(kind: BuildSystemSpec.Kind, projectRoot: URL, configPath: URL) {
    self.kind = kind
    self.projectRoot = projectRoot
    self.configPath = configPath
  }
}

/// A type that outwardly acts as a BSP build server and internally uses a `BuiltInBuildSystem` to satisfy the requests.
actor BuiltInBuildSystemAdapter: QueueBasedMessageHandler {
  let messageHandlingHelper = QueueBasedMessageHandlerHelper(
    signpostLoggingCategory: "build-system-message-handling",
    createLoggingScope: false
  )

  /// The queue on which all messages from SourceKit-LSP (or more specifically `BuildSystemManager`) are handled.
  package let messageHandlingQueue = AsyncQueue<BuildSystemMessageDependencyTracker>()

  /// The underlying build system
  private var underlyingBuildSystem: BuiltInBuildSystem

  /// The connection with which messages are sent to `BuildSystemManager`.
  private let connectionToSourceKitLSP: LocalConnection

  private let buildSystemHooks: BuildSystemHooks

  /// Create a `BuiltInBuildSystemAdapter` form an existing `BuiltInBuildSystem` and connection to communicate messages
  /// from the build system to SourceKit-LSP.
  init(
    underlyingBuildSystem: BuiltInBuildSystem,
    connectionToSourceKitLSP: LocalConnection,
    buildSystemHooks: BuildSystemHooks
  ) {
    self.underlyingBuildSystem = underlyingBuildSystem
    self.connectionToSourceKitLSP = connectionToSourceKitLSP
    self.buildSystemHooks = buildSystemHooks
  }

  deinit {
    connectionToSourceKitLSP.close()
  }

  private func initialize(request: InitializeBuildRequest) async -> InitializeBuildResponse {
    return InitializeBuildResponse(
      displayName: "\(type(of: underlyingBuildSystem))",
      version: "",
      bspVersion: "2.2.0",
      capabilities: BuildServerCapabilities(),
      dataKind: .sourceKit,
      data: SourceKitInitializeBuildResponseData(
        indexDatabasePath: await orLog("getting index database file path") {
          try await underlyingBuildSystem.indexDatabasePath?.filePath
        },
        indexStorePath: await orLog("getting index store file path") {
          try await underlyingBuildSystem.indexStorePath?.filePath
        },
        watchers: await underlyingBuildSystem.fileWatchers,
        prepareProvider: underlyingBuildSystem.supportsPreparation,
        sourceKitOptionsProvider: true
      ).encodeToLSPAny()
    )
  }

  package func handle(notification: some NotificationType) async {
    switch notification {
    case is OnBuildExitNotification:
      break
    case is OnBuildInitializedNotification:
      break
    case let notification as OnWatchedFilesDidChangeNotification:
      await self.underlyingBuildSystem.didChangeWatchedFiles(notification: notification)
    default:
      logger.error("Ignoring unknown notification \(type(of: notification).method) from SourceKit-LSP")
    }
  }

  func handle<Request: RequestType>(
    request: Request,
    id: RequestID,
    reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
  ) async {
    let request = RequestAndReply(request, reply: reply)
    await buildSystemHooks.preHandleRequest?(request.params)
    switch request {
    case let request as RequestAndReply<BuildShutdownRequest>:
      await request.reply { VoidResponse() }
    case let request as RequestAndReply<BuildTargetPrepareRequest>:
      await request.reply { try await underlyingBuildSystem.prepare(request: request.params) }
    case let request as RequestAndReply<BuildTargetSourcesRequest>:
      await request.reply { try await underlyingBuildSystem.buildTargetSources(request: request.params) }
    case let request as RequestAndReply<InitializeBuildRequest>:
      await request.reply { await self.initialize(request: request.params) }
    case let request as RequestAndReply<TextDocumentSourceKitOptionsRequest>:
      await request.reply { try await underlyingBuildSystem.sourceKitOptions(request: request.params) }
    case let request as RequestAndReply<WorkspaceBuildTargetsRequest>:
      await request.reply { try await underlyingBuildSystem.buildTargets(request: request.params) }
    case let request as RequestAndReply<WorkspaceWaitForBuildSystemUpdatesRequest>:
      await request.reply { await underlyingBuildSystem.waitForBuildSystemUpdates(request: request.params) }
    default:
      await request.reply { throw ResponseError.methodNotFound(Request.method) }
    }
  }
}