Skip to content

Commit 6c5164c

Browse files
committed
Remove swiftly from the path during proxying
Retaining swiftly in the path increases the probability that a tool might run the proxy again, resulting in circularities. Also, tools will locate programs in the path to try and find adjacent toolchain files that cannot be discovered in the swiftly bin directory. Remove the swiftly bin directory from the path when proxying to help improve the experience with other tools.
1 parent 2cedc32 commit 6c5164c

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

Sources/SwiftlyCore/Platform.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,19 +135,26 @@ extension Platform {
135135
}
136136

137137
#if os(macOS) || os(Linux)
138-
func proxyEnv(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion) throws -> [String: String] {
138+
func proxyEnv(_ ctx: SwiftlyCoreContext, env: [String: String], toolchain: ToolchainVersion) throws -> [String: String] {
139+
var newEnv = env
140+
139141
let tcPath = self.findToolchainLocation(ctx, toolchain).appendingPathComponent("usr/bin")
140142
guard tcPath.fileExists() else {
141143
throw SwiftlyError(message: "Toolchain \(toolchain) could not be located. You can try `swiftly uninstall \(toolchain)` to uninstall it and then `swiftly install \(toolchain)` to install it again.")
142144
}
143-
var newEnv = ProcessInfo.processInfo.environment
145+
146+
var pathComponents = (newEnv["PATH"] ?? "").split(separator: ":").map { String($0) }
144147

145148
// The toolchain goes to the beginning of the PATH
146-
var newPath = newEnv["PATH"] ?? ""
147-
if !newPath.hasPrefix(tcPath.path + ":") {
148-
newPath = "\(tcPath.path):\(newPath)"
149+
if pathComponents.first ?? "" != tcPath.path {
150+
pathComponents = [tcPath.path] + pathComponents
149151
}
150-
newEnv["PATH"] = newPath
152+
153+
// Remove swiftly bin directory from the PATH
154+
let swiftlyBinDir = self.swiftlyBinDir(ctx).path
155+
pathComponents.removeAll(where: { $0 == swiftlyBinDir })
156+
157+
newEnv["PATH"] = String(pathComponents.joined(by: ":"))
151158

152159
return newEnv
153160
}
@@ -158,7 +165,7 @@ extension Platform {
158165
/// the exit code and program information.
159166
///
160167
public func proxy(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion, _ command: String, _ arguments: [String], _ env: [String: String] = [:]) async throws {
161-
var newEnv = try self.proxyEnv(ctx, toolchain)
168+
var newEnv = try self.proxyEnv(ctx, env: ProcessInfo.processInfo.environment, toolchain: toolchain)
162169
for (key, value) in env {
163170
newEnv[key] = value
164171
}
@@ -171,7 +178,7 @@ extension Platform {
171178
/// the exit code and program information.
172179
///
173180
public func proxyOutput(_ ctx: SwiftlyCoreContext, _ toolchain: ToolchainVersion, _ command: String, _ arguments: [String]) async throws -> String? {
174-
try await self.runProgramOutput(command, arguments, env: self.proxyEnv(ctx, toolchain))
181+
try await self.runProgramOutput(command, arguments, env: self.proxyEnv(ctx, env: ProcessInfo.processInfo.environment, toolchain: toolchain))
175182
}
176183

177184
/// Run a program.

Tests/SwiftlyTests/PlatformTests.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,30 @@ import Testing
8585
toolchains = try FileManager.default.contentsOfDirectory(at: Swiftly.currentPlatform.swiftlyToolchainsDir(SwiftlyTests.ctx), includingPropertiesForKeys: nil)
8686
#expect(0 == toolchains.count)
8787
}
88+
89+
#if os(macOS) || os(Linux)
90+
@Test(
91+
.mockHomeToolchains(),
92+
arguments: [
93+
"/a/b/c:SWIFTLY_BIN_DIR:/d/e/f",
94+
"SWIFTLY_BIN_DIR:/abcde",
95+
"/defgh:SWIFTLY_BIN_DIR",
96+
"/xyzabc:/1/3/4",
97+
"",
98+
]
99+
) func proxyEnv(_ path: String) async throws {
100+
// GIVEN: a PATH that may contain the swiftly bin directory
101+
let env = ["PATH": path.replacing("SWIFTLY_BIN_DIR", with: Swiftly.currentPlatform.swiftlyBinDir(SwiftlyTests.ctx).path)]
102+
103+
// WHEN: proxying to an installed toolchain
104+
let newEnv = try Swiftly.currentPlatform.proxyEnv(SwiftlyTests.ctx, env: env, toolchain: .newStable)
105+
106+
// THEN: the toolchain's bin directory is added to the beginning of the PATH
107+
#expect(newEnv["PATH"]!.hasPrefix(Swiftly.currentPlatform.findToolchainLocation(SwiftlyTests.ctx, .newStable).appendingPathComponent("usr/bin").path))
108+
109+
// AND: the swiftly bin directory is removed from the PATH
110+
#expect(!newEnv["PATH"]!.contains(Swiftly.currentPlatform.swiftlyBinDir(SwiftlyTests.ctx).path))
111+
#expect(!newEnv["PATH"]!.contains(Swiftly.currentPlatform.swiftlyBinDir(SwiftlyTests.ctx).path))
112+
}
113+
#endif
88114
}

0 commit comments

Comments
 (0)