Skip to content

Commit 275ed7f

Browse files
authored
Switch to Build All task when listing tests fails (#814)
Use the buildAllTask instead of SwiftExecOperation to make long this behaviour the same as other builds in the extension. Added a task cache since provideTasks can be called multiple times and the most recently returned task is held by VSCode. If we attempted created the build all task and hooked up the event listeners but then provideTasks was called again before the task was executed, the executed task would not be the one we were listening to. Fixes #808
1 parent 5c83f5d commit 275ed7f

File tree

5 files changed

+64
-26
lines changed

5 files changed

+64
-26
lines changed

src/TestExplorer/TestExplorer.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -243,20 +243,18 @@ export class TestExplorer {
243243
// If a test list fails its possible the tests have not been built.
244244
// Build them and try again, and if we still fail then notify the user.
245245
if (firstTry) {
246-
await new Promise<string>(resolve => {
247-
const swiftBuildOperation = new SwiftExecOperation(
248-
["build", "--build-tests"],
249-
explorer.folderContext,
250-
"Building",
251-
{
252-
showStatusItem: true,
253-
checkAlreadyRunning: true,
254-
log: "Performing initial build",
255-
},
256-
resolve
246+
const backgroundTask = await getBuildAllTask(explorer.folderContext);
247+
if (!backgroundTask) {
248+
return;
249+
}
250+
251+
try {
252+
await explorer.folderContext.taskQueue.queueOperation(
253+
new TaskOperation(backgroundTask)
257254
);
258-
explorer.folderContext.taskQueue.queueOperation(swiftBuildOperation);
259-
});
255+
} catch {
256+
// can ignore if running task fails
257+
}
260258

261259
// Retry test discovery after performing a build.
262260
await runDiscover(explorer, false);

src/tasks/SwiftTaskProvider.ts

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,21 @@ function getBuildRevealOption(): vscode.TaskRevealKind {
111111
: vscode.TaskRevealKind.Never;
112112
}
113113

114+
const buildAllTaskCache = (() => {
115+
const cache = new Map<string, vscode.Task>();
116+
const key = (name: string, folderContext: FolderContext) => {
117+
return `${name}:${buildOptions(folderContext.workspaceContext.toolchain).join(",")}`;
118+
};
119+
return {
120+
get(name: string, folderContext: FolderContext): vscode.Task | undefined {
121+
return cache.get(key(name, folderContext));
122+
},
123+
set(name: string, folderContext: FolderContext, task: vscode.Task) {
124+
cache.set(key(name, folderContext), task);
125+
},
126+
};
127+
})();
128+
114129
/**
115130
* Creates a {@link vscode.Task Task} to build all targets in this package.
116131
*/
@@ -127,7 +142,16 @@ export function createBuildAllTask(folderContext: FolderContext): vscode.Task {
127142
if (folderContext.workspaceContext.toolchain.buildFlags.getDarwinTarget() === undefined) {
128143
additionalArgs = ["--build-tests", ...additionalArgs];
129144
}
130-
return createSwiftTask(
145+
146+
// Create one Build All task per folder context, since this can be called multiple
147+
// times and we want the same instance each time. Otherwise, VSCode may try and execute
148+
// one instance while our extension code tries to listen to events on an instance created earlier/later.
149+
const existingTask = buildAllTaskCache.get(buildTaskName, folderContext);
150+
if (existingTask) {
151+
return existingTask;
152+
}
153+
154+
const task = createSwiftTask(
131155
["build", ...additionalArgs],
132156
buildTaskName,
133157
{
@@ -143,6 +167,8 @@ export function createBuildAllTask(folderContext: FolderContext): vscode.Task {
143167
},
144168
folderContext.workspaceContext.toolchain
145169
);
170+
buildAllTaskCache.set(buildTaskName, folderContext, task);
171+
return task;
146172
}
147173

148174
/**
@@ -206,10 +232,13 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
206232
if (folderContext.relativePath.length > 0) {
207233
buildTaskNameSuffix = ` (${folderContext.relativePath})`;
208234
}
209-
return [
210-
createSwiftTask(
235+
236+
const buildDebugName = `Build Debug ${product.name}${buildTaskNameSuffix}`;
237+
let buildDebug = buildAllTaskCache.get(buildDebugName, folderContext);
238+
if (!buildDebug) {
239+
buildDebug = createSwiftTask(
211240
["build", "--product", product.name, ...buildOptions(toolchain)],
212-
`Build Debug ${product.name}${buildTaskNameSuffix}`,
241+
buildDebugName,
213242
{
214243
group: vscode.TaskGroup.Build,
215244
cwd: folderContext.folder,
@@ -223,8 +252,14 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
223252
showBuildStatus: configuration.showBuildStatus,
224253
},
225254
folderContext.workspaceContext.toolchain
226-
),
227-
createSwiftTask(
255+
);
256+
buildAllTaskCache.set(buildDebugName, folderContext, buildDebug);
257+
}
258+
259+
const buildReleaseName = `Build Release ${product.name}${buildTaskNameSuffix}`;
260+
let buildRelease = buildAllTaskCache.get(buildReleaseName, folderContext);
261+
if (!buildRelease) {
262+
buildRelease = createSwiftTask(
228263
["build", "-c", "release", "--product", product.name, ...configuration.buildArguments],
229264
`Build Release ${product.name}${buildTaskNameSuffix}`,
230265
{
@@ -240,8 +275,11 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
240275
showBuildStatus: configuration.showBuildStatus,
241276
},
242277
folderContext.workspaceContext.toolchain
243-
),
244-
];
278+
);
279+
buildAllTaskCache.set(buildReleaseName, folderContext, buildRelease);
280+
}
281+
282+
return [buildDebug, buildRelease];
245283
}
246284

247285
/**

src/tasks/TaskQueue.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,10 @@ export class TaskQueue {
253253
.catch(error => {
254254
// log error
255255
if (operation.log) {
256-
this.workspaceContext.outputChannel.logEnd(`${error}`);
256+
this.workspaceContext.outputChannel.logEnd(
257+
`${operation.log}: ${error}`,
258+
this.folderContext.name
259+
);
257260
}
258261
this.finishTask(operation, { fail: error });
259262
});

src/ui/SwiftOutputChannel.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ export class SwiftOutputChannel {
6565
console.log(line);
6666
}
6767

68-
logEnd(message: string) {
69-
this.channel.appendLine(message);
70-
console.log(message);
68+
logEnd(message: string, label?: string) {
69+
this.logStart(message, label);
7170
}
7271

7372
get nowFormatted(): string {

src/utilities/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export async function execFile(
8989
return new Promise<{ stdout: string; stderr: string }>((resolve, reject) =>
9090
cp.execFile(executable, args, options, (error, stdout, stderr) => {
9191
if (error) {
92-
reject({ error, stdout, stderr });
92+
reject({ error, stdout, stderr, toString: () => error.message });
9393
}
9494
resolve({ stdout, stderr });
9595
})

0 commit comments

Comments
 (0)