Skip to content

Commit aa0aa92

Browse files
committed
Stop using TSCBasic.resolveSymlinks and URL.resolvingSymlinksInPath
1 parent dd95a3d commit aa0aa92

12 files changed

+109
-83
lines changed

Sources/BuildSystemIntegration/BuildSystemManager.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ package import ToolchainRegistry
2323

2424
package import struct TSCBasic.AbsolutePath
2525
package import struct TSCBasic.RelativePath
26-
package import func TSCBasic.resolveSymlinks
2726
#else
2827
import BuildServerProtocol
2928
import Dispatch
@@ -37,7 +36,6 @@ import ToolchainRegistry
3736

3837
import struct TSCBasic.AbsolutePath
3938
import struct TSCBasic.RelativePath
40-
import func TSCBasic.resolveSymlinks
4139
#endif
4240

4341
fileprivate typealias RequestCache<Request: RequestType & Hashable> = Cache<Request, Request.Response>
@@ -96,18 +94,6 @@ fileprivate extension BuildTarget {
9694
}
9795
}
9896

99-
fileprivate extension DocumentURI {
100-
/// If this is a file URI pointing to a symlink, return the realpath of the URI, otherwise return `nil`.
101-
var symlinkTarget: DocumentURI? {
102-
guard let fileUrl = fileURL, let path = AbsolutePath(validatingOrNil: fileUrl.path),
103-
let symlinksResolved = try? TSCBasic.resolveSymlinks(path), symlinksResolved != path
104-
else {
105-
return nil
106-
}
107-
return DocumentURI(symlinksResolved.asURL)
108-
}
109-
}
110-
11197
fileprivate extension InitializeBuildResponse {
11298
var sourceKitData: SourceKitInitializeBuildResponseData? {
11399
guard dataKind == nil || dataKind == .sourceKit else {

Sources/BuildSystemIntegration/CompilationDatabase.swift

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package import struct TSCBasic.AbsolutePath
2121
package import protocol TSCBasic.FileSystem
2222
package import struct TSCBasic.RelativePath
2323
package import var TSCBasic.localFileSystem
24-
package import func TSCBasic.resolveSymlinks
2524
#else
2625
import BuildServerProtocol
2726
import Foundation
@@ -33,7 +32,6 @@ import struct TSCBasic.AbsolutePath
3332
import protocol TSCBasic.FileSystem
3433
import struct TSCBasic.RelativePath
3534
import var TSCBasic.localFileSystem
36-
import func TSCBasic.resolveSymlinks
3735
#endif
3836

3937
/// A single compilation database command.
@@ -262,7 +260,7 @@ package struct JSONCompilationDatabase: CompilationDatabase, Equatable, Codable
262260
if let indices = pathToCommands[uri] {
263261
return indices.map { commands[$0] }
264262
}
265-
if let fileURL = uri.fileURL, let indices = pathToCommands[DocumentURI(fileURL.resolvingSymlinksInPath())] {
263+
if let fileURL = uri.fileURL, let indices = pathToCommands[DocumentURI(fileURL.realpath)] {
266264
return indices.map { commands[$0] }
267265
}
268266
return []
@@ -278,13 +276,8 @@ package struct JSONCompilationDatabase: CompilationDatabase, Equatable, Codable
278276
let uri = command.uri
279277
pathToCommands[uri, default: []].append(commands.count)
280278

281-
if let fileURL = uri.fileURL,
282-
let symlinksResolved = try? resolveSymlinks(AbsolutePath(validating: fileURL.path))
283-
{
284-
let canonical = DocumentURI(filePath: symlinksResolved.pathString, isDirectory: false)
285-
if canonical != uri {
286-
pathToCommands[canonical, default: []].append(commands.count)
287-
}
279+
if let symlinkTarget = uri.symlinkTarget {
280+
pathToCommands[symlinkTarget, default: []].append(commands.count)
288281
}
289282

290283
commands.append(command)

Sources/BuildSystemIntegration/DetermineBuildSystem.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ package func determineBuildSystem(
5757
return .compilationDatabase(projectRoot: projectRoot)
5858
}
5959
case .swiftPM:
60-
if let projectRoot = SwiftPMBuildSystem.projectRoot(for: workspaceFolderPath, options: options) {
60+
if let projectRootURL = SwiftPMBuildSystem.projectRoot(for: workspaceFolderUrl, options: options),
61+
let projectRoot = try? AbsolutePath(validating: projectRootURL.path)
62+
{
6163
return .swiftPM(projectRoot: projectRoot)
6264
}
6365
}

Sources/BuildSystemIntegration/LegacyBuildServerBuildSystem.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import struct TSCBasic.FileSystemError
2626
import func TSCBasic.getEnvSearchPaths
2727
import var TSCBasic.localFileSystem
2828
import func TSCBasic.lookupExecutablePath
29-
import func TSCBasic.resolveSymlinks
3029

3130
#if compiler(>=6.3)
3231
#warning("We have had a one year transition period to the pull based build server. Consider removing this build server")

Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ package import Basics
1515
@preconcurrency import Build
1616
package import BuildServerProtocol
1717
import Dispatch
18-
import Foundation
18+
package import Foundation
1919
package import LanguageServerProtocol
2020
@preconcurrency import PackageGraph
2121
import PackageLoading
@@ -33,12 +33,10 @@ package import ToolchainRegistry
3333
package import struct Basics.AbsolutePath
3434
package import struct Basics.IdentifiableSet
3535
package import struct Basics.TSCAbsolutePath
36-
import struct Foundation.URL
37-
package import struct TSCBasic.AbsolutePath
38-
package import protocol TSCBasic.FileSystem
39-
package import class TSCBasic.Process
40-
package import var TSCBasic.localFileSystem
41-
package import func TSCBasic.resolveSymlinks
36+
import struct TSCBasic.AbsolutePath
37+
import protocol TSCBasic.FileSystem
38+
import class TSCBasic.Process
39+
import var TSCBasic.localFileSystem
4240
package import class ToolchainRegistry.Toolchain
4341
#else
4442
import Basics
@@ -68,7 +66,6 @@ import struct TSCBasic.AbsolutePath
6866
import protocol TSCBasic.FileSystem
6967
import class TSCBasic.Process
7068
import var TSCBasic.localFileSystem
71-
import func TSCBasic.resolveSymlinks
7269
import class ToolchainRegistry.Toolchain
7370
#endif
7471

@@ -240,26 +237,18 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
240237

241238
private var targetDependencies: [BuildTargetIdentifier: Set<BuildTargetIdentifier>] = [:]
242239

243-
static package func projectRoot(
244-
for path: TSCBasic.AbsolutePath,
245-
options: SourceKitLSPOptions
246-
) -> TSCBasic.AbsolutePath? {
247-
guard var path = try? resolveSymlinks(path) else {
248-
return nil
249-
}
240+
static package func projectRoot(for path: URL, options: SourceKitLSPOptions) -> URL? {
241+
var path = path.realpath
250242
while true {
251243
let packagePath = path.appending(component: "Package.swift")
252-
if localFileSystem.isFile(packagePath) {
253-
let contents = try? localFileSystem.readFileContents(packagePath)
254-
if contents?.cString.contains("PackageDescription") == true {
255-
return path
256-
}
244+
if (try? String(contentsOf: packagePath, encoding: .utf8))?.contains("PackageDescription") ?? false {
245+
return path
257246
}
258247

259-
if path.isRoot {
260-
return nil
248+
if (try? AbsolutePath(validating: path.path))?.isRoot ?? true {
249+
break
261250
}
262-
path = path.parentDirectory
251+
path.deleteLastPathComponent()
263252
}
264253
return nil
265254
}
@@ -611,7 +600,7 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem {
611600
let buildSettings = FileBuildSettings(
612601
compilerArguments: try await compilerArguments(for: DocumentURI(substituteFile), in: swiftPMTarget),
613602
workingDirectory: projectRoot.pathString
614-
).patching(newFile: DocumentURI(try resolveSymlinks(path).asURL), originalFile: DocumentURI(substituteFile))
603+
).patching(newFile: DocumentURI(path.asURL.realpath), originalFile: DocumentURI(substituteFile))
615604
return TextDocumentSourceKitOptionsResponse(
616605
compilerArguments: buildSettings.compilerArguments,
617606
workingDirectory: buildSettings.workingDirectory

Sources/Diagnose/ReproducerBundle.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func makeReproducerBundle(for requestInfo: RequestInfo, toolchain: Toolchain, bu
2626
encoding: .utf8
2727
)
2828
if let toolchainPath = toolchain.path {
29-
try toolchainPath.asURL.resolvingSymlinksInPath().path
29+
try toolchainPath.asURL.realpath.path
3030
.write(
3131
to: bundlePath.appendingPathComponent("toolchain.txt"),
3232
atomically: true,

Sources/SKSupport/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_library(SKSupport STATIC
66
Debouncer.swift
77
Dictionary+InitWithElementsKeyedBy.swift
88
DocumentURI+CustomLogStringConvertible.swift
9+
DocumentURI+symlinkTarget.swift
910
FileSystem.swift
1011
LineTable.swift
1112
LocalConnection.swift
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if compiler(>=6)
14+
import Foundation
15+
package import LanguageServerProtocol
16+
import struct TSCBasic.AbsolutePath
17+
#else
18+
import Foundation
19+
import LanguageServerProtocol
20+
21+
import struct TSCBasic.RelativePath
22+
#endif
23+
24+
extension DocumentURI {
25+
/// If this is a file URI pointing to a symlink, return the realpath of the URI, otherwise return `nil`.
26+
package var symlinkTarget: DocumentURI? {
27+
guard let fileUrl = fileURL else {
28+
return nil
29+
}
30+
let realpath = fileUrl.realpath
31+
if realpath == fileURL {
32+
return nil
33+
}
34+
return DocumentURI(realpath)
35+
}
36+
}

Sources/SKTestSupport/Utils.swift

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
#if compiler(>=6)
1414
package import Foundation
1515
package import LanguageServerProtocol
16+
import SwiftExtensions
1617
package import struct TSCBasic.AbsolutePath
1718
#else
1819
import Foundation
1920
import LanguageServerProtocol
21+
import SwiftExtensions
2022
import struct TSCBasic.AbsolutePath
2123
#endif
2224

@@ -94,31 +96,6 @@ package func withTestScratchDir<T>(
9496
return try await body(try AbsolutePath(validating: scratchDirectory.path))
9597
}
9698

97-
fileprivate extension URL {
98-
/// Assuming this is a file URL, resolves all symlinks in the path.
99-
///
100-
/// - Note: We need this because `URL.resolvingSymlinksInPath()` not only resolves symlinks but also standardizes the
101-
/// path by stripping away `private` prefixes. Since sourcekitd is not performing this standardization, using
102-
/// `resolvingSymlinksInPath` can lead to slightly mismatched URLs between the sourcekit-lsp response and the test
103-
/// assertion.
104-
var realpath: URL {
105-
#if canImport(Darwin)
106-
return self.path.withCString { path in
107-
guard let realpath = Darwin.realpath(path, nil) else {
108-
return self
109-
}
110-
let result = URL(fileURLWithPath: String(cString: realpath))
111-
free(realpath)
112-
return result
113-
}
114-
#else
115-
// Non-Darwin platforms don't have the `/private` stripping issue, so we can just use `self.resolvingSymlinksInPath`
116-
// here.
117-
return self.resolvingSymlinksInPath()
118-
#endif
119-
}
120-
}
121-
12299
let globalModuleCache: URL? = {
123100
if let customModuleCache = ProcessInfo.processInfo.environment["SOURCEKIT_LSP_TEST_MODULE_CACHE"] {
124101
if customModuleCache.isEmpty {

Sources/SwiftExtensions/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_library(SwiftExtensions STATIC
1616
Task+WithPriorityChangedHandler.swift
1717
ThreadSafeBox.swift
1818
TransitiveClosure.swift
19+
URL+realpath.swift
1920
)
2021
set_target_properties(SwiftExtensions PROPERTIES
2122
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if compiler(>=6)
14+
package import Foundation
15+
#else
16+
import Foundation
17+
#endif
18+
19+
extension URL {
20+
/// Assuming this is a file URL, resolves all symlinks in the path.
21+
///
22+
/// - Note: We need this because `URL.resolvingSymlinksInPath()` not only resolves symlinks but also standardizes the
23+
/// path by stripping away `private` prefixes. Since sourcekitd is not performing this standardization, using
24+
/// `resolvingSymlinksInPath` can lead to slightly mismatched URLs between the sourcekit-lsp response and the test
25+
/// assertion.
26+
package var realpath: URL {
27+
#if canImport(Darwin)
28+
return self.path.withCString { path in
29+
guard let realpath = Darwin.realpath(path, nil) else {
30+
return self
31+
}
32+
let result = URL(fileURLWithPath: String(cString: realpath))
33+
free(realpath)
34+
return result
35+
}
36+
#else
37+
// Non-Darwin platforms don't have the `/private` stripping issue, so we can just use `self.resolvingSymlinksInPath`
38+
// here.
39+
return self.resolvingSymlinksInPath()
40+
#endif
41+
}
42+
}

Tests/BuildSystemIntegrationTests/SwiftPMBuildSystemTests.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ final class SwiftPMBuildSystemTests: XCTestCase {
5555
]
5656
)
5757
let packageRoot = tempDir.appending(component: "pkg")
58-
XCTAssertNil(SwiftPMBuildSystem.projectRoot(for: packageRoot, options: .testDefault()))
58+
XCTAssertNil(SwiftPMBuildSystem.projectRoot(for: packageRoot.asURL, options: .testDefault()))
5959
}
6060
}
6161

@@ -621,9 +621,9 @@ final class SwiftPMBuildSystemTests: XCTestCase {
621621
withDestinationURL: URL(fileURLWithPath: tempDir.appending(component: "pkg_real").pathString)
622622
)
623623

624-
let projectRoot = try XCTUnwrap(SwiftPMBuildSystem.projectRoot(for: packageRoot, options: .testDefault()))
624+
let projectRoot = try XCTUnwrap(SwiftPMBuildSystem.projectRoot(for: packageRoot.asURL, options: .testDefault()))
625625
let buildSystemManager = await BuildSystemManager(
626-
buildSystemKind: .swiftPM(projectRoot: projectRoot),
626+
buildSystemKind: .swiftPM(projectRoot: try AbsolutePath(validating: projectRoot.path)),
627627
toolchainRegistry: .forTesting,
628628
options: SourceKitLSPOptions(),
629629
connectionToClient: DummyBuildSystemManagerConnectionToClient(),
@@ -697,9 +697,9 @@ final class SwiftPMBuildSystemTests: XCTestCase {
697697
withDestinationURL: URL(fileURLWithPath: tempDir.appending(component: "pkg_real").pathString)
698698
)
699699

700-
let projectRoot = try XCTUnwrap(SwiftPMBuildSystem.projectRoot(for: symlinkRoot, options: .testDefault()))
700+
let projectRoot = try XCTUnwrap(SwiftPMBuildSystem.projectRoot(for: symlinkRoot.asURL, options: .testDefault()))
701701
let buildSystemManager = await BuildSystemManager(
702-
buildSystemKind: .swiftPM(projectRoot: projectRoot),
702+
buildSystemKind: .swiftPM(projectRoot: try AbsolutePath(validating: projectRoot.path)),
703703
toolchainRegistry: .forTesting,
704704
options: SourceKitLSPOptions(),
705705
connectionToClient: DummyBuildSystemManagerConnectionToClient(),
@@ -779,10 +779,10 @@ final class SwiftPMBuildSystemTests: XCTestCase {
779779
""",
780780
]
781781
)
782-
let workspaceRoot = try resolveSymlinks(tempDir.appending(components: "pkg", "Sources", "lib"))
782+
let workspaceRoot = tempDir.appending(components: "pkg", "Sources", "lib").asURL
783783
let projectRoot = SwiftPMBuildSystem.projectRoot(for: workspaceRoot, options: .testDefault())
784784

785-
assertEqual(projectRoot, try resolveSymlinks(tempDir.appending(component: "pkg")))
785+
assertEqual(projectRoot, tempDir.appending(component: "pkg").asURL)
786786
}
787787
}
788788

0 commit comments

Comments
 (0)