Skip to content

Commit 01dc704

Browse files
refactor Swiftly class away from static methods
1 parent f2eb5de commit 01dc704

File tree

14 files changed

+690
-582
lines changed

14 files changed

+690
-582
lines changed

src/FolderContext.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,7 @@ export class FolderContext implements ExternalFolderContext, vscode.Disposable {
9999

100100
let toolchain: SwiftToolchain;
101101
try {
102-
toolchain = await SwiftToolchain.create(
103-
workspaceContext.extensionContext.extensionPath,
104-
folder
105-
);
102+
toolchain = await SwiftToolchain.create(workspaceContext.swiftly, folder);
106103
} catch (error) {
107104
// This error case is quite hard for the user to get in to, but possible.
108105
// Typically on startup the toolchain creation failure is going to happen in
@@ -116,10 +113,7 @@ export class FolderContext implements ExternalFolderContext, vscode.Disposable {
116113
if (userMadeSelection) {
117114
// User updated toolchain settings, retry once
118115
try {
119-
toolchain = await SwiftToolchain.create(
120-
workspaceContext.extensionContext.extensionPath,
121-
folder
122-
);
116+
toolchain = await SwiftToolchain.create(workspaceContext.swiftly, folder);
123117
workspaceContext.logger.info(
124118
`Successfully created toolchain for ${FolderContext.uriName(folder)} after user selection`,
125119
FolderContext.uriName(folder)

src/WorkspaceContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { SwiftPluginTaskProvider } from "./tasks/SwiftPluginTaskProvider";
3838
import { SwiftTaskProvider } from "./tasks/SwiftTaskProvider";
3939
import { TaskManager } from "./tasks/TaskManager";
4040
import { BuildFlags } from "./toolchain/BuildFlags";
41+
import { Swiftly } from "./toolchain/swiftly";
4142
import { SwiftToolchain } from "./toolchain/toolchain";
4243
import { ProjectPanelProvider } from "./ui/ProjectPanelProvider";
4344
import { StatusItem } from "./ui/StatusItem";
@@ -96,6 +97,7 @@ export class WorkspaceContext implements ExternalWorkspaceContext, vscode.Dispos
9697
public loggerFactory: SwiftLoggerFactory;
9798

9899
constructor(
100+
public swiftly: Swiftly | undefined,
99101
public extensionContext: vscode.ExtensionContext,
100102
public contextKeys: ContextKeys,
101103
public logger: SwiftLogger,

src/commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import { runTest } from "./commands/runTest";
5050
import { switchPlatform } from "./commands/switchPlatform";
5151
import { extractTestItemsAndCount, runTestMultipleTimes } from "./commands/testMultipleTimes";
5252
import { SwiftLogger } from "./logging/SwiftLogger";
53+
import { Swiftly } from "./toolchain/swiftly";
5354
import { SwiftToolchain } from "./toolchain/toolchain";
5455
import { PackageNode, PlaygroundNode } from "./ui/ProjectPanelProvider";
5556
import { showToolchainSelectionQuickPick } from "./ui/ToolchainSelection";
@@ -67,6 +68,7 @@ export type WorkspaceContextWithToolchain = WorkspaceContext & { toolchain: Swif
6768

6869
export function registerToolchainCommands(
6970
ctx: WorkspaceContext | undefined,
71+
swiftly: Swiftly | undefined,
7072
logger: SwiftLogger
7173
): vscode.Disposable[] {
7274
return [
@@ -76,6 +78,7 @@ export function registerToolchainCommands(
7678
vscode.commands.registerCommand("swift.selectToolchain", () =>
7779
showToolchainSelectionQuickPick(
7880
ctx?.currentFolder?.toolchain ?? ctx?.globalToolchain,
81+
swiftly,
7982
logger,
8083
ctx?.currentFolder?.folder
8184
)

src/commands/installSwiftly.ts

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ import * as path from "path";
1515
import * as vscode from "vscode";
1616

1717
import { SwiftLogger } from "../logging/SwiftLogger";
18-
import { Swiftly } from "../toolchain/swiftly";
18+
import { Swiftly, SwiftlyFactory } from "../toolchain/swiftly";
1919
import { Workbench } from "../utilities/commands";
2020
import { installSwiftlyToolchainWithProgress } from "./installSwiftlyToolchain";
2121

2222
/**
23-
* Prompts user for Swiftly installation with directory customization options
24-
* @param logger Optional logger
25-
* @returns A promise that resolves to true if the user has opted to install swiftly, false otherwise
23+
* Prompts user for Swiftly installation with directory customization options.
24+
*
25+
* @param logger The logger to use for logging messages.
26+
* @returns A promise that resolves to `true` if the user has opted to install swiftly, `false` otherwise.
2627
*/
27-
export async function promptForSwiftlyInstallation(logger?: SwiftLogger): Promise<boolean> {
28+
export async function promptForSwiftlyInstallation(logger: SwiftLogger): Promise<boolean> {
2829
const installMessage = `A .swift-version file was detected. Install Swiftly to automatically manage Swift toolchain versions for this project.`;
2930

3031
const selection = await vscode.window.showWarningMessage(
@@ -66,19 +67,19 @@ This process involves updating your shell profile in order to add swiftly to you
6667
await vscode.workspace
6768
.getConfiguration("swift")
6869
.update("disableSwiftlyInstallPrompt", true, vscode.ConfigurationTarget.Global);
69-
logger?.info("Swiftly installation prompt suppressed by user");
70+
logger.info("Swiftly installation prompt suppressed by user");
7071
}
7172

7273
return false;
7374
}
7475

7576
/**
76-
* Installs Swiftly with progress tracking and user feedback
77-
* @param options Installation options
78-
* @param logger Optional logger
79-
* @returns Promise<boolean> true if installation succeeded
77+
* Installs Swiftly with progress tracking and user feedback.
78+
*
79+
* @param logger The logger to use for logging messages.
80+
* @returns A promise that resolves to `true` if installation succeeded, `false` otherwise.
8081
*/
81-
export async function installSwiftlyWithProgress(logger?: SwiftLogger): Promise<boolean> {
82+
export async function installSwiftlyWithProgress(logger: SwiftLogger): Promise<boolean> {
8283
try {
8384
await vscode.window.withProgress(
8485
{
@@ -92,14 +93,14 @@ export async function installSwiftlyWithProgress(logger?: SwiftLogger): Promise<
9293
);
9394
return true;
9495
} catch (error) {
95-
logger?.error(`Failed to install Swiftly: ${error}`);
96+
logger.error(`Failed to install Swiftly: ${error}`);
9697
const message = error instanceof Error ? error.message : String(error);
9798
void vscode.window.showErrorMessage(`Failed to install Swiftly: ${message}`);
9899
return false;
99100
}
100101
}
101102

102-
async function promptToRestartVSCode(): Promise<void> {
103+
async function promptToRestartVSCode(): Promise<boolean> {
103104
const selection = await vscode.window.showInformationMessage(
104105
"Restart VS Code",
105106
{
@@ -110,27 +111,34 @@ async function promptToRestartVSCode(): Promise<void> {
110111
);
111112
if (selection === "Quit Visual Studio Code") {
112113
await vscode.commands.executeCommand(Workbench.ACTION_QUIT);
114+
return true;
113115
}
116+
return false;
114117
}
115118

116119
/**
117-
* Main function to handle missing Swiftly detection and installation
118-
* @param swiftVersionFiles A list of swift version files that will need to be installed
119-
* @param logger Optional logger
120-
* @returns Promise<boolean> true if Swiftly was installed or already exists
120+
* Main function to handle missing Swiftly detection and installation.
121+
*
122+
* Asks the user whether or not they want to install Swiftly to manage their Swift toolchains. It will
123+
* also install the provided Swift toolchain versions after installing Swiftly.
124+
*
125+
* @param swiftlyFactory Factory used to create a Swiftly instance after installation.
126+
* @param swiftVersions An array of Swift toolchain versions to install.
127+
* @param logger The logger to use for logging messages.
128+
* @returns A promise that resolves to `true` if Swiftly was installed or already exists, `false` otherwise.
121129
*/
122130
export async function handleMissingSwiftly(
131+
swiftlyFactory: SwiftlyFactory,
123132
swiftVersions: string[],
124-
extensionRoot: string,
125-
logger?: SwiftLogger
133+
logger: SwiftLogger
126134
): Promise<boolean> {
127135
if (await Swiftly.isInstalled()) {
128136
return true;
129137
}
130138

131139
// Check if the user wants to disable the prompt
132140
if (vscode.workspace.getConfiguration("swift").get("disableSwiftlyInstallPrompt", false)) {
133-
logger?.debug("Swiftly installation prompt is suppressed");
141+
logger.debug("Swiftly installation prompt is suppressed");
134142
return false;
135143
}
136144

@@ -145,12 +153,11 @@ export async function handleMissingSwiftly(
145153
}
146154

147155
// Install toolchains
148-
const swiftlyPath = path.join(Swiftly.defaultHomeDir(), "bin/swiftly");
156+
const swiftly = swiftlyFactory.create(path.join(Swiftly.defaultHomeDir(), "bin/swiftly"));
149157
for (const version of swiftVersions) {
150-
await installSwiftlyToolchainWithProgress(version, extensionRoot, logger, swiftlyPath);
158+
await installSwiftlyToolchainWithProgress(swiftly, version);
151159
}
152160

153161
// VS Code needs to be restarted after installing swiftly
154-
await promptToRestartVSCode();
155-
return true;
162+
return await promptToRestartVSCode();
156163
}

src/commands/installSwiftlyToolchain.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import * as vscode from "vscode";
1515

1616
import { WorkspaceContext } from "../WorkspaceContext";
17-
import { SwiftLogger } from "../logging/SwiftLogger";
1817
import { Swiftly, SwiftlyProgressData } from "../toolchain/swiftly";
1918
import { SwiftToolchain } from "../toolchain/toolchain";
2019
import {
@@ -31,10 +30,8 @@ import {
3130
* @returns A promise that resolves to true if installation succeeded, false otherwise
3231
*/
3332
export async function installSwiftlyToolchainWithProgress(
34-
version: string,
35-
extensionRoot: string,
36-
logger?: SwiftLogger,
37-
swiftlyPath?: string
33+
swiftly: Swiftly,
34+
version: string
3835
): Promise<boolean> {
3936
try {
4037
await vscode.window.withProgress(
@@ -48,9 +45,8 @@ export async function installSwiftlyToolchainWithProgress(
4845

4946
let lastProgress = 0;
5047

51-
await Swiftly.installToolchain(
48+
await swiftly.installToolchain(
5249
version,
53-
extensionRoot,
5450
(progressData: SwiftlyProgressData) => {
5551
if (progressData.complete) {
5652
// Swiftly will also verify the signature and extract the toolchain after the
@@ -74,9 +70,7 @@ export async function installSwiftlyToolchainWithProgress(
7470
});
7571
lastProgress = progressData.step.percent;
7672
},
77-
logger,
78-
token,
79-
swiftlyPath
73+
token
8074
);
8175
}
8276
);
@@ -87,12 +81,12 @@ export async function installSwiftlyToolchainWithProgress(
8781
} catch (error) {
8882
const errorMessage = (error as Error).message;
8983
if (errorMessage.includes(Swiftly.cancellationMessage)) {
90-
logger?.info(`Installation of Swift ${version} was cancelled by user`);
84+
swiftly.logger.info(`Installation of Swift ${version} was cancelled by user`);
9185
// Don't show error message for user-initiated cancellation
9286
return false;
9387
}
9488

95-
logger?.error(new Error(`Failed to install Swift ${version}`, { cause: error }));
89+
swiftly.logger.error(new Error(`Failed to install Swift ${version}`, { cause: error }));
9690
void vscode.window.showErrorMessage(`Failed to install Swift ${version}: ${error}`);
9791
return false;
9892
}
@@ -106,13 +100,20 @@ export async function promptToInstallSwiftlyToolchain(
106100
type: "stable" | "snapshot"
107101
): Promise<void> {
108102
if (!Swiftly.isSupported()) {
109-
ctx.logger?.warn("Swiftly is not supported on this platform.");
103+
ctx.logger.error("Swiftly is not supported on this platform.");
110104
void vscode.window.showErrorMessage(
111105
"Swiftly is not supported on this platform. Only macOS and Linux are supported."
112106
);
113107
return;
114108
}
115109

110+
const swiftly = ctx.swiftly;
111+
if (!swiftly) {
112+
ctx.logger.error("Swiftly is not installed.");
113+
void vscode.window.showErrorMessage("Swiftly is not installed on this machine.");
114+
return;
115+
}
116+
116117
let branch: string | undefined = undefined;
117118
if (type === "snapshot") {
118119
// Prompt user to enter the branch for snapshot toolchains
@@ -127,7 +128,7 @@ export async function promptToInstallSwiftlyToolchain(
127128
}
128129
}
129130

130-
const availableToolchains = await Swiftly.listAvailable(branch, ctx.logger);
131+
const availableToolchains = await swiftly.listAvailable(branch);
131132

132133
if (availableToolchains.length === 0) {
133134
ctx.logger?.debug("No toolchains available for installation via Swiftly.");
@@ -180,9 +181,8 @@ export async function promptToInstallSwiftlyToolchain(
180181
// Install the toolchain via Swiftly
181182
if (
182183
!(await installSwiftlyToolchainWithProgress(
183-
selectedToolchain.toolchain.version.name,
184-
ctx.extensionContext.extensionPath,
185-
ctx.logger
184+
swiftly,
185+
selectedToolchain.toolchain.version.name
186186
))
187187
) {
188188
return;
@@ -196,12 +196,12 @@ export async function promptToInstallSwiftlyToolchain(
196196
if (target === vscode.ConfigurationTarget.Workspace) {
197197
await Promise.all(
198198
vscode.workspace.workspaceFolders?.map(folder =>
199-
Swiftly.use(selectedToolchain.toolchain.version.name, folder.uri.fsPath)
199+
swiftly.use(selectedToolchain.toolchain.version.name, folder.uri.fsPath)
200200
) ?? []
201201
);
202202
return;
203203
}
204-
await Swiftly.use(selectedToolchain.toolchain.version.name);
204+
await swiftly.use(selectedToolchain.toolchain.version.name);
205205
},
206206
},
207207
selectedDeveloperDir.developerDir,

0 commit comments

Comments
 (0)