Skip to content

Commit fb206bd

Browse files
committed
Add macOS support for Swiftly toolchain management
1 parent d4c2470 commit fb206bd

File tree

4 files changed

+109
-5
lines changed

4 files changed

+109
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
### Added
66

7+
- Add macOS support for Swiftly toolchain management ([#1673](https://github.com/swiftlang/vscode-swift/pull/1673))
8+
9+
### Added
10+
711
- Show revision hash or local/editing keyword in project panel dependency descriptions ([#1667](https://github.com/swiftlang/vscode-swift/pull/1667))
812

913
## 2.6.2 - 2025-07-02

src/toolchain/toolchain.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,8 @@ export class SwiftToolchain {
254254
* @returns an array of toolchain paths
255255
*/
256256
public static async getSwiftlyToolchainInstalls(): Promise<string[]> {
257-
// Swiftly is only available on Linux right now
258-
// TODO: Add support for macOS
259-
if (process.platform !== "linux") {
257+
// Swiftly is available on Linux and macOS
258+
if (process.platform !== "linux" && process.platform !== "darwin") {
260259
return [];
261260
}
262261
try {

src/ui/ToolchainSelection.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,12 @@ async function getQuickPickItems(
223223
}
224224
// Various actions that the user can perform (e.g. to install new toolchains)
225225
const actionItems: ActionItem[] = [];
226-
if (process.platform === "linux") {
226+
if (process.platform === "linux" || process.platform === "darwin") {
227+
const platformName = process.platform === "linux" ? "Linux" : "macOS";
227228
actionItems.push({
228229
type: "action",
229230
label: "$(swift-icon) Install Swiftly for toolchain management...",
230-
detail: "Install https://swiftlang.github.io/swiftly to manage your toolchains on Linux",
231+
detail: `Install https://swiftlang.github.io/swiftly to manage your toolchains on ${platformName}`,
231232
run: installSwiftly,
232233
});
233234
}

test/unit-tests/toolchain/toolchain.test.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,104 @@ suite("SwiftToolchain Unit Test Suite", () => {
296296
await expect(SwiftToolchain.findXcodeInstalls()).to.eventually.be.empty;
297297
});
298298
});
299+
300+
suite("getSwiftlyToolchainInstalls()", () => {
301+
const mockedEnv = mockGlobalValue(process, "env");
302+
303+
test("returns installed toolchains on Linux", async () => {
304+
mockedPlatform.setValue("linux");
305+
const mockHomeDir = "/home/user/.swiftly";
306+
mockedEnv.setValue({ SWIFTLY_HOME_DIR: mockHomeDir });
307+
308+
mockFS({
309+
[path.join(mockHomeDir, "config.json")]: JSON.stringify({
310+
installedToolchains: ["swift-5.9.0", "swift-6.0.0"],
311+
}),
312+
});
313+
314+
const toolchains = await SwiftToolchain.getSwiftlyToolchainInstalls();
315+
expect(toolchains).to.deep.equal([
316+
path.join(mockHomeDir, "toolchains", "swift-5.9.0"),
317+
path.join(mockHomeDir, "toolchains", "swift-6.0.0"),
318+
]);
319+
});
320+
321+
test("returns installed toolchains on macOS", async () => {
322+
mockedPlatform.setValue("darwin");
323+
const mockHomeDir = "/Users/user/.swiftly";
324+
mockedEnv.setValue({ SWIFTLY_HOME_DIR: mockHomeDir });
325+
326+
mockFS({
327+
[path.join(mockHomeDir, "config.json")]: JSON.stringify({
328+
installedToolchains: ["swift-5.9.0", "swift-6.0.0"],
329+
}),
330+
});
331+
332+
const toolchains = await SwiftToolchain.getSwiftlyToolchainInstalls();
333+
expect(toolchains).to.deep.equal([
334+
path.join(mockHomeDir, "toolchains", "swift-5.9.0"),
335+
path.join(mockHomeDir, "toolchains", "swift-6.0.0"),
336+
]);
337+
});
338+
339+
test("returns empty array when SWIFTLY_HOME_DIR is not set", async () => {
340+
mockedPlatform.setValue("linux");
341+
mockedEnv.setValue({});
342+
343+
const toolchains = await SwiftToolchain.getSwiftlyToolchainInstalls();
344+
expect(toolchains).to.be.empty;
345+
});
346+
347+
test("returns empty array when config file does not exist", async () => {
348+
mockedPlatform.setValue("linux");
349+
const mockHomeDir = "/home/user/.swiftly";
350+
mockedEnv.setValue({ SWIFTLY_HOME_DIR: mockHomeDir });
351+
352+
mockFS({});
353+
354+
await expect(SwiftToolchain.getSwiftlyToolchainInstalls()).to.be.rejectedWith(
355+
"Failed to retrieve Swiftly installations from disk."
356+
);
357+
});
358+
359+
test("returns empty array when config has no installedToolchains", async () => {
360+
mockedPlatform.setValue("linux");
361+
const mockHomeDir = "/home/user/.swiftly";
362+
mockedEnv.setValue({ SWIFTLY_HOME_DIR: mockHomeDir });
363+
364+
mockFS({
365+
[path.join(mockHomeDir, "config.json")]: JSON.stringify({
366+
someOtherProperty: "value",
367+
}),
368+
});
369+
370+
const toolchains = await SwiftToolchain.getSwiftlyToolchainInstalls();
371+
expect(toolchains).to.be.empty;
372+
});
373+
374+
test("returns empty array on Windows", async () => {
375+
mockedPlatform.setValue("win32");
376+
const toolchains = await SwiftToolchain.getSwiftlyToolchainInstalls();
377+
expect(toolchains).to.be.empty;
378+
});
379+
380+
test("filters out non-string toolchain entries", async () => {
381+
mockedPlatform.setValue("linux");
382+
const mockHomeDir = "/home/user/.swiftly";
383+
mockedEnv.setValue({ SWIFTLY_HOME_DIR: mockHomeDir });
384+
385+
mockFS({
386+
[path.join(mockHomeDir, "config.json")]: JSON.stringify({
387+
installedToolchains: ["swift-5.9.0", null, "swift-6.0.0", 123, "swift-6.1.0"],
388+
}),
389+
});
390+
391+
const toolchains = await SwiftToolchain.getSwiftlyToolchainInstalls();
392+
expect(toolchains).to.deep.equal([
393+
path.join(mockHomeDir, "toolchains", "swift-5.9.0"),
394+
path.join(mockHomeDir, "toolchains", "swift-6.0.0"),
395+
path.join(mockHomeDir, "toolchains", "swift-6.1.0"),
396+
]);
397+
});
398+
});
299399
});

0 commit comments

Comments
 (0)