Files
sourcekit-lsp/Sources/SourceKitLSP/CreateBuildSystem.swift
Alex Hoppen f85d821839 Don’t cause any file system file effects when trying to find an implicit workspace for a file
When looking for a workspace that can handle a file, we were creating full-fledged workspaces along the way, which we would then discard if they couldn’t handle the file being opened. This had multiple problems:
1. When background indexing is enabled, it caused semantic indexing of the workspace, which wrote files to a `.index-build` directory and was a waste of work
2. When background indexing is enabled, it caused package resolution, which also created a `.index-build` folder to be created
3. It caused a syntactic test index of the workspace, which was a waste of work.

To fix this, do multiple things:
1. When creating a workspace, add a check right after build system creation. This allows us to early exit if the build system can’t handle the file and prevents us from generating the `Workspace`, fixing (1) and (3)
2. Don’t call `reloadPackage` when creating a `SwiftPMWorkspace`. Instead, explicitly call `generateBuildGraph` once we committed to creating the workspace.
2024-05-28 08:29:55 -07:00

77 lines
3.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 LSPLogging
import LanguageServerProtocol
import SKCore
import SKSwiftPMWorkspace
import struct TSCBasic.AbsolutePath
import struct TSCBasic.RelativePath
/// Tries to create a build system for a workspace at the given location, with the given parameters.
func createBuildSystem(
rootUri: DocumentURI,
options: SourceKitLSPServer.Options,
toolchainRegistry: ToolchainRegistry,
reloadPackageStatusCallback: @Sendable @escaping (ReloadPackageStatus) async -> Void
) async -> BuildSystem? {
guard let rootUrl = rootUri.fileURL, let rootPath = try? AbsolutePath(validating: rootUrl.path) else {
// We assume that workspaces are directories. This is only true for URLs not for URIs in general.
// Simply skip setting up the build integration in this case.
logger.error(
"cannot setup build integration at URI \(rootUri.forLogging) because the URI it is not a valid file URL"
)
return nil
}
func createSwiftPMBuildSystem(rootUrl: URL) async -> SwiftPMBuildSystem? {
return await SwiftPMBuildSystem(
url: rootUrl,
toolchainRegistry: toolchainRegistry,
buildSetup: options.buildSetup,
isForIndexBuild: options.indexOptions.enableBackgroundIndexing,
reloadPackageStatusCallback: reloadPackageStatusCallback
)
}
func createCompilationDatabaseBuildSystem(rootPath: AbsolutePath) -> CompilationDatabaseBuildSystem? {
return CompilationDatabaseBuildSystem(
projectRoot: rootPath,
searchPaths: options.compilationDatabaseSearchPaths
)
}
func createBuildServerBuildSystem(rootPath: AbsolutePath) async -> BuildServerBuildSystem? {
return await BuildServerBuildSystem(projectRoot: rootPath, buildSetup: options.buildSetup)
}
let defaultBuildSystem: BuildSystem? =
switch options.buildSetup.defaultWorkspaceType {
case .buildServer: await createBuildServerBuildSystem(rootPath: rootPath)
case .compilationDatabase: createCompilationDatabaseBuildSystem(rootPath: rootPath)
case .swiftPM: await createSwiftPMBuildSystem(rootUrl: rootUrl)
case nil: nil
}
if let defaultBuildSystem {
return defaultBuildSystem
} else if let buildServer = await createBuildServerBuildSystem(rootPath: rootPath) {
return buildServer
} else if let swiftpm = await createSwiftPMBuildSystem(rootUrl: rootUrl) {
return swiftpm
} else if let compdb = createCompilationDatabaseBuildSystem(rootPath: rootPath) {
return compdb
} else {
logger.error("Could not set up a build system at '\(rootUri.forLogging)'")
return nil
}
}