From 8617b8bbccdcef3e2cc7c9f4ca7e99cfeb040e1e Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Wed, 15 Jan 2025 09:54:20 -0800 Subject: [PATCH] Do not realpath the project root of a `SwiftPMBuildSystem` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you have a package located at `/pkg` and a symlink at `/symlink` and you open `/symlink` as a workspace, the SwiftPMBuildSystem’s project root would be `/pkg`. This would mean that it also only knew about build settings for files in `/pkg`, not in `/symlink`. Thus, whenever we were opening a file in `/symlink` we would create an implicit workspace to handle it (but which ended up having a project root at `/symlink` again) – or something close to this. We shouldn’t need to realpath here. If you open `/symlink`, we should view `/symlink` as the project root of your workspace. --- .../SwiftPMBuildSystem.swift | 4 +-- .../SwiftPMBuildSystemTests.swift | 27 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift b/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift index c8e92edc..18c92809 100644 --- a/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift +++ b/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift @@ -169,9 +169,7 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem { private var targetDependencies: [BuildTargetIdentifier: Set] = [:] static package func projectRoot(for path: URL, options: SourceKitLSPOptions) -> URL? { - guard var path = orLog("Getting realpath for project root", { try path.realpath }) else { - return nil - } + var path = path while true { let packagePath = path.appendingPathComponent("Package.swift") if (try? String(contentsOf: packagePath, encoding: .utf8))?.contains("PackageDescription") ?? false { diff --git a/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift b/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift index 213450c7..05616f9e 100644 --- a/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift +++ b/Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift @@ -806,28 +806,21 @@ final class SwiftPMBuildSystemTests: XCTestCase { fallbackAfterTimeout: false ) ).compilerArguments - let argumentsFromReal = try await unwrap( - buildSystemManager.buildSettingsInferredFromMainFile( - for: DocumentURI(aswiftReal), - language: .swift, - fallbackAfterTimeout: false - ) - ).compilerArguments - // The arguments retrieved from the symlink and the real document should be the same, except that both should - // contain they file the build settings were created. - // FIXME: Or should the build settings always reference the main file? - XCTAssertEqual( - try argumentsFromSymlink.filter { try $0 != aswiftSymlink.filePath && $0 != aswiftReal.filePath }, - try argumentsFromReal.filter { try $0 != aswiftSymlink.filePath && $0 != aswiftReal.filePath } + // We opened the project from a symlink. The realpath isn't part of the project and we should thus not receive + // build settings for it. + assertTrue( + try await unwrap( + buildSystemManager.buildSettingsInferredFromMainFile( + for: DocumentURI(aswiftReal), + language: .swift, + fallbackAfterTimeout: false + ) + ).isFallback ) - assertArgumentsContain(try aswiftSymlink.filePath, arguments: argumentsFromSymlink) assertArgumentsDoNotContain(try aswiftReal.filePath, arguments: argumentsFromSymlink) - assertArgumentsContain(try aswiftReal.filePath, arguments: argumentsFromReal) - assertArgumentsDoNotContain(try aswiftSymlink.filePath, arguments: argumentsFromReal) - let argsManifest = try await unwrap( buildSystemManager.buildSettingsInferredFromMainFile( for: DocumentURI(manifest),