From c94b0d058caa56b682390748741fd7010abf8aad Mon Sep 17 00:00:00 2001 From: David Goldman Date: Thu, 9 Jun 2022 10:45:52 -0400 Subject: [PATCH] Support index store path remappings (#562) This allows sourcekit-lsp to make use of the path remappings recently added to the index store and IndexStoreDB to remap remote paths into local paths when loading index data locally. These remappings can be provided via the `-index-prefix-map` command line flag to sourcekit-lsp or via the `BuildSystem` integration point. (cherry picked from commit 472a06c88af97135b6faa450c5854e8f1a0ab8de) --- Sources/SKCore/BuildServerBuildSystem.swift | 3 +++ Sources/SKCore/BuildSystem.swift | 3 +++ Sources/SKCore/BuildSystemManager.swift | 2 ++ Sources/SKCore/CMakeLists.txt | 1 + .../SKCore/CompilationDatabaseBuildSystem.swift | 2 ++ Sources/SKCore/FallbackBuildSystem.swift | 2 ++ Sources/SKCore/PathPrefixMapping.swift | 14 ++++++++++++++ .../SKSwiftPMWorkspace/SwiftPMWorkspace.swift | 2 ++ Sources/SourceKitLSP/Workspace.swift | 17 +++++++++++++++-- Sources/sourcekit-lsp/main.swift | 17 +++++++++++++++++ Tests/SKCoreTests/BuildSystemManagerTests.swift | 1 + Tests/SourceKitLSPTests/BuildSystemTests.swift | 1 + 12 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 Sources/SKCore/PathPrefixMapping.swift diff --git a/Sources/SKCore/BuildServerBuildSystem.swift b/Sources/SKCore/BuildServerBuildSystem.swift index fba894d7..328d3d64 100644 --- a/Sources/SKCore/BuildServerBuildSystem.swift +++ b/Sources/SKCore/BuildServerBuildSystem.swift @@ -35,6 +35,9 @@ public final class BuildServerBuildSystem { public private(set) var indexDatabasePath: AbsolutePath? public private(set) var indexStorePath: AbsolutePath? + // FIXME: Add support for prefix mappings to the Build Server protocol. + public var indexPrefixMappings: [PathPrefixMapping] { return [] } + /// Delegate to handle any build system events. public weak var delegate: BuildSystemDelegate? { get { return self.handler?.delegate } diff --git a/Sources/SKCore/BuildSystem.swift b/Sources/SKCore/BuildSystem.swift index 094d368c..5ecf15c6 100644 --- a/Sources/SKCore/BuildSystem.swift +++ b/Sources/SKCore/BuildSystem.swift @@ -43,6 +43,9 @@ public protocol BuildSystem: AnyObject { /// The path to put the index database, if any. var indexDatabasePath: AbsolutePath? { get } + /// Path remappings for remapping index data for local use. + var indexPrefixMappings: [PathPrefixMapping] { get } + /// Delegate to handle any build system events such as file build settings /// initial reports as well as changes. var delegate: BuildSystemDelegate? { get set } diff --git a/Sources/SKCore/BuildSystemManager.swift b/Sources/SKCore/BuildSystemManager.swift index d7727c01..c012e75c 100644 --- a/Sources/SKCore/BuildSystemManager.swift +++ b/Sources/SKCore/BuildSystemManager.swift @@ -140,6 +140,8 @@ extension BuildSystemManager: BuildSystem { public var indexDatabasePath: AbsolutePath? { queue.sync { buildSystem?.indexDatabasePath } } + public var indexPrefixMappings: [PathPrefixMapping] { queue.sync { buildSystem?.indexPrefixMappings ?? [] } } + public var delegate: BuildSystemDelegate? { get { queue.sync { _delegate } } set { queue.sync { _delegate = newValue } } diff --git a/Sources/SKCore/CMakeLists.txt b/Sources/SKCore/CMakeLists.txt index 7cd686d4..5281bf85 100644 --- a/Sources/SKCore/CMakeLists.txt +++ b/Sources/SKCore/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(SKCore STATIC FileBuildSettingsChange.swift LanguageServer.swift MainFilesProvider.swift + PathPrefixMapping.swift Toolchain.swift ToolchainRegistry.swift XCToolchainPlist.swift) diff --git a/Sources/SKCore/CompilationDatabaseBuildSystem.swift b/Sources/SKCore/CompilationDatabaseBuildSystem.swift index 1bb46fc6..7a3287cc 100644 --- a/Sources/SKCore/CompilationDatabaseBuildSystem.swift +++ b/Sources/SKCore/CompilationDatabaseBuildSystem.swift @@ -88,6 +88,8 @@ extension CompilationDatabaseBuildSystem: BuildSystem { indexStorePath?.parentDirectory.appending(component: "IndexDatabase") } + public var indexPrefixMappings: [PathPrefixMapping] { return [] } + public func registerForChangeNotifications(for uri: DocumentURI, language: Language) { queue.async { self.watchedFiles[uri] = language diff --git a/Sources/SKCore/FallbackBuildSystem.swift b/Sources/SKCore/FallbackBuildSystem.swift index ceb6cade..5f5d28ee 100644 --- a/Sources/SKCore/FallbackBuildSystem.swift +++ b/Sources/SKCore/FallbackBuildSystem.swift @@ -40,6 +40,8 @@ public final class FallbackBuildSystem: BuildSystem { public var indexDatabasePath: AbsolutePath? { return nil } + public var indexPrefixMappings: [PathPrefixMapping] { return [] } + public func settings(for uri: DocumentURI, _ language: Language) -> FileBuildSettings? { switch language { case .swift: diff --git a/Sources/SKCore/PathPrefixMapping.swift b/Sources/SKCore/PathPrefixMapping.swift new file mode 100644 index 00000000..ac71f4f2 --- /dev/null +++ b/Sources/SKCore/PathPrefixMapping.swift @@ -0,0 +1,14 @@ +import Foundation + +public struct PathPrefixMapping { + /// Path prefix to be replaced, typically the canonical or hermetic path. + public let original: String + + /// Replacement path prefix, typically the path on the local machine. + public let replacement: String + + public init(original: String, replacement: String) { + self.original = original + self.replacement = replacement + } +} diff --git a/Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift b/Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift index e542fd02..779a179c 100644 --- a/Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift +++ b/Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift @@ -240,6 +240,8 @@ extension SwiftPMWorkspace: SKCore.BuildSystem { return buildPath.appending(components: "index", "db") } + public var indexPrefixMappings: [PathPrefixMapping] { return [] } + /// **Public for testing only** public func _settings( for uri: DocumentURI, diff --git a/Sources/SourceKitLSP/Workspace.swift b/Sources/SourceKitLSP/Workspace.swift index edaec13d..957717e5 100644 --- a/Sources/SourceKitLSP/Workspace.swift +++ b/Sources/SourceKitLSP/Workspace.swift @@ -112,12 +112,14 @@ public final class Workspace { do { let lib = try IndexStoreLibrary(dylibPath: libPath.pathString) indexDelegate = SourceKitIndexDelegate() + let prefixMappings = indexOptions.indexPrefixMappings ?? buildSystem?.indexPrefixMappings ?? [] index = try IndexStoreDB( storePath: storePath.pathString, databasePath: dbPath.pathString, library: lib, delegate: indexDelegate, - listenToUnitEvents: indexOptions.listenToUnitEvents) + listenToUnitEvents: indexOptions.listenToUnitEvents, + prefixMappings: prefixMappings.map { PathMapping(original: $0.original, replacement: $0.replacement) }) log("opened IndexStoreDB at \(dbPath) with store path \(storePath)") } catch { log("failed to open IndexStoreDB: \(error.localizedDescription)", level: .error) @@ -144,11 +146,22 @@ public struct IndexOptions { /// Override the index-database-path provided by the build system. public var indexDatabasePath: AbsolutePath? + /// Override the index prefix mappings provided by the build system. + public var indexPrefixMappings: [PathPrefixMapping]? + /// *For Testing* Whether the index should listen to unit events, or wait for /// explicit calls to pollForUnitChangesAndWait(). public var listenToUnitEvents: Bool - public init(indexStorePath: AbsolutePath? = nil, indexDatabasePath: AbsolutePath? = nil, listenToUnitEvents: Bool = true) { + public init( + indexStorePath: AbsolutePath? = nil, + indexDatabasePath: AbsolutePath? = nil, + indexPrefixMappings: [PathPrefixMapping]? = nil, + listenToUnitEvents: Bool = true + ) { + self.indexStorePath = indexStorePath + self.indexDatabasePath = indexDatabasePath + self.indexPrefixMappings = indexPrefixMappings self.listenToUnitEvents = listenToUnitEvents } } diff --git a/Sources/sourcekit-lsp/main.swift b/Sources/sourcekit-lsp/main.swift index 8f0828d4..361cf52a 100644 --- a/Sources/sourcekit-lsp/main.swift +++ b/Sources/sourcekit-lsp/main.swift @@ -41,6 +41,14 @@ extension AbsolutePath: ExpressibleByArgument { } } +extension PathPrefixMapping: ExpressibleByArgument { + public init?(argument: String) { + guard let eqIndex = argument.firstIndex(of: "=") else { return nil } + self.init(original: String(argument[..) -> Void) { fatalError() diff --git a/Tests/SourceKitLSPTests/BuildSystemTests.swift b/Tests/SourceKitLSPTests/BuildSystemTests.swift index fbaadc83..45318375 100644 --- a/Tests/SourceKitLSPTests/BuildSystemTests.swift +++ b/Tests/SourceKitLSPTests/BuildSystemTests.swift @@ -27,6 +27,7 @@ typealias LSPNotification = LanguageServerProtocol.Notification final class TestBuildSystem: BuildSystem { var indexStorePath: AbsolutePath? = nil var indexDatabasePath: AbsolutePath? = nil + var indexPrefixMappings: [PathPrefixMapping] = [] weak var delegate: BuildSystemDelegate?