From 90abe905cf08c9496ff19b29184aa7be0b1197e7 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Fri, 20 Jun 2025 13:49:25 -0400 Subject: [PATCH 1/5] Resolve the swiftly bin path Was failing to compute the correct lldb-dap path because the user had pointed `swift.path` to `~/.swiftly/bin`. When resolving the path, lldb-dap path ends up being computed as `$PWD/lldb-dap`. To get around this, if we know the provided path is a swiftly bin directory, then resolve the correct swift path and toolchain path using built-in swiftly commands Issue: #1619 --- src/toolchain/toolchain.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/toolchain/toolchain.ts b/src/toolchain/toolchain.ts index 7eb9815f2..19b1f2ebd 100644 --- a/src/toolchain/toolchain.ts +++ b/src/toolchain/toolchain.ts @@ -20,7 +20,7 @@ import * as vscode from "vscode"; import configuration from "../configuration"; import { SwiftOutputChannel } from "../ui/SwiftOutputChannel"; import { execFile, ExecFileError, execSwift } from "../utilities/utilities"; -import { expandFilePathTilde, pathExists } from "../utilities/filesystem"; +import { expandFilePathTilde, fileExists, pathExists } from "../utilities/filesystem"; import { Version } from "../utilities/version"; import { BuildFlags } from "./BuildFlags"; import { Sanitizer } from "./Sanitizer"; @@ -605,7 +605,15 @@ export class SwiftToolchain { } } // swift may be a symbolic link - const realSwift = await fs.realpath(swift); + let realSwift = await fs.realpath(swift); + if (path.basename(realSwift) === "swiftly") { + try { + const { stdout } = await execFile(realSwift, ["run", "which", "swift"]); + realSwift = stdout.trim(); + } catch { + // Ignore + } + } const swiftPath = expandFilePathTilde(path.dirname(realSwift)); return await this.getSwiftEnvPath(swiftPath); } catch { @@ -645,7 +653,20 @@ export class SwiftToolchain { try { switch (process.platform) { case "darwin": { - if (configuration.path !== "") { + const configPath = configuration.path; + if (configPath !== "") { + const swiftlyPath = path.join(configPath, "swiftly"); + if (await fileExists(swiftlyPath)) { + try { + const { stdout } = await execFile(swiftlyPath, ["use", "--print-location"]); + const toolchainPath = path.join(stdout.trim(), "usr"); + if (await pathExists(toolchainPath)) { + return toolchainPath; + } + } catch { + // Ignore + } + } return path.dirname(configuration.path); } From 2938fe0ac5e353c139409fcd0a16b29d81d34474 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Fri, 20 Jun 2025 14:00:40 -0400 Subject: [PATCH 2/5] Fix formatting --- src/toolchain/toolchain.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/toolchain/toolchain.ts b/src/toolchain/toolchain.ts index 19b1f2ebd..68562d892 100644 --- a/src/toolchain/toolchain.ts +++ b/src/toolchain/toolchain.ts @@ -658,7 +658,10 @@ export class SwiftToolchain { const swiftlyPath = path.join(configPath, "swiftly"); if (await fileExists(swiftlyPath)) { try { - const { stdout } = await execFile(swiftlyPath, ["use", "--print-location"]); + const { stdout } = await execFile(swiftlyPath, [ + "use", + "--print-location", + ]); const toolchainPath = path.join(stdout.trim(), "usr"); if (await pathExists(toolchainPath)) { return toolchainPath; From a976e450119687e4965236d0e710480aec64ff34 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 23 Jun 2025 11:01:40 -0400 Subject: [PATCH 3/5] Address review comment Only use the "use --print-location" approach and share this code --- src/toolchain/toolchain.ts | 59 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/src/toolchain/toolchain.ts b/src/toolchain/toolchain.ts index 68562d892..caf014149 100644 --- a/src/toolchain/toolchain.ts +++ b/src/toolchain/toolchain.ts @@ -119,7 +119,7 @@ export class SwiftToolchain { } static async create(folder?: vscode.Uri): Promise { - const swiftFolderPath = await this.getSwiftFolderPath(); + const swiftFolderPath = await this.getSwiftFolderPath(folder); const toolchainPath = await this.getToolchainPath(swiftFolderPath, folder); const targetInfo = await this.getSwiftTargetInfo( this._getToolchainExecutable(toolchainPath, "swift") @@ -562,7 +562,7 @@ export class SwiftToolchain { channel.logDiagnostic(this.diagnostics); } - private static async getSwiftFolderPath(): Promise { + private static async getSwiftFolderPath(cwd?: vscode.Uri): Promise { try { let swift: string; if (configuration.path !== "") { @@ -608,10 +608,12 @@ export class SwiftToolchain { let realSwift = await fs.realpath(swift); if (path.basename(realSwift) === "swiftly") { try { - const { stdout } = await execFile(realSwift, ["run", "which", "swift"]); - realSwift = stdout.trim(); + const inUse = await this.swiftlyInUseLocation(realSwift, cwd); + if (inUse) { + realSwift = path.join(inUse, "usr", "bin", "swift"); + } } catch { - // Ignore + // Ignore, will fall back to original path } } const swiftPath = expandFilePathTilde(path.dirname(realSwift)); @@ -658,22 +660,18 @@ export class SwiftToolchain { const swiftlyPath = path.join(configPath, "swiftly"); if (await fileExists(swiftlyPath)) { try { - const { stdout } = await execFile(swiftlyPath, [ - "use", - "--print-location", - ]); - const toolchainPath = path.join(stdout.trim(), "usr"); - if (await pathExists(toolchainPath)) { - return toolchainPath; + const inUse = await this.swiftlyInUseLocation(swiftlyPath, cwd); + if (inUse) { + return path.join(inUse, "usr"); } } catch { - // Ignore + // Ignore, will fall back to original path } } return path.dirname(configuration.path); } - const swiftlyToolchainLocation = await this.swiftlyToolchainLocation(cwd); + const swiftlyToolchainLocation = await this.swiftlyToolchain(cwd); if (swiftlyToolchainLocation) { return swiftlyToolchainLocation; } @@ -693,12 +691,29 @@ export class SwiftToolchain { } } + private static async swiftlyInUseLocation(swiftlyPath: string, cwd?: vscode.Uri) { + const env: Record = {}; + if (path.isAbsolute(swiftlyPath)) { + env["SWIFTLY_HOME_DIR"] = path.dirname(path.dirname(swiftlyPath)); + env["SWIFTLY_BIN_DIR"] = path.dirname(swiftlyPath); + } + const { stdout: inUse } = await execFile( + swiftlyPath, + ["use", "--print-location"], + { + cwd: cwd?.fsPath, + env, + } + ); + return inUse.trimEnd(); + } + /** * Determine if Swiftly is being used to manage the active toolchain and if so, return * the path to the active toolchain. * @returns The location of the active toolchain if swiftly is being used to manage it. */ - private static async swiftlyToolchainLocation(cwd?: vscode.Uri): Promise { + private static async swiftlyToolchain(cwd?: vscode.Uri): Promise { const swiftlyHomeDir: string | undefined = process.env["SWIFTLY_HOME_DIR"]; if (swiftlyHomeDir) { const { stdout: swiftLocation } = await execFile("which", ["swift"]); @@ -707,17 +722,9 @@ export class SwiftToolchain { // is no cwd specified then it returns the global "inUse" toolchain otherwise // it respects the .swift-version file in the cwd and resolves using that. try { - const { stdout: swiftlyLocation } = await execFile( - "swiftly", - ["use", "--print-location"], - { - cwd: cwd?.fsPath, - } - ); - - const trimmedLocation = swiftlyLocation.trimEnd(); - if (trimmedLocation.length > 0) { - return path.join(trimmedLocation, "usr"); + const inUse = await this.swiftlyInUseLocation("swiftly", cwd); + if (inUse.length > 0) { + return path.join(inUse, "usr"); } } catch (err: unknown) { const error = err as ExecFileError; From 7f4d62e67e906e574fd4a63d7befe311dabea522 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 23 Jun 2025 11:02:31 -0400 Subject: [PATCH 4/5] CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a5bd28e0..27f3be2d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Make sure activation does not fail when `swift.path` is `null` ([#1616](https://github.com/swiftlang/vscode-swift/pull/1616)) - Fix `Swift: Reset Package Dependencies` command on Windows ([#1614](https://github.com/swiftlang/vscode-swift/pull/1614)) - Activate extension when a .swift source file exists in a subfolder ([#1635](https://github.com/swiftlang/vscode-swift/pull/1635)) +- Resolve Swiftly toolchain path ([#1632](https://github.com/swiftlang/vscode-swift/pull/1632)) ## 2.4.0 - 2025-06-11 From a3fc040e28f675db6c7906b8e0ab5b459775fc9b Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 23 Jun 2025 15:04:58 -0400 Subject: [PATCH 5/5] Don't set environment --- src/toolchain/toolchain.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/toolchain/toolchain.ts b/src/toolchain/toolchain.ts index caf014149..f974b1310 100644 --- a/src/toolchain/toolchain.ts +++ b/src/toolchain/toolchain.ts @@ -692,19 +692,9 @@ export class SwiftToolchain { } private static async swiftlyInUseLocation(swiftlyPath: string, cwd?: vscode.Uri) { - const env: Record = {}; - if (path.isAbsolute(swiftlyPath)) { - env["SWIFTLY_HOME_DIR"] = path.dirname(path.dirname(swiftlyPath)); - env["SWIFTLY_BIN_DIR"] = path.dirname(swiftlyPath); - } - const { stdout: inUse } = await execFile( - swiftlyPath, - ["use", "--print-location"], - { - cwd: cwd?.fsPath, - env, - } - ); + const { stdout: inUse } = await execFile(swiftlyPath, ["use", "--print-location"], { + cwd: cwd?.fsPath, + }); return inUse.trimEnd(); }