Do not realpath the project root of a SwiftPMBuildSystem

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.
This commit is contained in:
Alex Hoppen
2025-01-15 09:54:20 -08:00
parent f60752b6f0
commit 8617b8bbcc
2 changed files with 11 additions and 20 deletions

View File

@@ -169,9 +169,7 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
private var targetDependencies: [BuildTargetIdentifier: Set<BuildTargetIdentifier>] = [:]
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 {

View File

@@ -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),