Skip to content

Commit d82d0d0

Browse files
authored
Merge pull request swiftlang#139 from benlangmuir/find-your-inner-toolchain
[sourcekit-lsp] Prefer containing toolchain if applicable
2 parents c868ec6 + a74933f commit d82d0d0

File tree

5 files changed

+80
-25
lines changed

5 files changed

+80
-25
lines changed

Sources/SKCore/Toolchain.swift

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,14 @@ extension Toolchain {
9393
/// * `path/bin`, `path/lib`
9494
/// * `path/usr/bin`, `path/usr/lib`
9595
///
96-
/// If `path` has an ".xctoolchain" extension, we try to read an Info.plist file to provide the
96+
/// If `path` contains an ".xctoolchain", we try to read an Info.plist file to provide the
9797
/// toolchain identifier, etc. Otherwise this information is derived from the path.
9898
convenience public init?(_ path: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) {
99-
if path.extension == "xctoolchain",
100-
let infoPlist = orLog("", {
101-
try XCToolchainPlist(fromDirectory: path, fileSystem) })
102-
{
103-
self.init(
104-
identifier: infoPlist.identifier,
105-
displayName:
106-
infoPlist.displayName ?? String(path.basename.dropLast(path.suffix?.count ?? 0)),
107-
path: path)
99+
if let (infoPlist, xctoolchainPath) = containingXCToolchain(path, fileSystem) {
100+
let displayName = infoPlist.displayName ?? xctoolchainPath.basenameWithoutExt
101+
self.init(identifier: infoPlist.identifier, displayName: displayName, path: xctoolchainPath)
108102
} else {
109-
self.init(
110-
identifier: path.pathString,
111-
displayName: path.basename,
112-
path: path)
103+
self.init(identifier: path.pathString, displayName: path.basename, path: path)
113104
}
114105

115106
if !searchForTools(path, fileSystem) {
@@ -175,3 +166,21 @@ extension Toolchain {
175166
return foundAny
176167
}
177168
}
169+
170+
/// Find a containing xctoolchain with plist, if available.
171+
func containingXCToolchain(
172+
_ path: AbsolutePath,
173+
_ fileSystem: FileSystem) -> (XCToolchainPlist, AbsolutePath)?
174+
{
175+
var path = path
176+
while !path.isRoot {
177+
if path.extension == "xctoolchain" {
178+
if let infoPlist = orLog("", { try XCToolchainPlist(fromDirectory: path, fileSystem) }) {
179+
return (infoPlist, path)
180+
}
181+
return nil
182+
}
183+
path = path.parentDirectory
184+
}
185+
return nil
186+
}

Sources/SKCore/ToolchainRegistry.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ extension ToolchainRegistry {
6868
///
6969
/// If called with the default values, creates a toolchain registry that searches:
7070
/// * env SOURCEKIT_TOOLCHAIN_PATH <-- will override default toolchain
71+
/// * installPath <-- will override default toolchain
7172
/// * (Darwin) The currently selected Xcode
7273
/// * (Darwin) [~]/Library/Developer/Toolchains
7374
/// * env SOURCEKIT_PATH, PATH
@@ -77,9 +78,9 @@ extension ToolchainRegistry {
7778
/// let tr = ToolchainRegistry()
7879
/// tr.scanForToolchains()
7980
/// ```
80-
public convenience init(_ fileSystem: FileSystem) {
81+
public convenience init(installPath: AbsolutePath? = nil, _ fileSystem: FileSystem) {
8182
self.init()
82-
scanForToolchains(fileSystem)
83+
scanForToolchains(installPath: installPath, fileSystem)
8384
}
8485
}
8586

@@ -222,18 +223,12 @@ extension ToolchainRegistry {
222223
///
223224
/// If called with the default values, creates a toolchain registry that searches:
224225
/// * env SOURCEKIT_TOOLCHAIN_PATH <-- will override default toolchain
226+
/// * installPath <-- will override default toolchain
225227
/// * (Darwin) The currently selected Xcode
226228
/// * (Darwin) [~]/Library/Developer/Toolchains
227229
/// * env SOURCEKIT_PATH, PATH
228-
///
229-
/// This is equivalent to
230-
/// ```
231-
/// tr.scanForToolchains(environmentVariables: environmentVariables, setDefault: true)
232-
/// xcodes.forEach { tr.scanForToolchains(xcode: $0) }
233-
/// xctoolchainSearchPaths.forEach { tr.scanForToolchains(xctoolchainSearchPath: $0) }
234-
/// tr.scanForToolchains(pathVariables: pathVariables)
235-
/// ```
236230
public func scanForToolchains(
231+
installPath: AbsolutePath? = nil,
237232
environmentVariables: [String] = ["SOURCEKIT_TOOLCHAIN_PATH"],
238233
xcodes: [AbsolutePath] = [currentXcodeDeveloperPath].compactMap({$0}),
239234
xctoolchainSearchPaths: [AbsolutePath] = [
@@ -245,6 +240,12 @@ extension ToolchainRegistry {
245240
{
246241
queue.sync {
247242
_scanForToolchains(environmentVariables: environmentVariables, setDefault: true, fileSystem)
243+
if let installPath = installPath,
244+
let toolchain = try? _registerToolchain(installPath, fileSystem),
245+
_default == nil
246+
{
247+
_default = toolchain
248+
}
248249
xcodes.forEach { _scanForToolchains(xcode: $0, fileSystem) }
249250
xctoolchainSearchPaths.forEach { _scanForToolchains(xctoolchainSearchPath: $0, fileSystem) }
250251
_scanForToolchains(pathVariables: pathVariables, fileSystem)

Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public final class SwiftPMWorkspace {
6969

7070
self.packageRoot = resolveSymlinks(packageRoot)
7171

72-
guard let destinationToolchainBinDir = toolchainRegistry.default?.path?.appending(components: "usr", "bin") else {
72+
guard let destinationToolchainBinDir = toolchainRegistry.default?.swiftc?.parentDirectory else {
7373
throw Error.cannotDetermineHostToolchain
7474
}
7575

Sources/sourcekit-lsp/main.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ do {
6969
exit(1)
7070
}
7171

72+
let installPath = AbsolutePath(Bundle.main.bundlePath)
73+
ToolchainRegistry.shared = ToolchainRegistry(installPath: installPath, localFileSystem)
74+
7275
let server = SourceKitServer(client: clientConnection, buildSetup: buildSetup, onExit: {
7376
clientConnection.close()
7477
})

Tests/SKCoreTests/ToolchainRegistryTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ final class ToolchainRegistryTests: XCTestCase {
165165
XCTAssertNotNil(tc)
166166
XCTAssertEqual(tc?.identifier, "org.fake.explicit")
167167

168+
let tcBin = Toolchain(path.appending(components: "usr", "bin"), fs)
169+
XCTAssertNotNil(tcBin)
170+
XCTAssertEqual(tc?.identifier, tcBin?.identifier)
171+
XCTAssertEqual(tc?.path, tcBin?.path)
172+
XCTAssertEqual(tc?.displayName, tcBin?.displayName)
173+
174+
175+
let trInstall = ToolchainRegistry()
176+
trInstall.scanForToolchains(installPath: path.appending(components: "usr", "bin"), environmentVariables: [], xcodes: [], xctoolchainSearchPaths: [], pathVariables: [], fs)
177+
XCTAssertEqual(trInstall.default?.identifier, "org.fake.explicit")
178+
XCTAssertEqual(trInstall.default?.path, path)
179+
168180
let overrideReg = ToolchainRegistry(fs)
169181
overrideReg.darwinToolchainOverride = "org.fake.global.B"
170182
XCTAssertEqual(overrideReg.darwinToolchainIdentifier, "org.fake.global.B")
@@ -412,6 +424,36 @@ final class ToolchainRegistryTests: XCTestCase {
412424
XCTAssert(toolchains[0] === xcodeA)
413425
XCTAssert(toolchains[1] === xcodeB)
414426
}
427+
428+
func testInstallPath() {
429+
let fs = InMemoryFileSystem()
430+
makeToolchain(binPath: AbsolutePath("/t1/bin"), fs, sourcekitd: true)
431+
432+
let trEmpty = ToolchainRegistry(installPath: nil, fs)
433+
XCTAssertNil(trEmpty.default)
434+
435+
let tr1 = ToolchainRegistry(installPath: AbsolutePath("/t1/bin"), fs)
436+
XCTAssertEqual(tr1.default?.path, AbsolutePath("/t1/bin"))
437+
XCTAssertNotNil(tr1.default?.sourcekitd)
438+
439+
let tr2 = ToolchainRegistry(installPath: AbsolutePath("/t2/bin"), fs)
440+
XCTAssertNil(tr2.default)
441+
}
442+
443+
func testInstallPathVsEnv() {
444+
let fs = InMemoryFileSystem()
445+
makeToolchain(binPath: AbsolutePath("/t1/bin"), fs, sourcekitd: true)
446+
makeToolchain(binPath: AbsolutePath("/t2/bin"), fs, sourcekitd: true)
447+
448+
try! ProcessEnv.setVar("TEST_SOURCEKIT_TOOLCHAIN_PATH_1", value: "/t2/bin")
449+
450+
let tr = ToolchainRegistry()
451+
tr.scanForToolchains(installPath: AbsolutePath("/t1/bin"), environmentVariables: ["TEST_SOURCEKIT_TOOLCHAIN_PATH_1"], fs)
452+
XCTAssertEqual(tr.toolchains.count, 2)
453+
454+
// Env variable wins.
455+
XCTAssertEqual(tr.default?.path, AbsolutePath("/t2/bin"))
456+
}
415457
}
416458

417459
#if os(macOS)

0 commit comments

Comments
 (0)